libindi-0.9.7/0000755000175000017500000000000012241463656012132 5ustar jasemjasemlibindi-0.9.7/drivers/0000755000175000017500000000000012241463551013602 5ustar jasemjasemlibindi-0.9.7/drivers/auxiliary/0000755000175000017500000000000012241463551015611 5ustar jasemjasemlibindi-0.9.7/drivers/auxiliary/gpdriver.cpp0000644000175000017500000001034512241463551020142 0ustar jasemjasem/******************************************************************************* Copyright(c) 2012 Jasem Mutlaq. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #include "gpdriver.h" GPUSBDriver::GPUSBDriver() { //ctor guideCMD[0]=0; debug=false; } GPUSBDriver::~GPUSBDriver() { //dtor // usb_close(usb_handle); } bool GPUSBDriver::Connect() { if (debug) usb_set_debug(2); dev=FindDevice(0x134A, 0x9020,0); if(dev==NULL) { IDLog("Error: No GPUSB device found\n"); return false; } usb_handle=usb_open(dev); if(usb_handle != NULL) { int rc; rc=FindEndpoints(); rc = usb_detach_kernel_driver_np(usb_handle,0); if (debug) IDLog("Detach Kernel returns %d\n",rc); rc = usb_set_configuration(usb_handle,1); if (debug) IDLog("Set Configuration returns %d\n",rc); rc=usb_claim_interface(usb_handle,0); if (debug) IDLog("claim interface returns %d\n",rc); rc= usb_set_altinterface(usb_handle,0); if (debug) IDLog("set alt interface returns %d\n",rc); if (rc== 0) return true; } return false; } bool GPUSBDriver::Disconnect() { usb_release_interface(usb_handle, 0); usb_close(usb_handle); return true; } bool GPUSBDriver::startPulse(int direction) { int rc=0; switch (direction) { case GPUSB_NORTH: guideCMD[0] &= GPUSB_CLEAR_DEC; guideCMD[0] |= (GPUSB_NORTH | GPUSB_LED_ON) & ~GPUSB_LED_RED; break; case GPUSB_WEST: guideCMD[0] &= GPUSB_CLEAR_RA; guideCMD[0] |= (GPUSB_WEST | GPUSB_LED_ON) & ~GPUSB_LED_RED; break; case GPUSB_SOUTH: guideCMD[0] &= GPUSB_CLEAR_DEC; guideCMD[0] |= GPUSB_SOUTH | GPUSB_LED_ON | GPUSB_LED_RED; break; case GPUSB_EAST: guideCMD[0] &= GPUSB_CLEAR_RA; guideCMD[0] |= GPUSB_EAST | GPUSB_LED_ON | GPUSB_LED_RED; break; } if (debug) IDLog("start command value is 0x%X\n", guideCMD[0]); rc=WriteBulk(guideCMD,1,1000); if (debug) IDLog("startPulse WriteBulk returns %d\n",rc); if(rc==1) return true; return false; } bool GPUSBDriver::stopPulse(int direction) { int rc=0; switch (direction) { case GPUSB_NORTH: if (debug) IDLog("Stop North\n"); guideCMD[0] &= GPUSB_CLEAR_DEC; break; case GPUSB_WEST: if (debug) IDLog("Stop West\n"); guideCMD[0] &= GPUSB_CLEAR_RA; break; case GPUSB_SOUTH: if (debug) IDLog("Stop South\n"); guideCMD[0] &= GPUSB_CLEAR_DEC; break; case GPUSB_EAST: if (debug) IDLog("Stop East\n"); guideCMD[0] &= GPUSB_CLEAR_RA; break; } if ( (guideCMD[0] & GPUSB_NORTH) || (guideCMD[0] & GPUSB_WEST)) guideCMD[0] &= ~GPUSB_LED_RED; else if ( (guideCMD[0] & GPUSB_SOUTH) || (guideCMD[0] & GPUSB_EAST)) guideCMD[0] |= GPUSB_LED_RED; if ( (guideCMD[0] & 0xF) == 0) guideCMD[0] = 0; if (debug) IDLog("stop command value is 0x%X\n", guideCMD[0]); rc=WriteBulk(guideCMD,1,1000); if (debug) IDLog("stopPulse WriteBulk returns %d\n",rc); if(rc==1) return true; return false; } libindi-0.9.7/drivers/auxiliary/gpdriver.h0000644000175000017500000000361212241463551017606 0ustar jasemjasem/******************************************************************************* Copyright(c) 2012 Jasem Mutlaq. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #ifndef GPUSBDRIVER_H #define GPUSBDRIVER_H #include "libs/indibase/indiusbdevice.h" /* Standard headers */ #include #include #include #include #include #include #include #include enum { GPUSB_NORTH = 0x08, GPUSB_SOUTH = 0x04, GPUSB_EAST = 0x01, GPUSB_WEST = 0x02, GPUSB_LED_RED = 0x10, GPUSB_LED_ON = 0x20, GPUSB_CLEAR_RA = 0xFC, GPUSB_CLEAR_DEC= 0xF3 }; class GPUSBDriver : public INDI::USBDevice { public: GPUSBDriver(); virtual ~GPUSBDriver(); // Generic indi device entries bool Connect(); bool Disconnect(); bool startPulse(int direction); bool stopPulse(int direction); void setDebug(bool enable) { debug = enable; } private: char guideCMD[1]; bool debug; }; #endif // GPUSBDriver_H libindi-0.9.7/drivers/auxiliary/gpusb.cpp0000644000175000017500000002204712241463551017442 0ustar jasemjasem/******************************************************************************* Copyright(c) 2012 Jasem Mutlaq. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #include "gpusb.h" #include "gpdriver.h" #include #define POLLMS 250 // We declare an auto pointer to gpGuide. std::auto_ptr gpGuide(0); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(gpGuide.get() == 0) gpGuide.reset(new GPUSB()); //IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { ISInit(); gpGuide->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); gpGuide->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); gpGuide->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); gpGuide->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } GPUSB::GPUSB() { driver = new GPUSBDriver(); WEDir = NSDir = 0; //ctor } GPUSB::~GPUSB() { //dtor delete (driver); } const char * GPUSB::getDefaultName() { return (char *)"GPUSB"; } bool GPUSB::Connect() { driver->setDebug(isDebug()); bool rc = driver->Connect(); if (rc) IDMessage(getDeviceName(), "GPUSB is online."); else IDMessage(getDeviceName(), "Error: cannot find GPUSB device."); return rc; } bool GPUSB::Disconnect() { IDMessage(getDeviceName(), "GPSUSB is offline."); return driver->Disconnect(); } bool GPUSB::initProperties() { initGuiderProperties(getDeviceName(), MAIN_CONTROL_TAB); addDebugControl(); return INDI::DefaultDevice::initProperties(); } bool GPUSB::updateProperties() { INDI::DefaultDevice::updateProperties(); if (isConnected()) { defineNumber(&GuideNSNP); defineNumber(&GuideWENP); } else { deleteProperty(GuideNSNP.name); deleteProperty(GuideWENP.name); } return true; } void GPUSB::ISGetProperties (const char *dev) { INDI::DefaultDevice::ISGetProperties(dev); } bool GPUSB::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if (!strcmp(name,GuideNSNP.name) || !strcmp(name,GuideWENP.name)) { processGuiderProperties(name, values, names, n); return true; } } return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n); } bool GPUSB::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n); } bool GPUSB::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n); } bool GPUSB::ISSnoopDevice (XMLEle *root) { return INDI::DefaultDevice::ISSnoopDevice(root); } float GPUSB::CalcWEPulseTimeLeft() { double timesince; double timeleft; struct timeval now; gettimeofday(&now,NULL); timesince=(double)(now.tv_sec * 1000.0 + now.tv_usec/1000) - (double)(WEPulseStart.tv_sec * 1000.0 + WEPulseStart.tv_usec/1000); timesince=timesince/1000; timeleft=WEPulseRequest-timesince; return timeleft; } float GPUSB::CalcNSPulseTimeLeft() { double timesince; double timeleft; struct timeval now; gettimeofday(&now,NULL); timesince=(double)(now.tv_sec * 1000.0 + now.tv_usec/1000) - (double)(NSPulseStart.tv_sec * 1000.0 + NSPulseStart.tv_usec/1000); timesince=timesince/1000; timeleft=NSPulseRequest-timesince; return timeleft; } void GPUSB::TimerHit() { float timeleft; int rc; if(InWEPulse) { timeleft=CalcWEPulseTimeLeft(); if(timeleft < 1.0) { if(timeleft > 0.25) { // a quarter of a second or more // just set a tighter timer WEtimerID = SetTimer(250); } else { if(timeleft >0.07) { // use an even tighter timer WEtimerID = SetTimer(50); } else { // it's real close now, so spin on it while(timeleft > 0) { int slv; slv=100000*timeleft; //IDLog("usleep %d\n",slv); usleep(slv); timeleft=CalcWEPulseTimeLeft(); } driver->stopPulse(WEDir); InWEPulse = false; // If we have another pulse, keep going if (!InNSPulse) SetTimer(250); } } } else if (!InNSPulse) { WEtimerID = SetTimer(250); } } if(InNSPulse) { timeleft=CalcNSPulseTimeLeft(); if(timeleft < 1.0) { if(timeleft > 0.25) { // a quarter of a second or more // just set a tighter timer NStimerID = SetTimer(250); } else { if(timeleft >0.07) { // use an even tighter timer NStimerID = SetTimer(50); } else { // it's real close now, so spin on it while(timeleft > 0) { int slv; slv=100000*timeleft; //IDLog("usleep %d\n",slv); usleep(slv); timeleft=CalcNSPulseTimeLeft(); } driver->stopPulse(NSDir); InNSPulse = false; } } } else { NStimerID = SetTimer(250); } } } bool GPUSB::GuideNorth(float ms) { RemoveTimer(NStimerID); driver->startPulse(GPUSB_NORTH); NSDir = GPUSB_NORTH; IDLog("Starting NORTH guide\n"); if (ms <= POLLMS) { usleep(ms*1000); driver->stopPulse(GPUSB_NORTH); return true; } NSPulseRequest=ms/1000.0; gettimeofday(&NSPulseStart,NULL); InNSPulse=true; NStimerID = SetTimer(ms-50); return true; } bool GPUSB::GuideSouth(float ms) { RemoveTimer(NStimerID); driver->startPulse(GPUSB_SOUTH); IDLog("Starting SOUTH guide\n"); NSDir = GPUSB_SOUTH; if (ms <= POLLMS) { usleep(ms*1000); driver->stopPulse(GPUSB_SOUTH); return true; } NSPulseRequest=ms/1000.0; gettimeofday(&NSPulseStart,NULL); InNSPulse=true; NStimerID = SetTimer(ms-50); return true; } bool GPUSB::GuideEast(float ms) { RemoveTimer(WEtimerID); driver->startPulse(GPUSB_EAST); IDLog("Starting EAST guide\n"); WEDir = GPUSB_EAST; if (ms <= POLLMS) { usleep(ms*1000); driver->stopPulse(GPUSB_EAST); return true; } WEPulseRequest=ms/1000.0; gettimeofday(&WEPulseStart,NULL); InWEPulse=true; WEtimerID = SetTimer(ms-50); return true; } bool GPUSB::GuideWest(float ms) { RemoveTimer(WEtimerID); driver->startPulse(GPUSB_WEST); IDLog("Starting WEST guide\n"); WEDir = GPUSB_WEST; if (ms <= POLLMS) { usleep(ms*1000); driver->stopPulse(GPUSB_WEST); return true; } WEPulseRequest=ms/1000.0; gettimeofday(&WEPulseStart,NULL); InWEPulse=true; WEtimerID = SetTimer(ms-50); return true; } libindi-0.9.7/drivers/auxiliary/99-gpusb.rules0000644000175000017500000000012212241463551020237 0ustar jasemjasemSUBSYSTEMS=="usb", ATTRS{idVendor}=="134a", ATTRS{idProduct}=="9020", MODE="0666" libindi-0.9.7/drivers/auxiliary/joystickdriver.h0000644000175000017500000000772712241463551021052 0ustar jasemjasem/******************************************************************************* Copyright(c) 2013 Jasem Mutlaq. All rights reserved. Based on code by Keith Lantz. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #ifndef JOYSTICK_H #define JOYSTICK_H #include #include #include #include #include #include #include #include #define JOYSTICK_DEV "/dev/input/js0" struct joystick_position { float theta, r, x, y; }; struct joystick_state { std::vector button; std::vector axis; }; /** * @brief The JoyStickDriver class provides basic functionality to read events from supported game pads under Linux. * It provides functions to read the button, axis, and joystick status and values. By definition, a joystick is the combination of two axis. * A game pad may have one or more joysticks depending on the number of reported axis. You can utilize the class in an event driven fashion by using callbacks. * The callbacks have a specific signature and must be set. Alternatively, you may query the status and position of the buttons & axis at any time as well. * * Since the class runs a non-blocking thread, the thread goes to sleep when there are no events detected in order to reduce CPU utilization. The sleep period is set by * default to 100 milliseconds and can be adjusted by the \i setPoll function. * * Each joystick has a normalized magnitude [0 to 1] and an angle. The magnitude is 0 when the stick is not depressed, and 1 when depressed all the way. * The angles are measured counter clock wise [0 to 360] with right/east direction being zero. * * The axis value is reported in raw values [-32767.0 to 32767.0]. * * The buttons are either off (0) or on (1) * */ class JoyStickDriver { public: JoyStickDriver(); ~JoyStickDriver(); typedef std::tr1::function joystickFunc; typedef std::tr1::function axisFunc; typedef std::tr1::function buttonFunc; bool Connect(); bool Disconnect(); void setPort(const char *port); void setPoll(int ms); const char *getName(); __u32 getVersion(); __u8 getNumOfJoysticks(); __u8 getNumOfAxes(); __u8 getNumrOfButtons(); joystick_position joystickPosition(int n); bool buttonPressed(int n); void setJoystickCallback(joystickFunc joystickCallback); void setAxisCallback(axisFunc axisCallback); void setButtonCallback(buttonFunc buttonCallback); protected: static void joystickEvent(int joystick_n, double mag, double angle); static void axisEvent(int axis_n, int value); static void buttonEvent(int button_n, int value); static void* loop(void* obj); void readEv(); joystickFunc joystickCallbackFunc; buttonFunc buttonCallbackFunc; axisFunc axisCallbackFunc; private: pthread_t thread; bool active; int joystick_fd; js_event *joystick_ev; joystick_state *joystick_st; __u32 version; __u8 axes; __u8 buttons; char name[256]; char dev_path[256]; int pollMS; }; #endif // JOYSTICK_H libindi-0.9.7/drivers/auxiliary/joystick.h0000644000175000017500000000541212241463551017623 0ustar jasemjasem/******************************************************************************* Copyright(c) 2013 Jasem Mutlaq. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #ifndef INDIJOYSTICK_H #define INDIJOYSTICK_H #include /* Standard headers */ #include #include #include #include #include #include #include #include class JoyStickDriver; /** * @brief The JoyStick class provides an INDI driver that displays event data from game pads. The INDI driver can be encapsulated in any other driver * via snooping on properties of interesting. * */ class JoyStick : public INDI::DefaultDevice { public: JoyStick(); virtual ~JoyStick(); virtual bool initProperties(); virtual bool updateProperties(); virtual void ISGetProperties (const char *dev); virtual bool ISSnoopDevice (XMLEle *root); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); static void joystickHelper(int joystick_n, double mag, double angle); static void axisHelper(int axis_n, int value); static void buttonHelper(int button_n, int value); protected: // Generic indi device entries bool Connect(); bool Disconnect(); const char *getDefaultName(); void setupParams(); void joystickEvent(int joystick_n, double mag, double angle); void axisEvent(int axis_n, int value); void buttonEvent(int button_n, int value); INumberVectorProperty *JoyStickNP; INumber *JoyStickN; INumberVectorProperty AxisNP; INumber *AxisN; ISwitchVectorProperty ButtonSP; ISwitch *ButtonS; ITextVectorProperty PortTP; // A text vector that stores out physical port name IText PortT[1]; ITextVectorProperty JoystickInfoTP; IText JoystickInfoT[5]; JoyStickDriver *driver; }; #endif // INDIJOYSTICK_H libindi-0.9.7/drivers/auxiliary/gpusb.h0000644000175000017500000000514412241463551017106 0ustar jasemjasem/******************************************************************************* Copyright(c) 2012 Jasem Mutlaq. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #ifndef GPUSB_H #define GPUSB_H #include "libs/indibase/defaultdevice.h" #include "libs/indibase/indiguiderinterface.h" /* Standard headers */ #include #include #include #include #include #include #include #include class GPUSBDriver; class GPUSB : public INDI::GuiderInterface, public INDI::DefaultDevice { public: GPUSB(); virtual ~GPUSB(); virtual bool initProperties(); virtual bool updateProperties(); virtual void ISGetProperties (const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISSnoopDevice (XMLEle *root); protected: // Generic indi device entries bool Connect(); bool Disconnect(); const char *getDefaultName(); void TimerHit(); virtual bool GuideNorth(float ms); virtual bool GuideSouth(float ms); virtual bool GuideEast(float ms); virtual bool GuideWest(float ms); private: float CalcWEPulseTimeLeft(); float CalcNSPulseTimeLeft(); bool InWEPulse; float WEPulseRequest; struct timeval WEPulseStart; int WEtimerID; bool InNSPulse; float NSPulseRequest; struct timeval NSPulseStart; int NStimerID; int WEDir; int NSDir; GPUSBDriver *driver; }; #endif // GPUSB_H libindi-0.9.7/drivers/auxiliary/joystick.cpp0000644000175000017500000002244012241463551020156 0ustar jasemjasem/******************************************************************************* Copyright(c) 2013 Jasem Mutlaq. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #include "joystick.h" #include "joystickdriver.h" #include #define POLLMS 250 // We declare an auto pointer to joystick. std::auto_ptr joystick(0); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(joystick.get() == 0) joystick.reset(new JoyStick()); //IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { ISInit(); joystick->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); joystick->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); joystick->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); joystick->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } JoyStick::JoyStick() { driver = new JoyStickDriver(); JoyStickNP = NULL; JoyStickN = NULL; AxisN = NULL; ButtonS = NULL; } JoyStick::~JoyStick() { //dtor delete (driver); } const char * JoyStick::getDefaultName() { return (char *)"Joystick"; } bool JoyStick::Connect() { bool rc = driver->Connect(); if (rc) { IDMessage(getDeviceName(), "Joystick is online."); setupParams(); } else IDMessage(getDeviceName(), "Error: cannot find Joystick device."); return rc; } bool JoyStick::Disconnect() { IDMessage(getDeviceName(), "Joystick is offline."); return driver->Disconnect(); } void JoyStick::setupParams() { char propName[16], propLabel[16]; if (driver == NULL) return; int nAxis = driver->getNumOfAxes(); int nJoysticks = driver->getNumOfJoysticks(); int nButtons = driver->getNumrOfButtons(); JoyStickNP = new INumberVectorProperty[nJoysticks]; JoyStickN = new INumber[nJoysticks*2]; AxisN = new INumber[nAxis]; ButtonS = new ISwitch[nButtons]; for (int i=0; i < nJoysticks*2; i+=2) { snprintf(propName, 16, "JOYSTICK_%d", i/2+1); snprintf(propLabel, 16, "Joystick %d", i/2+1); IUFillNumber(&JoyStickN[i], "JOYSTICK_MAGNITUDE", "Magnitude", "%g", -32767.0, 32767.0, 0, 0); IUFillNumber(&JoyStickN[i+1], "JOYSTICK_ANGLE", "Angle", "%g", 0, 360.0, 0, 0); IUFillNumberVector(&JoyStickNP[i/2], JoyStickN + i, 2, getDeviceName(), propName, propLabel, "Monitor", IP_RO, 0, IPS_IDLE); } for (int i=0; i < nAxis; i++) { snprintf(propName, 16, "AXIS_%d", i+1); snprintf(propLabel, 16, "Axis %d", i+1); IUFillNumber(&AxisN[i], propName, propLabel, "%g", -32767.0, 32767.0, 0, 0); } IUFillNumberVector(&AxisNP, AxisN, nAxis, getDeviceName(), "JOYSTICK_AXES", "Axes", "Monitor", IP_RO, 0, IPS_IDLE ); for (int i=0; i < nButtons; i++) { snprintf(propName, 16, "BUTTON_%d", i+1); snprintf(propLabel, 16, "Button %d", i+1); IUFillSwitch(&ButtonS[i], propName, propLabel, ISS_OFF); } IUFillSwitchVector(&ButtonSP, ButtonS, nButtons, getDeviceName(), "JOYSTICK_BUTTONS", "Buttons", "Monitor", IP_RO, ISR_NOFMANY, 0, IPS_IDLE ); } bool JoyStick::initProperties() { INDI::DefaultDevice::initProperties(); IUFillText(&PortT[0],"PORT","Port","/dev/input/js0"); IUFillTextVector(&PortTP,PortT,1,getDeviceName(),"DEVICE_PORT","Ports",OPTIONS_TAB,IP_RW,60,IPS_IDLE); IUFillText(&JoystickInfoT[0],"JOYSTICK_NAME","Name",""); IUFillText(&JoystickInfoT[1],"JOYSTICK_VERSION","Version",""); IUFillText(&JoystickInfoT[2],"JOYSTICK_NJOYSTICKS","# Joysticks",""); IUFillText(&JoystickInfoT[3],"JOYSTICK_NAXES","# Axes",""); IUFillText(&JoystickInfoT[4],"JOYSTICK_NBUTTONS","# Buttons",""); IUFillTextVector(&JoystickInfoTP,JoystickInfoT,5,getDeviceName(),"JOYSTICK_INFO","Joystick Info",MAIN_CONTROL_TAB,IP_RO,60,IPS_IDLE); addDebugControl(); return true; } bool JoyStick::updateProperties() { INDI::DefaultDevice::updateProperties(); char buf[8]; if (isConnected()) { // Name IUSaveText(&JoystickInfoT[0], driver->getName()); // Version snprintf(buf, 8, "%d", driver->getVersion()); IUSaveText(&JoystickInfoT[1], buf); // # of Joysticks snprintf(buf, 8, "%d", driver->getNumOfJoysticks()); IUSaveText(&JoystickInfoT[2], buf); // # of Axes snprintf(buf, 8, "%d", driver->getNumOfAxes()); IUSaveText(&JoystickInfoT[3], buf); // # of buttons snprintf(buf, 8, "%d", driver->getNumrOfButtons()); IUSaveText(&JoystickInfoT[4], buf); defineText(&JoystickInfoTP); for (int i=0; i < driver->getNumOfJoysticks(); i++) defineNumber(&JoyStickNP[i]); defineNumber(&AxisNP); defineSwitch(&ButtonSP); // N.B. Only set callbacks AFTER we define our properties above // because these calls backs otherwise can be called asynchronously // and they mess up INDI XML output driver->setJoystickCallback(joystickHelper); driver->setAxisCallback(axisHelper); driver->setButtonCallback(buttonHelper); } else { deleteProperty(JoystickInfoTP.name); for (int i=0; i < driver->getNumOfJoysticks(); i++) deleteProperty(JoyStickNP[i].name); deleteProperty(AxisNP.name); deleteProperty(ButtonSP.name); delete [] JoyStickNP; delete [] JoyStickN; delete [] AxisN; delete [] ButtonS; } return true; } void JoyStick::ISGetProperties (const char *dev) { INDI::DefaultDevice::ISGetProperties(dev); defineText(&PortTP); if (isConnected()) { for (int i=0; i < driver->getNumOfJoysticks(); i++) defineNumber(&JoyStickNP[i]); defineNumber(&AxisNP); defineSwitch(&ButtonSP); } } bool JoyStick::ISSnoopDevice (XMLEle *root) { return INDI::DefaultDevice::ISSnoopDevice(root); } bool JoyStick::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if(strcmp(name,PortTP.name)==0) { PortTP.s=IPS_OK; IUUpdateText(&PortTP,texts,names,n); // Update client display IDSetText(&PortTP,NULL); return true; } } return DefaultDevice::ISNewText(dev,name,texts,names,n); } void JoyStick::joystickHelper(int joystick_n, double mag, double angle) { joystick->joystickEvent(joystick_n, mag, angle); } void JoyStick::buttonHelper(int button_n, int value) { joystick->buttonEvent(button_n, value); } void JoyStick::axisHelper(int axis_n, int value) { joystick->axisEvent(axis_n, value); } void JoyStick::joystickEvent(int joystick_n, double mag, double angle) { if (isConnected() == false) return; if (isDebug()) IDLog("joystickEvent[%d]: %g @ %g\n", joystick_n, mag, angle); if (mag == 0) JoyStickNP[joystick_n].s = IPS_IDLE; else JoyStickNP[joystick_n].s = IPS_BUSY; JoyStickNP[joystick_n].np[0].value = mag; JoyStickNP[joystick_n].np[1].value = angle; IDSetNumber(&JoyStickNP[joystick_n], NULL); } void JoyStick::axisEvent(int axis_n, int value) { if (isConnected() == false) return; if (isDebug()) IDLog("axisEvent[%d]: %d\n", axis_n, value); if (value == 0) AxisNP.s = IPS_IDLE; else AxisNP.s = IPS_BUSY; AxisNP.np[axis_n].value = value; IDSetNumber(&AxisNP, NULL); } void JoyStick::buttonEvent(int button_n, int value) { if (isConnected() == false) return; if (isDebug()) IDLog("buttonEvent[%d]: %s\n", button_n, value > 0 ? "On" : "Off"); ButtonSP.s = IPS_OK; ButtonS[button_n].s = (value == 0 )? ISS_OFF : ISS_ON; IDSetSwitch(&ButtonSP, NULL); } libindi-0.9.7/drivers/auxiliary/joystickdriver.cpp0000644000175000017500000001347112241463551021376 0ustar jasemjasem/******************************************************************************* Copyright(c) 2012 Jasem Mutlaq. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #include #include "joystickdriver.h" JoyStickDriver::JoyStickDriver() { active = false; pollMS = 100; joystick_fd = 0; joystick_ev = new js_event(); joystick_st = new joystick_state(); strncpy(dev_path, JOYSTICK_DEV, 256); joystickCallbackFunc = joystickEvent; axisCallbackFunc = axisEvent; buttonCallbackFunc = buttonEvent; } JoyStickDriver::~JoyStickDriver() { Disconnect(); delete joystick_st; delete joystick_ev; } void JoyStickDriver::setJoystickCallback(joystickFunc JoystickCallback) { joystickCallbackFunc = JoystickCallback; } void JoyStickDriver::setAxisCallback(axisFunc AxisCallback) { axisCallbackFunc = AxisCallback; } void JoyStickDriver::setButtonCallback(buttonFunc buttonCallback) { buttonCallbackFunc = buttonCallback; } void JoyStickDriver::setPort(const char *port) { strncpy(dev_path, port, 256); } bool JoyStickDriver::Connect() { joystick_fd = open(dev_path, O_RDONLY | O_NONBLOCK); if (joystick_fd > 0) { ioctl(joystick_fd, JSIOCGNAME(256), name); ioctl(joystick_fd, JSIOCGVERSION, &version); ioctl(joystick_fd, JSIOCGAXES, &axes); ioctl(joystick_fd, JSIOCGBUTTONS, &buttons); joystick_st->axis.reserve(axes); joystick_st->button.reserve(buttons); active = true; pthread_create(&thread, 0, &JoyStickDriver::loop, this); return true; } return false; } bool JoyStickDriver::Disconnect() { if (joystick_fd > 0) { active = false; pthread_join(thread, 0); close(joystick_fd); } joystick_fd = 0; return true; } void* JoyStickDriver::loop(void *obj) { while (reinterpret_cast(obj)->active) reinterpret_cast(obj)->readEv(); } void JoyStickDriver::readEv() { int bytes = read(joystick_fd, joystick_ev, sizeof(*joystick_ev)); if (bytes > 0) { joystick_ev->type &= ~JS_EVENT_INIT; if (joystick_ev->type & JS_EVENT_BUTTON) { joystick_st->button[joystick_ev->number] = joystick_ev->value; buttonCallbackFunc(joystick_ev->number, joystick_ev->value); } if (joystick_ev->type & JS_EVENT_AXIS) { joystick_st->axis[joystick_ev->number] = joystick_ev->value; int joystick_n = joystick_ev->number; if (joystick_n % 2 != 0) joystick_n--; joystick_position pos = joystickPosition(joystick_n); joystickCallbackFunc(joystick_n/2, pos.r, pos.theta); axisCallbackFunc(joystick_ev->number, joystick_ev->value); } } else usleep(pollMS*1000); } joystick_position JoyStickDriver::joystickPosition(int n) { joystick_position pos; if (n > -1 && n < axes) { int i0 = n, i1 = n+1; float x0 = joystick_st->axis[i0]/32767.0f, y0 = -joystick_st->axis[i1]/32767.0f; float x = x0 * sqrt(1 - pow(y0, 2)/2.0f), y = y0 * sqrt(1 - pow(x0, 2)/2.0f); pos.x = x0; pos.y = y0; pos.theta = atan2(y, x) * (180.0/3.141592653589); pos.r = sqrt(pow(y, 2) + pow(x, 2)); // For direction keys and scale/throttle keys if (pos.r == 0) { pos.r = -joystick_st->axis[i1]; if (pos.r < 0) { // Left if ((i0 % 2 == 0)) pos.theta = 180; // Down else pos.theta = 270; } else { // Up if ((i0 % 2 == 0)) pos.theta = 90; // Right else pos.theta = 0; } } else if (pos.theta<0) pos.theta += 360; // Make sure to reset angle if magnitude is zero if (pos.r == 0) pos.theta = 0; } else { pos.theta = pos.r = pos.x = pos.y = 0.0f; } return pos; } bool JoyStickDriver::buttonPressed(int n) { return n > -1 && n < buttons ? joystick_st->button[n] : 0; } void JoyStickDriver::setPoll(int ms) { pollMS = ms; } void JoyStickDriver::joystickEvent(int joystick_n, double mag, double angle) { (void)joystick_n; (void)mag; (void)angle; } void JoyStickDriver::axisEvent(int axis_n, int value) { (void)axis_n; (void)value; } void JoyStickDriver::buttonEvent(int button_n, int button_value) { (void)button_n; (void)button_value; } const char * JoyStickDriver::getName() { return name; } __u32 JoyStickDriver::getVersion() { return version; } __u8 JoyStickDriver::getNumOfJoysticks() { return axes/2; } __u8 JoyStickDriver::getNumOfAxes() { return axes; } __u8 JoyStickDriver::getNumrOfButtons() { return buttons; } libindi-0.9.7/drivers/video/0000755000175000017500000000000012241463551014710 5ustar jasemjasemlibindi-0.9.7/drivers/video/indi_v4l.cpp0000644000175000017500000000375212241463551017133 0ustar jasemjasem#if 0 V4L INDI Driver INDI Interface for V4L devices Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 "v4ldriver.h" V4L_Driver *MainCam = NULL; /* Main and only camera */ /* send client definitions of all properties */ void ISInit() { if (MainCam == NULL) { MainCam = new V4L_Driver(); MainCam->initProperties("Generic Video4Linux"); MainCam->initCamBase(); } } void ISGetProperties (const char *dev) { ISInit(); MainCam->ISGetProperties(dev); } void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); MainCam->ISNewSwitch(dev, name, states, names, n); } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); MainCam->ISNewText(dev, name, texts, names, n); } void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); MainCam->ISNewNumber(dev, name, values, names, n); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {} void ISSnoopDevice (XMLEle *root) {} libindi-0.9.7/drivers/video/stv.c0000644000175000017500000014306212241463551015676 0ustar jasemjasem#if 0 STV Driver Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch 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 /* Standard headers */ #include #include #include #include #include #ifndef _WIN32 #include #endif /* INDI Core headers */ #include "indidevapi.h" /* INDI Eventloop mechanism */ #include "eventloop.h" /* INDI Common Routines/RS232 */ #include "indicom.h" /* Config parameters */ #include /* Fits */ #include /* STV's definitions */ #include "stvdriver.h" /* Definitions */ #define mydev "STV Guider" /* Device name */ #define CONNECTION_GROUP "Connection" /* Group name */ #define SETTINGS_GROUP "Setings" /* Group name */ #define BUTTONS_GROUP "Buttons and Knobs" /* Button Pannel */ #define IMAGE_GROUP "Download" /* Button Pannel */ #define currentBuffer BufferN[0].value #define currentX WindowingN[0].value #define currentY WindowingN[1].value #define currentLines WindowingN[2].value #define currentLength WindowingN[3].value #define currentCompression CompressionS[0].s static int compression= OFF ; static int acquiring= OFF ; static int guiding= OFF ; static int processing= OFF ; /* Fits (fli_ccd project) */ enum STVFrames { LIGHT_FRAME = 0, BIAS_FRAME, DARK_FRAME, FLAT_FRAME }; #define TEMPFILE_LEN 16 /* Image (fli_ccd project)*/ typedef struct { int width; int height; int frameType; int expose; unsigned short *img; } img_t; static img_t *STVImg; /* Function adapted from fli_ccd project */ void addFITSKeywords(fitsfile *fptr, IMAGE_INFO *image_info) ; int writeFITS(const char* filename, IMAGE_INFO *image_info, char errmsg[]) ; void uploadFile(const char* filename) ; /* File descriptor and call back id */ int fd ; static int cb= -1 ; char tracking_buf[1024] ; /* Function prototypes */ int ISTerminateTXDisplay(void) ; int ISRestoreTXDisplay(void) ; int ISMessageImageInfo( int buffer, IMAGE_INFO *image_info) ; int ISRequestImageData( int compression, int buffer, int x_offset, int y_offset, int length, int lines) ; int STV_LRRotaryDecrease(void) ; int STV_LRRotaryIncrease(void) ; int STV_UDRotaryDecrease(void) ; int STV_UDRotaryIncrease(void) ; int STV_AKey(void) ; int STV_BKey(void) ; int STV_Setup(void) ; int STV_Interrupt(void) ; int STV_Focus(void) ; int STV_Image(void) ; int STV_Monitor(void) ; int STV_Calibrate(void) ; int STV_Track(void) ; int STV_Display(void) ; int STV_FileOps(void) ; int STV_RequestImageInfo(int imagebuffer, IMAGE_INFO *image_info) ; int STV_BufferStatus(int buffer) ; int STV_RequestImage( int compression, int buffer, int x_offset, int y_offset, int *length, int *lines, int image[][320], IMAGE_INFO *image_info) ; int STV_Download( void) ; int STV_TXDisplay(void) ; int STV_TerminateTXDisplay(void) ; int STV_RequestAck(void) ; unsigned int STV_GetBits( unsigned int x, int p, int n) ; int STV_PrintBuffer( unsigned char *cmdbuf, int n ); void handleError(ISwitchVectorProperty *svp, int err, const char *msg) ; static void ISInit() ; void ISCallBack(void) ; int init_serial(char *device_name, int bit_rate, int word_size, int parity, int stop_bits) ; int STV_ReceivePacket( unsigned char *buf, int mode) ; int STV_Connect( char *device, int baud) ; #ifdef HAVE_NOVA_H int STV_SetDateTime( char *times) ; #endif double STV_SetCCDTemperature(double set_value) ; static IText StatusT[]= { {"STATUS", "This driver", "is experimental, contact markus.wildi@datacomm.ch", 0, 0, 0}, }; static ITextVectorProperty StatusTP= { mydev, "STAUS", "Status", CONNECTION_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, StatusT, NARRAY(StatusT), "", 0 } ; /* RS 232 Connection */ static ISwitch PowerS[] = { {"CONNECT", "Connect", ISS_OFF, 0, 0}, {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty PowerSP = { mydev, "CONNECTION", "Connection", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0 }; /* Serial Port */ static IText PortT[]= { {"PORT", "Port", NULL, 0, 0, 0}, {"SPEED", "Speed", NULL, 0, 0, 0} }; static ITextVectorProperty PortTP= { mydev, "DEVICE_PORT", "Port", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, PortT, NARRAY(PortT), "", 0 } ; static ISwitch TXDisplayS[]= { {"1", "On", ISS_ON, 0, 0}, {"2", "Off", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty TXDisplaySP= { mydev, "Update Display", "Update Display", CONNECTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TXDisplayS, NARRAY(TXDisplayS), "", 0 } ; static IText DisplayCT[]= { {"DISPLAYC1", "Line 1", NULL, 0, 0, 0}, {"DISPLAYC2", "Line 2", NULL, 0, 0, 0} }; static ITextVectorProperty DisplayCTP= { mydev, "DISPLAYC", "Display", CONNECTION_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayCT, NARRAY(DisplayCT), "", 0 } ; static IText DisplayBT[]= { {"DISPLAYB1", "Line 1", NULL, 0, 0, 0}, {"DISPLAYB2", "Line 2", NULL, 0, 0, 0} }; static ITextVectorProperty DisplayBTP= { mydev, "DISPLAYB", "Display", BUTTONS_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayBT, NARRAY(DisplayBT), "", 0 } ; static IText DisplayDT[]= { {"DISPLAYD1", "Line 1", NULL, 0, 0, 0}, {"DISPLAYD2", "Line 2", NULL, 0, 0, 0} }; static ITextVectorProperty DisplayDTP= { mydev, "DISPLAYD", "Display", IMAGE_GROUP, IP_RO, ISR_1OFMANY, IPS_IDLE, DisplayDT, NARRAY(DisplayDT), "", 0 } ; /* Setings */ static IText UTCT[] = {{"UTC", "UTC", NULL, 0, 0, 0}}; ITextVectorProperty UTCTP = { mydev, "TIME_UTC", "UTC Time", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, UTCT, NARRAY(UTCT), "", 0}; static INumber SetCCDTemperatureN[]= { { "TEMPERATURE", "Cel. -55.1, +25.2", "%6.1f", -55.8, 25.2, 0.,16., 0, 0, 0}, } ; static INumberVectorProperty SetCCDTemperatureNP= { mydev, "CCD_TEMPERATURE", "CCD Temperature", SETTINGS_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, SetCCDTemperatureN, NARRAY(SetCCDTemperatureN), "", 0 } ; /* Buttons */ static ISwitch ControlS[]= { {"1", "Parameter", ISS_OFF, 0, 0}, {"2", "Increase", ISS_OFF, 0, 0}, {"3", "Decrease", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty ControlSP= { mydev, "ParaButtons", "Control", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ControlS, NARRAY(ControlS), "", 0 } ; static ISwitch ValueS[]= { {"1", "Value", ISS_OFF, 0, 0}, {"2", "Increase", ISS_OFF, 0, 0}, {"3", "Decrease", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty ValueSP= { mydev, "ValueButtons", "Control", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ValueS, NARRAY(ValueS), "", 0 } ; static ISwitch AuxiliaryS[]= { {"1", "Setup", ISS_OFF, 0, 0}, {"2", "Interrupt", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty AuxiliarySP= { mydev, "Auxilliary", "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AuxiliaryS, NARRAY(AuxiliaryS), "", 0 } ; static ISwitch AcquireS[]= { {"1", "Focus", ISS_OFF, 0, 0}, {"2", "Image", ISS_OFF, 0, 0}, {"3", "Monitor", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty AcquireSP= { mydev, "Acquire", "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AcquireS, NARRAY(AcquireS), "", 0 } ; static ISwitch GuideS[]= { {"1", "Calibrate", ISS_OFF, 0, 0}, {"2", "Track", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty GuideSP= { mydev, "Guide", "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, GuideS, NARRAY(GuideS), "", 0 } ; static ISwitch ProcessS[]= { {"1", "Display/Crosshairs", ISS_OFF, 0, 0}, {"2", "File Ops", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty ProcessSP= { mydev, "Process", "", BUTTONS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ProcessS, NARRAY(ProcessS), "", 0 } ; static ISwitch CompressionS[]= { {"1", "On", ISS_OFF, 0, 0}, {"2", "Off", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty CompressionSP= { mydev, "Compression", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, CompressionS, NARRAY(CompressionS), "", 0 } ; static ISwitch BufferStatusS[]= { {"1", "Status", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty BufferStatusSP= { mydev, "Buffers", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, BufferStatusS, NARRAY(BufferStatusS), "", 0 } ; static INumber BufferN[]= { { "A0", "Number 1 - 32", "%6.0f", 1., 32., 0.,32., 0, 0, 0}, } ; static INumberVectorProperty BufferNP= { mydev, "BUFFER_Number", "Buffer", IMAGE_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, BufferN, NARRAY(BufferN), "", 0 } ; static INumber WindowingN[]= { { "X", "Offset x", "%6.0f", 0., 199., 0., 0., 0, 0, 0}, { "Y", "Offset y", "%6.0f", 0., 319., 0., 0., 0, 0, 0}, { "HEIGHT", "Lines", "%6.0f", 1., 200., 0., 200., 0, 0, 0}, { "WIDTH", "Length", "%6.0f", 1., 320., 0., 320., 0, 0, 0}, } ; static INumberVectorProperty WindowingNP= { mydev, "CCD_FRAME", "Windowing", IMAGE_GROUP, IP_RW, ISR_1OFMANY, IPS_IDLE, WindowingN, NARRAY(WindowingN), "", 0 } ; static ISwitch ImageInfoS[]= { {"1", "One Image", ISS_OFF, 0, 0}, {"2", "All Images", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty ImageInfoSP= { mydev, "Information", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ImageInfoS, NARRAY(ImageInfoS), "", 0 } ; static ISwitch DownloadS[]= { {"1", "One Image", ISS_OFF, 0, 0}, {"2", "All Images", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty DownloadSP= { mydev, "Download", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DownloadS, NARRAY(DownloadS), "", 0 } ; /* BLOB for sending image */ static IBLOB imageB= {"CCD1", "Image", "", 0, 0, 0, 0, 0, 0, 0}; static IBLOBVectorProperty imageBP= {mydev, "Image", "Image", IMAGE_GROUP, IP_RO, 0, IPS_IDLE, &imageB, 1, "", 0}; /* Initlization routine */ static void ISInit() { static int isInit= 0; if( isInit) return; IUSaveText( &PortT[0], "/dev/ttyUSB0"); IUSaveText( &PortT[1], "115200"); if(( DisplayCT[0].text= malloc( 1024))== NULL){ fprintf(stderr,"3:Memory allocation error"); return; } if((DisplayCT[1].text = malloc( 1024))== NULL){ fprintf(stderr,"4:Memory allocation error"); return; } if(( DisplayBT[0].text= malloc( 1024))== NULL){ fprintf(stderr,"5:Memory allocation error"); return; } if(( DisplayBT[1].text= malloc( 1024))== NULL){ fprintf(stderr,"5:Memory allocation error"); return; } if(( DisplayDT[0].text= malloc( 1024))== NULL){ fprintf(stderr,"7:Memory allocation error"); return; } if(( DisplayDT[1].text= malloc( 1024))== NULL){ fprintf(stderr,"8:Memory allocation error"); return; } if(( STVImg= malloc( sizeof(img_t)))== NULL){ fprintf(stderr,"9:Memory allocation error"); return; } isInit = 1; } void ISResetButtons( char *message) { ControlSP.s= IPS_IDLE ; IUResetSwitch(&ControlSP); IDSetSwitch(&ControlSP, NULL); ValueSP.s= IPS_IDLE ; IUResetSwitch(&ValueSP); IDSetSwitch(&ValueSP, NULL); AuxiliarySP.s= IPS_IDLE ; IUResetSwitch(&AuxiliarySP); IDSetSwitch(&AuxiliarySP, NULL); AcquireSP.s= IPS_IDLE ; IUResetSwitch(&AcquireSP); IDSetSwitch(&AcquireSP, NULL); GuideSP.s= IPS_IDLE ; IUResetSwitch(&GuideSP); IDSetSwitch(&GuideSP, NULL); ProcessSP.s= IPS_IDLE ; IUResetSwitch(&ProcessSP); IDSetSwitch(&ProcessSP, NULL); ImageInfoSP.s= IPS_IDLE ; IUResetSwitch(&ImageInfoSP); IDSetSwitch(&ImageInfoSP, NULL); BufferStatusSP.s= IPS_IDLE ; IUResetSwitch(&BufferStatusSP); IDSetSwitch(&BufferStatusSP, NULL); /* SP.s= IPS_IDLE ; */ /* IUResetSwitch(&SP); */ /* IDSetSwitch(&SP, NULL); */ DownloadSP.s= IPS_IDLE ; IUResetSwitch(&DownloadSP); IDSetSwitch(&DownloadSP, "%s", message); return ; } /* This function is called when ever the file handle fd provides data */ void ISCallBack() { int res ; int k,l,m ; unsigned char buf[1024] ; IERmCallback( cb) ; cb = -1 ; /* fprintf( stderr, "ISCallBack\n") ; */ /* if(( counter++ % 4) ==0){ */ /* fprintf( stderr, ".") ; */ /* } */ if( PowerS[0].s == ISS_ON) { res= STV_ReceivePacket( buf, guiding) ; /* res= STV_PrintBuffer(buf,res) ; */ DisplayCTP.s= IPS_IDLE ; IDSetText( &DisplayCTP, NULL) ; DisplayBTP.s= IPS_IDLE ; IDSetText( &DisplayBTP, NULL) ; DisplayDTP.s= IPS_IDLE ; IDSetText( &DisplayDTP, NULL) ; switch ((int) buf[1]) { /* STV cmd byte */ case DISPLAY_ECHO: if( res < 0 ) { DisplayCTP.s= IPS_ALERT ; IDSetText( &DisplayCTP, NULL) ; DisplayBTP.s= IPS_ALERT ; IDSetText( &DisplayBTP, NULL) ; DisplayDTP.s= IPS_ALERT ; IDSetText( &DisplayDTP, NULL) ; IDMessage(mydev, "Error while reading, continuing\n"); } else { l= 0 ; m= 0 ; /* replace unprintable characters and format the string */ for( k= 0; k < 24; k++) { if( buf[k+ 6]== 0x5e) { /* first line */ DisplayCT[0].text[l-1]= 0x50 ; /* P */ DisplayCT[0].text[l++] = 0x6b ; /* k */ } else if( buf[k+ 6]== 0xd7) { DisplayCT[0].text[l++]= 0x28 ; /* "(x,y) " */ DisplayCT[0].text[l++]= 0x78 ; DisplayCT[0].text[l++]= 0x2c ; DisplayCT[0].text[l++]= 0x79 ; DisplayCT[0].text[l++]= 0x29 ; DisplayCT[0].text[l++]= 0x20 ; } else if( buf[k+ 6] >29 && buf[k+ 6] < 127) { DisplayCT[0].text[l++]= buf[k+ 6] ; } else { /* 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]) ; */ DisplayCT[0].text[l++]= 0x20 ; } if( buf[k+ 30]== 0xb0){ /* second line */ DisplayCT[1].text[m++]= 0x43 ; /* Celsius */ } else if( buf[k+ 30] >29 && buf[k +30] < 127) { DisplayCT[1].text[m++]=buf[k + 30] ; } else { /* 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]) ; */ DisplayCT[1].text[m++]= 0x20 ; } } DisplayCT[0].text[l]= 0 ; DisplayCT[1].text[m]= 0 ; strcpy(DisplayBT[0].text, DisplayCT[0].text) ; strcpy(DisplayBT[1].text, DisplayCT[1].text) ; strcpy(DisplayDT[0].text, DisplayCT[0].text) ; strcpy(DisplayDT[1].text, DisplayCT[1].text) ; DisplayCTP.s= IPS_OK ; IDSetText( &DisplayCTP, NULL) ; DisplayBTP.s= IPS_OK ; IDSetText( &DisplayBTP, NULL) ; DisplayDTP.s= IPS_OK ; IDSetText( &DisplayDTP, NULL) ; } break ; case REQUEST_DOWNLOAD: /* fprintf(stderr, "STV says REQUEST_DOWNLOAD\n") ; */ if( TXDisplayS[0].s == ISS_ON) { res= STV_Download() ; imageB.blob = NULL; imageB.bloblen = 0; imageB.size = 0; imageBP.s = IPS_ALERT; IDSetBLOB (&imageBP, NULL); IDMessage( mydev, "Switch off display read out manually first (Update Display: Off\n)") ; } else { tcflush(fd, TCIOFLUSH); usleep( 100000) ; res= ISRequestImageData( 1, 31, 0, 0, 320, 200) ; /* Download the on screen image (buffer 32 -1) */ } /*fprintf(stderr, "STV END REQUEST_DOWNLOAD\n") ; */ break ; case REQUEST_DOWNLOAD_ALL: IDMessage(mydev, "REQUEST_DOWNLOAD_ALL initiated at the STV not implemented") ; break ; case ACK: if( cb == -1) { strcpy(DisplayCT[0].text, "Key press acknowledged") ; strcpy(DisplayBT[0].text, DisplayCT[0].text) ; strcpy(DisplayDT[0].text, DisplayCT[0].text) ; DisplayCTP.s= IPS_OK ; IDSetText( &DisplayCTP, NULL) ; DisplayBTP.s= IPS_OK ; IDSetText( &DisplayBTP, NULL) ; DisplayDTP.s= IPS_OK ; IDSetText( &DisplayDTP, NULL) ; } break ; case NACK: /*fprintf(stderr, "STV says NACK!!") ; */ IDMessage(mydev, "STV says NACK!") ; break ; case REQUEST_BUFFER_STATUS: IDMessage(mydev, "Request Buffer status seen, ignoring\n") ; break ; default: if( guiding== ON) {/* While STV is tracking, it send time, brightnes, centroid x,y */ IDMessage( mydev, "Tracking: %s", tracking_buf) ; } else { /*fprintf(stderr, "STV ISCallBack: Unknown response 0x%2x\n", buf[1]) ; */ IDLog("ISCallBack: Unknown response 0x%2x\n", buf[1]) ; } break ; } } cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ; } /* Client retrieves properties */ void ISGetProperties (const char *dev) { /* #1 Let's make sure everything has been initialized properly */ ISInit(); /* #2 Let's make sure that the client is asking for the properties of our device, otherwise ignore */ if (dev && strcmp (mydev, dev)) return; /* #3 Tell the client to create new properties */ /* Connection tab */ IDDefText(&DisplayCTP, NULL) ; IDDefSwitch(&PowerSP, NULL) ; IDDefText(&PortTP, NULL) ; IDDefSwitch(&TXDisplaySP, NULL) ; IDDefText(&StatusTP, NULL) ; /* Settings Tab */ IDDefText(&UTCTP, NULL) ; IDDefNumber(&SetCCDTemperatureNP, NULL) ; /* Buttons tab */ IDDefText(&DisplayBTP, NULL) ; IDDefSwitch(&ControlSP, NULL) ; IDDefSwitch(&ValueSP, NULL) ; IDDefSwitch(&AuxiliarySP, NULL) ; IDDefSwitch(&AcquireSP, NULL) ; IDDefSwitch(&GuideSP, NULL) ; IDDefSwitch(&ProcessSP, NULL) ; /* Image tab */ IDDefText(&DisplayDTP, NULL) ; /* "direct" read out does not work well IDDefSwitch(&BufferStatusSP, NULL) ; */ IDDefSwitch(&BufferStatusSP, NULL) ; IDDefSwitch(&ImageInfoSP, NULL); IDDefNumber(&BufferNP, NULL); IDDefSwitch(&DownloadSP, NULL) ; IDDefSwitch(&CompressionSP, NULL) ; IDDefNumber(&WindowingNP, NULL); IDDefBLOB(&imageBP, NULL); } /* Client sets new switch */ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int i, j ; int res = 0; int baud ; IMAGE_INFO image_info ; ISwitch *sp ; int lower_buffer = 0; int upper_buffer = 0 ; /*fprintf(stderr, "ISNewSwitch\n") ; */ /* #1 Let's make sure everything has been initialized properly */ ISInit(); /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */ if (dev && strcmp (dev, mydev)) return; /* #3 Now let's check if the property the client wants to change is the PowerSP (name: CONNECTION) property*/ if( !strcmp (name, PowerSP.name)) { /* A. We reset all switches (in this case CONNECT and DISCONNECT) to ISS_OFF */ IUResetSwitch(&PowerSP); /* B. We update the switches by sending their names and updated states IUUpdateSwitch function */ IUUpdateSwitch(&PowerSP, states, names, n); /* C. We try to establish a connection to our device or terminate it*/ int res= 0 ; switch (PowerS[0].s) { case ISS_ON: if(( res= strcmp( "9600", PortT[1].text)) ==0) { baud= 9600 ; } else if(( res= strcmp( "19200", PortT[1].text)) ==0) { baud= 19200 ; } else if( (res= strcmp( "38400", PortT[1].text)) ==0) { baud= 38400 ; } else if(( res= strcmp( "57600", PortT[1].text)) ==0) { baud= 57600 ; } else if(( res= strcmp( "115200", PortT[1].text)) ==0) { baud= 115200 ; } else { IUSaveText(&PortT[1], "9600"); IDSetText(&PortTP, "Wrong RS 232 value: %s, defaulting to 9600 baud", PortT[1].text); return ; } if(( fd= STV_Connect( PortT[0].text, baud))== -1) { PowerSP.s = IPS_ALERT; IUResetSwitch( &PowerSP); IDSetSwitch( &PowerSP, "Error connecting to port %s", PortT[0].text); return; } else { cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ; /* The SBIG manual says one can request an ACK, never saw it, even not on a RS 232 tester */ if(( res= STV_RequestAck()) != 0) { fprintf( stderr, "COULD not write an ACK\n") ; } /* Second trial: start reading out the display */ if((res= STV_TXDisplay()) != 0) { fprintf(stderr, "STV: Could not write %d\n", res) ; return ; } } PowerSP.s = IPS_OK ; IDSetSwitch(&PowerSP, "STV is online, port: %s, baud rate: %s", PortT[0].text, PortT[1].text) ; PortTP.s = IPS_OK ; IDSetText(&PortTP, NULL); break; case ISS_OFF: IERmCallback( cb) ; cb = -1 ; /* Close the serial port */ tty_disconnect(fd); ISResetButtons(NULL) ; GuideSP.s= IPS_IDLE ; IUResetSwitch(&GuideSP); IDSetSwitch(&GuideSP, NULL); TXDisplaySP.s= IPS_IDLE ; IUResetSwitch(&TXDisplaySP); IDSetSwitch(&TXDisplaySP, NULL); DisplayCTP.s = IPS_IDLE; IDSetText (&DisplayCTP, NULL); DisplayBTP.s = IPS_IDLE; IDSetText (&DisplayBTP, NULL); DisplayDTP.s = IPS_IDLE; IDSetText (&DisplayDTP, NULL); PortTP.s = IPS_IDLE ; IDSetText(&PortTP, NULL) ; imageB.blob = NULL; imageB.bloblen = 0; imageB.size = 0; imageBP.s = IPS_IDLE; IDSetBLOB (&imageBP, NULL); PowerSP.s = IPS_IDLE; IUResetSwitch(&PowerSP); IDSetSwitch(&PowerSP, "STV is offline"); break; } return ; } else if( !strcmp (name, AuxiliarySP.name)) { /* Setup und interrupt buttons */ ISResetButtons(NULL) ; IUResetSwitch(&AuxiliarySP); IUUpdateSwitch(&AuxiliarySP, states, names, n); for( i = 0; i < n; i++) { sp = IUFindSwitch (&AuxiliarySP, names[i]) ; if( sp == &AuxiliaryS[0]){ res= STV_Setup() ; } else if( sp == &AuxiliaryS[1]){ res= STV_Interrupt() ; } } if( res== 0) { AuxiliarySP.s= IPS_OK ; IUResetSwitch(&AuxiliarySP) ; IDSetSwitch(&AuxiliarySP, NULL) ; } else { AuxiliarySP.s= IPS_ALERT ; IUResetSwitch(&AuxiliarySP) ; IDSetSwitch(&AuxiliarySP, "Check connection") ; } } else if( !strcmp (name, ControlSP.name)) { /* Parameter, value and the rotary knobs */ ISResetButtons(NULL) ; IUResetSwitch(&ControlSP); IUUpdateSwitch(&ControlSP, states, names, n); acquiring= OFF ; guiding= OFF ; processing= OFF ; for( i = 0; i < n; i++) { sp = IUFindSwitch (&ControlSP, names[i]) ; /* If the state found is ControlS[0] then process it */ if( sp == &ControlS[0]){ res= STV_AKey() ; } else if( sp == &ControlS[1]){ res= STV_UDRotaryIncrease() ; } else if( sp == &ControlS[2]){ res= STV_UDRotaryDecrease() ; } } if( res== 0) { ControlSP.s= IPS_OK ; IUResetSwitch(&ControlSP) ; IDSetSwitch(&ControlSP, NULL) ; } else { ControlSP.s= IPS_ALERT ; IUResetSwitch(&ControlSP) ; IDSetSwitch(&ControlSP, "Check connection") ; } } else if( !strcmp (name, ValueSP.name)) { /* Button Value, left/right knob */ ISResetButtons(NULL) ; IUResetSwitch(&ValueSP); IUUpdateSwitch(&ValueSP, states, names, n); acquiring= OFF ; guiding= OFF ; processing= OFF ; for( i = 0; i < n; i++) { sp = IUFindSwitch (&ValueSP, names[i]) ; if( sp == &ValueS[0]){ res= STV_BKey() ; } else if( sp == &ValueS[1]){ res= STV_LRRotaryIncrease() ; } else if( sp == &ValueS[2]){ res= STV_LRRotaryDecrease() ; } } if( res== 0) { ValueSP.s= IPS_OK ; IUResetSwitch(&ValueSP) ; IDSetSwitch(&ValueSP, NULL) ; } else { ValueSP.s= IPS_ALERT ; IUResetSwitch(&ValueSP) ; IDSetSwitch(&ValueSP, "Check connection") ; } } else if( !strcmp (name, AcquireSP.name)) { /* Focus, Image Monitor buttons */ ISResetButtons(NULL) ; IUResetSwitch(&AcquireSP); IUUpdateSwitch(&AcquireSP, states, names, n); acquiring= ON ; guiding= OFF ; processing= OFF ; for( i = 0; i < n; i++) { sp = IUFindSwitch (&AcquireSP, names[i]) ; if( sp == &AcquireS[0]){ res= STV_Focus() ; } else if( sp == &AcquireS[1]){ res= STV_Image() ; } else if( sp == &AcquireS[2]){ res= STV_Monitor() ; } } if( res== 0) { AcquireSP.s= IPS_OK ; IUResetSwitch(&AcquireSP) ; IDSetSwitch(&AcquireSP, NULL) ; } else { AcquireSP.s= IPS_ALERT ; IUResetSwitch(&AcquireSP) ; IDSetSwitch(&AcquireSP, "Check connection") ; } } else if( !strcmp (name, GuideSP.name)) { /* Calibrate, Track buttons */ ISResetButtons(NULL) ; IUResetSwitch(&GuideSP); IUUpdateSwitch(&GuideSP, states, names, n); acquiring= OFF ; guiding= ON ; processing= OFF ; for( i = 0; i < n; i++) { sp = IUFindSwitch (& GuideSP, names[i]) ; if( sp == & GuideS[0]){ res= STV_Calibrate() ; } else if( sp == &GuideS[1]){ res= STV_Track() ; } } if( res== 0) { GuideSP.s= IPS_OK ; IUResetSwitch(&GuideSP) ; IDSetSwitch(&GuideSP, NULL) ; } else { GuideSP.s= IPS_ALERT ; IUResetSwitch(&GuideSP) ; IDSetSwitch(&GuideSP, "Check connection") ; } } else if( !strcmp (name, ProcessSP.name)) { ISResetButtons(NULL) ; IUResetSwitch(&ProcessSP); IUUpdateSwitch(&ProcessSP, states, names, n); acquiring= OFF ; guiding= OFF ; processing= ON ; for( i = 0; i < n; i++) { sp = IUFindSwitch (&ProcessSP, names[i]) ; if( sp == &ProcessS[0]){ res= STV_Display() ; } else if( sp == &ProcessS[1]){ res= STV_FileOps() ; } } if( res== 0) { ProcessSP.s= IPS_OK ; IUResetSwitch(&ProcessSP) ; IDSetSwitch(&ProcessSP, NULL) ; } else { ProcessSP.s= IPS_ALERT ; IUResetSwitch(&ProcessSP) ; IDSetSwitch(&ProcessSP, "Check connection") ; } } else if( !strcmp (name, ImageInfoSP.name)) { acquiring= OFF ; guiding= OFF ; processing= OFF ; /* Read out the image buffer and display a short message if it is empty or not */ res= ISTerminateTXDisplay() ; for( i = 0; i < n; i++) { sp = IUFindSwitch( &ImageInfoSP, names[i]) ; if( sp == &ImageInfoS[0]){ if(( res= STV_RequestImageInfo( currentBuffer- 1, &image_info))== 0 ) { ISMessageImageInfo( (int)currentBuffer- 1, &image_info) ; } else { IDMessage( mydev, "Buffer %2d is empty", (int)currentBuffer) ; } break ; } else if( sp == &ImageInfoS[1]){ for( i= 0; i < 32 ; i++) { if(( res= STV_RequestImageInfo( i, &image_info))== 0 ) { ISMessageImageInfo( i, &image_info) ; } else { IDMessage( mydev, "Buffer %2d is empty", i+ 1) ; } } break ; } } if( res== 0) { ImageInfoSP.s= IPS_OK ; IUResetSwitch( &ImageInfoSP) ; IDSetSwitch( &ImageInfoSP, NULL) ; } else { ImageInfoSP.s= IPS_ALERT ; IUResetSwitch( &ImageInfoSP) ; /*IDSetSwitch( &ImageInfoSP, "Check connection") ; */ IDSetSwitch( &ImageInfoSP, NULL) ; } res= STV_Interrupt() ; /* STV initiates a download that we do not want */ res= ISRestoreTXDisplay() ; } else if( !strcmp (name, CompressionSP.name)) { acquiring= OFF ; guiding= OFF ; processing= OFF ; /* Enable or disable compression for image download */ ISResetButtons(NULL) ; IUResetSwitch(&CompressionSP); IUUpdateSwitch(&CompressionSP, states, names, n); for( i = 0; i < n; i++) { sp = IUFindSwitch (&CompressionSP, names[i]) ; if( sp == &CompressionS[0]){ CompressionS[0].s= ISS_ON ; } else if( sp == &CompressionS[1]){ CompressionS[1].s= ISS_ON ; } } CompressionSP.s= IPS_OK ; IDSetSwitch(&CompressionSP, NULL) ; } else if( !strcmp (name, BufferStatusSP.name)) { ISResetButtons(NULL) ; BufferStatusSP.s= IPS_ALERT ; IUResetSwitch(&BufferStatusSP) ; IDSetSwitch(&BufferStatusSP, "Wait...") ; if( ( AcquireSP.s != OFF) || ( GuideSP.s != OFF) || ( ProcessSP.s != OFF)) { acquiring= OFF ; guiding= OFF ; processing= OFF ; ISResetButtons( "Interrupting ongoing image acquisition, calibration or tracking\n") ; AcquireSP.s= IPS_IDLE ; IUResetSwitch(&AcquireSP); IDSetSwitch(&AcquireSP, NULL); GuideSP.s= IPS_IDLE ; IUResetSwitch(&GuideSP); IDSetSwitch(&GuideSP, NULL); ProcessSP.s= IPS_IDLE ; IUResetSwitch(&ProcessSP); IDSetSwitch(&ProcessSP, NULL); ImageInfoSP.s= IPS_IDLE ; IUResetSwitch(&ImageInfoSP); IDSetSwitch(&ImageInfoSP, NULL); res= STV_Interrupt() ; usleep(100000) ; res= STV_Interrupt() ; } acquiring= OFF ; guiding= OFF ; processing= OFF ; sp = IUFindSwitch (&BufferStatusSP, names[0]) ; if((res= ISTerminateTXDisplay()) != 0) { fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ; } if( sp == &BufferStatusS[0]) { for( i= 31; i > -1; i--) { usleep( 50000) ; if(( res= STV_BufferStatus( i))== 0) { IDMessage( mydev, "Buffer %2d: image present", i+ 1) ; } else { IDMessage( mydev, "Buffer %2d: empty", i+ 1) ; } } } BufferStatusS[0].s= ISS_OFF ; if( 0 <= res) { BufferStatusSP.s= IPS_OK ; IUResetSwitch(&BufferStatusSP) ; IDSetSwitch(&BufferStatusSP, NULL) ; } else { BufferStatusSP.s= IPS_ALERT ; IUResetSwitch(&BufferStatusSP) ; IDSetSwitch(&BufferStatusSP, "Check connection") ; } res= ISRestoreTXDisplay() ; res= STV_Interrupt() ; } else if( !strcmp (name, DownloadSP.name)) { /* Download images */ /* Downloading while the STV is occupied is not working */ if( ( AcquireSP.s != OFF) || ( GuideSP.s != OFF) || ( ProcessSP.s != OFF)) { ISResetButtons( "Interrupting ongoing image acquisition, calibration or tracking\n") ; AcquireSP.s= IPS_IDLE ; IUResetSwitch(&AcquireSP); IDSetSwitch(&AcquireSP, NULL); GuideSP.s= IPS_IDLE ; IUResetSwitch(&GuideSP); IDSetSwitch(&GuideSP, NULL); ProcessSP.s= IPS_IDLE ; IUResetSwitch(&ProcessSP); IDSetSwitch(&ProcessSP, NULL); ImageInfoSP.s= IPS_IDLE ; IUResetSwitch(&ImageInfoSP); IDSetSwitch(&ImageInfoSP, NULL); res= STV_Interrupt() ; usleep(100000) ; res= STV_Interrupt() ; } acquiring= OFF ; guiding= OFF ; processing= OFF ; if((res= ISTerminateTXDisplay()) != 0) { fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ; } DownloadSP.s= IPS_ALERT ; IUResetSwitch(&DownloadSP) ; IDSetSwitch(&DownloadSP, NULL) ; compression= OFF ; if( CompressionS[0].s == ISS_ON) { compression= ON ; } for( i = 0; i < n; i++) { sp = IUFindSwitch (&DownloadSP, names[i]) ; if( sp == &DownloadS[0]){ lower_buffer= currentBuffer- 2 ; upper_buffer= currentBuffer- 1 ; } else if( sp == &DownloadS[1]){ lower_buffer= -1 ; upper_buffer= 31 ; } } for( j= upper_buffer ; j> lower_buffer ; j--) { if((res= ISRequestImageData( compression, j, currentX, currentY, currentLength, currentLines)) != 0) { if( res== 1) { IDMessage( mydev, "Buffer %2.0f: empty", (double)(j+ 1)) ; } else { break ; } } } if( res== 0) { IDMessage( mydev, "STV waits for SYNC TIME Do it! Setting time, PLEASE WAIT!") ; #ifdef HAVE_NOVA_H if((res= STV_SetDateTime(NULL)) == 0) { UTCTP.s= IPS_OK ; IDSetText( &UTCTP, "Time set to UTC now") ; } else { UTCTP.s= IPS_ALERT ; IDSetText( &UTCTP, "Error setting time, check connection") ; } #endif DownloadSP.s= IPS_OK ; IUResetSwitch(&DownloadSP) ; IDSetSwitch(&DownloadSP, NULL) ; } else { /* res could be -1 (STV_RequestImageData) */ DownloadSP.s= IPS_ALERT ; IUResetSwitch(&DownloadSP) ; IDSetSwitch(&DownloadSP, "Check connection") ; IDSetSwitch(&DownloadSP, NULL) ; } res= ISRestoreTXDisplay() ; res= STV_Interrupt() ; IDMessage( mydev, "You may continue NOW") ; } else if( !strcmp (name, TXDisplaySP.name)) { acquiring= OFF ; guiding= OFF ; processing= OFF ; ISResetButtons(NULL) ; IUResetSwitch(&TXDisplaySP); IUUpdateSwitch(&TXDisplaySP, states, names, n); for( i = 0; i < n; i++) { sp= IUFindSwitch (&TXDisplaySP, names[i]) ; if( sp == &TXDisplayS[0]){ if((res= STV_TXDisplay()) == 0) { TXDisplaySP.s= IPS_OK ; IDSetSwitch( &TXDisplaySP, "Reading out display") ; DisplayCTP.s = IPS_OK ; IDSetText( &DisplayCTP, NULL); DisplayBTP.s = IPS_OK ; IDSetText( &DisplayBTP, NULL); DisplayDTP.s = IPS_OK ; IDSetText( &DisplayDTP, NULL); } } else if( sp== &TXDisplayS[1]){ DisplayCTP.s = IPS_IDLE ; DisplayBTP.s = IPS_IDLE ; DisplayDTP.s = IPS_IDLE ; if((res= STV_TerminateTXDisplay()) == 0) { TXDisplaySP.s = IPS_OK ; IDSetSwitch( &TXDisplaySP, "Stopping display read out") ; DisplayCTP.s = IPS_IDLE ; IUSaveText(&DisplayCT[0], " "); /* reset client's display */ IUSaveText(&DisplayCT[1], " "); IDSetText( &DisplayCTP, NULL); DisplayBTP.s = IPS_IDLE ; IUSaveText(&DisplayBT[0], " "); /* reset client's display */ IUSaveText(&DisplayBT[1], " "); IDSetText( &DisplayBTP, NULL); DisplayDTP.s = IPS_IDLE ; IUSaveText(&DisplayDT[0], " "); /* reset client's display */ IUSaveText(&DisplayDT[1], " "); IDSetText( &DisplayDTP, NULL); } } } if( res != 0) { TXDisplaySP.s= IPS_ALERT ; IUResetSwitch(&TXDisplaySP) ; IDSetSwitch(&TXDisplaySP, "Check connection") ; } } } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { int res ; IText *tp ; /*fprintf(stderr, "ISNewText\n") ; */ /* #1 Let's make sure everything has been initialized properly */ ISInit(); /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */ if ( dev && strcmp( dev, mydev)) return; if( !strcmp (name, PortTP.name)) { if (IUUpdateText(&PortTP, texts, names, n) < 0) return; PortTP.s = IPS_OK; if (PowerS[0].s == ISS_ON){ PortTP.s = IPS_ALERT; IDSetText(&PortTP, "STV is already online"); } /* JM: Don't forget to send acknowledgment */ IDSetText(&PortTP, NULL); } else if( !strcmp (name, UTCTP.name)) { ISResetButtons(NULL) ; tp= IUFindText (&UTCTP, names[0]) ; if((res= ISTerminateTXDisplay()) != 0) { fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ; } if( tp == &UTCT[0]) { #ifdef HAVE_NOVA_H if((res= STV_SetDateTime(NULL)) == 0) { UTCTP.s= IPS_OK ; IDSetText( &UTCTP, "Time set to UTC") ; } else { UTCTP.s= IPS_ALERT ; IDSetText( &UTCTP, "Error setting time, check connection") ; } #endif } res= ISRestoreTXDisplay() ; } } /* Client sets new number */ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { int res ; double ccd_temperature ; /*fprintf(stderr, "ISNewNumber\n") ; */ /* #1 Let's make sure everything has been initialized properly */ ISInit(); /* #2 Let's make sure that the client is asking to update the properties of our device, otherwise ignore */ if ( dev && strcmp( dev, mydev)) return; if (PowerS[0].s != ISS_ON){ PowerSP.s = IPS_ALERT; IDSetSwitch( &PowerSP, NULL) ; IDMessage("STV is offline", NULL); return ; } if( !strcmp (name, BufferNP.name)) { INumber *buffer = IUFindNumber( &BufferNP, names[0]) ; if( buffer == &BufferN[0]) { currentBuffer= values[0] ; /* Check the boundaries, this is incomplete at the moment */ BufferNP.s = IPS_OK ; IDSetNumber(&BufferNP, NULL) ; } } else if( !strcmp (name, WindowingNP.name)) { INumber *buffer = IUFindNumber( &WindowingNP, names[0]) ; if( buffer == &WindowingN[0]) { currentX = values[0] ; currentY = values[1] ; currentLines = values[2] ; currentLength= values[3] ; WindowingNP.s = IPS_OK ; IDSetNumber(&WindowingNP, NULL) ; } } else if( !strcmp (name, SetCCDTemperatureNP.name)) { if((res= ISTerminateTXDisplay()) != 0) { fprintf(stderr, "STV Buffer can not terminate TX %d\n", res) ; } INumber *np= IUFindNumber (&SetCCDTemperatureNP, names[0]) ; if( np == &SetCCDTemperatureN[0]) { if((ccd_temperature= STV_SetCCDTemperature(values[0])) != 0) { /* STV has no 0 C setting */ SetCCDTemperatureNP.s= IPS_OK ; SetCCDTemperatureN[0].value= ccd_temperature; IDSetNumber( &SetCCDTemperatureNP, "CCD Temperature set to %g", SetCCDTemperatureN[0].value) ; } else { SetCCDTemperatureNP.s= IPS_ALERT ; IDSetNumber( &SetCCDTemperatureNP, "Error setting CCD temperature, check connection") ; } } res= ISRestoreTXDisplay() ; } } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } int writeFITS(const char* filename, IMAGE_INFO *image_info, char errmsg[]) { fitsfile *fptr; /* pointer to the FITS file; defined in fitsio.h */ int status; long fpixel = 1, naxis = 2, nelements; long naxes[2]; char filename_rw[TEMPFILE_LEN+1]; naxes[0] = STVImg->width; naxes[1] = STVImg->height; /* Append ! to file name to over write it.*/ snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename); status = 0; /* initialize status before calling fitsio routines */ fits_create_file(&fptr, filename_rw, &status); /* create new file */ /* Create the primary array image (16-bit short integer pixels */ fits_create_img(fptr, USHORT_IMG, naxis, naxes, &status); addFITSKeywords(fptr, image_info); nelements = naxes[0] * naxes[1]; /* number of pixels to write */ /* Write the array of integers to the image */ fits_write_img(fptr, TUSHORT, fpixel, nelements, STVImg->img, &status); fits_close_file(fptr, &status); /* close the file */ fits_report_error(stderr, status); /* print out any error messages */ /* Success */ /*ExposeTimeNP.s = IPS_OK; */ /*IDSetNumber(&ExposeTimeNP, NULL); */ uploadFile(filename); return status; } void addFITSKeywords(fitsfile *fptr, IMAGE_INFO *image_info) { int status=0; char binning_s[32]; char frame_s[32]; char date_obs_s[64] ; char tmp[32] ; image_info->pixelSize= 7.4 ; /* microns */ if( image_info->binning== 1) { snprintf(binning_s, 32, "(%1.0f x %1.0f)", 1., 1.); } else if( image_info->binning== 2) { snprintf(binning_s, 32, "(%1.0f x %1.0f)", 2., 2.); } else if( image_info->binning== 3) { snprintf(binning_s, 32, "(%1.0f x %1.0f)", 3., 3.); } else { fprintf( stderr, "Error in binning information: %d\n", image_info->binning) ; } strcpy(frame_s, "Light"); /* ToDo: assign the frame type */ /* switch (STVImg->frameType) */ /* { */ /* case LIGHT_FRAME: */ /* strcpy(frame_s, "Light"); */ /* break; */ /* case BIAS_FRAME: */ /* strcpy(frame_s, "Bias"); */ /* break; */ /* case FLAT_FRAME: */ /* strcpy(frame_s, "Flat Field"); */ /* break; */ /* case DARK_FRAME: */ /* strcpy(frame_s, "Dark"); */ /* break; */ /* } */ fits_update_key(fptr, TDOUBLE, "CCD-TEMP", &(image_info->ccdTemp), "CCD Temperature (Celcius)", &status); fits_update_key(fptr, TDOUBLE, "EXPOSURE", &(image_info->exposure ), "Total Exposure Time (ms)", &status); fits_update_key(fptr, TDOUBLE, "PIX-SIZ", &(image_info->pixelSize), "Pixel Size (microns)", &status); fits_update_key(fptr, TSTRING, "BINNING", binning_s, "Binning HOR x VER", &status); fits_update_key(fptr, TSTRING, "FRAME", frame_s, "Frame Type", &status); fits_update_key(fptr, TDOUBLE, "DATAMIN", &(image_info->minValue), "Minimum value", &status); fits_update_key(fptr, TDOUBLE, "DATAMAX", &(image_info->maxValue), "Maximum value", &status); fits_update_key(fptr, TSTRING, "INSTRUME", "SBIG STV", "CCD Name", &status); sprintf( tmp, "%4d-",image_info->year) ; strcpy( date_obs_s,tmp ) ; if( image_info->month< 10) { sprintf( tmp, "0%1d-", image_info->month) ; } else { sprintf( tmp, "%2d-", image_info->month) ; } strcat( date_obs_s, tmp) ; if( image_info->day< 10) { sprintf( tmp, "0%1dT", image_info->day) ; } else { sprintf( tmp, "%2dT", image_info->day) ; } strcat( date_obs_s, tmp) ; if( image_info->hours< 10) { sprintf( tmp, "0%1d:", image_info->hours) ; } else { sprintf( tmp, "%2d:", image_info->hours) ; } strcat( date_obs_s, tmp) ; if( image_info->minutes< 10) { sprintf( tmp, "0%1d:",image_info->minutes) ; } else { sprintf( tmp, "%2d:", image_info->minutes) ; } strcat( date_obs_s, tmp) ; if( image_info->seconds< 10) { sprintf( tmp, "0%1d:", image_info->seconds) ; } else { sprintf( tmp, "%2d:", image_info->seconds) ; } strcat( date_obs_s, tmp) ; fits_update_key(fptr, TSTRING, "DATE-OBS", date_obs_s, "Observing date (YYYY-MM-DDThh:mm:ss UT", &status); fits_write_date(fptr, &status); } void uploadFile(const char* filename) { FILE * fitsFile; unsigned char *fitsData, *compressedData; int r=0; unsigned int i =0, nr = 0; uLongf compressedBytes=0; uLong totalBytes; struct stat stat_p; if ( -1 == stat (filename, &stat_p)) { IDLog("Error occurred attempting to stat file.\n"); return; } totalBytes = stat_p.st_size; fitsData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes); compressedData = (unsigned char *) malloc (sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3); if (fitsData == NULL || compressedData == NULL) { if (fitsData) free(fitsData); if (compressedData) free(compressedData); IDLog("Error! low memory. Unable to initialize fits buffers.\n"); return; } fitsFile = fopen(filename, "r"); if (fitsFile == NULL) return; /* #1 Read file from disk */ for (i=0; i < totalBytes; i+= nr) { nr = fread(fitsData + i, 1, totalBytes - i, fitsFile); if (nr <= 0) { IDLog("Error reading temporary FITS file.\n"); return; } } fclose(fitsFile); compressedBytes = sizeof(char) * totalBytes + totalBytes / 64 + 16 + 3; /* #2 Compress it */ r = compress2(compressedData, &compressedBytes, fitsData, totalBytes, 9); if (r != Z_OK) { /* this should NEVER happen */ IDLog("internal error - compression failed: %d\n", r); return; } /* #3 Send it */ imageB.blob = compressedData; imageB.bloblen = compressedBytes; imageB.size = totalBytes; strcpy(imageB.format, ".fits.z"); imageBP.s = IPS_OK; IDSetBLOB (&imageBP, NULL); free (fitsData); free (compressedData); } int ISTerminateTXDisplay(void) { int res = 0; res= STV_Interrupt() ; /* with out it hangs */ usleep(100000) ; IERmCallback( cb) ; cb = -1 ; if( TXDisplayS[0].s == ISS_ON) { TXDisplaySP.s = IPS_BUSY ; IDSetSwitch(&TXDisplaySP, "Stopping display read out"); DisplayCTP.s = IPS_IDLE ; IUSaveText(&DisplayCT[0], " "); /* reset client's display */ IUSaveText(&DisplayCT[1], " "); IDSetText( &DisplayCTP, NULL); DisplayBTP.s = IPS_IDLE ; IUSaveText(&DisplayBT[0], " "); /* reset client's display */ IUSaveText(&DisplayBT[1], " "); IDSetText( &DisplayBTP, NULL); DisplayDTP.s = IPS_IDLE ; IUSaveText(&DisplayDT[0], " "); /* reset client's display */ IUSaveText(&DisplayDT[1], " "); IDSetText( &DisplayDTP, NULL); if(( res= STV_TerminateTXDisplay()) != 0){ fprintf( stderr, "STV: error writing TTXD %d\n", res) ; } } else { res= 0 ; } usleep(500000) ; /* make sure that everything is discarded */ tcflush(fd, TCIOFLUSH); return res ; } int ISRestoreTXDisplay(void) { int res ; cb= IEAddCallback( fd, (IE_CBF *)ISCallBack, NULL) ; if( TXDisplayS[0].s == ISS_ON) { usleep(500000) ; /* STV need a little rest */ res= STV_TXDisplay() ; TXDisplaySP.s = IPS_OK ; IDSetSwitch(&TXDisplaySP, "Starting Display read out"); DisplayCTP.s = IPS_OK; IDSetText (&DisplayCTP, NULL); DisplayBTP.s = IPS_OK; IDSetText (&DisplayBTP, NULL); DisplayDTP.s = IPS_OK; IDSetText (&DisplayDTP, NULL); } return res ; } int ISMessageImageInfo( int buffer, IMAGE_INFO *image_info) { buffer++ ; /* IDMessage( mydev, "B%2d: descriptor:%d\n", buffer, image_info->descriptor) ; */ /* IDMessage( mydev, "B%2d: height:%d\n", buffer, image_info->height) ; */ /* IDMessage( mydev, "B%2d: width:%d\n", buffer, image_info->width) ; */ /* IDMessage( mydev, "B%2d: top:%d\n", buffer, image_info->top) ; */ /* IDMessage( mydev, "B%2d: left:%d\n", buffer, image_info->left) ; */ 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) ; /* IDMessage( mydev, "B%2d: noExposure:%d\n", buffer, image_info->noExposure) ; */ /* IDMessage( mydev, "B%2d: analogGain:%d\n", buffer, image_info->analogGain) ; */ /* IDMessage( mydev, "B%2d: digitalGain:%d\n", buffer, image_info->digitalGain) ; */ /* IDMessage( mydev, "B%2d: focalLength:%d\n", buffer, image_info->focalLength) ; */ /* IDMessage( mydev, "B%2d: aperture:%d\n", buffer, image_info->aperture) ; */ /* IDMessage( mydev, "B%2d: packedDate:%d\n", buffer, image_info->packedDate) ; */ IDMessage( mydev, "B%2d: Year:%4d, Month: %2d, Day:%2d\n", buffer, image_info->year, image_info->month, image_info->day) ; /* IDMessage( mydev, "B%2d: Day:%d\n", buffer, image_info->day) ; */ /* IDMessage( mydev, "B%2d: Month:%d\n", buffer, image_info->month) ; */ /* IDMessage( mydev, "B%2d: packedTime:%d\n", buffer, image_info->packedTime) ; */ /* IDMessage( mydev, "B%2d: Seconds:%d\n", buffer, image_info->seconds) ; */ /* IDMessage( mydev, "B%2d: minutes:%d\n", buffer, image_info->minutes) ; */ IDMessage( mydev, "B%2d: Hours:%2d, Minutes:%2d, Seconds:%d\n", buffer, image_info->hours, image_info->minutes, image_info->seconds) ; /* IDMessage( mydev, "B%2d: ccdTemp:%f\n", buffer, image_info->ccdTemp) ; */ /* IDMessage( mydev, "B%2d: siteID:%d\n", buffer, image_info->siteID) ; */ /* IDMessage( mydev, "B%2d: eGain:%d\n", buffer, image_info->eGain) ; */ /* IDMessage( mydev, "B%2d: background:%d\n", buffer, image_info->background) ; */ /* IDMessage( mydev, "B%2d: range :%d\n", buffer, image_info->range ) ; */ /* IDMessage( mydev, "B%2d: pedestal:%d\n", buffer, image_info->pedestal) ; */ /* IDMessage( mydev, "B%2d: ccdTop :%d\n", buffer, image_info->ccdTop) ; */ /* IDMessage( mydev, "B%2d: ccdLeft:%d\n", buffer, image_info->ccdLeft) ; */ return 0 ; } int ISRequestImageData( int compression, int buffer, int x_offset, int y_offset, int length, int lines) { int res ; int i, k ; int img_size ; char errmsg[1024] ; int image[320][320] ; IMAGE_INFO image_info ; for(i= 0 ; i < 320 ; i++) { for(k= 0 ; k < 320 ; k++) { image[i][k]= -1 ; } } res= STV_RequestImage( compression, buffer, x_offset, y_offset, &length, &lines, image, &image_info) ; if( res== 0) { STVImg->width= length; STVImg->height= lines ; img_size = STVImg->width * STVImg->height * sizeof(unsigned short); STVImg->img= malloc (img_size); for(i= 0 ; i < STVImg->height ; i++) { /* x */ for(k= 0 ; k < STVImg->width ; k++) { /* y */ STVImg->img[ STVImg->width* i + k]= (unsigned short)image[i][k] ; /* Uncomment this line in case of doubts about decompressed values and compare */ /* both sets. */ /*fprintf( stderr, "Line: %d %d %d %d\n", i, k, image[i][k], STVImg->img[ STVImg->width* i + k]) ; */ if(STVImg->img[ STVImg->width* i + k] < image_info.minValue) { image_info.minValue= STVImg->img[ STVImg->width* i + k] ; } if(STVImg->img[ STVImg->width* i + k] > image_info.maxValue) { image_info.maxValue= STVImg->img[ STVImg->width* i + k] ; } } } writeFITS( "FITS.fits", &image_info, errmsg) ; /*fprintf( stderr, "Fits writing message: %s\n", errmsg) ; */ free( STVImg->img) ; } return res ; } void ISUpdateDisplay( int buffer, int line) { if( !(( line+1) % 10)) { sprintf( DisplayCT[0].text, "Buffer %2d line: %3d", buffer+1, line+ 1) ; strcpy( DisplayBT[0].text, DisplayCT[0].text) ; strcpy( DisplayDT[0].text, DisplayCT[0].text) ; DisplayCTP.s= IPS_OK ; IDSetText( &DisplayCTP, NULL) ; DisplayBTP.s= IPS_OK ; IDSetText( &DisplayBTP, NULL) ; DisplayDTP.s= IPS_OK ; IDSetText( &DisplayDTP, NULL) ; } else if(( line+1)== 1) { /* first time */ IDMessage( mydev, "Image download started") ; } else if( line < 0) { /* last line */ line= -line ; sprintf( DisplayCT[0].text, "Buffer %2d line: %3d", buffer+1, line+ 1) ; strcpy( DisplayBT[0].text, DisplayCT[0].text) ; strcpy( DisplayDT[0].text, DisplayCT[0].text) ; DisplayCTP.s= IPS_OK ; IDSetText( &DisplayCTP, NULL) ; DisplayBTP.s= IPS_OK ; IDSetText( &DisplayBTP, NULL) ; DisplayDTP.s= IPS_OK ; IDSetText( &DisplayDTP, NULL) ; IDMessage( mydev, "Image download ended, buffer %2d line: %3d", buffer+1, line) ; } } libindi-0.9.7/drivers/video/v4ldriver.cpp0000644000175000017500000005665712241463551017360 0ustar jasemjasem#if 0 V4L INDI Driver INDI Interface for V4L devices Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 "v4ldriver.h" V4L_Driver::V4L_Driver() { allocateBuffers(); camNameT[0].text = NULL; PortT[0].text = NULL; IUSaveText(&PortT[0], "/dev/video0"); divider = 128.; } V4L_Driver::~V4L_Driver() { releaseBuffers(); } void V4L_Driver::initProperties(const char *dev) { strncpy(device_name, dev, MAXINDIDEVICE); /* Connection */ IUFillSwitch(&PowerS[0], "CONNECT", "Connect", ISS_OFF); IUFillSwitch(&PowerS[1], "DISCONNECT", "Disconnect", ISS_ON); IUFillSwitchVector(&PowerSP, PowerS, NARRAY(PowerS), dev, "CONNECTION", "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); /* Port */ IUFillText(&PortT[0], "PORT", "Port", "/dev/video0"); IUFillTextVector(&PortTP, PortT, NARRAY(PortT), dev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE); /* Video Stream */ IUFillSwitch(&StreamS[0], "ON", "Stream On", ISS_OFF); IUFillSwitch(&StreamS[1], "OFF", "Stream Off", ISS_ON); IUFillSwitchVector(&StreamSP, StreamS, NARRAY(StreamS), dev, "VIDEO_STREAM", "Video Stream", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); /* Compression */ IUFillSwitch(&CompressS[0], "ON", "", ISS_ON); IUFillSwitch(&CompressS[1], "OFF", "", ISS_OFF); IUFillSwitchVector(&CompressSP, CompressS, NARRAY(StreamS), dev, "Compression", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); /* Image type */ IUFillSwitch(&ImageTypeS[0], "Grey", "", ISS_ON); IUFillSwitch(&ImageTypeS[1], "Color", "", ISS_OFF); IUFillSwitchVector(&ImageTypeSP, ImageTypeS, NARRAY(ImageTypeS), dev, "Image Type", "", IMAGE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); /* Camera Name */ IUFillText(&camNameT[0], "Model", "", ""); IUFillTextVector(&camNameTP, camNameT, NARRAY(camNameT), dev, "Camera Model", "", COMM_GROUP, IP_RO, 0, IPS_IDLE); /* Expose */ IUFillNumber(&ExposeTimeN[0], "CCD_EXPOSURE_VALUE", "Duration (s)", "%5.2f", 0., 36000., 0.5, 1.); IUFillNumberVector(&ExposeTimeNP, ExposeTimeN, NARRAY(ExposeTimeN), dev, "CCD_EXPOSURE", "Expose", COMM_GROUP, IP_RW, 60, IPS_IDLE); /* Frame Rate */ IUFillNumber(&FrameRateN[0], "RATE", "Rate", "%0.f", 1., 50., 1., 10.); IUFillNumberVector(&FrameRateNP, FrameRateN, NARRAY(FrameRateN), dev, "FRAME_RATE", "Frame Rate", COMM_GROUP, IP_RW, 60, IPS_IDLE); /* Frame dimension */ IUFillNumber(&FrameN[0], "X", "X", "%.0f", 0., 0., 0., 0.); IUFillNumber(&FrameN[1], "Y", "Y", "%.0f", 0., 0., 0., 0.); IUFillNumber(&FrameN[2], "WIDTH", "Width", "%.0f", 0., 0., 10., 0.); IUFillNumber(&FrameN[3], "HEIGHT", "Height", "%.0f", 0., 0., 10., 0.); IUFillNumberVector(&FrameNP, FrameN, NARRAY(FrameN), dev, "CCD_FRAME", "Frame", IMAGE_GROUP, IP_RW, 60, IPS_IDLE); /*IUFillNumber(&ImageSizeN[0], "WIDTH", "Width", "%0.f", 0., 0., 10., 0.); IUFillNumber(&ImageSizeN[1], "HEIGHT", "Height", "%0.f", 0., 0., 10., 0.); IUFillNumberVector(&ImageSizeNP, ImageSizeN, NARRAY(ImageSizeN), dev, "IMAGE_SIZE", "Image Size", IMAGE_GROUP, IP_RW, 60, IPS_IDLE);*/ #ifndef HAVE_LINUX_VIDEODEV2_H IUFillNumber(&ImageAdjustN[0], "Contrast", "", "%0.f", 0., 256., 1., 0.); IUFillNumber(&ImageAdjustN[1], "Brightness", "", "%0.f", 0., 256., 1., 0.); IUFillNumber(&ImageAdjustN[2], "Hue", "", "%0.f", 0., 256., 1., 0.); IUFillNumber(&ImageAdjustN[3], "Color", "", "%0.f", 0., 256., 1., 0.); IUFillNumber(&ImageAdjustN[4], "Whiteness", "", "%0.f", 0., 256., 1., 0.); IUFillNumberVector(&ImageAdjustNP, ImageAdjustN, NARRAY(ImageAdjustN), dev, "Image Adjustments", "", IMAGE_GROUP, IP_RW, 60, IPS_IDLE); #else IUFillNumberVector(&ImageAdjustNP, NULL, 0, dev, "Image Adjustments", "", IMAGE_GROUP, IP_RW, 60, IPS_IDLE); #endif // We need to setup the BLOB (Binary Large Object) below. Using this property, we can send FITS to our client strcpy(imageB.name, "CCD1"); strcpy(imageB.label, "Feed"); strcpy(imageB.format, ""); imageB.blob = 0; imageB.bloblen = 0; imageB.size = 0; imageB.bvp = 0; imageB.aux0 = 0; imageB.aux1 = 0; imageB.aux2 = 0; strcpy(imageBP.device, dev); strcpy(imageBP.name, "Video"); strcpy(imageBP.label, "Video"); strcpy(imageBP.group, COMM_GROUP); strcpy(imageBP.timestamp, ""); imageBP.p = IP_RO; imageBP.timeout = 0; imageBP.s = IPS_IDLE; imageBP.bp = &imageB; imageBP.nbp = 1; imageBP.aux = 0; } void V4L_Driver::initCamBase() { v4l_base = new V4L2_Base(); } void V4L_Driver::ISGetProperties (const char *dev) { if (dev && strcmp (device_name, dev)) return; /* COMM_GROUP */ IDDefSwitch(&PowerSP, NULL); IDDefText(&PortTP, NULL); IDDefText(&camNameTP, NULL); IDDefSwitch(&StreamSP, NULL); #ifndef HAVE_LINUX_VIDEODEV2_H IDDefNumber(&FrameRateNP, NULL); #endif IDDefNumber(&ExposeTimeNP, NULL); IDDefBLOB(&imageBP, NULL); /* Image properties */ IDDefSwitch(&CompressSP, NULL); IDDefSwitch(&ImageTypeSP, NULL); IDDefNumber(&FrameNP, NULL); #ifndef HAVE_LINUX_VIDEODEV2_H IDDefNumber(&ImageAdjustNP, NULL); #endif } void V4L_Driver::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { char errmsg[ERRMSGSIZ]; /* ignore if not ours */ if (dev && strcmp (device_name, dev)) return; /* Connection */ if (!strcmp (name, PowerSP.name)) { IUResetSwitch(&PowerSP); IUUpdateSwitch(&PowerSP, states, names, n); connectCamera(); return; } /* Compression */ if (!strcmp(name, CompressSP.name)) { IUResetSwitch(&CompressSP); IUUpdateSwitch(&CompressSP, states, names, n); CompressSP.s = IPS_OK; IDSetSwitch(&CompressSP, NULL); return; } /* Image Type */ if (!strcmp(name, ImageTypeSP.name)) { IUResetSwitch(&ImageTypeSP); IUUpdateSwitch(&ImageTypeSP, states, names, n); ImageTypeSP.s = IPS_OK; IDSetSwitch(&ImageTypeSP, NULL); return; } /* Video Stream */ if (!strcmp(name, StreamSP.name)) { if (checkPowerS(&StreamSP)) return; IUResetSwitch(&StreamSP); IUUpdateSwitch(&StreamSP, states, names, n); StreamSP.s = IPS_IDLE; v4l_base->stop_capturing(errmsg); if (StreamS[0].s == ISS_ON) { frameCount = 0; IDLog("Starting the video stream.\n"); StreamSP.s = IPS_BUSY; v4l_base->start_capturing(errmsg); } else { IDLog("The video stream has been disabled. Frame count %d\n", frameCount); v4l_base->stop_capturing(errmsg); } IDSetSwitch(&StreamSP, NULL); return; } } void V4L_Driver::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int /*n*/) { IText *tp; /* ignore if not ours */ if (dev && strcmp (device_name, dev)) return; if (!strcmp(name, PortTP.name) ) { PortTP.s = IPS_OK; tp = IUFindText( &PortTP, names[0] ); if (!tp) return; IUSaveText(tp, texts[0]); IDSetText (&PortTP, NULL); return; } } void V4L_Driver::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { char errmsg[ERRMSGSIZ]; /* ignore if not ours */ if (dev && strcmp (device_name, dev)) return; /* Frame Size */ if (!strcmp (FrameNP.name, name)) { if (checkPowerN(&FrameNP)) return; int oldW = (int) FrameN[2].value; int oldH = (int) FrameN[3].value; FrameNP.s = IPS_OK; if (IUUpdateNumber(&FrameNP, values, names, n) < 0) return; if (v4l_base->setSize( (int) FrameN[2].value, (int) FrameN[3].value) != -1) { FrameN[2].value = v4l_base->getWidth(); FrameN[3].value = v4l_base->getHeight(); V4LFrame->width = (int) FrameN[2].value; V4LFrame->height= (int) FrameN[3].value; IDSetNumber(&FrameNP, NULL); return; } else { FrameN[2].value = oldW; FrameN[3].value = oldH; FrameNP.s = IPS_ALERT; IDSetNumber(&FrameNP, "Failed to set a new image size."); } return; } #ifndef HAVE_LINUX_VIDEODEV2_H /* Frame rate */ if (!strcmp (FrameRateNP.name, name)) { if (checkPowerN(&FrameRateNP)) return; FrameRateNP.s = IPS_IDLE; if (IUUpdateNumber(&FrameRateNP, values, names, n) < 0) return; v4l_base->setFPS( (int) FrameRateN[0].value ); FrameRateNP.s = IPS_OK; IDSetNumber(&FrameRateNP, NULL); return; } #endif if (!strcmp (ImageAdjustNP.name, name)) { if (checkPowerN(&ImageAdjustNP)) return; ImageAdjustNP.s = IPS_IDLE; if (IUUpdateNumber(&ImageAdjustNP, values, names, n) < 0) return; #ifndef HAVE_LINUX_VIDEODEV2_H v4l_base->setContrast( (int) (ImageAdjustN[0].value * divider)); v4l_base->setBrightness( (int) (ImageAdjustN[1].value * divider)); v4l_base->setHue( (int) (ImageAdjustN[2].value * divider)); v4l_base->setColor( (int) (ImageAdjustN[3].value * divider)); v4l_base->setWhiteness( (int) (ImageAdjustN[4].value * divider)); ImageAdjustN[0].value = v4l_base->getContrast() / divider; ImageAdjustN[1].value = v4l_base->getBrightness() / divider; ImageAdjustN[2].value = v4l_base->getHue() / divider; ImageAdjustN[3].value = v4l_base->getColor() / divider; ImageAdjustN[4].value = v4l_base->getWhiteness() / divider; #else unsigned int ctrl_id; for (int i=0; i < ImageAdjustNP.nnp; i++) { ctrl_id = *((unsigned int *) ImageAdjustNP.np[i].aux0); if (v4l_base->setINTControl( ctrl_id , ImageAdjustNP.np[i].value, errmsg) < 0) { ImageAdjustNP.s = IPS_ALERT; IDSetNumber(&ImageAdjustNP, "Unable to adjust setting. %s", errmsg); return; } } #endif ImageAdjustNP.s = IPS_OK; IDSetNumber(&ImageAdjustNP, NULL); return; } /* Exposure */ if (!strcmp (ExposeTimeNP.name, name)) { if (checkPowerN(&ExposeTimeNP)) return; //if (StreamS[0].s == ISS_ON) v4l_base->stop_capturing(errmsg); StreamS[0].s = ISS_OFF; StreamS[1].s = ISS_ON; StreamSP.s = IPS_IDLE; IDSetSwitch(&StreamSP, NULL); V4LFrame->expose = 1000; ExposeTimeNP.s = IPS_BUSY; IDSetNumber(&ExposeTimeNP, NULL); time(&capture_start); v4l_base->start_capturing(errmsg); return; } } void V4L_Driver::newFrame(void *p) { ((V4L_Driver *) (p))->updateFrame(); } void V4L_Driver::updateFrame() { char errmsg[ERRMSGSIZ]; static const unsigned int FRAME_DROP = 2; static int dropLarge = FRAME_DROP; if (StreamSP.s == IPS_BUSY) { // Ad hoc way of dropping frames frameCount++; dropLarge--; if (dropLarge == 0) { dropLarge = (int) (((ImageTypeS[0].s == ISS_ON) ? FRAME_DROP : FRAME_DROP*3) * (FrameN[2].value / 160.0)); updateStream(); return; } } else if (ExposeTimeNP.s == IPS_BUSY) { V4LFrame->Y = v4l_base->getY(); v4l_base->stop_capturing(errmsg); time(&capture_end); IDLog("Capture of ONE frame took %g seconds.\n", difftime(capture_end, capture_start)); grabImage(); } } void V4L_Driver::updateStream() { int width = v4l_base->getWidth(); int height = v4l_base->getHeight(); uLongf compressedBytes = 0; uLong totalBytes; unsigned char *targetFrame; int r; if (PowerS[0].s == ISS_OFF || StreamS[0].s == ISS_OFF) return; if (ImageTypeS[0].s == ISS_ON) V4LFrame->Y = v4l_base->getY(); else V4LFrame->colorBuffer = v4l_base->getColorBuffer(); totalBytes = ImageTypeS[0].s == ISS_ON ? width * height : width * height * 4; targetFrame = ImageTypeS[0].s == ISS_ON ? V4LFrame->Y : V4LFrame->colorBuffer; /* Do we want to compress ? */ if (CompressS[0].s == ISS_ON) { /* Compress frame */ V4LFrame->compressedFrame = (unsigned char *) realloc (V4LFrame->compressedFrame, sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3); compressedBytes = sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3; r = compress2(V4LFrame->compressedFrame, &compressedBytes, targetFrame, totalBytes, 4); if (r != Z_OK) { /* this should NEVER happen */ IDLog("internal error - compression failed: %d\n", r); return; } /* #3.A Send it compressed */ imageB.blob = V4LFrame->compressedFrame; imageB.bloblen = compressedBytes; imageB.size = totalBytes; strcpy(imageB.format, ".stream.z"); } else { /* #3.B Send it uncompressed */ imageB.blob = targetFrame; imageB.bloblen = totalBytes; imageB.size = totalBytes; strcpy(imageB.format, ".stream"); } imageBP.s = IPS_OK; IDSetBLOB (&imageBP, NULL); #ifndef HAVE_LINUX_VIDEODEV2_H char errmsg[ERRMSGSIZ]; v4l_base->start_capturing(errmsg); #endif } /* Downloads the image from the CCD row by row and store them in a raw file. N.B. No processing is done on the image */ int V4L_Driver::grabImage() { int err, fd; char errmsg[ERRMSG_SIZE]; char temp_filename[TEMPFILE_LEN] = "/tmp/fitsXXXXXX"; if ((fd = mkstemp(temp_filename)) < 0) { IDMessage(device_name, "Error making temporary filename."); IDLog("Error making temporary filename.\n"); return -1; } close(fd); err = writeFITS(temp_filename, errmsg); if (err) { IDMessage(device_name, errmsg, NULL); return -1; } return 0; } int V4L_Driver::writeFITS(const char * filename, char errmsg[]) { fitsfile *fptr; /* pointer to the FITS file; defined in fitsio.h */ int status; long fpixel = 1, naxis = 2, nelements; long naxes[2]; char filename_rw[TEMPFILE_LEN+1]; INDI_UNUSED(errmsg); // Append ! to file name to over write it. snprintf(filename_rw, TEMPFILE_LEN+1, "!%s", filename); naxes[0] = v4l_base->getWidth(); naxes[1] = v4l_base->getHeight(); status = 0; /* initialize status before calling fitsio routines */ fits_create_file(&fptr, filename_rw, &status); /* create new file */ /* Create the primary array image (16-bit short integer pixels */ fits_create_img(fptr, BYTE_IMG, naxis, naxes, &status); addFITSKeywords(fptr); nelements = naxes[0] * naxes[1]; /* number of pixels to write */ /* Write the array of integers to the image */ fits_write_img(fptr, TBYTE, fpixel, nelements, V4LFrame->Y, &status); fits_close_file(fptr, &status); /* close the file */ fits_report_error(stderr, status); /* print out any error messages */ /* Success */ ExposeTimeNP.s = IPS_OK; IDSetNumber(&ExposeTimeNP, NULL); uploadFile(filename); unlink(filename); return status; } void V4L_Driver::addFITSKeywords(fitsfile *fptr) { int status=0; char keyname[32], comment[64]; strncpy(keyname, "EXPOSURE", 32); strncpy(comment, "Total Exposure Time (ms)", 64); fits_update_key(fptr, TLONG, keyname , &(V4LFrame->expose), comment, &status); strncpy(keyname, "INSTRUME", 32); strncpy(comment, "Webcam Name", 64); fits_update_key(fptr, TSTRING, keyname, v4l_base->getDeviceName(), comment, &status); fits_write_date(fptr, &status); } void V4L_Driver::uploadFile(const char * filename) { FILE * fitsFile; int r=0; unsigned int nr = 0; uLong totalBytes; uLongf compressedBytes = 0; struct stat stat_p; if ( -1 == stat (filename, &stat_p)) { IDLog(" Error occurred attempting to stat %s\n", filename); return; } totalBytes = stat_p.st_size; fitsFile = fopen(filename, "r"); if (fitsFile == NULL) return; fitsData = (fitsData == NULL) ? (unsigned char *) malloc(sizeof(unsigned char) * totalBytes) : (unsigned char *) realloc(fitsData, sizeof(unsigned char) * totalBytes); /* #1 Read file from disk */ for (unsigned int i=0; i < totalBytes; i+= nr) { nr = fread(fitsData + i, 1, totalBytes - i, fitsFile); if (nr <= 0) { IDLog("Error reading temporary FITS file.\n"); return; } } fclose(fitsFile); if (CompressS[0].s == ISS_ON) { /* #2 Compress it */ V4LFrame->compressedFrame = (unsigned char *) realloc (V4LFrame->compressedFrame, sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3); compressedBytes = sizeof(unsigned char) * totalBytes + totalBytes / 64 + 16 + 3; r = compress2(V4LFrame->compressedFrame, &compressedBytes, fitsData, totalBytes, 9); if (r != Z_OK) { /* this should NEVER happen */ IDLog("internal error - compression failed: %d\n", r); return; } /* #3.A Send it compressed */ imageB.blob = V4LFrame->compressedFrame; imageB.bloblen = compressedBytes; imageB.size = totalBytes; strcpy(imageB.format, ".fits.z"); } else { imageB.blob = fitsData; imageB.bloblen = totalBytes; imageB.size = totalBytes; strcpy(imageB.format, ".fits"); } imageBP.s = IPS_OK; IDSetBLOB (&imageBP, NULL); } void V4L_Driver::connectCamera() { char errmsg[ERRMSGSIZ]; switch (PowerS[0].s) { case ISS_ON: if (v4l_base->connectCam(PortT[0].text, errmsg) < 0) { PowerSP.s = IPS_IDLE; PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; IDSetSwitch(&PowerSP, "Error: unable to open device"); IDLog("Error: %s\n", errmsg); return; } /* Sucess! */ PowerS[0].s = ISS_ON; PowerS[1].s = ISS_OFF; PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Video4Linux Generic Device is online. Retrieving basic data."); v4l_base->registerCallback(newFrame, this); IDLog("V4L Device is online. Retrieving basic data.\n"); getBasicData(); break; case ISS_OFF: PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; PowerSP.s = IPS_IDLE; v4l_base->disconnectCam(); IDSetSwitch(&PowerSP, "Video4Linux Generic Device is offline."); break; } } /* Retrieves basic data from the device upon connection.*/ void V4L_Driver::getBasicData() { int xmax, ymax, xmin, ymin; v4l_base->getMaxMinSize(xmax, ymax, xmin, ymin); /* Width */ FrameN[2].value = v4l_base->getWidth(); FrameN[2].min = xmin; FrameN[2].max = xmax; V4LFrame->width = (int) FrameN[2].value; /* Height */ FrameN[3].value = v4l_base->getHeight(); FrameN[3].min = ymin; FrameN[3].max = ymax; V4LFrame->height = (int) FrameN[3].value; IUUpdateMinMax(&FrameNP); IDSetNumber(&FrameNP, NULL); IUSaveText(&camNameT[0], v4l_base->getDeviceName()); IDSetText(&camNameTP, NULL); #ifndef HAVE_LINUX_VIDEODEV2_H updateV4L1Controls(); #else updateV4L2Controls(); #endif } #ifdef HAVE_LINUX_VIDEODEV2_H void V4L_Driver::updateV4L2Controls() { // #1 Query for INTEGER controls, and fill up the structure free(ImageAdjustNP.np); ImageAdjustNP.nnp = 0; if (v4l_base->queryINTControls(&ImageAdjustNP) > 0) IDDefNumber(&ImageAdjustNP, NULL); } #else void V4L_Driver::updateV4L1Controls() { if ( (v4l_base->getContrast() / divider) > ImageAdjustN[0].max) divider *=2; if ( (v4l_base->getHue() / divider) > ImageAdjustN[2].max) divider *=2; ImageAdjustN[0].value = v4l_base->getContrast() / divider; ImageAdjustN[1].value = v4l_base->getBrightness() / divider; ImageAdjustN[2].value = v4l_base->getHue() / divider; ImageAdjustN[3].value = v4l_base->getColor() / divider; ImageAdjustN[4].value = v4l_base->getWhiteness() / divider; ImageAdjustNP.s = IPS_OK; IDSetNumber(&ImageAdjustNP, NULL); } #endif int V4L_Driver::checkPowerS(ISwitchVectorProperty *sp) { if (PowerSP.s != IPS_OK) { if (!strcmp(sp->label, "")) IDMessage (device_name, "Cannot change property %s while the camera is offline.", sp->name); else IDMessage (device_name, "Cannot change property %s while the camera is offline.", sp->label); sp->s = IPS_IDLE; IDSetSwitch(sp, NULL); return -1; } return 0; } int V4L_Driver::checkPowerN(INumberVectorProperty *np) { if (PowerSP.s != IPS_OK) { if (!strcmp(np->label, "")) IDMessage (device_name, "Cannot change property %s while the camera is offline.", np->name); else IDMessage (device_name, "Cannot change property %s while the camera is offline.", np->label); np->s = IPS_IDLE; IDSetNumber(np, NULL); return -1; } return 0; } int V4L_Driver::checkPowerT(ITextVectorProperty *tp) { if (PowerSP.s != IPS_OK) { if (!strcmp(tp->label, "")) IDMessage (device_name, "Cannot change property %s while the camera is offline.", tp->name); else IDMessage (device_name, "Cannot change property %s while the camera is offline.", tp->label); tp->s = IPS_IDLE; IDSetText(tp, NULL); return -1; } return 0; } void V4L_Driver::allocateBuffers() { V4LFrame = (img_t *) malloc (sizeof(img_t)); if (V4LFrame == NULL) { IDMessage(NULL, "Error: unable to initialize driver. Low memory."); IDLog("Error: unable to initialize driver. Low memory."); exit(-1); } fitsData = (unsigned char *) malloc (sizeof(unsigned char) * 1); V4LFrame->Y = (unsigned char *) malloc (sizeof(unsigned char) * 1); V4LFrame->U = (unsigned char *) malloc (sizeof(unsigned char) * 1); V4LFrame->V = (unsigned char *) malloc (sizeof(unsigned char) * 1); V4LFrame->colorBuffer = (unsigned char *) malloc (sizeof(unsigned char) * 1); V4LFrame->compressedFrame = (unsigned char *) malloc (sizeof(unsigned char) * 1); } void V4L_Driver::releaseBuffers() { free(fitsData); free(V4LFrame->Y); free(V4LFrame->U); free(V4LFrame->V); free(V4LFrame->colorBuffer); free(V4LFrame->compressedFrame); free (V4LFrame); } libindi-0.9.7/drivers/video/indi_lpi.cpp0000644000175000017500000000712012241463551017203 0ustar jasemjasem/* Meade LPI Experimental driver Copyright (C) 2005 by Jasem Mutlaq 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 */ #include "v4ldriver.h" class Meade_LPI : public V4L_Driver { public: Meade_LPI(); ~Meade_LPI(); #ifdef HAVE_LINUX_VIDEODEV2_H void connectCamera(void); #endif }; Meade_LPI::Meade_LPI() : V4L_Driver() { } Meade_LPI::~Meade_LPI() { } #ifdef HAVE_LINUX_VIDEODEV2_H void Meade_LPI::connectCamera() { char errmsg[ERRMSGSIZ]; switch (PowerS[0].s) { case ISS_ON: if (v4l_base->connectCam(PortT[0].text, errmsg, V4L2_PIX_FMT_SBGGR8, 352, 288) < 0) { PowerSP.s = IPS_IDLE; PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; IDSetSwitch(&PowerSP, "Error: unable to open device"); IDLog("Error: %s\n", errmsg); return; } /* Sucess! */ PowerS[0].s = ISS_ON; PowerS[1].s = ISS_OFF; PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Meade LPI is online. Retrieving basic data."); v4l_base->registerCallback(newFrame, this); V4LFrame->compressedFrame = (unsigned char *) malloc (sizeof(unsigned char) * 1); IDLog("Meade LPI is online. Retrieving basic data.\n"); getBasicData(); break; case ISS_OFF: PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; PowerSP.s = IPS_IDLE; free(V4LFrame->compressedFrame); V4LFrame->compressedFrame = NULL; v4l_base->disconnectCam(); IDSetSwitch(&PowerSP, "Meade LPI is offline."); break; } } #endif Meade_LPI *MainCam = NULL; /* Main and only camera */ /* send client definitions of all properties */ void ISInit() { if (MainCam == NULL) { MainCam = new Meade_LPI(); MainCam->initProperties("Meade LPI"); MainCam->initCamBase(); } } void ISGetProperties (const char *dev) { ISInit(); MainCam->ISGetProperties(dev); } void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); MainCam->ISNewSwitch(dev, name, states, names, n); } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); MainCam->ISNewText(dev, name, texts, names, n); } void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); MainCam->ISNewNumber(dev, name, values, names, n); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } libindi-0.9.7/drivers/video/v4lphilips.h0000644000175000017500000000470412241463551017164 0ustar jasemjasem/* Phlips webcam INDI driver Copyright (C) 2003-2005 by Jasem Mutlaq 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 2005.04.29 JM: There is no need for this file for Video 4 Linux 2. It is kept for V4L 1 compatibility. */ #ifndef V4LPHILIPS_H #define V4LPHILIPS_H #ifndef HAVE_LINUX_VIDEODEV2_H #include "webcam/v4l1_pwc.h" #endif #include "v4ldriver.h" class V4L_Philips : public V4L_Driver { public: V4L_Philips(); ~V4L_Philips(); /* INDI Functions that must be called from indidrivermain */ void ISGetProperties (const char *dev); void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); void initCamBase(); void initProperties(const char *dev); void connectCamera(void); private: /* Switches */ ISwitch BackLightS[2]; ISwitch AntiFlickerS[2]; ISwitch NoiseReductionS[4]; ISwitch CamSettingS[3]; ISwitch WhiteBalanceModeS[5]; /* Nmubers */ INumber WhiteBalanceN[2]; INumber ShutterSpeedN[1]; /* Switch Vectors */ ISwitchVectorProperty BackLightSP; ISwitchVectorProperty AntiFlickerSP; ISwitchVectorProperty NoiseReductionSP; ISwitchVectorProperty CamSettingSP; ISwitchVectorProperty WhiteBalanceModeSP; /* Number Vectors */ INumberVectorProperty WhiteBalanceNP; INumberVectorProperty ShutterSpeedNP; #ifndef HAVE_LINUX_VIDEODEV2_H V4L1_PWC * v4l_pwc; void updateV4L1Controls(); void getBasicData(void); #endif }; #endif libindi-0.9.7/drivers/video/stvdriver.c0000644000175000017500000012376112241463551017116 0ustar jasemjasem#if 0 STV Low Level Driver Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch The initial work is based on the program STVremote by Shashikiran Ganesh. email: gshashikiran_AT_linuxmail_dot_org 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 #include #include #include #include #include #include #include #include "stvdriver.h" /* Config parameters */ #include #ifdef HAVE_NOVA_H #include #endif #ifndef _WIN32 #include #endif /* INDI Common Routines/RS232 */ #include "indicom.h" extern int fd ; extern char tracking_buf[] ; struct termios orig_tty_setting; /* old serial port setting to restore on close */ struct termios tty_setting; /* new serial port setting */ #define FALSE 0 #define TRUE 1 /*int tty_read( int fd, char *buf, int nbytes, int timeout, int *nbytes_read) ; */ /*int tty_write( int fd, const char *buffer, int *nbytes_written) ; */ void ISUpdateDisplay( int buffer, int line) ; int STV_portWrite( char *buf, int nbytes) ; int STV_TXDisplay( void) ; int STV_TerminateTXDisplay( void) ; int STV_FileStatus( int) ; int STV_DownloadComplete( void) ; int STV_RequestImage( int compression, int buffer, int x_offset, int y_offset, int *length, int *lines, int image[][320], IMAGE_INFO *image_info) ; int STV_RequestImageData( int compression, int *data, int j, int length, int *values) ; int STV_Download( void) ; int STV_DownloadAll( void) ; int STV_RequestAck( void) ; int STV_CheckHeaderSum( unsigned char *buf) ; int STV_CheckDataSum( unsigned char *data) ; int STV_PrintBuffer( unsigned char *buf, int n ) ; int STV_PrintBufferAsText( unsigned char *buf, int n ) ; int STV_CheckAck( unsigned char *buf) ; int STV_SendPacket( int cmd, int *data, int n) ; int STV_ReceivePacket( unsigned char *buf, int mode) ; int STV_DecompressData( unsigned char *data, int *values, int length, int expected_n_values) ; int STV_BufferStatus( int buffer) ; void STV_PrintBits( unsigned int x, int n) ; unsigned int STV_RecombineInt( unsigned char low_byte, unsigned char high_byte) ; unsigned int STV_GetBits( unsigned int x, int p, int n) ; int STV_MenueSetup( int delay) ; int STV_MenueDateTime( int delay) ; int STV_MenueCCDTemperature( int delay) ; typedef struct { double ccd_temperature ; } DISPLAY_INFO ; DISPLAY_INFO di ; /* STV Buttons */ int STV_LRRotaryDecrease(void) { int data[]={LR_ROTARY_DECREASE_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_LRRotaryIncrease(void) { int data[]={ LR_ROTARY_INCREASE_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_UDRotaryDecrease(void) { int data[]={UD_ROTARY_DECREASE_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_UDRotaryIncrease(void) { int data[]={UD_ROTARY_INCREASE_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_AKey(void) { /* Parameter button */ int data[]={A_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_BKey(void) { /* Value Button */ int data[]={ B_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_Setup(void) { int data[]={SETUP_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1); } int STV_Interrupt(void) { int data[]={INT_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_Focus(void) { int data[]= {FOCUS_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_Image(void) { int data[]={IMAGE_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_Monitor(void) { int data[]={MONITOR_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_Calibrate(void) { int data[]={CAL_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_Track(void) { int data[]={TRACK_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_Display(void) { int data[]={DISPLAY_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_FileOps(void) { int data[]={FILEOPS_KEY_PATTERN} ; return STV_SendPacket(SEND_KEY_PATTERN, data, 1) ; } int STV_RequestImageInfo(int buffer, IMAGE_INFO *image_info) { int i ; int length ; int res ; int data[]= {buffer} ; unsigned char buf[1024] ; unsigned int value[21] ; if(( res= STV_BufferStatus( buffer)) != 0) { if( res== 1) { /*fprintf( stderr," STV_RequestImageInfo buffer empty %d\n", buffer) ; */ return res ; /* Buffer is empty */ } else { fprintf( stderr," STV_RequestImageInfo error %d\n", res) ; return res ; } } res= STV_SendPacket( REQUEST_IMAGE_INFO, data, 1) ; usleep(50000) ; res= STV_ReceivePacket( buf, 0) ; if(buf[1] != REQUEST_IMAGE_INFO) { /*length= buf[3] * 0x100 + buf[2] ; */ /*res= STV_PrintBuffer(buf, 6+ length+ 2) ; */ AGAINI: if(( res= STV_ReceivePacket( buf, 0)) < 0) { /* STV answers with a packet 0x03 sometimes, should be 0x04 */ return -1 ;; } if(buf[1] != REQUEST_IMAGE_INFO) { /* Second try */ fprintf( stderr, "STV_RequestImageInfo: expected REQUEST_IMAGE_INFO, received %d, try again\n", buf[1]) ; goto AGAINI ; } } length= buf[3] * 0x100 + buf[2]; /* DECODE it */ for( i= 6; i < length; i+= 2) { value[( i- 6)/2]= STV_RecombineInt( buf[ i], buf[ i+1]) ; } image_info->descriptor = value[0] ; /* Decode the descriptor */ /*STV_PrintBits(( unsigned int)value[0], 16) ; */ if(( image_info->descriptor & ID_BITS_MASK)== ID_BITS_10) { /* fprintf( stderr, "ADC Resolution: 10 bits\n") ; */ } else if(( image_info->descriptor & ID_BITS_MASK )== ID_BITS_8) { /*fprintf( stderr, "Resolution: 8 bits (focus mode only)\n") ; */ } if(( image_info->descriptor & ID_UNITS_MASK)== ID_UNITS_INCHES) { /*fprintf( stderr, "Units: inch\n") ; */ } else if(( image_info->descriptor & ID_UNITS_MASK)== ID_UNITS_CM) { /*fprintf( stderr, "Unis: cm\n") ; */ } if(( image_info->descriptor & ID_SCOPE_MASK)== ID_SCOPE_REFRACTOR) { /*fprintf( stderr, "Refractor\n") ; */ } else if(( image_info->descriptor & ID_SCOPE_MASK)== ID_SCOPE_REFLECTOR) { /*fprintf( stderr, "Reflector\n") ; */ } if(( image_info->descriptor & ID_DATETIME_MASK)== ID_DATETIME_VALID) { /*fprintf( stderr, "Date and time valid\n") ; */ } else if(( image_info->descriptor & ID_DATETIME_MASK)== ID_DATETIME_INVALID) { /*fprintf( stderr, "Date and time invalid\n") ; */ } if(( image_info->descriptor & ID_BIN_MASK)== ID_BIN_1X1) { image_info->binning=1 ; } else if(( image_info->descriptor & ID_BIN_MASK)== ID_BIN_2X2) { image_info->binning=2 ; } else if(( image_info->descriptor & ID_BIN_MASK)== ID_BIN_3X3) { image_info->binning=3 ; } if(( image_info->descriptor & ID_PM_MASK)== ID_PM_PM) { /*fprintf( stderr, "Time: PM\n") ; */ } else if(( image_info->descriptor & ID_PM_MASK)== ID_PM_AM) { /*fprintf( stderr, "Time: AM\n") ; */ } /* ToDo: Include that to the fits header */ if(( image_info->descriptor & ID_FILTER_MASK)== ID_FILTER_LUNAR) { /*fprintf( stderr, "Filter: Lunar\n") ; */ } else if(( image_info->descriptor & ID_FILTER_MASK)== ID_FILTER_NP ) { /*fprintf( stderr, "Filter: clear\n") ; */ } /* ToDo: Include that to the fits header */ if(( image_info->descriptor & ID_DARKSUB_MASK )== ID_DARKSUB_YES) { /*fprintf( stderr, "Drak sub yes\n") ; */ } else if(( image_info->descriptor & ID_DARKSUB_MASK )== ID_DARKSUB_NO) { /*fprintf( stderr, "Dark sub no\n") ; */ } if(( image_info->descriptor & ID_MOSAIC_MASK)== ID_MOSAIC_NONE) { /*fprintf( stderr, "Is NOT a mosaic\n") ; */ } else if(( image_info->descriptor & ID_MOSAIC_MASK)== ID_MOSAIC_SMALL) { /*fprintf( stderr, "Is a small mosaic\n") ; */ } else if(( image_info->descriptor & ID_MOSAIC_MASK)== ID_MOSAIC_LARGE) { /*fprintf( stderr, "Is a large mosaic\n") ; */ } image_info->height = value[1] ; image_info->width = value[2] ; image_info->top = value[3] ; image_info->left = value[4] ; /* Exposure time */ if((value[5]>= 100 ) && (value[5]<= 60000)) { image_info->exposure = ((float)value[5]) * 0.01; } else if((value[5]>= 60001 ) && (value[5]<= 60999)){ image_info->exposure = (( float)value[5]- 60000.) *.001 ; } else { fprintf( stderr, "Error Exposure time %d\n", value[5]) ; image_info->exposure = -1. ; } image_info->noExposure = value[6] ; image_info->analogGain = value[7] ; image_info->digitalGain= value[8] ; image_info->focalLength= value[9] ; image_info->aperture = value[10] ; image_info->packedDate = value[11] ; image_info->year = STV_GetBits( value[11], 6, 7) + 1999; image_info->day = STV_GetBits( value[11], 11, 5) ; image_info->month = STV_GetBits( value[11], 15, 4) ; image_info->packedTime = value[12]; image_info->seconds = STV_GetBits( value[12], 5, 6) ; image_info->minutes = STV_GetBits( value[12], 11, 6) ; image_info->hours = STV_GetBits( value[12], 15, 4) ; if(( image_info->descriptor & ID_PM_PM) > 0) { image_info->hours += 12 ; } if((value[13] & 0x8000)== 0x8000) { image_info->ccdTemp= (float)(0xffff - value[13]) /100. ; } else { image_info->ccdTemp= (float)value[13]/100. ; } image_info->siteID = value[14] ; image_info->eGain = value[15] ; image_info->background = value[16] ; image_info->range = value[17] ; image_info->pedestal = value[18] ; image_info->ccdTop = value[19] ; image_info->ccdLeft = value[20] ; /* fprintf( stderr, "descriptor:%d 0x%2x 0x%2x\n", image_info->descriptor, buf[6], buf[6+1]) ; */ /* fprintf( stderr, "height:%d\n", image_info->height) ; */ /* fprintf( stderr, "width:%d\n", image_info->width) ; */ /* fprintf( stderr, "top:%d\n", image_info->top) ; */ /* fprintf( stderr, "left:%d\n", image_info->left) ; */ /* fprintf( stderr, "exposure:%f\n", image_info->exposure) ; */ /* fprintf( stderr, "noExposure:%d\n", image_info->noExposure) ; */ /* fprintf( stderr, "analogGain:%d\n", image_info->analogGain) ; */ /* fprintf( stderr, "digitalGain:%d\n", image_info->digitalGain) ; */ /* fprintf( stderr, "focalLength:%d\n", image_info->focalLength) ; */ /* fprintf( stderr, "aperture:%d\n", image_info->aperture) ; */ /* fprintf( stderr, "packedDate:%d\n", image_info->packedDate) ; */ /* fprintf( stderr, "Year:%d\n", image_info->year) ; */ /* fprintf( stderr, "Day:%d\n", image_info->day) ; */ /* fprintf( stderr, "Month:%d\n", image_info->month) ; */ /* fprintf( stderr, "packedTime:%d\n", image_info->packedTime) ; */ /* fprintf( stderr, "Seconds:%d\n", image_info->seconds) ; */ /* fprintf( stderr, "minutes:%d\n", image_info->minutes) ; */ /* fprintf( stderr, "hours:%d\n", image_info->hours) ; */ /* fprintf( stderr, "ccdTemp:%f\n", image_info->ccdTemp) ; */ /* fprintf( stderr, "siteID:%d\n", image_info->siteID) ; */ /* fprintf( stderr, "eGain:%d\n", image_info->eGain) ; */ /* fprintf( stderr, "background:%d\n", image_info->background) ; */ /* fprintf( stderr, "range :%d\n", image_info->range ) ; */ /* fprintf( stderr, "pedestal:%d\n", image_info->pedestal) ; */ /* fprintf( stderr, "ccdTop :%d\n", image_info->ccdTop) ; */ /* fprintf( stderr, "ccdLeft:%d\n", image_info->ccdLeft) ; */ return 0 ; } int STV_RequestImage( int compression, int buffer, int x_offset, int y_offset, int *length, int *lines, int image[][320], IMAGE_INFO *image_info) { int i, j ; int res ; int n_values ; unsigned char buf[0xffff] ; int values[1024] ; int data[]= { 0, y_offset, *length, buffer} ; /* Offset row, Offset line, length, buffer number */ int XOFF ; /* fprintf(stderr, "STV_RequestImage: --------------------------------buffer= %d, %d\n", buffer, lines) ; */ if(( res= STV_RequestImageInfo( buffer, image_info)) != 0) { /* Trigger for download */ /* buffer empty */ return res ; } res= STV_BKey() ; /* "press" the STV Value button */ usleep(50000) ; res= STV_ReceivePacket(buf, 0) ; /* Check the boundaries obtained from the image data versus windowing */ /* Take the smaller boundaries in each direction */ if( x_offset > image_info->height) { x_offset= image_info->height ; } XOFF= image_info->top + x_offset ; if( y_offset > image_info->width) { y_offset= image_info->width ; } data[1]= image_info->left + y_offset ; if( *length > image_info->width- y_offset) { *length= image_info->width- y_offset ; } data[2]= *length ; if( *lines > image_info->height- x_offset) { *lines= image_info->height- x_offset ; } /*fprintf(stderr, "STV_RequestImage: DATA 0=%d, 1=%d, 2=%d, 3=%d, length=%d, lines=%d\n", data[0], data[1], data[2], data[3], *length, *lines) ; */ for( j= 0 ; j < *lines ; j++) { data[0]= j + XOFF; /*line */ if(( n_values= STV_RequestImageData( compression, data, j, *length, values)) < 0) { fprintf(stderr, "STV_RequestImage: Calling STV_RequestImageData failed %d\n", n_values) ; return n_values ; } else { for( i= 0; i < n_values ; i++) { image[j][i]= values[i] ; } ISUpdateDisplay( buffer, j) ; } } /* Read the 201th line, see mosaic mode */ /* ToDo: analyze/display the data or use them in the fits header(s) */ data[0]= 200; /*line */ if(( res= STV_RequestImageData( 1, data, 200, *length, values)) < 0) { return res ; } else { for( i= 0 ; i< n_values ; i++) { /* fprintf( stderr, "%d: %d ", i, values[i]) ; */ } /* fprintf( stderr, "\n") ; */ } res= STV_DownloadComplete() ; ISUpdateDisplay( buffer, -j) ; return 0 ; } int STV_RequestImageData( int compression, int *data, int j, int length, int *values) { int i ; int res ; int data_length ; int n_values ; unsigned char buf[0xffff] ; data_length= -1 ; if( compression== ON) { /* compressed download */ if(( res= STV_SendPacket( REQUEST_COMPRESSED_IMAGE_DATA, data, 4)) != 0){ fprintf(stderr, "STV_RequestImageData: could not write\n") ; return -1 ; } AGAINC: if(( res= STV_ReceivePacket(buf, 0)) > 0) { if( buf[1] != REQUEST_COMPRESSED_IMAGE_DATA) { if( buf[1] != DISPLAY_ECHO) { if( buf[1] != ACK) { fprintf(stderr, "STV_RequestImageData: expected REQUEST_COMPRESSED_IMAGE_DATA, received %2x\n", buf[1]) ; } } goto AGAINC ; } data_length= (int)buf[3] * 0x100 + (int)buf[2] ; if(( n_values= STV_DecompressData((buf+6), values, data_length, length)) < 0 ) { n_values= -n_values ; fprintf( stderr, "SEVERE ERROR on Line %d, pixel position=%d\n", j, n_values) ; _exit( -1) ; } if( n_values == length) { return n_values ; } else { fprintf( stderr, "SEVERE Error: Length not equal, Line: %d, %d != %d, data %2x %2x, values %d, %d\n", j, n_values, length, buf[ 6+ length -2], buf[ 6+ length -1], values[n_values-2], values[n_values-1]) ; _exit( 1) ; } } else { fprintf( stderr, "Error: waiting for data on the serial port at line %d\n", j) ; return -1 ; } } else { /* uncompressed download */ if(( res= STV_SendPacket( REQUEST_IMAGE_DATA, data, 4))== 0) { AGAINU: if(( res= STV_ReceivePacket(buf, 0)) > 0) { if( buf[1] != REQUEST_IMAGE_DATA) { if( buf[1] != DISPLAY_ECHO) { if( buf[1] != ACK) { fprintf(stderr, "STV_RequestImageData: expected REQUEST_IMAGE_DATA, received %2x\n", buf[1]) ; } } goto AGAINU ; } data_length= (int)buf[3] * 0x100 + (int)buf[2] ; for( i= 0; i < data_length ; i += 2) { values[i/2]= STV_RecombineInt(buf[6 + i], buf[7 + i]) ; } return data_length/2 ; /*ISUpdateDisplay( buffer, j) ; */ /* Update the display of the INDI client */ } else { fprintf( stderr, "Error: waiting for data on the serial port at line %d\n", j) ; return -1 ; } } else { fprintf( stderr, "STV_RequestImageData: error writing %d\n", res) ; } } return 0 ; } int STV_DecompressData( unsigned char *data, int *values, int length, int expected_n_values) { int i, n_values ; int value ; int base ; base= STV_RecombineInt( data[0], data[1]) ; /*STV Manual says: MSB then LSB! */ values[0]= base ; i= 2 ; n_values= 1 ; while( i < length ) { if( (( data[ i] & 0xc0))== 0x80) { /*two bytes, first byte: bit 7 set, 6 cleared, 14 bits data */ if(( data[ i] & 0x20)== 0x20) { /* minus sign set? */ value= - ((int)(( (~data[ i] & 0x1f)) * 0x100) + (((int) (~data[ i+ 1])) & 0xff))- 1 ; /* value without sign */ } else { value= (int) (( data[ i] & 0x1f) * 0x100) + (int) (data[ i + 1]) ; } base= value + base ; /* new base value */ values[n_values++]= base ; /*pixel data */ i += 2 ; } else if((( data[ i] & 0x80))== 0) { /* one byte: bit 7 clear (7 bits data) */ if(( data[ i] & 0x40)== 0x40) { /* minus sign set? */ value= - (int) ( (~(data[ i])) & 0x3f) - 1 ; /* value without sign */ } else { value= (int) ( data[ i] & 0x3f) ; /*fprintf( stderr, "Value 7P: %d, pixel value: %d, length %d, pix=%d\n", value, value+ base, length, n_values) ; */ } /* Sometimes the STV send a 0 at the end, thats not very likely a pixel to pixel variation */ /* I checked the last decompressed pixel value against the last uncompressed pixel value */ /* with different images - it seems to be ok. */ if(( value == 0) &&( n_values== expected_n_values)){ /*fprintf( stderr, "Ignoring byte %d, Zero difference obtained values: %d\n", i, n_values) ; */ } else { base= value + base ; values[n_values++]= base ; } i++ ; } else if( (( data[ i] & 0xc0))== 0xc0) { /*two bytes, values= pixel_n/4 */ /*STV_PrintBits( data[ i], 8) ; */ /*STV_PrintBits( data[ i+ 1], 8) ; */ value= 4* ((int) (( data[ i] & 0x3f) * 0x100) + (int) (data[ i + 1])) ; /*fprintf( stderr, "Value 14P: %d, pixel value: %d, length %d, pix=%d\n", value, value+ base, length, n_values) ; */ base= value ; values[n_values++]= value ; i += 2 ; /*return -n_values ; */ } else { fprintf( stderr, "Unknown compression case: %2x, length %d, i=%d\n", data[ i], length, i) ; return -n_values ; /* exit */ } } return n_values ; } int STV_TXDisplay(void) { int data[]={TRUE} ; return STV_SendPacket( DISPLAY_ECHO, data, 1); } int STV_TerminateTXDisplay(void) { int res ; int data[]={FALSE} ; res= STV_SendPacket( DISPLAY_ECHO, data, 1); /* Despite the manual says so, I not always see an ACK packet */ /* So i flush it for the moment */ tcflush(fd, TCIOFLUSH); return res ; } int STV_FileStatus(int status) { int data[]= {status} ; return STV_SendPacket( FILE_STATUS, data, 1); } int STV_DownloadComplete(void) { return STV_SendPacket( DOWNLOAD_COMPLETE, NULL, 0); } int STV_Download(void) { return STV_SendPacket( REQUEST_DOWNLOAD, NULL, 0) ; } int STV_DownloadAll(void) { return STV_SendPacket( REQUEST_DOWNLOAD_ALL, NULL, 0); } int STV_RequestAck(void) { int data[]={0x06,0x06,0x06 } ; /* SBIG manual says contains data, which? */ return STV_SendPacket( REQUEST_ACK, data, 3) ; } int STV_BufferStatus( int buffer){ unsigned char buf[1024]; int buffers ; int res ; int val ; /*fprintf(stderr, "STV_BufferStatus entering\n") ; */ usleep(50000) ; if(( res= STV_SendPacket( REQUEST_BUFFER_STATUS, NULL, 0)) < 0) { fprintf( stderr, "STV_BufferStatus: Error requesting buffer status: %d\n", buffer) ; return -1 ; } else { /*fprintf( stderr, "STV_BufferStatus %2d\n", buffer) ; */ } AGAIN: if(( res= STV_ReceivePacket( buf, 0)) < 0) { fprintf( stderr, "STV_BufferStatus: Error reading: %d\n", res) ; return -1 ;; } if( buf[1]== REQUEST_BUFFER_STATUS) { buffers= STV_RecombineInt( buf[6], buf[7]) * 0x10000 + STV_RecombineInt( buf[8], buf[9]) ; if(( val= STV_GetBits( buffers, buffer, 1))== 1) { res= 0 ; /* image present */ } else { /*fprintf( stderr, "STV_BufferStatus %2d is empty\n", buffer) ; */ res= 1 ; /* empty */ } } else { /* The SBIG manual does not specify an ACK, but it is there (at least sometimes) */ if(( val= STV_CheckAck( buf))== 0) { /*fprintf( stderr, "STV_BufferStatus SAW ACK, reading again\n") ; */ goto AGAIN ; } /* The SBIG manual does not specify the cmd in the answer */ if( buf[1] != DISPLAY_ECHO) { fprintf( stderr, "STV_BufferStatus: unexpected cmd byte received %d\n", buf[1]) ; val= STV_RecombineInt(buf[2], buf[3]) ; res= STV_PrintBuffer( buf, 6+ val + 2) ; return -1 ; } else { /* a display packet is silently ignored, there are many of this kind */ fprintf( stderr, "STV_BufferStatus DISPLAY_ECHO received, try again\n") ; return -1 ; } } /* fprintf(stderr, "STV_BufferStatus leaving\n") ; */ return res; } /* Low level communication */ /* STV_ReceivePacket n_bytes read */ int STV_ReceivePacket( unsigned char *buf, int mode) { int i,j,k ; int n_bytes=0 ; int length=0 ; int res ; int trb=0 ; int pos=0 ; char display1[25] ; char display2[25] ; j= 0 ; tracking_buf[ 0]= 0 ; /*fprintf( stderr,"R") ; */ while(pos < 6) { /* Read the header first, calculate length of data */ /* At higher speeds the data arrives in smaller chunks, assembling the packet */ if(( trb= read( fd, (char *)(buf + pos), 1))== -1) { fprintf(stderr, "Error, %s\n", strerror(errno)) ; } if(buf[0]== 0xa5) { if( pos== 5) { pos++ ; break ; } else { pos+= trb ; /* could be zero */ } } else { /* In tracking mode the STV sends raw data (time, brightnes, centroid x,y). */ /* Under normal operation here appear pieces of a packet. This could happen */ /* on start up or if something goes wrong. */ tracking_buf[ j++]= buf[pos] ; /*fprintf(stderr, "READ: %d, read %d, pos %d, 0x%2x< %c\n", j, trb, pos, buf[pos], buf[pos]) ; */ } } if( j> 0) { /* Sometimes the packets are corrupt, e.g. at the very beginning */ /* Or it is tracking information */ tracking_buf[ j]= 0 ; if( mode== ON) { /* Tracking mode */ fprintf(stderr, "%s\n", tracking_buf) ; } else { for( k= 0 ; k< j; k++) { if(!( tracking_buf[ k] >29 && tracking_buf[ k] < 127)) { tracking_buf[ k]= 0x20 ; /* simply */ } } fprintf(stderr, "Not a packet: length: %d >%s<\n", j, tracking_buf) ; } } n_bytes= pos ; if(( buf[0]== 0xa5) && ( pos== 6)) { /* Check the sanity of the header part */ if((res= STV_CheckHeaderSum( buf))== 0) { length= (int)buf[3] * 0x100 + (int)buf[2]; ; if( length >0) { trb= 0 ; while( pos < 6 + length + 2) { /* header, data, check sum */ /* At higher speeds the data arrives in smaller chunks, assembling the packet */ if(( trb= read(fd, (char *)(buf + pos), (6 + length + 2)- pos))== -1) { fprintf(stderr, "STV_ReceivePacket: Error reading at serial port, %s\n", strerror( errno)) ; return -1 ; } pos += trb ; } n_bytes += pos ; /*fprintf(stderr, "STV_ReceivePacket: LEAVING LOOP length %d, to read %d, read %d, pos %d\n", length, (6 + length + 2)- pos, trb, pos) ; */ } } else { fprintf(stderr, "STV_ReceivePacket: Header check failed\n") ; return -1 ; } } else if( pos >0) { for(i= 0 ; i < 6 ; i++) { if( buf[i]==0xa5){ fprintf(stderr, "STV_ReceivePacket: pos= %d, saw 0xa5 at %d\n", pos, i) ; } } return -1 ; } else { fprintf(stderr, "STV_ReceivePacket: NO 0xa5 until pos= %d\n", pos) ; return -1 ; } if( length > 0) { /* Check the sanity of the data */ if((res= STV_CheckDataSum( buf))== -1) { return -1 ; } } /* Analyse the display and retrieve the values */ if( buf[1]== DISPLAY_ECHO) { for( i=0 ; i< 24; i++) { display1[i]= buf[i+6] ; if( display1[i]== 0 ){ display1[i]= 0x32 ; } display2[i]= buf[i+30] ; if( display2[i]== 0 ){ display2[i]= 0x32 ; } } display1[24]= 0 ; display2[24]= 0 ; /*fprintf(stderr, "STV_ReceivePacket: DISPLAY1 %s<\n", display1) ; */ /*fprintf(stderr, "STV_ReceivePacket: DISPLAY2 %s<\n", display2) ; */ /* CCD temperature */ if(( res= strncmp( "CCD Temp.", display2, 9)) ==0) { float t ; res= sscanf( display2, "CCD Temp. %f", &t) ; di.ccd_temperature= (double) t; /*fprintf(stderr, "STV_ReceivePacket: Read from DISPLAY2 %g<\n", di.ccd_temperature ) ; */ }/* further values can be stored here */ } return n_bytes ; } int STV_CheckHeaderSum( unsigned char *buf) { int sum = buf[0] + buf[1] + buf[2] + buf[3] ; /* Calculated header sum */ int sumbuf= STV_RecombineInt( buf[4],buf[5]) ; /* STV packet header sum */ if(buf[0] != 0xa5) { fprintf(stderr, "STV_CheckHeaderSum: Wrong start byte, skipping\n") ; return -1 ; } if( sum != sumbuf) { fprintf(stderr, "STV_CheckHeaderSum: NOK: %d==%d\n", sum, sumbuf ) ; return -1 ; } return 0 ; } int STV_CheckDataSum( unsigned char *buf) { /* *buf points to the beginning of the packet */ int j, n ; int sum= 0 ; int sumbuf=0 ; n= STV_RecombineInt( buf[2], buf[3]) ; if( n== 0) { fprintf(stderr, "STV_CheckDataSum: No data present\n") ; return 0 ; } sumbuf= STV_RecombineInt( buf[6 + n], buf[6 + n +1]) ; for( j=0; j < n ; j++) { sum += (int)buf[6 + j] ; } sum= sum & 0xffff ; if( sum != sumbuf) { fprintf(stderr, "DATA SUM NOK: %d !=%d\n", sum, sumbuf) ; return -1 ; } return 0 ; } int STV_PrintBuffer( unsigned char *buf, int n ) { /* For debugging purposes only */ int i ; fprintf(stderr, "\nHEADER: %d bytes ", n) ; for(i=0; i < n; i++) { if( i==6) { fprintf(stderr, "\nDATA : ") ; } fprintf(stderr, "%d:0x%2x<>%c< >>", i, (unsigned char)buf[i], (unsigned char)buf[i]) ; /*STV_PrintBits((unsigned int) buf[i], 8) ; */ } fprintf(stderr, "\n") ; return 0 ; } int STV_PrintBufferAsText( unsigned char *buf, int n ) { /* For debugging purposes only */ int i ; fprintf(stderr, "\nHEADER: %d bytes ", n) ; for(i=0; i < n; i++) { if( i==6) { fprintf(stderr, "\nDATA : ") ; } fprintf(stderr, "%c", (unsigned char)buf[i]) ; } fprintf(stderr, "\n") ; return 0 ; } /* Aggregates a STV command packet */ int STV_SendPacket( int cmd, int *data, int n) { char buf[1024]; int j,l ; int res ; int sum ; /* check sum */ /* Header section */ buf[0] = (unsigned char) 0xa5; /* start byte */ buf[1] = (unsigned char) cmd; /* command byte */ buf[2] = (unsigned char) 2 * n; /* data length N (low byte) */ buf[3] = (unsigned char) 0x00; /* data length N (high byte) */ sum = buf[0] + buf[1] + buf[2] + buf[3]; /* header checksum */ buf[4] = (unsigned char) sum % 0x100; /* header checksum low byte */ buf[5] = (unsigned char) (sum / 0x100); /* header checksum high byte */ /* DATA section */ l= 0 ; if( n > 0) { l= 2 ; /* Two bytes per value are sent to STV */ for( j=0; j < 2 * n ; j += 2) { buf[6+ j] = (unsigned char) (data[j/2] % 0x100); /* data low byte */ buf[7+ j] = (unsigned char) (data[j/2] / 0x100); /* data high byte */ } sum = 0 ; for( j=0; j < 2 * n ; j++) { if((int)buf[6+ j] < 0 ) { sum = sum + 0xff+ (int)buf[6+ j] + 1 ; } else { sum = sum + (int)buf[6+ j] ; } } buf[6 + 2 * n ] = (unsigned char) (sum % 0x10000) ; /* data checksum (low byte) */ buf[7 + 2 * n ] = (unsigned char) (sum / 0x100) ; /* data checksum (high byte) */ } if(( res= STV_CheckHeaderSum( (unsigned char *) buf)) != 0) { /* Check outgoing packet as well */ fprintf(stderr, "STV_SendPacket: corrupt header\n") ; if(n > 0) { if(( res= STV_CheckDataSum( (unsigned char *) buf)) != 0) { fprintf(stderr, "STV_SendPacket: corrupt data\n") ; } } } return STV_portWrite( buf, 8 + l * n ) ; } /* Returns 0 or -1 in case of an error */ int STV_portWrite( char *buf, int nbytes){ int bytesWritten = 0; /*fprintf( stderr,"w") ; */ while (nbytes > 0) { if((bytesWritten = write(fd, buf, nbytes)) == -1) { fprintf(stderr, "STV_portWrite: Error writing at serial port, %s\n", strerror( errno)) ; /* return -1 ; */ } if (bytesWritten < 0) { fprintf( stderr, "STV_portWrite: Error writing\n") ; return -1; } else { buf += bytesWritten; nbytes -= bytesWritten; } } return nbytes ; } int STV_CheckAck( unsigned char *buf) { /* Watch out for an ACK, for debugging purposes only */ int i ; unsigned char ackseq[]= {0xa5, 0x06, 0x00, 0x00, 0xab, 0x00} ; for(i= 0; i < 6; i++ ) { if( buf[i] != ackseq[i] ) { return -1 ; } } return 0 ; } unsigned int STV_RecombineInt( unsigned char low_byte, unsigned char high_byte) { return (unsigned int) high_byte * (unsigned int)0x100 + (unsigned int)low_byte ; } unsigned int STV_GetBits( unsigned int x, int p, int n){ /* from the C book */ return ( x >> (p+ 1-n)) & ~(~0 << n) ; } void STV_PrintBits( unsigned int x, int n) { /* debugging purposes only */ int i ; int res ; fprintf( stderr, "STV_PrintBits:\n") ; if( n> 8) { fprintf( stderr, "54321098 76543210\n") ; } else { fprintf( stderr, "76543210\n") ; } for( i= n; i >0 ; i--) { if(( i==8) && (n> 8)) { fprintf( stderr, " ") ; } if(( res=STV_GetBits( x, i-1, 1))==0) { fprintf( stderr, "0") ; } else { fprintf( stderr, "1") ; } } fprintf( stderr, "\n") ; } double STV_SetCCDTemperature( double set_value) { int i ; int res ; int delay= 40000 ; unsigned char buf[1024] ; /* 1st step */ res= STV_Interrupt() ; /* Reset Display */ tcflush(fd, TCIOFLUSH); usleep( 100000) ; STV_MenueCCDTemperature( delay) ; for( i=0 ; i< 100 ; i++) { /* Change to the highest temperature */ res= STV_LRRotaryIncrease() ; tcflush(fd, TCIOFLUSH); usleep( delay) ; } di.ccd_temperature= 25.2 ; /* The actual value is set in STV_ReceivePacket, needed to enter the while() loop */ i= 0 ; while( set_value < di.ccd_temperature) { /*fprintf( stderr, "STV_SetCCDTemperature %g %g\n", set_value, di.ccd_temperature) ; */ res= STV_LRRotaryDecrease() ; /* Lower CCD temperature */ /*fprintf(stderr, ":") ; */ usleep( 10000) ; res= STV_TerminateTXDisplay(); usleep( 10000) ; res= STV_TXDisplay(); /* That's the trick, STV sends at least one display */ res= STV_ReceivePacket( buf, 0) ; /* discard it */ /*STV_PrintBufferAsText( buf, res) ; */ if(( res != 62) || ( i++ > 100)) { /* why 56 + 6?, 6 + 48 + 6 */ STV_PrintBuffer( buf, res) ; /*STV_PrintBufferAsText( buf, res) ; */ return 0.0 ; } } res= STV_Interrupt() ; return di.ccd_temperature ; } int STV_MenueCCDTemperature( int delay) { int res ; res= STV_MenueSetup( delay) ; usleep( delay) ; res= STV_UDRotaryIncrease() ; /* Change to CCD Temperature */ /*usleep( delay) ; */ tcflush(fd, TCIOFLUSH); return 0 ; } #ifdef HAVE_NOVA_H int STV_SetDateTime( char *times) { int i ; int res ; int turn ; struct ln_date utm; int delay= 20000 ; /*fprintf(stderr, "STV_SetTime\n") ; */ if((times== NULL) || (( res= strlen(times))==0)) ln_get_date_from_sys(&utm); else { if( extractISOTime( times, &utm) < 0) { fprintf( stderr, "Bad time string %s\n", times) ; return -1 ; } } /* Print out the date and time in the standard format. */ /*fprintf( stderr, "TIME %s\n", asctime (utc)) ; */ /* 1st step */ res= STV_Interrupt() ; /* Reset Display */ usleep( delay) ; tcflush(fd, TCIOFLUSH); res= STV_MenueDateTime( delay) ; usleep( delay) ; res= STV_MenueDateTime( delay) ; /* This not an error */ usleep( delay) ; for( i=0 ; i< 13 ; i++) { /* Reset Month menu to the lef most position */ res= STV_LRRotaryDecrease() ; usleep( delay) ; } for( i=0 ; i< utm.months ; i++) { /* Set Month menu */ res= STV_LRRotaryIncrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } res= STV_AKey() ; /* Press the Parameter button */ usleep( delay) ; tcflush(fd, TCIOFLUSH); for( i=0 ; i< 32 ; i++) { /* Reset Day menu to the lef most position */ res= STV_LRRotaryDecrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } for( i= 0; i< utm.days-1 ; i++) { /* Set Day menu -1? */ res= STV_LRRotaryIncrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } res= STV_AKey() ; /* Press the Parameter button */ usleep( delay) ; tcflush(fd, TCIOFLUSH); for( i=0 ; i< 128 ; i++) { /* Reset Year menu to the lef most position, ATTENTION */ res= STV_LRRotaryDecrease() ; usleep( delay) ; /* sleep a 1/100 second */ tcflush(fd, TCIOFLUSH); } /* JM: Is this how you want not? Please verify the code! */ int ymenu = utm.years % 100; for( i=0 ; i< ymenu ; i++) { /* Set Year menu */ res= STV_LRRotaryIncrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } res= STV_AKey() ; /* Press the Parameter button */ usleep( delay) ; tcflush(fd, TCIOFLUSH); for( i=0 ; i< 25 ; i++) { /* Reset Hour menu to the lef most position, ATTENTION */ res= STV_LRRotaryDecrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } for( i=0 ; i< utm.hours ; i++) { /* Set Hour menu */ res= STV_LRRotaryIncrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } res= STV_AKey() ; /* Press the Parameter button */ usleep( delay) ; tcflush(fd, TCIOFLUSH); for( i=0 ; i< 61 ; i++) { /* Reset Minute menu to the lef most position, ATTENTION */ res= STV_LRRotaryDecrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } for( i=0 ; i< utm.minutes ; i++) { /* Set Minute menu */ res= STV_LRRotaryIncrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } res= STV_AKey() ; /* Press the Parameter button */ tcflush(fd, TCIOFLUSH); for( i=0 ; i< 5 ; i++) { /* Reset Seconds menu to the lef most position, ATTENTION */ res= STV_LRRotaryDecrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } if ( utm.seconds < 15) { turn= 0 ; } else if ( utm.seconds < 30) { turn= 1 ; } else if ( utm.seconds < 45) { turn= 2 ; } else { turn= 3 ; } for( i=0 ; i< turn ; i++) { /* Set Seconds menu, steps of 15 seconds */ res= STV_LRRotaryIncrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } res= STV_AKey() ; /* Press the Parameter button */ usleep( delay) ; tcflush(fd, TCIOFLUSH); res= STV_BKey() ; /* Press the Parameter button */ usleep( delay) ; tcflush(fd, TCIOFLUSH); res= STV_Interrupt() ; return 0 ; } #endif int STV_MenueDateTime( int delay) { int i ; int res ; res= STV_MenueSetup( delay) ; usleep( delay) ; res= STV_BKey() ; /* Press the Value button */ usleep( delay) ; for( i=0 ; i< 8 ; i++) { /* Reset Date menu to the lef most position */ res= STV_UDRotaryDecrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } return 0 ; } int STV_MenueSetup( int delay) { int i ; int res ; res= STV_Setup() ; /* Change to Setup */ usleep( delay) ; for( i=0 ; i< 16 ; i++) { /* Reset Setup menu to the lef most position */ res= STV_UDRotaryDecrease() ; usleep( delay) ; tcflush(fd, TCIOFLUSH); } return 0 ; } int STV_Connect( char *device, int baud) { /*fprintf( stderr, "STV_Connect\n") ; */ if(( fd= init_serial( device, baud, 8, 0, 1))== -1) { fprintf(stderr, "Error on port %s, %s\n", device, strerror(errno)) ; return -1 ; } return fd ; } /****************************************************************************** * shutdown_serial(..) ****************************************************************************** * Restores terminal settings of open serial port device and close the file. * Arguments: * fd: file descriptor of open serial port device. *****************************************************************************/ void shutdown_serial(int fd) { if (fd > 0) { if (tcsetattr(fd, TCSANOW, &orig_tty_setting) < 0) { perror("shutdown_serial: can't restore serial device's terminal settings."); } close(fd); } } /****************************************************************************** * init_serial(..) ****************************************************************************** * Opens and initializes a serial device and returns it's file descriptor. * Arguments: * device_name : device name string of the device to open (/dev/ttyS0, ...) * bit_rate : bit rate * word_size : number of data bits, 7 or 8, USE 8 DATA BITS with modbus * parity : 0=no parity, 1=parity EVEN, 2=parity ODD * stop_bits : number of stop bits : 1 or 2 * Return: * file descriptor of successfully opened serial device * or -1 in case of error. *****************************************************************************/ int init_serial(char *device_name, int bit_rate, int word_size, int parity, int stop_bits) { int fd; char *msg; /* open serial device */ fd = open(device_name, O_RDWR | O_NOCTTY); if (fd < 0) { if (asprintf(&msg, "init_serial: open %s failed", device_name) < 0) perror(NULL); else perror(msg); return -1; } /* save current tty settings */ if (tcgetattr(fd, &orig_tty_setting) < 0) { perror("init_serial: can't get terminal parameters."); return -1; } /* Control Modes */ /* Set bps rate */ int bps; switch (bit_rate) { case 0: bps = B0; break; case 50: bps = B50; break; case 75: bps = B75; break; case 110: bps = B110; break; case 134: bps = B134; break; case 150: bps = B150; break; case 200: bps = B200; break; case 300: bps = B300; break; case 600: bps = B600; break; case 1200: bps = B1200; break; case 1800: bps = B1800; break; case 2400: bps = B2400; break; case 4800: bps = B4800; break; case 9600: bps = B9600; break; case 19200: bps = B19200; break; case 38400: bps = B38400; break; case 57600: bps = B57600; break; case 115200: bps = B115200; break; case 230400: bps = B230400; break; default: if (asprintf(&msg, "init_serial: %d is not a valid bit rate.", bit_rate) < 0) perror(NULL); else perror(msg); return -1; } if ((cfsetispeed(&tty_setting, bps) < 0) || (cfsetospeed(&tty_setting, bps) < 0)) { perror("init_serial: failed setting bit rate."); return -1; } /* Control Modes */ /* set no flow control word size, parity and stop bits. */ /* Also don't hangup automatically and ignore modem status. */ /* Finally enable receiving characters. */ tty_setting.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | HUPCL | CRTSCTS); /* #ifdef CBAUDEX */ /*tty_setting.c_cflag &= ~(CBAUDEX); */ /*#endif */ /*#ifdef CBAUDEXT */ /*tty_setting.c_cflag &= ~(CBAUDEXT); */ /*#endif */ tty_setting.c_cflag |= (CLOCAL | CREAD); /* word size */ switch (word_size) { case 5: tty_setting.c_cflag |= CS5; break; case 6: tty_setting.c_cflag |= CS6; break; case 7: tty_setting.c_cflag |= CS7; break; case 8: tty_setting.c_cflag |= CS8; break; default: fprintf( stderr, "Default\n") ; if (asprintf(&msg, "init_serial: %d is not a valid data bit count.", word_size) < 0) perror(NULL); else perror(msg); return -1; } /* parity */ switch (parity) { case PARITY_NONE: break; case PARITY_EVEN: tty_setting.c_cflag |= PARENB; break; case PARITY_ODD: tty_setting.c_cflag |= PARENB | PARODD; break; default: fprintf( stderr, "Default1\n") ; if (asprintf(&msg, "init_serial: %d is not a valid parity selection value.", parity) < 0) perror(NULL); else perror(msg); return -1; } /* stop_bits */ switch (stop_bits) { case 1: break; case 2: tty_setting.c_cflag |= CSTOPB; break; default: fprintf( stderr, "Default2\n") ; if (asprintf(&msg, "init_serial: %d is not a valid stop bit count.", stop_bits) < 0) perror(NULL); else perror(msg); return -1; } /* Control Modes complete */ /* Ignore bytes with parity errors and make terminal raw and dumb. */ tty_setting.c_iflag &= ~(PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON | IXANY); tty_setting.c_iflag |= INPCK | IGNPAR | IGNBRK; /* Raw output. */ tty_setting.c_oflag &= ~(OPOST | ONLCR); /* Local Modes */ /* Don't echo characters. Don't generate signals. */ /* Don't process any characters. */ tty_setting.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN | NOFLSH | TOSTOP); tty_setting.c_lflag |= NOFLSH; /* blocking read until 1 char arrives */ tty_setting.c_cc[VMIN] = 1; tty_setting.c_cc[VTIME] = 0; /* now clear input and output buffers and activate the new terminal settings */ tcflush(fd, TCIOFLUSH); if (tcsetattr(fd, TCSANOW, &tty_setting)) { perror("init_serial: failed setting attributes on serial port."); shutdown_serial(fd); return -1; } return fd; } libindi-0.9.7/drivers/video/stvdriver.h0000644000175000017500000002011612241463551017111 0ustar jasemjasem#if 0 STV driver Copyright (C) 2006 Markus Wildi, markus.wildi@datacomm.ch 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 #define OFF 0 #define ON 1 #define REQUEST_DOWNLOAD 0x00 #define REQUEST_DOWNLOAD_ALL 0x01 #define DOWNLOAD_COMPLETE 0x02 #define REQUEST_BUFFER_STATUS 0x03 #define REQUEST_IMAGE_INFO 0x04 #define REQUEST_IMAGE_DATA 0x05 #define ACK 0x06 #define REQUEST_COMPRESSED_IMAGE_DATA 0x07 #define SEND_KEY_PATTERN 0x08 #define DISPLAY_ECHO 0x09 #define FILE_STATUS 0x0b #define REQUEST_ACK 0x10 #define NACK 0x15 /* Rotary Knob Key Patterns */ #define LR_ROTARY_DECREASE_PATTERN 0x8000 #define LR_ROTARY_INCREASE_PATTERN 0x4000 #define UD_ROTARY_DECREASE_PATTERN 0x2000 #define UD_ROTARY_INCREASE_PATTERN 0x1000 #define SHIFT_PATTERN 0x0008 /* increases rotary speed when 1 */ /* Mode Key Patterns */ #define CAL_KEY_PATTERN 0x0100 #define TRACK_KEY_PATTERN 0x0200 #define DISPLAY_KEY_PATTERN 0x0400 #define FILEOPS_KEY_PATTERN 0x0800 #define A_KEY_PATTERN 0x0010 #define SETUP_KEY_PATTERN 0x0020 #define B_KEY_PATTERN 0x0040 #define INT_KEY_PATTERN 0x0080 #define FOCUS_KEY_PATTERN 0x0001 #define IMAGE_KEY_PATTERN 0x0002 #define MONITOR_KEY_PATTERN 0x0004 /* The following bit masks have been take from Sbig's documentation */ #define ID_BITS_MASK 0x0001 /* mask for no bits*/ #define ID_BITS_10 0x0001 /* image is full 10 bits*/ #define ID_BITS_8 0x0000 /* image from focus, only 8 bits*/ #define ID_UNITS_MASK 0x0002 /* mask for units for scope*/ #define ID_UNITS_INCHES 0x0002 /* units were inches*/ #define ID_UNITS_CM 0x0000 /* units were cm*/ #define ID_SCOPE_MASK 0x0004 /* mask for telescope type*/ #define ID_SCOPE_REFRACTOR 0x0004 /* scope was refractor*/ #define ID_SCOPE_REFLECTOR 0x0000 /* scope was reflector*/ #define ID_DATETIME_MASK 0x0008 /* mask for date/time valid*/ #define ID_DATETIME_VALID 0x0008 /* date/time was set*/ #define ID_DATETIME_INVALID 0x0000 /* date/time was not set*/ #define ID_BIN_MASK 0x0030 /* mask for binning mode*/ #define ID_BIN_1X1 0x0010 /* binning was 1x1*/ #define ID_BIN_2X2 0x0020 /* binning was 2x2*/ #define ID_BIN_3X3 0x0030 /* binning was 3x3*/ #define ID_PM_MASK 0x0400 /* mask for am/pm in time*/ #define ID_PM_PM 0x0400 /* time was pm, add 12 hours*/ #define ID_PM_AM 0x0000 /* time was am, don;t add 12 hours*/ #define ID_FILTER_MASK 0x0800 /* mask for filter status*/ #define ID_FILTER_LUNAR 0x0800 /* lunar filter was used for image*/ #define ID_FILTER_NP 0x0000 /* no filter was used for image*/ #define ID_DARKSUB_MASK 0x1000 /* mask for dark subtraction*/ #define ID_DARKSUB_YES 0x1000 /* image was dark subtracted*/ #define ID_DARKSUB_NO 0x0000 /* image was not dark subtracted*/ #define ID_MOSAIC_MASK 0x6000 /* mask for mosaic status*/ #define ID_MOSAIC_NONE 0x0000 /* no mosaic, one image per frame*/ #define ID_MOSAIC_SMALL 0x2000 /* small mosaic: 40x40 pixels/image*/ #define ID_MOSAIC_LARGE 0x4000 /* large mosaic: 106x100 pixels/image*/ /* IMAGE_INFO - data for the image Notes: height - 0 or 0xFFFF if no data present exposure - 100-60000 = 1.00 - 600 secs by 0.01 60001-60999 = 0.001 - 0.999 secs by 0.001 packedDate - bits 6-0 = year - 1999 (0 -127) bits 11-7 = day ( 1-31) bits 15-12 = month (1-12) packedTime - bits 6-0 = seconds (0-59) bits 7-12 = minutes (0-59) bits 15-13 = hours mod 12 (0-11) + bit in descriptor can add 12 */ typedef struct { unsigned int descriptor ; /* set of bits*/ unsigned int height, width; /* image sze */ unsigned int top, left ; /* position in buffer */ double exposure ; /* exposure time */ unsigned int noExposure ; /* number of exposures added */ unsigned int analogGain ; /*analog gain */ int digitalGain ; /* digital gain */ unsigned int focalLength ; /*focal length of telescope */ unsigned int aperture ; /* aperture diameter */ unsigned int packedDate ; /* date of image */ unsigned int year ; unsigned int month ; unsigned int day ; unsigned int packedTime ; /* time of image */ unsigned int seconds ; /* time of image */ unsigned int minutes ; /* time of image */ unsigned int hours ; /* time of image */ double ccdTemp ; /* temperature of ccd in 1/100 deg C */ unsigned int siteID; /* site id */ unsigned int eGain ; /* eGain in 1/100th e/ADU */ unsigned int background ; /* background for display */ unsigned int range ; /* range for display */ unsigned int pedestal ; /* Track and Accumulate pedestal */ unsigned int ccdTop, ccdLeft ; /* position of pixels on CCD array */ unsigned int adcResolution ; /* value, 8 or 10 bits */ unsigned int units ; /* 0= cm, 1=inch */ unsigned int telescopeType ; /* 0=refractor, 1= reflector */ unsigned int dateTimeValid ; /* 0= valid */ unsigned int binning ; /* 1x1=1, 2x2=2, 3x3=3 */ unsigned int filterStatus ; /* 0= no filter, 1= lunar filter */ unsigned int darkFrameSuntracted ; /* 0= no, 1= yes */ unsigned int imageIsMosaic ; /* 0=no, 1=40x40 pixels, 2=106x100 pixels */ double pixelSize ; /* 7.4 um */ double minValue ; /* Pixel Contents */ double maxValue ; } IMAGE_INFO ; /* * $Id: serial.h 49 2006-08-25 18:07:14Z lukas $ * * Copyright (C) 2006, Lukas Zimmermann, Basel, Switzerland. * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Or visit http://www.gnu.org/licenses/gpl.html. */ #ifndef __serial_h__ #define __serial_h__ #define PARITY_NONE 0 #define PARITY_EVEN 1 #define PARITY_ODD 2 typedef unsigned char byte; /* define byte type */ /* Restores terminal settings of open serial port device and close the file. */ void shutdown_serial(int fd); /* Opens and initializes a serial device and returns it's file descriptor. */ int init_serial(char *device_name, int bit_rate, int word_size, int parity, int stop_bits); /* Calculates the 16 bit CRC of an array of bytes and returns it. */ unsigned int calc_crc(byte byte_array[], int size); #endif /*#ifndef __serial_h__*/ libindi-0.9.7/drivers/video/v4ldriver.h0000644000175000017500000001156112241463551017006 0ustar jasemjasem#if 0 V4L INDI Driver INDI Interface for V4L devices Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #ifndef V4L_DRIVER_H #define V4L_DRIVER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "indidevapi.h" #include "indicom.h" #include #include "eventloop.h" #include #ifdef HAVE_LINUX_VIDEODEV2_H #include "webcam/v4l2_base.h" #else #include "webcam/v4l1_base.h" #endif #define COMM_GROUP "Main Control" #define IMAGE_CONTROL "Image Control" #define IMAGE_GROUP "Image Settings" #define MAX_PIXELS 4096 /* Max number of pixels in one dimension */ #define ERRMSGSIZ 1024 #define TEMPFILE_LEN 16 class V4L_Driver { public: V4L_Driver(); virtual ~V4L_Driver(); /* INDI Functions that must be called from indidrivermain */ virtual void ISGetProperties (const char *dev); virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual void initCamBase(); virtual void initProperties(const char *dev); static void newFrame(void *p); void updateFrame(); protected: /* Structs */ typedef struct { int width; int height; int expose; unsigned char *Y; unsigned char *U; unsigned char *V; unsigned char *colorBuffer; unsigned char *compressedFrame; } img_t; /* Switches */ ISwitch PowerS[2]; ISwitch StreamS[2]; ISwitch CompressS[2]; ISwitch ImageTypeS[2]; /* Texts */ IText PortT[1]; IText camNameT[1]; /* Numbers */ INumber ExposeTimeN[1]; INumber FrameRateN[1]; INumber FrameN[4]; #ifndef HAVE_LINUX_VIDEODEV2_H INumber ImageAdjustN[5]; #endif /* BLOBs */ IBLOB imageB; /* Switch vectors */ ISwitchVectorProperty PowerSP; /* Connection switch */ ISwitchVectorProperty StreamSP; /* Stream switch */ ISwitchVectorProperty CompressSP; /* Compress stream switch */ ISwitchVectorProperty ImageTypeSP; /* Color or grey switch */ /* Number vectors */ INumberVectorProperty ExposeTimeNP; /* Exposure */ INumberVectorProperty FrameRateNP; /* Frame rate */ INumberVectorProperty FrameNP; /* Stream dimenstion */ INumberVectorProperty ImageAdjustNP; /* Image controls */ /* Text vectors */ ITextVectorProperty PortTP; ITextVectorProperty camNameTP; /* BLOB vectors */ IBLOBVectorProperty imageBP; /* Data stream */ /* Initilization functions */ virtual void connectCamera(void); virtual void getBasicData(void); /* Stream/FITS functions */ void updateStream(); void uploadFile(const char * filename); int writeFITS(const char *filename, char errmsg[]); int grabImage(void); void addFITSKeywords(fitsfile *fptr); void allocateBuffers(); void releaseBuffers(); /* Helper functions */ int checkPowerN(INumberVectorProperty *np); int checkPowerS(ISwitchVectorProperty *sp); int checkPowerT(ITextVectorProperty *tp); #ifndef HAVE_LINUX_VIDEODEV2_H virtual void updateV4L1Controls(); V4L1_Base *v4l_base; #else virtual void updateV4L2Controls(); V4L2_Base *v4l_base; #endif char device_name[MAXINDIDEVICE]; unsigned char *fitsData; /* Buffer to hold the FITS file */ int frameCount; /* For debugging */ double divider; /* For limits */ img_t * V4LFrame; /* Video frame */ time_t capture_start; /* To calculate how long a frame take */ time_t capture_end; }; #endif libindi-0.9.7/drivers/video/v4lphilips.cpp0000644000175000017500000004253512241463551017523 0ustar jasemjasem/* Phlips webcam INDI driver Copyright (C) 2003-2005 by Jasem Mutlaq 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 2005.04.29 JM: There is no need for this file for Video 4 Linux 2. It is kept for V4L 1 compatibility. */ #include "v4lphilips.h" #include "webcam/pwc-ioctl.h" V4L_Philips::V4L_Philips() : V4L_Driver() { } V4L_Philips::~V4L_Philips() { } void V4L_Philips::initCamBase() { #ifdef HAVE_LINUX_VIDEODEV2_H v4l_base = new V4L2_Base(); #else v4l_pwc = new V4L1_PWC(); v4l_base = (V4L1_Base *) v4l_pwc; #endif } void V4L_Philips::initProperties(const char *dev) { // Call parent V4L_Driver::initProperties(dev); IUFillSwitch(&BackLightS[0], "ON", "", ISS_OFF); IUFillSwitch(&BackLightS[1], "OFF", "", ISS_ON); IUFillSwitchVector(&BackLightSP, BackLightS, NARRAY(BackLightS), dev, "Back Light", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0 , IPS_IDLE); IUFillSwitch(&AntiFlickerS[0], "ON", "", ISS_OFF); IUFillSwitch(&AntiFlickerS[1], "OFF", "", ISS_ON); IUFillSwitchVector(&AntiFlickerSP, AntiFlickerS, NARRAY(AntiFlickerS), dev, "Anti Flicker", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0 , IPS_IDLE); IUFillSwitch(&NoiseReductionS[0], "None", "", ISS_ON); IUFillSwitch(&NoiseReductionS[1], "Low", "", ISS_OFF); IUFillSwitch(&NoiseReductionS[2], "Medium", "", ISS_OFF); IUFillSwitch(&NoiseReductionS[3], "High", "", ISS_OFF); IUFillSwitchVector(&NoiseReductionSP, NoiseReductionS, NARRAY(NoiseReductionS), dev, "Noise Reduction", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&CamSettingS[0], "Save", "", ISS_OFF); IUFillSwitch(&CamSettingS[1], "Restore", "", ISS_OFF); IUFillSwitch(&CamSettingS[2], "Factory", "", ISS_OFF); IUFillSwitchVector(&CamSettingSP, CamSettingS, NARRAY(CamSettingS), dev, "Settings", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&WhiteBalanceModeS[0], "Auto" , "", ISS_ON); IUFillSwitch(&WhiteBalanceModeS[1], "Manual" , "", ISS_OFF); IUFillSwitch(&WhiteBalanceModeS[2], "Indoor" , "", ISS_OFF); IUFillSwitch(&WhiteBalanceModeS[3], "Outdoor" , "", ISS_OFF); IUFillSwitch(&WhiteBalanceModeS[4], "Fluorescent" , "", ISS_OFF); IUFillSwitchVector(&WhiteBalanceModeSP, WhiteBalanceModeS, NARRAY(WhiteBalanceModeS), dev, "White Balance Mode", "", IMAGE_CONTROL, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillNumber(&WhiteBalanceN[0], "Manual Red", "", "%0.f", 0., 256., 1., 0.); IUFillNumber(&WhiteBalanceN[1], "Manual Blue", "", "%0.f", 0., 256., 1., 0.); IUFillNumberVector(&WhiteBalanceNP, WhiteBalanceN, NARRAY(WhiteBalanceN), dev, "White Balance", "", IMAGE_CONTROL, IP_RW, 60, IPS_IDLE); IUFillNumber(&ShutterSpeedN[0], "Speed", "", "%0.f", 0., 65535., 100., 0.); IUFillNumberVector(&ShutterSpeedNP, ShutterSpeedN, NARRAY(ShutterSpeedN), dev, "Shutter Speed", "", COMM_GROUP, IP_RW, 60, IPS_IDLE); } void V4L_Philips::ISGetProperties (const char *dev) { if (dev && strcmp (device_name, dev)) return; #ifdef HAVE_LINUX_VIDEODEV2_H V4L_Driver::ISGetProperties(dev); return; #endif /* COMM_GROUP */ IDDefSwitch(&PowerSP, NULL); IDDefText(&PortTP, NULL); IDDefText(&camNameTP, NULL); IDDefSwitch(&StreamSP, NULL); IDDefNumber(&FrameRateNP, NULL); IDDefNumber(&ExposeTimeNP, NULL); IDDefNumber(&ShutterSpeedNP, NULL); IDDefBLOB(&imageBP, NULL); /* Image Groups */ IDDefSwitch(&CompressSP, NULL); IDDefSwitch(&ImageTypeSP, NULL); IDDefNumber(&FrameNP, NULL); IDDefNumber(&ImageAdjustNP, NULL); /* Image Control */ IDDefSwitch(&WhiteBalanceModeSP, NULL); IDDefNumber(&WhiteBalanceNP, NULL); IDDefSwitch(&BackLightSP, NULL); IDDefSwitch(&AntiFlickerSP, NULL); IDDefSwitch(&NoiseReductionSP, NULL); IDDefSwitch(&CamSettingSP, NULL); } void V4L_Philips::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { /* ignore if not ours */ if (dev && strcmp (device_name, dev)) return; /* Connection */ if (!strcmp (name, PowerSP.name)) { IUResetSwitch(&PowerSP); IUUpdateSwitch(&PowerSP, states, names, n); connectCamera(); return; } #ifndef HAVE_LINUX_VIDEODEV2_H /* Anti Flicker control */ if (!strcmp (AntiFlickerSP.name, name)) { if (checkPowerS(&AntiFlickerSP)) return; AntiFlickerSP.s = IPS_IDLE; IUResetSwitch(&AntiFlickerSP); IUUpdateSwitch(&AntiFlickerSP, states, names, n); if (AntiFlickerS[0].s == ISS_ON) { if (v4l_pwc->setFlicker(true, errmsg) < 0) { AntiFlickerS[0].s = ISS_OFF; AntiFlickerS[1].s = ISS_ON; IDSetSwitch(&AntiFlickerSP, "%s", errmsg); return; } AntiFlickerSP.s = IPS_OK; IDSetSwitch(&AntiFlickerSP, NULL); } else { if (v4l_pwc->setFlicker(false, errmsg) < 0) { AntiFlickerS[0].s = ISS_ON; AntiFlickerS[1].s = ISS_OFF; IDSetSwitch(&AntiFlickerSP, "%s", errmsg); return; } IDSetSwitch(&AntiFlickerSP, NULL); } return; } /* Back light compensation */ if (!strcmp (BackLightSP.name, name)) { if (checkPowerS(&BackLightSP)) return; BackLightSP.s = IPS_IDLE; IUResetSwitch(&BackLightSP); IUUpdateSwitch(&BackLightSP, states, names, n); if (BackLightS[0].s == ISS_ON) { if (v4l_pwc->setBackLight(true, errmsg) < 0) { BackLightS[0].s = ISS_OFF; BackLightS[1].s = ISS_ON; IDSetSwitch(&BackLightSP, "%s", errmsg); return; } BackLightSP.s = IPS_OK; IDSetSwitch(&BackLightSP, NULL); } else { if (v4l_pwc->setBackLight(false, errmsg) < 0) { BackLightS[0].s = ISS_ON; BackLightS[1].s = ISS_OFF; IDSetSwitch(&BackLightSP, "%s", errmsg); return; } IDSetSwitch(&BackLightSP, NULL); } return; } /* Noise reduction control */ if (!strcmp (NoiseReductionSP.name, name)) { if (checkPowerS(&NoiseReductionSP)) return; NoiseReductionSP.s = IPS_IDLE; IUResetSwitch(&NoiseReductionSP); IUUpdateSwitch(&NoiseReductionSP, states, names, n); for (int i=0; i < 4; i++) if (NoiseReductionS[i].s == ISS_ON) { index = i; break; } if (v4l_pwc->setNoiseRemoval(index, errmsg) < 0) { IUResetSwitch(&NoiseReductionSP); NoiseReductionS[0].s = ISS_ON; IDSetSwitch(&NoiseReductionSP, "%s", errmsg); return; } NoiseReductionSP.s = IPS_OK; IDSetSwitch(&NoiseReductionSP, NULL); return; } /* White balace mode */ if (!strcmp (WhiteBalanceModeSP.name, name)) { if (checkPowerS(&WhiteBalanceModeSP)) return; WhiteBalanceModeSP.s = IPS_IDLE; IUResetSwitch(&WhiteBalanceModeSP); IUUpdateSwitch(&WhiteBalanceModeSP, states, names, n); for (int i=0; i < 5; i++) if (WhiteBalanceModeS[i].s == ISS_ON) { index = i; break; } switch (index) { // Auto case 0: if (v4l_pwc->setWhiteBalanceMode(PWC_WB_AUTO, errmsg) < 0) { IUResetSwitch(&WhiteBalanceModeSP), WhiteBalanceModeS[0].s = ISS_ON; IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); return; } break; // Manual case 1: if (v4l_pwc->setWhiteBalanceMode(PWC_WB_MANUAL, errmsg) < 0) { IUResetSwitch(&WhiteBalanceModeSP), WhiteBalanceModeS[0].s = ISS_ON; IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); return; } break; // Indoor case 2: if (v4l_pwc->setWhiteBalanceMode(PWC_WB_INDOOR, errmsg) < 0) { IUResetSwitch(&WhiteBalanceModeSP), WhiteBalanceModeS[0].s = ISS_ON; IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); return; } break; // Outdoor case 3: if (v4l_pwc->setWhiteBalanceMode(PWC_WB_OUTDOOR, errmsg) < 0) { IUResetSwitch(&WhiteBalanceModeSP), WhiteBalanceModeS[0].s = ISS_ON; IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); return; } break; // Flurescent case 4: if (v4l_pwc->setWhiteBalanceMode(PWC_WB_FL, errmsg) < 0) { IUResetSwitch(&WhiteBalanceModeSP), WhiteBalanceModeS[0].s = ISS_ON; IDSetSwitch(&WhiteBalanceModeSP, "%s", errmsg); return; } break; } WhiteBalanceModeSP.s = IPS_OK; IDSetSwitch(&WhiteBalanceModeSP, NULL); return; } /* Camera setttings */ if (!strcmp (CamSettingSP.name, name)) { if (checkPowerS(&CamSettingSP)) return; CamSettingSP.s = IPS_IDLE; IUResetSwitch(&CamSettingSP); IUUpdateSwitch(&CamSettingSP, states, names, n); if (CamSettingS[0].s == ISS_ON) { if (v4l_pwc->saveSettings(errmsg) < 0) { IUResetSwitch(&CamSettingSP); IDSetSwitch(&CamSettingSP, "%s", errmsg); return; } CamSettingSP.s = IPS_OK; IDSetSwitch(&CamSettingSP, "Settings saved."); return; } if (CamSettingS[1].s == ISS_ON) { v4l_pwc->restoreSettings(); IUResetSwitch(&CamSettingSP); CamSettingSP.s = IPS_OK; IDSetSwitch(&CamSettingSP, "Settings restored."); updateV4L1Controls(); return; } if (CamSettingS[2].s == ISS_ON) { v4l_pwc->restoreFactorySettings(); IUResetSwitch(&CamSettingSP); CamSettingSP.s = IPS_OK; IDSetSwitch(&CamSettingSP, "Factory settings restored."); updateV4L1Controls(); return; } } #endif // Call parent V4L_Driver::ISNewSwitch(dev, name, states, names, n); } void V4L_Philips::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { V4L_Driver::ISNewText(dev, name, texts, names, n); } void V4L_Philips::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // Nothing for V4L 2 to do here #ifndef HAVE_LINUX_VIDEODEV2_H char errmsg[ERRMSGSIZ]; /* Frame rate */ if (!strcmp (FrameRateNP.name, name)) { if (checkPowerN(&FrameRateNP)) return; FrameRateNP.s = IPS_IDLE; int oldFP = (int) FrameRateN[0].value; if (IUUpdateNumber(&FrameRateNP, values, names, n) < 0) return; if (v4l_pwc->setFrameRate( (int) FrameRateN[0].value, errmsg) < 0) { FrameRateN[0].value = oldFP; IDSetNumber(&FrameRateNP, "%s", errmsg); return; } FrameRateNP.s = IPS_OK; IDSetNumber(&FrameRateNP, NULL); return; } if (!strcmp (ShutterSpeedNP.name, name)) { if (checkPowerN(&ShutterSpeedNP)) return; ShutterSpeedNP.s = IPS_IDLE; if (v4l_pwc->setExposure( (int) values[0], errmsg) < 0) { IDSetNumber(&ShutterSpeedNP, "%s", errmsg); return; } ShutterSpeedN[0].value = values[0]; ShutterSpeedNP.s = IPS_OK; IDSetNumber(&ShutterSpeedNP, NULL); return; } /* White balance */ if (!strcmp (WhiteBalanceNP.name, name)) { if (checkPowerN(&WhiteBalanceNP)) return; WhiteBalanceNP.s = IPS_IDLE; int oldBalance[2]; oldBalance[0] = (int) WhiteBalanceN[0].value; oldBalance[1] = (int) WhiteBalanceN[1].value; if (IUUpdateNumber(&WhiteBalanceNP, values, names, n) < 0) return; if (v4l_pwc->setWhiteBalanceRed( (int) WhiteBalanceN[0].value * 256, errmsg)) { WhiteBalanceN[0].value = oldBalance[0]; WhiteBalanceN[1].value = oldBalance[1]; IDSetNumber(&WhiteBalanceNP, "%s", errmsg); return; } if (v4l_pwc->setWhiteBalanceBlue( (int) WhiteBalanceN[1].value * 256, errmsg)) { WhiteBalanceN[0].value = oldBalance[0]; WhiteBalanceN[1].value = oldBalance[1]; IDSetNumber(&WhiteBalanceNP, "%s", errmsg); return; } IUResetSwitch(&WhiteBalanceModeSP); WhiteBalanceModeS[1].s = ISS_ON; WhiteBalanceModeSP.s = IPS_OK; WhiteBalanceNP.s = IPS_OK; IDSetSwitch(&WhiteBalanceModeSP, NULL); IDSetNumber(&WhiteBalanceNP, NULL); return; } #endif // Call parent V4L_Driver::ISNewNumber(dev, name, values, names, n); } void V4L_Philips::connectCamera() { char errmsg[ERRMSGSIZ]; switch (PowerS[0].s) { case ISS_ON: #ifdef HAVE_LINUX_VIDEODEV2_H if (v4l_base->connectCam(PortT[0].text, errmsg, V4L2_PIX_FMT_YUV420) < 0) #else if (v4l_base->connectCam(PortT[0].text, errmsg) < 0) #endif { PowerSP.s = IPS_IDLE; PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; IDSetSwitch(&PowerSP, "Error: unable to open device"); IDLog("Error: %s\n", errmsg); return; } /* Sucess! */ PowerS[0].s = ISS_ON; PowerS[1].s = ISS_OFF; PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Philips Webcam is online. Retrieving basic data."); v4l_base->registerCallback(newFrame, this); IDLog("Philips Webcam is online. Retrieving basic data.\n"); getBasicData(); break; case ISS_OFF: PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; PowerSP.s = IPS_IDLE; v4l_base->disconnectCam(); IDSetSwitch(&PowerSP, "Philips Webcam is offline."); break; } } #ifndef HAVE_LINUX_VIDEODEV2_H /* Retrieves basic data from the device upon connection.*/ void V4L_Philips::getBasicData() { char errmsg[ERRMSGSIZ]; bool result; int xmax, ymax, xmin, ymin, index; v4l_pwc->getMaxMinSize(xmax, ymax, xmin, ymin); IDLog("X (%d,%d), Y (%d,%d)\n", xmin, xmax, ymin, ymax); /* Width */ FrameN[2].value = v4l_pwc->getWidth(); FrameN[2].min = xmin; FrameN[2].max = xmax; /* Height */ FrameN[3].value = v4l_pwc->getHeight(); FrameN[3].min = ymin; FrameN[3].max = ymax; IDSetNumber(&FrameNP, NULL); IUUpdateMinMax(&FrameNP); IUSaveText(&camNameT[0], v4l_pwc->getDeviceName()); IDSetText(&camNameTP, NULL); IDLog("Raw values\n Contrast: %d \n Brightness %d \n Color %d \n Sharpness %d \n Gain %d \n Gamma %d \n", v4l_pwc->getContrast(), v4l_pwc->getBrightness(), v4l_pwc->getColor(), v4l_pwc->getSharpness(), v4l_pwc->getGain(), v4l_pwc->getGama()); updateV4L1Controls(); if (v4l_pwc->setFrameRate( (int) FrameRateN[0].value, errmsg) < 0) { FrameRateNP.s = IPS_ALERT; IDSetNumber(&FrameRateNP, "%s", errmsg); } else { FrameRateNP.s = IPS_OK; IDSetNumber(&FrameRateNP, NULL); } result = v4l_pwc->getBackLight(); if (result) { BackLightS[0].s = ISS_ON; BackLightS[1].s = ISS_OFF; } else { BackLightS[0].s = ISS_OFF; BackLightS[1].s = ISS_ON; } IDSetSwitch(&BackLightSP, NULL); result = v4l_pwc->getFlicker(); if (result) { AntiFlickerS[0].s = ISS_ON; AntiFlickerS[1].s = ISS_OFF; } else { AntiFlickerS[0].s = ISS_OFF; AntiFlickerS[1].s = ISS_ON; } IDSetSwitch(&AntiFlickerSP, NULL); index = v4l_pwc->getNoiseRemoval(); IUResetSwitch(&NoiseReductionSP); NoiseReductionS[index].s = ISS_ON; IDSetSwitch(&NoiseReductionSP, NULL); index = v4l_pwc->getWhiteBalance(); IUResetSwitch(&WhiteBalanceModeSP); switch (index) { case PWC_WB_AUTO: WhiteBalanceModeS[0].s = ISS_ON; break; case PWC_WB_MANUAL: WhiteBalanceModeS[1].s = ISS_ON; break; case PWC_WB_INDOOR: WhiteBalanceModeS[2].s = ISS_ON; break; case PWC_WB_OUTDOOR: WhiteBalanceModeS[3].s = ISS_ON; break; case PWC_WB_FL: WhiteBalanceModeS[3].s = ISS_ON; break; } IDSetSwitch(&WhiteBalanceModeSP, NULL); } #endif #ifndef HAVE_LINUX_VIDEODEV2_H void V4L_Philips::updateV4L1Controls() { int index =0; ImageAdjustN[0].value = v4l_pwc->getContrast() / 256.; ImageAdjustN[1].value = v4l_pwc->getBrightness() / 256.; ImageAdjustN[2].value = v4l_pwc->getColor() / 256.; index = v4l_pwc->getSharpness(); if (index < 0) ImageAdjustN[3].value = -1; else ImageAdjustN[3].value = v4l_pwc->getSharpness() / 256.; ImageAdjustN[4].value = v4l_pwc->getGain() / 256.; ImageAdjustN[5].value = v4l_pwc->getGama() / 256.; ImageAdjustNP.s = IPS_OK; IDSetNumber(&ImageAdjustNP, NULL); } #endif libindi-0.9.7/drivers/video/indi_philips.cpp0000644000175000017500000000376212241463551020077 0ustar jasemjasem#if 0 V4L INDI Driver INDI Interface for V4L devices (Philips) Copyright (C) 2003-2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 "v4lphilips.h" V4L_Philips *MainCam = NULL; /* Main and only camera */ /* send client definitions of all properties */ void ISInit() { if (MainCam == NULL) { MainCam = new V4L_Philips(); MainCam->initProperties("Philips Webcam"); MainCam->initCamBase(); } } void ISGetProperties (const char *dev) { ISInit(); MainCam->ISGetProperties(dev); } void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); MainCam->ISNewSwitch(dev, name, states, names, n); } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); MainCam->ISNewText(dev, name, texts, names, n); } void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); MainCam->ISNewNumber(dev, name, values, names, n); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) {} void ISSnoopDevice (XMLEle *root) {} libindi-0.9.7/drivers/ccd/0000755000175000017500000000000012241463551014333 5ustar jasemjasemlibindi-0.9.7/drivers/ccd/ccd_simulator.cpp0000644000175000017500000010410512241463551017670 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. . 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 Library General Public License for more details. . You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "ccd_simulator.h" #include #include #include #include #include #include #include // We declare an auto pointer to ccdsim. std::auto_ptr ccdsim(0); void ISPoll(void *p); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(ccdsim.get() == 0) ccdsim.reset(new CCDSim()); //IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { ISInit(); ccdsim->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); ccdsim->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); ccdsim->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); ccdsim->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); ccdsim->ISSnoopDevice(root); } CCDSim::CCDSim() { //ctor testvalue=0; AbortGuideFrame=false; AbortPrimaryFrame = false; ShowStarField=true; HasSt4Port=true; HasGuideHead=true; polarError=0; polarDrift=0; usePE = false; raPE=RA; decPE=Dec; // sxvh9 bias=1500; maxnoise=20; maxval=65000; maxpix=0; minpix =65000; limitingmag=11.5; saturationmag=2; focallength=1280; // focal length of the telescope in millimeters guider_focallength=1280; OAGoffset=0; // An oag is offset this much from center of scope position (arcminutes); skyglow=40; seeing=3.5; // fwhm of our stars ImageScalex=1.0; // preset with a valid non-zero ImageScaley=1.0; time(&RunStart); // Our PEPeriod is 8 minutes // and we have a 22 arcsecond swing PEPeriod=8*60; PEMax=11; GuideRate=7; // guide rate is 7 arcseconds per second TimeFactor=1; SimulatorSettingsNV = new INumberVectorProperty; TimeFactorSV = new ISwitchVectorProperty; // Filter stuff FilterSlotN[0].min = 1; FilterSlotN[0].max = 5; } bool CCDSim::SetupParms() { int nbuf; SetCCDParams(SimulatorSettingsN[0].value,SimulatorSettingsN[1].value,16,SimulatorSettingsN[2].value,SimulatorSettingsN[3].value); // Kwiq maxnoise=SimulatorSettingsN[8].value; skyglow=SimulatorSettingsN[9].value; maxval=SimulatorSettingsN[4].value; bias=SimulatorSettingsN[5].value; limitingmag=SimulatorSettingsN[7].value; saturationmag=SimulatorSettingsN[6].value; OAGoffset=SimulatorSettingsN[10].value; // An oag is offset this much from center of scope position (arcminutes); polarError=SimulatorSettingsN[11].value; polarDrift=SimulatorSettingsN[12].value; nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8; nbuf += 512; PrimaryCCD.setFrameBufferSize(nbuf); GetFilterNames(FILTER_TAB); return true; } bool CCDSim::Connect() { int nbuf; SetTimer(1000); // start the timer return true; } CCDSim::~CCDSim() { //dtor } const char * CCDSim::getDefaultName() { return (char *)"CCD Simulator"; } bool CCDSim::initProperties() { // Most hardware layers wont actually have indi properties defined // but the simulators are a special case INDI::CCD::initProperties(); IUFillNumber(&SimulatorSettingsN[0],"SIM_XRES","CCD X resolution","%4.0f",0,2048,0,1280); IUFillNumber(&SimulatorSettingsN[1],"SIM_YRES","CCD Y resolution","%4.0f",0,2048,0,1024); IUFillNumber(&SimulatorSettingsN[2],"SIM_XSIZE","CCD X Pixel Size","%4.2f",0,60,0,5.2); IUFillNumber(&SimulatorSettingsN[3],"SIM_YSIZE","CCD Y Pixel Size","%4.2f",0,60,0,5.2); IUFillNumber(&SimulatorSettingsN[4],"SIM_MAXVAL","CCD Maximum ADU","%4.0f",0,65000,0,65000); IUFillNumber(&SimulatorSettingsN[5],"SIM_BIAS","CCD Bias","%4.0f",0,6000,0,10); IUFillNumber(&SimulatorSettingsN[6],"SIM_SATURATION","Saturation Mag","%4.1f",0,20,0,1.0); IUFillNumber(&SimulatorSettingsN[7],"SIM_LIMITINGMAG","Limiting Mag","%4.1f",0,20,0,17.0); IUFillNumber(&SimulatorSettingsN[8],"SIM_NOISE","CCD Noise","%4.0f",0,6000,0,10); IUFillNumber(&SimulatorSettingsN[9],"SIM_SKYGLOW","Sky Glow (magnitudes)","%4.1f",0,6000,0,19.5); IUFillNumber(&SimulatorSettingsN[10],"SIM_OAGOFFSET","Oag Offset (arcminutes)","%4.1f",0,6000,0,0); IUFillNumber(&SimulatorSettingsN[11],"SIM_POLAR","PAE (arcminutes)","%4.1f",-600,600,0,0); /* PAE = Polar Alignment Error */ IUFillNumber(&SimulatorSettingsN[12],"SIM_POLARDRIFT","PAE Drift (minutes)","%4.1f",0,6000,0,0); IUFillNumberVector(SimulatorSettingsNV,SimulatorSettingsN,13,getDeviceName(),"SIMULATOR_SETTINGS","Simulator Settings","Simulator Config",IP_RW,60,IPS_IDLE); IUFillSwitch(&TimeFactorS[0],"1X","Actual Time",ISS_ON); IUFillSwitch(&TimeFactorS[1],"10X","10x",ISS_OFF); IUFillSwitch(&TimeFactorS[2],"100X","100x",ISS_OFF); IUFillSwitchVector(TimeFactorSV,TimeFactorS,3,getDeviceName(),"ON_TIME_FACTOR","Time Factor","Simulator Config",IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillNumber(&FWHMN[0],"SIM_FWHM","FWHM (arcseconds)","%4.2f",0,60,0,7.5); IUFillNumberVector(&FWHMNP,FWHMN,1,ActiveDeviceT[1].text, "FWHM","FWHM",OPTIONS_TAB,IP_RO,60,IPS_IDLE); IUFillNumber(&ScopeParametersN[0],"TELESCOPE_APERTURE","Aperture (mm)","%g",50,4000,0,0.0); IUFillNumber(&ScopeParametersN[1],"TELESCOPE_FOCAL_LENGTH","Focal Length (mm)","%g",100,10000,0,0.0 ); IUFillNumber(&ScopeParametersN[2],"GUIDER_APERTURE","Guider Aperture (mm)","%g",50,4000,0,0.0); IUFillNumber(&ScopeParametersN[3],"GUIDER_FOCAL_LENGTH","Guider Focal Length (mm)","%g",100,10000,0,0.0 ); IUFillNumberVector(&ScopeParametersNP,ScopeParametersN,4,ActiveDeviceT[0].text,"TELESCOPE_INFO","Scope Properties",OPTIONS_TAB,IP_RW,60,IPS_OK); IUFillNumber(&EqPEN[0],"RA_PE","RA (hh:mm:ss)","%010.6m",0,24,0,0); IUFillNumber(&EqPEN[1],"DEC_PE","DEC (dd:mm:ss)","%010.6m",-90,90,0,0); IUFillNumberVector(&EqPENP,EqPEN,2,ActiveDeviceT[0].text,"EQUATORIAL_PE","EQ PE","Main Control",IP_RW,60,IPS_IDLE); IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_PE"); IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO"); IDSnoopDevice(ActiveDeviceT[1].text,"FWHM"); initFilterProperties(getDeviceName(), FILTER_TAB); FilterSlotN[0].min = 1; FilterSlotN[0].max = 5; addDebugControl(); return true; } void CCDSim::ISGetProperties (const char *dev) { // First we let our parent populate //IDLog("CCDSim IsGetProperties with %s\n",dev); INDI::CCD::ISGetProperties(dev); defineNumber(SimulatorSettingsNV); defineSwitch(TimeFactorSV); return; } bool CCDSim::updateProperties() { INDI::CCD::updateProperties(); if (isConnected()) { SetupParms(); if(HasGuideHead) { SetGuideHeadParams(500,290,16,9.8,12.6); GuideCCD.setFrameBufferSize(GuideCCD.getXRes() * GuideCCD.getYRes() * 2); } // Define the Filter Slot and name properties defineNumber(&FilterSlotNP); if (FilterNameT != NULL) defineText(FilterNameTP); } else { deleteProperty(FilterSlotNP.name); deleteProperty(FilterNameTP->name); } return true; } bool CCDSim::Disconnect() { return true; } int CCDSim::StartExposure(float duration) { // for the simulator, we can just draw the frame now // and it will get returned at the right time // by the timer routines AbortPrimaryFrame=false; ExposureRequest=duration; PrimaryCCD.setExposureDuration(duration); gettimeofday(&ExpStart,NULL); // Leave the proper time showing for the draw routines DrawCcdFrame(&PrimaryCCD); // Now compress the actual wait time ExposureRequest=duration*TimeFactor; InExposure=true; return 0; } int CCDSim::StartGuideExposure(float n) { GuideExposureRequest=n; AbortGuideFrame = false; GuideCCD.setExposureDuration(n); DrawCcdFrame(&GuideCCD); gettimeofday(&GuideExpStart,NULL); InGuideExposure=true; return 0; } bool CCDSim::AbortExposure() { if (!InExposure) return true; AbortPrimaryFrame = true; return true; } bool CCDSim::AbortGuideExposure() { //IDLog("Enter AbortGuideExposure\n"); if(!InGuideExposure) return true; // no need to abort if we aren't doing one AbortGuideFrame=true; return true; } float CCDSim::CalcTimeLeft(timeval start,float req) { double timesince; double timeleft; struct timeval now; gettimeofday(&now,NULL); timesince=(double)(now.tv_sec * 1000.0 + now.tv_usec/1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec/1000); timesince=timesince/1000; timeleft=req-timesince; return timeleft; } void CCDSim::TimerHit() { int nexttimer=1000; if(isConnected() == false) return; // No need to reset timer if we are not connected anymore if(InExposure) { if (AbortPrimaryFrame) { InExposure = false; AbortPrimaryFrame = false; } else { float timeleft; timeleft=CalcTimeLeft(ExpStart,ExposureRequest); //IDLog("CCD Exposure left: %g - Requset: %g\n", timeleft, ExposureRequest); if (timeleft < 0) timeleft = 0; PrimaryCCD.setExposureLeft(timeleft); if(timeleft < 1.0) { if(timeleft <= 0.001) { InExposure=false; ExposureComplete(&PrimaryCCD); } else { nexttimer=timeleft*1000; // set a shorter timer } } } } if(InGuideExposure) { float timeleft; timeleft=CalcTimeLeft(GuideExpStart,GuideExposureRequest); //IDLog("GUIDE Exposure left: %g - Requset: %g\n", timeleft, GuideExposureRequest); if (timeleft < 0) timeleft = 0; //ImageExposureN[0].value = timeleft; //IDSetNumber(ImageExposureNP, NULL); GuideCCD.setExposureLeft(timeleft); if(timeleft < 1.0) { if(timeleft <= 0.001) { InGuideExposure=false; if(!AbortGuideFrame) { //IDLog("Sending guider frame\n"); ExposureComplete(&GuideCCD); if(InGuideExposure) { // the call to complete triggered another exposure timeleft=CalcTimeLeft(GuideExpStart,GuideExposureRequest); if(timeleft <1.0) { nexttimer=timeleft*1000; } } } else { IDLog("Not sending guide frame cuz of abort\n"); } AbortGuideFrame=false; } else { nexttimer=timeleft*1000; // set a shorter timer } } } SetTimer(nexttimer); return; } int CCDSim::DrawCcdFrame(CCDChip *targetChip) { // Ok, lets just put a silly pattern into this // CCd frame is 16 bit data unsigned short int *ptr; unsigned short int val; float ExposureTime; float targetFocalLength; ptr=(unsigned short int *) targetChip->getFrameBuffer(); if (targetChip->getXRes() == 500) { targetFocalLength = guider_focallength; ExposureTime = GuideExposureRequest; } else { targetFocalLength = focallength; ExposureTime = ExposureRequest; } if(ShowStarField) { char gsccmd[250]; FILE *pp; int stars=0; int lines=0; int drawn=0; int x,y; float PEOffset; float PESpot; float decDrift; double rad; // telescope ra in degrees double rar; // telescope ra in radians double decr; // telescope dec in radians; int nwidth=0, nheight=0; double timesince; time_t now; time(&now); // Lets figure out where we are on the pe curve timesince=difftime(now,RunStart); // This is our spot in the curve PESpot=timesince/PEPeriod; // Now convert to radians PESpot=PESpot*2.0*3.14159; PEOffset=PEMax*sin(PESpot); //fprintf(stderr,"PEOffset = %4.2f arcseconds timesince %4.2f\n",PEOffset,timesince); PEOffset=PEOffset/3600; // convert to degrees //PeOffset=PeOffset/15; // ra is in h:mm // Start by clearing the frame buffer memset(targetChip->getFrameBuffer(),0,targetChip->getFrameBufferSize()); // Spin up a set of plate constants that will relate // ra/dec of stars, to our fictitious ccd layout // to account for various rotations etc // we should spin up some plate constants here // then we can use these constants to rotate and offset // the standard co-ordinates on each star for drawing // a ccd frame; double pa,pb,pc,pd,pe,pf; // Since this is a simple ccd, correctly aligned // for now we cheat // no offset or rotation for and y axis means pb=0.0; nwidth = targetChip->getXRes() / targetChip->getBinX(); pc=nwidth/2; pd=0.0; nheight = targetChip->getYRes() / targetChip->getBinY(); pf=nheight/2; // and we do a simple scale for x and y locations // based on the focal length and pixel size // focal length in mm, pixels in microns pa=targetFocalLength/targetChip->getPixelSizeX()*1000/targetChip->getBinX(); pe=targetFocalLength/targetChip->getPixelSizeY()*1000/targetChip->getBinY(); //IDLog("Pixels are %4.2f %4.2f pa %6.4f pe %6.4f\n",PixelSizex,PixelSizey,pa,pe); // these numbers are now pixels per radian float Scalex; float Scaley; Scalex=pa*0.0174532925; // pixels per degree Scalex=Scalex/3600.0; // pixels per arcsecond Scalex=1.0/Scalex; // arcseconds per pixel Scaley=pe*0.0174532925; // pixels per degree Scaley=Scaley/3600.0; // pixels per arcsecond Scaley=1.0/Scaley; // arcseconds per pixel //qq=qq/3600; // arcseconds per pixel //IDLog("Pixel scale is %4.2f x %4.2f\n",Scalex,Scaley); ImageScalex=Scalex; ImageScaley=Scaley; if (usePE == false) { raPE = RA; decPE = Dec; ln_equ_posn epochPos, J2000Pos; epochPos.ra = raPE*15.0; epochPos.dec = decPE; // Convert from JNow to J2000 ln_get_equ_prec2(&epochPos, ln_get_julian_from_sys(), JD2000, &J2000Pos); raPE = J2000Pos.ra/15.0; decPE = J2000Pos.dec; } // calc this now, we will use it a lot later rad=raPE*15.0; rar=rad*0.0174532925; // offsetting the dec by the guide head offset float cameradec; cameradec=decPE+OAGoffset/60; decr=cameradec*0.0174532925; decDrift = (polarDrift * polarError * cos(decr)) / 3.81; // Add declination drift, if any. decr += decDrift/3600.0 * 0.0174532925; //fprintf(stderr,"decPE %7.5f cameradec %7.5f CenterOffsetDec %4.4f\n",decPE,cameradec,CenterOffsetDec); // now lets calculate the radius we need to fetch float radius; radius=sqrt((Scalex*Scalex*targetChip->getXRes()/2.0*targetChip->getXRes()/2.0)+(Scaley*Scaley*targetChip->getYRes()/2.0*targetChip->getYRes()/2.0)); // we have radius in arcseconds now radius=radius/60; // convert to arcminutes //fprintf(stderr,"Lookup radius %4.2f\n",radius); //radius=radius*2; // A saturationmag star saturates in one second // and a limitingmag produces a one adu level in one second // solve for zero point and system gain k=(saturationmag-limitingmag)/((-2.5*log(maxval))-(-2.5*log(1.0/2.0))); z=saturationmag-k*(-2.5*log(maxval)); //z=z+saturationmag; //IDLog("K=%4.2f Z=%4.2f\n",k,z); // Should probably do some math here to figure out the dimmest // star we can see on this exposure // and only fetch to that magnitude // for now, just use the limiting mag number with some room to spare float lookuplimit; lookuplimit=limitingmag; lookuplimit=lookuplimit; if(radius > 60) lookuplimit=11; // if this is a light frame, we need a star field drawn if(targetChip->getFrameType()==CCDChip::LIGHT_FRAME) { //sprintf(gsccmd,"gsc -c %8.6f %+8.6f -r 120 -m 0 9.1",rad+PEOffset,decPE); sprintf(gsccmd,"gsc -c %8.6f %+8.6f -r %4.1f -m 0 %4.2f -n 3000",rad+PEOffset,cameradec,radius,lookuplimit); //fprintf(stderr,"gsccmd %s\n",gsccmd); pp=popen(gsccmd,"r"); if(pp != NULL) { char line[256]; while(fgets(line,256,pp)!=NULL) { //fprintf(stderr,"%s",line); // ok, lets parse this line for specifcs we want char id[20]; char plate[6]; char ob[6]; float mag; float mage; float ra; float dec; float pose; int band; float dist; int dir; int c; int rc; rc=sscanf(line,"%10s %f %f %f %f %f %d %d %4s %2s %f %d", id,&ra,&dec,&pose,&mag,&mage,&band,&c,plate,ob,&dist,&dir); //fprintf(stderr,"Parsed %d items\n",rc); if(rc==12) { lines++; //if(c==0) { stars++; //fprintf(stderr,"%s %8.4f %8.4f %5.2f %5.2f %d\n",id,ra,dec,mag,dist,dir); // Convert the ra/dec to standard co-ordinates double sx; // standard co-ords double sy; // double srar; // star ra in radians double sdecr; // star dec in radians; double ccdx; double ccdy; //fprintf(stderr,"line %s",line); //fprintf(stderr,"parsed %6.5f %6.5f\n",ra,dec); srar=ra*0.0174532925; sdecr=dec*0.0174532925; // Handbook of astronomical image processing // page 253 // equations 9.1 and 9.2 // convert ra/dec to standard co-ordinates sx=cos(decr)*sin(srar-rar)/( cos(decr)*cos(sdecr)*cos(srar-rar)+sin(decr)*sin(sdecr) ); sy=(sin(decr)*cos(sdecr)*cos(srar-rar)-cos(decr)*sin(sdecr))/( cos(decr)*cos(sdecr)*cos(srar-rar)+sin(decr)*sin(sdecr) ); // now convert to microns ccdx=pa*sx+pb*sy+pc; ccdy=pd*sx+pe*sy+pf; rc=DrawImageStar(targetChip, mag,ccdx,ccdy); drawn+=rc; if(rc==1) { //fprintf(stderr,"star %s scope %6.4f %6.4f star %6.4f %6.4f ccd %6.2f %6.2f\n",id,rad,decPE,ra,dec,ccdx,ccdy); //fprintf(stderr,"star %s ccd %6.2f %6.2f\n",id,ccdx,ccdy); } } } pclose(pp); } else { IDMessage(getDeviceName(),"Error looking up stars, is gsc installed with appropriate environment variables set ??"); //fprintf(stderr,"Error doing gsc lookup\n"); } if(drawn==0) { IDMessage(getDeviceName(),"Got no stars, is gsc installed with appropriate environment variables set ??"); } } //fprintf(stderr,"Got %d stars from %d lines drew %d\n",stars,lines,drawn); // now we need to add background sky glow, with vignetting // this is essentially the same math as drawing a dim star with // fwhm equivalent to the full field of view CCDChip::CCD_FRAME ftype = targetChip->getFrameType(); if((ftype==CCDChip::LIGHT_FRAME)||(ftype==CCDChip::FLAT_FRAME)) { float skyflux; float glow; // calculate flux from our zero point and gain values glow=skyglow; if(ftype==CCDChip::FLAT_FRAME) { // Assume flats are done with a diffuser // in broad daylight, so, the sky magnitude // is much brighter than at night glow=skyglow/10; } //fprintf(stderr,"Using glow %4.2f\n",glow); skyflux=pow(10,((glow-z)*k/-2.5)); // ok, flux represents one second now // scale up linearly for exposure time skyflux=skyflux*ExposureTime*targetChip->getBinX()*targetChip->getBinY(); //IDLog("SkyFlux = %g ExposureRequest %g\n",skyflux,ExposureTime); unsigned short *pt; pt=(unsigned short int *)targetChip->getFrameBuffer(); nheight = targetChip->getSubH() / targetChip->getBinY(); nwidth = targetChip->getSubW() / targetChip->getBinX(); for(int y=0; y< nheight; y++) { for(int x=0; x< nwidth; x++) { float dc; // distance from center float fp; // flux this pixel; float sx,sy; float vig; sx=nwidth/2-x; sy=nheight/2-y; vig=nwidth; vig=vig*ImageScalex; // need to make this account for actual pixel size dc=sqrt(sx*sx*ImageScalex*ImageScalex+sy*sy*ImageScaley*ImageScaley); // now we have the distance from center, in arcseconds // now lets plot a gaussian falloff to the edges // float fa; fa=exp(-2.0*0.7*(dc*dc)/vig/vig); // get the current value fp=pt[0]; // Add the sky glow fp+=skyflux; // now scale it for the vignetting fp=fa*fp; // clamp to limits if(fp > maxval) fp=maxval; if (fp > maxpix) maxpix = fp; if (fp < minpix) minpix = fp; // and put it back pt[0]=fp; pt++; } } } // Now we add some bias and read noise int subX = targetChip->getSubX() / targetChip->getBinX(); int subY = targetChip->getSubY() / targetChip->getBinX(); int subW = targetChip->getSubW() / targetChip->getBinX() + subX; int subH = targetChip->getSubH() / targetChip->getBinX() + subY; for(x=subX; x 255) testvalue=0; val=testvalue; int nbuf = targetChip->getSubW()*targetChip->getSubH(); for(int x=0; xgetSubX() / targetChip->getBinX(); int subY = targetChip->getSubY() / targetChip->getBinX(); int subW = targetChip->getSubW() / targetChip->getBinX() + subX; int subH = targetChip->getSubH() / targetChip->getBinX() + subY; if((xsubW||(ysubH))) { // this star is not on the ccd frame anyways return 0; } if (targetChip->getXRes() == 500) ExposureTime = GuideExposureRequest*4; else ExposureTime = ExposureRequest; // calculate flux from our zero point and gain values flux=pow(10,((mag-z)*k/-2.5)); // ok, flux represents one second now // scale up linearly for exposure time flux=flux*ExposureTime; float qx; // we need a box size that gives a radius at least 3 times fwhm qx=seeing/ImageScalex; qx=qx*3; boxsizex=(int)qx; boxsizex++; qx=seeing/ImageScaley; qx=qx*3; boxsizey=(int)qx; boxsizey++; //IDLog("BoxSize %d %d\n",boxsizex,boxsizey); for(sy=-boxsizey; sy<=boxsizey; sy++) { for(sx=-boxsizey; sx<=boxsizey; sx++) { int rc; float dc; // distance from center float fp; // flux this pixel; // need to make this account for actual pixel size dc=sqrt(sx*sx*ImageScalex*ImageScalex+sy*sy*ImageScaley*ImageScaley); // now we have the distance from center, in arcseconds // This should be gaussian, but, for now we'll just go with // a simple linear function float fa; fa=exp(-2.0*0.7*(dc*dc)/seeing/seeing); fp=fa*flux*targetChip->getBinX()*targetChip->getBinY(); if(fp < 0) fp=0; rc=AddToPixel(targetChip, x+sx,y+sy,fp); if(rc != 0) drew=1; } } return drew; } int CCDSim::AddToPixel(CCDChip *targetChip, int x,int y,int val) { int nwidth = targetChip->getSubW() / targetChip->getBinX(); int nheight = targetChip->getSubH() / targetChip->getBinY(); x -= targetChip->getSubX(); y -= targetChip->getSubY(); int drew=0; if(x >= 0) { if(x < nwidth) { if(y >= 0) { if(y < nheight) { unsigned short *pt; int newval; drew++; pt=(unsigned short int *)targetChip->getFrameBuffer(); pt+=(y*nwidth); pt+=x; newval=pt[0]; newval+=val; if(newval > maxval) newval=maxval; if (newval > maxpix) maxpix = newval; if (newval < minpix) minpix = newval; pt[0]=newval; } } } } return drew; } bool CCDSim::GuideNorth(float v) { float c; c=v/1000*GuideRate; // c=c/3600; decPE=decPE+c; return true; } bool CCDSim::GuideSouth(float v) { float c; c=v/1000*GuideRate; // c=c/3600; decPE=decPE-c; return true; } bool CCDSim::GuideEast(float v) { float c; c=v/1000*GuideRate; c=c/3600.0/15.0; c=c/(cos(decPE*0.0174532925)); raPE=raPE+c; return true; } bool CCDSim::GuideWest(float v) { float c; c=v/1000*GuideRate; // c=c/3600.0/15.0; c=c/(cos(decPE*0.0174532925)); raPE=raPE-c; return true; } bool CCDSim::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // first check if it's for our device //IDLog("INDI::CCD::ISNewNumber %s\n",name); if(strcmp(dev,getDeviceName())==0) { // This is for our device // Now lets see if it's something we process here //IDLog("CCDSim::ISNewNumber %s\n",name); if(strcmp(name,"SIMULATOR_SETTINGS")==0) { IUUpdateNumber(SimulatorSettingsNV, values, names, n); SimulatorSettingsNV->s=IPS_OK; // Reset our parameters now SetupParms(); IDSetNumber(SimulatorSettingsNV,NULL); saveConfig(); //IDLog("Frame set to %4.0f,%4.0f %4.0f x %4.0f\n",CcdFrameN[0].value,CcdFrameN[1].value,CcdFrameN[2].value,CcdFrameN[3].value); //seeing=SimulatorSettingsN[0].value; return true; } if (strcmp(name, FilterSlotNP.name)==0) { processFilterSlot(getDeviceName(), values, names); return true; } } // if we didn't process it, continue up the chain, let somebody else // give it a shot return INDI::CCD::ISNewNumber(dev,name,values,names,n); } bool CCDSim::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { //IDLog("Enter IsNewSwitch for %s\n",name); //for(int x=0; xs=IPS_OK; IUUpdateSwitch(TimeFactorSV,states,names,n); // Update client display IDSetSwitch(TimeFactorSV,NULL); saveConfig(); if(TimeFactorS[0].s==ISS_ON ) { //IDLog("CCDSim:: Time Factor 1\n"); TimeFactor=1; } if(TimeFactorS[1].s==ISS_ON ) { //IDLog("CCDSim:: Time Factor 0.1\n"); TimeFactor=0.1; } if(TimeFactorS[2].s==ISS_ON ) { //IDLog("CCDSim:: Time Factor 0.01\n"); TimeFactor=0.01; } return true; } } // Nobody has claimed this, so, ignore it return INDI::CCD::ISNewSwitch(dev,name,states,names,n); } void CCDSim::activeDevicesUpdated() { IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_PE"); IDSnoopDevice(ActiveDeviceT[0].text,"TELESCOPE_INFO"); IDSnoopDevice(ActiveDeviceT[1].text,"FWHM"); strncpy(EqPENP.device, ActiveDeviceT[0].text, MAXINDIDEVICE); strncpy(ScopeParametersNP.device, ActiveDeviceT[0].text, MAXINDIDEVICE); strncpy(FWHMNP.device, ActiveDeviceT[1].text, MAXINDIDEVICE); } bool CCDSim::ISSnoopDevice (XMLEle *root) { if (IUSnoopNumber(root,&FWHMNP)==0) { seeing = FWHMNP.np[0].value; if (isDebug()) IDLog("CCD Simulator: New FWHM value of %g\n", seeing); return true; } if (IUSnoopNumber(root,&ScopeParametersNP)==0) { focallength = ScopeParametersNP.np[1].value; guider_focallength = ScopeParametersNP.np[3].value; if (isDebug()) { IDLog("CCD Simulator: New focalLength value of %g\n", focallength); IDLog("CCD Simulator: New guider_focalLength value of %g\n", guider_focallength); } return true; } // We try to snoop EQPEC first, if not found, we snoop regular EQNP if(IUSnoopNumber(root,&EqPENP)==0) { double newra,newdec; newra=EqPEN[0].value; newdec=EqPEN[1].value; if((newra != raPE)||(newdec != decPE)) { ln_equ_posn epochPos, J2000Pos; epochPos.ra = newra*15.0; epochPos.dec = newdec; ln_get_equ_prec2(&epochPos, ln_get_julian_from_sys(), JD2000, &J2000Pos); raPE = J2000Pos.ra/15.0; decPE = J2000Pos.dec; usePE = true; if (isDebug()) IDLog("raPE %g decPE %g Snooped raPE %g decPE %g\n",raPE,decPE,newra,newdec); return true; } } return INDI::CCD::ISSnoopDevice(root); } bool CCDSim::saveConfigItems(FILE *fp) { INDI::CCD::saveConfigItems(fp); IUSaveConfigNumber(fp,SimulatorSettingsNV); IUSaveConfigSwitch(fp, TimeFactorSV); return true; } bool CCDSim::SelectFilter(int f) { CurrentFilter = f; SelectFilterDone(f); return true; } bool CCDSim::GetFilterNames(const char* groupName) { char filterName[MAXINDINAME]; char filterLabel[MAXINDILABEL]; int MaxFilter = FilterSlotN[0].max; const char *filterDesignation[5] = { "Red", "Green", "Blue", "H_Alpha", "Luminosity" }; if (FilterNameT != NULL) delete FilterNameT; FilterNameT = new IText[MaxFilter]; for (int i=0; i < MaxFilter; i++) { snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i+1); snprintf(filterLabel, MAXINDILABEL, "Filter #%d", i+1); IUFillText(&FilterNameT[i], filterName, filterLabel, filterDesignation[i]); } IUFillTextVector(FilterNameTP, FilterNameT, MaxFilter, getDeviceName(), "FILTER_NAME", "Filter", groupName, IP_RW, 0, IPS_IDLE); return true; } int CCDSim::QueryFilter() { return CurrentFilter; } libindi-0.9.7/drivers/ccd/ccd_simulator.h0000644000175000017500000000765212241463551017346 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. . 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 Library General Public License for more details. . You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef CCDSIM_H #define CCDSIM_H #include "indibase/indiccd.h" #include "indibase/indifilterinterface.h" /* Some headers we need */ #include #include class CCDSim : public INDI::CCD, public INDI::FilterInterface { protected: virtual bool saveConfigItems(FILE *fp); virtual void activeDevicesUpdated(); private: float ExposureRequest; struct timeval ExpStart; float GuideExposureRequest; struct timeval GuideExpStart; float CalcTimeLeft(timeval,float); int testvalue; int ShowStarField; int bias; int maxnoise; int maxval; int maxpix; int minpix; float skyglow; float limitingmag; float saturationmag; float seeing; float ImageScalex; float ImageScaley; float focallength; float guider_focallength; float OAGoffset; float TimeFactor; // our zero point calcs used for drawing stars float k; float z; bool AbortGuideFrame; bool AbortPrimaryFrame; float GuideRate; float PEPeriod; float PEMax; double raPE,decPE; bool usePE; time_t RunStart; float polarError; float polarDrift; // And this lives in our simulator settings page INumberVectorProperty *SimulatorSettingsNV; INumber SimulatorSettingsN[13]; ISwitch TimeFactorS[3]; ISwitchVectorProperty *TimeFactorSV; bool SetupParms(); // We are going to snoop these from focuser INumberVectorProperty FWHMNP; INumber FWHMN[1]; // We are going to snoop these from telescope INumber ScopeParametersN[4]; INumberVectorProperty ScopeParametersNP; INumberVectorProperty EqPENP; INumber EqPEN[2]; // Filter bool SelectFilter(int); bool SetFilterNames() { return false; } bool GetFilterNames(const char* groupName); int QueryFilter(); public: CCDSim(); virtual ~CCDSim(); const char *getDefaultName(); bool initProperties(); bool updateProperties(); void ISGetProperties (const char *dev); bool Connect(); bool Disconnect(); int StartExposure(float duration); int StartGuideExposure(float); bool AbortExposure(); bool AbortGuideExposure(); void TimerHit(); int DrawCcdFrame(CCDChip *targetChip); int DrawImageStar(CCDChip *targetChip, float,float,float); int AddToPixel(CCDChip *targetChip, int,int,int); bool GuideNorth(float); bool GuideSouth(float); bool GuideEast(float); bool GuideWest(float); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISSnoopDevice (XMLEle *root); }; #endif // CCDSim_H libindi-0.9.7/drivers/telescope/0000755000175000017500000000000012241463551015565 5ustar jasemjasemlibindi-0.9.7/drivers/telescope/lx200aplib.h0000644000175000017500000000244312241463551017616 0ustar jasemjasem/* LX200 AP Driver Copyright (C) 2007 Markus Wildi 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 */ #include #include #ifdef HAVE_NOVA_H #include #endif #define ATA 0 #define ATR 1 #define ARTT 2 #define ARTTO 3 /* not yet there, requires a pointing model */ double LDRAtoHA( double RA, double longitude) ; int LDEqToEqT( double ra_h, double dec_d, double *hxt, double *rat_h, double *dect_d); int LDCartToSph( double *vec, double *ra, double *dec) ; int LDAppToX( int trans_to, double *star_cat, double tjd, double *loc, double *hxt, double *star_trans) ; libindi-0.9.7/drivers/telescope/lx200gps.cpp0000644000175000017500000002624112241463551017655 0ustar jasemjasem/* LX200 GPS Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "lx200gps.h" #include "lx200driver.h" #include #include #include #include #define GPS_TAB "Extended GPS Features" LX200GPS::LX200GPS() : LX200Autostar() { MaxReticleFlashRate = 9; } const char * LX200GPS::getDefaultName() { return (const char *) "LX200 GPS"; } bool LX200GPS::initProperties() { LX200Autostar::initProperties(); IUFillSwitch(&GPSPowerS[0], "On", "", ISS_OFF); IUFillSwitch(&GPSPowerS[1], "Off", "", ISS_OFF); IUFillSwitchVector(&GPSPowerSP, GPSPowerS, 2, getDeviceName(), "GPS Power", "", GPS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&GPSStatusS[0], "Sleep", "", ISS_OFF); IUFillSwitch(&GPSStatusS[1], "Wake Up", "", ISS_OFF); IUFillSwitch(&GPSStatusS[2], "Restart", "", ISS_OFF); IUFillSwitchVector(&GPSStatusSP, GPSStatusS, 3, getDeviceName(), "GPS Status", "", GPS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&GPSUpdateS[0], "Update GPS", "", ISS_OFF); IUFillSwitch(&GPSUpdateS[1], "Update Client", "", ISS_OFF); IUFillSwitchVector(&GPSUpdateSP, GPSUpdateS, 2, getDeviceName(), "GPS System", "", GPS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&AltDecPecS[0], "Enable", "", ISS_OFF); IUFillSwitch(&AltDecPecS[1], "Disable", "", ISS_OFF); IUFillSwitchVector(&AltDecPecSP, AltDecPecS, 2, getDeviceName(), "Alt/Dec PEC", "", GPS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&AzRaPecS[0], "Enable", "", ISS_OFF); IUFillSwitch(&AzRaPecS[1], "Disable", "", ISS_OFF); IUFillSwitchVector(&AzRaPecSP, AzRaPecS, 2, getDeviceName(), "Az/RA PEC", "", GPS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&SelenSyncS[0], "Sync", "", ISS_OFF); IUFillSwitchVector(&SelenSyncSP, SelenSyncS, 1, getDeviceName(), "Selenographic Sync", "", GPS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); IUFillSwitch(&AltDecBacklashS[0], "Activate", "", ISS_OFF); IUFillSwitchVector(&AltDecBacklashSP, AltDecBacklashS, 1, getDeviceName(), "Alt/Dec Anti-backlash", "", GPS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); IUFillSwitch(&AzRaBacklashS[0], "Activate", "", ISS_OFF); IUFillSwitchVector(&AzRaBacklashSP, AzRaBacklashS, 1, getDeviceName(), "Az/Ra Anti-backlash", "", GPS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); IUFillSwitch(&OTAUpdateS[0], "Update", "", ISS_OFF); IUFillSwitchVector(&OTAUpdateSP, OTAUpdateS, 1, getDeviceName(), "OTA Update", "", GPS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); IUFillNumber(&OTATempN[0], "Temp", "", "%03g", -200.0, 500.0, 0.0, 0); IUFillNumberVector(&OTATempNP, OTATempN, 1, getDeviceName(), "OTA Temp (C)", "", GPS_TAB, IP_RO, 0, IPS_IDLE); } void LX200GPS::ISGetProperties (const char *dev) { if(dev && strcmp(dev,getDeviceName())) return; // process parent first LX200Autostar::ISGetProperties(dev); if (isConnected()) { defineSwitch (&GPSPowerSP); defineSwitch (&GPSStatusSP); defineSwitch (&GPSUpdateSP); defineSwitch (&AltDecPecSP); defineSwitch (&AzRaPecSP); defineSwitch (&SelenSyncSP); defineSwitch (&AltDecBacklashSP); defineSwitch (&AzRaBacklashSP); defineNumber (&OTATempNP); defineSwitch (&OTAUpdateSP); } } bool LX200GPS::updateProperties() { LX200Autostar::updateProperties(); if (isConnected()) { defineSwitch (&GPSPowerSP); defineSwitch (&GPSStatusSP); defineSwitch (&GPSUpdateSP); defineSwitch (&AltDecPecSP); defineSwitch (&AzRaPecSP); defineSwitch (&SelenSyncSP); defineSwitch (&AltDecBacklashSP); defineSwitch (&AzRaBacklashSP); defineNumber (&OTATempNP); defineSwitch (&OTAUpdateSP); } else { deleteProperty(GPSPowerSP.name); deleteProperty(GPSStatusSP.name); deleteProperty(GPSUpdateSP.name); deleteProperty(AltDecPecSP.name); deleteProperty(AzRaPecSP.name); deleteProperty(SelenSyncSP.name); deleteProperty(AltDecBacklashSP.name); deleteProperty(AzRaBacklashSP.name); deleteProperty(OTATempNP.name); deleteProperty(OTAUpdateSP.name); } return true; } bool LX200GPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int index=0, err=0; char msg[64]; if(strcmp(dev,getDeviceName())==0) { /* GPS Power */ if (!strcmp(name,GPSPowerSP.name)) { if (IUUpdateSwitch(&GPSPowerSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&GPSPowerSP); if (index == 0) turnGPSOn(PortFD); else turnGPSOff(PortFD); GPSPowerSP.s = IPS_OK; IDSetSwitch (&GPSPowerSP, index == 0 ? "GPS System is ON" : "GPS System is OFF" ); return true; } /* GPS Status Update */ if (!strcmp(name,GPSStatusSP.name)) { if (IUUpdateSwitch(&GPSStatusSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&GPSStatusSP); if (index == 0) { err = gpsSleep(PortFD); strncpy(msg, "GPS system is in sleep mode.",64); } else if (index == 1) { err = gpsWakeUp(PortFD); strncpy(msg, "GPS system is reactivated.", 64); } else { err = gpsRestart(PortFD); strncpy(msg, "GPS system is restarting...", 64); sendScopeTime(); sendScopeLocation(); } GPSStatusSP.s = IPS_OK; IDSetSwitch (&GPSStatusSP, "%s", msg); return true; } /* GPS Update */ if (!strcmp(name,GPSUpdateSP.name)) { if (IUUpdateSwitch(&GPSUpdateSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&GPSUpdateSP); GPSUpdateSP.s = IPS_OK; if (index == 0) { IDSetSwitch(&GPSUpdateSP, "Updating GPS system. This operation might take few minutes to complete..."); if (updateGPS_System(PortFD)) { IDSetSwitch(&GPSUpdateSP, "GPS system update successful."); sendScopeTime(); sendScopeLocation(); } else { GPSUpdateSP.s = IPS_IDLE; IDSetSwitch(&GPSUpdateSP, "GPS system update failed."); } } else { sendScopeTime(); sendScopeLocation(); IDSetSwitch(&GPSUpdateSP, "Client time and location is synced to LX200 GPS Data."); } return true; } /* Alt Dec Periodic Error correction */ if (!strcmp(name, AltDecPecSP.name)) { if (IUUpdateSwitch(&AltDecPecSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&AltDecPecSP); if (index == 0) { err = enableDecAltPec(PortFD); strncpy (msg, "Alt/Dec Compensation Enabled.", 64); } else { err = disableDecAltPec(PortFD); strncpy (msg, "Alt/Dec Compensation Disabled.", 64); } AltDecPecSP.s = IPS_OK; IDSetSwitch(&AltDecPecSP, "%s", msg); return true; } /* Az RA periodic error correction */ if (!strcmp(name, AzRaPecSP.name)) { if (IUUpdateSwitch(&AzRaPecSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&AzRaPecSP); if (index == 0) { err = enableRaAzPec(PortFD); strncpy (msg, "Ra/Az Compensation Enabled.", 64); } else { err = disableRaAzPec(PortFD); strncpy (msg, "Ra/Az Compensation Disabled.", 64); } AzRaPecSP.s = IPS_OK; IDSetSwitch(&AzRaPecSP, "%s", msg); return true; } if (!strcmp(name, AltDecBacklashSP.name)) { activateAltDecAntiBackSlash(PortFD); AltDecBacklashSP.s = IPS_OK; IDSetSwitch(&AltDecBacklashSP, "Alt/Dec Anti-backlash enabled"); return true; } if (!strcmp(name, AzRaBacklashSP.name)) { activateAzRaAntiBackSlash(PortFD); AzRaBacklashSP.s = IPS_OK; IDSetSwitch(&AzRaBacklashSP, "Az/Ra Anti-backlash enabled"); return true; } if (!strcmp(name, OTAUpdateSP.name)) { IUResetSwitch(&OTAUpdateSP); if ( getOTATemp(PortFD, &OTATempNP.np[0].value) < 0) { OTAUpdateSP.s = IPS_ALERT; OTATempNP.s = IPS_ALERT; IDSetNumber(&OTATempNP, "Error: OTA temperature read timed out."); return false; } else { OTAUpdateSP.s = IPS_OK; OTATempNP.s = IPS_OK; IDSetNumber(&OTATempNP, NULL); IDSetSwitch(&OTAUpdateSP, NULL); return true; } } } return LX200Autostar::ISNewSwitch (dev, name, states, names, n); } bool LX200GPS::updateTime(ln_date *utc, double utc_offset) { ln_zonedate ltm; if (isSimulation()) return true; JD = ln_get_julian_day(utc); DEBUGF(INDI::Logger::DBG_DEBUG, "New JD is %f", (float) JD); ln_date_to_zonedate(utc, <m, utc_offset*3600); DEBUGF(INDI::Logger::DBG_DEBUG, "Local time is %02d:%02d:%02g", ltm.hours, ltm.minutes, ltm.seconds); // Set Local Time if (setLocalTime(PortFD, ltm.hours, ltm.minutes, ltm.seconds) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting local time time."); return false; } if (setCalenderDate(PortFD, utc->days, utc->months, utc->years) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting UTC date."); return false; } // Meade defines UTC Offset as the offset ADDED to local time to yield UTC, which // is the opposite of the standard definition of UTC offset! if (setUTCOffset(PortFD, (utc_offset * -1.0)) < 0) { DEBUG(INDI::Logger::DBG_ERROR , "Error setting UTC Offset."); return false; } DEBUG(INDI::Logger::DBG_SESSION , "Time updated, updating planetary data..."); return true; } libindi-0.9.7/drivers/telescope/celestrongps.cpp0000644000175000017500000004351712241463551021013 0ustar jasemjasem#if 0 Celestron GPS Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include #include "celestronprotocol.h" #include "celestrongps.h" /* Simulation Parameters */ #define SLEWRATE 1 /* slew rate, degrees/s */ #define SIDRATE 0.004178 /* sidereal rate, degrees/s */ std::auto_ptr telescope(0); /* send client definitions of all properties */ void ISInit() { static int isInit=0; if (isInit) return; isInit = 1; if(telescope.get() == 0) telescope.reset(new CelestronGPS()); } void ISGetProperties (const char *dev) { ISInit(); telescope->ISGetProperties(dev);} void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);} void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); telescope->ISNewText(dev, name, texts, names, n);} void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); telescope->ISNewNumber(dev, name, values, names, n);} void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); telescope->ISSnoopDevice(root); } /************************************************** *** LX200 Generic Implementation ***************************************************/ CelestronGPS::CelestronGPS() { setVersion(2, 0); lastRA = 0; lastDEC = 0; currentSet = 0; lastSet = -1; controller = new INDI::Controller(this); controller->setJoystickCallback(joystickHelper); controller->setButtonCallback(buttonHelper); IDLog("initializing from Celeston GPS device...\n"); } const char * CelestronGPS::getDefaultName() { return ( (const char *) "Celestron GPS"); } bool CelestronGPS::initProperties() { INDI::Telescope::initProperties(); IUFillSwitch(&SlewModeS[0], "Max", "", ISS_ON); IUFillSwitch(&SlewModeS[1], "Find", "", ISS_OFF); IUFillSwitch(&SlewModeS[2], "Centering", "", ISS_OFF); IUFillSwitch(&SlewModeS[3], "Guide", "", ISS_OFF); IUFillSwitchVector(&SlewModeSP, SlewModeS, 4, getDeviceName(), "Slew Rate", "", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); controller->mapController("NSWE Control","NSWE Control", INDI::Controller::CONTROLLER_JOYSTICK, "JOYSTICK_1"); controller->mapController("Slew Max", "Slew Max", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1"); controller->mapController("Slew Find","Slew Find", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_2"); controller->mapController("Slew Centering", "Slew Centering", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_3"); controller->mapController("Slew Guide", "Slew Guide", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_4"); controller->mapController("Abort Motion", "Abort Motion", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_5"); controller->initProperties(); addAuxControls(); return true; } void CelestronGPS::ISGetProperties(const char *dev) { if(dev && strcmp(dev,getDeviceName())) return; INDI::Telescope::ISGetProperties(dev); if (isConnected()) defineSwitch(&SlewModeSP); controller->ISGetProperties(dev); } bool CelestronGPS::updateProperties() { INDI::Telescope::updateProperties(); if (isConnected()) defineSwitch(&SlewModeSP); else deleteProperty(SlewModeSP.name); controller->updateProperties(); return true; } bool CelestronGPS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { // Slew mode if (!strcmp (name, SlewModeSP.name)) { int index=0; IUResetSwitch(&SlewModeSP); IUUpdateSwitch(&SlewModeSP, states, names, n); index = IUFindOnSwitchIndex(&SlewModeSP); if (isSimulation() == false) SetRate(index); SlewModeSP.s = IPS_OK; IDSetSwitch(&SlewModeSP, NULL); return true; } } controller->ISNewSwitch(dev, name, states, names, n); return INDI::Telescope::ISNewSwitch(dev, name, states, names, n); } bool CelestronGPS::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { controller->ISNewText(dev, name, texts, names, n); return INDI::Telescope::ISNewText(dev, name, texts, names, n); } bool CelestronGPS::Goto(double ra, double dec) { int i=0; char RAStr[32], DecStr[32]; targetRA = ra; targetDEC = dec; if (EqNP.s == IPS_BUSY) { if (isSimulation() == false) StopNSEW(); // sleep for 500 mseconds usleep(500000); } if (isSimulation() == false && (i = SlewToCoords(targetRA, targetDEC))) { slewError(i); return false; } TrackState = SCOPE_SLEWING; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); IDMessage(getDeviceName(), "Slewing to JNOW RA %s - DEC %s", RAStr, DecStr); if (isDebug()) IDLog("Slewing to JNOW RA %s - DEC %s", RAStr, DecStr); return true; } bool CelestronGPS::Sync(double targetRA, double targetDEC) { if (isSimulation()) { currentRA = targetRA; currentDEC = targetDEC; } else if (SyncToCoords(targetRA, targetDEC)) { IDMessage(getDeviceName(), "Sync failed."); return false; } IDMessage(getDeviceName(), "Synchronization successful."); return true; } bool CelestronGPS::MoveNS(TelescopeMotionNS dir) { static int last_move=-1; int current_move = -1; current_move = IUFindOnSwitchIndex(&MovementNSSP); // Previosuly active switch clicked again, so let's stop. if (current_move == last_move && current_move != -1) { if (isSimulation() == false) StopSlew((current_move == 0) ? NORTH : SOUTH); IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, "Movement toward %s halted.", (current_move == 0) ? "North" : "South"); last_move = -1; return true; } last_move = current_move; if (isDebug()) IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); // Correction for LX200 Driver: North 0 - South 3 current_move = (dir == MOTION_NORTH) ? NORTH : SOUTH; if (isSimulation() == false) StartSlew(current_move); MovementNSSP.s = IPS_BUSY; IDSetSwitch(&MovementNSSP, "Moving toward %s.", (current_move == NORTH) ? "North" : "South"); return true; } bool CelestronGPS::MoveWE(TelescopeMotionWE dir) { static int last_move=-1; int current_move = -1; current_move = IUFindOnSwitchIndex(&MovementWESP); // Previosuly active switch clicked again, so let's stop. if (current_move == last_move && current_move != -1) { if (isSimulation() == false) StopSlew((current_move == 0) ? WEST : EAST); IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, "Movement toward %s halted.", (current_move == 0) ? "West" : "East"); last_move = -1; return true; } last_move = current_move; if (isDebug()) IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); current_move = (dir == MOTION_WEST) ? WEST : EAST; if (isSimulation() == false) StartSlew(current_move); MovementWESP.s = IPS_BUSY; IDSetSwitch(&MovementWESP, "Moving toward %s.", (current_move == WEST) ? "West" : "East"); return true; } bool CelestronGPS::ReadScopeStatus() { if (isSimulation()) { mountSim(); return true; } if (CheckConnectTel() == -1) { IDMessage(getDeviceName(), "Problem communication with the mount."); return false; } switch (TrackState) { case SCOPE_SLEWING: // are we done? if (isScopeSlewing() == 0) { IDMessage(getDeviceName(), "Slew complete, tracking..."); TrackState = SCOPE_TRACKING; } break; default: break; } currentRA = GetRA(); currentDEC = GetDec(); NewRaDec(currentRA, currentDEC); return true; } bool CelestronGPS::Abort() { if (isSimulation() == false) { StopNSEW(); StopSlew(NORTH); StopSlew(SOUTH); StopSlew(WEST); StopSlew(EAST); } TrackState = SCOPE_IDLE; if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY) { MovementNSSP.s = MovementWESP.s = EqNP.s = IPS_IDLE; IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); IDSetNumber(&EqNP, NULL); IDMessage(getDeviceName(), "Slew stopped."); } return true; } bool CelestronGPS::Connect() { bool rc=false; if(isConnected()) return true; rc=Connect(PortT[0].text); if(rc) SetTimer(POLLMS); return rc; } bool CelestronGPS::Connect(char *port) { if (isSimulation()) { IDMessage (getDeviceName(), "Simulated Celestron GPS is online. Retrieving basic data..."); currentRA = 0; currentDEC=90; return true; } if (ConnectTel(port) < 0) { IDMessage(getDeviceName(), "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.", port); return false; } IDMessage (getDeviceName(), "Telescope is online."); return true; } bool CelestronGPS::Disconnect() { if (isSimulation() == false) DisconnectTel(); return true; } void CelestronGPS::mountSim () { static struct timeval ltv; struct timeval tv; double dt, da, dx; int nlocked; /* update elapsed time since last poll, don't presume exactly POLLMS */ gettimeofday (&tv, NULL); if (ltv.tv_sec == 0 && ltv.tv_usec == 0) ltv = tv; dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; ltv = tv; da = SLEWRATE*dt; /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */ switch (TrackState) { case SCOPE_TRACKING: /* RA moves at sidereal, Dec stands still */ currentRA += (SIDRATE*dt/15.); break; case SCOPE_SLEWING: /* slewing - nail it when both within one pulse @ SLEWRATE */ nlocked = 0; dx = targetRA - currentRA; if (fabs(dx) <= da) { currentRA = targetRA; nlocked++; } else if (dx > 0) currentRA += da/15.; else currentRA -= da/15.; dx = targetDEC - currentDEC; if (fabs(dx) <= da) { currentDEC = targetDEC; nlocked++; } else if (dx > 0) currentDEC += da; else currentDEC -= da; if (nlocked == 2) { IDMessage(getDeviceName(), "Simulated telescope slew is complete, tracking..."); TrackState = SCOPE_TRACKING; } break; default: break; } NewRaDec(currentRA, currentDEC); } void CelestronGPS::slewError(int slewCode) { switch (slewCode) { case 1: IDMessage (getDeviceName(), "Invalid newDec in SlewToCoords"); break; case 2: IDMessage (getDeviceName(), "RA count overflow in SlewToCoords"); break; case 3: IDMessage (getDeviceName(), "Dec count overflow in SlewToCoords"); break; case 4: IDMessage (getDeviceName(), "No acknowledgment from telescope after SlewToCoords"); break; default: IDMessage (getDeviceName(), "Unknown error"); break; } } bool CelestronGPS::canSync() { return true; } bool CelestronGPS::canPark() { return false; } bool CelestronGPS::ISSnoopDevice(XMLEle *root) { controller->ISSnoopDevice(root); return INDI::Telescope::ISSnoopDevice(root); } void CelestronGPS::processButton(const char *button_n, ISState state) { //ignore OFF if (state == ISS_OFF) return; // Max Slew speed if (!strcmp(button_n, "Slew Max")) { SetRate(0); IUResetSwitch(&SlewModeSP); SlewModeS[0].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Find Slew speed else if (!strcmp(button_n, "Slew Find")) { SetRate(1); IUResetSwitch(&SlewModeSP); SlewModeS[1].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Centering Slew else if (!strcmp(button_n, "Slew Centering")) { SetRate(2); IUResetSwitch(&SlewModeSP); SlewModeS[2].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Guide Slew else if (!strcmp(button_n, "Slew Guide")) { SetRate(3); IUResetSwitch(&SlewModeSP); SlewModeS[3].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Abort else if (!strcmp(button_n, "Abort Motion")) { // Only abort if we have some sort of motion going on if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY) { Abort(); } } } void CelestronGPS::processNSWE(double mag, double angle) { if (mag < 0.5) { // Moving in the same direction will make it stop if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) Abort(); } // Put high threshold else if (mag > 0.9) { // North if (angle > 0 && angle < 180) { // Don't try to move if you're busy and moving in the same direction if (MovementNSSP.s != IPS_BUSY || MovementNSS[0].s != ISS_ON) MoveNS(MOTION_NORTH); MovementNSSP.s = IPS_BUSY; MovementNSSP.sp[0].s = ISS_ON; MovementNSSP.sp[1].s = ISS_OFF; IDSetSwitch(&MovementNSSP, NULL); } // South if (angle > 180 && angle < 360) { // Don't try to move if you're busy and moving in the same direction if (MovementNSSP.s != IPS_BUSY || MovementNSS[1].s != ISS_ON) MoveNS(MOTION_SOUTH); MovementNSSP.s = IPS_BUSY; MovementNSSP.sp[0].s = ISS_OFF; MovementNSSP.sp[1].s = ISS_ON; IDSetSwitch(&MovementNSSP, NULL); } // East if (angle < 90 || angle > 270) { // Don't try to move if you're busy and moving in the same direction if (MovementWESP.s != IPS_BUSY || MovementWES[1].s != ISS_ON) MoveWE(MOTION_EAST); MovementWESP.s = IPS_BUSY; MovementWESP.sp[0].s = ISS_OFF; MovementWESP.sp[1].s = ISS_ON; IDSetSwitch(&MovementWESP, NULL); } // West if (angle > 90 && angle < 270) { // Don't try to move if you're busy and moving in the same direction if (MovementWESP.s != IPS_BUSY || MovementWES[0].s != ISS_ON) MoveWE(MOTION_WEST); MovementWESP.s = IPS_BUSY; MovementWESP.sp[0].s = ISS_ON; MovementWESP.sp[1].s = ISS_OFF; IDSetSwitch(&MovementWESP, NULL); } } } bool CelestronGPS::saveConfigItems(FILE *fp) { INDI::Telescope::saveConfigItems(fp); controller->saveConfigItems(fp); return true; } bool CelestronGPS::updateLocation(double latitude, double longitude, double elevation) { INDI_UNUSED(elevation); if (isSimulation()) return true; return (::updateLocation(longitude, latitude) == 0); } bool CelestronGPS::updateTime(ln_date *utc, double utc_offset) { if (isSimulation()) return true; return (::updateTime(utc, utc_offset) == 0); } void CelestronGPS::processJoystick(const char * joystick_n, double mag, double angle) { if (!strcmp(joystick_n, "NSWE Control")) processNSWE(mag, angle); } void CelestronGPS::joystickHelper(const char * joystick_n, double mag, double angle) { telescope->processJoystick(joystick_n, mag, angle); } void CelestronGPS::buttonHelper(const char * button_n, ISState state) { telescope->processButton(button_n, state); } libindi-0.9.7/drivers/telescope/magellan1.h0000644000175000017500000000453712241463551017610 0ustar jasemjasem/* MAGELLAN Generic Copyright (C) 2011 Onno Hommes (ohommes@alumni.cmu.edu) 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 */ #ifndef MAGELLAN1_H #define MAGELLAN1_H #include "indidevapi.h" #include "indicom.h" #define POLLMS 1000 /* poll period, ms */ /* The device name below eventhough we have a Magellan I should remain set to a KStars registered telescope so It allows the service to be stopped */ #define mydev "Magellan I" /* The device name */ class Magellan1 { public: Magellan1(); virtual ~Magellan1(); virtual void ISGetProperties (const char *dev); virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual void ISSnoopDevice (XMLEle *root); virtual void ISPoll (); virtual void getBasicData(); void handleError(ISwitchVectorProperty *svp, int err, const char *msg); void handleError(INumberVectorProperty *nvp, int err, const char *msg); void handleError(ITextVectorProperty *tvp, int err, const char *msg); bool isTelescopeOn(void); void connectTelescope(); void setCurrentDeviceName(const char * devName); void correctFault(); int fd; protected: int timeFormat; int currentSiteNum; int trackingMode; double JD; double lastRA; double lastDEC; bool fault; bool simulation; char thisDevice[64]; int currentSet; int lastSet; double targetRA, targetDEC; }; #endif libindi-0.9.7/drivers/telescope/ieq45driver8407.c0000644000175000017500000011240512241463551020422 0ustar jasemjasem#if 0 IEQ45 Driver Copyright (C) 2011 Nacho Mas (mas.ignacio@gmail.com). Only litle changes from lx200basic made it by Jasem Mutlaq (mutlaqja@ikarustech.com) 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 NOTES on 9407 vs 8406: .-Diferente init V#, .- Diferent response to :MS# .- Diff RT0,1, .. codification #endif #include #include #include #include #include #include #include #include #include #include "indicom.h" #include "indidevapi.h" #include "ieq45driver.h" #ifndef _WIN32 #include #endif #define IEQ45_TIMEOUT 5 /* FD timeout in seconds */ int controller_format; int is8407ver=0; /************************************************************************** Diagnostics **************************************************************************/ int check_IEQ45_connection(int fd); /************************************************************************** Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure **************************************************************************/ /* Get Double from Sexagisemal */ int getCommandSexa(int fd, double *value, const char *cmd); /* Get String */ int getCommandString(int fd, char *data, const char* cmd); /* Get Int */ int getCommandInt(int fd, int *value, const char* cmd); /* Get tracking frequency */ int getTrackFreq(int fd, double * value); /* Get site Latitude */ int getSiteLatitude(int fd, int *dd, int *mm); /* Get site Longitude */ int getSiteLongitude(int fd, int *ddd, int *mm); /* Get Calender data */ int getCalenderDate(int fd, char *date); /* Get site Name */ int getSiteName(int fd, char *siteName, int siteNum); /* Get Number of Bars */ int getNumberOfBars(int fd, int *value); /* Get Home Search Status */ int getHomeSearchStatus(int fd, int *status); /* Get OTA Temperature */ int getOTATemp(int fd, double * value); /* Get time format: 12 or 24 */ int getTimeFormat(int fd, int *format); /************************************************************************** Set Commands **************************************************************************/ /* Set Int */ int setCommandInt(int fd, int data, const char *cmd); /* Set Sexigesimal */ int setCommandXYZ(int fd, int x, int y, int z, const char *cmd); /* Common routine for Set commands */ int setStandardProcedure(int fd, char * writeData); /* Set Slew Mode */ int setSlewMode(int fd, int slewMode); /* Set Alignment mode */ int setAlignmentMode(int fd, unsigned int alignMode); /* Set Object RA */ int setObjectRA(int fd, double ra); /* set Object DEC */ int setObjectDEC(int fd, double dec); /* Set Calender date */ int setCalenderDate(int fd, int dd, int mm, int yy); /* Set UTC offset */ int setUTCOffset(int fd, double hours); /* Set Track Freq */ int setTrackFreq(int fd, double trackF); /* Set current site longitude */ int setSiteLongitude(int fd, double Long); /* Set current site latitude */ int setSiteLatitude(int fd, double Lat); /* Set Object Azimuth */ int setObjAz(int fd, double az); /* Set Object Altitude */ int setObjAlt(int fd, double alt); /* Set site name */ int setSiteName(int fd, char * siteName, int siteNum); /* Set maximum slew rate */ int setMaxSlewRate(int fd, int slewRate); /* Set focuser motion */ int setFocuserMotion(int fd, int motionType); /* Set focuser speed mode */ int setFocuserSpeedMode (int fd, int speedMode); /* Set minimum elevation limit */ int setMinElevationLimit(int fd, int min); /* Set maximum elevation limit */ int setMaxElevationLimit(int fd, int max); /************************************************************************** Motion Commands **************************************************************************/ /* Slew to the selected coordinates */ int Slew(int fd); /* Synchronize to the selected coordinates and return the matching object if any */ int Sync(int fd, char *matchedObject); /* Abort slew in all axes */ 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 */ 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 **************************************************************************/ /* Ensures IEQ45 RA/DEC format is long */ int checkIEQ45Format(int fd); /* Select a site from the IEQ45 controller */ int selectSite(int fd, int siteNum); /* Select a catalog object */ int selectCatalogObject(int fd, int catalog, int NNNN); /* Select a sub catalog */ int selectSubCatalog(int fd, int catalog, int subCatalog); int check_IEQ45_connection(int in_fd) { int i=0; char firmwareVersion[] = ":V#"; char MountInfo[] =":MountInfo#"; char response[64]; int nbytes_read=0; #ifdef INDI_DEBUG IDLog("Testing telescope's connection using :V# command...\n"); #endif if (in_fd <= 0) return -1; for (i=0; i < 2; i++) { if (write(in_fd, firmwareVersion, sizeof(firmwareVersion)) < 0) return -1; tty_read(in_fd, response, 1, IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read != 1) return -1; usleep(50000); } #ifdef INDI_DEBUG IDLog("Initializating telescope's using :MountInfo# command...\n"); #endif for (i=0; i < 2; i++) { if (write(in_fd, MountInfo, sizeof(MountInfo)) < 0) return -1; tty_read(in_fd, response, 1, IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read == 1) return 0; usleep(50000); } return -1; } /********************************************************************** * GET **********************************************************************/ void remove_spaces(char *texto_recibe) { char *texto_sin_espacio; for (texto_sin_espacio = texto_recibe; *texto_recibe; texto_recibe++) { if (isspace(*texto_recibe)) continue; *texto_sin_espacio++ = *texto_recibe; } *texto_sin_espacio = '\0'; } int getCommandSexa(int fd, double *value, const char * cmd) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; tcflush(fd, TCIFLUSH); if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; /*if ( (read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT)) < 1) return read_ret;*/ tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); temp_string[nbytes_read - 1] = '\0'; /*IDLog("getComandSexa: %s\n", temp_string);*/ //IEQ45 sometimes send a malformed RA/DEC (intermediate spaces) //so I clean before: remove_spaces(temp_string); if (f_scansexa(temp_string, value)) { #ifdef INDI_DEBUG IDLog("unable to process [%s]\n", temp_string); #endif return -1; } tcflush(fd, TCIFLUSH); return 0; } int getCommandInt(int fd, int *value, const char* cmd) { char temp_string[16]; float temp_number; int error_type; int nbytes_write=0, nbytes_read=0; tcflush(fd, TCIFLUSH); if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); temp_string[nbytes_read - 1] = '\0'; /* Float */ if (strchr(temp_string, '.')) { if (sscanf(temp_string, "%f", &temp_number) != 1) return -1; *value = (int) temp_number; } /* Int */ else if (sscanf(temp_string, "%d", value) != 1) return -1; return 0; } int getCommandString(int fd, char *data, const char* cmd) { char * term; int error_type; int nbytes_write=0, nbytes_read=0; /*if (portWrite(cmd) < 0) return -1;*/ if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(data, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, data, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (error_type != TTY_OK) return error_type; term = strchr (data, '#'); if (term) *term = '\0'; #ifdef INDI_DEBUG /*IDLog("Requested data: %s\n", data);*/ #endif return 0; } int getCalenderDate(int fd, char *date) { int dd, mm, yy; int error_type; int nbytes_read=0; char mell_prefix[3]; if ( (error_type = getCommandString(fd, date, ":GC#")) ) return error_type; /* Meade format is MM/DD/YY */ nbytes_read = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy); if (nbytes_read < 3) return -1; /* We consider years 50 or more to be in the last century, anything less in the 21st century.*/ if (yy > 50) strncpy(mell_prefix, "19", 3); else strncpy(mell_prefix, "20", 3); /* We need to have in in YYYY/MM/DD format */ snprintf(date, 16, "%s%02d/%02d/%02d", mell_prefix, yy, mm, dd); return (0); } int getTimeFormat(int fd, int *format) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; int tMode; /*if (portWrite(":Gc#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Gc#", &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ if ( (error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read)) != TTY_OK) return error_type; tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read-1] = '\0'; nbytes_read = sscanf(temp_string, "(%d)", &tMode); if (nbytes_read < 1) return -1; else *format = tMode; return 0; } int getSiteName(int fd, char *siteName, int siteNum) { char * term; int error_type; int nbytes_write=0, nbytes_read=0; switch (siteNum) { case 1: /*if (portWrite(":GM#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GM#", &nbytes_write)) != TTY_OK) return error_type; break; case 2: /*if (portWrite(":GN#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GN#", &nbytes_write)) != TTY_OK) return error_type; break; case 3: /*if (portWrite(":GO#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GO#", &nbytes_write)) != TTY_OK) return error_type; break; case 4: /*if (portWrite(":GP#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GP#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; } /*read_ret = portRead(siteName, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, siteName, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; siteName[nbytes_read - 1] = '\0'; term = strchr (siteName, ' '); if (term) *term = '\0'; term = strchr (siteName, '<'); if (term) strcpy(siteName, "unused site"); #ifdef INDI_DEBUG IDLog("Requested site name: %s\n", siteName); #endif return 0; } int getSiteLatitude(int fd, int *dd, int *mm) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; /*if (portWrite(":Gt#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Gt#", &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read -1] = '\0'; if (sscanf (temp_string, "%d%*c%d", dd, mm) < 2) return -1; #ifdef INDI_DEBUG fprintf(stderr, "Requested site latitude in String %s\n", temp_string); fprintf(stderr, "Requested site latitude %d:%d\n", *dd, *mm); #endif return 0; } int getSiteLongitude(int fd, int *ddd, int *mm) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":Gg#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":Gg#") < 0) return -1;*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read -1] = '\0'; if (sscanf (temp_string, "%d%*c%d", ddd, mm) < 2) return -1; #ifdef INDI_DEBUG fprintf(stderr, "Requested site longitude in String %s\n", temp_string); fprintf(stderr, "Requested site longitude %d:%d\n", *ddd, *mm); #endif return 0; } int getTrackFreq(int fd, double *value) { float Freq; char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":GT#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":GT#") < 0) return -1;*/ /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read] = '\0'; /*fprintf(stderr, "Telescope tracking freq str: %s\n", temp_string);*/ if (sscanf(temp_string, "%f#", &Freq) < 1) return -1; *value = (double) Freq; #ifdef INDI_DEBUG fprintf(stderr, "Tracking frequency value is %f\n", Freq); #endif return 0; } int getNumberOfBars(int fd, int *value) { char temp_string[128]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":D#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":D#") < 0) return -1;*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 0) return error_type; *value = nbytes_read -1; return 0; } int getHomeSearchStatus(int fd, int *status) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":h?#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":h?#") < 0) return -1;*/ /*read_ret = portRead(temp_string, 1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[1] = '\0'; if (temp_string[0] == '0') *status = 0; else if (temp_string[0] == '1') *status = 1; else if (temp_string[0] == '2') *status = 1; return 0; } int getOTATemp(int fd, double *value) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; float temp; if ( (error_type = tty_write_string(fd, ":fT#", &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; temp_string[nbytes_read - 1] = '\0'; if (sscanf(temp_string, "%f", &temp) < 1) return -1; *value = (double) temp; return 0; } int updateSkyCommanderCoord(int fd, double *ra, double *dec) { char coords[16]; char CR[1] = { (char) 0x0D }; float RA=0.0, DEC=0.0; int error_type; int nbytes_read=0; error_type = write(fd, CR, 1); error_type = tty_read(fd, coords, 16, IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead(coords, 16, IEQ45_TIMEOUT);*/ tcflush(fd, TCIFLUSH); nbytes_read = sscanf(coords, " %g %g", &RA, &DEC); if (nbytes_read < 2) { #ifdef INDI_DEBUG IDLog("Error in Sky commander number format [%s], exiting.\n", coords); #endif return error_type; } *ra = RA; *dec = DEC; return 0; } int updateIntelliscopeCoord (int fd, double *ra, double *dec) { char coords[16]; char CR[1] = { (char) 0x51 }; /* "Q" */ float RA = 0.0, DEC = 0.0; int error_type; int nbytes_read=0; /*IDLog ("Sending a Q\n");*/ error_type = write (fd, CR, 1); /* We start at 14 bytes in case its a Sky Wizard, but read one more later it if it's a intelliscope */ /*read_ret = portRead (coords, 14, IEQ45_TIMEOUT);*/ error_type = tty_read(fd, coords, 14, IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); /*IDLog ("portRead() = [%s]\n", coords);*/ /* Remove the Q in the response from the Intelliscope but not the Sky Wizard */ if (coords[0] == 'Q') { coords[0] = ' '; /* Read one more byte if Intelliscope to get the "CR" */ error_type = tty_read(fd, coords, 1, IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead (coords, 1, IEQ45_TIMEOUT);*/ } nbytes_read = sscanf (coords, " %g %g", &RA, &DEC); /*IDLog ("sscanf() RA = [%f]\n", RA * 0.0390625);*/ /*IDLog ("sscanf() DEC = [%f]\n", DEC * 0.0390625);*/ /*IDLog ("Intelliscope output [%s]", coords);*/ if (nbytes_read < 2) { #ifdef INDI_DEBUG IDLog ("Error in Intelliscope number format [%s], exiting.\n", coords); #endif return -1; } *ra = RA * 0.0390625; *dec = DEC * 0.0390625; return 0; } /********************************************************************** * SET **********************************************************************/ int setStandardProcedure(int fd, char * data) { char bool_return[2]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read(fd, bool_return, 1, IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead(boolRet, 1, IEQ45_TIMEOUT);*/ tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; if (bool_return[0] == '0') { #ifdef INDI_DEBUG IDLog("%s Failed.\n", data); #endif return -1; } #ifdef INDI_DEBUG IDLog("%s Successful\n", data); #endif return 0; } int setCommandInt(int fd, int data, const char *cmd) { char temp_string[16]; int error_type; int nbytes_write=0; snprintf(temp_string, sizeof( temp_string ), "%s%d#", cmd, data); if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /* if (portWrite(temp_string) < 0) return -1;*/ return 0; } int setMinElevationLimit(int fd, int min) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":Sh%02d#", min); return (setStandardProcedure(fd, temp_string)); } int setMaxElevationLimit(int fd, int max) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":So%02d*#", max); return (setStandardProcedure(fd, temp_string)); } int setMaxSlewRate(int fd, int slewRate) { char temp_string[16]; if (slewRate < 2 || slewRate > 8) return -1; snprintf(temp_string, sizeof( temp_string ), ":Sw%d#", slewRate); return (setStandardProcedure(fd, temp_string)); } int setObjectRA(int fd, double ra) { int h, m, s, frac_m; char temp_string[16]; getSexComponents(ra, &h, &m, &s); frac_m = (s / 60.0) * 10.; if (controller_format == IEQ45_LONG_FORMAT) snprintf(temp_string, sizeof( temp_string ), ":Sr %02d:%02d:%02d#", h, m, s); else snprintf(temp_string, sizeof( temp_string ), ":Sr %02d:%02d.%01d#", h, m, frac_m); /*IDLog("Set Object RA String %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setObjectDEC(int fd, double dec) { int d, m, s; char temp_string[16]; getSexComponents(dec, &d, &m, &s); switch(controller_format) { case IEQ45_SHORT_FORMAT: /* case with negative zero */ if (!d && dec < 0) snprintf(temp_string, sizeof( temp_string ), ":Sd -%02d*%02d#", d, m); else snprintf(temp_string, sizeof( temp_string ), ":Sd %+03d*%02d#", d, m); break; case IEQ45_LONG_FORMAT: /* case with negative zero */ if (!d && dec < 0) snprintf(temp_string, sizeof( temp_string ), ":Sd -%02d:%02d:%02d#", d, m, s); else snprintf(temp_string, sizeof( temp_string ), ":Sd %+03d:%02d:%02d#", d, m, s); break; } /*IDLog("Set Object DEC String %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setCommandXYZ(int fd, int x, int y, int z, const char *cmd) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), "%s %02d:%02d:%02d#", cmd, x, y, z); return (setStandardProcedure(fd, temp_string)); } int setAlignmentMode(int fd, unsigned int alignMode) { /*fprintf(stderr , "Set alignment mode %d\n", alignMode);*/ int error_type; int nbytes_write=0; switch (alignMode) { case IEQ45_ALIGN_POLAR: if ( (error_type = tty_write_string(fd, ":AP#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":AP#") < 0) return -1;*/ break; case IEQ45_ALIGN_ALTAZ: if ( (error_type = tty_write_string(fd, ":AA#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":AA#") < 0) return -1;*/ break; case IEQ45_ALIGN_LAND: if ( (error_type = tty_write_string(fd, ":AL#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":AL#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setCalenderDate(int fd, int dd, int mm, int yy) { char temp_string[32]; char dumpPlanetaryUpdateString[64]; char bool_return[2]; int error_type; int nbytes_write=0, nbytes_read=0; yy = yy % 100; snprintf(temp_string, sizeof( temp_string ), ":SC %02d/%02d/%02d#", mm, dd, yy); if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(temp_string) < 0) return -1;*/ /*read_ret = portRead(boolRet, 1, IEQ45_TIMEOUT);*/ error_type = tty_read(fd, bool_return, 1, IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; bool_return[1] = '\0'; if (bool_return[0] == '0') return -1; /* Read dumped data */ error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', IEQ45_TIMEOUT, &nbytes_read); error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', 5, &nbytes_read); return 0; } int setUTCOffset(int fd, double hours) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":SG %+03d#", (int) hours); /*IDLog("UTC string is %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setSiteLongitude(int fd, double Long) { int d, m, s; char temp_string[32]; getSexComponents(Long, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":Sg%03d:%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setSiteLatitude(int fd, double Lat) { int d, m, s; char temp_string[32]; getSexComponents(Lat, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":St%+03d:%02d:%02d#", d, m, s); return (setStandardProcedure(fd, temp_string)); } int setObjAz(int fd, double az) { int d,m,s; char temp_string[16]; getSexComponents(az, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":Sz%03d:%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setObjAlt(int fd, double alt) { int d, m, s; char temp_string[16]; getSexComponents(alt, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":Sa%+02d*%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setSiteName(int fd, char * siteName, int siteNum) { char temp_string[16]; switch (siteNum) { case 1: snprintf(temp_string, sizeof( temp_string ), ":SM %s#", siteName); break; case 2: snprintf(temp_string, sizeof( temp_string ), ":SN %s#", siteName); break; case 3: snprintf(temp_string, sizeof( temp_string ), ":SO %s#", siteName); break; case 4: snprintf(temp_string, sizeof( temp_string ), ":SP %s#", siteName); break; default: return -1; } return (setStandardProcedure(fd, temp_string)); } int setSlewMode(int fd, int slewMode) { int error_type; int nbytes_write=0; switch (slewMode) { case IEQ45_SLEW_MAX: if ( (error_type = tty_write_string(fd, ":RS#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RS#") < 0) return -1;*/ break; case IEQ45_SLEW_FIND: if ( (error_type = tty_write_string(fd, ":RM#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RM#") < 0) return -1;*/ break; case IEQ45_SLEW_CENTER: if ( (error_type = tty_write_string(fd, ":RC#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RC#") < 0) return -1;*/ break; case IEQ45_SLEW_GUIDE: if ( (error_type = tty_write_string(fd, ":RG#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RG#") < 0) return -1;*/ break; default: break; } tcflush(fd, TCIFLUSH); return 0; } int setFocuserMotion(int fd, int motionType) { int error_type; int nbytes_write=0; switch (motionType) { case IEQ45_FOCUSIN: if ( (error_type = tty_write_string(fd, ":F+#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus IN Command\n");*/ #endif /*if (portWrite(":F+#") < 0) return -1;*/ break; case IEQ45_FOCUSOUT: if ( (error_type = tty_write_string(fd, ":F-#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus OUT Command\n");*/ #endif /*if (portWrite(":F-#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setFocuserSpeedMode (int fd, int speedMode) { int error_type; int nbytes_write=0; switch (speedMode) { case IEQ45_HALTFOCUS: if ( (error_type = tty_write_string(fd, ":FQ#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Halt Focus Command\n");*/ #endif /* if (portWrite(":FQ#") < 0) return -1;*/ break; case IEQ45_FOCUSSLOW: if ( (error_type = tty_write_string(fd, ":FS#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus Slow (FS) Command\n");*/ #endif /*if (portWrite(":FS#") < 0) return -1;*/ break; case IEQ45_FOCUSFAST: if ( (error_type = tty_write_string(fd, ":FF#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus Fast (FF) Command\n");*/ #endif /*if (portWrite(":FF#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setGPSFocuserSpeed (int fd, int speed) { char speed_str[8]; int error_type; int nbytes_write=0; if (speed == 0) { /*if (portWrite(":FQ#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":FQ#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("GPS Focus HALT Command (FQ) \n");*/ #endif return 0; } snprintf(speed_str, 8, ":F%d#", speed); if ( (error_type = tty_write_string(fd, speed_str, &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("GPS Focus Speed command %s \n", speed_str);*/ #endif /*if (portWrite(speed_str) < 0) return -1;*/ tcflush(fd, TCIFLUSH); return 0; } int setTrackFreq(int fd, double trackF) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":ST %04.1f#", trackF); return (setStandardProcedure(fd, temp_string)); } /********************************************************************** * Misc *********************************************************************/ int Slew(int fd) { char slewNum[2]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":MS#", &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read(fd, slewNum, 1, IEQ45_TIMEOUT, &nbytes_read); #ifdef INDI_DEBUG //IDLog("SLEW _MS# %s %u \n", slewNum, nbytes_read); #endif if (nbytes_read < 1) return error_type; /* We don't need to read the string message, just return corresponding error code */ tcflush(fd, TCIFLUSH); if (slewNum[0] == '1') return 0; else if (slewNum[0] == '0') return 1; else return 2; } int MoveTo(int fd, int direction) { int nbytes_write=0; switch (direction) { case IEQ45_NORTH: tty_write_string(fd, ":Mn#", &nbytes_write); /*portWrite(":Mn#");*/ break; case IEQ45_WEST: tty_write_string(fd, ":Mw#", &nbytes_write); /*portWrite(":Mw#");*/ break; case IEQ45_EAST: tty_write_string(fd, ":Me#", &nbytes_write); /*portWrite(":Me#");*/ break; case IEQ45_SOUTH: tty_write_string(fd, ":Ms#", &nbytes_write); /*portWrite(":Ms#");*/ break; default: break; } tcflush(fd, TCIFLUSH); return 0; } int SendPulseCmd(int fd, int direction, int duration_msec) { int nbytes_write=0; char cmd[20]; switch (direction) { case IEQ45_NORTH: sprintf(cmd, ":Mgn%04d#", duration_msec); break; case IEQ45_SOUTH: sprintf(cmd, ":Mgs%04d#", duration_msec); break; case IEQ45_EAST: sprintf(cmd, ":Mge%04d#", duration_msec); break; case IEQ45_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; int nbytes_write=0; switch (direction) { case IEQ45_NORTH: /*if (portWrite(":Qn#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Qn#", &nbytes_write)) != TTY_OK) return error_type; break; case IEQ45_WEST: /*if (portWrite(":Qw#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Qw#", &nbytes_write)) != TTY_OK) return error_type; break; case IEQ45_EAST: /*if (portWrite(":Qe#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Qe#", &nbytes_write)) != TTY_OK) return error_type; break; case IEQ45_SOUTH: if ( (error_type = tty_write_string(fd, ":Qs#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":Qs#") < 0) return -1;*/ break; case IEQ45_ALL: /*if (portWrite(":Q#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Q#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } int abortSlew(int fd) { /*if (portWrite(":Q#") < 0) return -1;*/ int error_type; int nbytes_write=0; if ( (error_type = tty_write_string(fd, ":Q#", &nbytes_write)) != TTY_OK) return error_type; tcflush(fd, TCIFLUSH); return 0; } int Sync(int fd, char *matchedObject) { int error_type; int nbytes_write=0, nbytes_read=0; // if ( (error_type = tty_write_string(fd, ":CM#", &nbytes_write)) != TTY_OK) if ( (error_type = tty_write_string(fd, ":CMR#", &nbytes_write)) != TTY_OK) return error_type; /*portWrite(":CM#");*/ /*read_ret = portRead(matchedObject, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, matchedObject, '#', IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; matchedObject[nbytes_read-1] = '\0'; /*IDLog("Matched Object: %s\n", matchedObject);*/ /* Sleep 10ms before flushing. This solves some issues with IEQ45 compatible devices. */ usleep(10000); tcflush(fd, TCIFLUSH); return 0; } int selectSite(int fd, int siteNum) { int error_type; int nbytes_write=0; switch (siteNum) { case 1: if ( (error_type = tty_write_string(fd, ":W1#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W1#") < 0) return -1;*/ break; case 2: if ( (error_type = tty_write_string(fd, ":W2#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W2#") < 0) return -1;*/ break; case 3: if ( (error_type = tty_write_string(fd, ":W3#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W3#") < 0) return -1;*/ break; case 4: if ( (error_type = tty_write_string(fd, ":W4#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W4#") < 0) return -1;*/ break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } int selectCatalogObject(int fd, int catalog, int NNNN) { char temp_string[16]; int error_type; int nbytes_write=0; switch (catalog) { case IEQ45_STAR_C: snprintf(temp_string, sizeof( temp_string ), ":LS%d#", NNNN); break; case IEQ45_DEEPSKY_C: snprintf(temp_string, sizeof( temp_string ), ":LC%d#", NNNN); break; case IEQ45_MESSIER_C: snprintf(temp_string, sizeof( temp_string ), ":LM%d#", NNNN); break; default: return -1; } if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(temp_string) < 0) return -1;*/ tcflush(fd, TCIFLUSH); return 0; } int selectSubCatalog(int fd, int catalog, int subCatalog) { char temp_string[16]; switch (catalog) { case IEQ45_STAR_C: snprintf(temp_string, sizeof( temp_string ), ":LsD%d#", subCatalog); break; case IEQ45_DEEPSKY_C: snprintf(temp_string, sizeof( temp_string ), ":LoD%d#", subCatalog); break; case IEQ45_MESSIER_C: return 1; default: return 0; } return (setStandardProcedure(fd, temp_string)); } int checkIEQ45Format(int fd) { char temp_string[16]; controller_format = IEQ45_LONG_FORMAT; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":GR#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":GR#") < 0) return -1;*/ /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; temp_string[nbytes_read - 1] = '\0'; /* Check whether it's short or long */ if (temp_string[5] == '.') { controller_format = IEQ45_SHORT_FORMAT; return 0; } else return 0; } int selectTrackingMode(int fd, int trackMode) { int error_type; int nbytes_write=0; switch (trackMode) { case IEQ45_TRACK_SIDERAL: #ifdef INDI_DEBUG IDLog("Setting tracking mode to sidereal.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT0#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TQ#") < 0) return -1;*/ break; case IEQ45_TRACK_LUNAR: #ifdef INDI_DEBUG IDLog("Setting tracking mode to LUNAR.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT1#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TL#") < 0) return -1;*/ break; case IEQ45_TRACK_SOLAR: #ifdef INDI_DEBUG IDLog("Setting tracking mode to SOLAR.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT2#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TM#") < 0) return -1;*/ break; case IEQ45_TRACK_ZERO: #ifdef INDI_DEBUG IDLog("Setting tracking mode to custom.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT4#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TM#") < 0) return -1;*/ break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } libindi-0.9.7/drivers/telescope/temmadriver.c0000644000175000017500000005226512241463551020262 0ustar jasemjasem#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 #include #include #include #include #include #include #include #include #include #include #include #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[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { INDI_UNUSED(names); INDI_UNUSED(n); 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){ IUResetSwitch(&OnCoordSetSw); sp = IUFindSwitch (&OnCoordSetSw, names[0]); if (!sp) return; fprintf(stderr,"new state %s\n",names[0]); sp->s = states[0]; IUResetSwitch(&OnCoordSetSw); IUUpdateSwitch(&OnCoordSetSw, states, names, n); /* currentSet = getOnSwitch(&OnCoordSetSw); */ OnCoordSetSw.s = IPS_OK; IDSetSwitch(&OnCoordSetSw, NULL); } else { IDSetSwitch (&OnCoordSetSw, "Power is off"); } } } double calcLST(char *strlst){ double jd,gmst,lst; jd = ln_get_julian_from_sys(); gmst = ln_get_mean_sidereal_time(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) { INDI_UNUSED(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( ( (unsigned char *) 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; } } libindi-0.9.7/drivers/telescope/celestronprotocol.c0000644000175000017500000005036212241463551021517 0ustar jasemjasem/* * Telescope Control Protocol for Celestron NexStar GPS telescopes * * Copyright 2003 John Kielkopf * John Kielkopf (kielkopf@louisville.edu) * 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 * * 15 May 2003 -- Version 2.00 * * * */ #include #include #include #include #include #include #include #include #include #include /* do NOT change this to config-kstars.h! INDI is independent of KStars*/ #ifdef HAVE_CONFIG_H #include #endif #ifndef _WIN32 #include #endif #include #include "celestronprotocol.h" #define NULL_PTR(x) (x *)0 /* There are two classes of routines defined here: */ /* XmTel commands to allow easy NexStar access. These */ /* include routines that mimic the extensive LX200 command */ /* language and, for the most part, trap calls and */ /* respond with an error message to the console. */ /* NexStar specific commands and data. */ /* The NexStar command set as documented by Celestron */ /* is very limited. This version of xmtel uses ta few */ /* auxilliary commands which permit direct access to the motor */ /* controllers. */ /* XmTel compatibility commands */ int ConnectTel(char *port); void DisconnectTel(void); int CheckConnectTel(void); void SetRate(int newRate); void SetLimits(double limitLower, double limitHigher); void StartSlew(int direction); void StopSlew(int direction); double GetRA(void); double GetDec(void); int SlewToCoords(double newRA, double newDec); int SyncToCoords(double newRA, double newDec); int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC); void StopNSEW(void); int SetSlewRate(void); int SyncLST(double newTime); int SyncLocalTime(void); void Reticle(int reticle); void Focus(int focus); void Derotator(int rotate); void Fan(int fan); static int TelPortFD; static int TelConnectFlag = 0; /* NexStar local data */ static double returnRA; /* Last update of RA */ static double returnDec; /* Last update of Dec */ static int updateRA; /* Set if no RA inquiry since last update */ static int updateDec; /* Set if no Dec inquiry since last update */ static int slewRate; /* Rate for slew request in StartSlew */ /* Coordinate reported by NexStar = true coordinate + offset. */ static double offsetRA = 0; /* Correction to RA from NexStar */ static double offsetDec = 0; /* Correction to Dec from NexStar */ /* NexStar local commands */ void GetRAandDec(void); /* Update RA and Dec from NexStar */ /* Serial communication utilities */ typedef fd_set telfds; static int readn(int fd, char *ptr, int nbytes, int sec); static int writen(int fd, char *ptr, int nbytes); static int telstat(int fd,int sec,int usec); int CheckConnectTel(void) { int numRead; char returnStr[128]; //return TelConnectFlag; tcflush(TelPortFD,TCIOFLUSH); /* Test connection */ writen(TelPortFD,"Kx",2); numRead=readn(TelPortFD,returnStr,3,2); returnStr[numRead] = '\0'; if (numRead == 2) { TelConnectFlag = 1; return (0); } else return -1; } int ConnectTel(char *port) { #ifdef _WIN32 return -1; #else struct termios tty; char returnStr[128]; int numRead; fprintf(stderr, "Connecting to port: %s\n",port); if(TelConnectFlag != 0) return 0; /* Make the connection */ TelPortFD = open(port,O_RDWR); if(TelPortFD == -1) return -1; tcgetattr(TelPortFD,&tty); cfsetospeed(&tty, (speed_t) B9600); cfsetispeed(&tty, (speed_t) B9600); tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; tty.c_iflag = IGNBRK; tty.c_lflag = 0; tty.c_oflag = 0; tty.c_cflag |= CLOCAL | CREAD; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 5; tty.c_iflag &= ~(IXON|IXOFF|IXANY); tty.c_cflag &= ~(PARENB | PARODD); tcsetattr(TelPortFD, TCSANOW, &tty); /* Flush the input (read) buffer */ tcflush(TelPortFD,TCIOFLUSH); /* Test connection */ writen(TelPortFD,"Kx",2); numRead=readn(TelPortFD,returnStr,3,2); returnStr[numRead] = '\0'; /* Diagnostic tests */ fprintf(stderr, "ConnectTel read %d characters: %s\n",numRead,returnStr); fprintf(stderr, "TelConnectFlag set to: %d\n",TelConnectFlag); if (numRead == 2) { TelConnectFlag = 1; return (0); } else return -1; #endif } /* Assign and save slewRate for use in StartSlew */ void SetRate(int newRate) { if(newRate == SLEW) { slewRate = 9; } else if(newRate == FIND) { slewRate = 6; } else if(newRate == CENTER) { slewRate = 3; } else if(newRate == GUIDE) { slewRate = 1; } } /* Start a slew in chosen direction at slewRate */ /* Use auxilliary NexStar command set through the hand control computer */ void StartSlew(int direction) { char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x09, 0x00, 0x00, 0x00 }; char inputStr[2048]; if(direction == NORTH) { slewCmd[2] = 0x11; slewCmd[3] = 0x24; slewCmd[4] = slewRate; } else if(direction == EAST) { slewCmd[2] = 0x10; slewCmd[3] = 0x25; slewCmd[4] = slewRate; } else if(direction == SOUTH) { slewCmd[2] = 0x11; slewCmd[3] = 0x25; slewCmd[4] = slewRate; } else if(direction == WEST) { slewCmd[2] = 0x10; slewCmd[3] = 0x24; slewCmd[4] = slewRate; } writen(TelPortFD,slewCmd,8); /* Look for '#' acknowledgment of request*/ for (;;) { if ( readn(TelPortFD,inputStr,1,1) ) { if (inputStr[0] == '#') break; } else { fprintf(stderr,"No acknowledgment from telescope in StartSlew.\n"); } } } /* Stop the slew in chosen direction */ void StopSlew(int direction) { char slewCmd[] = { 0x50, 0x02, 0x11, 0x24, 0x00, 0x00, 0x00, 0x00 }; char inputStr[2048]; if(direction == NORTH) { slewCmd[2] = 0x11; slewCmd[3] = 0x24; } else if(direction == EAST) { slewCmd[2] = 0x10; slewCmd[3] = 0x25; } else if(direction == SOUTH) { slewCmd[2] = 0x11; slewCmd[3] = 0x25; } else if(direction == WEST) { slewCmd[2] = 0x10; slewCmd[3] = 0x24; } writen(TelPortFD,slewCmd,8); /* Look for '#' acknowledgment of request*/ for (;;) { if ( readn(TelPortFD,inputStr,1,1) ) { if (inputStr[0] == '#') break; } else { fprintf(stderr,"No acknowledgment from telescope in StartSlew.\n"); } } } void DisconnectTel(void) { /* printf("DisconnectTel\n"); */ if(TelConnectFlag == 1) close(TelPortFD); TelConnectFlag = 0; } /* Test update status and return the telescope right ascension */ /* Set updateRA flag false */ /* Last telescope readout will be returned if no RA inquiry since then */ /* Otherwise force a new readout */ /* Two successive calls to GetRA will always force a new readout */ double GetRA(void) { if( updateRA != 1) GetRAandDec(); updateRA = 0; return returnRA; } /* Test update status and return the telescope declination */ /* Set updateDec flag false */ /* Last telescope readout will returned if no Dec inquiry since then */ /* Otherwise force a new readout */ /* Two successive calls to GetDec will always force a new readout */ double GetDec(void) { if( updateDec != 1) GetRAandDec(); updateDec = 0; return returnDec; } /* Read the telescope right ascension and declination and set update status */ int isScopeSlewing() { int numRead; char returnStr[128]; writen(TelPortFD,"L",1); numRead=readn(TelPortFD,returnStr,2,2); returnStr[numRead] = '\0'; // 0 Slew complete // 1 Slew in progress return (returnStr[0] == '0' ? 0 : 1); } void GetRAandDec(void) { char returnStr[12]; int countRA,countDec; int numRead; writen(TelPortFD,"E",1); numRead=readn(TelPortFD,returnStr,10,1); returnStr[4] = returnStr[9] = '\0'; /* Diagnostic * * printf("GetRAandDec: %d read %x\n",numRead,returnStr); * */ sscanf(returnStr,"%x",&countRA); sscanf(returnStr+5,"%x:",&countDec); returnRA = (double) countRA; returnRA = returnRA / (3. * 15. * 60. * 65536./64800.); returnDec = (double) countDec; returnDec = returnDec / (3. * 60. * 65536./64800.); /* Account for the quadrant in declination */ /* 90 to 180 */ if ( (returnDec > 90.) && (returnDec <= 180.) ) { returnDec = 180. - returnDec; } /* 180 to 270 */ if ( (returnDec > 180.) && (returnDec <= 270.) ) { returnDec = returnDec - 270.; } /* 270 to 360 */ if ( (returnDec > 270.) && (returnDec <= 360.) ) { returnDec = returnDec - 360.; } /* Set update flags */ updateRA = 1; updateDec = 1; /* Correct for offsets and return true coordinate */ /* Coordinate reported by NexStar = true coordinate + offset. */ returnRA = returnRA - offsetRA; returnDec = returnDec - offsetDec; } /* Reset telescope coordinates to new coordinates by adjusting offsets*/ /* Coordinate reported by NexStar = true coordinate + offset. */ int SyncToCoords(double newRA, double newDec) { /* offsetRA = 0.; offsetDec = 0.; GetRAandDec(); offsetRA = returnRA - newRA; offsetDec = returnDec - newDec; return (0);*/ /* 2013-10-19 JM: Trying to support sync in Nextstar command set v4.10+ */ char str[20]; int n1,n2; // so, lets format up a sync command n1=newRA*0x1000000/24; n2=newDec*0x1000000/360; n1=n1<<8; n2=n2<<8; sprintf((char *)str,"s%08X,%08X",n1,n2); writen(TelPortFD,str,18); /* Look for '#' in response */ for (;;) { if ( readn(TelPortFD,str,1,2) ) { if (str[0] == '#') break; } else fprintf(stderr,"No acknowledgment from telescope after SyncToCoords.\n"); return 4; } return 0; } /* 2013-11-06 JM: support location update in Nextstar command set */ int updateLocation(double lng, double lat) { int lat_d, lat_m, lat_s; int long_d, long_m ,long_s ; char str[10]; char cmd[8]; getSexComponents(lat, &lat_d, &lat_m, &lat_s); getSexComponents(lng, &long_d, &long_m, &long_s); // Convert from INDI standard to regular east/west -180 to 180 if (long_d > 180) long_d -= 360; cmd[0] = abs(lat_d); cmd[1] = lat_m; cmd[2] = lat_s; cmd[3] = lat_d > 0 ? 0 : 1; cmd[4] = abs(long_d); cmd[5] = long_m; cmd[6] = long_s; cmd[7] = long_d > 0 ? 0 : 1; 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]); writen(TelPortFD,str,9); /* Look for '#' in response */ for (;;) { if ( readn(TelPortFD,str,1,2) ) { if (str[0] == '#') break; } else fprintf(stderr,"No acknowledgment from telescope after updateLocation.\n"); return 4; } return 0; } int updateTime(struct ln_date *utc, double utc_offset) { char str[10]; char cmd[8]; struct ln_zonedate local_date; // Celestron takes local time ln_date_to_zonedate(utc, &local_date, utc_offset*3600); cmd[0] = local_date.hours; cmd[1] = local_date.minutes; cmd[2] = local_date.seconds; cmd[3] = local_date.months; cmd[4] = local_date.days; cmd[5] = local_date.years - 2000; if (utc_offset < 0) cmd[6] = 256 - ((unsigned int) fabs(utc_offset)); else cmd[6] = ((unsigned int) fabs(utc_offset)); // Always assume standard time cmd[7] = 0; 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]); writen(TelPortFD,str,9); /* Look for '#' in response */ for (;;) { if ( readn(TelPortFD,str,1,2) ) { if (str[0] == '#') break; } else fprintf(stderr,"No acknowledgment from telescope after updateTime.\n"); return 4; } return 0; } /* Slew to new coordinates */ /* Coordinate sent to NexStar = true coordinate + offset. */ int SlewToCoords(double newRA, double newDec) { int countRA,countDec; char r0,r1,r2,r3,d0,d1,d2,d3; double degs, hrs; char outputStr[32], inputStr[2048]; /* Add offsets */ hrs = newRA + offsetRA; degs = newDec + offsetDec; /* Convert float RA to integer count */ hrs = hrs*(3. * 15. * 60. * 65536./64800.); countRA = (int) hrs; /* Account for the quadrant in declination */ if ( (newDec >= 0.0) && (newDec <= 90.0) ) { degs = degs*(3. * 60. * 65536./64800.); } else if ( (newDec < 0.0) && (newDec >= -90.0) ) { degs = (360. + degs)*(3. * 60. * 65536./64800.); } else { fprintf(stderr,"Invalid newDec in SlewToCoords.\n"); return 1; } /* Convert float Declination to integer count */ countDec = (int) degs; /* Convert each integer count to four HEX characters */ /* Inline coding just to be fast */ if(countRA < 65536) { r0 = countRA % 16; if(r0 < 10) { r0 = r0 + 48; } else { r0 = r0 + 55; } countRA = countRA/16; r1 = countRA % 16; if(r1 < 10) { r1 = r1 + 48; } else { r1 = r1 + 55; } countRA = countRA/16; r2 = countRA % 16; if(r2 < 10) { r2 = r2 + 48; } else { r2 = r2 + 55; } r3 = countRA/16; if(r3 < 10) { r3 = r3 + 48; } else { r3 = r3 + 55; } } else { printf("RA count overflow in SlewToCoords.\n"); return 2; } if(countDec < 65536) { d0 = countDec % 16; if(d0 < 10) { d0 = d0 + 48; } else { d0 = d0 + 55; } countDec = countDec/16; d1 = countDec % 16; if(d1 < 10) { d1 = d1 + 48; } else { d1 = d1 + 55; } countDec = countDec/16; d2 = countDec % 16; if(d2 < 10) { d2 = d2 + 48; } else { d2 = d2 + 55; } d3 = countDec/16; if(d3 < 10) { d3 = d3 + 48; } else { d3 = d3 + 55; } } else { fprintf(stderr,"Dec count overflow in SlewToCoords.\n"); return 3; } /* Send the command and characters to the NexStar */ sprintf(outputStr,"R%c%c%c%c,%c%c%c%c",r3,r2,r1,r0,d3,d2,d1,d0); writen(TelPortFD,outputStr,10); /* Look for '#' in response */ for (;;) { if ( readn(TelPortFD,inputStr,1,2) ) { if (inputStr[0] == '#') break; } else fprintf(stderr,"No acknowledgment from telescope after SlewToCoords.\n"); return 4; } return 0; } /* Test whether the destination has been reached */ /* With the NexStar we use the goto in progress query */ /* Return value is */ /* 0 -- goto in progress */ /* 1 -- goto complete within tolerance */ /* 2 -- goto complete but outside tolerance */ int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC) { double errorRA, errorDec, nowRA, nowDec; char inputStr[2048]; writen(TelPortFD,"L",1); /* Look for '0#' in response indicating goto is not in progress */ for (;;) { if ( readn(TelPortFD,inputStr,2,2) ) { if ( (inputStr[0] == '0') && (inputStr[1] == '#')) break; } else return 0; } nowRA=GetRA(); errorRA = nowRA - desRA; nowDec=GetDec(); errorDec = nowDec - desDec; /* For 6 minute of arc precision; change as needed. */ if( fabs(errorRA) > tolRA || fabs(errorDec) > tolDEC) return 1; else return 2; } /* Set lower and upper limits to protect hardware */ void SetLimits(double limitLower, double limitHigher) { limitLower = limitHigher; fprintf(stderr,"NexStar does not support software limits.\n"); } /* Set slew speed limited by MAXSLEWRATE */ int SetSlewRate(void) { fprintf(stderr,"NexStar does not support remote setting of slew rate.\n"); return 0; } /* Stop all slew motion */ void StopNSEW(void) { char inputStr[2048]; writen(TelPortFD,"M",1); /* Look for '#' */ for (;;) { if ( readn(TelPortFD,inputStr,1,1) ) { if (inputStr[0] == '#') break; } else { fprintf(stderr,"No acknowledgment from telescope in StopNSEW.\n"); } } } /* Control the reticle function using predefined values */ void Reticle(int reticle) { reticle = reticle; fprintf(stderr,"NexStar does not support remote setting of reticle.\n"); } /* Control the focus using predefined values */ void Focus(int focus) { focus = focus; fprintf(stderr,"NexStar does not support remote setting of focus.\n"); } /* Control the derotator using predefined values */ void Derotator(int rotate) { rotate = rotate; fprintf(stderr,"NexStar does not support an image derotator.\n"); } /* Control the fan using predefined values */ void Fan(int fan) { fan = fan; fprintf(stderr,"NexStar does not have a fan.\n"); } /* Time synchronization utilities */ /* Reset the telescope sidereal time */ int SyncLST(double newTime) { newTime = newTime; fprintf(stderr,"NexStar does not support remote setting of sidereal time.\n"); return -1; } /* Reset the telescope local time */ int SyncLocalTime() { fprintf(stderr,"NexStar does not support remote setting of local time.\n"); return -1; } /* Serial port utilities */ static int writen(fd, ptr, nbytes) int fd; char *ptr; int nbytes; { int nleft, nwritten; nleft = nbytes; while (nleft > 0) { nwritten = write (fd, ptr, nleft); if (nwritten <=0 ) break; nleft -= nwritten; ptr += nwritten; } return (nbytes - nleft); } static int readn(fd, ptr, nbytes, sec) int fd; char *ptr; int nbytes; int sec; { int status; int nleft, nread; nleft = nbytes; while (nleft > 0) { status = telstat(fd,sec,0); if (status <= 0 ) break; nread = read (fd, ptr, nleft); /* Diagnostic */ /* printf("readn: %d read\n", nread); */ if (nread <= 0) break; nleft -= nread; ptr += nread; } return (nbytes - nleft); } /* * Examines the read status of a file descriptor. * The timeout (sec, usec) specifies a maximum interval to * wait for data to be available in the descriptor. * To effect a poll, the timeout (sec, usec) should be 0. * Returns non-negative value on data available. * 0 indicates that the time limit referred by timeout expired. * On failure, it returns -1 and errno is set to indicate the * error. */ static int telstat(fd,sec,usec) register int fd, sec, usec; { int ret; int width; struct timeval timeout; telfds readfds; memset((char *)&readfds,0,sizeof(readfds)); FD_SET(fd, &readfds); width = fd+1; timeout.tv_sec = sec; timeout.tv_usec = usec; ret = select(width,&readfds,NULL_PTR(telfds),NULL_PTR(telfds),&timeout); return(ret); } libindi-0.9.7/drivers/telescope/lx200generic.h0000644000175000017500000001054212241463551020142 0ustar jasemjasem/* LX200 Generic Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef LX200GENERIC_H #define LX200GENERIC_H #include "indiguiderinterface.h" #include "inditelescope.h" #include "indicontroller.h" #include "indidevapi.h" #include "indicom.h" #define POLLMS 1000 /* poll period, ms */ class LX200Generic: public INDI::Telescope, public INDI::GuiderInterface { public: LX200Generic(); virtual ~LX200Generic(); virtual const char *getDefaultName(); virtual bool Connect(); virtual bool Connect(char *); virtual bool Disconnect(); virtual bool ReadScopeStatus(); virtual void ISGetProperties(const char *dev); virtual bool initProperties(); virtual bool updateProperties(); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISSnoopDevice(XMLEle *root); void updateFocusTimer(); void guideTimeout(); static void joystickHelper(const char * joystick_n, double mag, double angle); static void buttonHelper(const char * button_n, ISState state); protected: virtual bool MoveNS(TelescopeMotionNS dir); virtual bool MoveWE(TelescopeMotionWE dir); virtual bool Abort(); virtual bool updateTime(ln_date * utc, double utc_offset); virtual bool updateLocation(double latitude, double longitude, double elevation); virtual bool GuideNorth(float ms); virtual bool GuideSouth(float ms); virtual bool GuideEast(float ms); virtual bool GuideWest(float ms); virtual bool saveConfigItems(FILE *fp); bool Goto(double,double); bool Park(); bool Sync(double ra, double dec); virtual bool canSync(); virtual bool canPark(); virtual void getBasicData(); void slewError(int slewCode); void getAlignment(); void sendScopeTime(); void sendScopeLocation(); void mountSim(); static void updateFocusHelper(void *p); static void guideTimeoutHelper(void *p); void processNSWE(double mag, double angle); void processJoystick(const char * joystick_n, double mag, double angle); void processButton(const char * button_n, ISState state); int GuideNSTID; int GuideWETID; int timeFormat; int currentSiteNum; int trackingMode; long guide_direction; double JD; double targetRA, targetDEC; double currentRA, currentDEC; int MaxReticleFlashRate; INDI::Controller *controller; /* Telescope Alignment Mode */ ISwitchVectorProperty AlignmentSP; ISwitch AlignmentS[3]; /* Slew Speed */ ISwitchVectorProperty SlewModeSP; ISwitch SlewModeS[4]; /* Tracking Mode */ ISwitchVectorProperty TrackModeSP; ISwitch TrackModeS[3]; /* Tracking Frequency */ INumberVectorProperty TrackingFreqNP; INumber TrackFreqN[1]; /* Use pulse-guide commands */ ISwitchVectorProperty UsePulseCmdSP; ISwitch UsePulseCmdS[2]; /* Site Management */ ISwitchVectorProperty SiteSP; ISwitch SiteS[4]; /* Site Name */ ITextVectorProperty SiteNameTP; IText SiteNameT[1]; /* Focus motion */ ISwitchVectorProperty FocusMotionSP; ISwitch FocusMotionS[2]; /* Focus Timer */ INumberVectorProperty FocusTimerNP; INumber FocusTimerN[1]; /* Focus Mode */ ISwitchVectorProperty FocusModeSP; ISwitch FocusModeS[3]; }; #endif libindi-0.9.7/drivers/telescope/lx200classic.h0000644000175000017500000000357212241463551020154 0ustar jasemjasem/* LX200 Classic Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef LX200CLASSIC_H #define LX200CLASSIC_H #include "lx200generic.h" class LX200Classic : public LX200Generic { public: LX200Classic(); ~LX200Classic() {} const char *getDefaultName(); bool initProperties(); void ISGetProperties (const char *dev); bool updateProperties(); bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); protected: ITextVectorProperty ObjectInfoTP; IText ObjectInfoT[1]; ISwitchVectorProperty StarCatalogSP; ISwitch StarCatalogS[3]; ISwitchVectorProperty DeepSkyCatalogSP; ISwitch DeepSkyCatalogS[7]; ISwitchVectorProperty SolarSP; ISwitch SolarS[10]; INumberVectorProperty ObjectNoNP; INumber ObjectNoN[1]; INumberVectorProperty MaxSlewRateNP; INumber MaxSlewRateN[1]; INumberVectorProperty ElevationLimitNP; INumber ElevationLimitN[2]; private: int currentCatalog; int currentSubCatalog; }; #endif libindi-0.9.7/drivers/telescope/lx200_16.cpp0000644000175000017500000002405512241463551017452 0ustar jasemjasem/* LX200 16" Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "lx200_16.h" #include "lx200driver.h" #include #include #include #include #include #define LX16_TAB "GPS/16 inch Features" LX200_16::LX200_16() : LX200GPS() { MaxReticleFlashRate = 3; } const char * LX200_16::getDefaultName() { return (const char *) "LX200 16"; } bool LX200_16::initProperties() { LX200GPS::initProperties(); IUFillSwitch(&FanStatusS[0], "On", "", ISS_OFF); IUFillSwitch(&FanStatusS[1], "Off", "", ISS_OFF); IUFillSwitchVector(&FanStatusSP, FanStatusS, 2, getDeviceName(), "Fan", "", LX16_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&HomeSearchS[0], "Save Home", "", ISS_OFF); IUFillSwitch(&HomeSearchS[1], "Set Home", "", ISS_OFF); IUFillSwitchVector(&HomeSearchSP, HomeSearchS, 2, getDeviceName(), "Home", "", LX16_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&FieldDeRotatorS[0], "On", "", ISS_OFF); IUFillSwitch(&FieldDeRotatorS[1], "Off", "", ISS_OFF); IUFillSwitchVector(&FieldDeRotatorSP, FieldDeRotatorS, 2, getDeviceName(), "Field De-rotater", "", LX16_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillNumber(&HorizontalCoordsN[0], "ALT", "Alt D:M:S", "%10.6m", -90., 90.0, 0.0, 0); IUFillNumber(&HorizontalCoordsN[1], "AZ", "Az D:M:S", "%10.6m", 0.0, 360.0, 0.0, 0); IUFillNumberVector(&HorizontalCoordsNP, HorizontalCoordsN, 2, getDeviceName(), "HORIZONTAL_COORD", "Horizontal Coord", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); } void LX200_16::ISGetProperties (const char *dev) { if(dev && strcmp(dev,getDeviceName())) return; // process parent first LX200GPS::ISGetProperties(dev); if (isConnected()) { defineNumber(&HorizontalCoordsNP); defineSwitch(&FanStatusSP); defineSwitch(&HomeSearchSP); defineSwitch(&FieldDeRotatorSP); } } bool LX200_16::updateProperties() { // process parent first LX200GPS::updateProperties(); if (isConnected()) { defineNumber(&HorizontalCoordsNP); defineSwitch(&FanStatusSP); defineSwitch(&HomeSearchSP); defineSwitch(&FieldDeRotatorSP); } else { deleteProperty(HorizontalCoordsNP.name); deleteProperty(FanStatusSP.name); deleteProperty(HomeSearchSP.name); deleteProperty(FieldDeRotatorSP.name); } } bool LX200_16::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { double newAlt=0, newAz=0; if(strcmp(dev,getDeviceName())==0) { if ( !strcmp (name, HorizontalCoordsNP.name) ) { int i=0, nset=0; for (nset = i = 0; i < n; i++) { INumber *horp = IUFindNumber (&HorizontalCoordsNP, names[i]); if (horp == &HorizontalCoordsN[0]) { newAlt = values[i]; nset += newAlt >= -90. && newAlt <= 90.0; } else if (horp == &HorizontalCoordsN[1]) { newAz = values[i]; nset += newAz >= 0. && newAz <= 360.0; } } if (nset == 2) { if (isSimulation() == false && (setObjAz(PortFD, newAz) < 0 || setObjAlt(PortFD, newAlt) < 0)) { HorizontalCoordsNP.s = IPS_ALERT; IDSetNumber(&HorizontalCoordsNP, "Error setting Alt/Az."); return false; } targetAZ = newAz; targetALT = newAlt; return handleAltAzSlew(); } else { HorizontalCoordsNP.s = IPS_ALERT; IDSetNumber(&HorizontalCoordsNP, "Altitude or Azimuth missing or invalid"); return false; } } } LX200GPS::ISNewNumber (dev, name, values, names, n); } bool LX200_16::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int index; if(strcmp(dev,getDeviceName())==0) { if (!strcmp(name, FanStatusSP.name)) { IUResetSwitch(&FanStatusSP); IUUpdateSwitch(&FanStatusSP, states, names, n); index = IUFindOnSwitchIndex(&FanStatusSP); if (index == 0) { if (turnFanOn(PortFD) < 0) { FanStatusSP.s = IPS_ALERT; IDSetSwitch(&FanStatusSP, "Error changing fan status."); return false; } } else { if (turnFanOff(PortFD) < 0) { FanStatusSP.s = IPS_ALERT; IDSetSwitch(&FanStatusSP, "Error changing fan status."); return false; } } FanStatusSP.s = IPS_OK; IDSetSwitch (&FanStatusSP, index == 0 ? "Fan is ON" : "Fan is OFF"); return true; } if (!strcmp(name, HomeSearchSP.name)) { IUResetSwitch(&HomeSearchSP); IUUpdateSwitch(&HomeSearchSP, states, names, n); index = IUFindOnSwitchIndex(&HomeSearchSP); if (index == 0) seekHomeAndSave(PortFD); else seekHomeAndSet(PortFD); HomeSearchSP.s = IPS_BUSY; IDSetSwitch (&HomeSearchSP, index == 0 ? "Seek Home and Save" : "Seek Home and Set"); return true; } if (!strcmp(name, FieldDeRotatorSP.name)) { IUResetSwitch(&FieldDeRotatorSP); IUUpdateSwitch(&FieldDeRotatorSP, states, names, n); index = IUFindOnSwitchIndex(&FieldDeRotatorSP); if (index == 0) turnFieldDeRotatorOn(PortFD); else turnFieldDeRotatorOff(PortFD); FieldDeRotatorSP.s = IPS_OK; IDSetSwitch (&FieldDeRotatorSP, index == 0 ? "Field deRotator is ON" : "Field deRotator is OFF"); return true; } } return LX200GPS::ISNewSwitch (dev, name, states, names, n); } bool LX200_16::handleAltAzSlew() { char altStr[64], azStr[64]; if (HorizontalCoordsNP.s == IPS_BUSY) { abortSlew(PortFD); // sleep for 100 mseconds usleep(100000); } if (isSimulation() == false && slewToAltAz(PortFD)) { HorizontalCoordsNP.s = IPS_ALERT; IDSetNumber(&HorizontalCoordsNP, "Slew is not possible."); return false; } HorizontalCoordsNP.s = IPS_BUSY; fs_sexa(azStr, targetAZ, 2, 3600); fs_sexa(altStr, targetALT, 2, 3600); TrackState = SCOPE_SLEWING; IDSetNumber(&HorizontalCoordsNP, "Slewing to Alt %s - Az %s", altStr, azStr); return true; } bool LX200_16::ReadScopeStatus() { int searchResult=0; double dx, dy; LX200Generic::ReadScopeStatus(); switch (HomeSearchSP.s) { case IPS_IDLE: break; case IPS_BUSY: if (isSimulation()) searchResult = 1; else if (getHomeSearchStatus(PortFD, &searchResult) < 0) { HomeSearchSP.s = IPS_ALERT; IDSetSwitch(&HomeSearchSP, "Error updating home search status."); return false; } if (searchResult == 0) { HomeSearchSP.s = IPS_ALERT; IDSetSwitch(&HomeSearchSP, "Home search failed."); } else if (searchResult == 1) { HomeSearchSP.s = IPS_OK; IDSetSwitch(&HomeSearchSP, "Home search successful."); } else if (searchResult == 2) IDSetSwitch(&HomeSearchSP, "Home search in progress..."); else { HomeSearchSP.s = IPS_ALERT; IDSetSwitch(&HomeSearchSP, "Home search error."); } break; case IPS_OK: break; case IPS_ALERT: break; } switch (HorizontalCoordsNP.s) { case IPS_IDLE: break; case IPS_BUSY: if (isSimulation()) { currentAZ = targetAZ; currentALT = targetALT; TrackState = SCOPE_TRACKING; return true; } if (getLX200Az(PortFD, ¤tAZ) < 0 || getLX200Alt(PortFD, ¤tALT) < 0) { HorizontalCoordsNP.s = IPS_ALERT; IDSetNumber(&HorizontalCoordsNP, "Error geting Alt/Az."); return false; } dx = targetAZ - currentAZ; dy = targetALT - currentALT; HorizontalCoordsNP.np[0].value = currentALT; HorizontalCoordsNP.np[1].value = currentAZ; // accuracy threshold (3'), can be changed as desired. if ( fabs(dx) <= 0.05 && fabs(dy) <= 0.05) { HorizontalCoordsNP.s = IPS_OK; currentAZ = targetAZ; currentALT = targetALT; IDSetNumber (&HorizontalCoordsNP, "Slew is complete."); } else IDSetNumber (&HorizontalCoordsNP, NULL); break; case IPS_OK: break; case IPS_ALERT: break; } return true; } void LX200_16::getBasicData() { LX200GPS::getBasicData(); if (isSimulation() == false) { getLX200Az(PortFD, ¤tAZ); getLX200Alt(PortFD, ¤tALT); HorizontalCoordsNP.np[0].value = currentALT; HorizontalCoordsNP.np[1].value = currentAZ; IDSetNumber (&HorizontalCoordsNP, NULL); } } libindi-0.9.7/drivers/telescope/lx200classic.cpp0000644000175000017500000002632112241463551020504 0ustar jasemjasem/* LX200 Classoc Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "lx200classic.h" #include "lx200driver.h" #include #include #include #define LIBRARY_TAB "Library" LX200Classic::LX200Classic() : LX200Generic() { currentCatalog = LX200_STAR_C; currentSubCatalog = 0; MaxReticleFlashRate = 3; setVersion(1, 0); } const char * LX200Classic::getDefaultName() { return (const char *) "LX200 Classic"; } bool LX200Classic::initProperties() { LX200Generic::initProperties(); IUFillText(&ObjectInfoT[0], "Info", "", ""); IUFillTextVector(&ObjectInfoTP, ObjectInfoT, 1, getDeviceName(), "Object Info", "", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE); IUFillSwitch(&StarCatalogS[0], "Star", "", ISS_ON); IUFillSwitch(&StarCatalogS[1], "SAO", "", ISS_OFF); IUFillSwitch(&StarCatalogS[2], "GCVS", "", ISS_OFF); IUFillSwitchVector(&StarCatalogSP, StarCatalogS, 3, getDeviceName(), "Star Catalogs", "", LIBRARY_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&DeepSkyCatalogS[0], "NGC", "", ISS_ON); IUFillSwitch(&DeepSkyCatalogS[1], "IC", "", ISS_OFF); IUFillSwitch(&DeepSkyCatalogS[2], "UGC", "", ISS_OFF); IUFillSwitch(&DeepSkyCatalogS[3], "Caldwell", "", ISS_OFF); IUFillSwitch(&DeepSkyCatalogS[4], "Arp", "", ISS_OFF); IUFillSwitch(&DeepSkyCatalogS[5], "Abell", "", ISS_OFF); IUFillSwitch(&DeepSkyCatalogS[6], "Messier", "", ISS_OFF); IUFillSwitchVector(&DeepSkyCatalogSP, DeepSkyCatalogS, 7, getDeviceName(), "Deep Sky Catalogs", "", LIBRARY_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&SolarS[0], "Select", "Select item", ISS_ON); IUFillSwitch(&SolarS[1], "1", "Mercury", ISS_OFF); IUFillSwitch(&SolarS[2], "2", "Venus", ISS_OFF); IUFillSwitch(&SolarS[3], "3", "Moon", ISS_OFF); IUFillSwitch(&SolarS[4], "4", "Mars", ISS_OFF); IUFillSwitch(&SolarS[5], "5", "Jupiter", ISS_OFF); IUFillSwitch(&SolarS[6], "6", "Saturn", ISS_OFF); IUFillSwitch(&SolarS[7], "7", "Uranus", ISS_OFF); IUFillSwitch(&SolarS[8], "8", "Neptune", ISS_OFF); IUFillSwitch(&SolarS[9], "9", "Pluto", ISS_OFF); IUFillSwitchVector(&SolarSP, SolarS, 10, getDeviceName(), "SOLAR_SYSTEM", "Solar System", LIBRARY_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillNumber(&ObjectNoN[0], "ObjectN", "Number", "%+03f", 1.0, 1000.0, 1.0, 0); IUFillNumberVector(&ObjectNoNP, ObjectNoN, 1, getDeviceName(), "Object Number", "", LIBRARY_TAB, IP_RW, 0, IPS_IDLE); IUFillNumber(&MaxSlewRateN[0], "maxSlew", "Rate", "%g", 2.0, 9.0, 1.0, 9.0); IUFillNumberVector(&MaxSlewRateNP, MaxSlewRateN, 1, getDeviceName(), "Max slew Rate", "", MOTION_TAB, IP_RW, 0, IPS_IDLE); IUFillNumber(&ElevationLimitN[0], "minAlt", "Speed", "%%+03f", -90.0, 90.0, 0.0, 0.0); IUFillNumber(&ElevationLimitN[1], "maxAlt", "Speed", "%+03f", -90.0, 90.0, 0.0, 0.0); IUFillNumberVector(&ElevationLimitNP, ElevationLimitN, 1, getDeviceName(), "Slew elevation Limit", "", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); } void LX200Classic::ISGetProperties (const char *dev) { if(dev && strcmp(dev,getDeviceName())) return; LX200Generic::ISGetProperties(dev); if (isConnected()) { defineNumber(&ElevationLimitNP); defineText(&ObjectInfoTP); defineSwitch(&SolarSP); defineSwitch(&StarCatalogSP); defineSwitch(&DeepSkyCatalogSP); defineNumber(&ObjectNoNP); defineNumber(&MaxSlewRateNP); } } bool LX200Classic::updateProperties() { LX200Generic::updateProperties(); if (isConnected()) { defineNumber(&ElevationLimitNP); defineText(&ObjectInfoTP); defineSwitch(&SolarSP); defineSwitch(&StarCatalogSP); defineSwitch(&DeepSkyCatalogSP); defineNumber(&ObjectNoNP); defineNumber(&MaxSlewRateNP); } else { deleteProperty(ElevationLimitNP.name); deleteProperty(ObjectInfoTP.name); deleteProperty(SolarSP.name); deleteProperty(StarCatalogSP.name); deleteProperty(DeepSkyCatalogSP.name); deleteProperty(ObjectNoNP.name); deleteProperty(MaxSlewRateNP.name); } } bool LX200Classic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if ( !strcmp (name, ObjectNoNP.name) ) { char object_name[256]; if (selectCatalogObject(PortFD, currentCatalog, (int) values[0]) < 0) { ObjectNoNP.s = IPS_ALERT; IDSetNumber(&ObjectNoNP, "Failed to select catalog object."); return false; } getLX200RA(PortFD, &targetRA); getLX200DEC(PortFD, &targetDEC); ObjectNoNP.s = IPS_OK; IDSetNumber(&ObjectNoNP , "Object updated."); if (getObjectInfo(PortFD, object_name) < 0) IDMessage(getDeviceName(), "Getting object info failed."); else { IUSaveText(&ObjectInfoTP.tp[0], object_name); IDSetText (&ObjectInfoTP, NULL); } Goto(targetRA, targetDEC); return true; } if ( !strcmp (name, MaxSlewRateNP.name) ) { if ( setMaxSlewRate(PortFD, (int) values[0] < 0) ) { MaxSlewRateNP.s = IPS_ALERT; IDSetNumber(&MaxSlewRateNP, "Error setting maximum slew rate."); return false; } MaxSlewRateNP.s = IPS_OK; MaxSlewRateNP.np[0].value = values[0]; IDSetNumber(&MaxSlewRateNP, NULL); return true; } if (!strcmp (name, ElevationLimitNP.name)) { // new elevation limits double minAlt = 0, maxAlt = 0; int i, nset; for (nset = i = 0; i < n; i++) { INumber *altp = IUFindNumber (&ElevationLimitNP, names[i]); if (altp == &ElevationLimitN[0]) { minAlt = values[i]; nset += minAlt >= -90.0 && minAlt <= 90.0; } else if (altp == &ElevationLimitN[1]) { maxAlt = values[i]; nset += maxAlt >= -90.0 && maxAlt <= 90.0; } } if (nset == 2) { if ( setMinElevationLimit(PortFD, (int) minAlt) < 0) { ElevationLimitNP.s = IPS_ALERT; IDSetNumber(&ElevationLimitNP, "Error setting elevation limit."); return false; } setMaxElevationLimit(PortFD, (int) maxAlt); ElevationLimitNP.np[0].value = minAlt; ElevationLimitNP.np[1].value = maxAlt; ElevationLimitNP.s = IPS_OK; IDSetNumber (&ElevationLimitNP, NULL); return true; } else { ElevationLimitNP.s = IPS_IDLE; IDSetNumber(&ElevationLimitNP, "elevation limit missing or invalid."); return false; } } } return LX200Generic::ISNewNumber (dev, name, values, names, n); } bool LX200Classic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int index=0; if(strcmp(dev,getDeviceName())==0) { // Star Catalog if (!strcmp (name, StarCatalogSP.name)) { IUResetSwitch(&StarCatalogSP); IUUpdateSwitch(&StarCatalogSP, states, names, n); index = IUFindOnSwitchIndex(&StarCatalogSP); currentCatalog = LX200_STAR_C; if (selectSubCatalog(PortFD, currentCatalog, index)) { currentSubCatalog = index; StarCatalogSP.s = IPS_OK; IDSetSwitch(&StarCatalogSP, NULL); return true; } else { StarCatalogSP.s = IPS_IDLE; IDSetSwitch(&StarCatalogSP, "Catalog unavailable."); return false; } } // Deep sky catalog if (!strcmp (name, DeepSkyCatalogSP.name)) { IUResetSwitch(&DeepSkyCatalogSP); IUUpdateSwitch(&DeepSkyCatalogSP, states, names, n); index = IUFindOnSwitchIndex(&DeepSkyCatalogSP); if (index == LX200_MESSIER_C) { currentCatalog = index; DeepSkyCatalogSP.s = IPS_OK; IDSetSwitch(&DeepSkyCatalogSP, NULL); } else currentCatalog = LX200_DEEPSKY_C; if (selectSubCatalog(PortFD, currentCatalog, index)) { currentSubCatalog = index; DeepSkyCatalogSP.s = IPS_OK; IDSetSwitch(&DeepSkyCatalogSP, NULL); } else { DeepSkyCatalogSP.s = IPS_IDLE; IDSetSwitch(&DeepSkyCatalogSP, "Catalog unavailable"); return false; } return true; } // Solar system if (!strcmp (name, SolarSP.name)) { if (IUUpdateSwitch(&SolarSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&SolarSP); // We ignore the first option : "Select item" if (index == 0) { SolarSP.s = IPS_IDLE; IDSetSwitch(&SolarSP, NULL); return true; } selectSubCatalog (PortFD, LX200_STAR_C, LX200_STAR); selectCatalogObject(PortFD, LX200_STAR_C, index + 900); ObjectNoNP.s = IPS_OK; SolarSP.s = IPS_OK; getObjectInfo(PortFD, ObjectInfoTP.tp[0].text); IDSetNumber(&ObjectNoNP , "Object updated."); IDSetSwitch(&SolarSP, NULL); if (currentCatalog == LX200_STAR_C || currentCatalog == LX200_DEEPSKY_C) selectSubCatalog(PortFD, currentCatalog, currentSubCatalog); getObjectRA(PortFD, &targetRA); getObjectDEC(PortFD, &targetDEC); Goto(targetRA, targetDEC); return true; } } return LX200Generic::ISNewSwitch (dev, name, states, names, n); } libindi-0.9.7/drivers/telescope/lx200apdriver.c0000644000175000017500000003212612241463551020337 0ustar jasemjasem#if 0 LX200 Astro-Physics Driver Copyright (C) 2007 Markus Wildi 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 /*ToDo: compare the routes with the new ones from lx200driver.c r111 */ #include #include #include #include #include #include #include #include #include #include "indicom.h" #include "indidevapi.h" #include "lx200driver.h" #include "lx200apdriver.h" #ifndef _WIN32 #include #endif #define LX200_TIMEOUT 5 /* FD timeout in seconds */ int check_lx200ap_connection(int fd) { int i=0; /* char ack[1] = { (char) 0x06 }; does not work for AP moung */ char temp_string[64]; int error_type; int nbytes_write=0; int nbytes_read=0; #ifdef INDI_DEBUG IDLog("Testing telescope's connection using #:GG#...\n"); #endif if (fd <= 0) { #ifdef INDI_DEBUG IDLog("check_lx200ap_connection: not a valid file descriptor received\n"); #endif return -1; } for (i=0; i < 2; i++) { if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK) { #ifdef INDI_DEBUG IDLog("check_lx200ap_connection: unsuccessful write to telescope, %d\n", nbytes_write); #endif return error_type; } error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read) ; tcflush(fd, TCIFLUSH); if (nbytes_read > 1) { temp_string[ nbytes_read -1] = '\0'; #ifdef INDI_DEBUG IDLog("check_lx200ap_connection: received bytes %d, [%s]\n", nbytes_write, temp_string); #endif return 0; } usleep(50000); } #ifdef INDI_DEBUG IDLog("check_lx200ap_connection: wrote, but nothing received\n"); #endif return -1; } int getAPUTCOffset(int fd, double *value) { int error_type; int nbytes_write=0; int nbytes_read=0; char temp_string[16]; if ( (error_type = tty_write_string(fd, "#:GG#", &nbytes_write)) != TTY_OK) return error_type; if(( error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) { #ifdef INDI_DEBUG IDLog("getAPUTCOffset: saying good bye %d, %d\n", error_type, nbytes_read); #endif return error_type ; } tcflush(fd, TCIFLUSH); /* Negative offsets, see AP keypad manual p. 77 */ if((temp_string[0]== 'A') || ((temp_string[0]== '0')&&(temp_string[1]== '0')) ||(temp_string[0]== '@')) { int i ; for( i=nbytes_read; i > 0; i--) { temp_string[i]= temp_string[i-1] ; } temp_string[0] = '-' ; temp_string[nbytes_read + 1] = '\0' ; if( temp_string[1]== 'A') { temp_string[1]= '0' ; switch (temp_string[2]) { case '5': temp_string[2]= '1' ; break ; case '4': temp_string[2]= '2' ; break ; case '3': temp_string[2]= '3' ; break ; case '2': temp_string[2]= '4' ; break ; case '1': temp_string[2]= '5' ; break ; default: #ifdef INDI_DEBUG IDLog("getAPUTCOffset: string not handled %s\n", temp_string); #endif return -1 ; break ; } } else if( temp_string[1]== '0') { temp_string[1]= '0' ; temp_string[2]= '6' ; #ifdef INDI_DEBUG IDLog("getAPUTCOffset: done here %s\n", temp_string); #endif } else if( temp_string[1]== '@') { temp_string[1]= '0' ; switch (temp_string[2]) { case '9': temp_string[2]= '7' ; break ; case '8': temp_string[2]= '8' ; break ; case '7': temp_string[2]= '9' ; break ; case '6': temp_string[2]= '0' ; break ; case '5': temp_string[1]= '1' ; temp_string[2]= '1' ; break ; case '4': temp_string[1]= '1' ; temp_string[2]= '2' ; break ; default: #ifdef INDI_DEBUG IDLog("getAPUTCOffset: string not handled %s\n", temp_string); #endif return -1 ; break; } } else { #ifdef INDI_DEBUG IDLog("getAPUTCOffset: string not handled %s\n", temp_string); #endif } } else { temp_string[nbytes_read - 1] = '\0' ; } /* #ifdef INDI_DEBUG IDLog("getAPUTCOffset: received string %s\n", temp_string); #endif */ if (f_scansexa(temp_string, value)) { fprintf(stderr, "getAPUTCOffset: unable to process [%s]\n", temp_string); return -1; } return 0; } int setAPObjectAZ(int fd, double az) { int h, m, s; char temp_string[16]; getSexComponents(az, &h, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:Sz %03d*%02d:%02d#", h, m, s); #ifdef INDI_DEBUG IDLog("setAPObjectAZ: Set Object AZ String %s\n", temp_string); #endif return (setStandardProcedure(fd, temp_string)); } /* wildi Valid set Values are positive, add error condition */ int setAPObjectAlt(int fd, double alt) { int d, m, s; char temp_string[16]; getSexComponents(alt, &d, &m, &s); /* case with negative zero */ if (!d && alt < 0) { snprintf(temp_string, sizeof( temp_string ), "#:Sa -%02d*%02d:%02d#", d, m, s) ; } else { snprintf(temp_string, sizeof( temp_string ), "#:Sa %+02d*%02d:%02d#", d, m, s) ; } #ifdef INDI_DEBUG IDLog("setAPObjectAlt: Set Object Alt String %s\n", temp_string); #endif return (setStandardProcedure(fd, temp_string)); } int setAPUTCOffset(int fd, double hours) { int h, m, s ; char temp_string[16]; /* To avoid the peculiar output format of AP controller, see p. 77 key pad manual */ if( hours < 0.) { hours += 24. ; } getSexComponents(hours, &h, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d:%02d:%02d#", h, m, s); #ifdef INDI_DEBUG IDLog("setAPUTCOffset: %s\n", temp_string); #endif return (setStandardProcedure(fd, temp_string)); } int APSyncCM(int fd, char *matchedObject) { int error_type; int nbytes_write=0; int nbytes_read=0; #ifdef INDI_DEBUG IDLog("APSyncCM\n"); #endif if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK) return error_type ; if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) return error_type ; matchedObject[nbytes_read-1] = '\0'; /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ usleep(10000); tcflush(fd, TCIFLUSH); return 0; } int APSyncCMR(int fd, char *matchedObject) { int error_type; int nbytes_write=0; int nbytes_read=0; #ifdef INDI_DEBUG IDLog("APSyncCMR\n"); #endif if ( (error_type = tty_write_string(fd, "#:CMR#", &nbytes_write)) != TTY_OK) return error_type; /* read_ret = portRead(matchedObject, -1, LX200_TIMEOUT); */ if(( error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) return error_type ; matchedObject[nbytes_read-1] = '\0'; /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ usleep(10000); tcflush(fd, TCIFLUSH); return 0; } int selectAPMoveToRate(int fd, int moveToRate) { int error_type; int nbytes_write=0; switch (moveToRate) { /* 1200x */ case 0: #ifdef INDI_DEBUG IDLog("selectAPMoveToRate: Setting move to rate to 1200x.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RC3#", &nbytes_write)) != TTY_OK) return error_type; break; /* 600x */ case 1: #ifdef INDI_DEBUG IDLog("selectAPMoveToRate: Setting move to rate to 600x.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RC2#", &nbytes_write)) != TTY_OK) return error_type; break; /* 64x */ case 2: #ifdef INDI_DEBUG IDLog("selectAPMoveToRate: Setting move to rate to 64x.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RC1#", &nbytes_write)) != TTY_OK) return error_type; break; /* 12x*/ case 3: #ifdef INDI_DEBUG IDLog("selectAPMoveToRate: Setting move to rate to 12x.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RC0#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; break; } return 0; } int selectAPSlewRate(int fd, int slewRate) { int error_type; int nbytes_write=0; switch (slewRate) { /* 1200x */ case 0: #ifdef INDI_DEBUG IDLog("selectAPSlewRate: Setting slew rate to 1200x.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RS2#", &nbytes_write)) != TTY_OK) return error_type; break; /* 900x */ case 1: #ifdef INDI_DEBUG IDLog("selectAPSlewRate: Setting slew rate to 900x.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RS1#", &nbytes_write)) != TTY_OK) return error_type; break; /* 600x */ case 2: #ifdef INDI_DEBUG IDLog("selectAPSlewRate: Setting slew rate to 600x.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RS0#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; break; } return 0; } int selectAPTrackingMode(int fd, int trackMode) { int error_type; int nbytes_write=0; switch (trackMode) { /* Lunar */ case 0: #ifdef INDI_DEBUG IDLog("selectAPTrackingMode: Setting tracking mode to lunar.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RT0#", &nbytes_write)) != TTY_OK) return error_type; break; /* Solar */ case 1: #ifdef INDI_DEBUG IDLog("selectAPTrackingMode: Setting tracking mode to solar.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RT1#", &nbytes_write)) != TTY_OK) return error_type; break; /* Sidereal */ case 2: #ifdef INDI_DEBUG IDLog("selectAPTrackingMode: Setting tracking mode to sidereal.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RT2#", &nbytes_write)) != TTY_OK) return error_type; break; /* Zero */ case 3: #ifdef INDI_DEBUG IDLog("selectAPTrackingMode: Setting tracking mode to zero.\n"); #endif if ( (error_type = tty_write_string(fd, "#:RT9#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; break; } return 0; } int swapAPButtons(int fd, int currentSwap) { int error_type; int nbytes_write=0; switch (currentSwap) { case 0: #ifdef INDI_DEBUG IDLog("#:NS#\n"); #endif if ( (error_type = tty_write_string(fd, "#:NS#", &nbytes_write)) != TTY_OK) return error_type; break; case 1: #ifdef INDI_DEBUG IDLog("#:EW#\n"); #endif if ( (error_type = tty_write_string(fd, "#:EW#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; break; } return 0; } int setAPObjectRA(int fd, double ra) { /*ToDo AP accepts "#:Sr %02d:%02d:%02d.%1d#"*/ int h, m, s; char temp_string[16]; getSexComponents(ra, &h, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s); #ifdef INDI_DEBUG IDLog("setAPObjectRA: Set Object RA String %s, %f\n", temp_string, ra); #endif return (setStandardProcedure(fd, temp_string)); } int setAPObjectDEC(int fd, double dec) { int d, m, s; char temp_string[16]; getSexComponents(dec, &d, &m, &s); /* case with negative zero */ if (!d && dec < 0) { snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d:%02d#", d, m, s); } else { snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d*%02d:%02d#", d, m, s); } #ifdef INDI_DEBUG IDLog("setAPObjectDEC: Set Object DEC String %s\n", temp_string) ; #endif return (setStandardProcedure(fd, temp_string)); } int setAPSiteLongitude(int fd, double Long) { int d, m, s; char temp_string[32]; getSexComponents(Long, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:Sg %03d*%02d:%02d#", d, m, s); return (setStandardProcedure(fd, temp_string)); } int setAPSiteLatitude(int fd, double Lat) { int d, m, s; char temp_string[32]; getSexComponents(Lat, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:St %+03d*%02d:%02d#", d, m, s); return (setStandardProcedure(fd, temp_string)); } libindi-0.9.7/drivers/telescope/magellandriver.c0000644000175000017500000001251712241463551020733 0ustar jasemjasem#if 0 MAGELLAN Driver Copyright (C) 2011 Onno Hommes (ohommes@alumni.cmu.edu) 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 #include #include #include #include #include #include #include #include #include "indicom.h" #include "indidevapi.h" #include "magellandriver.h" #ifndef _WIN32 #include #endif /************************************************************************** Connection Diagnostics **************************************************************************/ char ACK(int fd); int check_magellan_connection(int fd); /************************************************************************** Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure **************************************************************************/ /* Get Double from Sexagisemal */ int getCommandSexa(int fd, double *value, const char *cmd); /* Get String */ static int getCommandString(int fd, char *data, const char* cmd); /* Get Calender data */ int getCalenderDate(int fd, char *date); /************************************************************************** Driver Implementations **************************************************************************/ /* Check the Magellan Connection using any set command Magellan 1 does not support any sey but still sends 'OK' for it */ int check_magellan_connection(int fd) { int i=0; /* Magellan I ALways Response OK for :S?# */ char ack[4] = ":S?#"; char Response[64]; int nbytes_read=0; #ifdef INDI_DEBUG IDLog("Testing telescope's connection...\n"); #endif if (fd <= 0) return MAGELLAN_ERROR; for (i=0; i < CONNECTION_RETRIES; i++) { if (write(fd, ack, 4) < 0) return MAGELLAN_ERROR; tty_read(fd, Response, 2, MAGELLAN_TIMEOUT, &nbytes_read); if (nbytes_read == 2) return MAGELLAN_OK; usleep(50000); } tcflush(fd, TCIFLUSH); return MAGELLAN_ERROR; } /********************************************************************** * GET FUNCTIONS **********************************************************************/ char ACK(int fd) { /* Magellan I ALways Response OK for :S?# (any set will do)*/ char ack[4] = ":S?#"; char Response[64]; int nbytes_read=0; int i=0; int result = MAGELLAN_ERROR; /* Check for Comm handle */ if (fd > 0) { for (i=0; i < CONNECTION_RETRIES; i++) { /* Send ACK string to Magellan */ if (write(fd, ack, 4) >= 0) { /* Read Response */ tty_read(fd, Response, 2, MAGELLAN_TIMEOUT, &nbytes_read); /* If the two byte OK is returned we have an Ack */ if (nbytes_read == 2) { result = MAGELLAN_ACK; break; /* Force quick success return */ } else usleep(50000); } } } tcflush(fd, TCIFLUSH); return result; } int getCommandSexa(int fd, double *value, const char * cmd) { char temp_string[16]; int result = MAGELLAN_ERROR; int nbytes_write=0, nbytes_read=0; if ( (tty_write_string(fd, cmd, &nbytes_write)) == TTY_OK) { if ((tty_read_section(fd, temp_string, '#', MAGELLAN_TIMEOUT, &nbytes_read)) == TTY_OK) { temp_string[nbytes_read - 1] = '\0'; if (f_scansexa(temp_string, value)) { #ifdef INDI_DEBUG IDLog("unable to process [%s]\n", temp_string); #endif } else { result = MAGELLAN_OK; } } } tcflush(fd, TCIFLUSH); return result; } static int getCommandString(int fd, char *data, const char* cmd) { int nbytes_write=0, nbytes_read=0; int result = MAGELLAN_ERROR; if ( (tty_write_string(fd, cmd, &nbytes_write)) == TTY_OK) { if ((tty_read_section(fd, data, '#', MAGELLAN_TIMEOUT, &nbytes_read)) == TTY_OK) { data[nbytes_read - 1] = '\0'; result = MAGELLAN_OK; } } tcflush(fd, TCIFLUSH); return result; } int getCalenderDate(int fd, char *date) { int dd, mm, yy; char century[3]; int result; if ( (result = getCommandString(fd, date, "#:GC#")) ) { /* Magellan format is MM/DD/YY */ if ((sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy)) > 2) { /* Consider years 92 or more to be in the last century, anything less in the 21st century.*/ if (yy > CENTURY_THRESHOLD) strncpy(century, "19", 3); else strncpy(century, "20", 3); /* Format must be YYYY/MM/DD format */ snprintf(date, 16, "%s%02d/%02d/%02d", century, yy, mm, dd); } } return result; } libindi-0.9.7/drivers/telescope/lx200basic.cpp0000644000175000017500000006326112241463551020150 0ustar jasemjasem#if 0 LX200 Basic Driver Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include /* INDI Common Library Routines */ #include "indicom.h" /* LX200 Command Set */ #include "lx200driver.h" /* Our driver header */ #include "lx200basic.h" using namespace std; /* Our telescope auto pointer */ auto_ptr telescope(0); const int POLLMS = 1000; // Period of update, 1 second. char *mydev; // Name of our device. const char *BASIC_GROUP = "Main Control"; // Main Group const char *OPTIONS_GROUP = "Options"; // Options Group /* Handy Macros */ #define currentRA EquatorialCoordsRN[0].value #define currentDEC EquatorialCoordsRN[1].value static void ISPoll(void *); static void retry_connection(void *); /************************************************************************************** ** Send client definitions of all properties. ***************************************************************************************/ void ISInit() { static int isInit=0; if (isInit) return; if (telescope.get() == 0) telescope.reset(new LX200Basic()); isInit = 1; IEAddTimer (POLLMS, ISPoll, NULL); } /************************************************************************************** ** ***************************************************************************************/ void ISGetProperties (const char *dev) { ISInit(); telescope->ISGetProperties(dev); } /************************************************************************************** ** ***************************************************************************************/ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); telescope->ISNewSwitch(dev, name, states, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); telescope->ISNewText(dev, name, texts, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); telescope->ISNewNumber(dev, name, values, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISPoll (void *p) { INDI_UNUSED(p); telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); } /************************************************************************************** ** ***************************************************************************************/ void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } /************************************************************************************** ** ***************************************************************************************/ void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } /************************************************************************************** ** LX200 Basic constructor ***************************************************************************************/ LX200Basic::LX200Basic() { mydev = new char[MAXINDIDEVICE]; char *envDev = getenv("INDIDEV"); if (envDev != NULL) strncpy(mydev, envDev, MAXINDIDEVICE); else strncpy(mydev, "LX200 Basic", MAXINDIDEVICE); init_properties(); lastSet = -1; fd = -1; simulation = false; lastRA = 0; lastDEC = 0; currentSet = 0; IDLog("Initializing from LX200 Basic device...\n"); IDLog("Driver Version: 2007-09-28\n"); enable_simulation(false); } /************************************************************************************** ** ***************************************************************************************/ LX200Basic::~LX200Basic() { } /************************************************************************************** ** Initialize all properties & set default values. ***************************************************************************************/ void LX200Basic::init_properties() { // Connection IUFillSwitch(&ConnectS[0], "CONNECT", "Connect", ISS_OFF); IUFillSwitch(&ConnectS[1], "DISCONNECT", "Disconnect", ISS_ON); IUFillSwitchVector(&ConnectSP, ConnectS, NARRAY(ConnectS), mydev, "CONNECTION", "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); // Coord Set IUFillSwitch(&OnCoordSetS[0], "SLEW", "Slew", ISS_ON); IUFillSwitch(&OnCoordSetS[1], "TRACK", "Track", ISS_OFF); IUFillSwitch(&OnCoordSetS[2], "SYNC", "Sync", ISS_OFF); IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); // Abort IUFillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF); IUFillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); // Port IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyS0"); IUFillTextVector(&PortTP, PortT, NARRAY(PortT), mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE); // Object Name IUFillText(&ObjectT[0], "OBJECT_NAME", "Name", "--"); IUFillTextVector(&ObjectTP, ObjectT, NARRAY(ObjectT), mydev, "OBJECT_INFO", "Object", BASIC_GROUP, IP_RW, 0, IPS_IDLE); // Equatorial Coords IUFillNumber(&EquatorialCoordsRN[0], "RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0.); IUFillNumber(&EquatorialCoordsRN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.); IUFillNumberVector(&EquatorialCoordsRNP, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), mydev, "EQUATORIAL_EOD_COORD" , "Equatorial JNow", BASIC_GROUP, IP_RO, 0, IPS_IDLE); // Slew threshold IUFillNumber(&SlewAccuracyN[0], "SlewRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); IUFillNumber(&SlewAccuracyN[1], "SlewDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0); IUFillNumberVector(&SlewAccuracyNP, SlewAccuracyN, NARRAY(SlewAccuracyN), mydev, "Slew Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE); // Track threshold IUFillNumber(&TrackAccuracyN[0], "TrackRA", "RA (arcmin)", "%10.6m", 0., 60., 1., 3.0); IUFillNumber(&TrackAccuracyN[1], "TrackDEC", "Dec (arcmin)", "%10.6m", 0., 60., 1., 3.0); IUFillNumberVector(&TrackAccuracyNP, TrackAccuracyN, NARRAY(TrackAccuracyN), mydev, "Tracking Accuracy", "", OPTIONS_GROUP, IP_RW, 0, IPS_IDLE); } /************************************************************************************** ** Define LX200 Basic properties to clients. ***************************************************************************************/ void LX200Basic::ISGetProperties(const char *dev) { if (dev && strcmp (mydev, dev)) return; // Main Control IDDefSwitch(&ConnectSP, NULL); IDDefText(&PortTP, NULL); IDDefText(&ObjectTP, NULL); IDDefNumber(&EquatorialCoordsRNP, NULL); IDDefSwitch(&OnCoordSetSP, NULL); IDDefSwitch(&AbortSlewSP, NULL); // Options IDDefNumber(&SlewAccuracyNP, NULL); IDDefNumber(&TrackAccuracyNP, NULL); } /************************************************************************************** ** Process Text properties ***************************************************************************************/ void LX200Basic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // Ignore if not ours if (strcmp (dev, mydev)) return; // =================================== // Port Name // =================================== if (!strcmp(name, PortTP.name) ) { if (IUUpdateText(&PortTP, texts, names, n) < 0) return; PortTP.s = IPS_OK; IDSetText (&PortTP, NULL); return; } if (is_connected() == false) { IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands."); reset_all_properties(); return; } // =================================== // Object Name // =================================== if (!strcmp (name, ObjectTP.name)) { if (IUUpdateText(&ObjectTP, texts, names, n) < 0) return; ObjectTP.s = IPS_OK; IDSetText(&ObjectTP, NULL); return; } } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // Ignore if not ours if (strcmp (dev, mydev)) return; if (is_connected() == false) { IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands."); reset_all_properties(); return; } // =================================== // Equatorial Coords // =================================== if (!strcmp (name, EquatorialCoordsRNP.name)) { int i=0, nset=0, error_code=0; double newRA =0, newDEC =0; for (nset = i = 0; i < n; i++) { INumber *eqp = IUFindNumber (&EquatorialCoordsRNP, names[i]); if (eqp == &EquatorialCoordsRN[0]) { newRA = values[i]; nset += newRA >= 0 && newRA <= 24.0; } else if (eqp == &EquatorialCoordsRN[1]) { newDEC = values[i]; nset += newDEC >= -90.0 && newDEC <= 90.0; } } if (nset == 2) { char RAStr[32], DecStr[32]; fs_sexa(RAStr, newRA, 2, 3600); fs_sexa(DecStr, newDEC, 2, 3600); #ifdef INDI_DEBUG IDLog("We received JNow RA %g - DEC %g\n", newRA, newDEC); IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr); #endif if (!simulation && ( (error_code = setObjectRA(fd, newRA)) < 0 || ( error_code = setObjectDEC(fd, newDEC)) < 0)) { handle_error(&EquatorialCoordsRNP, error_code, "Setting RA/DEC"); return; } targetRA = newRA; targetDEC = newDEC; if (process_coords() == false) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, NULL); } } // end nset else { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, "RA or Dec missing or invalid"); } return; } /* end EquatorialCoordsWNP */ // =================================== // Update tracking precision limits // =================================== if (!strcmp (name, TrackAccuracyNP.name)) { if (IUUpdateNumber(&TrackAccuracyNP, values, names, n) < 0) return; TrackAccuracyNP.s = IPS_OK; if (TrackAccuracyN[0].value < 3 || TrackAccuracyN[1].value < 3) IDSetNumber(&TrackAccuracyNP, "Warning: Setting the tracking accuracy too low may result in a dead lock"); else IDSetNumber(&TrackAccuracyNP, NULL); return; } // =================================== // Update slew precision limit // =================================== if (!strcmp(name, SlewAccuracyNP.name)) { if (IUUpdateNumber(&SlewAccuracyNP, values, names, n) < 0) return; SlewAccuracyNP.s = IPS_OK; if (SlewAccuracyN[0].value < 3 || SlewAccuracyN[1].value < 3) IDSetNumber(&TrackAccuracyNP, "Warning: Setting the slew accuracy too low may result in a dead lock"); IDSetNumber(&SlewAccuracyNP, NULL); return; } } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { // ignore if not ours // if (strcmp (mydev, dev)) return; // =================================== // Connect Switch // =================================== if (!strcmp (name, ConnectSP.name)) { if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return; connect_telescope(); return; } if (is_connected() == false) { IDMessage(mydev, "LX200 Basic is offline. Please connect before issuing any commands."); reset_all_properties(); return; } // =================================== // Coordinate Set // =================================== if (!strcmp(name, OnCoordSetSP.name)) { if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return; currentSet = get_switch_index(&OnCoordSetSP); OnCoordSetSP.s = IPS_OK; IDSetSwitch(&OnCoordSetSP, NULL); } // =================================== // Abort slew // =================================== if (!strcmp (name, AbortSlewSP.name)) { IUResetSwitch(&AbortSlewSP); abortSlew(fd); if (EquatorialCoordsRNP.s == IPS_BUSY) { AbortSlewSP.s = IPS_OK; EquatorialCoordsRNP.s = IPS_IDLE; IDSetSwitch(&AbortSlewSP, "Slew aborted."); IDSetNumber(&EquatorialCoordsRNP, NULL); } return; } } /************************************************************************************** ** Retry connecting to the telescope on error. Give up if there is no hope. ***************************************************************************************/ void LX200Basic::handle_error(INumberVectorProperty *nvp, int err, const char *msg) { nvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_lx200_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetNumber(nvp, NULL); IEAddTimer(10000, retry_connection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { nvp->s = IPS_ALERT; IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetNumber( nvp , "%s failed.", msg); fault = true; } /************************************************************************************** ** Set all properties to idle and reset most switches to clean state. ***************************************************************************************/ void LX200Basic::reset_all_properties() { ConnectSP.s = IPS_IDLE; OnCoordSetSP.s = IPS_IDLE; AbortSlewSP.s = IPS_IDLE; PortTP.s = IPS_IDLE; ObjectTP.s = IPS_IDLE; EquatorialCoordsRNP.s = IPS_IDLE; SlewAccuracyNP.s = IPS_IDLE; TrackAccuracyNP.s = IPS_IDLE; IUResetSwitch(&OnCoordSetSP); IUResetSwitch(&AbortSlewSP); OnCoordSetS[0].s = ISS_ON; ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch(&ConnectSP, NULL); IDSetSwitch(&OnCoordSetSP, NULL); IDSetSwitch(&AbortSlewSP, NULL); IDSetText(&PortTP, NULL); IDSetText(&ObjectTP, NULL); IDSetNumber(&EquatorialCoordsRNP, NULL); IDSetNumber(&SlewAccuracyNP, NULL); IDSetNumber(&TrackAccuracyNP, NULL); } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::correct_fault() { fault = false; IDMessage(mydev, "Telescope is online."); } /************************************************************************************** ** ***************************************************************************************/ bool LX200Basic::is_connected() { if (simulation) return true; return (ConnectSP.sp[0].s == ISS_ON); } /************************************************************************************** ** ***************************************************************************************/ static void retry_connection(void * p) { int fd = *((int *) p); if (check_lx200_connection(fd)) telescope->connection_lost(); else telescope->connection_resumed(); } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::ISPoll() { if (is_connected() == false || simulation) return; double dx, dy; int error_code=0; switch (EquatorialCoordsRNP.s) { case IPS_IDLE: getLX200RA(fd, ¤tRA); getLX200DEC(fd, ¤tDEC); // Only update values if there are some interesting changes if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01) { lastRA = currentRA; lastDEC = currentDEC; IDSetNumber (&EquatorialCoordsRNP, NULL); } break; case IPS_BUSY: getLX200RA(fd, ¤tRA); getLX200DEC(fd, ¤tDEC); dx = targetRA - currentRA; dy = targetDEC - currentDEC; // Wait until acknowledged or within threshold if ( fabs(dx) <= (SlewAccuracyN[0].value/(900.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0)) { lastRA = currentRA; lastDEC = currentDEC; IUResetSwitch(&OnCoordSetSP); OnCoordSetSP.s = IPS_OK; EquatorialCoordsRNP.s = IPS_OK; IDSetNumber (&EquatorialCoordsRNP, NULL); switch (currentSet) { case LX200_SLEW: OnCoordSetSP.sp[LX200_SLEW].s = ISS_ON; IDSetSwitch (&OnCoordSetSP, "Slew is complete."); break; case LX200_TRACK: OnCoordSetSP.sp[LX200_TRACK].s = ISS_ON; IDSetSwitch (&OnCoordSetSP, "Slew is complete. Tracking..."); break; case LX200_SYNC: break; } } else IDSetNumber (&EquatorialCoordsRNP, NULL); break; case IPS_OK: if ( (error_code = getLX200RA(fd, ¤tRA)) < 0 || (error_code = getLX200DEC(fd, ¤tDEC)) < 0) { handle_error(&EquatorialCoordsRNP, error_code, "Getting RA/DEC"); return; } if (fault == true) correct_fault(); if ( (currentRA != lastRA) || (currentDEC != lastDEC)) { lastRA = currentRA; lastDEC = currentDEC; IDSetNumber (&EquatorialCoordsRNP, NULL); } break; case IPS_ALERT: break; } } /************************************************************************************** ** ***************************************************************************************/ bool LX200Basic::process_coords() { int error_code; char syncString[256]; char RAStr[32], DecStr[32]; double dx, dy; switch (currentSet) { // Slew case LX200_SLEW: lastSet = LX200_SLEW; if (EquatorialCoordsRNP.s == IPS_BUSY) { IDLog("Aborting Slew\n"); abortSlew(fd); // sleep for 100 mseconds usleep(100000); } if ( !simulation && (error_code = Slew(fd))) { slew_error(error_code); return false; } EquatorialCoordsRNP.s = IPS_BUSY; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); break; // Track case LX200_TRACK: //IDLog("We're in LX200_TRACK\n"); if (EquatorialCoordsRNP.s == IPS_BUSY) { IDLog("Aborting Slew\n"); abortSlew(fd); // sleep for 200 mseconds usleep(200000); } dx = fabs ( targetRA - currentRA ); dy = fabs (targetDEC - currentDEC); if (dx >= (TrackAccuracyN[0].value/(60.0*15.0)) || (dy >= TrackAccuracyN[1].value/60.0)) { if ( !simulation && (error_code = Slew(fd))) { slew_error(error_code); return false; } fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); EquatorialCoordsRNP.s = IPS_BUSY; IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); } else { //IDLog("Tracking called, but tracking threshold not reached yet.\n"); EquatorialCoordsRNP.s = IPS_OK; if (lastSet != LX200_TRACK) IDSetNumber(&EquatorialCoordsRNP, "Tracking..."); else IDSetNumber(&EquatorialCoordsRNP, NULL); } lastSet = LX200_TRACK; break; // Sync case LX200_SYNC: lastSet = LX200_SYNC; EquatorialCoordsRNP.s = IPS_IDLE; if ( !simulation && ( error_code = Sync(fd, syncString) < 0) ) { IDSetNumber( &EquatorialCoordsRNP , "Synchronization failed."); return false; } if (simulation) { EquatorialCoordsRN[0].value = EquatorialCoordsRN[0].value; EquatorialCoordsRN[1].value = EquatorialCoordsRN[1].value; } EquatorialCoordsRNP.s = IPS_OK; IDLog("Synchronization successful %s\n", syncString); IDSetNumber(&EquatorialCoordsRNP, "Synchronization successful."); break; } return true; } /************************************************************************************** ** ***************************************************************************************/ int LX200Basic::get_switch_index(ISwitchVectorProperty *sp) { for (int i=0; i < sp->nsp ; i++) if (sp->sp[i].s == ISS_ON) return i; return -1; } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::connect_telescope() { switch (ConnectSP.sp[0].s) { case ISS_ON: if (simulation) { ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Simulated telescope is online."); return; } if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.", PortT[0].text); return; } if (check_lx200_connection(fd)) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); return; } ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); get_initial_data(); break; case ISS_OFF: ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_IDLE; if (simulation) { IDSetSwitch (&ConnectSP, "Simulated Telescope is offline."); return; } IDSetSwitch (&ConnectSP, "Telescope is offline."); IDLog("Telescope is offline."); tty_disconnect(fd); break; } } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::get_initial_data() { // Make sure short checkLX200Format(fd); // Get current RA/DEC getLX200RA(fd, ¤tRA); getLX200DEC(fd, ¤tDEC); IDSetNumber (&EquatorialCoordsRNP, NULL); } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::slew_error(int slewCode) { OnCoordSetSP.s = IPS_IDLE; if (slewCode == 1) IDSetSwitch (&OnCoordSetSP, "Object below horizon."); else if (slewCode == 2) IDSetSwitch (&OnCoordSetSP, "Object below the minimum elevation limit."); else IDSetSwitch (&OnCoordSetSP, "Slew failed."); } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::enable_simulation(bool enable) { simulation = enable; if (simulation) IDLog("Warning: Simulation is activated.\n"); else IDLog("Simulation is disabled.\n"); } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::connection_lost() { ConnectSP.s = IPS_IDLE; IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); return; } /************************************************************************************** ** ***************************************************************************************/ void LX200Basic::connection_resumed() { ConnectS[0].s = ISS_ON; ConnectS[1].s = ISS_OFF; ConnectSP.s = IPS_OK; IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); } libindi-0.9.7/drivers/telescope/lx200fs2.cpp0000755000175000017500000002451612241463551017564 0ustar jasemjasem#if 0 LX200 FS2 Driver Copyright (C) 2009 Ferran Casarramona (ferran.casarramona@gmail.com) Based on LX200 driver from: Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 /* LX200 Command Set */ #include "lx200driver.h" /* Our driver header */ #include "lx200fs2.h" using namespace std; /* Our telescope auto pointer */ extern LX200GenericLegacy *telescope; // Access to properties defined in LX200GenericLegacy extern ISwitchVectorProperty ConnectSP; extern ITextVectorProperty PortTP; const char *BASIC_GROUP = "Main Control"; // Main Group const char *OPTIONS_GROUP = "Options"; // Options Group const char *MOTION_GROUP = "Motion Control"; /* Handy Macros */ #define currentRA EquatorialCoordsRN[0].value #define currentDEC EquatorialCoordsRN[1].value static void retryConnection(void *); void changeLX200FS2DeviceName(const char *newName) { } /************************************************************************************** ** LX200 FS2 constructor ***************************************************************************************/ LX200Fs2::LX200Fs2() : LX200GenericLegacy() { DeviceName = "LX200 FS2"; init_properties(); IDLog("Initializing from LX200 FS2 device...\n"); IDLog("Driver Version: 2012-07-22\n"); //enableSimulation(true); } /************************************************************************************** ** ***************************************************************************************/ LX200Fs2::~LX200Fs2() { } /************************************************************************************** ** Initialize all properties & set default values. ***************************************************************************************/ void LX200Fs2::init_properties() { // Firmware Version IUFillNumber(&FirmwareVerN[0], "FirmwareVer", "Firmware version", "%2.2f", 1.16, 1.25, 0.01, 1.18); IUFillNumberVector(&FirmwareVerNP, FirmwareVerN, NARRAY(FirmwareVerN), DeviceName, "FIRMWARE_VER" , "Firmware", BASIC_GROUP, IP_RW, 0, IPS_IDLE); } /************************************************************************************** ** Define LX200 FS2 properties to clients. ***************************************************************************************/ void LX200Fs2::ISGetProperties(const char *dev) { if (dev && strcmp (DeviceName, dev)) return; LX200GenericLegacy::ISGetProperties(dev); // Delete not supported properties IDDelete(DeviceName, "Alignment", NULL); IDDelete(DeviceName, "Tracking Mode", NULL); IDDelete(DeviceName, "Tracking Frequency", NULL); // Focus IDDelete(DeviceName, "FOCUS_MOTION", NULL); IDDelete(DeviceName, "FOCUS_TIMER", NULL); IDDelete(DeviceName, "FOCUS_MODE", NULL); // Time IDDelete(DeviceName, "TIME_UTC", NULL); IDDelete(DeviceName, "TIME_UTC_OFFSET", NULL); IDDelete(DeviceName, "TIME_LST", NULL); // Sites IDDelete(DeviceName, "Sites", NULL); IDDelete(DeviceName, "Site Name", NULL); IDDefNumber(&FirmwareVerNP, NULL); } /************************************************************************************** ** ***************************************************************************************/ void LX200Fs2::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // Ignore if not ours if (strcmp (dev, DeviceName)) return; // =================================== // Update Firmware version // =================================== if (!strcmp (name, FirmwareVerNP.name)) { if (IUUpdateNumber(&FirmwareVerNP, values, names, n) < 0) return; FirmwareVerNP.s = IPS_OK; IDSetNumber(&FirmwareVerNP, NULL); return; } LX200GenericLegacy::ISNewNumber (dev, name, values, names, n); } /************************************************************************************** ** ***************************************************************************************/ int LX200Fs2::check_fs2_connection(int fd) { double x; if (FirmwareVerNP.np[0].value < 1.19) { getLX200RA(fd, &x); return getLX200DEC(fd, &x); // Version 1.18 and below don't support ACK command } else return check_lx200_connection(fd); } /************************************************************************************** ** ***************************************************************************************/ void LX200Fs2::connectTelescope() { switch (ConnectSP.sp[0].s) { case ISS_ON: fprintf (stderr, "Trace: LX200FS2 connectTelescope ON"); if (simulation) { ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Simulated telescope is online."); return; } if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) { ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.", PortTP.tp[0].text); return; } if (check_fs2_connection(fd)) { ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); return; } ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); getBasicData(); break; case ISS_OFF: ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; ConnectSP.s = IPS_IDLE; if (simulation) { IDSetSwitch (&ConnectSP, "Simulated Telescope is offline."); return; } IDSetSwitch (&ConnectSP, "Telescope is offline."); IDLog("Telescope is offline."); tty_disconnect(fd); break; } } /************************************************************************************** ** ***************************************************************************************/ void LX200Fs2::getBasicData() { //LX200GenericLegacy::getBasicData() // Make sure short //checkLX200Format(fd); // Get current RA/DEC //getLX200RA(fd, ¤tRA); //getLX200DEC(fd, ¤tDEC); //IDSetNumber (&EquatorialCoordsRNP, NULL); } /********************************************************************************** ** handleError functions. Redefined because they call check_lx200_connection and this ** driver needs to call check_fs2_connection **************************************************************************************/ static void retryConnection(void * p) { int fd = *((int *) p); if (((LX200Fs2 *)telescope)->check_fs2_connection(fd)) { ConnectSP.s = IPS_IDLE; IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); return; } ConnectSP.sp[0].s = ISS_ON; ConnectSP.sp[1].s = ISS_OFF; ConnectSP.s = IPS_OK; IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); } void LX200Fs2::handleError(ISwitchVectorProperty *svp, int err, const char *msg) { svp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_fs2_connection(fd)) { /* The telescope is off locally */ ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetSwitch(svp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property or busy*/ if (err == -2) { svp->s = IPS_ALERT; IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetSwitch( svp , "%s failed.", msg); fault = true; } void LX200Fs2::handleError(INumberVectorProperty *nvp, int err, const char *msg) { nvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_fs2_connection(fd)) { /* The telescope is off locally */ ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetNumber(nvp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { nvp->s = IPS_ALERT; IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetNumber( nvp , "%s failed.", msg); fault = true; } void LX200Fs2::handleError(ITextVectorProperty *tvp, int err, const char *msg) { tvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_fs2_connection(fd)) { /* The telescope is off locally */ ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetText(tvp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { tvp->s = IPS_ALERT; IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetText( tvp , "%s failed.", msg); fault = true; } libindi-0.9.7/drivers/telescope/ieq45driver8406.c0000644000175000017500000011122712241463551020422 0ustar jasemjasem#if 0 IEQ45 Driver Copyright (C) 2011 Nacho Mas (mas.ignacio@gmail.com). Only litle changes from lx200basic made it by Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include #include "indicom.h" #include "indidevapi.h" #include "ieq45driver.h" #ifndef _WIN32 #include #endif #define IEQ45_TIMEOUT 5 /* FD timeout in seconds */ int controller_format; /************************************************************************** Diagnostics **************************************************************************/ int check_IEQ45_connection(int fd); /************************************************************************** Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure **************************************************************************/ /* Get Double from Sexagisemal */ int getCommandSexa(int fd, double *value, const char *cmd); /* Get String */ int getCommandString(int fd, char *data, const char* cmd); /* Get Int */ int getCommandInt(int fd, int *value, const char* cmd); /* Get tracking frequency */ int getTrackFreq(int fd, double * value); /* Get site Latitude */ int getSiteLatitude(int fd, int *dd, int *mm); /* Get site Longitude */ int getSiteLongitude(int fd, int *ddd, int *mm); /* Get Calender data */ int getCalenderDate(int fd, char *date); /* Get site Name */ int getSiteName(int fd, char *siteName, int siteNum); /* Get Number of Bars */ int getNumberOfBars(int fd, int *value); /* Get Home Search Status */ int getHomeSearchStatus(int fd, int *status); /* Get OTA Temperature */ int getOTATemp(int fd, double * value); /* Get time format: 12 or 24 */ int getTimeFormat(int fd, int *format); /************************************************************************** Set Commands **************************************************************************/ /* Set Int */ int setCommandInt(int fd, int data, const char *cmd); /* Set Sexigesimal */ int setCommandXYZ(int fd, int x, int y, int z, const char *cmd); /* Common routine for Set commands */ int setStandardProcedure(int fd, char * writeData); /* Set Slew Mode */ int setSlewMode(int fd, int slewMode); /* Set Alignment mode */ int setAlignmentMode(int fd, unsigned int alignMode); /* Set Object RA */ int setObjectRA(int fd, double ra); /* set Object DEC */ int setObjectDEC(int fd, double dec); /* Set Calender date */ int setCalenderDate(int fd, int dd, int mm, int yy); /* Set UTC offset */ int setUTCOffset(int fd, double hours); /* Set Track Freq */ int setTrackFreq(int fd, double trackF); /* Set current site longitude */ int setSiteLongitude(int fd, double Long); /* Set current site latitude */ int setSiteLatitude(int fd, double Lat); /* Set Object Azimuth */ int setObjAz(int fd, double az); /* Set Object Altitude */ int setObjAlt(int fd, double alt); /* Set site name */ int setSiteName(int fd, char * siteName, int siteNum); /* Set maximum slew rate */ int setMaxSlewRate(int fd, int slewRate); /* Set focuser motion */ int setFocuserMotion(int fd, int motionType); /* Set focuser speed mode */ int setFocuserSpeedMode (int fd, int speedMode); /* Set minimum elevation limit */ int setMinElevationLimit(int fd, int min); /* Set maximum elevation limit */ int setMaxElevationLimit(int fd, int max); /************************************************************************** Motion Commands **************************************************************************/ /* Slew to the selected coordinates */ int Slew(int fd); /* Synchronize to the selected coordinates and return the matching object if any */ int Sync(int fd, char *matchedObject); /* Abort slew in all axes */ 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 */ 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 **************************************************************************/ /* Ensures IEQ45 RA/DEC format is long */ int checkIEQ45Format(int fd); /* Select a site from the IEQ45 controller */ int selectSite(int fd, int siteNum); /* Select a catalog object */ int selectCatalogObject(int fd, int catalog, int NNNN); /* Select a sub catalog */ int selectSubCatalog(int fd, int catalog, int subCatalog); int check_IEQ45_connection(int in_fd) { int i=0; char firmwareDate[14] = ":FirmWareDate#"; char MountAlign[64]; int nbytes_read=0; #ifdef INDI_DEBUG IDLog("Testing telescope's connection using FirmwareDate command...\n"); #endif if (in_fd <= 0) return -1; for (i=0; i < 2; i++) { if (write(in_fd, firmwareDate, 14) < 0) return -1; tty_read(in_fd, MountAlign, 1, IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read == 1) return 0; usleep(50000); } return -1; } /********************************************************************** * GET **********************************************************************/ void remove_spaces(char *texto_recibe) { char *texto_sin_espacio; for (texto_sin_espacio = texto_recibe; *texto_recibe; texto_recibe++) { if (isspace(*texto_recibe)) continue; *texto_sin_espacio++ = *texto_recibe; } *texto_sin_espacio = '\0'; } int getCommandSexa(int fd, double *value, const char * cmd) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; tcflush(fd, TCIFLUSH); if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; /*if ( (read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT)) < 1) return read_ret;*/ tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); temp_string[nbytes_read - 1] = '\0'; /*IDLog("getComandSexa: %s\n", temp_string);*/ //IEQ45 sometimes send a malformed RA/DEC (intermediate spaces) //so I clean before: remove_spaces(temp_string); if (f_scansexa(temp_string, value)) { #ifdef INDI_DEBUG IDLog("unable to process [%s]\n", temp_string); #endif return -1; } tcflush(fd, TCIFLUSH); return 0; } int getCommandInt(int fd, int *value, const char* cmd) { char temp_string[16]; float temp_number; int error_type; int nbytes_write=0, nbytes_read=0; tcflush(fd, TCIFLUSH); if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); temp_string[nbytes_read - 1] = '\0'; /* Float */ if (strchr(temp_string, '.')) { if (sscanf(temp_string, "%f", &temp_number) != 1) return -1; *value = (int) temp_number; } /* Int */ else if (sscanf(temp_string, "%d", value) != 1) return -1; return 0; } int getCommandString(int fd, char *data, const char* cmd) { char * term; int error_type; int nbytes_write=0, nbytes_read=0; /*if (portWrite(cmd) < 0) return -1;*/ if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(data, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, data, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (error_type != TTY_OK) return error_type; term = strchr (data, '#'); if (term) *term = '\0'; #ifdef INDI_DEBUG /*IDLog("Requested data: %s\n", data);*/ #endif return 0; } int getCalenderDate(int fd, char *date) { int dd, mm, yy; int error_type; int nbytes_read=0; char mell_prefix[3]; if ( (error_type = getCommandString(fd, date, ":GC#")) ) return error_type; /* Meade format is MM/DD/YY */ nbytes_read = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy); if (nbytes_read < 3) return -1; /* We consider years 50 or more to be in the last century, anything less in the 21st century.*/ if (yy > 50) strncpy(mell_prefix, "19", 3); else strncpy(mell_prefix, "20", 3); /* We need to have in in YYYY/MM/DD format */ snprintf(date, 16, "%s%02d/%02d/%02d", mell_prefix, yy, mm, dd); return (0); } int getTimeFormat(int fd, int *format) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; int tMode; /*if (portWrite(":Gc#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Gc#", &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ if ( (error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read)) != TTY_OK) return error_type; tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read-1] = '\0'; nbytes_read = sscanf(temp_string, "(%d)", &tMode); if (nbytes_read < 1) return -1; else *format = tMode; return 0; } int getSiteName(int fd, char *siteName, int siteNum) { char * term; int error_type; int nbytes_write=0, nbytes_read=0; switch (siteNum) { case 1: /*if (portWrite(":GM#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GM#", &nbytes_write)) != TTY_OK) return error_type; break; case 2: /*if (portWrite(":GN#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GN#", &nbytes_write)) != TTY_OK) return error_type; break; case 3: /*if (portWrite(":GO#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GO#", &nbytes_write)) != TTY_OK) return error_type; break; case 4: /*if (portWrite(":GP#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":GP#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; } /*read_ret = portRead(siteName, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, siteName, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; siteName[nbytes_read - 1] = '\0'; term = strchr (siteName, ' '); if (term) *term = '\0'; term = strchr (siteName, '<'); if (term) strcpy(siteName, "unused site"); #ifdef INDI_DEBUG IDLog("Requested site name: %s\n", siteName); #endif return 0; } int getSiteLatitude(int fd, int *dd, int *mm) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; /*if (portWrite(":Gt#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Gt#", &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read -1] = '\0'; if (sscanf (temp_string, "%d%*c%d", dd, mm) < 2) return -1; #ifdef INDI_DEBUG fprintf(stderr, "Requested site latitude in String %s\n", temp_string); fprintf(stderr, "Requested site latitude %d:%d\n", *dd, *mm); #endif return 0; } int getSiteLongitude(int fd, int *ddd, int *mm) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":Gg#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":Gg#") < 0) return -1;*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read -1] = '\0'; if (sscanf (temp_string, "%d%*c%d", ddd, mm) < 2) return -1; #ifdef INDI_DEBUG fprintf(stderr, "Requested site longitude in String %s\n", temp_string); fprintf(stderr, "Requested site longitude %d:%d\n", *ddd, *mm); #endif return 0; } int getTrackFreq(int fd, double *value) { float Freq; char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":GT#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":GT#") < 0) return -1;*/ /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read] = '\0'; /*fprintf(stderr, "Telescope tracking freq str: %s\n", temp_string);*/ if (sscanf(temp_string, "%f#", &Freq) < 1) return -1; *value = (double) Freq; #ifdef INDI_DEBUG fprintf(stderr, "Tracking frequency value is %f\n", Freq); #endif return 0; } int getNumberOfBars(int fd, int *value) { char temp_string[128]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":D#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":D#") < 0) return -1;*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 0) return error_type; *value = nbytes_read -1; return 0; } int getHomeSearchStatus(int fd, int *status) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":h?#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":h?#") < 0) return -1;*/ /*read_ret = portRead(temp_string, 1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[1] = '\0'; if (temp_string[0] == '0') *status = 0; else if (temp_string[0] == '1') *status = 1; else if (temp_string[0] == '2') *status = 1; return 0; } int getOTATemp(int fd, double *value) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; float temp; if ( (error_type = tty_write_string(fd, ":fT#", &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; temp_string[nbytes_read - 1] = '\0'; if (sscanf(temp_string, "%f", &temp) < 1) return -1; *value = (double) temp; return 0; } int updateSkyCommanderCoord(int fd, double *ra, double *dec) { char coords[16]; char CR[1] = { (char) 0x0D }; float RA=0.0, DEC=0.0; int error_type; int nbytes_read=0; error_type = write(fd, CR, 1); error_type = tty_read(fd, coords, 16, IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead(coords, 16, IEQ45_TIMEOUT);*/ tcflush(fd, TCIFLUSH); nbytes_read = sscanf(coords, " %g %g", &RA, &DEC); if (nbytes_read < 2) { #ifdef INDI_DEBUG IDLog("Error in Sky commander number format [%s], exiting.\n", coords); #endif return error_type; } *ra = RA; *dec = DEC; return 0; } int updateIntelliscopeCoord (int fd, double *ra, double *dec) { char coords[16]; char CR[1] = { (char) 0x51 }; /* "Q" */ float RA = 0.0, DEC = 0.0; int error_type; int nbytes_read=0; /*IDLog ("Sending a Q\n");*/ error_type = write (fd, CR, 1); /* We start at 14 bytes in case its a Sky Wizard, but read one more later it if it's a intelliscope */ /*read_ret = portRead (coords, 14, IEQ45_TIMEOUT);*/ error_type = tty_read(fd, coords, 14, IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); /*IDLog ("portRead() = [%s]\n", coords);*/ /* Remove the Q in the response from the Intelliscope but not the Sky Wizard */ if (coords[0] == 'Q') { coords[0] = ' '; /* Read one more byte if Intelliscope to get the "CR" */ error_type = tty_read(fd, coords, 1, IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead (coords, 1, IEQ45_TIMEOUT);*/ } nbytes_read = sscanf (coords, " %g %g", &RA, &DEC); /*IDLog ("sscanf() RA = [%f]\n", RA * 0.0390625);*/ /*IDLog ("sscanf() DEC = [%f]\n", DEC * 0.0390625);*/ /*IDLog ("Intelliscope output [%s]", coords);*/ if (nbytes_read < 2) { #ifdef INDI_DEBUG IDLog ("Error in Intelliscope number format [%s], exiting.\n", coords); #endif return -1; } *ra = RA * 0.0390625; *dec = DEC * 0.0390625; return 0; } /********************************************************************** * SET **********************************************************************/ int setStandardProcedure(int fd, char * data) { char bool_return[2]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read(fd, bool_return, 1, IEQ45_TIMEOUT, &nbytes_read); /*read_ret = portRead(boolRet, 1, IEQ45_TIMEOUT);*/ tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; if (bool_return[0] == '0') { #ifdef INDI_DEBUG IDLog("%s Failed.\n", data); #endif return -1; } #ifdef INDI_DEBUG IDLog("%s Successful\n", data); #endif return 0; } int setCommandInt(int fd, int data, const char *cmd) { char temp_string[16]; int error_type; int nbytes_write=0; snprintf(temp_string, sizeof( temp_string ), "%s%d#", cmd, data); if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /* if (portWrite(temp_string) < 0) return -1;*/ return 0; } int setMinElevationLimit(int fd, int min) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":Sh%02d#", min); return (setStandardProcedure(fd, temp_string)); } int setMaxElevationLimit(int fd, int max) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":So%02d*#", max); return (setStandardProcedure(fd, temp_string)); } int setMaxSlewRate(int fd, int slewRate) { char temp_string[16]; if (slewRate < 2 || slewRate > 8) return -1; snprintf(temp_string, sizeof( temp_string ), ":Sw%d#", slewRate); return (setStandardProcedure(fd, temp_string)); } int setObjectRA(int fd, double ra) { int h, m, s, frac_m; char temp_string[16]; getSexComponents(ra, &h, &m, &s); frac_m = (s / 60.0) * 10.; if (controller_format == IEQ45_LONG_FORMAT) snprintf(temp_string, sizeof( temp_string ), ":Sr %02d:%02d:%02d#", h, m, s); else snprintf(temp_string, sizeof( temp_string ), ":Sr %02d:%02d.%01d#", h, m, frac_m); /*IDLog("Set Object RA String %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setObjectDEC(int fd, double dec) { int d, m, s; char temp_string[16]; getSexComponents(dec, &d, &m, &s); switch(controller_format) { case IEQ45_SHORT_FORMAT: /* case with negative zero */ if (!d && dec < 0) snprintf(temp_string, sizeof( temp_string ), ":Sd -%02d*%02d#", d, m); else snprintf(temp_string, sizeof( temp_string ), ":Sd %+03d*%02d#", d, m); break; case IEQ45_LONG_FORMAT: /* case with negative zero */ if (!d && dec < 0) snprintf(temp_string, sizeof( temp_string ), ":Sd -%02d:%02d:%02d#", d, m, s); else snprintf(temp_string, sizeof( temp_string ), ":Sd %+03d:%02d:%02d#", d, m, s); break; } /*IDLog("Set Object DEC String %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setCommandXYZ(int fd, int x, int y, int z, const char *cmd) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), "%s %02d:%02d:%02d#", cmd, x, y, z); return (setStandardProcedure(fd, temp_string)); } int setAlignmentMode(int fd, unsigned int alignMode) { /*fprintf(stderr , "Set alignment mode %d\n", alignMode);*/ int error_type; int nbytes_write=0; switch (alignMode) { case IEQ45_ALIGN_POLAR: if ( (error_type = tty_write_string(fd, ":AP#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":AP#") < 0) return -1;*/ break; case IEQ45_ALIGN_ALTAZ: if ( (error_type = tty_write_string(fd, ":AA#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":AA#") < 0) return -1;*/ break; case IEQ45_ALIGN_LAND: if ( (error_type = tty_write_string(fd, ":AL#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":AL#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setCalenderDate(int fd, int dd, int mm, int yy) { char temp_string[32]; char dumpPlanetaryUpdateString[64]; char bool_return[2]; int error_type; int nbytes_write=0, nbytes_read=0; yy = yy % 100; snprintf(temp_string, sizeof( temp_string ), ":SC %02d/%02d/%02d#", mm, dd, yy); if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(temp_string) < 0) return -1;*/ /*read_ret = portRead(boolRet, 1, IEQ45_TIMEOUT);*/ error_type = tty_read(fd, bool_return, 1, IEQ45_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; bool_return[1] = '\0'; if (bool_return[0] == '0') return -1; /* Read dumped data */ error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', IEQ45_TIMEOUT, &nbytes_read); error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', 5, &nbytes_read); return 0; } int setUTCOffset(int fd, double hours) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":SG %+03d#", (int) hours); /*IDLog("UTC string is %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setSiteLongitude(int fd, double Long) { int d, m, s; char temp_string[32]; getSexComponents(Long, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":Sg%03d:%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setSiteLatitude(int fd, double Lat) { int d, m, s; char temp_string[32]; getSexComponents(Lat, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":St%+03d:%02d:%02d#", d, m, s); return (setStandardProcedure(fd, temp_string)); } int setObjAz(int fd, double az) { int d,m,s; char temp_string[16]; getSexComponents(az, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":Sz%03d:%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setObjAlt(int fd, double alt) { int d, m, s; char temp_string[16]; getSexComponents(alt, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), ":Sa%+02d*%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setSiteName(int fd, char * siteName, int siteNum) { char temp_string[16]; switch (siteNum) { case 1: snprintf(temp_string, sizeof( temp_string ), ":SM %s#", siteName); break; case 2: snprintf(temp_string, sizeof( temp_string ), ":SN %s#", siteName); break; case 3: snprintf(temp_string, sizeof( temp_string ), ":SO %s#", siteName); break; case 4: snprintf(temp_string, sizeof( temp_string ), ":SP %s#", siteName); break; default: return -1; } return (setStandardProcedure(fd, temp_string)); } int setSlewMode(int fd, int slewMode) { int error_type; int nbytes_write=0; switch (slewMode) { case IEQ45_SLEW_MAX: if ( (error_type = tty_write_string(fd, ":RS#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RS#") < 0) return -1;*/ break; case IEQ45_SLEW_FIND: if ( (error_type = tty_write_string(fd, ":RM#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RM#") < 0) return -1;*/ break; case IEQ45_SLEW_CENTER: if ( (error_type = tty_write_string(fd, ":RC#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RC#") < 0) return -1;*/ break; case IEQ45_SLEW_GUIDE: if ( (error_type = tty_write_string(fd, ":RG#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":RG#") < 0) return -1;*/ break; default: break; } tcflush(fd, TCIFLUSH); return 0; } int setFocuserMotion(int fd, int motionType) { int error_type; int nbytes_write=0; switch (motionType) { case IEQ45_FOCUSIN: if ( (error_type = tty_write_string(fd, ":F+#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus IN Command\n");*/ #endif /*if (portWrite(":F+#") < 0) return -1;*/ break; case IEQ45_FOCUSOUT: if ( (error_type = tty_write_string(fd, ":F-#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus OUT Command\n");*/ #endif /*if (portWrite(":F-#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setFocuserSpeedMode (int fd, int speedMode) { int error_type; int nbytes_write=0; switch (speedMode) { case IEQ45_HALTFOCUS: if ( (error_type = tty_write_string(fd, ":FQ#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Halt Focus Command\n");*/ #endif /* if (portWrite(":FQ#") < 0) return -1;*/ break; case IEQ45_FOCUSSLOW: if ( (error_type = tty_write_string(fd, ":FS#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus Slow (FS) Command\n");*/ #endif /*if (portWrite(":FS#") < 0) return -1;*/ break; case IEQ45_FOCUSFAST: if ( (error_type = tty_write_string(fd, ":FF#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus Fast (FF) Command\n");*/ #endif /*if (portWrite(":FF#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setGPSFocuserSpeed (int fd, int speed) { char speed_str[8]; int error_type; int nbytes_write=0; if (speed == 0) { /*if (portWrite(":FQ#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":FQ#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("GPS Focus HALT Command (FQ) \n");*/ #endif return 0; } snprintf(speed_str, 8, ":F%d#", speed); if ( (error_type = tty_write_string(fd, speed_str, &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("GPS Focus Speed command %s \n", speed_str);*/ #endif /*if (portWrite(speed_str) < 0) return -1;*/ tcflush(fd, TCIFLUSH); return 0; } int setTrackFreq(int fd, double trackF) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), ":ST %04.1f#", trackF); return (setStandardProcedure(fd, temp_string)); } /********************************************************************** * Misc *********************************************************************/ int Slew(int fd) { char slewNum[2]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":MS#", &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read(fd, slewNum, 1, IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; /* We don't need to read the string message, just return corresponding error code */ tcflush(fd, TCIFLUSH); if (slewNum[0] == '0') return 0; else if (slewNum[0] == '1') return 1; else return 2; } int MoveTo(int fd, int direction) { int nbytes_write=0; switch (direction) { case IEQ45_NORTH: tty_write_string(fd, ":Mn#", &nbytes_write); /*portWrite(":Mn#");*/ break; case IEQ45_WEST: tty_write_string(fd, ":Mw#", &nbytes_write); /*portWrite(":Mw#");*/ break; case IEQ45_EAST: tty_write_string(fd, ":Me#", &nbytes_write); /*portWrite(":Me#");*/ break; case IEQ45_SOUTH: tty_write_string(fd, ":Ms#", &nbytes_write); /*portWrite(":Ms#");*/ break; default: break; } tcflush(fd, TCIFLUSH); return 0; } int SendPulseCmd(int fd, int direction, int duration_msec) { int nbytes_write=0; char cmd[20]; switch (direction) { case IEQ45_NORTH: sprintf(cmd, ":Mgn%04d#", duration_msec); break; case IEQ45_SOUTH: sprintf(cmd, ":Mgs%04d#", duration_msec); break; case IEQ45_EAST: sprintf(cmd, ":Mge%04d#", duration_msec); break; case IEQ45_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; int nbytes_write=0; switch (direction) { case IEQ45_NORTH: /*if (portWrite(":Qn#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Qn#", &nbytes_write)) != TTY_OK) return error_type; break; case IEQ45_WEST: /*if (portWrite(":Qw#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Qw#", &nbytes_write)) != TTY_OK) return error_type; break; case IEQ45_EAST: /*if (portWrite(":Qe#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Qe#", &nbytes_write)) != TTY_OK) return error_type; break; case IEQ45_SOUTH: if ( (error_type = tty_write_string(fd, ":Qs#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":Qs#") < 0) return -1;*/ break; case IEQ45_ALL: /*if (portWrite(":Q#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, ":Q#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } int abortSlew(int fd) { /*if (portWrite(":Q#") < 0) return -1;*/ int error_type; int nbytes_write=0; if ( (error_type = tty_write_string(fd, ":Q#", &nbytes_write)) != TTY_OK) return error_type; tcflush(fd, TCIFLUSH); return 0; } int Sync(int fd, char *matchedObject) { int error_type; int nbytes_write=0, nbytes_read=0; // if ( (error_type = tty_write_string(fd, ":CM#", &nbytes_write)) != TTY_OK) if ( (error_type = tty_write_string(fd, ":CMR#", &nbytes_write)) != TTY_OK) return error_type; /*portWrite(":CM#");*/ /*read_ret = portRead(matchedObject, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, matchedObject, '#', IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; matchedObject[nbytes_read-1] = '\0'; /*IDLog("Matched Object: %s\n", matchedObject);*/ /* Sleep 10ms before flushing. This solves some issues with IEQ45 compatible devices. */ usleep(10000); tcflush(fd, TCIFLUSH); return 0; } int selectSite(int fd, int siteNum) { int error_type; int nbytes_write=0; switch (siteNum) { case 1: if ( (error_type = tty_write_string(fd, ":W1#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W1#") < 0) return -1;*/ break; case 2: if ( (error_type = tty_write_string(fd, ":W2#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W2#") < 0) return -1;*/ break; case 3: if ( (error_type = tty_write_string(fd, ":W3#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W3#") < 0) return -1;*/ break; case 4: if ( (error_type = tty_write_string(fd, ":W4#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":W4#") < 0) return -1;*/ break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } int selectCatalogObject(int fd, int catalog, int NNNN) { char temp_string[16]; int error_type; int nbytes_write=0; switch (catalog) { case IEQ45_STAR_C: snprintf(temp_string, sizeof( temp_string ), ":LS%d#", NNNN); break; case IEQ45_DEEPSKY_C: snprintf(temp_string, sizeof( temp_string ), ":LC%d#", NNNN); break; case IEQ45_MESSIER_C: snprintf(temp_string, sizeof( temp_string ), ":LM%d#", NNNN); break; default: return -1; } if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(temp_string) < 0) return -1;*/ tcflush(fd, TCIFLUSH); return 0; } int selectSubCatalog(int fd, int catalog, int subCatalog) { char temp_string[16]; switch (catalog) { case IEQ45_STAR_C: snprintf(temp_string, sizeof( temp_string ), ":LsD%d#", subCatalog); break; case IEQ45_DEEPSKY_C: snprintf(temp_string, sizeof( temp_string ), ":LoD%d#", subCatalog); break; case IEQ45_MESSIER_C: return 1; default: return 0; } return (setStandardProcedure(fd, temp_string)); } int checkIEQ45Format(int fd) { char temp_string[16]; controller_format = IEQ45_LONG_FORMAT; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, ":GR#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":GR#") < 0) return -1;*/ /*read_ret = portRead(temp_string, -1, IEQ45_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', IEQ45_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; temp_string[nbytes_read - 1] = '\0'; /* Check whether it's short or long */ if (temp_string[5] == '.') { controller_format = IEQ45_SHORT_FORMAT; return 0; } else return 0; } int selectTrackingMode(int fd, int trackMode) { int error_type; int nbytes_write=0; switch (trackMode) { case IEQ45_TRACK_SIDERAL: #ifdef INDI_DEBUG IDLog("Setting tracking mode to sidereal.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT2#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TQ#") < 0) return -1;*/ break; case IEQ45_TRACK_LUNAR: #ifdef INDI_DEBUG IDLog("Setting tracking mode to LUNAR.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT0#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TL#") < 0) return -1;*/ break; case IEQ45_TRACK_SOLAR: #ifdef INDI_DEBUG IDLog("Setting tracking mode to SOLAR.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT1#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TM#") < 0) return -1;*/ break; case IEQ45_TRACK_ZERO: #ifdef INDI_DEBUG IDLog("Setting tracking mode to ZERO.\n"); #endif if ( (error_type = tty_write_string(fd, ":RT9#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(":TM#") < 0) return -1;*/ break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } libindi-0.9.7/drivers/telescope/telescope_simulator.cpp0000644000175000017500000005013212241463551022354 0ustar jasemjasem#include #include #include #include #include #include #include #include "telescope_simulator.h" #include "indicom.h" #include // We declare an auto pointer to ScopeSim. std::auto_ptr telescope_sim(0); #define GOTO_RATE 2 /* slew rate, degrees/s */ #define SLEW_RATE 0.5 /* slew rate, degrees/s */ #define FINE_SLEW_RATE 0.1 /* slew rate, degrees/s */ #define SID_RATE 0.004178 /* sidereal rate, degrees/s */ #define GOTO_LIMIT 5 /* Move at GOTO_RATE until distance from target is GOTO_LIMIT degrees */ #define SLEW_LIMIT 2 /* Move at SLEW_LIMIT until distance from target is SLEW_LIMIT degrees */ #define FINE_SLEW_LIMIT 0.5 /* Move at FINE_SLEW_RATE until distance from target is FINE_SLEW_LIMIT degrees */ #define POLLMS 250 /* poll period, ms */ #define RA_AXIS 0 #define DEC_AXIS 1 #define GUIDE_NORTH 0 #define GUIDE_SOUTH 1 #define GUIDE_WEST 0 #define GUIDE_EAST 1 void ISPoll(void *p); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(telescope_sim.get() == 0) telescope_sim.reset(new ScopeSim()); //IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { ISInit(); telescope_sim->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); telescope_sim->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); telescope_sim->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); telescope_sim->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } ScopeSim::ScopeSim() { //ctor currentRA=0; currentDEC=90; Parked=false; DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"); /* initialize random seed: */ srand ( time(NULL) ); } ScopeSim::~ScopeSim() { //dtor } const char * ScopeSim::getDefaultName() { return (char *)"Telescope Simulator"; } bool ScopeSim::initProperties() { /* Make sure to init parent properties first */ INDI::Telescope::initProperties(); /* Simulated periodic error in RA, DEC */ IUFillNumber(&EqPEN[RA_AXIS],"RA_PE","RA (hh:mm:ss)","%010.6m",0,24,0,15.); IUFillNumber(&EqPEN[DEC_AXIS],"DEC_PE","DEC (dd:mm:ss)","%010.6m",-90,90,0,15.); IUFillNumberVector(&EqPENV,EqPEN,2,getDeviceName(),"EQUATORIAL_PE","Periodic Error",MOTION_TAB,IP_RO,60,IPS_IDLE); /* Enable client to manually add periodic error northward or southward for simulation purposes */ IUFillSwitch(&PEErrNSS[MOTION_NORTH], "PE_N", "North", ISS_OFF); IUFillSwitch(&PEErrNSS[MOTION_SOUTH], "PE_S", "South", ISS_OFF); IUFillSwitchVector(&PEErrNSSP, PEErrNSS, 2, getDeviceName(),"PE_NS", "PE N/S", MOTION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); /* Enable client to manually add periodic error westward or easthward for simulation purposes */ IUFillSwitch(&PEErrWES[MOTION_WEST], "PE_W", "West", ISS_OFF); IUFillSwitch(&PEErrWES[MOTION_EAST], "PE_E", "East", ISS_OFF); IUFillSwitchVector(&PEErrWESP, PEErrWES, 2, getDeviceName(),"PE_WE", "PE W/E", MOTION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); /* How fast do we guide compared to sidereal rate */ IUFillNumber(&GuideRateN[RA_AXIS], "GUIDE_RATE_WE", "W/E Rate", "%g", 0, 1, 0.1, 0.3); IUFillNumber(&GuideRateN[DEC_AXIS], "GUIDE_RATE_NS", "N/S Rate", "%g", 0, 1, 0.1, 0.3); IUFillNumberVector(&GuideRateNP, GuideRateN, 2, getDeviceName(), "GUIDE_RATE", "Guiding Rate", MOTION_TAB, IP_RW, 0, IPS_IDLE); // Let's simulate it to be an F/10 8" telescope ScopeParametersN[0].value = 203; ScopeParametersN[1].value = 2000; ScopeParametersN[2].value = 203; ScopeParametersN[3].value = 2000; TrackState=SCOPE_IDLE; initGuiderProperties(getDeviceName(), MOTION_TAB); /* Add debug controls so we may debug driver if necessary */ addDebugControl(); return true; } void ScopeSim::ISGetProperties (const char *dev) { /* First we let our parent populate */ INDI::Telescope::ISGetProperties(dev); if(isConnected()) { defineNumber(&GuideNSNP); defineNumber(&GuideWENP); defineNumber(&GuideRateNP); defineNumber(&EqPENV); defineSwitch(&PEErrNSSP); defineSwitch(&PEErrWESP); } return; } bool ScopeSim::updateProperties() { INDI::Telescope::updateProperties(); if (isConnected()) { defineNumber(&GuideNSNP); defineNumber(&GuideWENP); defineNumber(&GuideRateNP); defineNumber(&EqPENV); defineSwitch(&PEErrNSSP); defineSwitch(&PEErrWESP); } else { deleteProperty(GuideNSNP.name); deleteProperty(GuideWENP.name); deleteProperty(EqPENV.name); deleteProperty(PEErrNSSP.name); deleteProperty(PEErrWESP.name); deleteProperty(GuideRateNP.name); } return true; } bool ScopeSim::Connect() { bool rc=false; if(isConnected()) return true; rc=Connect(PortT[0].text); if(rc) SetTimer(POLLMS); return rc; } bool ScopeSim::Connect(char *port) { DEBUG(INDI::Logger::DBG_SESSION, "Telescope simulator is online."); return true; } bool ScopeSim::Disconnect() { DEBUG(INDI::Logger::DBG_SESSION, "Telescope simulator is offline."); return true; } bool ScopeSim::ReadScopeStatus() { static struct timeval ltv; struct timeval tv; double dt=0, da_ra=0, da_dec=0, dx=0, dy=0, ra_guide_dt=0, dec_guide_dt=0; static double last_dx=0, last_dy=0; int nlocked, ns_guide_dir=-1, we_guide_dir=-1; char RA_DISP[64], DEC_DISP[64], RA_GUIDE[64], DEC_GUIDE[64], RA_PE[64], DEC_PE[64], RA_TARGET[64], DEC_TARGET[64]; /* update elapsed time since last poll, don't presume exactly POLLMS */ gettimeofday (&tv, NULL); if (ltv.tv_sec == 0 && ltv.tv_usec == 0) ltv = tv; dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; ltv = tv; if ( fabs(targetRA - currentRA)*15. >= GOTO_LIMIT ) da_ra = GOTO_RATE *dt; else if ( fabs(targetRA - currentRA)*15. >= SLEW_LIMIT ) da_ra = SLEW_RATE *dt; else da_ra = FINE_SLEW_RATE *dt; if ( fabs(targetDEC - currentDEC) >= GOTO_LIMIT ) da_dec = GOTO_RATE *dt; else if ( fabs(targetDEC - currentDEC) >= SLEW_LIMIT ) da_dec = SLEW_RATE *dt; else da_dec = FINE_SLEW_RATE *dt; switch (MovementNSSP.s) { case IPS_BUSY: if (MovementNSS[MOTION_NORTH].s == ISS_ON) currentDEC += da_dec; else if (MovementNSS[MOTION_SOUTH].s == ISS_ON) currentDEC -= da_dec; NewRaDec(currentRA, currentDEC); return true; break; } switch (MovementWESP.s) { case IPS_BUSY: if (MovementWES[MOTION_WEST].s == ISS_ON) currentRA += da_ra/15.; else if (MovementWES[MOTION_EAST].s == ISS_ON) currentRA -= da_ra/15.; NewRaDec(currentRA, currentDEC); return true; break; } /* Process per current state. We check the state of EQUATORIAL_EOD_COORDS_REQUEST and act acoordingly */ switch (TrackState) { /*case SCOPE_IDLE: EqNP.s = IPS_IDLE; break;*/ case SCOPE_SLEWING: case SCOPE_PARKING: /* slewing - nail it when both within one pulse @ SLEWRATE */ nlocked = 0; dx = targetRA - currentRA; if (fabs(dx)*15. <= da_ra) { currentRA = targetRA; nlocked++; } else if (dx > 0) currentRA += da_ra/15.; else currentRA -= da_ra/15.; dy = targetDEC - currentDEC; if (fabs(dy) <= da_dec) { currentDEC = targetDEC; nlocked++; } else if (dy > 0) currentDEC += da_dec; else currentDEC -= da_dec; EqNP.s = IPS_BUSY; if (nlocked == 2) { if (TrackState == SCOPE_SLEWING) { // Initially no PE in both axis. EqPEN[0].value = currentRA; EqPEN[1].value = currentDEC; IDSetNumber(&EqPENV, NULL); TrackState = SCOPE_TRACKING; EqNP.s = IPS_OK; DEBUG(INDI::Logger::DBG_SESSION,"Telescope slew is complete. Tracking..."); } else { TrackState = SCOPE_PARKED; EqNP.s = IPS_IDLE; DEBUG(INDI::Logger::DBG_SESSION,"Telescope parked successfully."); } } break; case SCOPE_IDLE: case SCOPE_TRACKING: /* tracking */ dt *= 1000; if (guiderNSTarget[GUIDE_NORTH] > 0) { DEBUGF(INDI::Logger::DBG_DEBUG, "Commanded to GUIDE NORTH for %g ms", guiderNSTarget[GUIDE_NORTH]); ns_guide_dir = GUIDE_NORTH; } else if (guiderNSTarget[GUIDE_SOUTH] > 0) { DEBUGF(INDI::Logger::DBG_DEBUG, "Commanded to GUIDE SOUTH for %g ms", guiderNSTarget[GUIDE_SOUTH]); ns_guide_dir = GUIDE_SOUTH; } // WE Guide Selection if (guiderEWTarget[GUIDE_WEST] > 0) { we_guide_dir = GUIDE_WEST; DEBUGF(INDI::Logger::DBG_DEBUG, "Commanded to GUIDE WEST for %g ms", guiderEWTarget[GUIDE_WEST]); } else if (guiderEWTarget[GUIDE_EAST] > 0) { we_guide_dir = GUIDE_EAST; DEBUGF(INDI::Logger::DBG_DEBUG, "Commanded to GUIDE EAST for %g ms", guiderEWTarget[GUIDE_EAST]); } if (ns_guide_dir != -1) { dec_guide_dt = SID_RATE * GuideRateN[DEC_AXIS].value * guiderNSTarget[ns_guide_dir]/1000.0 * (ns_guide_dir==GUIDE_NORTH ? 1 : -1); // If time remaining is more that dt, then decrement and if (guiderNSTarget[ns_guide_dir] >= dt) guiderNSTarget[ns_guide_dir] -= dt; else guiderNSTarget[ns_guide_dir] = 0; EqPEN[DEC_AXIS].value += dec_guide_dt; } if (we_guide_dir != -1) { ra_guide_dt = SID_RATE/15.0 * GuideRateN[RA_AXIS].value * guiderEWTarget[we_guide_dir]/1000.0 * (we_guide_dir==GUIDE_WEST ? -1 : 1); if (guiderEWTarget[we_guide_dir] >= dt) guiderEWTarget[we_guide_dir] -= dt; else guiderEWTarget[we_guide_dir] = 0; EqPEN[RA_AXIS].value += ra_guide_dt; } //Mention the followng: // Current RA displacemet and direction // Current DEC displacement and direction // Amount of RA GUIDING correction and direction // Amount of DEC GUIDING correction and direction dx = EqPEN[RA_AXIS].value - targetRA; dy = EqPEN[DEC_AXIS].value - targetDEC; fs_sexa(RA_DISP, fabs(dx), 2, 3600 ); fs_sexa(DEC_DISP, fabs(dy), 2, 3600 ); fs_sexa(RA_GUIDE, fabs(ra_guide_dt), 2, 3600 ); fs_sexa(DEC_GUIDE, fabs(dec_guide_dt), 2, 3600 ); fs_sexa(RA_PE, EqPEN[RA_AXIS].value, 2, 3600); fs_sexa(DEC_PE, EqPEN[DEC_AXIS].value, 2, 3600); fs_sexa(RA_TARGET, targetRA, 2, 3600); fs_sexa(DEC_TARGET, targetDEC, 2, 3600); if ((dx!=last_dx || dy!=last_dy || ra_guide_dt || dec_guide_dt)) { last_dx=dx; last_dy=dy; DEBUGF(INDI::Logger::DBG_DEBUG, "dt is %g\n", dt); DEBUGF(INDI::Logger::DBG_DEBUG, "RA Displacement (%c%s) %s -- %s of target RA %s\n", dx >= 0 ? '+' : '-', RA_DISP, RA_PE, (EqPEN[RA_AXIS].value - targetRA) > 0 ? "East" : "West", RA_TARGET); DEBUGF(INDI::Logger::DBG_DEBUG, "DEC Displacement (%c%s) %s -- %s of target RA %s\n", dy >= 0 ? '+' : '-', DEC_DISP, DEC_PE, (EqPEN[DEC_AXIS].value - targetDEC) > 0 ? "North" : "South", DEC_TARGET); DEBUGF(INDI::Logger::DBG_DEBUG, "RA Guide Correction (%g) %s -- Direction %s\n", ra_guide_dt, RA_GUIDE, ra_guide_dt > 0 ? "East" : "West"); DEBUGF(INDI::Logger::DBG_DEBUG, "DEC Guide Correction (%g) %s -- Direction %s\n", dec_guide_dt, DEC_GUIDE, dec_guide_dt > 0 ? "North" : "South"); } if (ns_guide_dir != -1 || we_guide_dir != -1) IDSetNumber(&EqPENV, NULL); break; default: break; } char RAStr[64], DecStr[64]; fs_sexa(RAStr, currentRA, 2, 3600); fs_sexa(DecStr, currentDEC, 2, 3600); DEBUGF(DBG_SCOPE, "Current RA: %s Current DEC: %s", RAStr, DecStr); NewRaDec(currentRA, currentDEC); return true; } bool ScopeSim::Goto(double r,double d) { //IDLog("ScopeSim Goto\n"); targetRA=r; targetDEC=d; char RAStr[64], DecStr[64]; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); Parked=false; TrackState = SCOPE_SLEWING; EqNP.s = IPS_BUSY; DEBUGF(INDI::Logger::DBG_SESSION,"Slewing to RA: %s - DEC: %s", RAStr, DecStr); return true; } bool ScopeSim::Sync(double ra, double dec) { currentRA = ra; currentDEC = dec; EqPEN[RA_AXIS].value = ra; EqPEN[DEC_AXIS].value = dec; IDSetNumber(&EqPENV, NULL); DEBUG(INDI::Logger::DBG_SESSION,"Sync is successful."); TrackState = SCOPE_IDLE; EqNP.s = IPS_OK; NewRaDec(currentRA, currentDEC); return true; } bool ScopeSim::Park() { targetRA=0; targetDEC=90; Parked=true; TrackState = SCOPE_PARKING; DEBUG(INDI::Logger::DBG_SESSION,"Parking telescope in progress..."); return true; } bool ScopeSim::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // first check if it's for our device if(strcmp(dev,getDeviceName())==0) { if(strcmp(name,"GUIDE_RATE")==0) { IUUpdateNumber(&GuideRateNP, values, names, n); GuideRateNP.s = IPS_OK; IDSetNumber(&GuideRateNP, NULL); return true; } if (!strcmp(name,GuideNSNP.name) || !strcmp(name,GuideWENP.name)) { processGuiderProperties(name, values, names, n); return true; } } // if we didn't process it, continue up the chain, let somebody else // give it a shot return INDI::Telescope::ISNewNumber(dev,name,values,names,n); } bool ScopeSim::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if(strcmp(name,"PE_NS")==0) { IUUpdateSwitch(&PEErrNSSP,states,names,n); PEErrNSSP.s = IPS_OK; if (PEErrNSS[MOTION_NORTH].s == ISS_ON) { EqPEN[DEC_AXIS].value += SID_RATE * GuideRateN[DEC_AXIS].value; DEBUGF(INDI::Logger::DBG_DEBUG, "Simulating PE in NORTH direction for value of %g", SID_RATE); } else { EqPEN[DEC_AXIS].value -= SID_RATE * GuideRateN[DEC_AXIS].value; DEBUGF(INDI::Logger::DBG_DEBUG, "Simulating PE in SOUTH direction for value of %g", SID_RATE); } IUResetSwitch(&PEErrNSSP); IDSetSwitch(&PEErrNSSP, NULL); IDSetNumber(&EqPENV, NULL); return true; } if(strcmp(name,"PE_WE")==0) { IUUpdateSwitch(&PEErrWESP,states,names,n); PEErrWESP.s = IPS_OK; if (PEErrWES[MOTION_WEST].s == ISS_ON) { EqPEN[RA_AXIS].value -= SID_RATE/15. * GuideRateN[RA_AXIS].value; DEBUGF(INDI::Logger::DBG_DEBUG, "Simulator PE in WEST direction for value of %g", SID_RATE); } else { EqPEN[RA_AXIS].value += SID_RATE/15. * GuideRateN[RA_AXIS].value; DEBUGF(INDI::Logger::DBG_DEBUG, "Simulator PE in EAST direction for value of %g", SID_RATE); } IUResetSwitch(&PEErrWESP); IDSetSwitch(&PEErrWESP, NULL); IDSetNumber(&EqPENV, NULL); return true; } } // Nobody has claimed this, so, ignore it return INDI::Telescope::ISNewSwitch(dev,name,states,names,n); } bool ScopeSim::Abort() { if (MovementNSSP.s == IPS_BUSY) { IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); } if (MovementWESP.s == IPS_BUSY) { MovementWESP.s = IPS_IDLE; IUResetSwitch(&MovementWESP); IDSetSwitch(&MovementWESP, NULL); } if (ParkSP.s == IPS_BUSY) { ParkSP.s = IPS_IDLE; IUResetSwitch(&ParkSP); IDSetSwitch(&ParkSP, NULL); } if (EqNP.s == IPS_BUSY) { EqNP.s = IPS_IDLE; IDSetNumber(&EqNP, NULL); } TrackState = SCOPE_IDLE; AbortSP.s = IPS_OK; IUResetSwitch(&AbortSP); IDSetSwitch(&AbortSP, NULL); DEBUG(INDI::Logger::DBG_SESSION, "Telescope aborted."); return true; } bool ScopeSim::MoveNS(TelescopeMotionNS dir) { static int last_motion=-1; switch (dir) { case MOTION_NORTH: if (last_motion != MOTION_NORTH) last_motion = MOTION_NORTH; else { IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); } break; case MOTION_SOUTH: if (last_motion != MOTION_SOUTH) last_motion = MOTION_SOUTH; else { IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); } break; } return true; } bool ScopeSim::MoveWE(TelescopeMotionWE dir) { static int last_motion=-1; switch (dir) { case MOTION_WEST: if (last_motion != MOTION_WEST) last_motion = MOTION_WEST; else { IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, NULL); } break; case MOTION_EAST: if (last_motion != MOTION_EAST) last_motion = MOTION_EAST; else { IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, NULL); } break; } return true; } bool ScopeSim::GuideNorth(float ms) { guiderNSTarget[GUIDE_NORTH] = ms; guiderNSTarget[GUIDE_SOUTH] = 0; return true; } bool ScopeSim::GuideSouth(float ms) { guiderNSTarget[GUIDE_SOUTH] = ms; guiderNSTarget[GUIDE_NORTH] = 0; return true; } bool ScopeSim::GuideEast(float ms) { guiderEWTarget[GUIDE_EAST] = ms; guiderEWTarget[GUIDE_WEST] = 0; return true; } bool ScopeSim::GuideWest(float ms) { guiderEWTarget[GUIDE_WEST] = ms; guiderEWTarget[GUIDE_EAST] = 0; return true; } bool ScopeSim::canSync() { return true; } bool ScopeSim::canPark() { return true; } libindi-0.9.7/drivers/telescope/lx200ap.cpp0000644000175000017500000017367212241463551017477 0ustar jasemjasem/* LX200 Astro-Physics INDI driver, tested with controller software version D Copyright (C) 2007 Markus Wildi based on the work of Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ //HAVE_NOVASCC_H: NOVAS-C, Version 2.0.1, Astronomical Applications Dept. //U.S. Naval Observatory, Washington, DC 20392-5420 http://aa.usno.navy.mil/AA/ //#define HAVE_NOVASCC_H //HAVE_NOVA_H: http://libnova.sourceforge.net/ //#define HAVE_NOVA_H #include "lx200ap.h" #include "lx200driver.h" #include "lx200apdriver.h" #include "lx200aplib.h" #include #ifdef HAVE_NOVA_H #include #endif #include #include #include #include #define COMM_GROUP "Communication" #define BASIC_GROUP "Main Control" #define MOTION_GROUP "Motion Control" #define FIRMWARE_GROUP "Firmware data" #define SETTINGS_GROUP "Settings" #define ATMOSPHERE_GROUP "Atmosphere" #define MOUNT_GROUP "Mounting" /* Handy Macros */ #define currentRA EquatorialCoordsRNP.np[0].value #define currentDEC EquatorialCoordsRNP.np[1].value #define currentAZ HorizontalCoordsRNP.np[0].value #define currentALT HorizontalCoordsRNP.np[1].value /* SNOOP */ #define CONTROL_GROUP "Control" /* Do not forget to remove static in LX200GenericLegacy.cpp */ extern INumberVectorProperty EquatorialCoordsRNP; extern ITextVectorProperty PortTP ; extern ISwitchVectorProperty MovementNSSP ; extern ISwitchVectorProperty MovementWESP ; extern ISwitchVectorProperty ConnectSP ; extern ISwitchVectorProperty AbortSlewSP ; extern ISwitchVectorProperty OnCoordSetSP ; extern INumberVectorProperty geoNP ; extern INumberVectorProperty TrackingAccuracyNP ; extern INumberVectorProperty SlewAccuracyNP ; /* Communication */ static ISwitch DomeControlS[] = { {"ON" , "on" , ISS_ON, 0, 0}, {"OFF" , "off" , ISS_OFF, 0, 0}, }; ISwitchVectorProperty DomeControlSP = { myapdev, "DOMECONTROL" , "Dome control", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, DomeControlS, NARRAY(DomeControlS), "", 0 }; static ISwitch StartUpS[] = { {"COLD" , "cold" , ISS_OFF, 0, 0}, {"WARM" , "warm" , ISS_ON, 0, 0}, }; ISwitchVectorProperty StartUpSP = { myapdev, "STARTUP" , "Mount init.", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, StartUpS, NARRAY(StartUpS), "", 0 }; /* Main control */ #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H static ISwitch ApparentToObservedS[] = { {"NCTC" , "identity" , ISS_ON, 0, 0}, {"NATR" , "app. to refracted" , ISS_OFF, 0, 0}, {"NARTT" , "app., refr., telescope" , ISS_OFF, 0, 0}, {"NARTTO" , "app., refr., tel., observed" , ISS_OFF, 0, 0}, }; ISwitchVectorProperty ApparentToObservedSP = { myapdev, "TRANSFORMATION" , "Transformation", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ApparentToObservedS, NARRAY(ApparentToObservedS), "", 0 }; #endif static INumber HourangleCoordsN[] = { {"HA", "HA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"Dec", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}, }; static INumberVectorProperty HourangleCoordsNP = { myapdev, "HOURANGLE_COORD", "Hourangle Coords", BASIC_GROUP, IP_RO, 0., IPS_IDLE, HourangleCoordsN, NARRAY( HourangleCoordsN), "", 0 }; static INumber HorizontalCoordsRN[] = { {"AZ", "Az D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0}, {"ALT", "Alt D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0} }; static INumberVectorProperty HorizontalCoordsRNP = { myapdev, "HORIZONTAL_COORD", "Horizontal Coords", BASIC_GROUP, IP_RW, 120, IPS_IDLE, HorizontalCoordsRN, NARRAY(HorizontalCoordsRN), "", 0 }; /* Difference of the equatorial coordinates, used to estimate the applied corrections */ static INumber DiffEquatorialCoordsN[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"Dec", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}, }; static INumberVectorProperty DiffEquatorialCoordsNP = { myapdev, "DIFFEQUATORIAL_COORD", "Diff. Eq.", BASIC_GROUP, IP_RO, 0., IPS_IDLE, DiffEquatorialCoordsN, NARRAY( DiffEquatorialCoordsN), "", 0 }; static ISwitch TrackModeS[] = { {"LUNAR" , "lunar" , ISS_OFF, 0, 0}, {"SOLAR" , "solar" , ISS_OFF, 0, 0}, {"SIDEREAL", "sidereal" , ISS_OFF, 0, 0}, {"ZERO" , "zero" , ISS_ON, 0, 0}, }; ISwitchVectorProperty TrackModeSP = { myapdev, "TRACKINGMODE" , "Tracking mode", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0 }; static ISwitch MoveToRateS[] = { {"1200" , "1200x" , ISS_OFF, 0, 0}, {"600" , "600x" , ISS_OFF, 0, 0}, {"64" , "64x" , ISS_ON, 0, 0}, {"12" , "12x" , ISS_OFF, 0, 0}, }; ISwitchVectorProperty MoveToRateSP = { myapdev, "MOVETORATE" , "Move to rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MoveToRateS, NARRAY(MoveToRateS), "", 0 }; static ISwitch SlewRateS[] = { {"1200" , "1200x" , ISS_OFF, 0, 0}, {"900" , "900x" , ISS_OFF, 0, 0}, {"600" , "600x" , ISS_ON, 0, 0}, }; ISwitchVectorProperty SlewRateSP = { myapdev, "SLEWRATE" , "Slew rate", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewRateS, NARRAY(SlewRateS), "", 0 }; static ISwitch SwapS[] = { {"NS" , "North/South" , ISS_OFF, 0, 0}, {"EW" , "East/West" , ISS_OFF, 0, 0}, }; ISwitchVectorProperty SwapSP = { myapdev, "SWAP" , "Swap buttons", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SwapS, NARRAY(SwapS), "", 0 }; static ISwitch SyncCMRS[] = { {":CM#" , ":CM#" , ISS_ON, 0, 0}, {":CMR#" , ":CMR#" , ISS_OFF, 0, 0}, }; ISwitchVectorProperty SyncCMRSP = { myapdev, "SYNCCMR" , "Sync", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SyncCMRS, NARRAY(SyncCMRS), "", 0 }; /* Firmware data */ static IText VersionT[] = { // AP has only versionnumber { "Number", "", 0, 0, 0 ,0} }; static ITextVectorProperty VersionInfo = { myapdev, "Firmware Info", "", FIRMWARE_GROUP, IP_RO, 0, IPS_IDLE, VersionT, NARRAY(VersionT), "" ,0 }; /* Mount */ static IText DeclinationAxisT[] = { { "RELHA", "rel. to HA", 0, 0, 0, 0} , }; static ITextVectorProperty DeclinationAxisTP = { myapdev, "DECLINATIONAXIS", "Declination axis", MOUNT_GROUP, IP_RO, 0, IPS_IDLE, DeclinationAxisT, NARRAY(DeclinationAxisT), "" ,0 }; static INumber APLocalTimeN[] = { {"VALUE", "H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, }; static INumberVectorProperty APLocalTimeNP = { myapdev, "APLOCALTIME", "AP local time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APLocalTimeN, NARRAY(APLocalTimeN), "", 0 }; static INumber APSiderealTimeN[] = { {"VALUE", "H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, }; static INumberVectorProperty APSiderealTimeNP = { myapdev, "APSIDEREALTIME", "AP sidereal time", MOUNT_GROUP, IP_RO, 0., IPS_IDLE, APSiderealTimeN, NARRAY(APSiderealTimeN), "", 0 }; static INumber APUTCOffsetN[] = { {"VALUE", "H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, }; static INumberVectorProperty APUTCOffsetNP = { myapdev, "APUTCOFFSET", "AP UTC Offset", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, APUTCOffsetN, NARRAY(APUTCOffsetN), "", 0 }; static INumber HourAxisN[] = { {"THETA", "Theta D:M:S", "%10.6m", 0., 360., 0., 0., 0, 0, 0}, // 0., it points to the apparent pole {"GAMMA", "Gamma D:M:S", "%10.6m", 0., 90., 0., 0., 0, 0, 0}, }; static INumberVectorProperty HourAxisNP = { myapdev, "HOURAXIS", "Hour axis", MOUNT_GROUP, IP_RW, 0., IPS_IDLE, HourAxisN, NARRAY(HourAxisN), "", 0 }; /* Atmosphere */ static INumber AirN[] = { {"TEMPERATURE", "Temperature K", "%10.2f", 0., 383.1, 0., 283.1, 0, 0, 0}, {"PRESSURE", "Pressure hPa", "%10.2f", 0., 1300., 0., 975., 0, 0, 0}, {"HUMIDITY", "Humidity Perc.", "%10.2f", 0., 100., 0., 70., 0, 0, 0}, }; static INumberVectorProperty AirNP = { myapdev, "ATMOSPHERE", "Atmosphere", ATMOSPHERE_GROUP, IP_RW, 0., IPS_IDLE, AirN, NARRAY(AirN), "", 0 }; /* Settings Group */ static IText ConnectionDCODT[] = { { "DEVICE", "Device", 0, 0, 0, 0} , { "PROPERTY", "Property", 0, 0, 0, 0} }; static ITextVectorProperty ConnectionDCODTP = { myapdev, "SNOOPCONNECTIONDC", "Snoop dc connection", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ConnectionDCODT, NARRAY(ConnectionDCODT), "" ,0 }; static IText MasterAlarmODT[]= { { "DEVICE", "Device", 0, 0, 0, 0} , { "PROPERTY", "Property", 0, 0, 0, 0} }; static ITextVectorProperty MasterAlarmODTP = { myapdev, "SNOOPMASTERALARM", "Snoop dc master alarm", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, MasterAlarmODT, NARRAY(MasterAlarmODT), "" ,0 }; static IText ModeDCODT[] = { { "DEVICE", "Device", 0, 0, 0, 0} , { "PROPERTY", "Property", 0, 0, 0, 0} }; static ITextVectorProperty ModeDCODTP = { myapdev, "SNOOPMODEDC", "Snoop dc mode", SETTINGS_GROUP, IP_RW, 0, IPS_IDLE, ModeDCODT, NARRAY(ModeDCODT), "" ,0 }; /******************************************** Property: Park telescope to HOME *********************************************/ static ISwitch ParkS[] = { {"PARK", "Park", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty ParkSP = { myapdev, "TELESCOPE_PARK", "Park Scope", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, ParkS, NARRAY(ParkS), "", 0 }; /* SNOOPed properties */ static ISwitch ConnectionDCS[] = { {"CONNECT", "Connect", ISS_OFF, 0, 0}, {"DISCONNECT", "Disconnect", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty ConnectionDCSP = { "dc", "CONNECTION", "Connection", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectionDCS, NARRAY(ConnectionDCS), "", 0 }; static ISwitch MasterAlarmS[] = { {"OFF", "off", ISS_OFF, 0, 0}, {"DANGER", "danger", ISS_OFF, 0, 0}, {"ON", "ON", ISS_OFF, 0, 0}, {"RESET", "reset", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty MasterAlarmSP = { "dc", "MASTERALARM", "Master alarm", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, MasterAlarmS, NARRAY(MasterAlarmS), "", 0 }; static ISwitch ModeS[] = { {"MANUAL", "manual", ISS_ON, 0, 0}, {"DOMECONTROL", "dome control", ISS_OFF, 0, 0} }; static ISwitchVectorProperty ModeSP = { "dc", "MODE", "Mode", CONTROL_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ModeS, NARRAY(ModeS), "", 0 }; void changeLX200AstroPhysicsDeviceName(const char *newName) { strcpy(VersionInfo.device, newName); strcpy(ParkSP.device, newName); strcpy(AirNP.device, newName); strcpy(ConnectionDCODTP.device, newName); strcpy(MasterAlarmODTP.device, newName); strcpy(ModeDCODTP.device, newName); strcpy(TrackModeSP.device, newName); strcpy(MovementNSSP.device, newName); strcpy(MovementWESP.device, newName); strcpy(MoveToRateSP.device, newName); strcpy(SlewRateSP.device, newName); strcpy(SwapSP.device, newName); strcpy(SyncCMRSP.device, newName); strcpy(DeclinationAxisTP.device, newName); strcpy(APLocalTimeNP.device, newName); strcpy(APSiderealTimeNP.device, newName); strcpy(HourAxisNP.device, newName); strcpy(APUTCOffsetNP.device, newName); #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H strcpy(ApparentToObservedSP.device, newName); #endif strcpy(HourangleCoordsNP.device, newName); strcpy(HorizontalCoordsRNP.device, newName); strcpy(EquatorialCoordsRNP.device, newName); strcpy(DiffEquatorialCoordsNP.device, newName); strcpy(StartUpSP.device, newName); strcpy(DomeControlSP.device, newName); } /* Constructor */ LX200AstroPhysics::LX200AstroPhysics() : LX200GenericLegacy() { const char dev[]= "/dev/apmount" ; const char status[]= "undefined" ; IUSaveText(&ConnectionDCODT[0], ConnectionDCSP.device); IUSaveText(&ConnectionDCODT[1], ConnectionDCSP.name); IUSaveText(&MasterAlarmODT[0], MasterAlarmSP.device); IUSaveText(&MasterAlarmODT[1], MasterAlarmSP.name); IUSaveText(&ModeDCODT[0], ModeSP.device); IUSaveText(&ModeDCODT[1], ModeSP.name); IUSaveText(&PortTP.tp[0], dev); IUSaveText(&DeclinationAxisTP.tp[0], status); } void LX200AstroPhysics::ISGetProperties (const char *dev) { if (dev && strcmp (thisDevice, dev)) return; LX200GenericLegacy::ISGetProperties(dev); IDDelete(thisDevice, "TELESCOPE_PARK", NULL); IDDefSwitch (&ParkSP, NULL); IDDefText(&VersionInfo, NULL); /* Communication group */ // AstroPhysics has no alignment mode IDDelete(thisDevice, "Alignment", NULL); IDDefSwitch (&StartUpSP, NULL); IDDefSwitch (&DomeControlSP, NULL); /* Main Group */ #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H IDDefSwitch(&ApparentToObservedSP, NULL); #endif IDDefNumber(&HourangleCoordsNP, NULL) ; IDDefNumber(&HorizontalCoordsRNP, NULL); IDDelete(thisDevice, "EQUATORIAL_EOD_COORD", NULL); IDDefNumber(&EquatorialCoordsRNP, NULL); IDDefNumber(&DiffEquatorialCoordsNP, NULL); /* Date&Time group */ IDDelete(thisDevice, "TIME_UTC_OFFSET", NULL); IDDefText(&DeclinationAxisTP, NULL); /* Mount group */ IDDefText(&DeclinationAxisTP, NULL); IDDefNumber(&APLocalTimeNP, NULL); IDDefNumber(&APSiderealTimeNP, NULL); IDDefNumber(&APUTCOffsetNP, NULL); IDDefNumber(&HourAxisNP, NULL); /* Atmosphere group */ IDDefNumber (&AirNP, NULL); /* Settings group */ IDDefText (&ConnectionDCODTP, NULL); IDDefText (&MasterAlarmODTP, NULL); IDDefText (&ModeDCODTP, NULL); // AstroPhysics, we have no focuser, therefore, we don't need the classical one IDDelete(thisDevice, "FOCUS_MODE", NULL); IDDelete(thisDevice, "FOCUS_MOTION", NULL); IDDelete(thisDevice, "FOCUS_TIMER", NULL); /* Motion group */ IDDelete(thisDevice, "Slew rate", NULL); IDDelete(thisDevice, "Tracking Mode", NULL); IDDelete(thisDevice, "Tracking Frequency", NULL); /* AP does not have :GT, :ST commands */ IDDefSwitch (&TrackModeSP, NULL); IDDefSwitch (&MovementNSSP, NULL); IDDefSwitch (&MovementWESP, NULL); IDDefSwitch (&MoveToRateSP, NULL); IDDefSwitch (&SlewRateSP, NULL); IDDefSwitch (&SwapSP, NULL); IDDefSwitch (&SyncCMRSP, NULL); /* Site management */ /* Astro Physics has no commands to retrieve the values */ /* True for all three control boxes and the software and C-KE1, G-L*/ IDDelete(thisDevice, "Sites", NULL); IDDelete(thisDevice, "Site Name", NULL); } void LX200AstroPhysics::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { IText *tp=NULL; // ignore if not ours // if (strcmp (dev, thisDevice)) return; // =================================== // Snoop DC Connection // =================================== if (!strcmp(name, ConnectionDCODTP.name) ) { tp = IUFindText( &ConnectionDCODTP, names[0] ); if (!tp) return; IUSaveText(tp, texts[0]); tp = IUFindText( &ConnectionDCODTP, names[1] ); if (!tp) return; ConnectionDCODTP.s = IPS_OK; IUSaveText(tp, texts[1]); IDSnoopDevice( ConnectionDCODT[0].text, ConnectionDCODT[1].text); ConnectionDCODTP.s= IPS_OK ; IDSetText (&ConnectionDCODTP, "Snooping property %s at device %s", ConnectionDCODT[1].text, ConnectionDCODT[0].text); return; } // =================================== // Master Alarm // =================================== if (!strcmp(name, MasterAlarmODTP.name) ) { tp = IUFindText( &MasterAlarmODTP, names[0] ); if (!tp) return; IUSaveText(tp, texts[0]); tp = IUFindText( &MasterAlarmODTP, names[1] ); if (!tp) return; IUSaveText(tp, texts[1]); IDSnoopDevice( MasterAlarmODT[0].text, MasterAlarmODT[1].text); MasterAlarmODTP.s= IPS_OK ; IDSetText (&MasterAlarmODTP, "Snooping property %s at device %s", MasterAlarmODT[1].text, MasterAlarmODT[0].text) ; return; } // =================================== // Snope DC Mode // =================================== if (!strcmp(name, ModeDCODTP.name) ) { tp = IUFindText( &ModeDCODTP, names[0] ); if (!tp) return; IUSaveText(tp, texts[0]); tp = IUFindText( &ModeDCODTP, names[1] ); if (!tp) return; ModeDCODTP.s = IPS_OK; IUSaveText(tp, texts[1]); IDSnoopDevice( ModeDCODT[0].text, ModeDCODT[1].text); ModeDCODTP.s= IPS_OK ; IDSetText (&ModeDCODTP, "Snooping property %s at device %s", ModeDCODT[1].text, ModeDCODT[0].text); return; } LX200GenericLegacy::ISNewText (dev, name, texts, names, n); } void LX200AstroPhysics::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { int i=0, nset=0; INumber *np=NULL; // ignore if not ours if (strcmp (dev, thisDevice)) return; // =================================== // Atmosphere // =================================== if (!strcmp (name, AirNP.name)) { double newTemperature ; double newPressure ; double newHumidity ; if (checkPower(&AirNP)) return; for (nset = i = 0; i < n; i++) { np = IUFindNumber (&AirNP, names[i]); if( np == &AirN[0]) { newTemperature = values[i]; nset++ ; } else if( np == &AirN[1]) { newPressure = values[i]; nset++ ; } else if( np == &AirN[2]) { newHumidity = values[i]; nset++ ; } } if (nset == 3) { AirNP.s = IPS_OK; AirN[0].value = newTemperature; AirN[1].value = newPressure; AirN[2].value = newHumidity; IDSetNumber(&AirNP, NULL); } else { AirNP.s = IPS_ALERT; IDSetNumber(&AirNP, "Temperature, Pressure or Humidity missing or invalid"); } return; } // =================================== // AP UTC Offset // =================================== if ( !strcmp (name, APUTCOffsetNP.name) ) { int ret ; if (checkPower(&APUTCOffsetNP)) return; if (values[0] <= 0.0 || values[0] > 24.0) { APUTCOffsetNP.s = IPS_IDLE; IDSetNumber(&APUTCOffsetNP , "UTC offset invalid"); return; } if(( ret = setAPUTCOffset(fd, values[0]) < 0) ) { handleError(&APUTCOffsetNP, ret, "Setting AP UTC offset"); return; } APUTCOffsetN[0].value = values[0]; APUTCOffsetNP.s = IPS_OK; IDSetNumber(&APUTCOffsetNP, NULL); return; } // ======================================= // Hour axis' intersection with the sphere // ======================================= if (!strcmp (name, HourAxisNP.name)) { int i=0, nset=0; double newTheta, newGamma ; if (checkPower(&HourAxisNP)) return; for (nset = i = 0; i < n; i++) { np = IUFindNumber (&HourAxisNP, names[i]); if ( np == &HourAxisN[0]) { newTheta = values[i]; nset += newTheta >= 0 && newTheta <= 360.0; } else if ( np == &HourAxisN[1]) { newGamma = values[i]; nset += newGamma >= 0. && newGamma <= 90.0; } } if (nset == 2) { HourAxisNP.s = IPS_OK; HourAxisN[0].value = newTheta; HourAxisN[1].value = newGamma; IDSetNumber(&HourAxisNP, NULL); } else { HourAxisNP.s = IPS_ALERT; IDSetNumber(&HourAxisNP, "Theta or gamma missing or invalid"); } return; } // ======================================= // Equatorial Coord - SET // ======================================= if (!strcmp (name, EquatorialCoordsRNP.name)) { int err ; int i=0, nset=0; double newRA, newDEC ; if (checkPower(&EquatorialCoordsRNP)) return; for (nset = i = 0; i < n; i++) { INumber *np = IUFindNumber (&EquatorialCoordsRNP, names[i]); if (np == &EquatorialCoordsRNP.np[0]) { newRA = values[i]; nset += newRA >= 0 && newRA <= 24.0; } else if (np == &EquatorialCoordsRNP.np[1]) { newDEC = values[i]; nset += newDEC >= -90.0 && newDEC <= 90.0; } } if (nset == 2) { int ret ; #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H double geo[6] ; double eqt[2] ; double eqn[2] ; double hxt[2] ; #endif /*EquatorialCoordsWNP.s = IPS_BUSY;*/ char RAStr[32], DecStr[32]; fs_sexa(RAStr, newRA, 2, 3600); fs_sexa(DecStr, newDEC, 2, 3600); #ifdef INDI_DEBUG IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC); IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr); #endif #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H // Transfor the coordinates /* Get the current time. */ geo[0]= geoNP.np[0].value ; geo[1]= geoNP.np[1].value ; geo[2]= geoNP.np[2].value ; geo[3]= AirN[0].value ; geo[4]= AirN[1].value ; geo[5]= AirN[2].value ; eqn[0]= newRA ; eqn[1]= newDEC ; hxt[0]= HourAxisN[0].value ; hxt[1]= HourAxisN[1].value ; if((ret = LDAppToX( getOnSwitch(&ApparentToObservedSP), eqn, ln_get_julian_from_sys(), geo, hxt, eqt)) != 0) { IDMessage( myapdev, "ISNewNumber: transformation %d failed", getOnSwitch(&ApparentToObservedSP)) ; exit(1) ; } ; /*EquatorialCoordsWNP.s = IPS_BUSY;*/ targetRA= eqt[0]; targetDEC= eqt[1]; #else targetRA= newRA; targetDEC= newDEC; #endif if ( (ret = setAPObjectRA(fd, targetRA)) < 0 || ( ret = setAPObjectDEC(fd, targetDEC)) < 0) { DiffEquatorialCoordsNP.s= IPS_ALERT; IDSetNumber(&DiffEquatorialCoordsNP, NULL); handleError(&EquatorialCoordsRNP, err, "Setting RA/DEC"); return; } EquatorialCoordsRNP.s = IPS_OK; IDSetNumber(&EquatorialCoordsRNP, NULL); DiffEquatorialCoordsNP.np[0].value= targetRA - currentRA ; DiffEquatorialCoordsNP.np[1].value= targetDEC - currentDEC; DiffEquatorialCoordsNP.s= IPS_OK; IDSetNumber(&DiffEquatorialCoordsNP, NULL); // ToDo don't we need to stop the motion (:Q#)? if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) { IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); MovementNSSP.s = MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); } handleEqCoordSet() ; //ToDo : conversion to boolean { // EquatorialCoordsWNP.s = IPS_ALERT; // IDSetNumber(&EquatorialCoordsWNP, NULL); // } } // end nset else { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, "RA or Dec missing or invalid"); } return ; } // ======================================= // Horizontal Coords - SET // ======================================= if ( !strcmp (name, HorizontalCoordsRNP.name) ) { int i=0, nset=0; double newAz, newAlt ; int ret ; char altStr[64], azStr[64]; if (checkPower(&HorizontalCoordsRNP)) return; for (nset = i = 0; i < n; i++) { np = IUFindNumber (&HorizontalCoordsRNP, names[i]); if (np == &HorizontalCoordsRN[0]) { newAz = values[i]; nset += newAz >= 0. && newAz <= 360.0; } else if (np == &HorizontalCoordsRN[1]) { newAlt = values[i]; nset += newAlt >= -90. && newAlt <= 90.0; } } if (nset == 2) { if ( (ret = setAPObjectAZ(fd, newAz)) < 0 || (ret = setAPObjectAlt(fd, newAlt)) < 0) { handleError(&HorizontalCoordsRNP, ret, "Setting Alt/Az"); return; } targetAZ= newAz; targetALT= newAlt; HorizontalCoordsRNP.s = IPS_OK; IDSetNumber(&HorizontalCoordsRNP, NULL) ; fs_sexa(azStr, targetAZ, 2, 3600); fs_sexa(altStr, targetALT, 2, 3600); //IDSetNumber (&HorizontalCoordsWNP, "Attempting to slew to Alt %s - Az %s", altStr, azStr); handleAltAzSlew(); } else { HorizontalCoordsRNP.s = IPS_ALERT; IDSetNumber(&HorizontalCoordsRNP, "Altitude or Azimuth missing or invalid"); } return; } // ======================================= // Geographical Location // ======================================= if (!strcmp (name, geoNP.name)) { // new geographic coords double newLong = 0, newLat = 0; int i, nset, err; char msg[128]; if (checkPower(&geoNP)) return; for (nset = i = 0; i < n; i++) { np = IUFindNumber (&geoNP, names[i]); if (np == &geoNP.np[0]) { newLat = values[i]; nset += newLat >= -90.0 && newLat <= 90.0; } else if (np == &geoNP.np[1]) { newLong = values[i]; nset += newLong >= 0.0 && newLong < 360.0; } } if (nset == 2) { char l[32], L[32]; geoNP.s = IPS_OK; fs_sexa (l, newLat, 3, 3600); fs_sexa (L, newLong, 4, 3600); if ( ( err = setAPSiteLongitude(fd, 360.0 - newLong) < 0) ) { handleError(&geoNP, err, "Setting site coordinates"); return; } if ( ( err = setAPSiteLatitude(fd, newLat) < 0) ) { handleError(&geoNP, err, "Setting site coordinates"); return; } geoNP.np[0].value = newLat; geoNP.np[1].value = newLong; snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L); } else { geoNP.s = IPS_IDLE; strcpy(msg, "Lat or Long missing or invalid"); } IDSetNumber (&geoNP, "%s", msg); return; } LX200GenericLegacy::ISNewNumber (dev, name, values, names, n); } void LX200AstroPhysics::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int err=0; // ignore if not ours // if (strcmp (thisDevice, dev)) return; // ======================================= // Connect // ======================================= if (!strcmp (name, ConnectSP.name)) { IUUpdateSwitch(&ConnectSP, states, names, n) ; connectTelescope(); return; } // ============================================================ // Satisfy AP mount initialization, see AP key pad manual p. 76 // ============================================================ if (!strcmp (name, StartUpSP.name)) { int ret ; int switch_nr ; static int mount_status= MOUNTNOTINITIALIZED ; IUUpdateSwitch(&StartUpSP, states, names, n) ; if( mount_status == MOUNTNOTINITIALIZED) { mount_status=MOUNTINITIALIZED; if(( ret= setBasicDataPart0())< 0) { // ToDo do something if needed StartUpSP.s = IPS_ALERT ; IDSetSwitch(&StartUpSP, "Mount initialization failed") ; return ; } if( StartUpSP.sp[0].s== ISS_ON) // do it only in case a power on (cold start) { if(( ret= setBasicDataPart1())< 0) { // ToDo do something if needed StartUpSP.s = IPS_ALERT ; IDSetSwitch(&StartUpSP, "Mount initialization failed") ; return ; } } // Make sure that the mount is setup according to the properties switch_nr = getOnSwitch(&TrackModeSP); if ( ( err = selectAPTrackingMode(fd, switch_nr) < 0) ) { handleError(&TrackModeSP, err, "StartUpSP: Setting tracking mode."); return; } TrackModeSP.s = IPS_OK; IDSetSwitch(&TrackModeSP, NULL); //ToDo set button swapping acording telescope east west // ... some code here switch_nr = getOnSwitch(&MoveToRateSP); if ( ( err = selectAPMoveToRate(fd, switch_nr) < 0) ) { handleError(&MoveToRateSP, err, "StartUpSP: Setting move to rate."); return; } MoveToRateSP.s = IPS_OK; IDSetSwitch(&MoveToRateSP, NULL); switch_nr = getOnSwitch(&SlewRateSP); if ( ( err = selectAPSlewRate(fd, switch_nr) < 0) ) { handleError(&SlewRateSP, err, "StartUpSP: Setting slew rate."); return; } SlewRateSP.s = IPS_OK; IDSetSwitch(&SlewRateSP, NULL); StartUpSP.s = IPS_OK ; IDSetSwitch(&StartUpSP, "Mount initialized") ; // Fetch the coordinates and set RNP and WNP getLX200RA( fd, ¤tRA); getLX200DEC(fd, ¤tDEC); // make a IDSet in order the dome controller is aware of the initial values targetRA= currentRA ; targetDEC= currentDEC ; EquatorialCoordsRNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */ IDSetNumber(&EquatorialCoordsRNP, "EquatorialCoordsWNP.s = IPS_BUSY after initialization"); // sleep for 100 mseconds usleep(100000); EquatorialCoordsRNP.s = IPS_OK; IDSetNumber(&EquatorialCoordsRNP, NULL); getLX200Az(fd, ¤tAZ); getLX200Alt(fd, ¤tALT); HorizontalCoordsRNP.s = IPS_OK ; IDSetNumber (&HorizontalCoordsRNP, NULL); VersionInfo.tp[0].text = new char[64]; getAPVersionNumber(fd, VersionInfo.tp[0].text); VersionInfo.s = IPS_OK ; IDSetText(&VersionInfo, NULL); if(( getOnSwitch(&DomeControlSP))== DOMECONTROL) { //ToDo compare that with other driver, not the best way IDSnoopDevice( MasterAlarmODTP.tp[0].text, MasterAlarmODTP.tp[1].text); MasterAlarmODTP.s= IPS_OK ; IDSetText (&MasterAlarmODTP, "SNOOPing %s on device %s", MasterAlarmODTP.tp[1].text, MasterAlarmODTP.tp[0].text); IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text); ConnectionDCODTP.s= IPS_OK ; IDSetText (&ConnectionDCODTP, "SNOOPing %s on device %s", ConnectionDCODTP.tp[1].text, ConnectionDCODTP.tp[0].text); IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text); IDSnoopDevice( ModeDCODTP.tp[0].text, ModeDCODTP.tp[1].text); ModeDCODTP.s= IPS_OK ; IDSetText (&ModeDCODTP, "SNOOPing %s on device %s", ModeDCODTP.tp[1].text, ModeDCODTP.tp[0].text); // once chosen no unsnooping is possible DomeControlSP.s= IPS_OK ; IDSetSwitch(&DomeControlSP, NULL) ; } else { IDMessage( myapdev, "Not operating in dome control mode") ; } #ifndef HAVE_NOVA_H IDMessage( myapdev, "Libnova not compiled in, consider to install it (http://libnova.sourceforge.net/)") ; #endif #ifndef HAVE_NOVASCC_H IDMessage( myapdev, "NOVASCC not compiled in, consider to install it (http://aa.usno.navy.mil/AA/)") ; #endif } else { StartUpSP.s = IPS_ALERT ; IDSetSwitch(&StartUpSP, "Mount is already initialized") ; } return; } // ======================================= // Park // ======================================= if (!strcmp(name, ParkSP.name)) { if (checkPower(&ParkSP)) return; if (EquatorialCoordsRNP.s == IPS_BUSY) { // ToDo handle return value abortSlew(fd); // sleep for 200 mseconds usleep(200000); AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); } if (setAPPark(fd) < 0) { ParkSP.s = IPS_ALERT; IDSetSwitch(&ParkSP, "Parking Failed."); return; } ParkSP.s = IPS_OK; IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting..."); // avoid sending anything to the mount controller tty_disconnect( fd); ConnectSP.s = IPS_IDLE; ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; IDSetSwitch(&ConnectSP, NULL); StartUpSP.s = IPS_IDLE ; IDSetSwitch(&StartUpSP, NULL) ; // ToDo reset all values return; } // ======================================= // Tracking Mode // ======================================= if (!strcmp (name, TrackModeSP.name)) { if (checkPower(&TrackModeSP)) return; IUResetSwitch(&TrackModeSP); IUUpdateSwitch(&TrackModeSP, states, names, n); trackingMode = getOnSwitch(&TrackModeSP); if ( ( err = selectAPTrackingMode(fd, trackingMode) < 0) ) { handleError(&TrackModeSP, err, "Setting tracking mode."); return; } TrackModeSP.s = IPS_OK; IDSetSwitch(&TrackModeSP, NULL); if( trackingMode != 3) /* not zero */ { AbortSlewSP.s = IPS_IDLE; IDSetSwitch(&AbortSlewSP, NULL); } return; } // ======================================= // Swap Buttons // ======================================= if (!strcmp(name, SwapSP.name)) { int currentSwap ; if (checkPower(&SwapSP)) return; IUResetSwitch(&SwapSP); IUUpdateSwitch(&SwapSP, states, names, n); currentSwap = getOnSwitch(&SwapSP); if(( err = swapAPButtons(fd, currentSwap) < 0) ) { handleError(&SwapSP, err, "Swapping buttons."); return; } SwapS[0].s= ISS_OFF ; SwapS[1].s= ISS_OFF ; SwapSP.s = IPS_OK; IDSetSwitch(&SwapSP, NULL); return ; } // ======================================= // Swap to rate // ======================================= if (!strcmp (name, MoveToRateSP.name)) { int moveToRate ; if (checkPower(&MoveToRateSP)) return; IUResetSwitch(&MoveToRateSP); IUUpdateSwitch(&MoveToRateSP, states, names, n); moveToRate = getOnSwitch(&MoveToRateSP); if ( ( err = selectAPMoveToRate(fd, moveToRate) < 0) ) { handleError(&MoveToRateSP, err, "Setting move to rate."); return; } MoveToRateSP.s = IPS_OK; IDSetSwitch(&MoveToRateSP, NULL); return; } // ======================================= // Slew Rate // ======================================= if (!strcmp (name, SlewRateSP.name)) { int slewRate ; if (checkPower(&SlewRateSP)) return; IUResetSwitch(&SlewRateSP); IUUpdateSwitch(&SlewRateSP, states, names, n); slewRate = getOnSwitch(&SlewRateSP); if ( ( err = selectAPSlewRate(fd, slewRate) < 0) ) { handleError(&SlewRateSP, err, "Setting slew rate."); return; } SlewRateSP.s = IPS_OK; IDSetSwitch(&SlewRateSP, NULL); return; } // ======================================= // Choose the appropriate sync command // ======================================= if (!strcmp(name, SyncCMRSP.name)) { int currentSync ; if (checkPower(&SyncCMRSP)) return; IUResetSwitch(&SyncCMRSP); IUUpdateSwitch(&SyncCMRSP, states, names, n); currentSync = getOnSwitch(&SyncCMRSP); SyncCMRSP.s = IPS_OK; IDSetSwitch(&SyncCMRSP, NULL); return ; } #if defined HAVE_NOVA_H || defined HAVE_NOVASCC_H // ======================================= // Set various transformations // ======================================= if (!strcmp (name, ApparentToObservedSP.name)) { int trans_to ; if (checkPower(&ApparentToObservedSP)) return; IUResetSwitch(&ApparentToObservedSP); IUUpdateSwitch(&ApparentToObservedSP, states, names, n); trans_to = getOnSwitch(&ApparentToObservedSP); ApparentToObservedSP.s = IPS_OK; IDSetSwitch(&ApparentToObservedSP, "Transformation %d", trans_to); return; } #endif if (!strcmp (name, DomeControlSP.name)) { if((DomeControlSP.s== IPS_OK) &&( DomeControlSP.sp[0].s== ISS_ON)) { #ifdef INDI_DEBUG IDLog("Once in dome control mode no return is possible (INDI has no \"unsnoop\")\n") ; #endif DomeControlSP.s= IPS_ALERT ; IDSetSwitch(&DomeControlSP, "Once in dome control mode no return is possible (INDI has no \"unsnoop\")") ; } else { int last_state= getOnSwitch(&DomeControlSP) ; IUResetSwitch(&DomeControlSP); IUUpdateSwitch(&DomeControlSP, states, names, n) ; DomeControlSP.s= IPS_OK ; IDSetSwitch(&DomeControlSP, NULL) ; if(( DomeControlSP.s== IPS_OK) &&( last_state== NOTDOMECONTROL)) /* dome control mode after mount init. */ { //ToDo compare that with other driver, not the best way IDSnoopDevice( MasterAlarmODTP.tp[0].text, MasterAlarmODTP.tp[1].text); MasterAlarmODTP.s= IPS_OK ; IDSetText (&MasterAlarmODTP, "SNOOPing %s on device %s", MasterAlarmODTP.tp[1].text, MasterAlarmODTP.tp[0].text); IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text); ConnectionDCODTP.s= IPS_OK ; IDSetText (&ConnectionDCODTP, "SNOOPing %s on device %s", ConnectionDCODTP.tp[1].text, ConnectionDCODTP.tp[0].text); IDSnoopDevice( ConnectionDCODTP.tp[0].text, ConnectionDCODTP.tp[1].text); IDSnoopDevice( ModeDCODTP.tp[0].text, ModeDCODTP.tp[1].text); ModeDCODTP.s= IPS_OK ; IDSetText (&ModeDCODTP, "SNOOPing %s on device %s", ModeDCODTP.tp[1].text, ModeDCODTP.tp[0].text); } } return; } LX200GenericLegacy::ISNewSwitch (dev, name, states, names, n); } void LX200AstroPhysics::ISSnoopDevice (XMLEle *root) { int err ; if (IUSnoopSwitch(root, &MasterAlarmSP) == 0) { //IDMessage( myapdev, "ISCollisionStatusS received new values %s: %d, %s: %d, %s: %d.", names[0], states[0],names[1], states[1],names[2], states[2]); if( MasterAlarmS[1].s == ISS_ON) /* Approaching a critical situation */ { /* Stop if possible any motion */ // ToDo abortSlew(fd); AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */ { IDMessage( myapdev, "FAILED: Setting tracking mode ZERO."); return; } IUResetSwitch(&TrackModeSP); TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */ TrackModeSP.sp[1].s= ISS_OFF ; /* solar */ TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */ TrackModeSP.sp[3].s= ISS_ON ; /* zero */ TrackModeSP.s = IPS_ALERT; IDSetSwitch(&TrackModeSP, "Device %s MasterAlarm OFF: approaching a critical situation, avoided by apmount, stopped motors, no tracking!", MasterAlarmODT[0].text); } else if( MasterAlarmS[2].s == ISS_ON) /* a critical situation */ { /* If Master Alarm is on it is "too" late. So we do the same as under MasterAlarmS[1].s == ISS_ON*/ /* The device setting up the Master Alarm should switch power off*/ // ToDo abortSlew(fd); AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */ { IDMessage( myapdev, "FAILED: Setting tracking mode ZERO."); return; } IUResetSwitch(&TrackModeSP); TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */ TrackModeSP.sp[1].s= ISS_OFF ; /* solar */ TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */ TrackModeSP.sp[3].s= ISS_ON ; /* zero */ TrackModeSP.s = IPS_ALERT; IDSetSwitch(&TrackModeSP, "Device %s MasterAlarm ON: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text); } else if((MasterAlarmS[2].s == ISS_OFF) && (MasterAlarmS[1].s == ISS_OFF) && (MasterAlarmS[0].s == ISS_OFF)) { //ToDo make the mastar alarm indicator more visible!! TrackModeSP.s = IPS_OK; IDSetSwitch(&TrackModeSP, "MasterAlarm Status ok"); // values obtained via ISPoll IDSetNumber(&EquatorialCoordsRNP, "Setting (sending) EquatorialCoordsRNP on reset MasterAlarm"); } else { if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */ { IDMessage( myapdev, "FAILED: Setting tracking mode ZERO."); return; } IUResetSwitch(&TrackModeSP); TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */ TrackModeSP.sp[1].s= ISS_OFF ; /* solar */ TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */ TrackModeSP.sp[3].s= ISS_ON ; /* zero */ TrackModeSP.s = IPS_ALERT; TrackModeSP.s = IPS_ALERT; IDSetSwitch(&TrackModeSP, "Device %s MASTER ALARM Unknown Status", MasterAlarmODT[0].text); } } else if (IUSnoopSwitch(root, &ConnectionDCSP) == 0) { if( ConnectionDCS[0].s != ISS_ON) { // ToDo abortSlew(fd); AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); if ( ( err = selectAPTrackingMode(fd, 3) < 0) ) /* Tracking Mode 3 = zero */ { IDMessage( myapdev, "FAILED: Setting tracking mode ZERO."); return; } IUResetSwitch(&TrackModeSP); TrackModeSP.sp[0].s= ISS_OFF ; /* lunar */ TrackModeSP.sp[1].s= ISS_OFF ; /* solar */ TrackModeSP.sp[2].s= ISS_OFF ; /* sidereal */ TrackModeSP.sp[3].s= ISS_ON ; /* zero */ TrackModeSP.s = IPS_ALERT; IDSetSwitch(&TrackModeSP, "Driver %s disconnected: critical situation avoided, stopped motors, no tracking!", MasterAlarmODT[0].text); } } else if (IUSnoopSwitch(root, &ModeSP) == 0) { if( ModeS[1].s == ISS_ON) /* late dome control mode */ { getLX200RA( fd, ¤tRA); getLX200DEC(fd, ¤tDEC); targetRA= currentRA ; targetDEC= currentDEC ; EquatorialCoordsRNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */ IDSetNumber(&EquatorialCoordsRNP, "Setting (sending) EquatorialCoordsRNP on ModeS[1].s != ISS_ON"); // sleep for 100 mseconds usleep(100000); EquatorialCoordsRNP.s = IPS_OK; IDSetNumber(&EquatorialCoordsRNP, NULL) ; } } } bool LX200AstroPhysics::isMountInit(void) { return (StartUpSP.s != IPS_IDLE); } void LX200AstroPhysics::ISPoll() { int ret ; // int ddd, mm ; if (!isMountInit()) return; // #ifdef INDI_DEBUG // getSiteLongitude(fd, &ddd, &mm) ; // IDLog("longitude %d:%d\n", ddd, mm); // getSiteLatitude(fd, &ddd, &mm) ; // IDLog("latitude %d:%d\n", ddd, mm); // getAPUTCOffset( fd, &APUTCOffsetN[0].value) ; // IDLog("UTC offset %10.6f\n", APUTCOffsetN[0].value); // #endif //============================================================ // #1 Call LX200GenericLegacy ISPoll //============================================================ LX200GenericLegacy::ISPoll(); //============================================================ // #2 Get Local Time //============================================================ if(( ret= getLocalTime24( fd, &APLocalTimeN[0].value)) == 0) { APLocalTimeNP.s = IPS_OK ; } else { APLocalTimeNP.s = IPS_ALERT ; } IDSetNumber(&APLocalTimeNP, NULL); // #ifdef INDI_DEBUG // IDLog("localtime %f\n", APLocalTimeN[0].value) ; // #endif //============================================================ // #3 Get Sidereal Time //============================================================ if(( ret= getSDTime( fd, &APSiderealTimeN[0].value)) == 0) { APSiderealTimeNP.s = IPS_OK ; } else { APSiderealTimeNP.s = IPS_ALERT ; } IDSetNumber(&APSiderealTimeNP, NULL); // #ifdef INDI_DEBUG // IDLog("siderealtime %f\n", APSiderealTimeN[0].value) ; // #endif //============================================================ // #4 Get UTC Offset //============================================================ if(( ret= getAPUTCOffset( fd, &APUTCOffsetN[0].value)) == 0) { APUTCOffsetNP.s = IPS_OK ; } else { APUTCOffsetNP.s = IPS_ALERT ; } IDSetNumber(&APUTCOffsetNP, NULL); //============================================================ // #5 //============================================================ if(( ret= getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) == 0) { DeclinationAxisTP.s = IPS_OK ; } else { DeclinationAxisTP.s = IPS_ALERT ; } IDSetText(&DeclinationAxisTP, NULL) ; /* LX200GenericLegacy should take care of this */ //getLX200RA(fd, ¤tRA ); //getLX200DEC(fd, ¤tDEC ); //EquatorialCoordsRNP.s = IPS_OK ; //IDSetNumber (&EquatorialCoordsRNP, NULL); /* Calculate the hour angle */ HourangleCoordsNP.np[0].value= 180. /M_PI/15. * LDRAtoHA( 15.* currentRA /180. *M_PI, -geoNP.np[1].value/180. *M_PI); HourangleCoordsNP.np[1].value= currentDEC; HourangleCoordsNP.s = IPS_OK; IDSetNumber(&HourangleCoordsNP, NULL); getLX200Az(fd, ¤tAZ); getLX200Alt(fd, ¤tALT); /* The state of RNP is coupled to the WNP HorizontalCoordsRNP.s = IPS_OK ; IDSetNumber (&HorizontalCoordsRNP, NULL); */ // LX200GenericLegacy has no HorizontalCoords(R|W)NP if( HorizontalCoordsRNP.s == IPS_BUSY) /* telescope is syncing or slewing */ { double dx = fabs ( targetAZ - currentAZ); double dy = fabs ( targetALT - currentALT); if (dx <= (SlewAccuracyNP.np[0].value/(60.0*15.0)) && (dy <= SlewAccuracyNP.np[1].value/60.0)) { #ifdef INDI_DEBUG IDLog("Slew completed.\n"); #endif HorizontalCoordsRNP.s = IPS_OK ; IDSetNumber(&HorizontalCoordsRNP, "Slew completed") ; } else { #ifdef INDI_DEBUG IDLog("Slew in progress.\n"); #endif } } if(StartUpSP.s== IPS_OK) /* the dome controller needs to be informed even in case dc has been started long after lx200ap*/ { StartUpSP.s = IPS_OK ; IDSetSwitch(&StartUpSP, NULL) ; } else { StartUpSP.s = IPS_ALERT ; IDSetSwitch(&StartUpSP, NULL) ; } } int LX200AstroPhysics::setBasicDataPart0() { int err ; #ifdef HAVE_NOVA_H struct ln_date utm; struct ln_zonedate ltm; #endif if(setAPClearBuffer( fd) < 0) { handleError(&ConnectSP, err, "Clearing the buffer"); return -1; } if(setAPLongFormat( fd) < 0) { IDMessage( myapdev, "Setting long format failed") ; return -1; } // ToDo make a property if(setAPBackLashCompensation(fd, 0,0,0) < 0) { handleError(&ConnectSP, err, "Setting back lash compensation"); return -1; } #if defined HAVE_NOVA_H ln_get_date_from_sys( &utm) ; ln_date_to_zonedate(&utm, <m, 3600); if(( err = setLocalTime(fd, ltm.hours, ltm.minutes, (int) ltm.seconds) < 0)) { handleError(&ConnectSP, err, "Setting local time"); return -1; } if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) ) { handleError(&ConnectSP, err, "Setting local date"); return -1; } #ifdef INDI_DEBUG IDLog("UT time is: %04d/%02d/%02d T %02d:%02d:%02d\n", utm.years, utm.months, utm.days, utm.hours, utm.minutes, (int)utm.seconds); IDLog("Local time is: %04d/%02d/%02d T %02d:%02d:%02d\n", ltm.years, ltm.months, ltm.days, ltm.hours, ltm.minutes, (int)ltm.seconds); #endif // ToDo: strange but true offset 22:56:07, -1:03:53 (valid for obs Vermes) // Understand what happens with AP controller sidereal time, azimut coordinates if((err = setAPUTCOffset( fd, -1.0647222)) < 0) { handleError(&ConnectSP, err,"Setting AP UTC offset") ; return -1; } #else IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ; #endif return 0 ; } int LX200AstroPhysics::setBasicDataPart1() { int err ; if((err = setAPUnPark( fd)) < 0) { handleError(&ConnectSP, err,"Unparking failed") ; return -1; } #ifdef INDI_DEBUG IDLog("Unparking successful\n"); #endif if((err = setAPMotionStop( fd)) < 0) { handleError(&ConnectSP, err, "Stop motion (:Q#) failed, check the mount") ; return -1; } #ifdef INDI_DEBUG IDLog("Stopped any motion (:Q#)\n"); #endif return 0 ; } void LX200AstroPhysics::connectTelescope() { static int established= NOTESTABLISHED ; switch (ConnectSP.sp[0].s) { case ISS_ON: if( ! established) { if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) { ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text); established= NOTESTABLISHED ; return; } if (check_lx200ap_connection(fd)) { ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); established= NOTESTABLISHED ; return; } established= ESTABLISHED ; #ifdef INDI_DEBUG IDLog("Telescope test successful\n"); #endif // At this point e.g. no GEOGRAPHIC_COORD are available after the first client connects. // Postpone set up of the telescope // NO setBasicData() ; // ToDo what is that *((int *) UTCOffsetN[0].aux0) = 0; // Jasem: This is just a way to know if the client has init UTC Offset, and if he did, then we set aux0 to 1, otherwise it stays at 0. When // the client tries to change UTC, but has not set UTFOffset yet (that is, aux0 = 0) then we can tell him to set the UTCOffset first. Btw, // the UTF & UTFOffset will be merged in one property for INDI v0.6 ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Telescope is online"); } else { ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Connection already established."); } break; case ISS_OFF: ConnectSP.sp[0].s = ISS_OFF; ConnectSP.sp[1].s = ISS_ON; ConnectSP.s = IPS_IDLE; IDSetSwitch (&ConnectSP, "Telescope is offline."); if (setAPPark(fd) < 0) { ParkSP.s = IPS_ALERT; IDSetSwitch(&ParkSP, "Parking Failed."); return; } ParkSP.s = IPS_OK; IDSetSwitch(&ParkSP, "The telescope is parked. Turn off the telescope. Disconnecting..."); tty_disconnect(fd); established= NOTESTABLISHED ; #ifdef INDI_DEBUG IDLog("The telescope is parked. Turn off the telescope. Disconnected.\n"); #endif break; } } // taken from lx200_16 void LX200AstroPhysics::handleAltAzSlew() { int i=0; char altStr[64], azStr[64]; if (HorizontalCoordsRNP.s == IPS_BUSY) { abortSlew(fd); AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); // sleep for 100 mseconds usleep(100000); } // ToDo is it ok ? // if ((i = slewToAltAz(fd))) if ((i = Slew(fd))) { HorizontalCoordsRNP.s = IPS_ALERT; IDSetNumber(&HorizontalCoordsRNP, "Slew is not possible."); return; } HorizontalCoordsRNP.s = IPS_OK; fs_sexa(azStr, targetAZ, 2, 3600); fs_sexa(altStr, targetALT, 2, 3600); IDSetNumber(&HorizontalCoordsRNP, "Slewing to Alt %s - Az %s", altStr, azStr); return; } void LX200AstroPhysics::handleEqCoordSet() { int sync ; int err; char syncString[256]; char RAStr[32], DecStr[32]; double dx, dy; int syncOK= 0 ; double targetHA ; #ifdef INDI_DEBUG IDLog("In Handle AP EQ Coord Set(), switch %d\n", getOnSwitch(&OnCoordSetSP)); #endif switch (getOnSwitch(&OnCoordSetSP)) { // Slew case LX200_TRACK: lastSet = LX200_TRACK; if (EquatorialCoordsRNP.s == IPS_BUSY) { #ifdef INDI_DEBUG IDLog("Aborting Track\n"); #endif // ToDo abortSlew(fd); AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); // sleep for 100 mseconds usleep(100000); } if ((err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */ { slewError(err); // ToDo handle that with the handleError function return ; } EquatorialCoordsRNP.s = IPS_BUSY; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); #ifdef INDI_DEBUG IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); #endif break; // Sync case LX200_SYNC: lastSet = LX200_SYNC; /* Astro-Physics has two sync options. In order that no collision occurs, the SYNCCMR */ /* variant behaves for now identical like SYNCCM. Later this feature will be enabled.*/ /* Calculate the hour angle of the target */ targetHA= 180. /M_PI/15. * LDRAtoHA( 15.* targetRA/180. *M_PI, -geoNP.np[1].value/180. *M_PI); if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR) { if (!strcmp("West", DeclinationAxisT[0].text)) { if(( targetHA > 12.0) && ( targetHA <= 24.0)) { syncOK= 1 ; } else { syncOK= 0 ; } } else if (!strcmp("East", DeclinationAxisT[0].text)) { if(( targetHA >= 0.0) && ( targetHA <= 12.0)) { syncOK= 1 ; } else { syncOK= 0 ; } } else { #ifdef INDI_DEBUG IDLog("handleEqCoordSet(): SYNC NOK not East or West\n") ; #endif return ; } } else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCM) { syncOK = 1 ; } else { #ifdef INDI_DEBUG IDLog("handleEqCoordSet(): SYNC NOK not SYNCCM or SYNCCMR\n") ; #endif return ; } if( syncOK == 1) { if( (sync=getOnSwitch(&SyncCMRSP))==SYNCCM) { if ( ( err = APSyncCM(fd, syncString) < 0) ) { EquatorialCoordsRNP.s = IPS_ALERT ; IDSetNumber( &EquatorialCoordsRNP , "Synchronization failed."); // ToDo handle with handleError function return ; } } else if((sync=getOnSwitch(&SyncCMRSP))==SYNCCMR) { if ( ( err = APSyncCMR(fd, syncString) < 0) ) { EquatorialCoordsRNP.s = IPS_ALERT ; IDSetNumber( &EquatorialCoordsRNP, "Synchronization failed."); // ToDo handle with handleError function return ; } } else { EquatorialCoordsRNP.s = IPS_ALERT ; IDSetNumber( &EquatorialCoordsRNP , "SYNC NOK no valid SYNCCM, SYNCCMR"); #ifdef INDI_DEBUG IDLog("SYNC NOK no valid SYNCCM, SYNCCMR\n") ; #endif return ; } /* get the property DeclinationAxisTP first */ if(( err = getAPDeclinationAxis( fd, DeclinationAxisT[0].text)) < 0) { //ToDo handleErr DeclinationAxisTP.s = IPS_ALERT ; IDSetText(&DeclinationAxisTP, "Declination axis undefined") ; return ; } DeclinationAxisTP.s = IPS_OK ; #ifdef INDI_DEBUG IDLog("Declination axis is on the %s side\n", DeclinationAxisT[0].text) ; #endif IDSetText(&DeclinationAxisTP, NULL) ; getLX200RA( fd, ¤tRA); getLX200DEC(fd, ¤tDEC); // The mount executed the sync command, now read back the values, make a IDSet in order the dome controller // is aware of the new target targetRA= currentRA ; targetDEC= currentDEC ; EquatorialCoordsRNP.s = IPS_BUSY; /* dome controller sets target only if this state is busy */ IDSetNumber(&EquatorialCoordsRNP, "EquatorialCoordsWNP.s = IPS_BUSY after SYNC"); } else { #ifdef INDI_DEBUG IDLog("Synchronization not allowed\n") ; #endif EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, "Synchronization not allowed" ); #ifdef INDI_DEBUG IDLog("Telescope is on the wrong side targetHA was %f\n", targetHA) ; #endif DeclinationAxisTP.s = IPS_ALERT ; IDSetText(&DeclinationAxisTP, "Telescope is on the wrong side targetHA was %f", targetHA) ; return ; } #ifdef INDI_DEBUG IDLog("Synchronization successful >%s<\n", syncString); #endif EquatorialCoordsRNP.s = IPS_OK; /* see above for dome controller dc */ IDSetNumber(&EquatorialCoordsRNP, "Synchronization successful, EquatorialCoordsWNP.s = IPS_OK after SYNC"); break; } return ; } // ToDo Not yet used void LX200AstroPhysics::handleAZCoordSet() { int err; char AZStr[32], AltStr[32]; switch (getOnSwitch(&OnCoordSetSP)) { // Slew case LX200_TRACK: lastSet = LX200_TRACK; if (HorizontalCoordsRNP.s == IPS_BUSY) { #ifdef INDI_DEBUG IDLog("Aborting Slew\n"); #endif // ToDo abortSlew(fd); AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); // sleep for 100 mseconds usleep(100000); } if ((err = Slew(fd))) { slewError(err); //ToDo handle it return ; } HorizontalCoordsRNP.s = IPS_BUSY; fs_sexa(AZStr, targetAZ, 2, 3600); fs_sexa(AltStr, targetALT, 2, 3600); IDSetNumber(&HorizontalCoordsRNP, "Slewing to AZ %s - Alt %s", AZStr, AltStr); #ifdef INDI_DEBUG IDLog("Slewing to AZ %s - Alt %s\n", AZStr, AltStr); #endif break; // Sync /* ToDo DO SYNC */ case LX200_SYNC: IDMessage( myapdev, "Sync not supported in ALT/AZ mode") ; break; } } /*********Library Section**************/ /*********Library Section**************/ /*********Library Section**************/ /*********Library Section**************/ double LDRAtoHA( double RA, double longitude) { #ifdef HAVE_NOVA_H double HA ; double JD ; double theta_0= 0. ; JD= ln_get_julian_from_sys() ; // #ifdef INDI_DEBUG // IDLog("LDRAtoHA: JD %f\n", JD); // #endif theta_0= 15. * ln_get_mean_sidereal_time( JD) ; // #ifdef INDI_DEBUG // IDLog("LDRAtoHA:1 theta_0 %f\n", theta_0); // #endif theta_0= fmod( theta_0, 360.) ; theta_0= theta_0 /180. * M_PI ; HA = fmod(theta_0 - longitude - RA, 2. * M_PI) ; if( HA < 0.) { HA += 2. * M_PI ; } return HA ; #else IDMessage( myapdev, "Initialize %s manually or install libnova", myapdev) ; return 0 ; #endif } // Transformation from apparent to various coordinate systems int LDAppToX( int trans_to, double *star_cat, double tjd, double *loc, double *hxt, double *star_trans) { #if defined HAVE_NOVASCC_H short int error = 0; /* 'deltat' is the difference in time scales, TT - UT1. */ double deltat = 60.0; double gst ; /* Set x,y in case where sub arcsec precission is required */ double x=0. ; double y=0. ; short int ref_option ; double ra_ar, dec_ar; /* apparent and refracted EQ coordinate system */ double az_ar, zd_ar ; /* apparent and refracted, AltAz coordinate system */ double ra_art, dec_art ; /* apparent, refracted and telescope EQ coordinate system */ double ha_ar ; double ha_art ; cat_entry star = {"FK5", "NONAME", 0, star_cat[0], star_cat[1], 0., 0., 0., 0.}; site_info geo_loc= {loc[0], loc[1], loc[2], loc[3], loc[4]} ; /* A structure containing the body designation for Earth.*/ body earth ; /* Set up the structure containing the body designation for Earth. */ if ((error = set_body (0,3,"Earth", &earth))) { IDMessage( myapdev, "LDAppToX: Error %d from set_body.\n", error); return -1; } switch (trans_to) { case ATA: /* identity */ star_trans[0]= star.ra ; star_trans[1]= star.dec ; break ; case ATR: /* T4, apparent to refracted */ /* Alt Azimut refraction */ ref_option= 2 ; /* Set x,y in case where sub arcsec precission is required */ equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ; if(ra_ar <0.) { ra_ar += 24. ; } star_trans[0]= ra_ar ; star_trans[1]= dec_ar ; break ; case ARTT: /* T4, apparent, refracted to telescope */ /* Alt Azimut refraction */ ref_option= 2 ; /* Set x,y in case where sub arcsec precission is required */ equ2hor(tjd, deltat, x, y, &geo_loc, star.ra, star.dec, ref_option, &zd_ar, &az_ar, &ra_ar, &dec_ar) ; /* Calculate the apparent refracted hour angle */ ha_ar= (gst + geo_loc.longitude/180. * 12. - ra_ar) ; if( ha_ar < 0.) { ha_ar += 24. ; } /* Equatorial system of the telescope, these are ra_art, dec_art needed for the setting */ /* To be defined: sign of rotation theta= -7.5 ; */ /* The values of hxt are defined in the local hour system, ha [hour]*/ if(( error= LDEqToEqT( ha_ar, dec_ar, hxt, &ha_art, &dec_art)) != 0) { IDMessage( myapdev, "LDAppToX: \nError in calculation\n\n"); return -1 ; } ra_art = -ha_art + gst + geo_loc.longitude/180. * 12. ; if(ra_art <0.) { ra_art += 24. ; } star_trans[0]= ra_art ; star_trans[1]= dec_art ; break ; case ARTTO: /* T5, apparent, refracted, telescope to observed*/ IDMessage( myapdev, "LDAppToX: Not yet implemented, exiting...\n") ; return -1; break ; default: IDMessage(myapdev, "LDAppToX: No default, exiting\n") ; return -1; } return 0; #elif defined HAVE_NOVA_H IDMessage( myapdev, "Only identity transformation is supported without HAVE_NOVASCC_H") ; star_trans[0]= star_cat[0]; star_trans[1]= star_cat[1]; return 0 ; #else IDMessage( myapdev, "Install libnova to use this feature") ; // we never get here return 0 ; #endif } // Trans form to the ideal telescope coordinate system (no mount defects) int LDEqToEqT( double ra_h, double dec_d, double *hxt, double *rat_h, double *dect_d) { int res ; int i,j; double ra = ra_h / 12. * M_PI ; /* novas-c unit is hour */ double dec= dec_d/180. * M_PI ; double theta= hxt[0]/180. * M_PI ; double gamma= hxt[1]/180. * M_PI ; double unit_vector_in[3]= {cos(dec)*cos(ra), cos(dec)*sin(ra), sin(dec)} ; double unit_vector_rot[3]= {0.,0.,0.} ; double unit_vector_tmp[3]= {0.,0.,0.} ; double rat ; double dect ; /* theta rotation around polar axis, gamma around y axis */ double rotation[3][3]= { {cos(gamma)*cos(theta),-(cos(gamma)*sin(theta)),-sin(gamma)}, {sin(theta),cos(theta),0}, {cos(theta)*sin(gamma),-(sin(gamma)*sin(theta)), cos(gamma)} } ; /* minus theta rotation around telescope polar axis */ /* Despite the above matrix is correct, no body has a telescope */ /* with fixed setting circles in RA - or a telescope is usually */ /* calibrated in RA/HA by choosing one star. The matrix below */ /* takes that into account */ double rotation_minus_theta[3][3]= { { cos(theta), sin(theta), 0.}, {-sin(theta), cos(theta), 0.}, { 0., 0., 1.} } ; unit_vector_in[0]= cos(dec)*cos(ra) ; unit_vector_in[1]= cos(dec)*sin(ra) ; unit_vector_in[2]= sin(dec) ; if( gamma < 0 ) { IDMessage(myapdev, "LDEqToEqT: gamma is the distance from the celestial pole and always positive\n") ; return -1 ; } for( i=0; i < 3 ; i++) { for( j=0; j < 3 ; j++) { unit_vector_tmp[i] += rotation[i][j] * unit_vector_in[j] ; } } for( i=0; i < 3 ; i++) { for( j=0; j < 3 ; j++) { unit_vector_rot[i] += rotation_minus_theta[i][j] * unit_vector_tmp[j] ; } } if(( res= LDCartToSph( unit_vector_rot, &rat, &dect))!= 0) { return -1 ; } else { *rat_h = rat /M_PI * 12. ; *dect_d= dect/M_PI * 180. ; return 0 ; } } int LDCartToSph( double *vec, double *ra, double *dec) { if( vec[0] !=0.) { *ra = atan2( vec[1], vec[0]) ; } else { return -1 ; } *dec= asin( vec[2]) ; return 0 ; } libindi-0.9.7/drivers/telescope/lx200driver.h0000644000175000017500000002474712241463551020035 0ustar jasemjasem/* LX200 Driver Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef LX200DRIVER_H #define LX200DRIVER_H /* Slew speeds */ enum TSlew { LX200_SLEW_MAX, LX200_SLEW_FIND, LX200_SLEW_CENTER, LX200_SLEW_GUIDE}; /* Alignment modes */ enum TAlign { LX200_ALIGN_POLAR, LX200_ALIGN_ALTAZ, LX200_ALIGN_LAND }; /* Directions */ enum TDirection { LX200_NORTH, LX200_WEST, LX200_EAST, LX200_SOUTH, LX200_ALL}; /* Formats of Right ascention and Declenation */ enum TFormat { LX200_SHORT_FORMAT, LX200_LONG_FORMAT}; /* Time Format */ enum TTimeFormat { LX200_24, LX200_AM, LX200_PM}; /* Focus operation */ enum TFocusMotion { LX200_FOCUSIN, LX200_FOCUSOUT }; enum TFocusSpeed { LX200_HALTFOCUS = 0, LX200_FOCUSSLOW, LX200_FOCUSFAST}; /* Library catalogs */ enum TCatalog { LX200_STAR_C, LX200_DEEPSKY_C}; /* Frequency mode */ enum StarCatalog { LX200_STAR, LX200_SAO, LX200_GCVS }; /* Deep Sky Catalogs */ enum DeepSkyCatalog { LX200_NGC, LX200_IC, LX200_UGC, LX200_CALDWELL, LX200_ARP, LX200_ABELL, LX200_MESSIER_C}; /* Mount tracking frequency, in Hz */ enum TFreq { LX200_TRACK_DEFAULT, LX200_TRACK_LUNAR, LX200_TRACK_MANUAL}; #define MaxReticleDutyCycle 15 #define MaxFocuserSpeed 4 /* GET formatted sexagisemal value from device, return as double */ #define getLX200RA(fd, x) getCommandSexa(fd, x, "#:GR#") #define getLX200DEC(fd, x) getCommandSexa(fd, x, "#:GD#") #define getObjectRA(fd, x) getCommandSexa(fd, x, "#:Gr#") #define getObjectDEC(fd, x) getCommandSexa(fd, x, "#:Gd#") #define getLocalTime12(fd, x) getCommandSexa(fd, x, "#:Ga#") #define getLocalTime24(fd, x) getCommandSexa(fd, x, "#:GL#") #define getSDTime(fd, x) getCommandSexa(fd, x, "#:GS#") #define getLX200Alt(fd, x) getCommandSexa(fd, x, "#:GA#") #define getLX200Az(fd, x) getCommandSexa(fd, x, "#:GZ#") /* GET String from device and store in supplied buffer x */ #define getObjectInfo(fd, x) getCommandString(fd, x, "#:LI#") #define getVersionDate(fd, x) getCommandString(fd, x, "#:GVD#") #define getVersionTime(fd, x) getCommandString(fd, x, "#:GVT#") #define getFullVersion(fd, x) getCommandString(fd, x, "#:GVF#") #define getVersionNumber(fd, x) getCommandString(fd, x, "#:GVN#") #define getProductName(fd, x) getCommandString(fd, x, "#:GVP#") #define turnGPS_StreamOn(fd) getCommandString(fd, x, "#:gps#") /* GET Int from device and store in supplied pointer to integer x */ #define getUTCOffset(fd, x) getCommandInt(fd, x, "#:GG#") #define getMaxElevationLimit(fd, x) getCommandInt(fd, x, "#:Go#") #define getMinElevationLimit(fd, x) getCommandInt(fd, x, "#:Gh#") /* Generic set, x is an integer */ #define setReticleDutyFlashCycle(fd, x) setCommandInt(fd, x, "#:BD") #define setReticleFlashRate(fd, x) setCommandInt(fd, x, "#:B") #define setFocuserSpeed(fd, x) setCommandInt(fd, x, "#:F") #define setSlewSpeed(fd, x) setCommandInt(fd, x, "#:Sw") /* Set X:Y:Z */ #define setLocalTime(fd, x,y,z) setCommandXYZ(fd, x,y,z, "#:SL") #define setSDTime(fd, x,y,z) setCommandXYZ(fd, x,y,z, "#:SS") /* GPS Specefic */ #define turnGPSOn(fd) write(fd, "#:g+#", 5) #define turnGPSOff(fd) write(fd, "#:g-#", 5) #define alignGPSScope(fd) write(fd, "#:Aa#", 5) #define gpsSleep(fd) write(fd, "#:hN#", 5) #define gpsWakeUp(fd) write(fd, "#:hW#", 5); #define gpsRestart(fd) write(fd, "#:I#", 4); #define updateGPS_System(fd) setStandardProcedure(fd, "#:gT#") #define enableDecAltPec(fd) write(fd, "#:QA+#", 6) #define disableDecAltPec(fd) write(fd, "#:QA-#", 6) #define enableRaAzPec(fd) write(fd, "#:QZ+#", 6) #define disableRaAzPec(fd) write(fd, "#:QZ-#", 6) #define activateAltDecAntiBackSlash(fd) write(fd, "#$BAdd#", 7) #define activateAzRaAntiBackSlash(fd) write(fd, "#$BZdd#", 7) #define SelenographicSync(fd) write(fd, "#:CL#", 5); #define slewToAltAz(fd) setStandardProcedure(fd, "#:MA#") #define toggleTimeFormat(fd) write(fd, "#:H#", 4) #define increaseReticleBrightness(fd) write(fd, "#:B+#", 5) #define decreaseReticleBrightness(fd) write(fd, "#:B-#", 5) #define turnFanOn(fd) write(fd, "#:f+#", 5) #define turnFanOff(fd) write(fd, "#:f-#", 5) #define seekHomeAndSave(fd) write(fd, "#:hS#", 5) #define seekHomeAndSet(fd) write(fd, "#:hF#", 5) #define turnFieldDeRotatorOn(fd) write(fd, "#:r+#", 5) #define turnFieldDeRotatorOff(fd) write(fd, "#:r-#", 5) #define slewToPark(fd) write(fd, "#:hP#", 5) #ifdef __cplusplus extern "C" { #endif /************************************************************************** Basic I/O - OBSELETE **************************************************************************/ /*int openPort(const char *portID); int portRead(char *buf, int nbytes, int timeout); int portWrite(const char * buf); int LX200readOut(int timeout); int Connect(const char* device); void Disconnect();*/ /************************************************************************** Diagnostics **************************************************************************/ char ACK(int fd); /*int testTelescope(); int testAP();*/ int check_lx200_connection(int fd); /************************************************************************** Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure **************************************************************************/ /* Get Double from Sexagisemal */ int getCommandSexa(int fd, double *value, const char *cmd); /* Get String */ int getCommandString(int fd, char *data, const char* cmd); /* Get Int */ int getCommandInt(int fd, int *value, const char* cmd); /* Get tracking frequency */ int getTrackFreq(int fd, double * value); /* Get site Latitude */ int getSiteLatitude(int fd, int *dd, int *mm); /* Get site Longitude */ int getSiteLongitude(int fd, int *ddd, int *mm); /* Get Calender data */ int getCalenderDate(int fd, char *date); /* Get site Name */ int getSiteName(int fd, char *siteName, int siteNum); /* Get Number of Bars */ int getNumberOfBars(int fd, int *value); /* Get Home Search Status */ int getHomeSearchStatus(int fd, int *status); /* Get OTA Temperature */ int getOTATemp(int fd, double * value); /* Get time format: 12 or 24 */ int getTimeFormat(int fd, int *format); /* Get RA, DEC from Sky Commander controller */ int updateSkyCommanderCoord(int fd, double *ra, double *dec); /* Get RA, DEC from Intelliscope/SkyWizard controllers */ int updateIntelliscopeCoord (int fd, double *ra, double *dec); /************************************************************************** Set Commands **************************************************************************/ /* Set Int */ int setCommandInt(int fd, int data, const char *cmd); /* Set Sexigesimal */ int setCommandXYZ(int fd, int x, int y, int z, const char *cmd); /* Common routine for Set commands */ int setStandardProcedure(int fd, const char * writeData); /* Set Slew Mode */ int setSlewMode(int fd, int slewMode); /* Set Alignment mode */ int setAlignmentMode(int fd, unsigned int alignMode); /* Set Object RA */ int setObjectRA(int fd, double ra); /* set Object DEC */ int setObjectDEC(int fd, double dec); /* Set Calender date */ int setCalenderDate(int fd, int dd, int mm, int yy); /* Set UTC offset */ int setUTCOffset(int fd, double hours); /* Set Track Freq */ int setTrackFreq(int fd, double trackF); /* Set current site longitude */ int setSiteLongitude(int fd, double Long); /* Set current site latitude */ int setSiteLatitude(int fd, double Lat); /* Set Object Azimuth */ int setObjAz(int fd, double az); /* Set Object Altitude */ int setObjAlt(int fd, double alt); /* Set site name */ int setSiteName(int fd, char * siteName, int siteNum); /* Set maximum slew rate */ int setMaxSlewRate(int fd, int slewRate); /* Set focuser motion */ int setFocuserMotion(int fd, int motionType); /* SET GPS Focuser raneg (1 to 4) */ int setGPSFocuserSpeed (int fd, int speed); /* Set focuser speed mode */ int setFocuserSpeedMode (int fd, int speedMode); /* Set minimum elevation limit */ int setMinElevationLimit(int fd, int min); /* Set maximum elevation limit */ int setMaxElevationLimit(int fd, int max); /************************************************************************** Motion Commands **************************************************************************/ /* Slew to the selected coordinates */ int Slew(int fd); /* Synchronize to the selected coordinates and return the matching object if any */ int Sync(int fd, char *matchedObject); /* Abort slew in all axes */ int abortSlew(int fd); /* Move into one direction, two valid directions can be stacked */ int MoveTo(int fd, int direction); /* Halt movement in a particular direction */ int HaltMovement(int fd, int direction); /* Select the tracking mode */ int selectTrackingMode(int fd, int trackMode); /* Is Slew complete? 0 if complete, 1 if in progress, otherwise return an error */ int isSlewComplete(int fd); /* 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 **************************************************************************/ /* Ensures LX200 RA/DEC format is long */ int checkLX200Format(int fd); /* Select a site from the LX200 controller */ int selectSite(int fd, int siteNum); /* Select a catalog object */ int selectCatalogObject(int fd, int catalog, int NNNN); /* Select a sub catalog */ int selectSubCatalog(int fd, int catalog, int subCatalog); #ifdef __cplusplus } #endif #endif libindi-0.9.7/drivers/telescope/lx200driver.c0000644000175000017500000011203212241463551020011 0ustar jasemjasem#if 0 LX200 Driver Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include #include "indicom.h" #include "indidevapi.h" #include "lx200driver.h" #ifndef _WIN32 #include #endif #define LX200_TIMEOUT 5 /* FD timeout in seconds */ int controller_format; /************************************************************************** Diagnostics **************************************************************************/ char ACK(int fd); /*int testTelescope(void); int testAP(void);*/ int check_lx200_connection(int fd); /************************************************************************** Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure **************************************************************************/ /* Get Double from Sexagisemal */ int getCommandSexa(int fd, double *value, const char *cmd); /* Get String */ int getCommandString(int fd, char *data, const char* cmd); /* Get Int */ int getCommandInt(int fd, int *value, const char* cmd); /* Get tracking frequency */ int getTrackFreq(int fd, double * value); /* Get site Latitude */ int getSiteLatitude(int fd, int *dd, int *mm); /* Get site Longitude */ int getSiteLongitude(int fd, int *ddd, int *mm); /* Get Calender data */ int getCalenderDate(int fd, char *date); /* Get site Name */ int getSiteName(int fd, char *siteName, int siteNum); /* Get Number of Bars */ int getNumberOfBars(int fd, int *value); /* Get Home Search Status */ int getHomeSearchStatus(int fd, int *status); /* Get OTA Temperature */ int getOTATemp(int fd, double * value); /* Get time format: 12 or 24 */ int getTimeFormat(int fd, int *format); /************************************************************************** Set Commands **************************************************************************/ /* Set Int */ int setCommandInt(int fd, int data, const char *cmd); /* Set Sexigesimal */ int setCommandXYZ(int fd, int x, int y, int z, const char *cmd); /* Common routine for Set commands */ int setStandardProcedure(int fd, const char * writeData); /* Set Slew Mode */ int setSlewMode(int fd, int slewMode); /* Set Alignment mode */ int setAlignmentMode(int fd, unsigned int alignMode); /* Set Object RA */ int setObjectRA(int fd, double ra); /* set Object DEC */ int setObjectDEC(int fd, double dec); /* Set Calender date */ int setCalenderDate(int fd, int dd, int mm, int yy); /* Set UTC offset */ int setUTCOffset(int fd, double hours); /* Set Track Freq */ int setTrackFreq(int fd, double trackF); /* Set current site longitude */ int setSiteLongitude(int fd, double Long); /* Set current site latitude */ int setSiteLatitude(int fd, double Lat); /* Set Object Azimuth */ int setObjAz(int fd, double az); /* Set Object Altitude */ int setObjAlt(int fd, double alt); /* Set site name */ int setSiteName(int fd, char * siteName, int siteNum); /* Set maximum slew rate */ int setMaxSlewRate(int fd, int slewRate); /* Set focuser motion */ int setFocuserMotion(int fd, int motionType); /* Set focuser speed mode */ int setFocuserSpeedMode (int fd, int speedMode); /* Set minimum elevation limit */ int setMinElevationLimit(int fd, int min); /* Set maximum elevation limit */ int setMaxElevationLimit(int fd, int max); /************************************************************************** Motion Commands **************************************************************************/ /* Slew to the selected coordinates */ int Slew(int fd); /* Synchronize to the selected coordinates and return the matching object if any */ int Sync(int fd, char *matchedObject); /* Abort slew in all axes */ 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 */ 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 **************************************************************************/ /* Ensures LX200 RA/DEC format is long */ int checkLX200Format(int fd); /* Select a site from the LX200 controller */ int selectSite(int fd, int siteNum); /* Select a catalog object */ int selectCatalogObject(int fd, int catalog, int NNNN); /* Select a sub catalog */ int selectSubCatalog(int fd, int catalog, int subCatalog); int check_lx200_connection(int in_fd) { int i=0; char ack[1] = { (char) 0x06 }; char MountAlign[64]; int nbytes_read=0; #ifdef INDI_DEBUG IDLog("Testing telescope's connection using ACK...\n"); #endif if (in_fd <= 0) return -1; for (i=0; i < 2; i++) { if (write(in_fd, ack, 1) < 0) return -1; tty_read(in_fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read); if (nbytes_read == 1) return 0; usleep(50000); } return -1; } /********************************************************************** * GET **********************************************************************/ char ACK(int fd) { char ack[1] = { (char) 0x06 }; char MountAlign[2]; int nbytes_write=0, nbytes_read=0, error_type; nbytes_write = write(fd, ack, 1); if (nbytes_write < 0) return -1; /*read_ret = portRead(MountAlign, 1, LX200_TIMEOUT);*/ error_type = tty_read(fd, MountAlign, 1, LX200_TIMEOUT, &nbytes_read); if (nbytes_read == 1) return MountAlign[0]; else return error_type; } int getCommandSexa(int fd, double *value, const char * cmd) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; tcflush(fd, TCIFLUSH); if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; /*if ( (read_ret = portRead(temp_string, -1, LX200_TIMEOUT)) < 1) return read_ret;*/ error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (error_type != TTY_OK) return error_type; temp_string[nbytes_read - 1] = '\0'; /*IDLog("getComandSexa: %s\n", temp_string);*/ if (f_scansexa(temp_string, value)) { #ifdef INDI_DEBUG IDLog("unable to process [%s]\n", temp_string); #endif return -1; } tcflush(fd, TCIFLUSH); return 0; } int getCommandInt(int fd, int *value, const char* cmd) { char temp_string[16]; float temp_number; int error_type; int nbytes_write=0, nbytes_read=0; tcflush(fd, TCIFLUSH); if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (error_type != TTY_OK) return error_type; temp_string[nbytes_read - 1] = '\0'; /* Float */ if (strchr(temp_string, '.')) { if (sscanf(temp_string, "%f", &temp_number) != 1) return -1; *value = (int) temp_number; } /* Int */ else if (sscanf(temp_string, "%d", value) != 1) return -1; return 0; } int getCommandString(int fd, char *data, const char* cmd) { char * term; int error_type; int nbytes_write=0, nbytes_read=0; /*if (portWrite(cmd) < 0) return -1;*/ if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(data, -1, LX200_TIMEOUT);*/ error_type = tty_read_section(fd, data, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (error_type != TTY_OK) return error_type; term = strchr (data, '#'); if (term) *term = '\0'; #ifdef INDI_DEBUG /*IDLog("Requested data: %s\n", data);*/ #endif return 0; } int isSlewComplete(int fd) { char data[8]; int error_type; int nbytes_write=0, nbytes_read=0; char *cmd = "#:D#"; if ( (error_type = tty_write_string(fd, cmd, &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read_section(fd, data, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIOFLUSH); if (error_type != TTY_OK) return error_type; if (data[0] == '#') return 0; else return 1; } int getCalenderDate(int fd, char *date) { int dd, mm, yy; int error_type; int nbytes_read=0; char mell_prefix[3]; if ( (error_type = getCommandString(fd, date, "#:GC#")) ) return error_type; /* Meade format is MM/DD/YY */ nbytes_read = sscanf(date, "%d%*c%d%*c%d", &mm, &dd, &yy); if (nbytes_read < 3) return -1; /* We consider years 50 or more to be in the last century, anything less in the 21st century.*/ if (yy > 50) strncpy(mell_prefix, "19", 3); else strncpy(mell_prefix, "20", 3); /* We need to have in in YYYY/MM/DD format */ snprintf(date, 16, "%s%02d/%02d/%02d", mell_prefix, yy, mm, dd); return (0); } int getTimeFormat(int fd, int *format) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; int tMode; /*if (portWrite("#:Gc#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:Gc#", &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/ if ( (error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read)) != TTY_OK) return error_type; tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read-1] = '\0'; nbytes_read = sscanf(temp_string, "(%d)", &tMode); if (nbytes_read < 1) return -1; else *format = tMode; return 0; } int getSiteName(int fd, char *siteName, int siteNum) { char * term; int error_type; int nbytes_write=0, nbytes_read=0; switch (siteNum) { case 1: /*if (portWrite("#:GM#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:GM#", &nbytes_write)) != TTY_OK) return error_type; break; case 2: /*if (portWrite("#:GN#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:GN#", &nbytes_write)) != TTY_OK) return error_type; break; case 3: /*if (portWrite("#:GO#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:GO#", &nbytes_write)) != TTY_OK) return error_type; break; case 4: /*if (portWrite("#:GP#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:GP#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; } /*read_ret = portRead(siteName, -1, LX200_TIMEOUT);*/ error_type = tty_read_section(fd, siteName, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; siteName[nbytes_read - 1] = '\0'; term = strchr (siteName, ' '); if (term) *term = '\0'; term = strchr (siteName, '<'); if (term) strcpy(siteName, "unused site"); #ifdef INDI_DEBUG IDLog("Requested site name: %s\n", siteName); #endif return 0; } int getSiteLatitude(int fd, int *dd, int *mm) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; /*if (portWrite("#:Gt#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:Gt#", &nbytes_write)) != TTY_OK) return error_type; /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read -1] = '\0'; if (sscanf (temp_string, "%d%*c%d", dd, mm) < 2) return -1; #ifdef INDI_DEBUG fprintf(stderr, "Requested site latitude in String %s\n", temp_string); fprintf(stderr, "Requested site latitude %d:%d\n", *dd, *mm); #endif return 0; } int getSiteLongitude(int fd, int *ddd, int *mm) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, "#:Gg#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:Gg#") < 0) return -1;*/ error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/ tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read -1] = '\0'; if (sscanf (temp_string, "%d%*c%d", ddd, mm) < 2) return -1; #ifdef INDI_DEBUG fprintf(stderr, "Requested site longitude in String %s\n", temp_string); fprintf(stderr, "Requested site longitude %d:%d\n", *ddd, *mm); #endif return 0; } int getTrackFreq(int fd, double *value) { float Freq; char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, "#:GT#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:GT#") < 0) return -1;*/ /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[nbytes_read] = '\0'; /*fprintf(stderr, "Telescope tracking freq str: %s\n", temp_string);*/ if (sscanf(temp_string, "%f#", &Freq) < 1) return -1; *value = (double) Freq; #ifdef INDI_DEBUG fprintf(stderr, "Tracking frequency value is %f\n", Freq); #endif return 0; } int getNumberOfBars(int fd, int *value) { char temp_string[128]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, "#:D#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:D#") < 0) return -1;*/ error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 0) return error_type; *value = nbytes_read -1; return 0; } int getHomeSearchStatus(int fd, int *status) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, "#:h?#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:h?#") < 0) return -1;*/ /*read_ret = portRead(temp_string, 1, LX200_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; temp_string[1] = '\0'; if (temp_string[0] == '0') *status = 0; else if (temp_string[0] == '1') *status = 1; else if (temp_string[0] == '2') *status = 1; return 0; } int getOTATemp(int fd, double *value) { char temp_string[16]; int error_type; int nbytes_write=0, nbytes_read=0; float temp; if ( (error_type = tty_write_string(fd, "#:fT#", &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; temp_string[nbytes_read - 1] = '\0'; if (sscanf(temp_string, "%f", &temp) < 1) return -1; *value = (double) temp; return 0; } int updateSkyCommanderCoord(int fd, double *ra, double *dec) { char coords[16]; char CR[1] = { (char) 0x0D }; float RA=0.0, DEC=0.0; int error_type; int nbytes_read=0; error_type = write(fd, CR, 1); error_type = tty_read(fd, coords, 16, LX200_TIMEOUT, &nbytes_read); /*read_ret = portRead(coords, 16, LX200_TIMEOUT);*/ tcflush(fd, TCIFLUSH); nbytes_read = sscanf(coords, " %g %g", &RA, &DEC); if (nbytes_read < 2) { #ifdef INDI_DEBUG IDLog("Error in Sky commander number format [%s], exiting.\n", coords); #endif return error_type; } *ra = RA; *dec = DEC; return 0; } int updateIntelliscopeCoord (int fd, double *ra, double *dec) { char coords[16]; char CR[1] = { (char) 0x51 }; /* "Q" */ float RA = 0.0, DEC = 0.0; int error_type; int nbytes_read=0; /*IDLog ("Sending a Q\n");*/ error_type = write (fd, CR, 1); /* We start at 14 bytes in case its a Sky Wizard, but read one more later it if it's a intelliscope */ /*read_ret = portRead (coords, 14, LX200_TIMEOUT);*/ error_type = tty_read(fd, coords, 14, LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); /*IDLog ("portRead() = [%s]\n", coords);*/ /* Remove the Q in the response from the Intelliscope but not the Sky Wizard */ if (coords[0] == 'Q') { coords[0] = ' '; /* Read one more byte if Intelliscope to get the "CR" */ error_type = tty_read(fd, coords, 1, LX200_TIMEOUT, &nbytes_read); /*read_ret = portRead (coords, 1, LX200_TIMEOUT);*/ } nbytes_read = sscanf (coords, " %g %g", &RA, &DEC); /*IDLog ("sscanf() RA = [%f]\n", RA * 0.0390625);*/ /*IDLog ("sscanf() DEC = [%f]\n", DEC * 0.0390625);*/ /*IDLog ("Intelliscope output [%s]", coords);*/ if (nbytes_read < 2) { #ifdef INDI_DEBUG IDLog ("Error in Intelliscope number format [%s], exiting.\n", coords); #endif return -1; } *ra = RA * 0.0390625; *dec = DEC * 0.0390625; return 0; } /********************************************************************** * SET **********************************************************************/ int setStandardProcedure(int fd, const char * data) { char bool_return[2]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, data, &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read); /*read_ret = portRead(boolRet, 1, LX200_TIMEOUT);*/ tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; if (bool_return[0] == '0') { #ifdef INDI_DEBUG IDLog("%s Failed.\n", data); #endif return -1; } #ifdef INDI_DEBUG IDLog("%s Successful\n", data); #endif return 0; } int setCommandInt(int fd, int data, const char *cmd) { char temp_string[16]; int error_type; int nbytes_write=0; snprintf(temp_string, sizeof( temp_string ), "%s%d#", cmd, data); if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /* if (portWrite(temp_string) < 0) return -1;*/ return 0; } int setMinElevationLimit(int fd, int min) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), "#:Sh%02d#", min); return (setStandardProcedure(fd, temp_string)); } int setMaxElevationLimit(int fd, int max) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), "#:So%02d*#", max); return (setStandardProcedure(fd, temp_string)); } int setMaxSlewRate(int fd, int slewRate) { char temp_string[16]; if (slewRate < 2 || slewRate > 8) return -1; snprintf(temp_string, sizeof( temp_string ), "#:Sw%d#", slewRate); return (setStandardProcedure(fd, temp_string)); } int setObjectRA(int fd, double ra) { int h, m, s, frac_m; char temp_string[16]; getSexComponents(ra, &h, &m, &s); frac_m = (s / 60.0) * 10.; if (controller_format == LX200_LONG_FORMAT) snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d:%02d#", h, m, s); else snprintf(temp_string, sizeof( temp_string ), "#:Sr %02d:%02d.%01d#", h, m, frac_m); /*IDLog("Set Object RA String %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setObjectDEC(int fd, double dec) { int d, m, s; char temp_string[16]; getSexComponents(dec, &d, &m, &s); switch(controller_format) { case LX200_SHORT_FORMAT: /* case with negative zero */ if (!d && dec < 0) snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d*%02d#", d, m); else snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d*%02d#", d, m); break; case LX200_LONG_FORMAT: /* case with negative zero */ if (!d && dec < 0) snprintf(temp_string, sizeof( temp_string ), "#:Sd -%02d:%02d:%02d#", d, m, s); else snprintf(temp_string, sizeof( temp_string ), "#:Sd %+03d:%02d:%02d#", d, m, s); break; } /*IDLog("Set Object DEC String %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setCommandXYZ(int fd, int x, int y, int z, const char *cmd) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), "%s %02d:%02d:%02d#", cmd, x, y, z); return (setStandardProcedure(fd, temp_string)); } int setAlignmentMode(int fd, unsigned int alignMode) { /*fprintf(stderr , "Set alignment mode %d\n", alignMode);*/ int error_type; int nbytes_write=0; switch (alignMode) { case LX200_ALIGN_POLAR: if ( (error_type = tty_write_string(fd, "#:AP#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:AP#") < 0) return -1;*/ break; case LX200_ALIGN_ALTAZ: if ( (error_type = tty_write_string(fd, "#:AA#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:AA#") < 0) return -1;*/ break; case LX200_ALIGN_LAND: if ( (error_type = tty_write_string(fd, "#:AL#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:AL#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setCalenderDate(int fd, int dd, int mm, int yy) { char temp_string[32]; char dumpPlanetaryUpdateString[64]; char bool_return[2]; int error_type; int nbytes_write=0, nbytes_read=0; yy = yy % 100; snprintf(temp_string, sizeof( temp_string ), "#:SC %02d/%02d/%02d#", mm, dd, yy); if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(temp_string) < 0) return -1;*/ /*read_ret = portRead(boolRet, 1, LX200_TIMEOUT);*/ error_type = tty_read(fd, bool_return, 1, LX200_TIMEOUT, &nbytes_read); tcflush(fd, TCIFLUSH); if (nbytes_read < 1) return error_type; bool_return[1] = '\0'; if (bool_return[0] == '0') return -1; /* Read dumped data */ error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', LX200_TIMEOUT, &nbytes_read); error_type = tty_read_section(fd, dumpPlanetaryUpdateString, '#', 5, &nbytes_read); return 0; } int setUTCOffset(int fd, double hours) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), "#:SG %+03d#", (int) hours); /*IDLog("UTC string is %s\n", temp_string);*/ return (setStandardProcedure(fd, temp_string)); } int setSiteLongitude(int fd, double Long) { int d, m, s; char temp_string[32]; getSexComponents(Long, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:Sg%03d:%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setSiteLatitude(int fd, double Lat) { int d, m, s; char temp_string[32]; getSexComponents(Lat, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:St%+03d:%02d:%02d#", d, m, s); return (setStandardProcedure(fd, temp_string)); } int setObjAz(int fd, double az) { int d,m,s; char temp_string[16]; getSexComponents(az, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:Sz%03d:%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setObjAlt(int fd, double alt) { int d, m, s; char temp_string[16]; getSexComponents(alt, &d, &m, &s); snprintf(temp_string, sizeof( temp_string ), "#:Sa%+02d*%02d#", d, m); return (setStandardProcedure(fd, temp_string)); } int setSiteName(int fd, char * siteName, int siteNum) { char temp_string[16]; switch (siteNum) { case 1: snprintf(temp_string, sizeof( temp_string ), "#:SM %s#", siteName); break; case 2: snprintf(temp_string, sizeof( temp_string ), "#:SN %s#", siteName); break; case 3: snprintf(temp_string, sizeof( temp_string ), "#:SO %s#", siteName); break; case 4: snprintf(temp_string, sizeof( temp_string ), "#:SP %s#", siteName); break; default: return -1; } return (setStandardProcedure(fd, temp_string)); } int setSlewMode(int fd, int slewMode) { int error_type; int nbytes_write=0; switch (slewMode) { case LX200_SLEW_MAX: if ( (error_type = tty_write_string(fd, "#:RS#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:RS#") < 0) return -1;*/ break; case LX200_SLEW_FIND: if ( (error_type = tty_write_string(fd, "#:RM#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:RM#") < 0) return -1;*/ break; case LX200_SLEW_CENTER: if ( (error_type = tty_write_string(fd, "#:RC#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:RC#") < 0) return -1;*/ break; case LX200_SLEW_GUIDE: if ( (error_type = tty_write_string(fd, "#:RG#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:RG#") < 0) return -1;*/ break; default: break; } tcflush(fd, TCIFLUSH); return 0; } int setFocuserMotion(int fd, int motionType) { int error_type; int nbytes_write=0; switch (motionType) { case LX200_FOCUSIN: if ( (error_type = tty_write_string(fd, "#:F+#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus IN Command\n");*/ #endif /*if (portWrite("#:F+#") < 0) return -1;*/ break; case LX200_FOCUSOUT: if ( (error_type = tty_write_string(fd, "#:F-#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus OUT Command\n");*/ #endif /*if (portWrite("#:F-#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setFocuserSpeedMode (int fd, int speedMode) { int error_type; int nbytes_write=0; switch (speedMode) { case LX200_HALTFOCUS: if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Halt Focus Command\n");*/ #endif /* if (portWrite("#:FQ#") < 0) return -1;*/ break; case LX200_FOCUSSLOW: if ( (error_type = tty_write_string(fd, "#:FS#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus Slow (FS) Command\n");*/ #endif /*if (portWrite("#:FS#") < 0) return -1;*/ break; case LX200_FOCUSFAST: if ( (error_type = tty_write_string(fd, "#:FF#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("Focus Fast (FF) Command\n");*/ #endif /*if (portWrite("#:FF#") < 0) return -1;*/ break; } tcflush(fd, TCIFLUSH); return 0; } int setGPSFocuserSpeed (int fd, int speed) { char speed_str[8]; int error_type; int nbytes_write=0; if (speed == 0) { /*if (portWrite("#:FQ#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:FQ#", &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("GPS Focus HALT Command (FQ) \n");*/ #endif return 0; } snprintf(speed_str, 8, "#:F%d#", speed); if ( (error_type = tty_write_string(fd, speed_str, &nbytes_write)) != TTY_OK) return error_type; #ifdef INDI_DEBUG /*IDLog("GPS Focus Speed command %s \n", speed_str);*/ #endif /*if (portWrite(speed_str) < 0) return -1;*/ tcflush(fd, TCIFLUSH); return 0; } int setTrackFreq(int fd, double trackF) { char temp_string[16]; snprintf(temp_string, sizeof( temp_string ), "#:ST %04.1f#", trackF); return (setStandardProcedure(fd, temp_string)); } /********************************************************************** * Misc *********************************************************************/ int Slew(int fd) { char slewNum[2]; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, "#:MS#", &nbytes_write)) != TTY_OK) return error_type; error_type = tty_read(fd, slewNum, 1, LX200_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; /* We don't need to read the string message, just return corresponding error code */ tcflush(fd, TCIFLUSH); if (slewNum[0] == '0') return 0; else if (slewNum[0] == '1') return 1; else return 2; } int MoveTo(int fd, int direction) { int nbytes_write=0; switch (direction) { case LX200_NORTH: tty_write_string(fd, "#:Mn#", &nbytes_write); /*portWrite("#:Mn#");*/ break; case LX200_WEST: tty_write_string(fd, "#:Mw#", &nbytes_write); /*portWrite("#:Mw#");*/ break; case LX200_EAST: tty_write_string(fd, "#:Me#", &nbytes_write); /*portWrite("#:Me#");*/ break; case LX200_SOUTH: tty_write_string(fd, "#:Ms#", &nbytes_write); /*portWrite("#:Ms#");*/ break; default: break; } tcflush(fd, TCIFLUSH); 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; int nbytes_write=0; switch (direction) { case LX200_NORTH: /*if (portWrite("#:Qn#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:Qn#", &nbytes_write)) != TTY_OK) return error_type; break; case LX200_WEST: /*if (portWrite("#:Qw#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:Qw#", &nbytes_write)) != TTY_OK) return error_type; break; case LX200_EAST: /*if (portWrite("#:Qe#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:Qe#", &nbytes_write)) != TTY_OK) return error_type; break; case LX200_SOUTH: if ( (error_type = tty_write_string(fd, "#:Qs#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:Qs#") < 0) return -1;*/ break; case LX200_ALL: /*if (portWrite("#:Q#") < 0) return -1;*/ if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK) return error_type; break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } int abortSlew(int fd) { /*if (portWrite("#:Q#") < 0) return -1;*/ int error_type; int nbytes_write=0; if ( (error_type = tty_write_string(fd, "#:Q#", &nbytes_write)) != TTY_OK) return error_type; tcflush(fd, TCIFLUSH); return 0; } int Sync(int fd, char *matchedObject) { int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, "#:CM#", &nbytes_write)) != TTY_OK) return error_type; /*portWrite("#:CM#");*/ /*read_ret = portRead(matchedObject, -1, LX200_TIMEOUT);*/ error_type = tty_read_section(fd, matchedObject, '#', LX200_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; matchedObject[nbytes_read-1] = '\0'; /*IDLog("Matched Object: %s\n", matchedObject);*/ /* Sleep 10ms before flushing. This solves some issues with LX200 compatible devices. */ usleep(10000); tcflush(fd, TCIFLUSH); return 0; } int selectSite(int fd, int siteNum) { int error_type; int nbytes_write=0; switch (siteNum) { case 1: if ( (error_type = tty_write_string(fd, "#:W1#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:W1#") < 0) return -1;*/ break; case 2: if ( (error_type = tty_write_string(fd, "#:W2#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:W2#") < 0) return -1;*/ break; case 3: if ( (error_type = tty_write_string(fd, "#:W3#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:W3#") < 0) return -1;*/ break; case 4: if ( (error_type = tty_write_string(fd, "#:W4#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:W4#") < 0) return -1;*/ break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } int selectCatalogObject(int fd, int catalog, int NNNN) { char temp_string[16]; int error_type; int nbytes_write=0; switch (catalog) { case LX200_STAR_C: snprintf(temp_string, sizeof( temp_string ), "#:LS%d#", NNNN); break; case LX200_DEEPSKY_C: snprintf(temp_string, sizeof( temp_string ), "#:LC%d#", NNNN); break; case LX200_MESSIER_C: snprintf(temp_string, sizeof( temp_string ), "#:LM%d#", NNNN); break; default: return -1; } if ( (error_type = tty_write_string(fd, temp_string, &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite(temp_string) < 0) return -1;*/ tcflush(fd, TCIFLUSH); return 0; } int selectSubCatalog(int fd, int catalog, int subCatalog) { char temp_string[16]; switch (catalog) { case LX200_STAR_C: snprintf(temp_string, sizeof( temp_string ), "#:LsD%d#", subCatalog); break; case LX200_DEEPSKY_C: snprintf(temp_string, sizeof( temp_string ), "#:LoD%d#", subCatalog); break; case LX200_MESSIER_C: return 1; default: return 0; } return (setStandardProcedure(fd, temp_string)); } int checkLX200Format(int fd) { char temp_string[16]; controller_format = LX200_LONG_FORMAT; int error_type; int nbytes_write=0, nbytes_read=0; if ( (error_type = tty_write_string(fd, "#:GR#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:GR#") < 0) return -1;*/ /*read_ret = portRead(temp_string, -1, LX200_TIMEOUT);*/ error_type = tty_read_section(fd, temp_string, '#', LX200_TIMEOUT, &nbytes_read); if (nbytes_read < 1) return error_type; temp_string[nbytes_read - 1] = '\0'; /* Check whether it's short or long */ if (temp_string[5] == '.') { controller_format = LX200_SHORT_FORMAT; return 0; } else return 0; } int selectTrackingMode(int fd, int trackMode) { int error_type; int nbytes_write=0; switch (trackMode) { case LX200_TRACK_DEFAULT: #ifdef INDI_DEBUG IDLog("Setting tracking mode to sidereal.\n"); #endif if ( (error_type = tty_write_string(fd, "#:TQ#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:TQ#") < 0) return -1;*/ break; case LX200_TRACK_LUNAR: #ifdef INDI_DEBUG IDLog("Setting tracking mode to LUNAR.\n"); #endif if ( (error_type = tty_write_string(fd, "#:TL#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:TL#") < 0) return -1;*/ break; case LX200_TRACK_MANUAL: #ifdef INDI_DEBUG IDLog("Setting tracking mode to CUSTOM.\n"); #endif if ( (error_type = tty_write_string(fd, "#:TM#", &nbytes_write)) != TTY_OK) return error_type; /*if (portWrite("#:TM#") < 0) return -1;*/ break; default: return -1; break; } tcflush(fd, TCIFLUSH); return 0; } libindi-0.9.7/drivers/telescope/lx200autostar.cpp0000644000175000017500000001406512241463551020727 0ustar jasemjasem/* LX200 Autostar Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "lx200autostar.h" #include "lx200driver.h" #include #include #include #include #define FIRMWARE_TAB "Firmware data" /******************************************** Property: Park telescope to HOME *********************************************/ LX200Autostar::LX200Autostar() : LX200Generic() { MaxReticleFlashRate = 9; } const char *LX200Autostar::getDefaultName() { return (const char *) "LX200 Autostar"; } bool LX200Autostar::initProperties() { LX200Generic::initProperties(); IUFillText(&VersionT[0], "Date", "", ""); IUFillText(&VersionT[1], "Time", "", ""); IUFillText(&VersionT[2], "Number", "", ""); IUFillText(&VersionT[3], "Full", "", ""); IUFillText(&VersionT[4], "Name", "", ""); IUFillTextVector(&VersionTP, VersionT, 5, getDeviceName(), "Firmware Info", "", FIRMWARE_TAB, IP_RO, 0, IPS_IDLE); IUFillNumber(&FocusSpeedN[0], "SPEED", "Speed", "%0.f", 0, 4.0, 1.0, 0); IUFillNumberVector(&FocusSpeedNP, FocusSpeedN, 1, getDeviceName(), "FOCUS_SPEED", "Speed", FOCUS_TAB, IP_RW, 0, IPS_IDLE); return true; } void LX200Autostar::ISGetProperties (const char *dev) { if(dev && strcmp(dev,getDeviceName())) return; LX200Generic::ISGetProperties(dev); if (isConnected()) { defineText(&VersionTP); defineNumber(&FocusSpeedNP); // For Autostar, we have a different focus speed method // Therefore, we don't need the classical one deleteProperty(FocusModeSP.name); } } bool LX200Autostar::updateProperties() { LX200Generic::updateProperties(); if (isConnected()) { defineText(&VersionTP); defineNumber(&FocusSpeedNP); // For Autostar, we have a different focus speed method // Therefore, we don't need the classical one deleteProperty(FocusModeSP.name); } else { deleteProperty(VersionTP.name); deleteProperty(FocusSpeedNP.name); } } bool LX200Autostar::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { // Focus speed if (!strcmp (name, FocusSpeedNP.name)) { if (IUUpdateNumber(&FocusSpeedNP, values, names, n) < 0) return false; if (isSimulation() == false) setGPSFocuserSpeed(PortFD, ( (int) FocusSpeedN[0].value)); FocusSpeedNP.s = IPS_OK; IDSetNumber(&FocusSpeedNP, NULL); return true; } } return LX200Generic::ISNewNumber (dev, name, values, names, n); } bool LX200Autostar::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int index=0; if(strcmp(dev,getDeviceName())==0) { // Focus Motion if (!strcmp (name, FocusMotionSP.name)) { // If speed is "halt" if (FocusSpeedN[0].value == 0) { FocusMotionSP.s = IPS_IDLE; IDSetSwitch(&FocusMotionSP, NULL); return false; } int last_motion = IUFindOnSwitchIndex(&FocusMotionSP); if (IUUpdateSwitch(&FocusMotionSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&FocusMotionSP); // If same direction and we're busy, stop if (last_motion == index && FocusMotionSP.s == IPS_BUSY) { IUResetSwitch(&FocusMotionSP); FocusMotionSP.s = IPS_IDLE; setFocuserSpeedMode(PortFD, 0); IDSetSwitch(&FocusMotionSP, NULL); return true; } if (isSimulation() == false && setFocuserMotion(PortFD, index) < 0) { FocusMotionSP.s = IPS_ALERT; IDSetSwitch(&FocusMotionSP, "Error setting focuser speed."); return false; } FocusMotionSP.s = IPS_BUSY; // with a timer if (FocusTimerNP.np[0].value > 0) { FocusTimerNP.s = IPS_BUSY; if (isDebug()) IDLog("Starting Focus Timer BUSY\n"); IEAddTimer(50, LX200Generic::updateFocusHelper, this); } IDSetSwitch(&FocusMotionSP, NULL); return true; } } return LX200Generic::ISNewSwitch (dev, name, states, names, n); } void LX200Autostar::getBasicData() { // process parent LX200Generic::getBasicData(); if (isSimulation() == false) { VersionTP.tp[0].text = new char[64]; getVersionDate(PortFD, VersionTP.tp[0].text); VersionTP.tp[1].text = new char[64]; getVersionTime(PortFD, VersionTP.tp[1].text); VersionTP.tp[2].text = new char[64]; getVersionNumber(PortFD, VersionTP.tp[2].text); VersionTP.tp[3].text = new char[128]; getFullVersion(PortFD, VersionTP.tp[3].text); VersionTP.tp[4].text = new char[128]; getProductName(PortFD, VersionTP.tp[4].text); IDSetText(&VersionTP, NULL); } } libindi-0.9.7/drivers/telescope/magellandriver.h0000644000175000017500000000461212241463551020735 0ustar jasemjasem/* MAGELLAN Driver Copyright (C) 2011 Onno Hommes (ohommes@alumni.cmu.edu) 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 */ #ifndef MAGELLANDRIVER_H #define MAGELLANDRIVER_H /* Just use Default tracking for what ever telescope is feeding Magellan I */ enum TFreq { MAGELLAN_TRACK_DEFAULT, MAGELLAN_TRACK_LUNAR, MAGELLAN_TRACK_MANUAL}; /* Time Format */ enum TTimeFormat { MAGELLAN_24, MAGELLAN_AM, MAGELLAN_PM}; #define MAGELLAN_TIMEOUT 5 /* FD timeout in seconds */ #define MAGELLAN_ERROR -1 /* Default Error Code */ #define MAGELLAN_OK 0 /* Default Success Code */ #define MAGELLAN_ACK 'P' /* Default Success Code */ #define CENTURY_THRESHOLD 91 /* When to goto 21st Century */ #define CONNECTION_RETRIES 2 /* Retry Attempt cut-off */ /* GET formatted sexagisemal value from device, return as double */ #define getMAGELLANRA(fd, x) getCommandSexa(fd, x, "#:GR#") #define getMAGELLANDEC(fd, x) getCommandSexa(fd, x, "#:GD#") #ifdef __cplusplus extern "C" { #endif /************************************************************************** Diagnostics **************************************************************************/ char ACK(int fd); int check_magellan_connection(int fd); /************************************************************************** Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure **************************************************************************/ /* Get Double from Sexagisemal */ int getCommandSexa(int fd, double *value, const char *cmd); /* Get Calender data */ int getCalenderDate(int fd, char *date); #ifdef __cplusplus } #endif #endif libindi-0.9.7/drivers/telescope/lx200basic.h0000644000175000017500000000633112241463551017610 0ustar jasemjasem/* LX200 Basic Driver Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef LX200BASIC_H #define LX200BASIC_H #include "indidevapi.h" #include "indicom.h" class LX200Basic { public: LX200Basic(); ~LX200Basic(); void ISGetProperties (const char *dev); void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); void ISPoll (); void connection_lost(); void connection_resumed(); private: enum LX200_STATUS { LX200_SLEW, LX200_TRACK, LX200_SYNC, LX200_PARK }; /* Switches */ ISwitch ConnectS[2]; ISwitch OnCoordSetS[3]; ISwitch AbortSlewS[1]; /* Texts */ IText PortT[1]; IText ObjectT[1]; /* Numbers */ INumber EquatorialCoordsRN[2]; INumber SlewAccuracyN[2]; INumber TrackAccuracyN[2]; /* Switch Vectors */ ISwitchVectorProperty ConnectSP; ISwitchVectorProperty OnCoordSetSP; ISwitchVectorProperty AbortSlewSP; /* Number Vectors */ INumberVectorProperty EquatorialCoordsRNP; INumberVectorProperty SlewAccuracyNP; INumberVectorProperty TrackAccuracyNP; /* Text Vectors */ ITextVectorProperty PortTP; ITextVectorProperty ObjectTP; /*******************************************************/ /* Connection Routines ********************************************************/ void init_properties(); void get_initial_data(); void connect_telescope(); bool is_connected(void); /*******************************************************/ /* Misc routines ********************************************************/ bool process_coords(); int get_switch_index(ISwitchVectorProperty *sp); /*******************************************************/ /* Simulation Routines ********************************************************/ void enable_simulation(bool enable); /*******************************************************/ /* Error handling routines ********************************************************/ void slew_error(int slewCode); void reset_all_properties(); void handle_error(INumberVectorProperty *nvp, int err, const char *msg); void correct_fault(); protected: double JD; /* Julian Date */ double lastRA; double lastDEC; bool simulation; bool fault; int fd; /* Telescope tty file descriptor */ int currentSet; int lastSet; double targetRA, targetDEC; }; #endif libindi-0.9.7/drivers/telescope/lx200_16.h0000644000175000017500000000337112241463551017115 0ustar jasemjasem#ifndef LX200_16_H #define LX200_16_H /* LX200 16" Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "lx200gps.h" class LX200_16 : public LX200GPS { public: LX200_16(); ~LX200_16() {} const char *getDefaultName(); bool initProperties(); bool updateProperties(); void ISGetProperties (const char *dev); bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); bool ReadScopeStatus(); void getBasicData(); bool handleAltAzSlew(); protected: ISwitchVectorProperty FieldDeRotatorSP; ISwitch FieldDeRotatorS[2]; ISwitchVectorProperty HomeSearchSP; ISwitch HomeSearchS[2]; ISwitchVectorProperty FanStatusSP; ISwitch FanStatusS[2]; INumberVectorProperty HorizontalCoordsNP; INumber HorizontalCoordsN[2]; private: double targetAZ, targetALT; double currentAZ, currentALT; }; #endif libindi-0.9.7/drivers/telescope/lx200genericlegacy.h0000644000175000017500000000552612241463551021335 0ustar jasemjasem/* LX200 Generic Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef LX200GenericLegacy_H #define LX200GenericLegacy_H #include "indidevapi.h" #include "indicom.h" #define POLLMS 1000 /* poll period, ms */ #define mydev "LX200 Generic" /* The device name */ class LX200GenericLegacy { public: LX200GenericLegacy(); virtual ~LX200GenericLegacy(); virtual void ISGetProperties (const char *dev); virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual void ISSnoopDevice (XMLEle *root); virtual void ISPoll (); virtual void getBasicData(); int checkPower(INumberVectorProperty *np); int checkPower(ISwitchVectorProperty *sp); int checkPower(ITextVectorProperty *tp); virtual void handleError(ISwitchVectorProperty *svp, int err, const char *msg); virtual void handleError(INumberVectorProperty *nvp, int err, const char *msg); virtual void handleError(ITextVectorProperty *tvp, int err, const char *msg); bool isTelescopeOn(void); virtual void connectTelescope(); void slewError(int slewCode); void getAlignment(); int handleCoordSet(); int getOnSwitch(ISwitchVectorProperty *sp); void setCurrentDeviceName(const char * devName); void correctFault(); void enableSimulation(bool enable); void updateTime(); void updateLocation(); void mountSim(); static void updateFocusTimer(void *p); static void guideTimeout(void *p); int fd; int GuideNSTID; int GuideWETID; protected: int timeFormat; int currentSiteNum; int trackingMode; double JD; double lastRA; double lastDEC; bool fault; bool simulation; char thisDevice[64]; int currentSet; int lastSet; double targetRA, targetDEC; }; void changeLX200GenericLegacyDeviceName(const char * newName); void changeAllDeviceNames(const char *newName); #endif libindi-0.9.7/drivers/telescope/synscanmount.cpp0000644000175000017500000001751312241463551021041 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "synscanmount.h" #include "indicom.h" #include #include #include #include #include #include #include #include #include #include // We declare an auto pointer to Synscan. std::auto_ptr synscan(0); void ISPoll(void *p); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(synscan.get() == 0) synscan.reset(new SynscanMount()); //IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { ISInit(); synscan->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); synscan->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); synscan->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); synscan->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } SynscanMount::SynscanMount() { //ctor } SynscanMount::~SynscanMount() { //dtor } const char * SynscanMount::getDefaultName() { return "SynScan"; } bool SynscanMount::initProperties() { //if (isDebug()) IDLog("Synscan::init_properties\n"); //setDeviceName("Synscan"); INDI::Telescope::initProperties(); return true; } void SynscanMount::ISGetProperties (const char *dev) { // First we let our parent class do it's thing INDI::Telescope::ISGetProperties(dev); // Now we add anything that's specific to this telescope // or we could just load from a skeleton file too return; } bool SynscanMount::ReadScopeStatus() { char str[20]; int bytesWritten, bytesRead; int numread; double ra,dec; long unsigned int n1,n2; //IDLog("SynScan Read Status\n"); //tty_write(PortFD,(unsigned char *)"Ka",2, &bytesWritten); // test for an echo tty_write(PortFD,"Ka",2, &bytesWritten); // test for an echo tty_read(PortFD,str,2,2, &bytesRead); // Read 2 bytes of response if(str[1] != '#') { // this is not a correct echo if (isDebug()) IDLog("ReadStatus Echo Fail. %s\n", str); IDMessage(getDeviceName(),"Mount Not Responding"); return false; } if(TrackState==SCOPE_SLEWING) { // We have a slew in progress // lets see if it's complete // This only works for ra/dec goto commands // The goto complete flag doesn't trip for ALT/AZ commands memset(str,0,3); tty_write(PortFD,"L",1, &bytesWritten); numread=tty_read(PortFD,str,2,3, &bytesRead); if(str[0]!=48) { // Nothing to do here } else { if(TrackState==SCOPE_PARKING) TrackState=SCOPE_PARKED; else TrackState=SCOPE_TRACKING; } } if(TrackState==SCOPE_PARKING) { // ok, lets try read where we are // and see if we have reached the park position memset(str,0,20); tty_write(PortFD,"Z",1, &bytesWritten); numread=tty_read(PortFD,str,10,2, &bytesRead); //IDLog("PARK READ %s\n",str); if(strncmp((char *)str,"0000,4000",9)==0) { TrackState=SCOPE_PARKED; ParkSP.s=IPS_OK; IDSetSwitch(&ParkSP,NULL); IDMessage(getDeviceName(),"Telescope is Parked."); } } memset(str,0,20); tty_write(PortFD,"e",1, &bytesWritten); numread=tty_read(PortFD,str,18,1, &bytesRead); if (bytesRead!=18) //if(str[17] != '#') { IDLog("read status bytes didn't get a full read\n"); return false; } if (isDebug()) IDLog("Bytes read is (%s)\n", str); // bytes read is as expected //sscanf((char *)str,"%x",&n1); //sscanf((char *)&str[9],"%x",&n2); // JM read as unsigned long int, otherwise we get negative RA! sscanf(str, "%lx,%lx#", &n1, &n2); ra=(double)n1/0x100000000*24.0; dec=(double)n2/0x100000000*360.0; NewRaDec(ra,dec); return true; } bool SynscanMount::Goto(double ra,double dec) { char str[20]; int n1,n2; int numread, bytesWritten, bytesRead; // not fleshed in yet tty_write(PortFD,"Ka",2, &bytesWritten); // test for an echo tty_read(PortFD,str,2,2, &bytesRead); // Read 2 bytes of response if(str[1] != '#') { // this is not a correct echo // so we are not talking to a mount properly return false; } // Ok, mount is alive and well // so, lets format up a goto command n1=ra*0x1000000/24; n2=dec*0x1000000/360; n1=n1<<8; n2=n2<<8; sprintf((char *)str,"r%08X,%08X",n1,n2); tty_write(PortFD,str,18, &bytesWritten); TrackState=SCOPE_SLEWING; numread=tty_read(PortFD,str,1,60, &bytesRead); if (bytesRead!=1||str[0]!='#') { if (isDebug()) IDLog("Timeout waiting for scope to complete slewing."); return false; } return true; } bool SynscanMount::Park() { char str[20]; int numread, bytesWritten, bytesRead; memset(str,0,3); tty_write(PortFD,"Ka",2, &bytesWritten); // test for an echo tty_read(PortFD,str,2,2, &bytesRead); // Read 2 bytes of response if(str[1] != '#') { // this is not a correct echo // so we are not talking to a mount properly return false; } // Now we stop tracking tty_write(PortFD,"T0",2, &bytesWritten); numread=tty_read(PortFD,str,1,60, &bytesRead); if (bytesRead!=1||str[0]!='#') { if (isDebug()) IDLog("Timeout waiting for scope to stop tracking."); return false; } //sprintf((char *)str,"b%08X,%08X",0x0,0x40000000); tty_write(PortFD,"B0000,4000",10, &bytesWritten); numread=tty_read(PortFD,str,1,60, &bytesRead); if (bytesRead!=1||str[0]!='#') { if (isDebug()) IDLog("Timeout waiting for scope to respond to park."); return false; } TrackState=SCOPE_PARKING; IDMessage(getDeviceName(),"Parking Telescope..."); return true; } bool SynscanMount::Abort() { char str[20]; int bytesWritten, bytesRead; // Hmmm twice only stops it tty_write(PortFD,"M",1, &bytesWritten); tty_read(PortFD,str,1,1, &bytesRead); // Read 1 bytes of response tty_write(PortFD,"M",1, &bytesWritten); tty_read(PortFD,str,1,1, &bytesRead); // Read 1 bytes of response return true; } bool SynscanMount::canPark() { return true; } libindi-0.9.7/drivers/telescope/lx200genericlegacy.cpp0000644000175000017500000017473612241463551021702 0ustar jasemjasem#if 0 LX200 Generic Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include "indicom.h" #include "lx200driver.h" #include "lx200ap.h" #include "lx200fs2.h" #include #ifdef HAVE_NOVA_H #include #endif LX200GenericLegacy *telescope = NULL; int MaxReticleFlashRate = 3; /* There is _one_ binary for all LX200 drivers, but each binary is renamed ** to its device name (i.e. lx200gps, lx200_16..etc). The main function will ** fetch from std args the binary name and ISInit will create the apporpiate ** device afterwards. If the binary name does not match any known devices, ** we simply create a generic device. */ extern char* me; #define COMM_GROUP "Communication" #define BASIC_GROUP "Main Control" #define MOTION_GROUP "Motion Control" #define DATETIME_GROUP "Date/Time" #define SITE_GROUP "Site Management" #define FOCUS_GROUP "Focus Control" #define LX200_TRACK 0 #define LX200_SYNC 1 /* Simulation Parameters */ #define SLEWRATE 1 /* slew rate, degrees/s */ #define SIDRATE 0.004178 /* sidereal rate, degrees/s */ /* Handy Macros */ #define currentRA EquatorialCoordsRN[0].value #define currentDEC EquatorialCoordsRN[1].value static void ISPoll(void *); static void retryConnection(void *); /*INDI Propertries */ /**********************************************************************************************/ /************************************ GROUP: Communication ************************************/ /**********************************************************************************************/ /******************************************** Property: Connection *********************************************/ static ISwitch ConnectS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}}; ISwitchVectorProperty ConnectSP = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0}; /******************************************** Property: Device Port *********************************************/ /*wildi removed static */ static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}}; ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0}; /******************************************** Property: Telescope Alignment Mode *********************************************/ static ISwitch AlignmentS [] = {{"Polar", "", ISS_ON, 0, 0}, {"AltAz", "", ISS_OFF, 0, 0}, {"Land", "", ISS_OFF, 0, 0}}; static ISwitchVectorProperty AlignmentSw= { mydev, "Alignment", "", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AlignmentS, NARRAY(AlignmentS), "", 0}; /**********************************************************************************************/ /************************************ GROUP: Main Control *************************************/ /**********************************************************************************************/ /******************************************** Property: Equatorial Coordinates JNow Perm: RO *********************************************/ INumber EquatorialCoordsRN[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}}; INumberVectorProperty EquatorialCoordsRNP= { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RW, 120, IPS_IDLE, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0}; /******************************************** Property: On Coord Set Description: This property decides what happens when we receive a new equatorial coord value. We either track, or sync to the new coordinates. *********************************************/ static ISwitch OnCoordSetS[] = {{"SLEW", "Slew", ISS_ON, 0, 0 }, {"SYNC", "Sync", ISS_OFF, 0 , 0}}; ISwitchVectorProperty OnCoordSetSP= { mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0}; /******************************************** Property: Abort telescope motion *********************************************/ static ISwitch AbortSlewS[] = {{"ABORT", "Abort", ISS_OFF, 0, 0 }}; ISwitchVectorProperty AbortSlewSP= { mydev, "TELESCOPE_ABORT_MOTION", "Abort Slew", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, AbortSlewS, NARRAY(AbortSlewS), "", 0}; /**********************************************************************************************/ /************************************** GROUP: Motion *****************************************/ /**********************************************************************************************/ /******************************************** Property: Slew Speed *********************************************/ static ISwitch SlewModeS[] = {{"Max", "", ISS_ON, 0, 0}, {"Find", "", ISS_OFF, 0, 0}, {"Centering", "", ISS_OFF, 0, 0}, {"Guide", "", ISS_OFF, 0 , 0}}; ISwitchVectorProperty SlewModeSP = { mydev, "Slew rate", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SlewModeS, NARRAY(SlewModeS), "", 0}; /******************************************** Property: Tracking Mode *********************************************/ static ISwitch TrackModeS[] = {{ "Default", "", ISS_ON, 0, 0} , { "Lunar", "", ISS_OFF, 0, 0}, {"Manual", "", ISS_OFF, 0, 0}}; static ISwitchVectorProperty TrackModeSP= { mydev, "Tracking Mode", "", MOTION_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, TrackModeS, NARRAY(TrackModeS), "", 0}; /******************************************** Property: Tracking Frequency *********************************************/ static INumber TrackFreqN[] = {{ "trackFreq", "Freq", "%g", 56.4, 60.1, 0.1, 60.1, 0, 0, 0}}; static INumberVectorProperty TrackingFreqNP= { mydev, "Tracking Frequency", "", MOTION_GROUP, IP_RW, 0, IPS_IDLE, TrackFreqN, NARRAY(TrackFreqN), "", 0}; /******************************************** 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", MOTION_GROUP, IP_RW, ISR_1OFMANY, 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", 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 (ms)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_S", "South (ms)", "%g", 0, 10000, 100, 100, 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 (ms)", "%g", 0, 10, 0.001, 0, 0, 0}, {"TIMED_GUIDE_E", "East (ms)", "%g", 0, 10000, 100, 100, 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 the tracking operation to be successull i.e. returns OK *********************************************/ INumber SlewAccuracyN[] = { {"SlewRA", "RA (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0}, {"SlewkDEC", "Dec (arcmin)", "%g", 0., 60., 1., 3.0, 0, 0, 0}, }; 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 ******************************************/ /**********************************************************************************************/ /******************************************** Property: Focus Direction *********************************************/ ISwitch FocusMotionS[] = { {"IN", "Focus in", ISS_OFF, 0, 0}, {"OUT", "Focus out", ISS_OFF, 0, 0}}; ISwitchVectorProperty FocusMotionSP = {mydev, "FOCUS_MOTION", "Motion", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusMotionS, NARRAY(FocusMotionS), "", 0}; /******************************************** Property: Focus Timer *********************************************/ INumber FocusTimerN[] = { {"TIMER", "Timer (ms)", "%g", 0., 10000., 1000., 50., 0, 0, 0 }}; INumberVectorProperty FocusTimerNP = { mydev, "FOCUS_TIMER", "Focus Timer", FOCUS_GROUP, IP_RW, 0, IPS_IDLE, FocusTimerN, NARRAY(FocusTimerN), "", 0}; /******************************************** Property: Focus Mode *********************************************/ static ISwitch FocusModeS[] = { {"FOCUS_HALT", "Halt", ISS_ON, 0, 0}, {"FOCUS_SLOW", "Slow", ISS_OFF, 0, 0}, {"FOCUS_FAST", "Fast", ISS_OFF, 0, 0}}; static ISwitchVectorProperty FocusModeSP = {mydev, "FOCUS_MODE", "Mode", FOCUS_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, FocusModeS, NARRAY(FocusModeS), "", 0}; /**********************************************************************************************/ /*********************************** GROUP: Date & Time ***************************************/ /**********************************************************************************************/ /******************************************** Property: UTC Time *********************************************/ static IText TimeT[] = {{"UTC", "UTC", 0, 0, 0, 0}}; ITextVectorProperty TimeTP = { mydev, "TIME_UTC", "UTC Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, TimeT, NARRAY(TimeT), "", 0}; /******************************************** Property: DST Corrected UTC Offfset *********************************************/ static INumber UTCOffsetN[] = {{"OFFSET", "Offset", "%0.3g" , -12.,12.,0.5,0., 0, 0, 0}}; INumberVectorProperty UTCOffsetNP = { mydev, "TIME_UTC_OFFSET", "UTC Offset", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, UTCOffsetN , NARRAY(UTCOffsetN), "", 0}; /******************************************** Property: Sidereal Time *********************************************/ static INumber SDTimeN[] = {{"LST", "Sidereal time", "%10.6m" , 0.,24.,0.,0., 0, 0, 0}}; INumberVectorProperty SDTimeNP = { mydev, "TIME_LST", "Sidereal Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, SDTimeN, NARRAY(SDTimeN), "", 0}; /**********************************************************************************************/ /************************************* GROUP: Sites *******************************************/ /**********************************************************************************************/ /******************************************** Property: Site Management *********************************************/ static ISwitch SitesS[] = {{"Site 1", "", ISS_ON, 0, 0}, {"Site 2", "", ISS_OFF, 0, 0}, {"Site 3", "", ISS_OFF, 0, 0}, {"Site 4", "", ISS_OFF, 0 ,0}}; static ISwitchVectorProperty SitesSP = { mydev, "Sites", "", SITE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, SitesS, NARRAY(SitesS), "", 0}; /******************************************** Property: Site Name *********************************************/ static IText SiteNameT[] = {{"Name", "", 0, 0, 0, 0}}; static ITextVectorProperty SiteNameTP = { mydev, "Site Name", "", SITE_GROUP, IP_RW, 0 , IPS_IDLE, SiteNameT, NARRAY(SiteNameT), "", 0}; /******************************************** Property: Geographical Location *********************************************/ static INumber geo[] = { {"LAT", "Lat. D:M:S +N", "%10.6m", -90., 90., 0., 0., 0, 0, 0}, {"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0}, {"HEIGHT", "Height m", "%10.2f", -300., 6000., 0., 610., 0, 0, 0}, }; INumberVectorProperty geoNP = { mydev, "GEOGRAPHIC_COORD", "Geographic Location", SITE_GROUP, IP_RW, 0., IPS_IDLE, geo, NARRAY(geo), "", 0}; /*****************************************************************************************************/ /**************************************** END PROPERTIES *********************************************/ /*****************************************************************************************************/ void changeLX200GenericLegacyDeviceName(const char * newName) { // COMM_GROUP strcpy(ConnectSP.device , newName); strcpy(PortTP.device , newName); strcpy(AlignmentSw.device, newName); // BASIC_GROUP strcpy(EquatorialCoordsRNP.device, newName); strcpy(OnCoordSetSP.device , newName ); strcpy(AbortSlewSP.device , newName ); // MOTION_GROUP strcpy(SlewModeSP.device , newName ); strcpy(TrackModeSP.device , newName ); 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 ); strcpy(FocusMotionSP.device , newName ); strcpy(FocusTimerNP.device, newName); // DATETIME_GROUP strcpy(TimeTP.device , newName ); strcpy(UTCOffsetNP.device , newName ); strcpy(SDTimeNP.device , newName ); // SITE_GROUP strcpy(SitesSP.device , newName ); strcpy(SiteNameTP.device , newName ); strcpy(geoNP.device , newName ); } void changeAllDeviceNames(const char *newName) { changeLX200GenericLegacyDeviceName(newName); changeLX200AstroPhysicsDeviceName(newName); changeLX200FS2DeviceName(newName); } /* send client definitions of all properties */ void ISInit() { static int isInit=0; char *envDev = getenv("INDIDEV"); if (isInit) return; isInit = 1; IUSaveText(&PortT[0], "/dev/ttyS0"); IUSaveText(&TimeT[0], "YYYY-MM-DDTHH:MM:SS"); // We need to check if UTCOffset has been set by user or not UTCOffsetN[0].aux0 = (int *) malloc(sizeof(int)); *((int *) UTCOffsetN[0].aux0) = 0; if (strstr(me, "indi_lx200ap")) { fprintf(stderr , "initializing from ap device...\n"); // 2. device = sub_class telescope = new LX200AstroPhysics(); if (envDev != NULL) { // 1. change device name changeAllDeviceNames(envDev); telescope->setCurrentDeviceName(envDev); } else { // 1. change device name changeAllDeviceNames("LX200 Astro-Physics"); telescope->setCurrentDeviceName("LX200 Astro-Physics"); } MaxReticleFlashRate = 9; } else if (strstr(me, "indi_lx200fs2")) { fprintf(stderr , "initializing from fs2 device...\n"); // 2. device = sub_class telescope = new LX200Fs2(); if (envDev != NULL) { // 1. change device name changeAllDeviceNames(envDev); telescope->setCurrentDeviceName(envDev); } else { // 1. change device name changeAllDeviceNames("LX200 FS2"); telescope->setCurrentDeviceName("LX200 FS2"); } } // be nice and give them a generic device else { telescope = new LX200GenericLegacy(); if (envDev != NULL) { // 1. change device name changeAllDeviceNames(envDev); telescope->setCurrentDeviceName(envDev); } else { // 1. change device name changeAllDeviceNames("LX200 Generic"); telescope->setCurrentDeviceName("LX200 Generic"); } } IEAddTimer (POLLMS, ISPoll, NULL); } void ISGetProperties (const char *dev) { ISInit(); telescope->ISGetProperties(dev);} void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);} void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); telescope->ISNewText(dev, name, texts, names, n);} void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); telescope->ISNewNumber(dev, name, values, names, n);} void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;} void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { telescope->ISSnoopDevice(root); } /************************************************** *** LX200 Generic Implementation ***************************************************/ LX200GenericLegacy::LX200GenericLegacy() { currentSiteNum = 1; trackingMode = LX200_TRACK_DEFAULT; lastSet = -1; fault = false; 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); IDLog("initializing from generic LX200 device...\n"); IDLog("Driver Version: 2012-07-27\n"); //enableSimulation(true); } LX200GenericLegacy::~LX200GenericLegacy() { } void LX200GenericLegacy::setCurrentDeviceName(const char * devName) { strcpy(thisDevice, devName); } void LX200GenericLegacy::ISGetProperties(const char *dev) { if (dev && strcmp (thisDevice, dev)) return; // COMM_GROUP IDDefSwitch (&ConnectSP, NULL); IDDefText (&PortTP, NULL); IDDefSwitch (&AlignmentSw, NULL); // BASIC_GROUP IDDefNumber (&EquatorialCoordsRNP, NULL); IDDefSwitch (&OnCoordSetSP, NULL); IDDefSwitch (&AbortSlewSP, NULL); // MOTION_GROUP IDDefNumber (&TrackingFreqNP, NULL); IDDefSwitch (&SlewModeSP, NULL); 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); IDDefSwitch(&FocusMotionSP, NULL); IDDefNumber(&FocusTimerNP, NULL); // DATETIME_GROUP #ifdef HAVE_NOVA_H IDDefText (&TimeTP, NULL); IDDefNumber(&UTCOffsetNP, NULL); #endif IDDefNumber (&SDTimeNP, NULL); // SITE_GROUP IDDefSwitch (&SitesSP, NULL); IDDefText (&SiteNameTP, NULL); IDDefNumber (&geoNP, NULL); /* Send the basic data to the new client if the previous client(s) are already connected. */ if (ConnectSP.s == IPS_OK) getBasicData(); } void LX200GenericLegacy::ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } void LX200GenericLegacy::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { int err; IText *tp; // ignore if not ours // if (strcmp (dev, thisDevice)) return; // suppress warning n=n; if (!strcmp(name, PortTP.name) ) { PortTP.s = IPS_OK; tp = IUFindText( &PortTP, names[0] ); if (!tp) return; IUSaveText(&PortTP.tp[0], texts[0]); IDSetText (&PortTP, NULL); return; } if (!strcmp (name, SiteNameTP.name) ) { if (checkPower(&SiteNameTP)) return; if ( ( err = setSiteName(fd, texts[0], currentSiteNum) < 0) ) { handleError(&SiteNameTP, err, "Setting site name"); return; } SiteNameTP.s = IPS_OK; tp = IUFindText(&SiteNameTP, names[0]); tp->text = new char[strlen(texts[0])+1]; strcpy(tp->text, texts[0]); IDSetText(&SiteNameTP , "Site name updated"); return; } #ifdef HAVE_NOVA_H if (!strcmp (name, TimeTP.name)) { if (checkPower(&TimeTP)) return; if (simulation) { TimeTP.s = IPS_OK; IUSaveText(&TimeTP.tp[0], texts[0]); IDSetText(&TimeTP, "Simulated time updated."); return; } struct ln_date utm; struct ln_zonedate ltm; if (*((int *) UTCOffsetN[0].aux0) == 0) { TimeTP.s = IPS_IDLE; IDSetText(&TimeTP, "You must set the UTC Offset property first."); return; } if (extractISOTime(texts[0], &utm) < 0) { TimeTP.s = IPS_IDLE; IDSetText(&TimeTP , "Time invalid"); return; } // update JD JD = ln_get_julian_day(&utm); IDLog("New JD is %f\n", (float) JD); ln_date_to_zonedate(&utm, <m, UTCOffsetN[0].value*3600.0); // Set Local Time if ( ( err = setLocalTime(fd, ltm.hours, ltm.minutes, ltm.seconds) < 0) ) { handleError(&TimeTP, err, "Setting local time"); return; } if (!strcmp(dev, "LX200 GPS")) { if ( ( err = setCalenderDate(fd, utm.days, utm.months, utm.years) < 0) ) { handleError(&TimeTP, err, "Setting TimeT date."); return; } } else { if ( ( err = setCalenderDate(fd, ltm.days, ltm.months, ltm.years) < 0) ) { handleError(&TimeTP, err, "Setting local date."); return; } } // Everything Ok, save time value if (IUUpdateText(&TimeTP, texts, names, n) < 0) return; TimeTP.s = IPS_OK; IDSetText(&TimeTP , "Time updated to %s, updating planetary data...", texts[0]); // Also update telescope's sidereal time getSDTime(fd, &SDTimeN[0].value); IDSetNumber(&SDTimeNP, NULL); } #endif } void LX200GenericLegacy::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { int h =0, m =0, s=0, err; double newRA =0, newDEC =0; // ignore if not ours // if (strcmp (dev, thisDevice)) return; // Slewing Accuracy if (!strcmp (name, SlewAccuracyNP.name)) { if (!IUUpdateNumber(&SlewAccuracyNP, values, names, n)) { SlewAccuracyNP.s = IPS_OK; IDSetNumber(&SlewAccuracyNP, NULL); return; } SlewAccuracyNP.s = IPS_ALERT; IDSetNumber(&SlewAccuracyNP, "unknown error while setting tracking precision"); return; } #ifdef HAVE_NOVA_H // DST Correct TimeT Offset if (!strcmp (name, UTCOffsetNP.name)) { if (strcmp(names[0], UTCOffsetN[0].name)) { UTCOffsetNP.s = IPS_ALERT; IDSetNumber( &UTCOffsetNP , "Unknown element %s for property %s.", names[0], UTCOffsetNP.label); return; } if (!simulation) if ( ( err = setUTCOffset(fd, (values[0] * -1.0)) < 0) ) { UTCOffsetNP.s = IPS_ALERT; IDSetNumber( &UTCOffsetNP , "Setting UTC Offset failed."); return; } *((int *) UTCOffsetN[0].aux0) = 1; IUUpdateNumber(&UTCOffsetNP, values, names, n); UTCOffsetNP.s = IPS_OK; IDSetNumber(&UTCOffsetNP, NULL); return; } #endif if (!strcmp (name, EquatorialCoordsRNP.name)) { int i=0, nset=0; if (checkPower(&EquatorialCoordsRNP)) return; for (nset = i = 0; i < n; i++) { INumber *eqp = IUFindNumber (&EquatorialCoordsRNP, names[i]); if (eqp == &EquatorialCoordsRN[0]) { newRA = values[i]; nset += newRA >= 0 && newRA <= 24.0; } else if (eqp == &EquatorialCoordsRN[1]) { newDEC = values[i]; nset += newDEC >= -90.0 && newDEC <= 90.0; } } if (nset == 2) { /*EquatorialCoordsWNP.s = IPS_BUSY;*/ char RAStr[32], DecStr[32]; fs_sexa(RAStr, newRA, 2, 3600); fs_sexa(DecStr, newDEC, 2, 3600); #ifdef INDI_DEBUG IDLog("We received JNOW RA %g - DEC %g\n", newRA, newDEC); IDLog("We received JNOW RA %s - DEC %s\n", RAStr, DecStr); #endif if (!simulation) if ( (err = setObjectRA(fd, newRA)) < 0 || ( err = setObjectDEC(fd, newDEC)) < 0) { EquatorialCoordsRNP.s = IPS_ALERT ; IDSetNumber(&EquatorialCoordsRNP, NULL); handleError(&EquatorialCoordsRNP, err, "Setting RA/DEC"); return; } /* wildi In principle this line is according to the discussion */ /* In case the telescope is slewing, we have to abort that. No status change here */ /* EquatorialCoordsWNP.s = IPS_OK; */ IDSetNumber(&EquatorialCoordsRNP, NULL); targetRA = newRA; targetDEC = newDEC; if (handleCoordSet()) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, NULL); } } // end nset else { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, "RA or Dec missing or invalid"); } return; } /* end EquatorialCoordsWNP */ // Update Sidereal Time if ( !strcmp (name, SDTimeNP.name) ) { if (checkPower(&SDTimeNP)) return; if (values[0] < 0.0 || values[0] > 24.0) { SDTimeNP.s = IPS_IDLE; IDSetNumber(&SDTimeNP , "Time invalid"); return; } getSexComponents(values[0], &h, &m, &s); IDLog("Sidereal Time is %02d:%02d:%02d\n", h, m, s); if ( ( err = setSDTime(fd, h, m, s) < 0) ) { handleError(&SDTimeNP, err, "Setting sidereal time"); return; } SDTimeNP.np[0].value = values[0]; SDTimeNP.s = IPS_OK; IDSetNumber(&SDTimeNP , "Sidereal time updated to %02d:%02d:%02d", h, m, s); return; } // Update Geographical Location if (!strcmp (name, geoNP.name)) { // new geographic coords double newLong = 0, newLat = 0; int i, nset; char msg[128]; if (checkPower(&geoNP)) return; for (nset = i = 0; i < n; i++) { INumber *geop = IUFindNumber (&geoNP, names[i]); if (geop == &geo[0]) { newLat = values[i]; nset += newLat >= -90.0 && newLat <= 90.0; } else if (geop == &geo[1]) { newLong = values[i]; nset += newLong >= 0.0 && newLong < 360.0; } } if (nset == 2) { char l[32], L[32]; geoNP.s = IPS_OK; fs_sexa (l, newLat, 3, 3600); fs_sexa (L, newLong, 4, 3600); if (!simulation) { if ( ( err = setSiteLongitude(fd, 360.0 - newLong) < 0) ) { handleError(&geoNP, err, "Setting site longitude coordinates"); return; } if ( ( err = setSiteLatitude(fd, newLat) < 0) ) { handleError(&geoNP, err, "Setting site latitude coordinates"); return; } } geoNP.np[0].value = newLat; geoNP.np[1].value = newLong; snprintf (msg, sizeof(msg), "Site location updated to Lat %.32s - Long %.32s", l, L); } else { geoNP.s = IPS_IDLE; strcpy(msg, "Lat or Long missing or invalid"); } IDSetNumber (&geoNP, "%s", msg); return; } // Update Frequency if ( !strcmp (name, TrackingFreqNP.name) ) { if (checkPower(&TrackingFreqNP)) return; IDLog("Trying to set track freq of: %f\n", values[0]); if ( ( err = setTrackFreq(fd, values[0])) < 0) { handleError(&TrackingFreqNP, err, "Setting tracking frequency"); return; } TrackingFreqNP.s = IPS_OK; TrackingFreqNP.np[0].value = values[0]; IDSetNumber(&TrackingFreqNP, "Tracking frequency set to %04.1f", values[0]); if (trackingMode != LX200_TRACK_MANUAL) { trackingMode = LX200_TRACK_MANUAL; TrackModeS[0].s = ISS_OFF; TrackModeS[1].s = ISS_OFF; TrackModeS[2].s = ISS_ON; TrackModeSP.s = IPS_OK; selectTrackingMode(fd, trackingMode); IDSetSwitch(&TrackModeSP, NULL); } return; } if (!strcmp(name, FocusTimerNP.name)) { if (checkPower(&FocusTimerNP)) return; // Don't update if busy if (FocusTimerNP.s == IPS_BUSY) return; IUUpdateNumber(&FocusTimerNP, values, names, n); FocusTimerNP.s = IPS_OK; IDSetNumber(&FocusTimerNP, NULL); IDLog("Setting focus timer to %g\n", FocusTimerN[0].value); return; } if (!strcmp(name, GuideNSNP.name)) { long 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)) { long 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; direction = LX200_WEST; } else { duration_msec = GuideWENP.np[1].value; 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 LX200GenericLegacy::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int err=0, index=0; INDI_UNUSED(names); // ignore if not ours // if (strcmp (thisDevice, dev)) return; // FIRST Switch ALWAYS for power if (!strcmp (name, ConnectSP.name)) { bool connectionEstablished = (ConnectS[0].s == ISS_ON); if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return; if ( (connectionEstablished && ConnectS[0].s == ISS_ON) || (!connectionEstablished && ConnectS[1].s == ISS_ON)) { ConnectSP.s = IPS_OK; IDSetSwitch(&ConnectSP, NULL); return; } connectTelescope(); return; } // Coord set if (!strcmp(name, OnCoordSetSP.name)) { if (checkPower(&OnCoordSetSP)) return; if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return; currentSet = getOnSwitch(&OnCoordSetSP); OnCoordSetSP.s = IPS_OK; IDSetSwitch(&OnCoordSetSP, NULL); } // Abort Slew if (!strcmp (name, AbortSlewSP.name)) { if (checkPower(&AbortSlewSP)) { AbortSlewSP.s = IPS_IDLE; IDSetSwitch(&AbortSlewSP, NULL); return; } IUResetSwitch(&AbortSlewSP); if (!simulation && abortSlew(fd) < 0) { AbortSlewSP.s = IPS_ALERT; IDSetSwitch(&AbortSlewSP, NULL); return; } if (EquatorialCoordsRNP.s == IPS_BUSY) { AbortSlewSP.s = IPS_OK; EquatorialCoordsRNP.s = IPS_IDLE; IDSetSwitch(&AbortSlewSP, "Slew aborted."); IDSetNumber(&EquatorialCoordsRNP, NULL); } else if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) { MovementNSSP.s = MovementWESP.s = IPS_IDLE; AbortSlewSP.s = IPS_OK; EquatorialCoordsRNP.s = IPS_IDLE; IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); IUResetSwitch(&AbortSlewSP); IDSetSwitch(&AbortSlewSP, "Slew aborted."); IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); IDSetNumber(&EquatorialCoordsRNP, 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; EquatorialCoordsRNP.s = IPS_IDLE; IUResetSwitch(&AbortSlewSP); IDSetSwitch(&AbortSlewSP, "Guide aborted."); IDSetNumber(&GuideNSNP, NULL); IDSetNumber(&GuideWENP, NULL); IDSetNumber(&EquatorialCoordsRNP, NULL); } else { AbortSlewSP.s = IPS_OK; IDSetSwitch(&AbortSlewSP, NULL); } return; } // Alignment if (!strcmp (name, AlignmentSw.name)) { if (checkPower(&AlignmentSw)) return; if (IUUpdateSwitch(&AlignmentSw, states, names, n) < 0) return; index = getOnSwitch(&AlignmentSw); if ( ( err = setAlignmentMode(fd, index) < 0) ) { handleError(&AlignmentSw, err, "Setting alignment"); return; } AlignmentSw.s = IPS_OK; IDSetSwitch (&AlignmentSw, NULL); return; } // Sites if (!strcmp (name, SitesSP.name)) { int dd=0, mm=0; if (checkPower(&SitesSP)) return; if (IUUpdateSwitch(&SitesSP, states, names, n) < 0) return; currentSiteNum = getOnSwitch(&SitesSP) + 1; if ( ( err = selectSite(fd, currentSiteNum) < 0) ) { handleError(&SitesSP, err, "Selecting sites"); return; } if ( ( err = getSiteLatitude(fd, &dd, &mm) < 0)) { handleError(&SitesSP, err, "Selecting sites"); return; } if (dd > 0) geoNP.np[0].value = dd + mm / 60.0; else geoNP.np[0].value = dd - mm / 60.0; if ( ( err = getSiteLongitude(fd, &dd, &mm) < 0)) { handleError(&SitesSP, err, "Selecting sites"); return; } if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm / 60.0); else geoNP.np[1].value = (dd - mm / 60.0) * -1.0; getSiteName(fd, SiteNameTP.tp[0].text, currentSiteNum); IDLog("Selecting site %d\n", currentSiteNum); geoNP.s = SiteNameTP.s = SitesSP.s = IPS_OK; IDSetNumber (&geoNP, NULL); IDSetText (&SiteNameTP, NULL); IDSetSwitch (&SitesSP, NULL); return; } // Focus Motion if (!strcmp (name, FocusMotionSP.name)) { if (checkPower(&FocusMotionSP)) return; // If mode is "halt" if (FocusModeS[0].s == ISS_ON) { FocusMotionSP.s = IPS_IDLE; IDSetSwitch(&FocusMotionSP, NULL); return; } if (IUUpdateSwitch(&FocusMotionSP, states, names, n) < 0) return; index = getOnSwitch(&FocusMotionSP); if ( ( err = setFocuserMotion(fd, index) < 0) ) { handleError(&FocusMotionSP, err, "Setting focuser speed"); return; } FocusMotionSP.s = IPS_BUSY; // with a timer if (FocusTimerN[0].value > 0) { FocusTimerNP.s = IPS_BUSY; IEAddTimer(50, LX200GenericLegacy::updateFocusTimer, this); } IDSetSwitch(&FocusMotionSP, NULL); return; } // Slew mode if (!strcmp (name, SlewModeSP.name)) { if (checkPower(&SlewModeSP)) return; if (IUUpdateSwitch(&SlewModeSP, states, names, n) < 0) return; index = getOnSwitch(&SlewModeSP); if ( ( err = setSlewMode(fd, index) < 0) ) { handleError(&SlewModeSP, err, "Setting slew mode"); return; } SlewModeSP.s = IPS_OK; IDSetSwitch(&SlewModeSP, NULL); return; } // Movement (North/South) if (!strcmp (name, MovementNSSP.name)) { 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; // -1 means all off previously last_move = getOnSwitch(&MovementNSSP); if (IUUpdateSwitch(&MovementNSSP, states, names, n) < 0) return; current_move = getOnSwitch(&MovementNSSP); // Previosuly active switch clicked again, so let's stop. if (current_move == last_move) { HaltMovement(fd, (current_move == 0) ? LX200_NORTH : LX200_SOUTH); IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); return; } #ifdef INDI_DEBUG IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); #endif // 0 (North) or 1 (South) last_move = current_move; // Correction for LX200 Driver: North 0 - South 3 current_move = (current_move == 0) ? LX200_NORTH : LX200_SOUTH; if ( ( err = MoveTo(fd, current_move) < 0) ) { handleError(&MovementNSSP, err, "Setting motion direction"); return; } MovementNSSP.s = IPS_BUSY; IDSetSwitch(&MovementNSSP, "Moving toward %s", (current_move == LX200_NORTH) ? "North" : "South"); return; } // Movement (West/East) if (!strcmp (name, MovementWESP.name)) { 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; // -1 means all off previously last_move = getOnSwitch(&MovementWESP); if (IUUpdateSwitch(&MovementWESP, states, names, n) < 0) return; current_move = getOnSwitch(&MovementWESP); // Previosuly active switch clicked again, so let's stop. if (current_move == last_move) { HaltMovement(fd, (current_move ==0) ? LX200_WEST : LX200_EAST); IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, NULL); return; } #ifdef INDI_DEBUG IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); #endif // 0 (West) or 1 (East) last_move = current_move; // Correction for LX200 Driver: West 1 - East 2 current_move = (current_move == 0) ? LX200_WEST : LX200_EAST; if ( ( err = MoveTo(fd, current_move) < 0) ) { handleError(&MovementWESP, err, "Setting motion direction"); return; } MovementWESP.s = IPS_BUSY; IDSetSwitch(&MovementWESP, "Moving toward %s", (current_move == LX200_WEST) ? "West" : "East"); return; } // Tracking mode if (!strcmp (name, TrackModeSP.name)) { if (checkPower(&TrackModeSP)) return; IUResetSwitch(&TrackModeSP); IUUpdateSwitch(&TrackModeSP, states, names, n); trackingMode = getOnSwitch(&TrackModeSP); if ( ( err = selectTrackingMode(fd, trackingMode) < 0) ) { handleError(&TrackModeSP, err, "Setting tracking mode."); return; } getTrackFreq(fd, &TrackFreqN[0].value); TrackModeSP.s = IPS_OK; IDSetNumber(&TrackingFreqNP, NULL); IDSetSwitch(&TrackModeSP, NULL); return; } // Focus speed if (!strcmp (name, FocusModeSP.name)) { if (checkPower(&FocusModeSP)) return; IUResetSwitch(&FocusModeSP); IUUpdateSwitch(&FocusModeSP, states, names, n); index = getOnSwitch(&FocusModeSP); /* disable timer and motion */ if (index == 0) { IUResetSwitch(&FocusMotionSP); FocusMotionSP.s = IPS_IDLE; FocusTimerNP.s = IPS_IDLE; IDSetSwitch(&FocusMotionSP, NULL); IDSetNumber(&FocusTimerNP, NULL); } setFocuserSpeedMode(fd, index); FocusModeSP.s = IPS_OK; IDSetSwitch(&FocusModeSP, NULL); 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 LX200GenericLegacy::handleError(ISwitchVectorProperty *svp, int err, const char *msg) { svp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_lx200_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetSwitch(svp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property or busy*/ if (err == -2) { svp->s = IPS_ALERT; IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetSwitch( svp , "%s failed.", msg); fault = true; } void LX200GenericLegacy::handleError(INumberVectorProperty *nvp, int err, const char *msg) { nvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_lx200_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetNumber(nvp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { nvp->s = IPS_ALERT; IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetNumber( nvp , "%s failed.", msg); fault = true; } void LX200GenericLegacy::handleError(ITextVectorProperty *tvp, int err, const char *msg) { tvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_lx200_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetText(tvp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { tvp->s = IPS_ALERT; IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetText( tvp , "%s failed.", msg); fault = true; } void LX200GenericLegacy::correctFault() { fault = false; IDMessage(thisDevice, "Telescope is online."); } bool LX200GenericLegacy::isTelescopeOn(void) { //if (simulation) return true; return (ConnectSP.sp[0].s == ISS_ON); } static void retryConnection(void * p) { int fd = *( (int *) p); if (check_lx200_connection(fd)) { ConnectSP.s = IPS_IDLE; IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); return; } ConnectS[0].s = ISS_ON; ConnectS[1].s = ISS_OFF; ConnectSP.s = IPS_OK; IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); } void LX200GenericLegacy::updateFocusTimer(void *p) { int err=0; switch (FocusTimerNP.s) { case IPS_IDLE: break; case IPS_BUSY: IDLog("Focus Timer Value is %g\n", FocusTimerN[0].value); FocusTimerN[0].value-=50; if (FocusTimerN[0].value <= 0) { IDLog("Focus Timer Expired\n"); if ( ( err = setFocuserSpeedMode(telescope->fd, 0) < 0) ) { telescope->handleError(&FocusModeSP, err, "setting focuser mode"); IDLog("Error setting focuser mode\n"); return; } FocusMotionSP.s = IPS_IDLE; FocusTimerNP.s = IPS_OK; FocusModeSP.s = IPS_OK; IUResetSwitch(&FocusMotionSP); IUResetSwitch(&FocusModeSP); FocusModeS[0].s = ISS_ON; IDSetSwitch(&FocusModeSP, NULL); IDSetSwitch(&FocusMotionSP, NULL); } IDSetNumber(&FocusTimerNP, NULL); if (FocusTimerN[0].value > 0) IEAddTimer(50, LX200GenericLegacy::updateFocusTimer, p); break; case IPS_OK: break; case IPS_ALERT: break; } } void LX200GenericLegacy::guideTimeout(void *p) { long direction = (long)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 LX200GenericLegacy::ISPoll() { double dx, dy; int err=0; if (!isTelescopeOn()) return; if (simulation) { mountSim(); return; } if ( (err = getLX200RA(fd, ¤tRA)) < 0 || (err = getLX200DEC(fd, ¤tDEC)) < 0) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, NULL); handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC"); return; } if (fault) correctFault(); switch (EquatorialCoordsRNP.s) { case IPS_IDLE: case IPS_OK: if ( fabs(lastRA - currentRA) > (SlewAccuracyN[0].value/(60.0*15.0)) || fabs(lastDEC - currentDEC) > (SlewAccuracyN[1].value/60.0)) { lastRA = currentRA; lastDEC = currentDEC; IDSetNumber (&EquatorialCoordsRNP, NULL); } break; case IPS_BUSY: dx = targetRA - currentRA; dy = targetDEC - currentDEC; // Wait until acknowledged or within threshold if ( fabs(dx) <= (SlewAccuracyN[0].value/(60.0*15.0)) && fabs(dy) <= (SlewAccuracyN[1].value/60.0)) { lastRA = currentRA; lastDEC = currentDEC; EquatorialCoordsRNP.s = IPS_OK; IDSetNumber(&EquatorialCoordsRNP, "Slew is complete, target locked..."); } break; case IPS_ALERT: break; } } // wildi nothing changed in LX200GenericLegacy::mountSim void LX200GenericLegacy::mountSim () { static struct timeval ltv; struct timeval tv; double dt, da, dx; int nlocked; /* update elapsed time since last poll, don't presume exactly POLLMS */ gettimeofday (&tv, NULL); if (ltv.tv_sec == 0 && ltv.tv_usec == 0) ltv = tv; dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; ltv = tv; da = SLEWRATE*dt; /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */ switch (EquatorialCoordsRNP.s) { /* #1 State is idle, update telesocpe at sidereal rate */ case IPS_IDLE: /* RA moves at sidereal, Dec stands still */ currentRA += (SIDRATE*dt/15.); IDSetNumber(&EquatorialCoordsRNP, NULL); break; case IPS_BUSY: /* slewing - nail it when both within one pulse @ SLEWRATE */ nlocked = 0; dx = targetRA - currentRA; if (fabs(dx) <= da) { currentRA = targetRA; nlocked++; } else if (dx > 0) currentRA += da/15.; else currentRA -= da/15.; dx = targetDEC - currentDEC; if (fabs(dx) <= da) { currentDEC = targetDEC; nlocked++; } else if (dx > 0) currentDEC += da; else currentDEC -= da; if (nlocked == 2) { EquatorialCoordsRNP.s = IPS_OK; IDSetNumber(&EquatorialCoordsRNP, "Now tracking"); } else IDSetNumber(&EquatorialCoordsRNP, NULL); break; case IPS_OK: /* tracking */ IDSetNumber(&EquatorialCoordsRNP, NULL); break; case IPS_ALERT: break; } } void LX200GenericLegacy::getBasicData() { int err; #ifdef HAVE_NOVA_H struct tm *timep; time_t ut; time (&ut); timep = gmtime (&ut); strftime (TimeTP.tp[0].text, strlen(TimeTP.tp[0].text), "%Y-%m-%dT%H:%M:%S", timep); IDLog("PC UTC time is %s\n", TimeTP.tp[0].text); #endif getAlignment(); checkLX200Format(fd); if ( (err = getTimeFormat(fd, &timeFormat)) < 0) IDMessage(thisDevice, "Failed to retrieve time format from device."); else { timeFormat = (timeFormat == 24) ? LX200_24 : LX200_AM; // We always do 24 hours if (timeFormat != LX200_24) err = toggleTimeFormat(fd); } // wildi proposal if ( (err = getLX200RA(fd, &targetRA)) < 0 || (err = getLX200DEC(fd, &targetDEC)) < 0) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, NULL); handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC"); return; } if (fault) correctFault(); // getLX200RA(fd, &targetRA); // getLX200DEC(fd, &targetDEC); EquatorialCoordsRNP.np[0].value = targetRA; EquatorialCoordsRNP.np[1].value = targetDEC; EquatorialCoordsRNP.s = IPS_OK; IDSetNumber (&EquatorialCoordsRNP, NULL); SiteNameT[0].text = new char[64]; if ( (err = getSiteName(fd, SiteNameT[0].text, currentSiteNum)) < 0) IDMessage(thisDevice, "Failed to get site name from device"); else IDSetText (&SiteNameTP, NULL); if ( (err = getTrackFreq(fd, &TrackFreqN[0].value)) < 0) IDMessage(thisDevice, "Failed to get tracking frequency from device."); else IDSetNumber (&TrackingFreqNP, NULL); /*updateLocation(); updateTime();*/ } int LX200GenericLegacy::handleCoordSet() { int err; char syncString[256]; char RAStr[32], DecStr[32]; switch (currentSet) { // Slew case LX200_TRACK: lastSet = LX200_TRACK; if (EquatorialCoordsRNP.s == IPS_BUSY) { #ifdef INDI_DEBUG IDLog("Aborting Slew\n"); #endif if (!simulation && abortSlew(fd) < 0) { AbortSlewSP.s = IPS_ALERT; IDSetSwitch(&AbortSlewSP, NULL); slewError(err); return (-1); } AbortSlewSP.s = IPS_OK; EquatorialCoordsRNP.s = IPS_IDLE; IDSetSwitch(&AbortSlewSP, "Slew aborted."); IDSetNumber(&EquatorialCoordsRNP, NULL); if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) { MovementNSSP.s = MovementWESP.s = IPS_IDLE; EquatorialCoordsRNP.s = IPS_IDLE; IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); IUResetSwitch(&AbortSlewSP); IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); } // sleep for 100 mseconds usleep(100000); } if (!simulation && (err = Slew(fd))) /* Slew reads the '0', that is not the end of the slew */ { IDMessage(mydev "ERROR Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); slewError(err); return -1; } EquatorialCoordsRNP.s = IPS_BUSY; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); #ifdef INDI_DEBUG IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); #endif break; // Sync case LX200_SYNC: lastSet = LX200_SYNC; if (!simulation) if ( ( err = Sync(fd, syncString) < 0) ) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP , "Synchronization failed."); return (-1); } EquatorialCoordsRN[0].value = targetRA; EquatorialCoordsRN[1].value = targetDEC; EquatorialCoordsRNP.s = IPS_OK; IDLog("Synchronization successful %s\n", syncString); IDSetNumber(&EquatorialCoordsRNP, "Synchronization successful."); break; } return (0); } int LX200GenericLegacy::getOnSwitch(ISwitchVectorProperty *sp) { for (int i=0; i < sp->nsp ; i++) if (sp->sp[i].s == ISS_ON) return i; return -1; } int LX200GenericLegacy::checkPower(ISwitchVectorProperty *sp) { if (simulation) return 0; if (ConnectSP.s != IPS_OK) { if (!strcmp(sp->label, "")) IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->name); else IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", sp->label); sp->s = IPS_IDLE; IDSetSwitch(sp, NULL); return -1; } return 0; } int LX200GenericLegacy::checkPower(INumberVectorProperty *np) { if (simulation) return 0; if (ConnectSP.s != IPS_OK) { if (!strcmp(np->label, "")) IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->name); else IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", np->label); np->s = IPS_IDLE; IDSetNumber(np, NULL); return -1; } return 0; } int LX200GenericLegacy::checkPower(ITextVectorProperty *tp) { if (simulation) return 0; if (ConnectSP.s != IPS_OK) { if (!strcmp(tp->label, "")) IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->name); else IDMessage (thisDevice, "Cannot change property %s while the telescope is offline.", tp->label); tp->s = IPS_IDLE; IDSetText(tp, NULL); return -1; } return 0; } void LX200GenericLegacy::connectTelescope() { switch (ConnectSP.sp[0].s) { case ISS_ON: if (simulation) { ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Simulated telescope is online."); //updateTime(); return; } tty_disconnect(fd); // Close if already open if (tty_connect(PortTP.tp[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text); return; } if (check_lx200_connection(fd)) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); return; } #ifdef INDI_DEBUG IDLog("Telescope test successful.\n"); #endif *((int *) UTCOffsetN[0].aux0) = 0; ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); getBasicData(); break; case ISS_OFF: ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_IDLE; IDSetSwitch (&ConnectSP, "Telescope is offline."); IDLog("Telescope is offline."); tty_disconnect(fd); break; } } void LX200GenericLegacy::slewError(int slewCode) { EquatorialCoordsRNP.s = IPS_ALERT; if (slewCode == 1) IDSetNumber(&EquatorialCoordsRNP, "Object below horizon."); else if (slewCode == 2) IDSetNumber(&EquatorialCoordsRNP, "Object below the minimum elevation limit."); else IDSetNumber(&EquatorialCoordsRNP, "Slew failed."); } void LX200GenericLegacy::getAlignment() { if (ConnectSP.s != IPS_OK) return; signed char align = ACK(fd); if (align < 0) { IDSetSwitch (&AlignmentSw, "Failed to get telescope alignment."); return; } AlignmentS[0].s = ISS_OFF; AlignmentS[1].s = ISS_OFF; AlignmentS[2].s = ISS_OFF; switch (align) { case 'P': AlignmentS[0].s = ISS_ON; break; case 'A': AlignmentS[1].s = ISS_ON; break; case 'L': AlignmentS[2].s = ISS_ON; break; } AlignmentSw.s = IPS_OK; IDSetSwitch (&AlignmentSw, NULL); IDLog("ACK success %c\n", align); } void LX200GenericLegacy::enableSimulation(bool enable) { simulation = enable; if (simulation) IDLog("Warning: Simulation is activated.\n"); else IDLog("Simulation is disabled.\n"); } void LX200GenericLegacy::updateTime() { #ifdef HAVE_NOVA_H char cdate[32]; double ctime; int h, m, s, lx200_utc_offset=0; int day, month, year, result; struct tm ltm; struct tm utm; time_t time_epoch; if (simulation) { sprintf(TimeT[0].text, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30); IDLog("Telescope ISO date and time: %s\n", TimeT[0].text); IDSetText(&TimeTP, NULL); return; } getUTCOffset(fd, &lx200_utc_offset); // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition. UTCOffsetN[0].value = lx200_utc_offset*-1; // We got a valid value for UTCOffset now *((int *) UTCOffsetN[0].aux0) = 1; #ifdef INDI_DEBUG IDLog("Telescope TimeT Offset: %g\n", UTCOffsetN[0].value); #endif getLocalTime24(fd, &ctime); getSexComponents(ctime, &h, &m, &s); if ( (result = getSDTime(fd, &SDTimeN[0].value)) < 0) IDMessage(thisDevice, "Failed to retrieve sidereal time from device."); getCalenderDate(fd, cdate); result = sscanf(cdate, "%d/%d/%d", &year, &month, &day); if (result != 3) return; // Let's fill in the local time ltm.tm_sec = s; ltm.tm_min = m; ltm.tm_hour = h; ltm.tm_mday = day; ltm.tm_mon = month - 1; ltm.tm_year = year - 1900; // Get time epoch time_epoch = mktime(<m); // Convert to TimeT time_epoch -= (int) (UTCOffsetN[0].value * 60.0 * 60.0); // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time) localtime_r(&time_epoch, &utm); /* Format it into ISO 8601 */ strftime(cdate, 32, "%Y-%m-%dT%H:%M:%S", &utm); IUSaveText(&TimeT[0], cdate); #ifdef INDI_DEBUG IDLog("Telescope Local Time: %02d:%02d:%02d\n", h, m , s); IDLog("Telescope SD Time is: %g\n", SDTimeN[0].value); IDLog("Telescope UTC Time: %s\n", TimeT[0].text); #endif // Let's send everything to the client IDSetText(&TimeTP, NULL); IDSetNumber(&SDTimeNP, NULL); IDSetNumber(&UTCOffsetNP, NULL); #endif } void LX200GenericLegacy::updateLocation() { int dd = 0, mm = 0, err = 0; if (simulation) return; if ( (err = getSiteLatitude(fd, &dd, &mm)) < 0) IDMessage(thisDevice, "Failed to get site latitude from device."); else { if (dd > 0) geoNP.np[0].value = dd + mm/60.0; else geoNP.np[0].value = dd - mm/60.0; IDLog("Autostar Latitude: %d:%d\n", dd, mm); IDLog("INDI Latitude: %g\n", geoNP.np[0].value); } if ( (err = getSiteLongitude(fd, &dd, &mm)) < 0) IDMessage(thisDevice, "Failed to get site longitude from device."); else { if (dd > 0) geoNP.np[1].value = 360.0 - (dd + mm/60.0); else geoNP.np[1].value = (dd - mm/60.0) * -1.0; IDLog("Autostar Longitude: %d:%d\n", dd, mm); IDLog("INDI Longitude: %g\n", geoNP.np[1].value); } IDSetNumber (&geoNP, NULL); } libindi-0.9.7/drivers/telescope/lx200gps.h0000644000175000017500000000360512241463551017321 0ustar jasemjasem#ifndef LX200GPS_H #define LX200GPS_H /* LX200 GPS Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "lx200autostar.h" class LX200GPS : public LX200Autostar { public: LX200GPS(); ~LX200GPS() {} const char *getDefaultName(); bool initProperties(); bool updateProperties(); void ISGetProperties (const char *dev); bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool updateTime(ln_date *utc, double utc_offset); protected: ISwitchVectorProperty GPSPowerSP; ISwitch GPSPowerS[2]; ISwitchVectorProperty GPSStatusSP; ISwitch GPSStatusS[3]; ISwitchVectorProperty GPSUpdateSP; ISwitch GPSUpdateS[2]; ISwitchVectorProperty AltDecPecSP; ISwitch AltDecPecS[2]; ISwitchVectorProperty AzRaPecSP; ISwitch AzRaPecS[2]; ISwitchVectorProperty SelenSyncSP; ISwitch SelenSyncS[1]; ISwitchVectorProperty AltDecBacklashSP; ISwitch AltDecBacklashS[1]; ISwitchVectorProperty AzRaBacklashSP; ISwitch AzRaBacklashS[1]; ISwitchVectorProperty OTAUpdateSP; ISwitch OTAUpdateS[1]; INumberVectorProperty OTATempNP; INumber OTATempN[1]; }; #endif libindi-0.9.7/drivers/telescope/skycommander.c0000644000175000017500000001131112241463551020422 0ustar jasemjasem#if 0 Sky Commander INDI driver Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include "indidevapi.h" #include "indicom.h" #include "lx200driver.h" #define mydev "Sky Commander" #define BASIC_GROUP "Main Control" #define POLLMS 1000 #define currentRA eq[0].value #define currentDEC eq[1].value static void ISPoll(void *); static void ISInit(void); static void connectTelescope(void); int fd; static ISwitch PowerS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}}; ISwitchVectorProperty PowerSP = { mydev, "CONNECTION" , "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0}; static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}}; static ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0}; /* equatorial position */ INumber eq[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}, }; INumberVectorProperty eqNum = { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 0, IPS_IDLE, eq, NARRAY(eq), "", 0}; void ISInit(void) { static int isInit=0; if (isInit) return; isInit = 1; fd = -1; IEAddTimer (POLLMS, ISPoll, NULL); } void ISGetProperties (const char *dev) { ISInit(); dev=dev; IDDefSwitch(&PowerSP, NULL); IDDefText(&PortTP, NULL); IDDefNumber(&eqNum, NULL); } void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); dev = dev; if (!strcmp(name, PowerSP.name)) { IUResetSwitch(&PowerSP); IUUpdateSwitch(&PowerSP, states, names, n); connectTelescope(); return; } } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); dev=dev; names=names; n=n; if (!strcmp(name, PortTP.name)) { IUSaveText(&PortT[0], texts[0]); PortTP.s = IPS_OK; IDSetText(&PortTP, NULL); return; } } void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { dev=dev;name=name;values=values;names=names;n=n; } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } void ISPoll (void *p) { p=p; if (PowerS[0].s == ISS_ON) { switch (eqNum.s) { case IPS_IDLE: case IPS_OK: case IPS_BUSY: if (updateSkyCommanderCoord(fd, ¤tRA, ¤tDEC) < 0) { eqNum.s = IPS_ALERT; IDSetNumber(&eqNum, "Unknown error while reading telescope coordinates"); IDLog("Unknown error while reading telescope coordinates\n"); break; } IDSetNumber(&eqNum, NULL); break; case IPS_ALERT: break; } } IEAddTimer(POLLMS, ISPoll, NULL); } void connectTelescope(void) { switch (PowerS[0].s) { case ISS_ON: if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) { PowerSP.s = IPS_ALERT; IUResetSwitch(&PowerSP); IDSetSwitch(&PowerSP, "Error connecting to port %s", PortT[0].text); return; } PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Sky Commander is online."); break; case ISS_OFF: tty_disconnect(fd); IUResetSwitch(&PowerSP); eqNum.s = PortTP.s = PowerSP.s = IPS_IDLE; IDSetSwitch(&PowerSP, "Sky Commander is offline."); IDSetText(&PortTP, NULL); IDSetNumber(&eqNum, NULL); break; } } libindi-0.9.7/drivers/telescope/synscanmount.h0000644000175000017500000000263612241463551020506 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef SYNSCANMOUNT_H #define SYNSCANMOUNT_H #include "indibase/inditelescope.h" class SynscanMount : public INDI::Telescope { public: SynscanMount(); virtual ~SynscanMount(); // overrides of base class virtual functions bool initProperties(); void ISGetProperties (const char *dev); const char *getDefaultName(); bool ReadScopeStatus(); bool Goto(double,double); bool Park(); bool Abort(); bool canPark(); }; #endif // SYNSCANMOUNT_H libindi-0.9.7/drivers/telescope/celestrongps.h0000644000175000017500000000542412241463551020453 0ustar jasemjasem/* Celestron GPS Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef CELESTRONGPS_H #define CELESTRONGPS_H #include #include "indidevapi.h" #include "indicom.h" #include "indicontroller.h" #define POLLMS 1000 /* poll period, ms */ class CelestronGPS : public INDI::Telescope { public: CelestronGPS(); virtual ~CelestronGPS() {} virtual const char *getDefaultName(); virtual bool Connect(); virtual bool Connect(char *); virtual bool Disconnect(); virtual bool ReadScopeStatus(); virtual void ISGetProperties(const char *dev); virtual bool initProperties(); virtual bool updateProperties(); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISSnoopDevice(XMLEle *root); static void joystickHelper(const char * joystick_n, double mag, double angle); static void buttonHelper(const char * button_n, ISState state); protected: virtual bool MoveNS(TelescopeMotionNS dir); virtual bool MoveWE(TelescopeMotionWE dir); virtual bool Abort(); virtual bool updateLocation(double latitude, double longitude, double elevation); virtual bool updateTime(ln_date *utc, double utc_offset); virtual bool saveConfigItems(FILE *fp); bool Goto(double ra,double dec); bool Sync(double ra, double dec); virtual bool canSync(); virtual bool canPark(); void slewError(int slewCode); void mountSim(); void processNSWE(double mag, double angle); void processJoystick(const char * joystick_n, double mag, double angle); void processButton(const char * button_n, ISState state); /* Slew Speed */ ISwitchVectorProperty SlewModeSP; ISwitch SlewModeS[4]; private: int timeFormat; double lastRA; double lastDEC; INDI::Controller *controller; int lastSet; int currentSet; double currentRA, currentDEC; double targetRA, targetDEC; }; #endif libindi-0.9.7/drivers/telescope/telescope_simulator.h0000644000175000017500000000337312241463551022026 0ustar jasemjasem#ifndef SCOPESIM_H #define SCOPESIM_H #include "indibase/indiguiderinterface.h" #include "indibase/inditelescope.h" class ScopeSim : public INDI::Telescope, public INDI::GuiderInterface { public: ScopeSim(); virtual ~ScopeSim(); virtual const char *getDefaultName(); virtual bool Connect(); virtual bool Connect(char *); virtual bool Disconnect(); virtual bool ReadScopeStatus(); virtual bool initProperties(); virtual void ISGetProperties (const char *dev); virtual bool updateProperties(); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); protected: virtual bool MoveNS(TelescopeMotionNS dir); virtual bool MoveWE(TelescopeMotionWE dir); virtual bool Abort(); virtual bool GuideNorth(float ms); virtual bool GuideSouth(float ms); virtual bool GuideEast(float ms); virtual bool GuideWest(float ms); bool Goto(double,double); bool Park(); bool Sync(double ra, double dec); bool canSync(); bool canPark(); private: double currentRA; double currentDEC; double targetRA; double targetDEC; unsigned int DBG_SCOPE; bool Parked; double guiderEWTarget[2]; double guiderNSTarget[2]; INumber GuideRateN[2]; INumberVectorProperty GuideRateNP; INumberVectorProperty EqPENV; INumber EqPEN[2]; ISwitch PEErrNSS[2]; ISwitchVectorProperty PEErrNSSP; ISwitch PEErrWES[2]; ISwitchVectorProperty PEErrWESP; }; #endif // SCOPESIM_H libindi-0.9.7/drivers/telescope/lx200apdriver.h0000644000175000017500000000434112241463551020342 0ustar jasemjasem/* LX200 AP Driver Copyright (C) 2007 Markus Wildi 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 */ #ifndef LX200APDRIVER_H #define LX200APDRIVER_H #endif #define getAPDeclinationAxis(fd, x) getCommandString(fd, x, "#:pS#") #define getAPVersionNumber(fd, x) getCommandString(fd, x, "#:V#") #define setAPPark( fd) write(fd, "#:KA", 4) #define setAPUnPark( fd) write(fd, "#:PO", 4) #define setAPLongFormat( fd) write(fd, "#:U", 3) #define setAPClearBuffer( fd) write(fd, "#", 1) /* AP key pad manual startup sequence */ #define setAPBackLashCompensation(fd, x,y,z) setCommandXYZ(fd, x,y,z, "#:Br") #define setAPMotionStop( fd) write(fd, "#:Q", 3) #ifdef __cplusplus extern "C" { #endif int check_lx200ap_connection(int fd) ; int initializeAPmount(int fd) ; int getAPUTCOffset (int fd, double *value) ; int setAPObjectAZ(int fd, double az); int setAPObjectAlt(int fd, double alt); int setAPUTCOffset(int fd, double hours) ; int setAPSlewMode(int fd, int slewMode) ; int APSyncCM(int fd, char *matchedObject) ; int APSyncCMR(int fd, char *matchedObject) ; int selectAPMoveToRate(int fd, int moveToRate) ; int selectAPSlewRate(int fd, int slewRate) ; int selectAPTrackingMode(int fd, int trackMode) ; int swapAPButtons(int fd, int currentSwap) ; int setAPObjectRA(int fd, double ra) ; int setAPObjectDEC(int fd, double dec) ; int setAPSiteLongitude(int fd, double Long) ; int setAPSiteLatitude(int fd, double Lat) ; #ifdef __cplusplus } #endif libindi-0.9.7/drivers/telescope/temmadriver.h0000644000175000017500000002177012241463551020264 0ustar jasemjasem/* 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 */ #ifndef TEMMADRIVER_H #define TEMMADRIVER_H #define VERSION "Temma indi driver Ver 0.0, fm-2004/10/09" #if 0 bit definition for M message : slew speed and parameters #endif #define HS 0x01 /* high speed */ #define RR 0x02 /* RA right */ #define RL 0x04 /* RA left */ #define DU 0x08 /* DEC up */ #define DD 0x10 /* DEC down */ #define EN 0x20 /* ENC on */ #define BB 0x40 /* Always set */ #if 0 (HS|RR|EN|BB) #endif #define HRAD (M_PI/12) #define DEGRAD (M_PI/180) #define TEMMA_TIMEOUT 1 /* FD timeout in seconds */ /* error codes */ #define SUCCESS (2) /* return value for successful read */ #define ETIMEOUT (-2) /* timeout */ #define EREAD (-3) /* error reading from port */ #define EWRITE (-4) /* error writing to port */ #define ECOMMAND (-5) /* unexpected answer */ /* Definitions */ #define mydev "Temma" /* Device name */ #define MAIN_GROUP "Main Control" /* Group name */ #define COMM_GROUP "Communication" /* Group name */ #define MOVE_GROUP "Movement Control" #define DATETIME_GROUP "Date/Time/Location" #define SLEWSW OnCoordSetS[0].s #define SYNCSW OnCoordSetS[1].s #define TRACKSW OnCoordSetS[2].s #define POWSW (power[0].s==ISS_ON) #define SLEWRATE 1 /* slew rate, degrees/s */ #define POLLMS 1000 /* poll period, ms */ #define latitude geo[0].value /* scope's current rads. */ #define longitude geo[1].value /* scope's current rads. */ #define currentUTC UTC[0].value /* scope's current rads. */ #define currentLST STime[0].value /* scope's current rads. */ #define currentRA eq[0].value /* scope's current RA, rads. */ #define currentDec eq[1].value /* scope's current Dec, rads. */ #define temmaRA eqtem[0].value /* scope's current RA, rads. */ #define temmaDec eqtem[1].value /* scope's current Dec, rads. */ int openPort(const char *portID); int portRead(char *buf, int nbytes, int timeout); int portWrite(char * buf); int TemmareadOut(int timeout); static void mountInit(void); void ISGetProperties (const char *dev); void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); double calcLST(char *strlst); int TemmaConnect(const char *device) ; int TemmaDisconnect(void) ; int set_CometTracking(int RArate, int DECrate); int TemmaabortSlew(void) ; int do_TemmaGOTO(void) ; int extractRA(char *buf); int extractDEC(char *buf); int get_TemmaCurrentpos(char *buffer); int set_TemmaCurrentpos(void) ; int do_TemmaSLEW(char mode); int get_TemmaVERSION(char *buffer); int get_TemmaGOTOstatus(char *buffer); int get_TemmaBOTHcorrspeed(char *buffer); int get_TemmaDECcorrspeed(char *buffer); int set_TemmaDECcorrspeed(char *buffer); int get_TemmaRAcorrspeed(char *buffer); int set_TemmaRAcorrspeed(char *buffer); int get_TemmaLatitude(char *buffer); int set_TemmaLatitude(char *buffer); int get_TemmaLST(char *buffer); int set_TemmaLST(char *buffer); int set_TemmaStandbyState(int on); int get_TemmaStandbyState(unsigned char *buffer); int get_TemmaCometTracking(char *buffer); int set_TemmaCometTracking(char *buffer); int set_TemmaSolarRate(void); int set_TemmaStellarRate(void); int switch_Temmamountside(void); static void disconnectMount (void); static void connectMount (void); static void readMountcurrentpos (void *); /***************************/ /* RA motor control switch */ /***************************/ static ISwitch RAmotor[] = { {"RUN", "On", ISS_OFF, 0, 0}, {"STOP", "Off", ISS_ON, 0, 0} }; static ISwitchVectorProperty RAmotorSw = { mydev, "RA motor", "RA motor", MOVE_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, RAmotor, NARRAY(RAmotor), "", 0}; /*****************************/ /* Track mode control switch */ /*****************************/ static ISwitch trackmode[] = { {"Sidereal", "Sidereal", ISS_ON, 0, 0}, {"Lunar", "Lunar", ISS_OFF, 0, 0}, {"Comet", "Comet", ISS_OFF, 0, 0}, }; static ISwitchVectorProperty trackmodeSw = { mydev, "Tracking mode", "Tracking mode", MOVE_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, trackmode, NARRAY(trackmode), "", 0}; /*****************************/ /* Power control switch */ /*****************************/ static ISwitch power[] = { {"CONNECT", "On", ISS_OFF, 0, 0}, {"DISCONNECT", "Off", ISS_ON, 0, 0}, }; static ISwitchVectorProperty powSw = { mydev, "CONNECTION", "Connection", MAIN_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE, power, NARRAY(power), "", 0}; /*******************************/ /* Temma version text property */ /*******************************/ static IText TemmaVersionT[] = {{"VERSION", "Version", 0, 0, 0, 0}}; static ITextVectorProperty TemmaVersion = { mydev, "VERSION", "Temma version", COMM_GROUP, IP_RO, 0, IPS_OK, TemmaVersionT, NARRAY(TemmaVersionT), "", 0}; /*******************************/ /* Driver notes text property */ /*******************************/ static IText TemmaNoteT[] = {{"Note", "", 0, 0, 0, 0}, {"Feedback", "", 0, 0,0 ,0}}; static ITextVectorProperty TemmaNoteTP = { mydev, "Temma Driver", "", MAIN_GROUP, IP_RO, 0, IPS_OK, TemmaNoteT, NARRAY(TemmaNoteT), "", 0}; /*******************************/ /* Port names text property */ /*******************************/ static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}}; static ITextVectorProperty Port = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_OK, PortT, NARRAY(PortT), "", 0}; /*******************************/ /* EQUATORIAL_COORD RW property */ /*******************************/ static INumber eq[] = { {"RA" ,"RA H:M:S" , "%10.6m", 0, 24, 0, 0, 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90, 90, 0, 0, 0, 0, 0} }; static INumberVectorProperty eqNum = { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", MAIN_GROUP , IP_RW, 0, IPS_IDLE, eq, NARRAY(eq), "", 0}; /*******************************/ /* MOUNT_COORD RO property */ /*******************************/ static INumber eqtem[] = { {"RA", "RA H:M:S", "%10.6m", 0, 24, 0, 0, 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90, 90, 0, 0, 0, 0, 0} }; static INumberVectorProperty eqTemma = { mydev, "Temma", "Mount coordinates", MAIN_GROUP , IP_RO, 0, IPS_IDLE, eqtem, NARRAY(eqtem), "", 0}; /* Traccking correction parameters (i.e. to track comets) */ static INumber comet[] = { {"RAcorrspeed","Comet RA motion arcmin/day","%+5d",-21541,21541,0,0,0,0,0}, {"DECcor rspeed", "Comet DEC motion arcmin/day", "%+4d", -600, 600,0, 0., 0, 0, 0} }; static INumberVectorProperty cometNum = { mydev, "COMET_TRACKING", "Comet tracking parameters", MOVE_GROUP, IP_RW, 0, IPS_IDLE, comet, NARRAY(comet), "", 0}; /* Date & Time */ static INumber UTC[] = { {"UTC", "UTC", "%10.6m" , 0.,0.,0.,0., 0, 0, 0}}; INumberVectorProperty Time = { mydev, "TIME_UTC", "UTC Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, UTC, NARRAY(UTC), "", 0}; static INumber STime[] = { {"LST", "Sidereal time", "%10.6m" , 0.,0.,0.,0., 0, 0, 0}}; INumberVectorProperty SDTime = { mydev, "TIME_LST", "Sidereal Time", DATETIME_GROUP, IP_RW, 0, IPS_IDLE, STime, NARRAY(STime), "", 0}; static ISwitch OnCoordSetS[] = { {"SLEW", "Goto", ISS_OFF, 0, 0 }, {"SYNC", "Sync", ISS_ON, 0 , 0}, {"TRACK", "Track", ISS_OFF, 0, 0 }}; static ISwitchVectorProperty OnCoordSetSw = { mydev, "ON_COORD_SET", "On Set", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, OnCoordSetS, NARRAY(OnCoordSetS), "", 0}; static ISwitch abortSlewS[] = { {"ABORT", "Abort", ISS_OFF, 0, 0 }}; static ISwitchVectorProperty abortSlewSw = { mydev, "ABORT_MOTION", "******* ABORT GOTO *********", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, abortSlewS, NARRAY(abortSlewS), "", 0}; /* geographic location */ static INumber geo[] = { {"LAT", "Lat. D:M:S +N", "%10.6m", -90., 90., 0., 0., 0, 0, 0}, {"LONG", "Long. D:M:S +E", "%10.6m", 0., 360., 0., 0., 0, 0, 0} }; static INumberVectorProperty geoNum = { mydev, "GEOGRAPHIC_COORD", "Geographic Location", DATETIME_GROUP, IP_RW, 0., IPS_IDLE, geo, NARRAY(geo), "", 0}; #endif libindi-0.9.7/drivers/telescope/lx200generic.cpp0000644000175000017500000014416012241463551020501 0ustar jasemjasem#if 0 LX200 Generic Copyright (C) 2003-2013 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 2013-10-27: Updated driver to use INDI::Telescope (JM) #endif #include #include #include #include #include #include #include #include #include #include #include #include "indicom.h" #include "lx200driver.h" #include "lx200gps.h" #include "lx200_16.h" #include "lx200classic.h" // We declare an auto pointer to LX200Generic. std::auto_ptr telescope(0); /* There is _one_ binary for all LX200 drivers, but each binary is renamed ** to its device name (i.e. lx200gps, lx200_16..etc). The main function will ** fetch from std args the binary name and ISInit will create the apporpiate ** device afterwards. If the binary name does not match any known devices, ** we simply create a generic device. */ extern char* me; #define LX200_TRACK 0 #define LX200_SYNC 1 /* Simulation Parameters */ #define SLEWRATE 1 /* slew rate, degrees/s */ #define SIDRATE 0.004178 /* sidereal rate, degrees/s */ /* send client definitions of all properties */ void ISInit() { static int isInit=0; if (isInit) return; isInit = 1; if (strstr(me, "indi_lx200classic")) { IDLog("initializing from LX200 classic device...\n"); if(telescope.get() == 0) telescope.reset(new LX200Classic()); } else if (strstr(me, "indi_lx200gps")) { IDLog("initializing from LX200 GPS device...\n"); if(telescope.get() == 0) telescope.reset(new LX200GPS()); } else if (strstr(me, "indi_lx200_16")) { IDLog("Initializing from LX200 16 device...\n"); if(telescope.get() == 0) telescope.reset(new LX200_16()); } else if (strstr(me, "indi_lx200autostar")) { IDLog("initializing from Autostar device...\n"); if(telescope.get() == 0) telescope.reset(new LX200Autostar()); } // be nice and give them a generic device else if(telescope.get() == 0) telescope.reset(new LX200Generic()); } void ISGetProperties(const char *dev) { ISInit(); telescope->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); telescope->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); telescope->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); telescope->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); telescope->ISSnoopDevice(root); } /************************************************** *** LX200 Generic Implementation ***************************************************/ LX200Generic::LX200Generic() { setVersion(2, 0); currentSiteNum = 1; trackingMode = LX200_TRACK_DEFAULT; GuideNSTID = 0; GuideWETID = 0; controller = new INDI::Controller(this); controller->setJoystickCallback(joystickHelper); controller->setButtonCallback(buttonHelper); IDLog("Initializing from generic LX200 device...\n"); } LX200Generic::~LX200Generic() { delete(controller); } const char * LX200Generic::getDefaultName() { return (char *)"LX200 Generic"; } bool LX200Generic::initProperties() { /* Make sure to init parent properties first */ INDI::Telescope::initProperties(); IUFillSwitch(&AlignmentS[0], "Polar", "", ISS_ON); IUFillSwitch(&AlignmentS[1], "AltAz", "", ISS_OFF); IUFillSwitch(&AlignmentS[2], "Land", "", ISS_OFF); IUFillSwitchVector(&AlignmentSP, AlignmentS, 3, getDeviceName(), "Alignment", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&SlewModeS[0], "Max", "", ISS_ON); IUFillSwitch(&SlewModeS[1], "Find", "", ISS_OFF); IUFillSwitch(&SlewModeS[2], "Centering", "", ISS_OFF); IUFillSwitch(&SlewModeS[3], "Guide", "", ISS_OFF); IUFillSwitchVector(&SlewModeSP, SlewModeS, 4, getDeviceName(), "Slew Rate", "", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&TrackModeS[0], "Default", "", ISS_ON); IUFillSwitch(&TrackModeS[1], "Lunar", "", ISS_OFF); IUFillSwitch(&TrackModeS[2], "Manual", "", ISS_OFF); IUFillSwitchVector(&TrackModeSP, TrackModeS, 3, getDeviceName(), "Tracking Mode", "", MOTION_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillNumber(&TrackFreqN[0], "trackFreq", "Freq", "%g", 56.4,60.1, 0.1, 60.1); IUFillNumberVector(&TrackingFreqNP, TrackFreqN, 1, getDeviceName(), "Tracking Frequency", "", MOTION_TAB, IP_RW, 0, IPS_IDLE); IUFillSwitch(&UsePulseCmdS[0], "Off", "", ISS_ON); IUFillSwitch(&UsePulseCmdS[1], "On", "", ISS_OFF); IUFillSwitchVector(&UsePulseCmdSP, UsePulseCmdS, 2, getDeviceName(), "Use Pulse Cmd", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&SiteS[0], "Site 1", "", ISS_ON); IUFillSwitch(&SiteS[1], "Site 2", "", ISS_OFF); IUFillSwitch(&SiteS[2], "Site 3", "", ISS_OFF); IUFillSwitch(&SiteS[3], "Site 4", "", ISS_OFF); IUFillSwitchVector(&SiteSP, SiteS, 4, getDeviceName(), "Sites", "", SITE_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillText(&SiteNameT[0], "Name", "", ""); IUFillTextVector(&SiteNameTP, SiteNameT, 1, getDeviceName(), "Site Name", "", SITE_TAB, IP_RW, 0, IPS_IDLE); IUFillSwitch(&FocusMotionS[0], "IN", "Focus in", ISS_OFF); IUFillSwitch(&FocusMotionS[1], "OUT", "Focus out", ISS_OFF); IUFillSwitchVector(&FocusMotionSP, FocusMotionS, 2, getDeviceName(), "FOCUS_MOTION", "Motion", FOCUS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillNumber(&FocusTimerN[0], "TIMER", "Timer (ms)", "%g", 0, 10000., 1000., 0); IUFillNumberVector(&FocusTimerNP, FocusTimerN, 1, getDeviceName(), "FOCUS_TIMER", "Focus Timer", FOCUS_TAB, IP_RW, 0, IPS_IDLE); IUFillSwitch(&FocusModeS[0], "FOCUS_HALT", "Halt", ISS_ON); IUFillSwitch(&FocusModeS[1], "FOCUS_SLOW", "Slow", ISS_OFF); IUFillSwitch(&FocusModeS[2], "FOCUS_FAST", "Fast", ISS_OFF); IUFillSwitchVector(&FocusModeSP, FocusModeS, 3, getDeviceName(), "FOCUS_MODE", "Mode", FOCUS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); controller->mapController("NSWE Control", "NSWE Control", INDI::Controller::CONTROLLER_JOYSTICK, "JOYSTICK_1"); controller->mapController("Slew Max", "Slew Max", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1"); controller->mapController("Slew Find", "Slew Find", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_2"); controller->mapController("Slew Centering", "Slew Centering", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_3"); controller->mapController("Slew Guide", "Slew Guide", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_4"); controller->mapController("Abort Motion", "Abort Motion", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_5"); controller->initProperties(); TrackState=SCOPE_IDLE; initGuiderProperties(getDeviceName(), GUIDE_TAB); /* Add debug/simulation/config controls so we may debug driver if necessary */ addAuxControls(); return true; } void LX200Generic::ISGetProperties(const char *dev) { if(dev && strcmp(dev,getDeviceName())) return; INDI::Telescope::ISGetProperties(dev); if (isConnected()) { defineSwitch(&AlignmentSP); defineSwitch(&SlewModeSP); defineSwitch(&TrackModeSP); defineNumber(&TrackingFreqNP); defineSwitch(&UsePulseCmdSP); defineSwitch(&SiteSP); defineText(&SiteNameTP); defineNumber(&GuideNSNP); defineNumber(&GuideWENP); defineSwitch(&FocusMotionSP); defineNumber(&FocusTimerNP); defineSwitch(&FocusModeSP); } controller->ISGetProperties(dev); } bool LX200Generic::updateProperties() { INDI::Telescope::updateProperties(); if (isConnected()) { defineSwitch(&AlignmentSP); defineSwitch(&SlewModeSP); defineSwitch(&TrackModeSP); defineNumber(&TrackingFreqNP); defineSwitch(&UsePulseCmdSP); defineSwitch(&SiteSP); defineText(&SiteNameTP); defineNumber(&GuideNSNP); defineNumber(&GuideWENP); defineSwitch(&FocusMotionSP); defineNumber(&FocusTimerNP); defineSwitch(&FocusModeSP); getBasicData(); } else { deleteProperty(AlignmentSP.name); deleteProperty(SlewModeSP.name); deleteProperty(TrackModeSP.name); deleteProperty(TrackingFreqNP.name); deleteProperty(UsePulseCmdSP.name); deleteProperty(SiteSP.name); deleteProperty(SiteNameTP.name); deleteProperty(GuideNSNP.name); deleteProperty(GuideWENP.name); deleteProperty(FocusMotionSP.name); deleteProperty(FocusTimerNP.name); deleteProperty(FocusModeSP.name); } controller->updateProperties(); return true; } bool LX200Generic::Connect() { bool rc=false; if(isConnected()) return true; rc=Connect(PortT[0].text); if(rc) SetTimer(POLLMS); return rc; } bool LX200Generic::Connect(char *port) { if (isSimulation()) { IDMessage (getDeviceName(), "Simulated LX200 is online. Retrieving basic data..."); return true; } if (tty_connect(port, 9600, 8, 0, 1, &PortFD) != TTY_OK) { DEBUGF(INDI::Logger::DBG_ERROR, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.", port); return false; } if (check_lx200_connection(PortFD)) { DEBUG(INDI::Logger::DBG_ERROR, "Error connecting to Telescope. Telescope is offline."); return false; } //*((int *) UTCOffsetN[0].aux0) = 0; IDMessage (getDeviceName(), "Telescope is online. Retrieving basic data..."); return true; } bool LX200Generic::Disconnect() { if (isSimulation() == false) tty_disconnect(PortFD); return true; } bool LX200Generic::ReadScopeStatus() { if (isConnected() == false) return false; if (isSimulation()) { mountSim(); return true; } //if (check_lx200_connection(PortFD)) //return false; if (TrackState == SCOPE_SLEWING) { // Check if LX200 is done slewing if(isSlewComplete(PortFD) == 0) { // Set slew mode to "Centering" IUResetSwitch(&SlewModeSP); SlewModeS[2].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); // Nothing to do here if(TrackState==SCOPE_PARKING) { TrackState=SCOPE_PARKED; IDMessage(getDeviceName(),"Telescope is Parked."); } else { TrackState=SCOPE_TRACKING; IDMessage(getDeviceName(),"Slew is complete. Tracking..."); } } } else if(TrackState == SCOPE_PARKING) { if(isSlewComplete(PortFD) == 0) { TrackState=SCOPE_PARKED; ParkSP.s=IPS_OK; IDSetSwitch(&ParkSP,NULL); IDMessage(getDeviceName(),"Telescope is Parked."); } } if ( getLX200RA(PortFD, ¤tRA) < 0 || getLX200DEC(PortFD, ¤tDEC) < 0) { EqNP.s = IPS_ALERT; IDSetNumber(&EqNP, "Error reading RA/DEC."); return false; } NewRaDec(currentRA, currentDEC); return true; } bool LX200Generic::Goto(double r,double d) { targetRA=r; targetDEC=d; char RAStr[64], DecStr[64]; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); // If moving, let's stop it first. if (EqNP.s == IPS_BUSY) { if (!isSimulation() && abortSlew(PortFD) < 0) { AbortSP.s = IPS_ALERT; IDSetSwitch(&AbortSP, "Abort slew failed."); return false; } AbortSP.s = IPS_OK; EqNP.s = IPS_IDLE; IDSetSwitch(&AbortSP, "Slew aborted."); IDSetNumber(&EqNP, NULL); if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) { MovementNSSP.s = MovementWESP.s = IPS_IDLE; EqNP.s = IPS_IDLE; IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); } // sleep for 100 mseconds usleep(100000); } if (isSimulation() == false) { if (setObjectRA(PortFD, targetRA) < 0 || (setObjectDEC(PortFD, targetDEC)) < 0) { EqNP.s = IPS_ALERT; IDSetNumber(&EqNP, "Error setting RA/DEC."); return false; } int err=0; /* Slew reads the '0', that is not the end of the slew */ if (err = Slew(PortFD)) { EqNP.s = IPS_ALERT; IDSetNumber(&EqNP, "Error Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); slewError(err); return false; } } //Parked=false; TrackState = SCOPE_SLEWING; EqNP.s = IPS_BUSY; IDMessage(getDeviceName(), "Slewing to RA: %s - DEC: %s", RAStr, DecStr); return true; } bool LX200Generic::Sync(double ra, double dec) { char syncString[256]; if (isSimulation() == false && (setObjectRA(PortFD, ra) < 0 || (setObjectDEC(PortFD, dec)) < 0)) { EqNP.s = IPS_ALERT; IDSetNumber(&EqNP, "Error setting RA/DEC. Unable to Sync."); return false; } if (isSimulation() == false && ::Sync(PortFD, syncString) < 0) { EqNP.s = IPS_ALERT; IDSetNumber(&EqNP , "Synchronization failed."); return false; } currentRA = ra; currentDEC = dec; if (isDebug()) IDLog("Synchronization successful %s\n", syncString); IDMessage(getDeviceName(), "Synchronization successful."); TrackState = SCOPE_IDLE; EqNP.s = IPS_OK; NewRaDec(currentRA, currentDEC); return true; } bool LX200Generic::Park() { if (isSimulation() == false) { // If scope is moving, let's stop it first. if (EqNP.s == IPS_BUSY) { if (isSimulation() == false && abortSlew(PortFD) < 0) { AbortSP.s = IPS_ALERT; IDSetSwitch(&AbortSP, "Abort slew failed."); return false; } AbortSP.s = IPS_OK; EqNP.s = IPS_IDLE; IDSetSwitch(&AbortSP, "Slew aborted."); IDSetNumber(&EqNP, NULL); if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) { MovementNSSP.s = MovementWESP.s = IPS_IDLE; EqNP.s = IPS_IDLE; IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); } // sleep for 100 msec usleep(100000); } if (isSimulation() == false && slewToPark(PortFD) < 0) { ParkSP.s = IPS_ALERT; IDSetSwitch(&ParkSP, "Parking Failed."); return false; } } ParkSP.s = IPS_OK; //Parked=true; TrackState = SCOPE_PARKING; IDMessage(getDeviceName(), "Parking telescope in progress..."); return true; } bool LX200Generic::MoveNS(TelescopeMotionNS dir) { static int last_move=-1; int current_move = -1; current_move = IUFindOnSwitchIndex(&MovementNSSP); // Previosuly active switch clicked again, so let's stop. if (current_move == last_move && current_move != -1) { if (isSimulation() == false) HaltMovement(PortFD, (current_move == 0) ? LX200_NORTH : LX200_SOUTH); IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, "Movement toward %s halted.", (current_move == 0) ? "North" : "South"); last_move = -1; return true; } last_move = current_move; if (isDebug()) IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); // Correction for LX200 Driver: North 0 - South 3 current_move = (dir == MOTION_NORTH) ? LX200_NORTH : LX200_SOUTH; if (isSimulation() == false && MoveTo(PortFD, current_move) < 0) { MovementNSSP.s = IPS_ALERT; IDSetSwitch(&MovementNSSP, "Error setting N/S motion direction."); return false; } MovementNSSP.s = IPS_BUSY; IDSetSwitch(&MovementNSSP, "Moving toward %s.", (current_move == LX200_NORTH) ? "North" : "South"); return true; } bool LX200Generic::MoveWE(TelescopeMotionWE dir) { static int last_move=-1; int current_move = -1; current_move = IUFindOnSwitchIndex(&MovementWESP); // Previosuly active switch clicked again, so let's stop. if (current_move == last_move && current_move != -1) { if (isSimulation() == false) HaltMovement(PortFD, (current_move == 0) ? LX200_WEST : LX200_EAST); IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, "Movement toward %s halted.", (current_move == 0) ? "West" : "East"); last_move = -1; return true; } last_move = current_move; if (isDebug()) IDLog("Current Move: %d - Previous Move: %d\n", current_move, last_move); current_move = (dir == MOTION_WEST) ? LX200_WEST : LX200_EAST; if (isSimulation() == false && MoveTo(PortFD, current_move) < 0) { MovementWESP.s = IPS_ALERT; IDSetSwitch(&MovementWESP, "Error setting W/E motion direction."); return false; } MovementWESP.s = IPS_BUSY; IDSetSwitch(&MovementWESP, "Moving toward %s.", (current_move == LX200_WEST) ? "West" : "East"); return true; } bool LX200Generic::Abort() { if (isSimulation() == false && abortSlew(PortFD) < 0) { IDMessage(getDeviceName(), "Failed to abort slew."); return false; } 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; } IDMessage(getDeviceName(), "Guide aborted."); IDSetNumber(&GuideNSNP, NULL); IDSetNumber(&GuideWENP, NULL); return true; } IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); MovementNSSP.s = IPS_IDLE; MovementWESP.s = IPS_IDLE; EqNP.s = IPS_IDLE; TrackState = SCOPE_IDLE; IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); IDSetNumber(&EqNP, NULL); IDMessage(getDeviceName(), "Slew aborted."); return true; } bool LX200Generic::updateTime(ln_date * utc, double utc_offset) { struct ln_zonedate ltm; if (isSimulation()) return true; ln_date_to_zonedate(utc, <m, utc_offset*3600.0); JD = ln_get_julian_day(utc); DEBUGF(INDI::Logger::DBG_DEBUG, "New JD is %f\n", (float) JD); // Set Local Time if (setLocalTime(PortFD, ltm.hours, ltm.minutes, ltm.seconds) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting local time."); return false; } if (setCalenderDate(PortFD, ltm.days, ltm.months, ltm.years) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting local date."); return false; } // Meade defines UTC Offset as the offset ADDED to local time to yield UTC, which // is the opposite of the standard definition of UTC offset! if (setUTCOffset(PortFD, (utc_offset * -1.0)) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting UTC Offset."); return false; } DEBUG(INDI::Logger::DBG_SESSION, "Time updated, updating planetary data..."); return true; } bool LX200Generic::updateLocation(double latitude, double longitude, double elevation) { INDI_UNUSED(elevation); if (isSimulation()) return true; if (isSimulation() == false && setSiteLongitude(PortFD, 360.0 - longitude) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting site longitude coordinates"); return false; } if (isSimulation() == false && setSiteLatitude(PortFD, latitude) < 0) { DEBUG(INDI::Logger::DBG_ERROR, "Error setting site latitude coordinates"); return false; } char l[32], L[32]; fs_sexa (l, latitude, 3, 3600); fs_sexa (L, longitude, 4, 3600); IDMessage(getDeviceName(), "Site location updated to Lat %.32s - Long %.32s", l, L); return true; } bool LX200Generic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if (!strcmp (name, SiteNameTP.name) ) { if (isSimulation() == false && setSiteName(PortFD, texts[0], currentSiteNum) < 0) { SiteNameTP.s = IPS_ALERT; IDSetText(&SiteNameTP, "Setting site name"); return false; } SiteNameTP.s = IPS_OK; IText *tp = IUFindText(&SiteNameTP, names[0]); IUSaveText(tp, texts[0]); IDSetText(&SiteNameTP , "Site name updated"); return true; } } controller->ISNewText(dev, name, texts, names, n); return INDI::Telescope::ISNewText(dev, name, texts, names, n); } bool LX200Generic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { // Update Frequency if ( !strcmp (name, TrackingFreqNP.name) ) { DEBUGF(INDI::Logger::DBG_DEBUG, "Trying to set track freq of: %f\n", values[0]); if (isSimulation() == false && setTrackFreq(PortFD, values[0]) < 0) { TrackingFreqNP.s = IPS_ALERT; IDSetNumber(&TrackingFreqNP, "Error setting tracking frequency"); return false; } TrackingFreqNP.s = IPS_OK; TrackingFreqNP.np[0].value = values[0]; IDSetNumber(&TrackingFreqNP, "Tracking frequency set to %04.1f", values[0]); if (trackingMode != LX200_TRACK_MANUAL) { trackingMode = LX200_TRACK_MANUAL; TrackModeS[0].s = ISS_OFF; TrackModeS[1].s = ISS_OFF; TrackModeS[2].s = ISS_ON; TrackModeSP.s = IPS_OK; selectTrackingMode(PortFD, trackingMode); IDSetSwitch(&TrackModeSP, NULL); } return true; } if (!strcmp(name, FocusTimerNP.name)) { // Don't update if busy if (FocusTimerNP.s == IPS_BUSY) return true; IUUpdateNumber(&FocusTimerNP, values, names, n); FocusTimerNP.s = IPS_OK; IDSetNumber(&FocusTimerNP, NULL); if (isDebug()) IDLog("Setting focus timer to %g\n", FocusTimerN[0].value); return true; } processGuiderProperties(name, values, names, n); } // if we didn't process it, continue up the chain, let somebody else // give it a shot return INDI::Telescope::ISNewNumber(dev,name,values,names,n); } bool LX200Generic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int index=0; if(strcmp(dev,getDeviceName())==0) { // Alignment if (!strcmp (name, AlignmentSP.name)) { if (IUUpdateSwitch(&AlignmentSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&AlignmentSP); if (isSimulation() == false && setAlignmentMode(PortFD, index) < 0) { AlignmentSP.s = IPS_ALERT; IDSetSwitch(&AlignmentSP, "Error setting alignment mode."); return false; } AlignmentSP.s = IPS_OK; IDSetSwitch (&AlignmentSP, NULL); return true; } // Sites if (!strcmp (name, SiteSP.name)) { if (IUUpdateSwitch(&SiteSP, states, names, n) < 0) return false; currentSiteNum = IUFindOnSwitchIndex(&SiteSP) + 1; if (isSimulation() == false && selectSite(PortFD, currentSiteNum) < 0) { SiteSP.s = IPS_ALERT; IDSetSwitch(&SiteSP, "Error selecting sites."); return false; } if (isSimulation()) IUSaveText(&SiteNameTP.tp[0], "Sample Site"); else getSiteName(PortFD, SiteNameTP.tp[0].text, currentSiteNum); if (isDebug()) IDLog("Selecting site %d\n", currentSiteNum); sendScopeLocation(); SiteNameTP.s = SiteSP.s = IPS_OK; IDSetText (&SiteNameTP, NULL); IDSetSwitch (&SiteSP, NULL); return false; } // Focus Motion if (!strcmp (name, FocusMotionSP.name)) { // If mode is "halt" if (FocusModeS[0].s == ISS_ON) { FocusMotionSP.s = IPS_IDLE; IDSetSwitch(&FocusMotionSP, "Focus mode is halt. Select slow or fast mode"); return true; } int last_motion = IUFindOnSwitchIndex(&FocusMotionSP); if (IUUpdateSwitch(&FocusMotionSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&FocusMotionSP); // If same direction and we're busy, stop if (last_motion == index && FocusMotionSP.s == IPS_BUSY) { IUResetSwitch(&FocusMotionSP); FocusMotionSP.s = IPS_IDLE; setFocuserSpeedMode(PortFD, 0); IDSetSwitch(&FocusMotionSP, NULL); return true; } if (isSimulation() == false && setFocuserMotion(PortFD, index) < 0) { FocusMotionSP.s = IPS_ALERT; IDSetSwitch(&FocusMotionSP, "Error setting focuser speed."); return false; } // with a timer if (FocusTimerN[0].value > 0) { FocusTimerNP.s = IPS_BUSY; FocusMotionSP.s = IPS_BUSY; IEAddTimer(50, LX200Generic::updateFocusHelper, this); } FocusMotionSP.s = IPS_OK; IDSetSwitch(&FocusMotionSP, NULL); return true; } // Slew mode if (!strcmp (name, SlewModeSP.name)) { if (IUUpdateSwitch(&SlewModeSP, states, names, n) < 0) return false; index = IUFindOnSwitchIndex(&SlewModeSP); if (isSimulation() == false && setSlewMode(PortFD, index) < 0) { SlewModeSP.s = IPS_ALERT; IDSetSwitch(&SlewModeSP, "Error setting slew mode."); return false; } SlewModeSP.s = IPS_OK; IDSetSwitch(&SlewModeSP, NULL); return true; } // Tracking mode if (!strcmp (name, TrackModeSP.name)) { IUResetSwitch(&TrackModeSP); IUUpdateSwitch(&TrackModeSP, states, names, n); trackingMode = IUFindOnSwitchIndex(&TrackModeSP); if (isSimulation() == false && selectTrackingMode(PortFD, trackingMode) < 0) { TrackModeSP.s = IPS_ALERT; IDSetSwitch(&TrackModeSP, "Error setting tracking mode."); return false; } if (isSimulation() == false) getTrackFreq(PortFD, &TrackFreqN[0].value); TrackModeSP.s = IPS_OK; IDSetNumber(&TrackingFreqNP, NULL); IDSetSwitch(&TrackModeSP, NULL); return true; } // Focus speed if (!strcmp (name, FocusModeSP.name)) { IUResetSwitch(&FocusModeSP); IUUpdateSwitch(&FocusModeSP, states, names, n); index = IUFindOnSwitchIndex(&FocusModeSP); /* disable timer and motion */ if (index == 0) { IUResetSwitch(&FocusMotionSP); FocusMotionSP.s = IPS_IDLE; FocusTimerNP.s = IPS_IDLE; IDSetSwitch(&FocusMotionSP, NULL); IDSetNumber(&FocusTimerNP, NULL); } if (isSimulation() == false) setFocuserSpeedMode(PortFD, index); FocusModeSP.s = IPS_OK; IDSetSwitch(&FocusModeSP, NULL); return true; } // Pulse-Guide command support if (!strcmp (name, UsePulseCmdSP.name)) { IUResetSwitch(&UsePulseCmdSP); IUUpdateSwitch(&UsePulseCmdSP, states, names, n); UsePulseCmdSP.s = IPS_OK; IDSetSwitch(&UsePulseCmdSP, NULL); return true; } } controller->ISNewSwitch(dev, name, states, names, n); // Nobody has claimed this, so pass it to the parent return INDI::Telescope::ISNewSwitch(dev,name,states,names,n); } void LX200Generic::updateFocusHelper(void *p) { ((LX200Generic *) p)->updateFocusTimer(); } void LX200Generic::updateFocusTimer() { switch (FocusTimerNP.s) { case IPS_IDLE: break; case IPS_BUSY: if (isDebug()) IDLog("Focus Timer Value is %g\n", FocusTimerN[0].value); FocusTimerN[0].value-=50; if (FocusTimerN[0].value <= 0) { if (isDebug()) IDLog("Focus Timer Expired\n"); if (isSimulation() == false && setFocuserSpeedMode(telescope->PortFD, 0) < 0) { FocusModeSP.s = IPS_ALERT; IDSetSwitch(&FocusModeSP, "Error setting focuser mode."); if (isDebug()) IDLog("Error setting focuser mode\n"); return; } FocusMotionSP.s = IPS_IDLE; FocusTimerNP.s = IPS_OK; FocusModeSP.s = IPS_OK; IUResetSwitch(&FocusMotionSP); IUResetSwitch(&FocusModeSP); FocusModeS[0].s = ISS_ON; IDSetSwitch(&FocusModeSP, NULL); IDSetSwitch(&FocusMotionSP, NULL); } IDSetNumber(&FocusTimerNP, NULL); if (FocusTimerN[0].value > 0) IEAddTimer(50, LX200Generic::updateFocusHelper, this); break; case IPS_OK: break; case IPS_ALERT: break; } } void LX200Generic::mountSim () { static struct timeval ltv; struct timeval tv; double dt, da, dx; int nlocked; /* update elapsed time since last poll, don't presume exactly POLLMS */ gettimeofday (&tv, NULL); if (ltv.tv_sec == 0 && ltv.tv_usec == 0) ltv = tv; dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; ltv = tv; da = SLEWRATE*dt; /* Process per current state. We check the state of EQUATORIAL_COORDS and act acoordingly */ switch (TrackState) { case SCOPE_TRACKING: /* RA moves at sidereal, Dec stands still */ currentRA += (SIDRATE*dt/15.); break; case SCOPE_SLEWING: /* slewing - nail it when both within one pulse @ SLEWRATE */ nlocked = 0; dx = targetRA - currentRA; if (fabs(dx) <= da) { currentRA = targetRA; nlocked++; } else if (dx > 0) currentRA += da/15.; else currentRA -= da/15.; dx = targetDEC - currentDEC; if (fabs(dx) <= da) { currentDEC = targetDEC; nlocked++; } else if (dx > 0) currentDEC += da; else currentDEC -= da; if (nlocked == 2) TrackState = SCOPE_TRACKING; break; default: break; } NewRaDec(currentRA, currentDEC); } void LX200Generic::getBasicData() { if (isSimulation() == false) { getAlignment(); checkLX200Format(PortFD); if (getTimeFormat(PortFD, &timeFormat) < 0) IDMessage(getDeviceName(), "Failed to retrieve time format from device."); else { timeFormat = (timeFormat == 24) ? LX200_24 : LX200_AM; // We always do 24 hours if (timeFormat != LX200_24) toggleTimeFormat(PortFD); } SiteNameT[0].text = new char[64]; if (getSiteName(PortFD, SiteNameT[0].text, currentSiteNum) < 0) IDMessage(getDeviceName(), "Failed to get site name from device"); else IDSetText (&SiteNameTP, NULL); if (getTrackFreq(PortFD, &TrackFreqN[0].value) < 0) IDMessage(getDeviceName(), "Failed to get tracking frequency from device."); else IDSetNumber (&TrackingFreqNP, NULL); } sendScopeLocation(); sendScopeTime(); } void LX200Generic::slewError(int slewCode) { EqNP.s = IPS_ALERT; if (slewCode == 1) IDSetNumber(&EqNP, "Object below horizon."); else if (slewCode == 2) IDSetNumber(&EqNP, "Object below the minimum elevation limit."); else IDSetNumber(&EqNP, "Slew failed."); } void LX200Generic::getAlignment() { signed char align = ACK(PortFD); if (align < 0) { IDSetSwitch (&AlignmentSP, "Failed to get telescope alignment."); return; } AlignmentS[0].s = ISS_OFF; AlignmentS[1].s = ISS_OFF; AlignmentS[2].s = ISS_OFF; switch (align) { case 'P': AlignmentS[0].s = ISS_ON; break; case 'A': AlignmentS[1].s = ISS_ON; break; case 'L': AlignmentS[2].s = ISS_ON; break; } AlignmentSP.s = IPS_OK; IDSetSwitch (&AlignmentSP, NULL); } void LX200Generic::sendScopeTime() { char cdate[32]; double ctime; int h, m, s, lx200_utc_offset=0; int day, month, year, result; struct tm ltm; struct tm utm; time_t time_epoch; if (isSimulation()) { snprintf(cdate, 32, "%d-%02d-%02dT%02d:%02d:%02d", 1979, 6, 25, 3, 30, 30); IDLog("Telescope ISO date and time: %s\n", cdate); IUSaveText(&TimeT[0], cdate); IUSaveText(&TimeT[1], "3"); IDSetText(&TimeTP, NULL); return; } getUTCOffset(PortFD, &lx200_utc_offset); // LX200 TimeT Offset is defined at the number of hours added to LOCAL TIME to get TimeT. This is contrary to the normal definition. char utcStr[8]; snprintf(utcStr, 8, "%02d", lx200_utc_offset*-1); IUSaveText(&TimeT[1], utcStr); if (isDebug()) IDLog("Telescope TimeT Offset: %s\n", TimeT[1].text); getLocalTime24(PortFD, &ctime); getSexComponents(ctime, &h, &m, &s); getCalenderDate(PortFD, cdate); result = sscanf(cdate, "%d/%d/%d", &year, &month, &day); if (result != 3) return; // Let's fill in the local time ltm.tm_sec = s; ltm.tm_min = m; ltm.tm_hour = h; ltm.tm_mday = day; ltm.tm_mon = month - 1; ltm.tm_year = year - 1900; // Get time epoch time_epoch = mktime(<m); // Convert to TimeT time_epoch -= (int) (atof(TimeT[1].text) * 3600.0); // Get UTC (we're using localtime_r, but since we shifted time_epoch above by UTCOffset, we should be getting the real UTC time localtime_r(&time_epoch, &utm); /* Format it into ISO 8601 */ strftime(cdate, 32, "%Y-%m-%dT%H:%M:%S", &utm); IUSaveText(&TimeT[0], cdate); if (isDebug()) { IDLog("Telescope Local Time: %02d:%02d:%02d\n", h, m , s); IDLog("Telescope UTC Time: %s\n", TimeT[0].text); } // Let's send everything to the client IDSetText(&TimeTP, NULL); } void LX200Generic::sendScopeLocation() { int dd = 0, mm = 0; if (isSimulation()) { LocationNP.np[0].value = 29.5; LocationNP.np[1].value = 48.0; LocationNP.s = IPS_OK; IDSetNumber(&LocationNP, NULL); return; } if (getSiteLatitude(PortFD, &dd, &mm) < 0) IDMessage(getDeviceName(), "Failed to get site latitude from device."); else { if (dd > 0) LocationNP.np[0].value = dd + mm/60.0; else LocationNP.np[0].value = dd - mm/60.0; if (isDebug()) { IDLog("Autostar Latitude: %d:%d\n", dd, mm); IDLog("INDI Latitude: %g\n", LocationNP.np[0].value); } } if (getSiteLongitude(PortFD, &dd, &mm) < 0) IDMessage(getDeviceName(), "Failed to get site longitude from device."); else { if (dd > 0) LocationNP.np[1].value = 360.0 - (dd + mm/60.0); else LocationNP.np[1].value = (dd - mm/60.0) * -1.0; if (isDebug()) { IDLog("Autostar Longitude: %d:%d\n", dd, mm); IDLog("INDI Longitude: %g\n", LocationNP.np[1].value); } } IDSetNumber (&LocationNP, NULL); } bool LX200Generic::GuideNorth(float ms) { int use_pulse_cmd; use_pulse_cmd = IUFindOnSwitchIndex(&UsePulseCmdSP); if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { IDMessage(getDeviceName(), "Cannot guide while moving."); return false; } // If already moving (no pulse command), then stop movement if (MovementNSSP.s == IPS_BUSY) { int dir = IUFindOnSwitchIndex(&MovementNSSP); MoveNS(dir == 0 ? MOTION_NORTH : MOTION_SOUTH); } if (GuideNSTID) { IERmTimer(GuideNSTID); GuideNSTID = 0; } if (use_pulse_cmd) { SendPulseCmd(PortFD, LX200_NORTH, ms); } else { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { SlewModeSP.s = IPS_ALERT; IDSetSwitch(&SlewModeSP, "Error setting slew mode."); return false; } MovementNSS[0].s = ISS_ON; MoveNS(MOTION_NORTH); } // Set slew to guiding IUResetSwitch(&SlewModeSP); SlewModeS[3].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); guide_direction = LX200_NORTH; GuideNSTID = IEAddTimer (ms, guideTimeoutHelper, this); return true; } bool LX200Generic::GuideSouth(float ms) { int use_pulse_cmd; use_pulse_cmd = IUFindOnSwitchIndex(&UsePulseCmdSP); if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { IDMessage(getDeviceName(), "Cannot guide while moving."); return false; } // If already moving (no pulse command), then stop movement if (MovementNSSP.s == IPS_BUSY) { int dir = IUFindOnSwitchIndex(&MovementNSSP); MoveNS(dir == 0 ? MOTION_NORTH : MOTION_SOUTH); } if (GuideNSTID) { IERmTimer(GuideNSTID); GuideNSTID = 0; } if (use_pulse_cmd) { SendPulseCmd(PortFD, LX200_SOUTH, ms); } else { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { SlewModeSP.s = IPS_ALERT; IDSetSwitch(&SlewModeSP, "Error setting slew mode."); return false; } MovementNSS[1].s = ISS_ON; MoveNS(MOTION_SOUTH); } // Set slew to guiding IUResetSwitch(&SlewModeSP); SlewModeS[3].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); guide_direction = LX200_SOUTH; GuideNSTID = IEAddTimer (ms, guideTimeoutHelper, this); return true; } bool LX200Generic::GuideEast(float ms) { int use_pulse_cmd; use_pulse_cmd = IUFindOnSwitchIndex(&UsePulseCmdSP); if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { IDMessage(getDeviceName(), "Cannot guide while moving."); return false; } // If already moving (no pulse command), then stop movement if (MovementWESP.s == IPS_BUSY) { int dir = IUFindOnSwitchIndex(&MovementWESP); MoveWE(dir == 0 ? MOTION_WEST : MOTION_EAST); } if (GuideWETID) { IERmTimer(GuideWETID); GuideWETID = 0; } if (use_pulse_cmd) { SendPulseCmd(PortFD, LX200_EAST, ms); } else { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { SlewModeSP.s = IPS_ALERT; IDSetSwitch(&SlewModeSP, "Error setting slew mode."); return false; } MovementWES[1].s = ISS_ON; MoveWE(MOTION_EAST); } // Set slew to guiding IUResetSwitch(&SlewModeSP); SlewModeS[3].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); guide_direction = LX200_EAST; GuideWETID = IEAddTimer (ms, guideTimeoutHelper, this); return true; } bool LX200Generic::GuideWest(float ms) { int use_pulse_cmd; use_pulse_cmd = IUFindOnSwitchIndex(&UsePulseCmdSP); if (!use_pulse_cmd && (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY)) { IDMessage(getDeviceName(), "Cannot guide while moving."); return false; } // If already moving (no pulse command), then stop movement if (MovementWESP.s == IPS_BUSY) { int dir = IUFindOnSwitchIndex(&MovementWESP); MoveWE(dir == 0 ? MOTION_WEST : MOTION_EAST); } if (GuideWETID) { IERmTimer(GuideWETID); GuideWETID = 0; } if (use_pulse_cmd) { SendPulseCmd(PortFD, LX200_WEST, ms); } else { if (setSlewMode(PortFD, LX200_SLEW_GUIDE) < 0) { SlewModeSP.s = IPS_ALERT; IDSetSwitch(&SlewModeSP, "Error setting slew mode."); return false; } MovementWES[0].s = ISS_ON; MoveWE(MOTION_WEST); } // Set slew to guiding IUResetSwitch(&SlewModeSP); SlewModeS[3].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); guide_direction = LX200_WEST; GuideWETID = IEAddTimer (ms, guideTimeoutHelper, this); return true; } void LX200Generic::guideTimeoutHelper(void *p) { ((LX200Generic *)p)->guideTimeout(); } void LX200Generic::guideTimeout() { int use_pulse_cmd; use_pulse_cmd = IUFindOnSwitchIndex(&UsePulseCmdSP); if (guide_direction == -1) { HaltMovement(PortFD, LX200_NORTH); HaltMovement(PortFD, LX200_SOUTH); HaltMovement(PortFD, LX200_EAST); HaltMovement(PortFD, LX200_WEST); MovementNSSP.s = IPS_IDLE; MovementWESP.s = IPS_IDLE; IUResetSwitch(&MovementNSSP); IUResetSwitch(&MovementWESP); IDSetSwitch(&MovementNSSP, NULL); IDSetSwitch(&MovementWESP, NULL); IERmTimer(GuideNSTID); IERmTimer(GuideWETID); } else if (! use_pulse_cmd) { if (guide_direction == LX200_NORTH || guide_direction == LX200_SOUTH) { MoveNS(guide_direction == LX200_NORTH ? MOTION_NORTH : MOTION_SOUTH); if (guide_direction == LX200_NORTH) GuideNSNP.np[0].value = 0; else GuideNSNP.np[1].value = 0; GuideNSNP.s = IPS_IDLE; IDSetNumber(&GuideNSNP, NULL); MovementNSSP.s = IPS_IDLE; IUResetSwitch(&MovementNSSP); IDSetSwitch(&MovementNSSP, NULL); } if (guide_direction == LX200_WEST || guide_direction == LX200_EAST) { MoveWE(guide_direction == LX200_WEST ? MOTION_WEST : MOTION_EAST); if (guide_direction == LX200_WEST) GuideWENP.np[0].value = 0; else GuideWENP.np[1].value = 0; GuideWENP.s = IPS_IDLE; IDSetNumber(&GuideWENP, NULL); MovementWESP.s = IPS_IDLE; IUResetSwitch(&MovementWESP); IDSetSwitch(&MovementWESP, NULL); } } if (guide_direction == LX200_NORTH || guide_direction == LX200_SOUTH || guide_direction == -1) { GuideNSNP.np[0].value = 0; GuideNSNP.np[1].value = 0; GuideNSNP.s = IPS_IDLE; GuideNSTID = 0; IDSetNumber(&GuideNSNP, NULL); } if (guide_direction == LX200_WEST || guide_direction == LX200_EAST || guide_direction == -1) { GuideWENP.np[0].value = 0; GuideWENP.np[1].value = 0; GuideWENP.s = IPS_IDLE; GuideWETID = 0; IDSetNumber(&GuideWENP, NULL); } } bool LX200Generic::canSync() { return true; } // Don't assume generic can, let children decide bool LX200Generic::canPark() { return false; } bool LX200Generic::ISSnoopDevice(XMLEle *root) { controller->ISSnoopDevice(root); return INDI::Telescope::ISSnoopDevice(root); } void LX200Generic::processButton(const char * button_n, ISState state) { //ignore OFF if (state == ISS_OFF) return; // Max Slew speed if (!strcmp(button_n, "Slew Max")) { setSlewMode(PortFD, 0); IUResetSwitch(&SlewModeSP); SlewModeS[0].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Find Slew speed else if (!strcmp(button_n, "Slew Find")) { setSlewMode(PortFD, 1); IUResetSwitch(&SlewModeSP); SlewModeS[1].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Centering Slew else if (!strcmp(button_n, "Slew Centering")) { setSlewMode(PortFD, 2); IUResetSwitch(&SlewModeSP); SlewModeS[2].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Guide Slew else if (!strcmp(button_n, "Slew Guide")) { setSlewMode(PortFD, 3); IUResetSwitch(&SlewModeSP); SlewModeS[3].s = ISS_ON; IDSetSwitch(&SlewModeSP, NULL); } // Abort else if (!strcmp(button_n, "Abort Motion")) { // Only abort if we have some sort of motion going on if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY || EqNP.s == IPS_BUSY || GuideNSNP.s == IPS_BUSY || GuideWENP.s == IPS_BUSY) { Abort(); } } } void LX200Generic::processNSWE(double mag, double angle) { if (mag < 0.5) { // Moving in the same direction will make it stop if (MovementNSSP.s == IPS_BUSY || MovementWESP.s == IPS_BUSY) Abort(); } // Put high threshold else if (mag > 0.9) { // North if (angle > 0 && angle < 180) { // Don't try to move if you're busy and moving in the same direction if (MovementNSSP.s != IPS_BUSY || MovementNSS[0].s != ISS_ON) MoveNS(MOTION_NORTH); MovementNSSP.s = IPS_BUSY; MovementNSSP.sp[0].s = ISS_ON; MovementNSSP.sp[1].s = ISS_OFF; IDSetSwitch(&MovementNSSP, NULL); } // South if (angle > 180 && angle < 360) { // Don't try to move if you're busy and moving in the same direction if (MovementNSSP.s != IPS_BUSY || MovementNSS[1].s != ISS_ON) MoveNS(MOTION_SOUTH); MovementNSSP.s = IPS_BUSY; MovementNSSP.sp[0].s = ISS_OFF; MovementNSSP.sp[1].s = ISS_ON; IDSetSwitch(&MovementNSSP, NULL); } // East if (angle < 90 || angle > 270) { // Don't try to move if you're busy and moving in the same direction if (MovementWESP.s != IPS_BUSY || MovementWES[1].s != ISS_ON) MoveWE(MOTION_EAST); MovementWESP.s = IPS_BUSY; MovementWESP.sp[0].s = ISS_OFF; MovementWESP.sp[1].s = ISS_ON; IDSetSwitch(&MovementWESP, NULL); } // West if (angle > 90 && angle < 270) { // Don't try to move if you're busy and moving in the same direction if (MovementWESP.s != IPS_BUSY || MovementWES[0].s != ISS_ON) MoveWE(MOTION_WEST); MovementWESP.s = IPS_BUSY; MovementWESP.sp[0].s = ISS_ON; MovementWESP.sp[1].s = ISS_OFF; IDSetSwitch(&MovementWESP, NULL); } } } bool LX200Generic::saveConfigItems(FILE *fp) { controller->saveConfigItems(fp); INDI::Telescope::saveConfigItems(fp); return true; } void LX200Generic::processJoystick(const char * joystick_n, double mag, double angle) { if (!strcmp(joystick_n, "NSWE Control")) processNSWE(mag, angle); } void LX200Generic::joystickHelper(const char * joystick_n, double mag, double angle) { telescope->processJoystick(joystick_n, mag, angle); } void LX200Generic::buttonHelper(const char * button_n, ISState state) { telescope->processButton(button_n, state); } libindi-0.9.7/drivers/telescope/celestronprotocol.h0000644000175000017500000001032612241463551021520 0ustar jasemjasem/* * Header File for the Telescope Control protocols for the Meade LX200 * Author: John Kielkopf (kielkopf@louisville.edu) * * This file contains header information used in common with xmtel. 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 * * 15 May 2003 -- Version 2.00 * */ #ifndef CELESTRON_PROTOCOL_H #define CELESTRON_PROTOCOL_H #include /* These are user defined quantities that set the limits over which it */ /* is safe to operate the telescope. */ /* LOWER is the number of degrees from the zenith that you will allow. */ /* Use 80, for example, to keep the eyepiece end out of the fork arm space */ /* of an LX200 telescope. */ #define LOWER 90. /* HIGHER is the horizon. 0 is an unobstructed horizon in every direction. */ /* Use 10, for example, to limit sighting below 10 degrees above the horizon. */ #define HIGHER 0. /* Set this if a slew to the north sends the telescope south. */ #define REVERSE_NS 0 /* 1 for reverse; 0 for normal. */ /* Set this for maximum slew rate allowed in degree/sec. */ #define MAXSLEWRATE 4 /* 2 for safety; 4 for 16-inch; 8 otherwise. */ /* The following parameters are used internally to set speed and direction. */ /* Do not change these values. */ #define SLEW 0 #define FIND 1 #define CENTER 2 #define GUIDE 3 #if REVERSE_NS > 0 #define NORTH 3 #define SOUTH 0 #else #define NORTH 0 #define SOUTH 3 #endif #define EAST 2 #define WEST 1 /* Slew speed defines */ # define SLEWRATE8 8 /* should be 8 degrees per second (not 16-inch) */ # define SLEWRATE4 4 /* should be 4 degrees per second */ # define SLEWRATE3 3 /* should be 3 degrees per second */ # define SLEWRATE2 2 /* should be 2 degrees per second */ /* Reticle defines */ #define BRIGHTER 16 /* increase */ #define DIMMER 8 /* decrease */ #define BLINK0 0 /* no blinking */ #define BLINK1 1 /* blink rate 1 */ #define BLINK2 2 /* blink rate 2 */ #define BLINK3 4 /* blink rate 3 */ /* Focus defines */ #define FOCUSOUT 8 /* positive voltage output */ #define FOCUSIN 4 /* negative voltage output */ #define FOCUSSTOP 0 /* no output */ #define FOCUSSLOW 1 /* half voltage */ #define FOCUSFAST 2 /* full voltage */ /* Rotator defines */ #define ROTATORON 1 /* image rotator on */ #define ROTATOROFF 0 /* image rotator off */ /* Fan defines */ #define FANON 1 /* cooling fan on */ #define FANOFF 0 /* cooling fan off */ #ifdef __cplusplus extern "C" { #endif int ConnectTel(char *port); void DisconnectTel(void); /* 0 if connection is OK, -1 otherwise */ int CheckConnectTel(void); void SetRate(int newRate); void SetLimits(double limitLower, double limitHigher); void StartSlew(int direction); void StopSlew(int direction); double GetRA(void); double GetDec(void); int SlewToCoords(double newRA, double newDec); int SyncToCoords(double newRA, double newDec); int CheckCoords(double desRA, double desDec, double tolRA, double tolDEC); int isScopeSlewing(); int updateLocation(double lng, double lat); int updateTime(struct ln_date *utc, double utc_offset); void StopNSEW(void); int SetSlewRate(void); int SyncLST(double newTime); int SyncLocalTime(); void Reticle(int reticle); void Focus(int focus); void Derotator(int rotate); void Fan(int fan); #ifdef __cplusplus } #endif #endif libindi-0.9.7/drivers/telescope/magellan1.cpp0000644000175000017500000003315412241463551020140 0ustar jasemjasem#if 0 MAGELLAN Generic Copyright (C) 2011 Onno Hommes (ohommes@alumni.cmu.edu) 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 #include #include #include #include #include #include #include #include "magellandriver.h" #include "magellan1.h" #include Magellan1 *telescope = NULL; extern char* me; #define COMM_GROUP "Communication" #define BASIC_GROUP "Position" #define MAGELLAN_TRACK 0 #define MAGELLAN_SYNC 1 /* Handy Macros */ #define currentRA EquatorialCoordsRN[0].value #define currentDEC EquatorialCoordsRN[1].value static void ISPoll(void *); static void retryConnection(void *); /*INDI Propertries */ /**********************************************************************************************/ /************************************ GROUP: Communication ************************************/ /**********************************************************************************************/ /******************************************** Property: Connection *********************************************/ static ISwitch ConnectS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}}; ISwitchVectorProperty ConnectSP = { mydev, "CONNECTION" , "Connection", COMM_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, ConnectS, NARRAY(ConnectS), "", 0}; /******************************************** Property: Device Port *********************************************/ /*wildi removed static */ static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}}; ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", COMM_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0}; /**********************************************************************************************/ /************************************ GROUP: Position Display**********************************/ /**********************************************************************************************/ /******************************************** Property: Equatorial Coordinates JNow Perm: RO *********************************************/ INumber EquatorialCoordsRN[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}}; INumberVectorProperty EquatorialCoordsRNP= { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 120, IPS_IDLE, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), "", 0}; /*****************************************************************************************************/ /**************************************** END PROPERTIES *********************************************/ /*****************************************************************************************************/ /* send client definitions of all properties */ void ISInit() { static int isInit=0; if (isInit) return; if (telescope == NULL) { IUSaveText(&PortT[0], "/dev/ttyS0"); telescope = new Magellan1(); telescope->setCurrentDeviceName(mydev); } isInit = 1; IEAddTimer (POLLMS, ISPoll, NULL); } void ISGetProperties (const char *dev) { ISInit(); telescope->ISGetProperties(dev);} void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); telescope->ISNewSwitch(dev, name, states, names, n);} void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); telescope->ISNewText(dev, name, texts, names, n);} void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); telescope->ISNewNumber(dev, name, values, names, n);} void ISPoll (void *p) { telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); p=p;} void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { telescope->ISSnoopDevice(root); } /************************************************** *** MAGELLAN1 Implementation ***************************************************/ Magellan1::Magellan1() { currentSiteNum = 1; trackingMode = MAGELLAN_TRACK_DEFAULT; lastSet = -1; fault = false; simulation = false; currentSet = 0; fd = -1; // Children call parent routines, this is the default IDLog("INDI Library v%g\n", INDI_LIBV); IDLog("Initializing from MAGELLAN device...\n"); IDLog("Driver Version: 2011-07-28\n"); } Magellan1::~Magellan1() { } void Magellan1::setCurrentDeviceName(const char * devName) { strcpy(thisDevice, devName); } void Magellan1::ISGetProperties(const char *dev) { if (dev && strcmp (thisDevice, dev)) return; // COMM_GROUP IDDefSwitch (&ConnectSP, NULL); IDDefText (&PortTP, NULL); // POSITION_GROUP IDDefNumber (&EquatorialCoordsRNP, NULL); /* Send the basic data to the new client if the previous client(s) are already connected. */ if (ConnectSP.s == IPS_OK) getBasicData(); } void Magellan1::ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } void Magellan1::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { IText *tp; /* Ignore other devices */ if (strcmp (dev, thisDevice)) return; /* See if the port is updated */ if (!strcmp(name, PortTP.name) ) { PortTP.s = IPS_OK; tp = IUFindText( &PortTP, names[0] ); if (!tp) return; IUSaveText(&PortTP.tp[0], texts[0]); IDSetText (&PortTP, NULL); return; } } void Magellan1::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(values); INDI_UNUSED(names); INDI_UNUSED(n); } void Magellan1::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { INDI_UNUSED(names); /* Ignore other devices */ if (strcmp (thisDevice, dev)) return; // FIRST Switch ALWAYS for Connection if (!strcmp (name, ConnectSP.name)) { bool connectionEstablished = (ConnectS[0].s == ISS_ON); if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return; if ( (connectionEstablished && ConnectS[0].s == ISS_ON) || (!connectionEstablished && ConnectS[1].s == ISS_ON)) { ConnectSP.s = IPS_OK; IDSetSwitch(&ConnectSP, NULL); return; } connectTelescope(); return; } } void Magellan1::handleError(ISwitchVectorProperty *svp, int err, const char *msg) { svp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_magellan_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetSwitch(svp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property or busy*/ if (err == -2) { svp->s = IPS_ALERT; IDSetSwitch(svp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetSwitch( svp , "%s failed.", msg); fault = true; } void Magellan1::handleError(INumberVectorProperty *nvp, int err, const char *msg) { nvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_magellan_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetNumber(nvp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { nvp->s = IPS_ALERT; IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetNumber( nvp , "%s failed.", msg); fault = true; } void Magellan1::handleError(ITextVectorProperty *tvp, int err, const char *msg) { tvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_magellan_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetText(tvp, NULL); IEAddTimer(10000, retryConnection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { tvp->s = IPS_ALERT; IDSetText(tvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else { /* Changing property failed, user should retry. */ IDSetText( tvp , "%s failed.", msg); } fault = true; } void Magellan1::correctFault() { fault = false; IDMessage(thisDevice, "Telescope is online."); } bool Magellan1::isTelescopeOn(void) { return (ConnectSP.sp[0].s == ISS_ON); } static void retryConnection(void * p) { int fd = *( (int *) p); if (check_magellan_connection(fd)) { ConnectSP.s = IPS_IDLE; IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); return; } ConnectS[0].s = ISS_ON; ConnectS[1].s = ISS_OFF; ConnectSP.s = IPS_OK; IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); } void Magellan1::ISPoll() { int err=0; if (!isTelescopeOn()) return; if ( (err = getMAGELLANRA(fd, ¤tRA)) < 0 || (err = getMAGELLANDEC(fd, ¤tDEC)) < 0) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, NULL); handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC"); return; } if (fault) correctFault(); EquatorialCoordsRNP.s = IPS_OK; lastRA = currentRA; lastDEC = currentDEC; IDSetNumber (&EquatorialCoordsRNP, NULL); } void Magellan1::getBasicData() { char caldendarDate[10]; int err; /* Magellan 1 Get Calendar Date As a Test (always 1/1/96) */ if ( (err = getCalenderDate(fd, caldendarDate)) < 0) IDMessage(thisDevice, "Failed to retrieve calendar date from device."); else IDMessage(thisDevice, "Successfully retrieved calendar date from device."); /* Only 24 Time format on Magellan and you cant get to the local time which you can set in Magellan I */ timeFormat = MAGELLAN_24; if ( (err = getMAGELLANRA(fd, &targetRA)) < 0 || (err = getMAGELLANDEC(fd, &targetDEC)) < 0) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, NULL); handleError(&EquatorialCoordsRNP, err, "Getting RA/DEC"); return; } if (fault) correctFault(); EquatorialCoordsRNP.np[0].value = targetRA; EquatorialCoordsRNP.np[1].value = targetDEC; EquatorialCoordsRNP.s = IPS_OK; IDSetNumber (&EquatorialCoordsRNP, NULL); } void Magellan1::connectTelescope() { switch (ConnectSP.sp[0].s) { case ISS_ON: /* Magellan I only has 1200 buad, 8 data bits, 0 parity and 1 stop bit */ if (tty_connect(PortTP.tp[0].text, 1200, 8, 0, 1, &fd) != TTY_OK) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH write and read permission to your port.\n", PortTP.tp[0].text); return; } if (check_magellan_connection(fd)) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); return; } #ifdef INDI_DEBUG IDLog("Telescope test successful.\n"); #endif ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); getBasicData(); break; case ISS_OFF: ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_IDLE; IDSetSwitch (&ConnectSP, "Telescope is offline."); IDLog("Telescope is offline."); tty_disconnect(fd); break; } } libindi-0.9.7/drivers/telescope/lx200fs2.h0000755000175000017500000000465712241463551017235 0ustar jasemjasem/* LX200 FS2 Driver Copyright (C) 2009 Ferran Casarramona (ferran.casarramona@gmail.com) Based on LX200 Basic driver from: Copyright (C) 2005 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef LX200FS2_H #define LX200FS2_H //#include "indidevapi.h" //#include "indicom.h" #include "lx200genericlegacy.h" // To prevent of using mydev from generic by error #ifdef mydev #undef mydevice #endif class LX200Fs2 : public LX200GenericLegacy { public: LX200Fs2(); ~LX200Fs2(); virtual void ISGetProperties (const char *dev); virtual void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); // Not implemented. LX200 generic used. //virtual void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); //virtual void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); //virtual void ISPoll (); virtual void handleError(ISwitchVectorProperty *svp, int err, const char *msg); virtual void handleError(INumberVectorProperty *nvp, int err, const char *msg); virtual void handleError(ITextVectorProperty *tvp, int err, const char *msg); int check_fs2_connection(int fd); // Added to support firmware versions below 1.19 protected: const char *DeviceName; /* Numbers */ INumber FirmwareVerN[1]; // Firmware version /* Number Vectors */ INumberVectorProperty FirmwareVerNP; //*******************************************************/ /* Connection Routines ********************************************************/ void init_properties(); void getBasicData(); virtual void connectTelescope(); bool is_connected(void); }; void changeLX200FS2DeviceName(const char *newName); #endif libindi-0.9.7/drivers/telescope/ieq45.cpp0000644000175000017500000005517412241463551017234 0ustar jasemjasem#if 0 IEQ45 Basic Driver Copyright (C) 2011 Nacho Mas (mas.ignacio@gmail.com). Only litle changes from lx200basic made it by Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include /* INDI Common Library Routines */ #include "indicom.h" /* IEQ45 Command Set */ #include "ieq45driver.h" /* Our driver header */ #include "ieq45.h" using namespace std; /* Our telescope auto pointer */ auto_ptr telescope(0); const int POLLMS = 100; // Period of update, 1 second. const char *mydev = "IEQ45"; // Name of our device. const char *BASIC_GROUP = "Main Control"; // Main Group const char *OPTIONS_GROUP = "Options"; // Options Group /* Handy Macros */ #define currentRA EquatorialCoordsRN[0].value #define currentDEC EquatorialCoordsRN[1].value static void ISPoll(void *); static void retry_connection(void *); /************************************************************************************** ** Send client definitions of all properties. ***************************************************************************************/ void ISInit() { static int isInit=0; if (isInit) return; if (telescope.get() == 0) telescope.reset(new IEQ45Basic()); isInit = 1; IEAddTimer (POLLMS, ISPoll, NULL); } /************************************************************************************** ** ***************************************************************************************/ void ISGetProperties (const char *dev) { ISInit(); telescope->ISGetProperties(dev); } /************************************************************************************** ** ***************************************************************************************/ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); telescope->ISNewSwitch(dev, name, states, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); telescope->ISNewText(dev, name, texts, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); telescope->ISNewNumber(dev, name, values, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISPoll (void *p) { INDI_UNUSED(p); telescope->ISPoll(); IEAddTimer (POLLMS, ISPoll, NULL); } /************************************************************************************** ** ***************************************************************************************/ void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } /************************************************************************************** ** ***************************************************************************************/ void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } /************************************************************************************** ** IEQ45 Basic constructor ***************************************************************************************/ IEQ45Basic::IEQ45Basic() { init_properties(); lastSet = -1; fd = -1; simulation = false; lastRA = 0; lastDEC = 0; currentSet = 0; IDLog("Initializing from IEQ45 device...\n"); IDLog("Driver Version: 0.1 (2011-11-07)\n"); enable_simulation(false); } /************************************************************************************** ** ***************************************************************************************/ IEQ45Basic::~IEQ45Basic() { } /************************************************************************************** ** Initialize all properties & set default values. ***************************************************************************************/ void IEQ45Basic::init_properties() { // Connection IUFillSwitch(&ConnectS[0], "CONNECT", "Connect", ISS_OFF); IUFillSwitch(&ConnectS[1], "DISCONNECT", "Disconnect", ISS_ON); IUFillSwitchVector(&ConnectSP, ConnectS, NARRAY(ConnectS), mydev, "CONNECTION", "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); // Coord Set IUFillSwitch(&OnCoordSetS[0], "SLEW", "Slew", ISS_ON); IUFillSwitch(&OnCoordSetS[1], "SYNC", "Sync", ISS_OFF); IUFillSwitchVector(&OnCoordSetSP, OnCoordSetS, NARRAY(OnCoordSetS), mydev, "ON_COORD_SET", "On Set", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); //Track MODE IUFillSwitch(&TrackModeS[0],"SIDERAL", "Sidereal", ISS_ON); IUFillSwitch(&TrackModeS[1],"LUNAR","Lunar", ISS_OFF); IUFillSwitch(&TrackModeS[2],"SOLAR", "Solar", ISS_OFF); IUFillSwitch(&TrackModeS[3],"ZERO", "Stop", ISS_OFF); IUFillSwitchVector(&TrackModeSP, TrackModeS, NARRAY(TrackModeS), mydev, "TRACK_MODE", "Track Mode", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); // Abort IUFillSwitch(&AbortSlewS[0], "ABORT", "Abort", ISS_OFF); IUFillSwitchVector(&AbortSlewSP, AbortSlewS, NARRAY(AbortSlewS), mydev, "ABORT_MOTION", "Abort Slew/Track", BASIC_GROUP, IP_RW, ISR_ATMOST1, 0, IPS_IDLE); // Port IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyS0"); IUFillTextVector(&PortTP, PortT, NARRAY(PortT), mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE); // Equatorial Coords IUFillNumber(&EquatorialCoordsRN[0], "RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0.); IUFillNumber(&EquatorialCoordsRN[1], "DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0.); IUFillNumberVector(&EquatorialCoordsRNP, EquatorialCoordsRN, NARRAY(EquatorialCoordsRN), mydev, "EQUATORIAL_EOD_COORD" , "Equatorial JNow", BASIC_GROUP, IP_RW, 0, IPS_IDLE); } /************************************************************************************** ** Define IEQ45 Basic properties to clients. ***************************************************************************************/ void IEQ45Basic::ISGetProperties(const char *dev) { if (dev && strcmp (mydev, dev)) return; // Main Control IDDefSwitch(&ConnectSP, NULL); IDDefText(&PortTP, NULL); IDDefNumber(&EquatorialCoordsRNP, NULL); IDDefSwitch(&OnCoordSetSP, NULL); IDDefSwitch(&TrackModeSP, NULL); IDDefSwitch(&AbortSlewSP, NULL); } /************************************************************************************** ** Process Text properties ***************************************************************************************/ void IEQ45Basic::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // Ignore if not ours if (strcmp (dev, mydev)) return; // =================================== // Port Name // =================================== if (!strcmp(name, PortTP.name) ) { if (IUUpdateText(&PortTP, texts, names, n) < 0) return; PortTP.s = IPS_OK; IDSetText (&PortTP, NULL); return; } if (is_connected() == false) { IDMessage(mydev, "IEQ45 is offline. Please connect before issuing any commands."); reset_all_properties(); return; } } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // Ignore if not ours if (strcmp (dev, mydev)) return; if (is_connected() == false) { IDMessage(mydev, "IEQ45 is offline. Please connect before issuing any commands."); reset_all_properties(); return; } // =================================== // Equatorial Coords // =================================== if (!strcmp (name, EquatorialCoordsRNP.name)) { int i=0, nset=0, error_code=0; double newRA =0, newDEC =0; for (nset = i = 0; i < n; i++) { INumber *eqp = IUFindNumber (&EquatorialCoordsRNP, names[i]); if (eqp == &EquatorialCoordsRN[0]) { newRA = values[i]; nset += newRA >= 0 && newRA <= 24.0; } else if (eqp == &EquatorialCoordsRN[1]) { newDEC = values[i]; nset += newDEC >= -90.0 && newDEC <= 90.0; } } if (nset == 2) { char RAStr[32], DecStr[32]; fs_sexa(RAStr, newRA, 2, 3600); fs_sexa(DecStr, newDEC, 2, 3600); #ifdef INDI_DEBUG IDLog("We received JNow RA %g - DEC %g\n", newRA, newDEC); IDLog("We received JNow RA %s - DEC %s\n", RAStr, DecStr); #endif if (!simulation && ( (error_code = setObjectRA(fd, newRA)) < 0 || ( error_code = setObjectDEC(fd, newDEC)) < 0)) { handle_error(&EquatorialCoordsRNP, error_code, "Setting RA/DEC"); return; } targetRA = newRA; targetDEC = newDEC; if (process_coords() == false) { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, NULL); } } // end nset else { EquatorialCoordsRNP.s = IPS_ALERT; IDSetNumber(&EquatorialCoordsRNP, "RA or Dec missing or invalid"); } return; } /* end EquatorialCoordsWNP */ } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { // ignore if not ours // if (strcmp (mydev, dev)) return; // =================================== // Connect Switch // =================================== if (!strcmp (name, ConnectSP.name)) { if (IUUpdateSwitch(&ConnectSP, states, names, n) < 0) return; connect_telescope(); return; } if (is_connected() == false) { IDMessage(mydev, "IEQ45 is offline. Please connect before issuing any commands."); reset_all_properties(); return; } // =================================== // Coordinate Set // =================================== if (!strcmp(name, OnCoordSetSP.name)) { if (IUUpdateSwitch(&OnCoordSetSP, states, names, n) < 0) return; currentSet = get_switch_index(&OnCoordSetSP); OnCoordSetSP.s = IPS_OK; IDSetSwitch(&OnCoordSetSP, NULL); } // =================================== // Track Mode Set // =================================== if (!strcmp(name, TrackModeSP.name)) { if (IUUpdateSwitch(&TrackModeSP, states, names, n) < 0) return; int trackMode = get_switch_index(&TrackModeSP); selectTrackingMode(fd, trackMode); TrackModeSP.s = IPS_OK; IDSetSwitch(&TrackModeSP, NULL); } // =================================== // Abort slew // =================================== if (!strcmp (name, AbortSlewSP.name)) { IUResetSwitch(&AbortSlewSP); abortSlew(fd); if (EquatorialCoordsRNP.s == IPS_BUSY) { AbortSlewSP.s = IPS_OK; EquatorialCoordsRNP.s = IPS_IDLE; IDSetSwitch(&AbortSlewSP, "Slew aborted."); IDSetNumber(&EquatorialCoordsRNP, NULL); } return; } } /************************************************************************************** ** Retry connecting to the telescope on error. Give up if there is no hope. ***************************************************************************************/ void IEQ45Basic::handle_error(INumberVectorProperty *nvp, int err, const char *msg) { nvp->s = IPS_ALERT; /* First check to see if the telescope is connected */ if (check_IEQ45_connection(fd)) { /* The telescope is off locally */ ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_BUSY; IDSetSwitch(&ConnectSP, "Telescope is not responding to commands, will retry in 10 seconds."); IDSetNumber(nvp, NULL); IEAddTimer(10000, retry_connection, &fd); return; } /* If the error is a time out, then the device doesn't support this property */ if (err == -2) { nvp->s = IPS_ALERT; IDSetNumber(nvp, "Device timed out. Current device may be busy or does not support %s. Will retry again.", msg); } else /* Changing property failed, user should retry. */ IDSetNumber( nvp , "%s failed.", msg); fault = true; } /************************************************************************************** ** Set all properties to idle and reset most switches to clean state. ***************************************************************************************/ void IEQ45Basic::reset_all_properties() { ConnectSP.s = IPS_IDLE; OnCoordSetSP.s = IPS_IDLE; TrackModeSP.s = IPS_IDLE; AbortSlewSP.s = IPS_IDLE; PortTP.s = IPS_IDLE; EquatorialCoordsRNP.s = IPS_IDLE; IUResetSwitch(&OnCoordSetSP); IUResetSwitch(&TrackModeSP); IUResetSwitch(&AbortSlewSP); OnCoordSetS[0].s = ISS_ON; TrackModeS[0].s = ISS_ON; ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch(&ConnectSP, NULL); IDSetSwitch(&OnCoordSetSP, NULL); IDSetSwitch(&TrackModeSP, NULL); IDSetSwitch(&AbortSlewSP, NULL); IDSetText(&PortTP, NULL); IDSetNumber(&EquatorialCoordsRNP, NULL); } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::correct_fault() { fault = false; IDMessage(mydev, "Telescope is online."); } /************************************************************************************** ** ***************************************************************************************/ bool IEQ45Basic::is_connected() { if (simulation) return true; return (ConnectSP.sp[0].s == ISS_ON); } /************************************************************************************** ** ***************************************************************************************/ static void retry_connection(void * p) { int fd = *((int *) p); if (check_IEQ45_connection(fd)) telescope->connection_lost(); else telescope->connection_resumed(); } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::ISPoll() { if (is_connected() == false || simulation) return; double dx, dy; int error_code=0; switch (EquatorialCoordsRNP.s) { case IPS_IDLE: getIEQ45RA(fd, ¤tRA); getIEQ45DEC(fd, ¤tDEC); if ( fabs (currentRA - lastRA) > 0.01 || fabs (currentDEC - lastDEC) > 0.01) { lastRA = currentRA; lastDEC = currentDEC; IDSetNumber (&EquatorialCoordsRNP, NULL); IDLog("IDLE update coord\n"); } break; case IPS_BUSY: getIEQ45RA(fd, ¤tRA); getIEQ45DEC(fd, ¤tDEC); dx = targetRA - currentRA; dy = targetDEC - currentDEC; // Wait until acknowledged or within threshold if ( fabs(dx) <= (3/(900.0)) && fabs(dy) <= (3/60.0)) { lastRA = currentRA; lastDEC = currentDEC; IUResetSwitch(&OnCoordSetSP); OnCoordSetSP.s = IPS_OK; EquatorialCoordsRNP.s = IPS_OK; IDSetNumber (&EquatorialCoordsRNP, NULL); switch (currentSet) { case IEQ45_SLEW: OnCoordSetSP.sp[IEQ45_SLEW].s = ISS_ON; IDSetSwitch (&OnCoordSetSP, "Slew is complete."); break; case IEQ45_SYNC: break; } } else IDSetNumber (&EquatorialCoordsRNP, NULL); break; case IPS_OK: if ( (error_code = getIEQ45RA(fd, ¤tRA)) < 0 || (error_code = getIEQ45DEC(fd, ¤tDEC)) < 0) { handle_error(&EquatorialCoordsRNP, error_code, "Getting RA/DEC"); return; } if (fault == true) correct_fault(); if ( (currentRA != lastRA) || (currentDEC != lastDEC)) { lastRA = currentRA; lastDEC = currentDEC; //IDLog("IPS_OK update coords %g %g\n",currentRA,currentDEC); IDSetNumber (&EquatorialCoordsRNP, NULL); } break; case IPS_ALERT: break; } } /************************************************************************************** ** ***************************************************************************************/ bool IEQ45Basic::process_coords() { int error_code; char syncString[256]; char RAStr[32], DecStr[32]; double dx, dy; switch (currentSet) { // Slew case IEQ45_SLEW: lastSet = IEQ45_SLEW; if (EquatorialCoordsRNP.s == IPS_BUSY) { IDLog("Aborting Slew\n"); abortSlew(fd); // sleep for 100 mseconds usleep(100000); } if ( !simulation && (error_code = Slew(fd))) { slew_error(error_code); return false; } EquatorialCoordsRNP.s = IPS_BUSY; fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); IDSetNumber(&EquatorialCoordsRNP, "Slewing to JNow RA %s - DEC %s", RAStr, DecStr); IDLog("Slewing to JNow RA %s - DEC %s\n", RAStr, DecStr); break; // Sync case IEQ45_SYNC: lastSet = IEQ45_SYNC; EquatorialCoordsRNP.s = IPS_IDLE; if ( !simulation && ( error_code = Sync(fd, syncString) < 0) ) { IDSetNumber( &EquatorialCoordsRNP , "Synchronization failed."); return false; } if (simulation) { EquatorialCoordsRN[0].value = EquatorialCoordsRN[0].value; EquatorialCoordsRN[1].value = EquatorialCoordsRN[1].value; } EquatorialCoordsRNP.s = IPS_OK; IDLog("Synchronization successful %s\n", syncString); IDSetNumber(&EquatorialCoordsRNP, "Synchronization successful."); break; } return true; } /************************************************************************************** ** ***************************************************************************************/ int IEQ45Basic::get_switch_index(ISwitchVectorProperty *sp) { for (int i=0; i < sp->nsp ; i++) if (sp->sp[i].s == ISS_ON) return i; return -1; } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::connect_telescope() { switch (ConnectSP.sp[0].s) { case ISS_ON: if (simulation) { ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Simulated telescope is online."); return; } if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.", PortT[0].text); return; } if (check_IEQ45_connection(fd)) { ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; IDSetSwitch (&ConnectSP, "Error connecting to Telescope. Telescope is offline."); return; } ConnectSP.s = IPS_OK; IDSetSwitch (&ConnectSP, "Telescope is online. Retrieving basic data..."); get_initial_data(); break; case ISS_OFF: ConnectS[0].s = ISS_OFF; ConnectS[1].s = ISS_ON; ConnectSP.s = IPS_IDLE; if (simulation) { IDSetSwitch (&ConnectSP, "Simulated Telescope is offline."); return; } IDSetSwitch (&ConnectSP, "Telescope is offline."); IDLog("Telescope is offline."); tty_disconnect(fd); break; } } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::get_initial_data() { // Make sure short checkIEQ45Format(fd); // Get current RA/DEC getIEQ45RA(fd, ¤tRA); getIEQ45DEC(fd, ¤tDEC); IDSetNumber (&EquatorialCoordsRNP, NULL); } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::slew_error(int slewCode) { OnCoordSetSP.s = IPS_IDLE; IDLog("Aborting Slew\n"); abortSlew(fd); if (slewCode == 1) IDSetSwitch (&OnCoordSetSP, "Object below horizon."); else if (slewCode == 2) IDSetSwitch (&OnCoordSetSP, "Object below the minimum elevation limit."); else IDSetSwitch (&OnCoordSetSP, "Slew failed."); } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::enable_simulation(bool enable) { simulation = enable; if (simulation) IDLog("Warning: Simulation is activated.\n"); else IDLog("Simulation is disabled.\n"); } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::connection_lost() { ConnectSP.s = IPS_IDLE; IDSetSwitch(&ConnectSP, "The connection to the telescope is lost."); return; } /************************************************************************************** ** ***************************************************************************************/ void IEQ45Basic::connection_resumed() { ConnectS[0].s = ISS_ON; ConnectS[1].s = ISS_OFF; ConnectSP.s = IPS_OK; IDSetSwitch(&ConnectSP, "The connection to the telescope has been resumed."); } libindi-0.9.7/drivers/telescope/lx200ap.h0000644000175000017500000000451312241463551017127 0ustar jasemjasem/* LX200 Astro-Physics INDI driver Copyright (C) 2007 Markus Wildi 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 */ #ifndef LX200ASTROPHYSICS_H #define LX200ASTROPHYSICS_H #include "lx200genericlegacy.h" /* thisDevice is not defined with the global section property definitions.*/ /* So I use this macro throught the lx200ap.cpp */ /* even one can use thisDevice e.g. in function call like IDMessage( thisDevice,...)*/ /* That may collide with what is defined in LX200GenericLegacy.cpp */ #define myapdev "LX200 Astro-Physics" #define DOMECONTROL 0 #define NOTDOMECONTROL 1 #define SYNCCM 0 #define SYNCCMR 1 #define NOTESTABLISHED 0 #define ESTABLISHED 1 #define MOUNTNOTINITIALIZED 0 #define MOUNTINITIALIZED 1 class LX200AstroPhysics : public LX200GenericLegacy { public: LX200AstroPhysics(); ~LX200AstroPhysics() {} void ISGetProperties (const char *dev); void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); void ISSnoopDevice (XMLEle *root) ; void ISPoll (); int setBasicDataPart0(); int setBasicDataPart1(); void connectTelescope(); void setupTelescope(); void handleAltAzSlew(); void handleAZCoordSet() ; void handleEqCoordSet() ; void ISInit() ; bool isMountInit(void) ; private: enum LX200_STATUS { LX200_SLEW, LX200_TRACK, LX200_SYNC, LX200_PARK }; private: double targetRA, targetDEC; double targetAZ, targetALT; }; void changeLX200AstroPhysicsDeviceName(const char *newName); #endif libindi-0.9.7/drivers/telescope/ieq45driver.h0000644000175000017500000002512512241463551020106 0ustar jasemjasem/* IEQ45 Driver Copyright (C) 2011 Nacho Mas (mas.ignacio@gmail.com). Only litle changes from lx200basic made it by Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef IEQ45DRIVER_H #define IEQ45DRIVER_H /* Slew speeds */ enum TSlew { IEQ45_SLEW_MAX, IEQ45_SLEW_FIND, IEQ45_SLEW_CENTER, IEQ45_SLEW_GUIDE}; /* Alignment modes */ enum TAlign { IEQ45_ALIGN_POLAR, IEQ45_ALIGN_ALTAZ, IEQ45_ALIGN_LAND }; /* Directions */ enum TDirection { IEQ45_NORTH, IEQ45_WEST, IEQ45_EAST, IEQ45_SOUTH, IEQ45_ALL}; /* Formats of Right ascention and Declenation */ enum TFormat { IEQ45_SHORT_FORMAT, IEQ45_LONG_FORMAT}; /* Time Format */ enum TTimeFormat { IEQ45_24, IEQ45_AM, IEQ45_PM}; /* Focus operation */ enum TFocusMotion { IEQ45_FOCUSIN, IEQ45_FOCUSOUT }; enum TFocusSpeed { IEQ45_HALTFOCUS = 0, IEQ45_FOCUSSLOW, IEQ45_FOCUSFAST}; /* Library catalogs */ enum TCatalog { IEQ45_STAR_C, IEQ45_DEEPSKY_C}; /* Frequency mode */ enum StarCatalog { IEQ45_STAR, IEQ45_SAO, IEQ45_GCVS }; /* Deep Sky Catalogs */ enum DeepSkyCatalog { IEQ45_NGC, IEQ45_IC, IEQ45_UGC, IEQ45_CALDWELL, IEQ45_ARP, IEQ45_ABELL, IEQ45_MESSIER_C}; /* Mount tracking frequency, in Hz */ enum TFreq { IEQ45_TRACK_SIDERAL, IEQ45_TRACK_LUNAR, IEQ45_TRACK_SOLAR,IEQ45_TRACK_ZERO}; #define MaxReticleDutyCycle 15 #define MaxFocuserSpeed 4 /* GET formatted sexagisemal value from device, return as double */ #define getIEQ45RA(fd, x) getCommandSexa(fd, x, ":GR#") //OK #define getIEQ45DEC(fd, x) getCommandSexa(fd, x, ":GD#") //OK //#define getObjectRA(fd, x) getCommandSexa(fd, x, ":Gr#") //NO OK //#define getObjectDEC(fd, x) getCommandSexa(fd, x, ":Gd#") //NO OK //#define getLocalTime12(fd, x) getCommandSexa(fd, x, ":Ga#") //NO OK #define getLocalTime24(fd, x) getCommandSexa(fd, x, ":GL#") //OK #define getSDTime(fd, x) getCommandSexa(fd, x, ":GS#") //OK #define getIEQ45Alt(fd, x) getCommandSexa(fd, x, ":GA#") //OK #define getIEQ45Az(fd, x) getCommandSexa(fd, x, ":GZ#") //OK /* GET String from device and store in supplied buffer x */ //#define getObjectInfo(fd, x) getCommandString(fd, x, ":LI#") //NO OK //#define getVersionDate(fd, x) getCommandString(fd, x, ":GVD#") //NO OK //#define getVersionTime(fd, x) getCommandString(fd, x, ":GVT#") //NO OK //#define getFullVersion(fd, x) getCommandString(fd, x, ":GVF#") //NO OK //#define getVersionNumber(fd, x) getCommandString(fd, x, ":GVN#") //NO OK //#define getProductName(fd, x) getCommandString(fd, x, ":GVP#") //NO OK //#define turnGPS_StreamOn(fd) getCommandString(fd, x, ":gps#") //NO OK /* GET Int from device and store in supplied pointer to integer x */ #define getUTCOffset(fd, x) getCommandInt(fd, x, ":GG#") //OK //#define getMaxElevationLimit(fd, x) getCommandInt(fd, x, ":Go#") //NO OK //#define getMinElevationLimit(fd, x) getCommandInt(fd, x, ":Gh#") //NO OK /* Generic set, x is an integer */ //#define setReticleDutyFlashCycle(fd, x) setCommandInt(fd, x, ":BD") #define setReticleFlashRate(fd, x) setCommandInt(fd, x, ":B") #define setFocuserSpeed(fd, x) setCommandInt(fd, x, ":F") #define setSlewSpeed(fd, x) setCommandInt(fd, x, ":Sw") /* Set X:Y:Z */ #define setLocalTime(fd, x,y,z) setCommandXYZ(fd, x,y,z, ":SL") #define setSDTime(fd, x,y,z) setCommandXYZ(fd, x,y,z, ":SS") /* GPS Specefic */ #define turnGPSOn(fd) write(fd, ":g+#", 5) #define turnGPSOff(fd) write(fd, ":g-#", 5) #define alignGPSScope(fd) write(fd, ":Aa#", 5) #define gpsSleep(fd) write(fd, ":hN#", 5) #define gpsWakeUp(fd) write(fd, ":hW#", 5); #define gpsRestart(fd) write(fd, ":I#", 4); #define updateGPS_System(fd) setStandardProcedure(fd, ":gT#") #define enableDecAltPec(fd) write(fd, ":QA+#", 6) #define disableDecAltPec(fd) write(fd, ":QA-#", 6) #define enableRaAzPec(fd) write(fd, ":QZ+#", 6) #define disableRaAzPec(fd) write(fd, ":QZ-#", 6) #define activateAltDecAntiBackSlash(fd) write(fd, "$BAdd#", 7) #define activateAzRaAntiBackSlash(fd) write(fd, "$BZdd#", 7) #define SelenographicSync(fd) write(fd, ":CL#", 5); #define slewToAltAz(fd) setStandardProcedure(fd, ":MA#") #define toggleTimeFormat(fd) write(fd, ":H#", 4) #define increaseReticleBrightness(fd) write(fd, ":B+#", 5) #define decreaseReticleBrightness(fd) write(fd, ":B-#", 5) #define turnFanOn(fd) write(fd, ":f+#", 5) #define turnFanOff(fd) write(fd, ":f-#", 5) #define seekHomeAndSave(fd) write(fd, ":hS#", 5) #define seekHomeAndSet(fd) write(fd, ":hF#", 5) #define turnFieldDeRotatorOn(fd) write(fd, ":r+#", 5) #define turnFieldDeRotatorOff(fd) write(fd, ":r-#", 5) #define slewToPark(fd) write(fd, ":hP#", 5) #ifdef __cplusplus extern "C" { #endif /************************************************************************** Basic I/O - OBSELETE **************************************************************************/ /*int openPort(const char *portID); int portRead(char *buf, int nbytes, int timeout); int portWrite(const char * buf); int IEQ45readOut(int timeout); int Connect(const char* device); void Disconnect();*/ /************************************************************************** Diagnostics **************************************************************************/ char ACK(int fd); /*int testTelescope(); int testAP();*/ int check_IEQ45_connection(int fd); /************************************************************************** Get Commands: store data in the supplied buffer. Return 0 on success or -1 on failure **************************************************************************/ /* Get Double from Sexagisemal */ int getCommandSexa(int fd, double *value, const char *cmd); /* Get String */ int getCommandString(int fd, char *data, const char* cmd); /* Get Int */ int getCommandInt(int fd, int *value, const char* cmd); /* Get tracking frequency */ int getTrackFreq(int fd, double * value); /* Get site Latitude */ int getSiteLatitude(int fd, int *dd, int *mm); /* Get site Longitude */ int getSiteLongitude(int fd, int *ddd, int *mm); /* Get Calender data */ int getCalenderDate(int fd, char *date); /* Get site Name */ int getSiteName(int fd, char *siteName, int siteNum); /* Get Number of Bars */ int getNumberOfBars(int fd, int *value); /* Get Home Search Status */ int getHomeSearchStatus(int fd, int *status); /* Get OTA Temperature */ int getOTATemp(int fd, double * value); /* Get time format: 12 or 24 */ int getTimeFormat(int fd, int *format); /* Get RA, DEC from Sky Commander controller */ int updateSkyCommanderCoord(int fd, double *ra, double *dec); /* Get RA, DEC from Intelliscope/SkyWizard controllers */ int updateIntelliscopeCoord (int fd, double *ra, double *dec); /************************************************************************** Set Commands **************************************************************************/ /* Set Int */ int setCommandInt(int fd, int data, const char *cmd); /* Set Sexigesimal */ int setCommandXYZ(int fd, int x, int y, int z, const char *cmd); /* Common routine for Set commands */ int setStandardProcedure(int fd, char * writeData); /* Set Slew Mode */ int setSlewMode(int fd, int slewMode); /* Set Alignment mode */ int setAlignmentMode(int fd, unsigned int alignMode); /* Set Object RA */ int setObjectRA(int fd, double ra); /* set Object DEC */ int setObjectDEC(int fd, double dec); /* Set Calender date */ int setCalenderDate(int fd, int dd, int mm, int yy); /* Set UTC offset */ int setUTCOffset(int fd, double hours); /* Set Track Freq */ int setTrackFreq(int fd, double trackF); /* Set current site longitude */ int setSiteLongitude(int fd, double Long); /* Set current site latitude */ int setSiteLatitude(int fd, double Lat); /* Set Object Azimuth */ int setObjAz(int fd, double az); /* Set Object Altitude */ int setObjAlt(int fd, double alt); /* Set site name */ int setSiteName(int fd, char * siteName, int siteNum); /* Set maximum slew rate */ int setMaxSlewRate(int fd, int slewRate); /* Set focuser motion */ int setFocuserMotion(int fd, int motionType); /* SET GPS Focuser raneg (1 to 4) */ int setGPSFocuserSpeed (int fd, int speed); /* Set focuser speed mode */ int setFocuserSpeedMode (int fd, int speedMode); /* Set minimum elevation limit */ int setMinElevationLimit(int fd, int min); /* Set maximum elevation limit */ int setMaxElevationLimit(int fd, int max); /************************************************************************** Motion Commands **************************************************************************/ /* Slew to the selected coordinates */ int Slew(int fd); /* Synchronize to the selected coordinates and return the matching object if any */ int Sync(int fd, char *matchedObject); /* Abort slew in all axes */ int abortSlew(int fd); /* Move into one direction, two valid directions can be stacked */ int MoveTo(int fd, int 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 **************************************************************************/ /* Ensures IEQ45 RA/DEC format is long */ int checkIEQ45Format(int fd); /* Select a site from the IEQ45 controller */ int selectSite(int fd, int siteNum); /* Select a catalog object */ int selectCatalogObject(int fd, int catalog, int NNNN); /* Select a sub catalog */ int selectSubCatalog(int fd, int catalog, int subCatalog); #ifdef __cplusplus } #endif #endif libindi-0.9.7/drivers/telescope/ieq45.h0000644000175000017500000000624412241463551016673 0ustar jasemjasem/* IEQ45 Basic Driver Copyright (C) 2011 Nacho Mas (mas.ignacio@gmail.com). Only litle changes from lx200basic made it by Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef IEQ45BASIC_H #define IEQ45BASIC_H #include "indidevapi.h" #include "indicom.h" class IEQ45Basic { public: IEQ45Basic(); ~IEQ45Basic(); void ISGetProperties (const char *dev); void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); void ISPoll (); void connection_lost(); void connection_resumed(); private: enum IEQ45_STATUS { IEQ45_SLEW, IEQ45_SYNC, IEQ45_PARK }; /* Switches */ ISwitch ConnectS[2]; ISwitch OnCoordSetS[2]; ISwitch TrackModeS[4]; ISwitch AbortSlewS[1]; /* Texts */ IText PortT[1]; /* Numbers */ INumber EquatorialCoordsRN[2]; /* Switch Vectors */ ISwitchVectorProperty ConnectSP; ISwitchVectorProperty OnCoordSetSP; ISwitchVectorProperty TrackModeSP; ISwitchVectorProperty AbortSlewSP; /* Number Vectors */ INumberVectorProperty EquatorialCoordsRNP; /* Text Vectors */ ITextVectorProperty PortTP; /*******************************************************/ /* Connection Routines ********************************************************/ void init_properties(); void get_initial_data(); void connect_telescope(); bool is_connected(void); /*******************************************************/ /* Misc routines ********************************************************/ bool process_coords(); int get_switch_index(ISwitchVectorProperty *sp); /*******************************************************/ /* Simulation Routines ********************************************************/ void enable_simulation(bool enable); /*******************************************************/ /* Error handling routines ********************************************************/ void slew_error(int slewCode); void reset_all_properties(); void handle_error(INumberVectorProperty *nvp, int err, const char *msg); void correct_fault(); protected: double JD; /* Julian Date */ double lastRA; double lastDEC; bool simulation; bool fault; int fd; /* Telescope tty file descriptor */ int currentSet; int lastSet; double targetRA, targetDEC; }; #endif libindi-0.9.7/drivers/telescope/intelliscope.c0000644000175000017500000001140212241463551020421 0ustar jasemjasem#if 0 Intelliscope INDI driver Copyright (C) 2005 Douglas Philipson (dougp AT intermind DOT net) Based on code by Jasem Mutlaq (mutlaqja@ikarustech.com) 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 #include #include #include #include #include #include #include #include "indidevapi.h" #include "indicom.h" #include "lx200driver.h" #define mydev "Intelliscope" #define BASIC_GROUP "Main Control" #define POLLMS 1000 #define currentRA eq[0].value #define currentDEC eq[1].value static void ISPoll(void *); static void ISInit(void); static void connectTelescope(void); int fd; static ISwitch PowerS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}}; ISwitchVectorProperty PowerSP = { mydev, "CONNECTION" , "Connection", BASIC_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0}; static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}}; static ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", BASIC_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0}; /* equatorial position */ INumber eq[] = { {"RA", "RA H:M:S", "%10.6m", 0., 24., 0., 0., 0, 0, 0}, {"DEC", "Dec D:M:S", "%10.6m", -90., 90., 0., 0., 0, 0, 0}, }; INumberVectorProperty eqNum = { mydev, "EQUATORIAL_EOD_COORD", "Equatorial JNow", BASIC_GROUP, IP_RO, 0, IPS_IDLE, eq, NARRAY(eq), "", 0}; void ISInit(void) { static int isInit=0; if (isInit) return; isInit = 1; fd = -1; IEAddTimer (POLLMS, ISPoll, NULL); } void ISGetProperties (const char *dev) { ISInit(); dev=dev; IDDefSwitch(&PowerSP, NULL); IDDefText(&PortTP, NULL); IDDefNumber(&eqNum, NULL); } void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); dev = dev; if (!strcmp(name, PowerSP.name)) { IUResetSwitch(&PowerSP); IUUpdateSwitch(&PowerSP, states, names, n); connectTelescope(); return; } } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); dev=dev; names=names; n=n; if (!strcmp(name, PortTP.name)) { IUSaveText(&PortT[0], texts[0]); PortTP.s = IPS_OK; IDSetText(&PortTP, NULL); return; } } void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { dev=dev;name=name;values=values;names=names;n=n; } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } void ISPoll (void *p) { p=p; if (PowerS[0].s == ISS_ON) { switch (eqNum.s) { case IPS_IDLE: case IPS_OK: case IPS_BUSY: if (updateIntelliscopeCoord(fd, ¤tRA, ¤tDEC) < 0) { eqNum.s = IPS_ALERT; IDSetNumber(&eqNum, "Unknown error while reading telescope coordinates"); IDLog("Unknown error while reading telescope coordinates\n"); break; } IDSetNumber(&eqNum, NULL); break; case IPS_ALERT: break; } } IEAddTimer(POLLMS, ISPoll, NULL); } void connectTelescope(void) { switch (PowerS[0].s) { case ISS_ON: if (tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd) != TTY_OK) { PowerSP.s = IPS_ALERT; IUResetSwitch(&PowerSP); IDSetSwitch(&PowerSP, "Error connecting to port %s", PortT[0].text); return; } PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Intelliscope is online."); break; case ISS_OFF: tty_disconnect(fd); IUResetSwitch(&PowerSP); eqNum.s = PortTP.s = PowerSP.s = IPS_IDLE; IDSetSwitch(&PowerSP, "Intelliscope is offline."); IDSetText(&PortTP, NULL); IDSetNumber(&eqNum, NULL); break; } } libindi-0.9.7/drivers/telescope/lx200autostar.h0000644000175000017500000000306612241463551020373 0ustar jasemjasem/* LX200 Autostar Copyright (C) 2003 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef LX200AUTOSTAR_H #define LX200AUTOSTAR_H #include "lx200generic.h" class LX200Autostar : public LX200Generic { public: LX200Autostar(); ~LX200Autostar() {} const char *getDefaultName(); virtual void ISGetProperties (const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual void getBasicData(); protected: virtual bool initProperties(); virtual bool updateProperties(); ITextVectorProperty VersionTP; IText VersionT[5]; INumberVectorProperty FocusSpeedNP; INumber FocusSpeedN[1]; }; #endif libindi-0.9.7/drivers/filter_wheel/0000755000175000017500000000000012241463551016253 5ustar jasemjasemlibindi-0.9.7/drivers/filter_wheel/filter_simulator.h0000644000175000017500000000260012241463551022006 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef FILTERSIM_H #define FILTERSIM_H #include "indibase/indifilterwheel.h" class FilterSim : public INDI::FilterWheel { protected: private: public: FilterSim(); virtual ~FilterSim(); const char *getDefaultName(); bool Connect(); bool Disconnect(); bool SelectFilter(int); void TimerHit(); virtual bool SetFilterNames() { return true; } virtual bool GetFilterNames(const char* groupName); }; #endif // FILTERSIM_H libindi-0.9.7/drivers/filter_wheel/filter_simulator.cpp0000644000175000017500000000717612241463551022356 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "filter_simulator.h" #include // We declare an auto pointer to FilterSim. std::auto_ptr filter_sim(0); void ISPoll(void *p); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(filter_sim.get() == 0) filter_sim.reset(new FilterSim()); //IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { ISInit(); filter_sim->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); filter_sim->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); filter_sim->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); filter_sim->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } FilterSim::FilterSim() { //ctor } FilterSim::~FilterSim() { //dtor } const char *FilterSim::getDefaultName() { return (char *)"Filter Simulator"; } bool FilterSim::Connect() { CurrentFilter=1; FilterSlotN[0].min = 1; FilterSlotN[0].max = 5; return true; } bool FilterSim::Disconnect() { return true; } bool FilterSim::SelectFilter(int f) { CurrentFilter=f; SetTimer(500); return true; } void FilterSim::TimerHit() { SelectFilterDone(CurrentFilter); } bool FilterSim::GetFilterNames(const char* groupName) { char filterName[MAXINDINAME]; char filterLabel[MAXINDILABEL]; int MaxFilter = FilterSlotN[0].max; const char *filterDesignation[5] = { "Red", "Green", "Blue", "H_Alpha", "Luminosity" }; if (FilterNameT != NULL) delete FilterNameT; FilterNameT = new IText[MaxFilter]; for (int i=0; i < MaxFilter; i++) { snprintf(filterName, MAXINDINAME, "FILTER_SLOT_NAME_%d", i+1); snprintf(filterLabel, MAXINDILABEL, "Filter #%d", i+1); IUFillText(&FilterNameT[i], filterName, filterLabel, filterDesignation[i]); } IUFillTextVector(FilterNameTP, FilterNameT, MaxFilter, getDeviceName(), "FILTER_NAME", "Filter", groupName, IP_RW, 0, IPS_IDLE); return true; } libindi-0.9.7/drivers/filter_wheel/fli_wheel.c0000644000175000017500000004134012241463551020357 0ustar jasemjasem#if 0 FLI WHEEL INDI Interface for Finger Lakes Instruments Filter Wheels Copyright (C) 2005 Gaetano Vocca (yagvoc-web AT yahoo DOT it) Based on fli_ccd by Jasem Mutlaq (mutlaqja AT ikarustech DOT com) 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libfli.h" #include "indidevapi.h" #include "eventloop.h" #include "indicom.h" void ISInit(void); void getBasicData(void); void ISPoll(void *); void handleExposure(void *); void connectFilter(void); int findwheel(flidomain_t domain); int manageDefaults(char errmsg[]); int checkPowerS(ISwitchVectorProperty *sp); int checkPowerN(INumberVectorProperty *np); int checkPowerT(ITextVectorProperty *tp); int getOnSwitch(ISwitchVectorProperty *sp); int isFilterConnected(void); double min(void); double max(void); extern char* me; extern int errno; #define mydev "FLI Wheel" #define MAIN_GROUP "Main Control" #define LAST_FILTER 14 /* Max slot index */ #define FIRST_FILTER 0 /* Min slot index */ #define currentFilter FilterN[0].value #define POLLMS 1000 #define LIBVERSIZ 1024 #define PREFIXSIZ 64 #define PIPEBUFSIZ 8192 #define FRAME_ILEN 64 typedef struct { flidomain_t domain; char *dname; char *name; char *model; long HWRevision; long FWRevision; long current_filter; long filter_count; long home; } cam_t; static flidev_t fli_dev; static cam_t *FLIWheel; static int portSwitchIndex; static int simulation; static int targetFilter; long int Domains[] = { FLIDOMAIN_USB, FLIDOMAIN_SERIAL, FLIDOMAIN_PARALLEL_PORT, FLIDOMAIN_INET }; /*INDI controls */ /* Connect/Disconnect */ static ISwitch PowerS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}}; static ISwitchVectorProperty PowerSP = { mydev, "CONNECTION" , "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0}; /* Types of Ports */ static ISwitch PortS[] = {{"USB", "", ISS_ON, 0, 0}, {"Serial", "", ISS_OFF, 0, 0}, {"Parallel", "", ISS_OFF, 0, 0}, {"INet", "", ISS_OFF, 0, 0}}; static ISwitchVectorProperty PortSP = { mydev, "Port Type", "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 0, IPS_IDLE, PortS, NARRAY(PortS), "", 0}; /* Filter control */ static INumber FilterN[] = { {"FILTER_SLOT_VALUE", "Active Filter", "%2.0f", FIRST_FILTER, LAST_FILTER, 1, 0, 0, 0, 0}}; static INumberVectorProperty FilterNP = { mydev, "FILTER_SLOT", "Filter", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FilterN, NARRAY(FilterN), "", 0}; /* send client definitions of all properties */ void ISInit() { static int isInit=0; if (isInit) return; /* USB by default {USB, SERIAL, PARALLEL, INET} */ portSwitchIndex = 0; targetFilter = 0; /* No Simulation by default */ simulation = 0; /* Enable the following for simulation mode */ /*simulation = 1; IDLog("WARNING: Simulation is on\n");*/ IEAddTimer (POLLMS, ISPoll, NULL); isInit = 1; } void ISGetProperties (const char *dev) { ISInit(); if (dev && strcmp (mydev, dev)) return; /* Main Control */ IDDefSwitch(&PowerSP, NULL); IDDefSwitch(&PortSP, NULL); IDDefNumber(&FilterNP, NULL); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { /* ignore if not ours */ if (dev && strcmp (dev, mydev)) return; ISInit(); /* Port type */ if (!strcmp (name, PortSP.name)) { PortSP.s = IPS_IDLE; IUResetSwitch(&PortSP); IUUpdateSwitch(&PortSP, states, names, n); portSwitchIndex = getOnSwitch(&PortSP); PortSP.s = IPS_OK; IDSetSwitch(&PortSP, NULL); return; } /* Connection */ if (!strcmp (name, PowerSP.name)) { IUResetSwitch(&PowerSP); IUUpdateSwitch(&PowerSP, states, names, n); connectFilter(); return; } } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); /* ignore if not ours */ if (dev && strcmp (mydev, dev)) return; /* suppress warning */ n=n; dev=dev; name=name; names=names; texts=texts; } void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { long err; INumber *np; long newFilter; n = n; /* ignore if not ours */ if (dev && strcmp (dev, mydev)) return; ISInit(); if (!strcmp(FilterNP.name, name)) { if (simulation) { targetFilter = values[0]; FilterNP.s = IPS_BUSY; IDSetNumber(&FilterNP, "Setting current filter to slot %d", targetFilter); IDLog("Setting current filter to slot %d\n", targetFilter); return; } if (!isFilterConnected()) { IDMessage(mydev, "Device not connected."); FilterNP.s = IPS_IDLE; IDSetNumber(&FilterNP, NULL); return; } targetFilter = values[0]; np = IUFindNumber(&FilterNP, names[0]); if (!np) { FilterNP.s = IPS_ALERT; IDSetNumber(&FilterNP, "Unknown error. %s is not a member of %s property.", names[0], name); return; } if (targetFilter < FIRST_FILTER || targetFilter > FLIWheel->filter_count - 1) { FilterNP.s = IPS_ALERT; IDSetNumber(&FilterNP, "Error: valid range of filter is from %d to %d", FIRST_FILTER, LAST_FILTER); return; } FilterNP.s = IPS_BUSY; IDSetNumber(&FilterNP, "Setting current filter to slot %d", targetFilter); IDLog("Setting current filter to slot %d\n", targetFilter); if ( (err = FLISetFilterPos(fli_dev, targetFilter))) { FilterNP.s = IPS_ALERT; IDSetNumber(&FilterNP, "FLISetFilterPos() failed. %s.", strerror((int)-err)); IDLog("FLISetFilterPos() failed. %s.", strerror((int)-err)); return; } /* Check current filter position */ if (( err = FLIGetFilterPos(fli_dev, &newFilter))) { FilterNP.s = IPS_ALERT; IDSetNumber(&FilterNP, "FLIGetFilterPos() failed. %s.", strerror((int)-err)); IDLog("FLIGetFilterPos() failed. %s.\n", strerror((int)-err)); return; } if (newFilter == targetFilter) { FLIWheel->current_filter = targetFilter; FilterN[0].value = FLIWheel->current_filter; FilterNP.s = IPS_OK; IDSetNumber(&FilterNP, "Filter set to slot #%d", targetFilter); return; } return; } } /* Retrieves basic data from the Wheel upon connection like temperature, array size, firmware..etc */ void getBasicData() { char buff[2048]; long err; if ((err = FLIGetModel (fli_dev, buff, 2048))) { IDMessage(mydev, "FLIGetModel() failed. %s.", strerror((int)-err)); IDLog("FLIGetModel() failed. %s.\n", strerror((int)-err)); return; } else { if ( (FLIWheel->model = malloc (sizeof(char) * 2048)) == NULL) { IDMessage(mydev, "malloc() failed."); IDLog("malloc() failed."); return; } strcpy(FLIWheel->model, buff); } if (( err = FLIGetHWRevision(fli_dev, &FLIWheel->HWRevision))) { IDMessage(mydev, "FLIGetHWRevision() failed. %s.", strerror((int)-err)); IDLog("FLIGetHWRevision() failed. %s.\n", strerror((int)-err)); return; } if (( err = FLIGetFWRevision(fli_dev, &FLIWheel->FWRevision))) { IDMessage(mydev, "FLIGetFWRevision() failed. %s.", strerror((int)-err)); IDLog("FLIGetFWRevision() failed. %s.\n", strerror((int)-err)); return; } if (( err = FLIGetFilterCount(fli_dev, &FLIWheel->filter_count))) { IDMessage(mydev, "FLIGetFilterCount() failed. %s.", strerror((int)-err)); IDLog("FLIGetFilterCount() failed. %s.\n", strerror((int)-err)); return; } IDLog("The filter count is %ld\n", FLIWheel->filter_count); FilterN[0].max = FLIWheel->filter_count - 1; FilterNP.s = IPS_OK; IUUpdateMinMax(&FilterNP); IDSetNumber(&FilterNP, "Setting basic data"); IDLog("Exiting getBasicData()\n"); } int manageDefaults(char errmsg[]) { long err; /*IDLog("Resetting filter wheel to slot %d\n", 0); FLIWheel->home = 0; if (( err = FLISetFilterPos(fli_dev, 0))) { IDMessage(mydev, "FLISetFilterPos() failed. %s.", strerror((int)-err)); IDLog("FLISetFilterPos() failed. %s.\n", strerror((int)-err)); return (int)-err; }*/ if (( err = FLIGetFilterPos(fli_dev, &FLIWheel->current_filter))) { IDMessage(mydev, "FLIGetFilterPos() failed. %s.", strerror((int)-err)); IDLog("FLIGetFilterPos() failed. %s.\n", strerror((int)-err)); return (int)-err; } IDLog("The current filter is %ld\n", FLIWheel->current_filter); FilterN[0].value = FLIWheel->current_filter; IDSetNumber(&FilterNP, "Storing defaults"); /* Success */ return 0; } void ISPoll(void *p) { static int simMTC = 5; if (!isFilterConnected()) { IEAddTimer (POLLMS, ISPoll, NULL); return; } switch (FilterNP.s) { case IPS_IDLE: case IPS_OK: break; case IPS_BUSY: /* Simulate that it takes 5 seconds to change slot */ if (simulation) { simMTC--; if (simMTC == 0) { simMTC = 5; currentFilter = targetFilter; FilterNP.s = IPS_OK; IDSetNumber(&FilterNP, "Filter set to slot #%2.0f", currentFilter); break; } IDSetNumber(&FilterNP, NULL); break; } /*if (( err = FLIGetFilterPos(fli_dev, ¤tFilter))) { FilterNP.s = IPS_ALERT; IDSetNumber(&FilterNP, "FLIGetFilterPos() failed. %s.", strerror((int)-err)); IDLog("FLIGetFilterPos() failed. %s.\n", strerror((int)-err)); return; } if (targetFilter == currentFilter) { FLIWheel->current_filter = currentFilter; FilterNP.s = IPS_OK; IDSetNumber(&FilterNP, "Filter set to slot #%2.0f", currentFilter); return; } IDSetNumber(&FilterNP, NULL);*/ break; case IPS_ALERT: break; } IEAddTimer (POLLMS, ISPoll, NULL); } int getOnSwitch(ISwitchVectorProperty *sp) { int i=0; for (i=0; i < sp->nsp ; i++) { /*IDLog("Switch %s is %s\n", sp->sp[i].name, sp->sp[i].s == ISS_ON ? "On" : "Off");*/ if (sp->sp[i].s == ISS_ON) return i; } return -1; } int checkPowerS(ISwitchVectorProperty *sp) { if (simulation) return 0; if (PowerSP.s != IPS_OK) { if (!strcmp(sp->label, "")) IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->name); else IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->label); sp->s = IPS_IDLE; IDSetSwitch(sp, NULL); return -1; } return 0; } int checkPowerN(INumberVectorProperty *np) { if (simulation) return 0; if (PowerSP.s != IPS_OK) { if (!strcmp(np->label, "")) IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->name); else IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->label); np->s = IPS_IDLE; IDSetNumber(np, NULL); return -1; } return 0; } int checkPowerT(ITextVectorProperty *tp) { if (simulation) return 0; if (PowerSP.s != IPS_OK) { if (!strcmp(tp->label, "")) IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->name); else IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->label); tp->s = IPS_IDLE; IDSetText(tp, NULL); return -1; } return 0; } void connectFilter() { long err; char errmsg[ERRMSG_SIZE]; /* USB by default {USB, SERIAL, PARALLEL, INET} */ switch (PowerS[0].s) { case ISS_ON: if (simulation) { /* Success! */ PowerS[0].s = ISS_ON; PowerS[1].s = ISS_OFF; PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Simulation Wheel is online."); IDLog("Simulation Wheel is online.\n"); return; } IDLog("Current portSwitch is %d\n", portSwitchIndex); IDLog("Attempting to find the device in domain %ld\n", Domains[portSwitchIndex]); if (findwheel(Domains[portSwitchIndex])) { PowerSP.s = IPS_IDLE; PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; IDSetSwitch(&PowerSP, "Error: no wheels were detected."); IDLog("Error: no wheels were detected.\n"); return; } if ((err = FLIOpen(&fli_dev, FLIWheel->name, FLIWheel->domain | FLIDEVICE_FILTERWHEEL))) { PowerSP.s = IPS_IDLE; PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; IDSetSwitch(&PowerSP, "Error: FLIOpen() failed. %s.", strerror( (int) -err)); IDLog("Error: FLIOpen() failed. %s.\n", strerror( (int) -err)); return; } /* Success! */ PowerS[0].s = ISS_ON; PowerS[1].s = ISS_OFF; PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Wheel is online. Retrieving basic data."); IDLog("Wheel is online. Retrieving basic data.\n"); getBasicData(); if (manageDefaults(errmsg)) { IDMessage(mydev, errmsg, NULL); IDLog("%s", errmsg); return; } break; case ISS_OFF: if (simulation) { PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; PowerSP.s = IPS_IDLE; IDSetSwitch(&PowerSP, "Wheel is offline."); return; } PowerS[0].s = ISS_OFF; PowerS[1].s = ISS_ON; PowerSP.s = IPS_IDLE; if ((err = FLIClose(fli_dev))) { PowerSP.s = IPS_ALERT; IDSetSwitch(&PowerSP, "Error: FLIClose() failed. %s.", strerror( (int) -err)); IDLog("Error: FLIClose() failed. %s.\n", strerror( (int) -err)); return; } IDSetSwitch(&PowerSP, "Wheel is offline."); break; } } /* isFilterConnected: return 1 if we have a connection, 0 otherwise */ int isFilterConnected(void) { if (simulation) return 1; return ((PowerS[0].s == ISS_ON) ? 1 : 0); } int findwheel(flidomain_t domain) { char **devlist; long err; IDLog("In find Camera, the domain is %ld\n", domain); if (( err = FLIList(domain | FLIDEVICE_FILTERWHEEL, &devlist))) { IDLog("FLIList() failed. %s\n", strerror((int)-err)); return -1; } if (devlist != NULL && devlist[0] != NULL) { int i; IDLog("Trying to allocate memory to FLIWheel\n"); if ((FLIWheel = malloc (sizeof (cam_t))) == NULL) { IDLog("malloc() failed.\n"); return -1; } for (i = 0; devlist[i] != NULL; i++) { int j; for (j = 0; devlist[i][j] != '\0'; j++) if (devlist[i][j] == ';') { devlist[i][j] = '\0'; break; } } FLIWheel->domain = domain; /* Each driver handles _only_ one camera for now */ switch (domain) { case FLIDOMAIN_PARALLEL_PORT: FLIWheel->dname = strdup("parallel port"); break; case FLIDOMAIN_USB: FLIWheel->dname = strdup("USB"); break; case FLIDOMAIN_SERIAL: FLIWheel->dname = strdup("serial"); break; case FLIDOMAIN_INET: FLIWheel->dname = strdup("inet"); break; default: FLIWheel->dname = strdup("Unknown domain"); } IDLog("Domain set OK\n"); FLIWheel->name = strdup(devlist[0]); if ((err = FLIFreeList(devlist))) { IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err)); return -1; } } /* end if */ else { if ((err = FLIFreeList(devlist))) { IDLog("FLIFreeList() failed. %s.\n", strerror((int)-err)); return -1; } return -1; } IDLog("Findcam() finished successfully.\n"); return 0; } libindi-0.9.7/drivers/filter_wheel/trutech_wheel.c0000644000175000017500000003010312241463551021256 0ustar jasemjasem#if 0 True Technology Filter Wheel Copyright (C) 2006 Jasem Mutlaq (mutlaqja AT ikarustech DOT com) 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "indidevapi.h" #include "eventloop.h" #include "indicom.h" void ISInit(void); void getBasicData(void); void ISPoll(void *); void handleExposure(void *); void connectFilter(void); int manageDefaults(char errmsg[]); int checkPowerS(ISwitchVectorProperty *sp); int checkPowerN(INumberVectorProperty *np); int checkPowerT(ITextVectorProperty *tp); int getOnSwitch(ISwitchVectorProperty *sp); int isFilterConnected(void); static int targetFilter; static int fd; const unsigned char COMM_PRE = 0x01; const unsigned char COMM_INIT = 0xA5; const unsigned char COMM_FILL = 0x20; #define mydev "TruTech Wheel" #define MAIN_GROUP "Main Control" #define currentFilter FilterPositionN[0].value #define POLLMS 3000 #define DEFAULT_FILTER_COUNT 5 #define MAX_FILTER_COUNT 10 #define ERRMSG_SIZE 1024 #define CMD_SIZE 5 #define CMD_JUNK 64 #define CMD_RESP 15 #define FILTER_TIMEOUT 15 /* 15 Seconds before timeout */ #define FIRST_FILTER 1 #define DEBUG_ON 0 #define SIMULATION_ON 0 /*INDI controls */ /* Connect/Disconnect */ static ISwitch PowerS[] = {{"CONNECT" , "Connect" , ISS_OFF, 0, 0},{"DISCONNECT", "Disconnect", ISS_ON, 0, 0}}; static ISwitchVectorProperty PowerSP = { mydev, "CONNECTION" , "Connection", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, PowerS, NARRAY(PowerS), "", 0}; /* Connection Port */ static IText PortT[] = {{"PORT", "Port", 0, 0, 0, 0}}; static ITextVectorProperty PortTP = { mydev, "DEVICE_PORT", "Ports", MAIN_GROUP, IP_RW, 0, IPS_IDLE, PortT, NARRAY(PortT), "", 0}; /* Home/Learn Swtich */ static ISwitch HomeS[] = {{"Find" , "" , ISS_OFF, 0, 0}}; static ISwitchVectorProperty HomeSP = { mydev, "HOME" , "", MAIN_GROUP, IP_RW, ISR_1OFMANY, 60, IPS_IDLE, HomeS, NARRAY(HomeS), "", 0}; /* Filter Count */ static INumber FilterCountN[] = { {"Count", "", "%2.0f", 0 , MAX_FILTER_COUNT, 1, DEFAULT_FILTER_COUNT, 0, 0, 0}}; static INumberVectorProperty FilterCountNP = { mydev, "Filter Count", "", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FilterCountN, NARRAY(FilterCountN), "", 0}; /* Filter Position */ static INumber FilterPositionN[] = { {"FILTER_SLOT_VALUE", "Active Filter", "%2.0f", 1 , DEFAULT_FILTER_COUNT, 1, 1, 0, 0, 0}}; static INumberVectorProperty FilterPositionNP = { mydev, "FILTER_SLOT", "Filter", MAIN_GROUP, IP_RW, 0, IPS_IDLE, FilterPositionN, NARRAY(FilterPositionN), "", 0}; /* send client definitions of all properties */ void ISInit() { static int isInit=0; if (isInit) return; targetFilter = -1; fd = -1; isInit = 1; } void ISGetProperties (const char *dev) { ISInit(); if (dev && strcmp (mydev, dev)) return; /* Main Control */ IDDefSwitch(&PowerSP, NULL); IDDefText(&PortTP, NULL); IDDefNumber(&FilterCountNP, NULL); IDDefSwitch(&HomeSP, NULL); IDDefNumber(&FilterPositionNP, NULL); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int err; char error_message[ERRMSG_SIZE]; /* ignore if not ours */ if (dev && strcmp (dev, mydev)) return; ISInit(); /* Connection */ if (!strcmp (name, PowerSP.name)) { IUUpdateSwitch(&PowerSP, states, names, n); connectFilter(); return; } /* Home Search */ if (!strcmp (name, HomeSP.name)) { int nbytes=0; unsigned char type = 0x03; unsigned char chksum = COMM_INIT + type + COMM_FILL; unsigned char filter_command[CMD_SIZE]; //snprintf(filter_command, CMD_SIZE, "%c%c%c%c%c", COMM_PRE, COMM_INIT, type, COMM_FILL, chksum); snprintf(filter_command, CMD_SIZE, "%c%c%c%c", COMM_INIT, type, COMM_FILL, chksum); if (checkPowerS(&HomeSP)) return; if (!SIMULATION_ON) err = tty_write(fd, filter_command, CMD_SIZE, &nbytes); if (DEBUG_ON) { IDLog("Home Search Command (int): #%d#%d#%d#%d#\n",COMM_INIT, type, COMM_FILL, chksum); IDLog("Home Search Command (char): #%c#%c#%c#%c#\n",COMM_INIT, type, COMM_FILL, chksum); } /* Send Home Command */ if (err != TTY_OK) { tty_error_msg(err, error_message, ERRMSG_SIZE); HomeSP.s = IPS_ALERT; IDSetSwitch(&HomeSP, "Sending command Home to filter failed. %s", error_message); IDLog("Sending command Home to filter failed. %s\n", error_message); return; } FilterPositionN[0].value = 1; FilterPositionNP.s = IPS_OK; HomeSP.s = IPS_OK; IDSetSwitch(&HomeSP, "Filter set to HOME."); IDSetNumber(&FilterPositionNP, NULL); } } void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); /* ignore if not ours */ if (dev && strcmp (mydev, dev)) return; if (!strcmp(name, PortTP.name)) { if (IUUpdateText(&PortTP, texts, names, n)) return; PortTP.s = IPS_OK; IDSetText(&PortTP, NULL); } } void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { long err; INumber *np; n = n; /* ignore if not ours */ if (dev && strcmp (dev, mydev)) return; ISInit(); if (!strcmp(FilterPositionNP.name, name)) { if (!isFilterConnected()) { IDMessage(mydev, "Filter is not connected."); FilterPositionNP.s = IPS_IDLE; IDSetNumber(&FilterPositionNP, NULL); return; } np = IUFindNumber(&FilterPositionNP, names[0]); if (np == &FilterPositionN[0]) { targetFilter = values[0]; int nbytes=0; unsigned char type = 0x01; unsigned char chksum = COMM_INIT + type + (unsigned char) targetFilter; /*char filter_command[5] = { COMM_PRE, COMM_INIT, type, targetFilter, chksum };*/ unsigned char filter_command[CMD_SIZE]; if (targetFilter < FilterPositionN[0].min || targetFilter > FilterPositionN[0].max) { FilterPositionNP.s = IPS_ALERT; IDSetNumber(&FilterPositionNP, "Error: valid range of filter is from %d to %d", (int) FilterPositionN[0].min, (int) FilterPositionN[0].max); return; } IUUpdateNumber(&FilterPositionNP, values, names, n); //snprintf(filter_command, CMD_SIZE, "%c%c%c%c%c", COMM_PRE, COMM_INIT, type, targetFilter, chksum); snprintf(filter_command, CMD_SIZE, "%c%c%c%c", COMM_INIT, type, targetFilter, chksum); if (DEBUG_ON) { IDLog("Filter Position Command (int): #%d#%d#%d#%d#\n", COMM_INIT, type, targetFilter, chksum); IDLog("Filter Position Command (char): #%c#%c#%c#%c#\n", COMM_INIT, type, targetFilter, chksum); } if (!SIMULATION_ON) err = tty_write(fd, filter_command, CMD_SIZE, &nbytes); FilterPositionNP.s = IPS_OK; IDSetNumber(&FilterPositionNP, "Setting current filter to slot %d", targetFilter); } else { FilterPositionNP.s = IPS_IDLE; IDSetNumber(&FilterPositionNP, NULL); } return; } if (!strcmp(FilterCountNP.name, name)) { if (!isFilterConnected()) { IDMessage(mydev, "Filter is not connected."); FilterCountNP.s = IPS_IDLE; IDSetNumber(&FilterCountNP, NULL); return; } np = IUFindNumber(&FilterCountNP, names[0]); if (np == &FilterCountN[0]) { if (IUUpdateNumber(&FilterCountNP, values, names, n) <0) return; FilterPositionN[0].min = 1; FilterPositionN[0].max = (int) FilterCountN[0].value; IUUpdateMinMax(&FilterPositionNP); FilterCountNP.s = IPS_OK; IDSetNumber(&FilterCountNP, "Updated number of available filters to %d", ((int) FilterCountN[0].value)); } else { FilterCountNP.s = IPS_IDLE; IDSetNumber(&FilterCountNP, NULL); } return; } } int getOnSwitch(ISwitchVectorProperty *sp) { int i=0; for (i=0; i < sp->nsp ; i++) { if (sp->sp[i].s == ISS_ON) return i; } return -1; } int checkPowerS(ISwitchVectorProperty *sp) { if (PowerSP.s != IPS_OK) { if (!strcmp(sp->label, "")) IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->name); else IDMessage (mydev, "Cannot change property %s while the wheel is offline.", sp->label); sp->s = IPS_IDLE; IDSetSwitch(sp, NULL); return -1; } return 0; } int checkPowerN(INumberVectorProperty *np) { if (PowerSP.s != IPS_OK) { if (!strcmp(np->label, "")) IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->name); else IDMessage (mydev, "Cannot change property %s while the wheel is offline.", np->label); np->s = IPS_IDLE; IDSetNumber(np, NULL); return -1; } return 0; } int checkPowerT(ITextVectorProperty *tp) { if (PowerSP.s != IPS_OK) { if (!strcmp(tp->label, "")) IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->name); else IDMessage (mydev, "Cannot change property %s while the wheel is offline.", tp->label); tp->s = IPS_IDLE; IDSetText(tp, NULL); return -1; } return 0; } void connectFilter() { int err; char errmsg[ERRMSG_SIZE]; switch (PowerS[0].s) { case ISS_ON: if (SIMULATION_ON) { PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Simulated Filter Wheel is online."); return; } if ( (err = tty_connect(PortT[0].text, 9600, 8, 0, 1, &fd)) != TTY_OK) { PowerSP.s = IPS_ALERT; IDSetSwitch(&PowerSP, "Error: cannot connect to %s. Make sure the filter is connected and you have access to the port.", PortT[0].text); tty_error_msg(err, errmsg, ERRMSG_SIZE); IDLog("Error: %s\n", errmsg); return; } PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Filter Wheel is online. True Technology filter wheel suffers from several bugs. Please refer to http://indi.sf.net/profiles/trutech.html for more details."); break; case ISS_OFF: if (SIMULATION_ON) { PowerSP.s = IPS_OK; IDSetSwitch(&PowerSP, "Simulated Filter Wheel is offline."); return; } if ( (err = tty_disconnect(fd)) != TTY_OK) { PowerSP.s = IPS_ALERT; IDSetSwitch(&PowerSP, "Error: cannot disconnect."); tty_error_msg(err, errmsg, ERRMSG_SIZE); IDLog("Error: %s\n", errmsg); return; } PowerSP.s = IPS_IDLE; IDSetSwitch(&PowerSP, "Filter Wheel is offline."); break; } } /* isFilterConnected: return 1 if we have a connection, 0 otherwise */ int isFilterConnected(void) { return ((PowerS[0].s == ISS_ON) ? 1 : 0); } libindi-0.9.7/drivers/focuser/0000755000175000017500000000000012241463551015250 5ustar jasemjasemlibindi-0.9.7/drivers/focuser/tcfs.h0000644000175000017500000000662512241463551016371 0ustar jasemjasem/* INDI Driver for Optec TCF-S Focuser Copyright (C) 2010 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef TCFS_H #define TCFS_H #include #include #include #include using namespace std; #define TCFS_MAX_CMD 16 #define TCFS_MAX_TRIES 3 #define TCFS_ERROR_BUFFER 1024 class TCFS : public INDI::DefaultDevice { public: enum TCFSCommand { FMMODE , // Focuser Manual Mode FFMODE, // Focuser Free Mode FAMODE, // Focuser Auto-A Mode FBMODE, // Focuser Auto-B Mode FCENTR, // Focus Center FIN, // Focuser In “nnnn†FOUT, // Focuser Out “nnnn†FPOSRO, // Focuser Position Read Out FTMPRO, // Focuser Temperature Read Out FSLEEP, // Focuser Sleep FWAKUP, // Focuser Wake Up FHOME, // Focuser Home Command }; enum TCFSMode { TCFS_MANUAL_MODE, TCFS_A_MODE, TCFS_B_MODE }; enum TCFSMotion { TCFS_INWARD, TCFS_OUTWARD }; enum TCFSError { NO_ERROR, ER_1, ER_2, ER_3 }; TCFS(); ~TCFS(); virtual bool Connect(); virtual bool Disconnect(); // Standard INDI interface fucntions virtual void ISGetProperties(const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); void ISPoll(); private: ISwitchVectorProperty *ConnectSP; ISwitchVectorProperty *FocusPowerSP; ISwitchVectorProperty *FocusModeSP; INumberVectorProperty *FocusStepNP; INumberVectorProperty *FocusPositionNP; INumberVectorProperty *FocusPositionRequestNP; INumberVectorProperty *FocusTemperatureNP; // Functions void init_properties(); bool move_focuser(TCFSMotion dir); const char *getDefaultName(); bool read_tcfs(); bool dispatch_command(TCFSCommand command); // Variables string default_port; int fd; char command[TCFS_MAX_CMD]; char response[TCFS_MAX_CMD]; unsigned int simulated_position; unsigned int target_position; float simulated_temperature; bool isTCFS3; }; #endif libindi-0.9.7/drivers/focuser/robofocus.cpp0000644000175000017500000011367212241463551017767 0ustar jasemjasem/* RoboFocus Copyright (C) 2006 Markus Wildi (markus.wildi@datacomm.ch) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "robofocus.h" #include "indicom.h" #include #include #include #include #include #define RF_MAX_CMD 9 #define RF_TIMEOUT 15 #define RF_STEP_RES 5 #define RF_MAX_TRIES 3 #define RF_MAX_DELAY 100000 #define BACKLASH_READOUT 99999 #define MAXTRAVEL_READOUT 99999 #define currentSpeed SpeedN[0].value #define currentPosition FocusAbsPosN[0].value #define currentTemperature TemperatureN[0].value #define currentBacklash SetBacklashN[0].value #define currentDuty SettingsN[0].value #define currentDelay SettingsN[1].value #define currentTicks SettingsN[2].value #define currentRelativeMovement FocusRelPosN[0].value #define currentAbsoluteMovement FocusAbsPosN[0].value #define currentSetBacklash SetBacklashN[0].value #define currentMinPosition MinMaxPositionN[0].value #define currentMaxPosition MinMaxPositionN[1].value #define currentMaxTravel MaxTravelN[0].value std::auto_ptr roboFocus(0); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(roboFocus.get() == 0) roboFocus.reset(new RoboFocus()); //IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { ISInit(); roboFocus->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); roboFocus->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); roboFocus->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); roboFocus->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); } RoboFocus::RoboFocus() { } RoboFocus::~RoboFocus() { } bool RoboFocus::initProperties() { INDI::Focuser::initProperties(); // No speed for robofocus FocusSpeedN[0].min = FocusSpeedN[0].max = FocusSpeedN[0].value = 1; IUUpdateMinMax(&FocusSpeedNP); /* Port */ IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyUSB0"); IUFillTextVector(&PortTP, PortT, 1, getDeviceName(), "DEVICE_PORT", "Ports", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE); /* Focuser temperature */ IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", 0, 65000., 0., 10000.); IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE); /* Settings of the Robofocus */ IUFillNumber(&SettingsN[0], "Duty cycle", "Duty cycle", "%6.0f", 0., 255., 0., 1.0); IUFillNumber(&SettingsN[1], "Step Delay", "Step delay", "%6.0f", 0., 255., 0., 1.0); IUFillNumber(&SettingsN[2], "Motor Steps", "Motor steps per tick", "%6.0f", 0., 255., 0., 1.0); IUFillNumberVector(&SettingsNP, SettingsN, 3, getDeviceName(), "FOCUS_SETTINGS", "Settings", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); /* Power Switches of the Robofocus */ IUFillSwitch(&PowerSwitchesS[0], "1", "Switch 1", ISS_OFF); IUFillSwitch(&PowerSwitchesS[1], "2", "Switch 2", ISS_OFF); IUFillSwitch(&PowerSwitchesS[2], "3", "Switch 3", ISS_OFF); IUFillSwitch(&PowerSwitchesS[3], "4", "Switch 4", ISS_ON); IUFillSwitchVector(&PowerSwitchesSP, PowerSwitchesS, 4, getDeviceName(), "SWTICHES", "Power", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); /* Robofocus should stay within these limits */ IUFillNumber(&MinMaxPositionN[0], "MINPOS", "Minimum Tick", "%6.0f", 1., 65000., 0., 100. ); IUFillNumber(&MinMaxPositionN[1], "MAXPOS", "Maximum Tick", "%6.0f", 1., 65000., 0., 55000.); IUFillNumberVector(&MinMaxPositionNP, MinMaxPositionN, 2, getDeviceName(), "FOCUS_MINMAXPOSITION", "Extrema", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); IUFillNumber(&MaxTravelN[0], "MAXTRAVEL", "Maximum travel", "%6.0f", 1., 64000., 0., 10000.); IUFillNumberVector(&MaxTravelNP, MaxTravelN, 1, getDeviceName(), "FOCUS_MAXTRAVEL", "Max. travel", OPTIONS_TAB, IP_RW, 0, IPS_IDLE ); /* Set Robofocus position register to this position */ IUFillNumber(&SetRegisterPositionN[0], "SETPOS", "Position", "%6.0f", 0, 64000., 0., 0. ); IUFillNumberVector(&SetRegisterPositionNP, SetRegisterPositionN, 1, getDeviceName(), "FOCUS_REGISTERPOSITION", "Set register", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); /* Backlash */ IUFillNumber(&SetBacklashN[0], "SETBACKLASH", "Backlash", "%6.0f", -255., 255., 0., 0.); IUFillNumberVector(&SetBacklashNP, SetBacklashN, 1, getDeviceName(), "FOCUS_BACKLASH", "Set Register", OPTIONS_TAB, IP_RW, 0, IPS_IDLE); /* Relative and absolute movement */ FocusRelPosN[0].min = -65000.; FocusRelPosN[0].max = 65000.; FocusRelPosN[0].value = 0; FocusRelPosN[0].step = 100; FocusAbsPosN[0].min = 0.; FocusAbsPosN[0].max = 65000.; FocusAbsPosN[0].value = 0; FocusAbsPosN[0].step = 10000; addDebugControl(); return true; } void RoboFocus::ISGetProperties(const char *dev) { INDI::Focuser::ISGetProperties(dev); defineText(&PortTP); } bool RoboFocus::updateProperties() { INDI::Focuser::updateProperties(); if (isConnected()) { defineNumber(&TemperatureNP); defineSwitch(&PowerSwitchesSP); defineNumber(&SettingsNP); defineNumber(&MinMaxPositionNP); defineNumber(&MaxTravelNP); defineNumber(&SetRegisterPositionNP); defineNumber(&SetBacklashNP); defineNumber(&FocusRelPosNP); defineNumber(&FocusAbsPosNP); GetFocusParams(); IDMessage(getDeviceName(), "RoboFocus paramaters readout complete, focuser ready for use."); } else { deleteProperty(TemperatureNP.name); deleteProperty(SettingsNP.name); deleteProperty(PowerSwitchesSP.name); deleteProperty(MinMaxPositionNP.name); deleteProperty(MaxTravelNP.name); deleteProperty(SetRegisterPositionNP.name); deleteProperty(SetBacklashNP.name); deleteProperty(FocusRelPosNP.name); deleteProperty(FocusAbsPosNP.name); } return true; } bool RoboFocus::Connect() { int connectrc=0; char errorMsg[MAXRBUF]; char firmeware[]="FV0000000"; if (isDebug()) IDLog("connecting to %s\n",PortT[0].text); if ( (connectrc = tty_connect(PortT[0].text, 9600, 8, 0, 1, &PortFD)) != TTY_OK) { tty_error_msg(connectrc, errorMsg, MAXRBUF); if (isDebug()) IDLog("Failed to connect o port %s. Error: %s", PortT[0].text, errorMsg); IDMessage(getDeviceName(), "Failed to connect to port %s. Error: %s", PortT[0].text, errorMsg); return false; } if((updateRFFirmware(firmeware)) < 0) { /* This would be the end*/ IDMessage( getDeviceName(), "Unknown error while reading Robofocus firmware\n"); return false; } IDMessage(getDeviceName(), "Robofocus is online. Getting focus parameters..."); return true; } bool RoboFocus::Disconnect() { tty_disconnect(PortFD); IDMessage(getDeviceName(), "RoboFocus is offline."); return true; } const char * RoboFocus::getDefaultName() { return "RoboFocus"; } unsigned char RoboFocus::CheckSum(char *rf_cmd) { char substr[255] ; unsigned char val= 0 ; int i= 0 ; for(i=0; i < 8; i++) { substr[i]=rf_cmd[i] ; } val = CalculateSum( substr) ; if( val== (unsigned char) rf_cmd[8]) { } else { if (isDebug()) fprintf(stderr, "Wrong (%s,%ld), %x != %x\n", rf_cmd, strlen(rf_cmd), val, (unsigned char) rf_cmd[8]) ; } return val ; } unsigned char RoboFocus::CalculateSum(char *rf_cmd) { unsigned char val= 0 ; int i=0 ; for(i=0; i < 8; i++) { val = val + (unsigned char) rf_cmd[i] ; } return val % 256 ; } int RoboFocus::SendCommand(char *rf_cmd) { int nbytes_written=0, nbytes_read=0, check_ret=0, err_code=0; char rf_cmd_cks[32],robofocus_error[MAXRBUF]; unsigned char val= 0 ; val = CalculateSum( rf_cmd ); for(int i=0; i < 8; i++) { rf_cmd_cks[i]= rf_cmd[i] ; } rf_cmd_cks[8]= (unsigned char) val ; rf_cmd_cks[9]= 0 ; if (isDebug()) { fprintf(stderr, "WRITE: ") ; for(int i=0; i < 9; i++) { fprintf(stderr, "0x%2x ", (unsigned char) rf_cmd_cks[i]) ; } fprintf(stderr, "\n") ; } tcflush(PortFD, TCIOFLUSH); if ( (err_code = tty_write(PortFD, rf_cmd_cks, RF_MAX_CMD, &nbytes_written) != TTY_OK)) { tty_error_msg(err_code, robofocus_error, MAXRBUF); if (isDebug()) IDLog("TTY error detected: %s\n", robofocus_error); return -1; } nbytes_read= ReadResponse(rf_cmd, RF_MAX_CMD, RF_TIMEOUT) ; if (nbytes_read < 1) return nbytes_read; check_ret= CheckSum(rf_cmd) ; rf_cmd[ nbytes_read - 1] = 0 ; if (isDebug()) IDLog("Reply is (%s)\n", rf_cmd); return 0; } int RoboFocus::ReadResponse(char *buf, int nbytes, int timeout) { char robofocus_error[MAXRBUF]; int bytesRead = 0; int totalBytesRead = 0; int err_code; if (isDebug()) IDLog("##########################################\n") ; while (totalBytesRead < nbytes) { //IDLog("Nbytes: %d\n", nbytes); if ( (err_code = tty_read(PortFD, buf+totalBytesRead, nbytes-totalBytesRead, timeout, &bytesRead)) != TTY_OK) { tty_error_msg(err_code, robofocus_error, MAXRBUF); if (isDebug()) { IDLog("TTY error detected: %s\n", robofocus_error); IDMessage(getDeviceName(), "TTY error detected: %s\n", robofocus_error); } return -1; } if (isDebug()) IDLog("Bytes Read: %d\n", bytesRead); if (bytesRead < 0 ) { if (isDebug()) IDLog("Bytesread < 1\n"); return -1; } if(( buf[0]== 'I')|| ( buf[0]== 'O')) { if (isDebug()) IDLog("Moving... with buf[0]=(%c)\n", buf[0]) ; for(int i=0; i < 9; i++) { if (isDebug()) IDLog("buf[%d]=(%c)\n", i, buf[i]); // Catch the F in stream of I's and O's // The robofocus reply might get mixed with the movement strings. For example: // 0x49 0x49 0x49 0x49 0x49 0x46 0x44 0x30 0x32 // The 0x46 above is the START for the rofofocus response string, but it's lost unless we catch it here if (buf[i] == 0x46) { totalBytesRead = bytesRead - i; strncpy(buf, buf+i, totalBytesRead); break; } } usleep(100000) ; } else { //buf += bytesRead; totalBytesRead += bytesRead; //nbytes -= bytesRead; } } tcflush(PortFD, TCIOFLUSH); if (isDebug()) { fprintf(stderr, "READ : (%s,%d), %d\n", buf, 9, totalBytesRead) ; fprintf(stderr, "READ : ") ; for(int i=0; i < 9; i++) { fprintf(stderr, "0x%2x ", (unsigned char)buf[i]) ; } fprintf(stderr, "\n") ; } return 9; } int RoboFocus::updateRFPosition(double *value) { float temp ; char rf_cmd[32] ; int ret_read_tmp ; strcpy(rf_cmd, "FG000000" ) ; if ((ret_read_tmp= SendCommand( rf_cmd)) < 0){ return ret_read_tmp; } if (sscanf(rf_cmd, "FD%6f", &temp) < 1){ return -1; } *value = (double) temp; return 0; } int RoboFocus::updateRFTemperature(double *value) { float temp ; char rf_cmd[32] ; int ret_read_tmp ; strcpy(rf_cmd, "FT000000" ) ; if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; if (sscanf(rf_cmd, "FT%6f", &temp) < 1) return -1; *value = (double) temp/2.- 273.15; return 0; } int RoboFocus::updateRFBacklash(double *value) { float temp ; char rf_cmd[32] ; char vl_tmp[4] ; int ret_read_tmp ; int sign= 0 ; if(*value== BACKLASH_READOUT) { strcpy(rf_cmd, "FB000000" ) ; } else { rf_cmd[0]= 'F' ; rf_cmd[1]= 'B' ; if( *value > 0) { rf_cmd[2]= '3' ; } else { *value= - *value ; rf_cmd[2]= '2' ; } rf_cmd[3]= '0' ; rf_cmd[4]= '0' ; if(*value > 99) { sprintf( vl_tmp, "%3d", (int) *value) ; } else if(*value > 9) { sprintf( vl_tmp, "0%2d", (int) *value) ; } else { sprintf( vl_tmp, "00%1d", (int) *value) ; } rf_cmd[5]= vl_tmp[0] ; rf_cmd[6]= vl_tmp[1] ; rf_cmd[7]= vl_tmp[2] ; } if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; if (sscanf(rf_cmd, "FB%1d%5f", &sign, &temp) < 1) return -1; *value = (double) temp ; if(( sign== 2) && ( *value > 0)) { *value = - (*value) ; } return 0; } int RoboFocus::updateRFFirmware(char *rf_cmd) { int ret_read_tmp ; strcpy(rf_cmd, "FV000000" ) ; if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; return 0; } int RoboFocus::updateRFMotorSettings(double *duty, double *delay, double *ticks) { char rf_cmd[32] ; int ret_read_tmp ; if(( *duty== 0 ) && (*delay== 0) && (*ticks== 0) ){ strcpy(rf_cmd, "FC000000" ) ; } else { rf_cmd[0]= 'F' ; rf_cmd[1]= 'C' ; rf_cmd[2]= (char) *duty ; rf_cmd[3]= (char) *delay ; rf_cmd[4]= (char) *ticks ; rf_cmd[5]= '0' ; rf_cmd[6]= '0' ; rf_cmd[7]= '0' ; rf_cmd[8]= 0 ; } if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; *duty= (float) rf_cmd[2] ; *delay= (float) rf_cmd[3] ; *ticks= (float) rf_cmd[4] ; return 0; } int RoboFocus::updateRFPositionRelativeInward(double *value) { char rf_cmd[32] ; int ret_read_tmp ; float temp ; rf_cmd[0]= 0 ; if(*value > 9999) { sprintf( rf_cmd, "FI0%5d", (int) *value) ; } else if(*value > 999) { sprintf( rf_cmd, "FI00%4d", (int) *value) ; } else if(*value > 99) { sprintf( rf_cmd, "FI000%3d", (int) *value) ; } else if(*value > 9) { sprintf( rf_cmd, "FI0000%2d", (int) *value) ; } else { sprintf( rf_cmd, "FI00000%1d", (int) *value) ; } if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; if (sscanf(rf_cmd, "FD0%5f", &temp) < 1) return -1; *value = (double) temp ; return 0; } int RoboFocus::updateRFPositionRelativeOutward(double *value) { char rf_cmd[32] ; int ret_read_tmp ; float temp ; rf_cmd[0]= 0 ; if(*value > 9999) { sprintf( rf_cmd, "FO0%5d", (int) *value) ; } else if(*value > 999) { sprintf( rf_cmd, "FO00%4d", (int) *value) ; } else if(*value > 99) { sprintf( rf_cmd, "FO000%3d", (int) *value) ; } else if(*value > 9) { sprintf( rf_cmd, "FO0000%2d", (int) *value) ; } else { sprintf( rf_cmd, "FO00000%1d", (int) *value) ; } if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; if (sscanf(rf_cmd, "FD0%5f", &temp) < 1) return -1; *value = (double) temp ; return 0; } int RoboFocus::updateRFPositionAbsolute(double *value) { char rf_cmd[32] ; int ret_read_tmp ; float temp ; rf_cmd[0]= 0 ; if(*value > 9999) { sprintf( rf_cmd, "FG0%5d", (int) *value) ; } else if(*value > 999) { sprintf( rf_cmd, "FG00%4d", (int) *value) ; } else if(*value > 99) { sprintf( rf_cmd, "FG000%3d", (int) *value) ; } else if(*value > 9) { sprintf( rf_cmd, "FG0000%2d", (int) *value) ; } else { sprintf( rf_cmd, "FG00000%1d", (int) *value) ; } if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; if (sscanf(rf_cmd, "FD0%5f", &temp) < 1) return -1; *value = (double) temp ; return 0; } int RoboFocus::updateRFPowerSwitches(int s, int new_sn, int *cur_s1LL, int *cur_s2LR, int *cur_s3RL, int *cur_s4RR) { char rf_cmd[32] ; char rf_cmd_tmp[32] ; int ret_read_tmp ; int i = 0 ; /* Get first the status */ strcpy(rf_cmd_tmp, "FP000000" ) ; if ((ret_read_tmp= SendCommand( rf_cmd_tmp)) < 0) return ret_read_tmp ; for(i= 0; i < 9; i++) { rf_cmd[i]= rf_cmd_tmp[i] ; } if( rf_cmd[new_sn + 4]== '2') { rf_cmd[new_sn + 4]= '1' ; } else { rf_cmd[new_sn + 4]= '2' ; } /* if( s== ISS_ON) { */ /* rf_cmd[new_sn + 4]= '2' ; */ /* } else { */ /* rf_cmd[new_sn + 4]= '1' ; */ /* } */ rf_cmd[8]= 0 ; if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp ; *cur_s1LL= *cur_s2LR= *cur_s3RL= *cur_s4RR= ISS_OFF ; if(rf_cmd[4]== '2' ) { *cur_s1LL= ISS_ON ; } if(rf_cmd[5]== '2' ) { *cur_s2LR= ISS_ON ; } if(rf_cmd[6]== '2' ) { *cur_s3RL= ISS_ON ; } if(rf_cmd[7]== '2' ) { *cur_s4RR= ISS_ON ; } return 0 ; } int RoboFocus::updateRFMaxPosition(double *value) { float temp ; char rf_cmd[32] ; char vl_tmp[6] ; int ret_read_tmp ; char waste[1] ; if(*value== MAXTRAVEL_READOUT) { strcpy(rf_cmd, "FL000000" ) ; } else { rf_cmd[0]= 'F' ; rf_cmd[1]= 'L' ; rf_cmd[2]= '0' ; if(*value > 9999) { sprintf( vl_tmp, "%5d", (int) *value) ; } else if(*value > 999) { sprintf( vl_tmp, "0%4d", (int) *value) ; } else if(*value > 99) { sprintf( vl_tmp, "00%3d", (int) *value) ; } else if(*value > 9) { sprintf( vl_tmp, "000%2d", (int) *value) ; } else { sprintf( vl_tmp, "0000%1d", (int) *value) ; } rf_cmd[3]= vl_tmp[0] ; rf_cmd[4]= vl_tmp[1] ; rf_cmd[5]= vl_tmp[2] ; rf_cmd[6]= vl_tmp[3] ; rf_cmd[7]= vl_tmp[4] ; rf_cmd[8]= 0 ; } if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; if (sscanf(rf_cmd, "FL%1c%5f", waste, &temp) < 1) return -1; *value = (double) temp ; return 0; } int RoboFocus::updateRFSetPosition(double *value) { char rf_cmd[32] ; char vl_tmp[6] ; int ret_read_tmp ; rf_cmd[0]= 'F' ; rf_cmd[1]= 'S' ; rf_cmd[2]= '0' ; if(*value > 9999) { sprintf( vl_tmp, "%5d", (int) *value) ; } else if(*value > 999) { sprintf( vl_tmp, "0%4d", (int) *value) ; } else if(*value > 99) { sprintf( vl_tmp, "00%3d", (int) *value) ; } else if(*value > 9) { sprintf( vl_tmp, "000%2d", (int) *value) ; } else { sprintf( vl_tmp, "0000%1d", (int) *value) ; } rf_cmd[3]= vl_tmp[0] ; rf_cmd[4]= vl_tmp[1] ; rf_cmd[5]= vl_tmp[2] ; rf_cmd[6]= vl_tmp[3] ; rf_cmd[7]= vl_tmp[4] ; rf_cmd[8]= 0 ; if ((ret_read_tmp= SendCommand( rf_cmd)) < 0) return ret_read_tmp; return 0; } bool RoboFocus::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { // =================================== // Port Name // =================================== if (!strcmp(name, PortTP.name) ) { if (IUUpdateText(&PortTP, texts, names, n) < 0) return false; PortTP.s = IPS_OK; IDSetText (&PortTP, NULL); return true; } } return INDI::Focuser::ISNewText(dev, name, texts, names, n); } bool RoboFocus::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if (!strcmp (name, PowerSwitchesSP.name)) { int ret= -1 ; int nset= 0 ; int i= 0 ; int new_s= -1 ; int new_sn= -1 ; int cur_s1LL=0 ; int cur_s2LR=0 ; int cur_s3RL=0 ; int cur_s4RR=0 ; ISwitch *sp ; PowerSwitchesSP.s = IPS_BUSY ; IDSetSwitch(&PowerSwitchesSP, NULL) ; for( nset = i = 0; i < n; i++) { /* Find numbers with the passed names in the SettingsNP property */ sp = IUFindSwitch (&PowerSwitchesSP, names[i]) ; /* If the state found is (PowerSwitchesS[0]) then process it */ if( sp == &PowerSwitchesS[0]){ new_s = (states[i]) ; new_sn= 0; nset++ ; } else if( sp == &PowerSwitchesS[1]){ new_s = (states[i]) ; new_sn= 1; nset++ ; } else if( sp == &PowerSwitchesS[2]){ new_s = (states[i]) ; new_sn= 2; nset++ ; } else if( sp == &PowerSwitchesS[3]){ new_s = (states[i]) ; new_sn= 3; nset++ ; } } if (nset == 1) { cur_s1LL= cur_s2LR= cur_s3RL= cur_s4RR= 0 ; if(( ret= updateRFPowerSwitches(new_s, new_sn, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0) { PowerSwitchesSP.s = IPS_ALERT; IDSetSwitch(&PowerSwitchesSP, "Unknown error while reading Robofocus power swicht settings"); return true; } } else { /* Set property state to idle */ PowerSwitchesSP.s = IPS_IDLE ; IDSetNumber(&SettingsNP, "Power switch settings absent or bogus."); return true ; } } } return INDI::Focuser::ISNewSwitch(dev, name, states, names, n); } bool RoboFocus::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { int nset=0,i=0; if(strcmp(dev,getDeviceName())==0) { if (!strcmp (name, SettingsNP.name)) { /* new speed */ double new_duty = 0 ; double new_delay = 0 ; double new_ticks = 0 ; int ret = -1 ; for (nset = i = 0; i < n; i++) { /* Find numbers with the passed names in the SettingsNP property */ INumber *eqp = IUFindNumber (&SettingsNP, names[i]); /* If the number found is (SettingsN[0]) then process it */ if (eqp == &SettingsN[0]) { new_duty = (values[i]); nset += new_duty >= 0 && new_duty <= 255; } else if (eqp == &SettingsN[1]) { new_delay = (values[i]); nset += new_delay >= 0 && new_delay <= 255; } else if (eqp == &SettingsN[2]) { new_ticks = (values[i]); nset += new_ticks >= 0 && new_ticks <= 255; } } /* Did we process the three numbers? */ if (nset == 3) { /* Set the robofocus state to BUSY */ SettingsNP.s = IPS_BUSY; IDSetNumber(&SettingsNP, NULL); if(( ret= updateRFMotorSettings(&new_duty, &new_delay, &new_ticks))< 0) { IDSetNumber(&SettingsNP, "Changing to new settings failed"); return false; } currentDuty = new_duty ; currentDelay= new_delay ; currentTicks= new_ticks ; SettingsNP.s = IPS_OK; IDSetNumber(&SettingsNP, "Motor settings are now %3.0f %3.0f %3.0f", currentDuty, currentDelay, currentTicks); return true; } else { /* Set property state to idle */ SettingsNP.s = IPS_IDLE; IDSetNumber(&SettingsNP, "Settings absent or bogus."); return false ; } } if (!strcmp (name, SetBacklashNP.name)) { double new_back = 0 ; int nset = 0; int ret= -1 ; for (nset = i = 0; i < n; i++) { /* Find numbers with the passed names in the SetBacklashNP property */ INumber *eqp = IUFindNumber (&SetBacklashNP, names[i]); /* If the number found is SetBacklash (SetBacklashN[0]) then process it */ if (eqp == &SetBacklashN[0]){ new_back = (values[i]); /* limits */ nset += new_back >= -0xff && new_back <= 0xff; } if (nset == 1) { /* Set the robofocus state to BUSY */ SetBacklashNP.s = IPS_BUSY; IDSetNumber(&SetBacklashNP, NULL); if(( ret= updateRFBacklash(&new_back)) < 0) { SetBacklashNP.s = IPS_IDLE; IDSetNumber(&SetBacklashNP, "Setting new backlash failed."); return false ; } currentSetBacklash= new_back ; SetBacklashNP.s = IPS_OK; IDSetNumber(&SetBacklashNP, "Backlash is now %3.0f", currentSetBacklash) ; return true; } else { SetBacklashNP.s = IPS_IDLE; IDSetNumber(&SetBacklashNP, "Need exactly one parameter."); return false ; } } } if (!strcmp (name, MinMaxPositionNP.name)) { /* new positions */ double new_min = 0 ; double new_max = 0 ; for (nset = i = 0; i < n; i++) { /* Find numbers with the passed names in the MinMaxPositionNP property */ INumber *mmpp = IUFindNumber (&MinMaxPositionNP, names[i]); /* If the number found is (MinMaxPositionN[0]) then process it */ if (mmpp == &MinMaxPositionN[0]) { new_min = (values[i]); nset += new_min >= 1 && new_min <= 65000; } else if (mmpp == &MinMaxPositionN[1]) { new_max = (values[i]); nset += new_max >= 1 && new_max <= 65000; } } /* Did we process the two numbers? */ if (nset == 2) { /* Set the robofocus state to BUSY */ MinMaxPositionNP.s = IPS_BUSY; currentMinPosition = new_min ; currentMaxPosition= new_max ; MinMaxPositionNP.s = IPS_OK; IDSetNumber(&MinMaxPositionNP, "Minimum and Maximum settings are now %3.0f %3.0f", currentMinPosition, currentMaxPosition); return true; } else { /* Set property state to idle */ MinMaxPositionNP.s = IPS_IDLE; IDSetNumber(&MinMaxPositionNP, "Minimum and maximum limits absent or bogus."); return false; } } if (!strcmp (name, MaxTravelNP.name)) { double new_maxt = 0 ; int ret = -1 ; for (nset = i = 0; i < n; i++) { /* Find numbers with the passed names in the MinMaxPositionNP property */ INumber *mmpp = IUFindNumber (&MaxTravelNP, names[i]); /* If the number found is (MaxTravelN[0]) then process it */ if (mmpp == &MaxTravelN[0]) { new_maxt = (values[i]); nset += new_maxt >= 1 && new_maxt <= 64000; } } /* Did we process the one number? */ if (nset == 1) { IDSetNumber(&MinMaxPositionNP, NULL); if(( ret= updateRFMaxPosition(&new_maxt))< 0 ) { MaxTravelNP.s = IPS_IDLE; IDSetNumber(&MaxTravelNP, "Changing to new maximum travel failed"); return false ; } currentMaxTravel= new_maxt ; MaxTravelNP.s = IPS_OK; IDSetNumber(&MaxTravelNP, "Maximum travel is now %3.0f", currentMaxTravel) ; return true; } else { /* Set property state to idle */ MaxTravelNP.s = IPS_IDLE; IDSetNumber(&MaxTravelNP, "Maximum travel absent or bogus."); return false ; } } if (!strcmp (name, SetRegisterPositionNP.name)) { double new_apos = 0 ; int nset = 0; int ret= -1 ; for (nset = i = 0; i < n; i++) { /* Find numbers with the passed names in the SetRegisterPositionNP property */ INumber *srpp = IUFindNumber (&SetRegisterPositionNP, names[i]); /* If the number found is SetRegisterPosition (SetRegisterPositionN[0]) then process it */ if (srpp == &SetRegisterPositionN[0]) { new_apos = (values[i]); /* limits are absolute */ nset += new_apos >= 0 && new_apos <= 64000; } if (nset == 1) { if((new_apos < currentMinPosition) || (new_apos > currentMaxPosition)) { SetRegisterPositionNP.s = IPS_ALERT ; IDSetNumber(&SetRegisterPositionNP, "Value out of limits %5.0f", new_apos); return false ; } /* Set the robofocus state to BUSY */ SetRegisterPositionNP.s = IPS_BUSY; IDSetNumber(&SetRegisterPositionNP, NULL); if(( ret= updateRFSetPosition(&new_apos)) < 0) { SetRegisterPositionNP.s = IPS_OK; IDSetNumber(&SetRegisterPositionNP, "Read out of the set position to %3d failed. Trying to recover the position", ret); if((ret= updateRFPosition( ¤tPosition)) < 0) { FocusAbsPosNP.s = IPS_ALERT; IDSetNumber(&FocusAbsPosNP, "Unknown error while reading Robofocus position: %d", ret); SetRegisterPositionNP.s = IPS_IDLE; IDSetNumber(&SetRegisterPositionNP, "Relative movement failed."); } SetRegisterPositionNP.s = IPS_OK; IDSetNumber(&SetRegisterPositionNP, NULL); FocusAbsPosNP.s = IPS_OK; IDSetNumber(&FocusAbsPosNP, "Robofocus position recovered %5.0f", currentPosition); IDMessage( getDeviceName(), "Robofocus position recovered resuming normal operation"); /* We have to leave here, because new_apos is not set */ return true ; } currentPosition= new_apos ; SetRegisterPositionNP.s = IPS_OK; IDSetNumber(&SetRegisterPositionNP, "Robofocus register set to %5.0f", currentPosition); FocusAbsPosNP.s = IPS_OK; IDSetNumber(&FocusAbsPosNP, "Robofocus position is now %5.0f", currentPosition); return true ; } else { SetRegisterPositionNP.s = IPS_IDLE; IDSetNumber(&SetRegisterPositionNP, "Need exactly one parameter."); return false; } if((ret= updateRFPosition(¤tPosition)) < 0) { FocusAbsPosNP.s = IPS_ALERT; IDSetNumber(&FocusAbsPosNP, "Unknown error while reading Robofocus position: %d", ret); return false ; } SetRegisterPositionNP.s = IPS_OK; IDSetNumber(&SetRegisterPositionNP, "Robofocus has accepted new register setting" ) ; FocusAbsPosNP.s = IPS_OK; IDSetNumber(&FocusAbsPosNP, "Robofocus new position %5.0f", currentPosition); return true; } } } return INDI::Focuser::ISNewNumber(dev, name, values, names, n); } void RoboFocus::GetFocusParams () { int ret = -1 ; int cur_s1LL=0 ; int cur_s2LR=0 ; int cur_s3RL=0 ; int cur_s4RR=0 ; if((ret= updateRFPosition(¤tPosition)) < 0) { FocusAbsPosNP.s = IPS_ALERT; IDSetNumber(&FocusAbsPosNP, "Unknown error while reading Robofocus position: %d", ret); return; } FocusAbsPosNP.s = IPS_OK; IDSetNumber(&FocusAbsPosNP, NULL); FocusAbsPosN[0].value = currentPosition; IDSetNumber(&FocusAbsPosNP, NULL); if(( ret= updateRFTemperature(¤tTemperature)) < 0) { TemperatureNP.s = IPS_ALERT; IDSetNumber(&TemperatureNP, "Unknown error while reading Robofocus temperature"); return; } TemperatureNP.s = IPS_OK; IDSetNumber(&TemperatureNP, NULL); currentBacklash= BACKLASH_READOUT ; if(( ret= updateRFBacklash(¤tBacklash)) < 0) { SetBacklashNP.s = IPS_ALERT; IDSetNumber(&SetBacklashNP, "Unknown error while reading Robofocus backlash"); return; } SetBacklashNP.s = IPS_OK; IDSetNumber(&SetBacklashNP, NULL); currentDuty= currentDelay= currentTicks=0 ; if(( ret= updateRFMotorSettings(¤tDuty, ¤tDelay, ¤tTicks )) < 0) { SettingsNP.s = IPS_ALERT; IDSetNumber(&SettingsNP, "Unknown error while reading Robofocus motor settings"); return; } SettingsNP.s = IPS_OK; IDSetNumber(&SettingsNP, NULL); if(( ret= updateRFPowerSwitches(-1, -1, &cur_s1LL, &cur_s2LR, &cur_s3RL, &cur_s4RR)) < 0) { PowerSwitchesSP.s = IPS_ALERT; IDSetSwitch(&PowerSwitchesSP, "Unknown error while reading Robofocus power swicht settings"); return; } PowerSwitchesS[0].s= PowerSwitchesS[1].s= PowerSwitchesS[2].s= PowerSwitchesS[3].s= ISS_OFF ; if(cur_s1LL== ISS_ON) { PowerSwitchesS[0].s= ISS_ON ; } if(cur_s2LR== ISS_ON) { PowerSwitchesS[1].s= ISS_ON ; } if(cur_s3RL== ISS_ON) { PowerSwitchesS[2].s= ISS_ON ; } if(cur_s4RR== ISS_ON) { PowerSwitchesS[3].s= ISS_ON ; } PowerSwitchesSP.s = IPS_OK ; IDSetSwitch(&PowerSwitchesSP, NULL); currentMaxTravel= MAXTRAVEL_READOUT ; if(( ret= updateRFMaxPosition(¤tMaxTravel)) < 0) { MaxTravelNP.s = IPS_ALERT; IDSetNumber(&MaxTravelNP, "Unknown error while reading Robofocus maximum travel"); return; } MaxTravelNP.s = IPS_OK; IDSetNumber(&MaxTravelNP, NULL); } bool RoboFocus::Move(FocusDirection dir, int speed, int duration) { INDI_UNUSED(speed); double pos=0; struct timeval tv_start; struct timeval tv_finish; double dt=0; gettimeofday (&tv_start, NULL); while (duration > 0) { pos = RF_STEP_RES; if (dir == FOCUS_INWARD) updateRFPositionRelativeInward(&pos); else updateRFPositionRelativeOutward(&pos); gettimeofday (&tv_finish, NULL); dt = tv_finish.tv_sec - tv_start.tv_sec + (tv_finish.tv_usec - tv_start.tv_usec)/1e6; duration -= dt * 1000; // IDLog("dt is: %g --- duration is: %d -- pos: %g\n", dt, duration, pos); } return true; } int RoboFocus::MoveAbs(int targetTicks) { int ret= -1 ; double new_apos = targetTicks; if (targetTicks < FocusAbsPosN[0].min || targetTicks > FocusAbsPosN[0].max) { IDMessage(getDeviceName(), "Error, requested absolute position is out of range."); return -1; } IDMessage(getDeviceName() , "Focuser is moving to requested position..."); if(( ret= updateRFPositionAbsolute(&new_apos)) < 0) { IDMessage(getDeviceName(), "Read out of the absolute movement failed %3d, trying to recover position.", ret); for (int i=0;; i++) { if((ret= updateRFPosition(¤tPosition)) < 0) { IDMessage(getDeviceName(),"Unknown error while reading Robofocus position: %d.", ret); if (i == RF_MAX_TRIES) return false; else usleep(RF_MAX_DELAY); } else break; } IDMessage( getDeviceName(), "Robofocus position recovered resuming normal operation"); /* We have to leave here, because new_apos is not set */ return -1; } return 0; } int RoboFocus::MoveRel(FocusDirection dir, unsigned int ticks) { double cur_rpos=0 ; double new_rpos = 0 ; int ret=0; bool nset = false; cur_rpos= new_rpos = ticks; /* CHECK 2006-01-26, limits are relative to the actual position */ nset = new_rpos >= -0xffff && new_rpos <= 0xffff; if (nset) { if((currentPosition + new_rpos < currentMinPosition) || (currentPosition + new_rpos > currentMaxPosition)) { IDMessage(getDeviceName(), "Value out of limits %5.0f", currentPosition + new_rpos); return -1 ; } if( dir == FOCUS_OUTWARD) ret= updateRFPositionRelativeOutward(&new_rpos) ; else ret= updateRFPositionRelativeInward(&new_rpos) ; if( ret < 0) { IDMessage(getDeviceName(), "Read out of the relative movement failed, trying to recover position."); if((ret= updateRFPosition(¤tPosition)) < 0) { IDMessage(getDeviceName(), "Unknown error while reading Robofocus position: %d", ret); return false; } IDMessage(getDeviceName(), "Robofocus position recovered %5.0f", currentPosition); // We have to leave here, because new_rpos is not set return -1 ; } currentRelativeMovement= cur_rpos ; currentAbsoluteMovement= new_rpos; return 0; } { IDMessage(getDeviceName(), "Value out of limits."); return -1; } } bool RoboFocus::saveConfigItems(FILE *fp) { IUSaveConfigText(fp, &PortTP); IUSaveConfigNumber(fp, &SettingsNP); IUSaveConfigNumber(fp, &SetBacklashNP); } libindi-0.9.7/drivers/focuser/tcfs.cpp0000644000175000017500000006067112241463551016725 0ustar jasemjasem/* INDI Driver for Optec TCF-S Focuser Copyright (C) 2010 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tcfs.h" #define mydev "Optec TCF-S" #define nFocusSteps FocusStepNP->np[0].value #define nFocusCurrentPosition FocusPositionNP->np[0].value #define nFocusTargetPosition FocusPositionRequestNP->np[0].value #define nFocusTemperature FocusTemperatureNP->np[0].value #define isFocusSleep (FocusPowerSP->sp[0].s == ISS_ON) const int POLLMS = 1000; // We declare an auto pointer to TCFS. auto_ptr tcfs(0); void ISPoll(void *p); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(tcfs.get() == 0) tcfs.reset(new TCFS()); IEAddTimer(POLLMS, ISPoll, NULL); } void ISPoll(void *p) { tcfs->ISPoll(); IEAddTimer(POLLMS, ISPoll, NULL); } void ISGetProperties(const char *dev) { if(dev && strcmp(mydev, dev)) return; ISInit(); tcfs->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { if(dev && strcmp (mydev, dev)) return; ISInit(); tcfs->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { if(dev && strcmp (mydev, dev)) return; ISInit(); tcfs->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { if(dev && strcmp (mydev, dev)) return; ISInit(); tcfs->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } /**************************************************************** ** ** *****************************************************************/ TCFS::TCFS() { const char *skelFileName = "/usr/share/indi/indi_tcfs_sk.xml"; struct stat st; char *skel = getenv("INDISKEL"); if (skel) buildSkeleton(skel); else if (stat(skelFileName,&st) == 0) buildSkeleton(skelFileName); else IDLog("No skeleton file was specified. Set environment variable INDISKEL to the skeleton path and try again.\n"); // Optional: Add aux controls for configuration, debug & simulation addAuxControls(); simulated_position = 3000; simulated_temperature = 25.4; } /**************************************************************** ** ** *****************************************************************/ TCFS::~TCFS() { } /**************************************************************** ** ** *****************************************************************/ void TCFS::ISGetProperties(const char *dev) { static int propInit=0; INDI::DefaultDevice::ISGetProperties(dev); if (propInit == 0) { init_properties(); loadConfig(); isTCFS3 = false; // Set upper limit for TCF-S3 focuser if (!strcmp(me, "indi_tcfs3_focus")) { isTCFS3 = true; FocusPositionRequestNP->np[0].max = 9999; IUUpdateMinMax(FocusPositionRequestNP); if (isDebug()) IDLog("TCF-S3 detected. Updating maximum position value to 9999.\n"); } propInit = 1; } } /**************************************************************** ** ** *****************************************************************/ void TCFS::init_properties() { ConnectSP = getSwitch("CONNECTION"); FocusStepNP = getNumber("FOCUS_STEP"); FocusPositionNP = getNumber("FOCUS_POSITION"); FocusPositionRequestNP = getNumber("FOCUS_POSITION_REQUEST"); FocusTemperatureNP = getNumber("FOCUS_TEMPERATURE"); FocusPowerSP = getSwitch("FOCUS_POWER"); FocusModeSP = getSwitch("FOCUS_MODE"); } /**************************************************************** ** ** *****************************************************************/ bool TCFS::Connect() { ITextVectorProperty *tProp = getText("DEVICE_PORT"); if (isConnected()) return true; if (tProp == NULL) return false; if (isSimulation()) { setConnected(true); IDSetSwitch(ConnectSP, "TCF-S: Simulating connection to port %s.", tProp->tp[0].text); fd=-1; IUResetSwitch(FocusModeSP); FocusModeSP->sp[0].s = ISS_ON; FocusModeSP->s = IPS_OK; IDSetSwitch(FocusModeSP, NULL); FocusPositionNP->s = IPS_OK; IDSetNumber(FocusPositionNP, NULL); FocusTemperatureNP->s = IPS_OK; IDSetNumber(FocusTemperatureNP, NULL); IUResetSwitch(FocusPowerSP); IDSetSwitch(FocusPowerSP, NULL); return true; } if (isDebug()) IDLog("Attempting to connect to TCF-S focuser....\n"); if (tty_connect(tProp->tp[0].text, 19200, 8, 0, 1, &fd) != TTY_OK) { IDMessage(getDeviceName(), "Error connecting to port %s. Make sure you have BOTH read and write permission to the port.", tProp->tp[0].text); return false; } IDMessage(getDeviceName(), "Successfully connected to TCF-S Focuser in Manual Mode."); IUResetSwitch(FocusModeSP); FocusModeSP->sp[0].s = ISS_ON; FocusModeSP->s = IPS_OK; IDSetSwitch(FocusModeSP, NULL); FocusPositionNP->s = IPS_OK; IDSetNumber(FocusPositionNP, NULL); FocusTemperatureNP->s = IPS_OK; IDSetNumber(FocusTemperatureNP, NULL); IUResetSwitch(FocusPowerSP); IDSetSwitch(FocusPowerSP, NULL); return true; } /**************************************************************** ** ** *****************************************************************/ bool TCFS::Disconnect() { FocusPositionNP->s = IPS_IDLE; IDSetNumber(FocusPositionNP, NULL); FocusTemperatureNP->s = IPS_IDLE; IDSetNumber(FocusTemperatureNP, NULL); dispatch_command(FFMODE); tty_disconnect(fd); setConnected(false, IPS_OK, "Disconnected from TCF-S."); return true; } /**************************************************************** ** ** *****************************************************************/ bool TCFS::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { INumberVectorProperty *nProp = getNumber(name); if (nProp == NULL) return false; if (isConnected() == false) { resetProperties(); IDMessage(getDeviceName(), "TCF-S is offline. Connect before issiuing any commands."); return false; } if (!strcmp(nProp->name, "FOCUS_STEP")) { IUUpdateNumber(nProp, values, names, n); nProp->s = IPS_OK; IDSetNumber(nProp, NULL); return true; } if (isFocusSleep) { nProp->s = IPS_IDLE; IDSetNumber(nProp, "Focuser is still in sleep mode. Wake up in order to issue commands."); return true; } if (!strcmp(nProp->name, "FOCUS_POSITION_REQUEST")) { int current_step = nFocusSteps; IUUpdateNumber(nProp, values, names, n); nFocusSteps = fabs(nFocusTargetPosition - nFocusCurrentPosition); if ( (nFocusTargetPosition - nFocusCurrentPosition) > 0) move_focuser(TCFS_OUTWARD); else move_focuser(TCFS_INWARD); nFocusSteps = current_step; FocusPositionNP->s = IPS_BUSY; nProp->s = IPS_BUSY; IDSetNumber(nProp, "Moving focuser to new position %g...", nFocusTargetPosition); return true; } return DefaultDevice::ISNewNumber (dev, name, values, names, n); } /**************************************************************** ** ** *****************************************************************/ bool TCFS::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ITextVectorProperty * tProp = getText(name); if (tProp == NULL) return false; // Device Port Text if (!strcmp(tProp->name, "DEVICE_PORT")) { if (IUUpdateText(tProp, texts, names, n) < 0) return false; tProp->s = IPS_OK; IDSetText(tProp, "Port updated."); return true; } return DefaultDevice::ISNewText(dev, name, texts, names, n); } /**************************************************************** ** ** *****************************************************************/ bool TCFS::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISwitch *current_active_switch = NULL, *target_active_switch = NULL; // First process parent! if (INDI::DefaultDevice::ISNewSwitch(getDeviceName(), name, states, names, n) == true) return true; ISwitchVectorProperty *sProp = getSwitch(name); if (sProp == NULL) return false; /*if (!strcmp(sProp->name, "CONNECTION")) { if (!strcmp(names[0], "CONNECT")) connect(); else disconnect(); return true; }*/ if (isConnected() == false) { resetProperties(); IDMessage(getDeviceName(), "TCF-S is offline. Connect before issiuing any commands."); return false; } // Which switch is CURRENTLY on? current_active_switch = IUFindOnSwitch(sProp); IUUpdateSwitch(sProp, states, names, n); // Which switch the CLIENT wants to turn on? target_active_switch = IUFindOnSwitch(sProp); if (target_active_switch == NULL) { if (isDebug()) { IDLog("Error: no ON switch found in %s property.\n", sProp->name); } return true; } if (!strcmp(sProp->name, "FOCUS_POWER")) { bool sleep = false; // Sleep if (!strcmp(target_active_switch->name, "FOCUS_SLEEP")) { dispatch_command(FSLEEP); sleep = true; } // Wake Up else dispatch_command(FWAKUP); if (read_tcfs() == false) { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Error reading TCF-S reply."); return true; } if (sleep) { if (isSimulation()) strncpy(response, "ZZZ", TCFS_MAX_CMD); if (!strcmp(response, "ZZZ")) { sProp->s = IPS_OK; IDSetSwitch(sProp, "Focuser is set into sleep mode."); FocusPositionNP->s = IPS_IDLE; IDSetNumber(FocusPositionNP, NULL); FocusTemperatureNP->s = IPS_IDLE; IDSetNumber(FocusTemperatureNP, NULL); return true; } else { sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Focuser sleep mode operation failed. Response: %s.", response); return true; } } else { if (isSimulation()) strncpy(response, "WAKE", TCFS_MAX_CMD); if (!strcmp(response, "WAKE")) { sProp->s = IPS_OK; IDSetSwitch(sProp, "Focuser is awake."); FocusPositionNP->s = IPS_OK; IDSetNumber(FocusPositionNP, NULL); FocusTemperatureNP->s = IPS_OK; IDSetNumber(FocusTemperatureNP, NULL); return true; } else { sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Focuser wake up operation failed. Response: %s", response); return true; } } } if (isFocusSleep) { sProp->s = IPS_IDLE; IUResetSwitch(sProp); if (!strcmp(sProp->name, "FOCUS_MODE") && current_active_switch != NULL) current_active_switch->s = ISS_ON; IDSetSwitch(sProp, "Focuser is still in sleep mode. Wake up in order to issue commands."); return true; } if (!strcmp(sProp->name, "FOCUS_MODE")) { sProp->s = IPS_OK; if (!strcmp(target_active_switch->name, "Manual")) { dispatch_command(FMMODE); read_tcfs(); if (isSimulation() == false && strcmp(response, "!")) { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Error switching to manual mode. No reply from TCF-S. Try again."); return true; } } else if (!strcmp(target_active_switch->name, "Auto A")) { dispatch_command(FAMODE); read_tcfs(); if (isSimulation() == false && strcmp(response, "A")) { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Error switching to Auto Mode A. No reply from TCF-S. Try again."); return true; } } else { dispatch_command(FBMODE); read_tcfs(); if (isSimulation() == false && strcmp(response, "B")) { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Error switching to Auto Mode B. No reply from TCF-S. Try again."); return true; } } IDSetSwitch(sProp, NULL); return true; } if (!strcmp(sProp->name, "FOCUS_MOTION")) { // Inward if (!strcmp(target_active_switch->name, "FOCUS_INWARD")) move_focuser(TCFS_INWARD); // Outward else move_focuser(TCFS_OUTWARD); return true; } if (!strcmp(sProp->name, "FOCUS_GOTO")) { int currentStep = nFocusSteps; FocusPositionNP->s = IPS_BUSY; sProp->s = IPS_OK; // Min if (!strcmp(target_active_switch->name, "FOCUS_MIN")) { nFocusSteps = nFocusCurrentPosition; move_focuser(TCFS_INWARD); nFocusSteps = currentStep; IUResetSwitch(sProp); IDSetSwitch(sProp, "Moving focuser to minimum position..."); } // Center else if (!strcmp(target_active_switch->name, "FOCUS_CENTER")) { dispatch_command(FCENTR); read_tcfs(); if (isSimulation()) strncpy(response, "CENTER", TCFS_MAX_CMD); if (!strcmp(response, "CENTER")) { IUResetSwitch(sProp); sProp->s = IPS_OK; FocusPositionNP->s = IPS_BUSY; if (isTCFS3) nFocusTargetPosition = 5000; else nFocusTargetPosition = 3500; IDSetSwitch(sProp, "Moving focuser to center position %g...", nFocusTargetPosition); return true; } else { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Failed to move focuser to center position!"); return true; } } // Max else if (!strcmp(target_active_switch->name, "FOCUS_MAX")) { nFocusSteps = FocusPositionRequestNP->np[0].max - nFocusCurrentPosition; move_focuser(TCFS_OUTWARD); nFocusSteps = currentStep; IUResetSwitch(sProp); IDSetSwitch(sProp, "Moving focuser to maximum position %g...", FocusPositionRequestNP->np[0].max); } // Home else if (!strcmp(target_active_switch->name, "FOCUS_HOME")) { dispatch_command(FHOME); read_tcfs(); if (isSimulation()) strncpy(response, "DONE", TCFS_MAX_CMD); if (!strcmp(response, "DONE")) { IUResetSwitch(sProp); sProp->s = IPS_OK; //FocusInfoNP->s = IPS_BUSY; IDSetSwitch(sProp, "Moving focuser to new calculated position based on temperature..."); return true; } else { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Failed to move focuser to home position!"); return true; } } return true; } return DefaultDevice::ISNewSwitch(dev, name, states, names, n); } bool TCFS::move_focuser(TCFSMotion dir) { ISwitchVectorProperty *sProp = getSwitch("FOCUS_MOTION"); if (sProp == NULL) return false; // Inward if (dir == TCFS_INWARD) { dispatch_command(FIN); nFocusTargetPosition = nFocusCurrentPosition - nFocusSteps; } // Outward else { dispatch_command(FOUT); nFocusTargetPosition = nFocusCurrentPosition + nFocusSteps; } if (read_tcfs() == false) { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Error reading TCF-S reply."); return false; } if (isSimulation()) strncpy(response, "*", TCFS_MAX_CMD); if (!strcmp(response, "*")) { IUResetSwitch(sProp); sProp->s = IPS_OK; FocusPositionNP->s = IPS_BUSY; IDSetSwitch(sProp, "Moving focuser %s %d steps to position %g.", (dir == TCFS_INWARD) ? "inward" : "outward", ((int) nFocusSteps), nFocusTargetPosition); return true; } else { IUResetSwitch(sProp); sProp->s = IPS_ALERT; IDSetSwitch(sProp, "Failed to move focuser %s!", (dir == TCFS_INWARD) ? "inward" : "outward"); return true; } } bool TCFS::dispatch_command(TCFSCommand command_type) { int err_code = 0, nbytes_written=0, nbytes_read=0; char tcfs_error[TCFS_ERROR_BUFFER]; INumberVectorProperty *nProp = NULL; ISwitchVectorProperty *sProp = NULL; // Clear string command[0] = '\0'; switch (command_type) { // Focuser Manual Mode case FMMODE: strncpy(command, "FMMODE", TCFS_MAX_CMD); break; // Focuser Free Mode case FFMODE: strncpy(command, "FFMODE", TCFS_MAX_CMD); break; // Focuser Auto-A Mode case FAMODE: strncpy(command, "FAMODE", TCFS_MAX_CMD); break; // Focuser Auto-A Mode case FBMODE: strncpy(command, "FBMODE", TCFS_MAX_CMD); break; // Focus Center case FCENTR: strncpy(command, "FCENTR", TCFS_MAX_CMD); break; // Focuser In “nnnn†case FIN: simulated_position = nFocusCurrentPosition; /* if ( (nFocusTargetPosition - nFocusSteps) >= FocusInfoNP->np[0].min) nFocusTargetPosition -= nFocusSteps; else return false;*/ snprintf(command, TCFS_MAX_CMD, "FI%04d", ((int) nFocusSteps)); break; // Focuser Out “nnnn†case FOUT: simulated_position = nFocusCurrentPosition; /*if ( (nFocusTargetPosition + nFocusSteps) <= FocusInfoNP->np[0].max) nFocusTargetPosition += nFocusSteps; else return false;*/ snprintf(command, TCFS_MAX_CMD, "FO%04d", ((int) nFocusSteps)); break; // Focuser Position Read Out case FPOSRO: strncpy(command, "FPOSRO", TCFS_MAX_CMD); break; // Focuser Position Read Out case FTMPRO: strncpy(command, "FTMPRO", TCFS_MAX_CMD); break; // Focuser Sleep case FSLEEP: strncpy(command, "FSLEEP", TCFS_MAX_CMD); break; // Focuser Wake Up case FWAKUP: strncpy(command, "FWAKUP", TCFS_MAX_CMD); break; // Focuser Home Command case FHOME: strncpy(command, "FHOME", TCFS_MAX_CMD); break; } if (isDebug()) IDLog("Dispatching command #%s#\n", command); if (isSimulation()) return true; tcflush(fd, TCIOFLUSH); if ( (err_code = tty_write(fd, command, TCFS_MAX_CMD, &nbytes_written) != TTY_OK)) { tty_error_msg(err_code, tcfs_error, TCFS_ERROR_BUFFER); if (isDebug()) IDLog("TTY error detected: %s\n", tcfs_error); return false; } return true; } void TCFS::ISPoll() { if (!isConnected()) return; int f_position=0; float f_temperature=0; if (FocusPositionNP->s != IPS_IDLE) { // Read Position // Manual Mode if (FocusModeSP->sp[0].s == ISS_ON) dispatch_command(FPOSRO); if (read_tcfs() == false) return; if (isSimulation()) { if (FocusPositionNP->s == IPS_BUSY) { if ( static_cast(nFocusTargetPosition - simulated_position) > 0) simulated_position += FocusStepNP->np[0].step; else if ( static_cast(nFocusTargetPosition - simulated_position) < 0) simulated_position -= FocusStepNP->np[0].step; } snprintf(response, TCFS_MAX_CMD, "P=%04d", simulated_position); if (isDebug()) IDLog("Target Position: %g -- Simulated position: #%s#\n", nFocusTargetPosition, response); } sscanf(response, "P=%d", &f_position); nFocusCurrentPosition = f_position; if (nFocusCurrentPosition == nFocusTargetPosition) { FocusPositionNP->s = IPS_OK; FocusPositionRequestNP->s = IPS_OK; IDSetNumber(FocusPositionRequestNP, NULL); } IDSetNumber(FocusPositionNP, NULL); } if (FocusTemperatureNP->s != IPS_IDLE) { // Read Temperature // Manual Mode if (FocusModeSP->sp[0].s == ISS_ON) dispatch_command(FTMPRO); if (read_tcfs() == false) return; if (isSimulation()) { snprintf(response, TCFS_MAX_CMD, "T=%0.1f", simulated_temperature); if (isDebug()) IDLog("Simulated temperature: #%s#\n", response); } sscanf(response, "T=%f", &f_temperature); nFocusTemperature = f_temperature; IDSetNumber(FocusTemperatureNP, NULL); } } bool TCFS::read_tcfs() { int err_code = 0, nbytes_written=0, nbytes_read=0; char err_msg[TCFS_ERROR_BUFFER]; // Clear string response[0] = '\0'; if (isSimulation()) { strncpy(response, "SIMULATION", TCFS_MAX_CMD); return true; } // Read until encountring a CR if ( (err_code = tty_read_section(fd, response, 0x0D, 15, &nbytes_read)) != TTY_OK) { tty_error_msg(err_code, err_msg, 32); if (isDebug()) { IDLog("TTY error detected: %s\n", err_msg); IDMessage(mydev, "TTY error detected: %s\n", err_msg); } return false; } // Remove LF & CR response[nbytes_read-2] = '\0'; if (isDebug()) IDLog("Bytes Read: %d - strlen(response): %ld - Response from TCF-S: #%s#\n", nbytes_read, strlen(response), response); return true; } const char * TCFS::getDefaultName() { return mydev; } libindi-0.9.7/drivers/focuser/robofocus.h0000644000175000017500000000651312241463551017427 0ustar jasemjasem/* RoboFocus Copyright (C) 2006 Markus Wildi (markus.wildi@datacomm.ch) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef ROBOFOCUS_H #define ROBOFOCUS_H #include "indibase/indifocuser.h" #include "robofocus.h" class RoboFocus : public INDI::Focuser { public: RoboFocus(); ~RoboFocus(); virtual bool Connect(); virtual bool Disconnect(); const char * getDefaultName(); virtual bool initProperties(); virtual bool updateProperties(); virtual void ISGetProperties(const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool Move(FocusDirection dir, int speed, int duration); virtual int MoveAbs(int ticks); virtual int MoveRel(FocusDirection dir, unsigned int ticks); protected: bool saveConfigItems(FILE *fp); private: int PortFD; unsigned char CheckSum(char *rf_cmd); unsigned char CalculateSum(char *rf_cmd); int SendCommand(char *rf_cmd); int ReadResponse(char *buf, int nbytes, int timeout); void GetFocusParams(); int updateRFPosition(double *value); int updateRFTemperature(double *value) ; int updateRFBacklash(double *value); int updateRFFirmware(char *rf_cmd) ; int updateRFMotorSettings(double *duty, double *delay, double *ticks); int updateRFPositionRelativeInward(double *value); int updateRFPositionRelativeOutward(double *value) ; int updateRFPositionAbsolute(double *value); int updateRFPowerSwitches(int s, int new_sn, int *cur_s1LL, int *cur_s2LR, int *cur_s3RL, int *cur_s4RR) ; int updateRFMaxPosition(double *value); int updateRFSetPosition(double *value); ITextVectorProperty PortTP; IText PortT[1]; INumber TemperatureN[1]; INumberVectorProperty TemperatureNP; INumber SettingsN[3]; INumberVectorProperty SettingsNP; ISwitch PowerSwitchesS[4]; ISwitchVectorProperty PowerSwitchesSP; INumber MinMaxPositionN[2]; INumberVectorProperty MinMaxPositionNP; INumber MaxTravelN[1]; INumberVectorProperty MaxTravelNP; INumber SetRegisterPositionN[1]; INumberVectorProperty SetRegisterPositionNP; INumber RelMovementN[1]; INumberVectorProperty RelMovementNP; INumber AbsMovementN[1]; INumberVectorProperty AbsMovementNP; INumber SetBacklashN[1]; INumberVectorProperty SetBacklashNP; }; #endif // ROBOFOCUS_H libindi-0.9.7/drivers/focuser/focus_simulator.h0000644000175000017500000000365512241463551020650 0ustar jasemjasem/******************************************************************************* Copyright(c) 2012 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. . 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 Library General Public License for more details. . You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef FOCUSSIM_H #define FOCUSSIM_H #include "indibase/indifocuser.h" /* Some headers we need */ #include #include class FocusSim : public INDI::Focuser { protected: private: double ticks; double initTicks; INumberVectorProperty SeeingNP; INumberVectorProperty FWHMNP; INumber SeeingN[1]; INumber FWHMN[1]; bool SetupParms(); public: FocusSim(); virtual ~FocusSim(); const char *getDefaultName(); bool initProperties(); bool updateProperties(); void ISGetProperties (const char *dev); bool Connect(); bool Disconnect(); void TimerHit(); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool Move(FocusDirection dir, int speed, int duration); virtual int MoveAbs(int ticks); }; #endif libindi-0.9.7/drivers/focuser/focus_simulator.cpp0000644000175000017500000001614212241463551021176 0ustar jasemjasem/******************************************************************************* Copyright(c) 2012 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. . 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 Library General Public License for more details. . You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "focus_simulator.h" #include #include #include #include #include #include // We declare an auto pointer to focusSim. std::auto_ptr focusSim(0); #define SIM_SEEING 0 #define SIM_FWHM 1 #define FOCUS_MOTION_DELAY 100 /* Focuser takes 100 microsecond to move for each step, completing 100,000 steps in 10 seconds */ void ISPoll(void *p); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(focusSim.get() == 0) focusSim.reset(new FocusSim()); } void ISGetProperties(const char *dev) { ISInit(); focusSim->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); focusSim->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); focusSim->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); focusSim->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); focusSim->ISSnoopDevice(root); } FocusSim::FocusSim() { } bool FocusSim::SetupParms() { IDSetNumber(&FWHMNP, NULL); return true; } bool FocusSim::Connect() { SetTimer(1000); // start the timer return true; } FocusSim::~FocusSim() { //dtor } const char * FocusSim::getDefaultName() { return (char *)"Focuser Simulator"; } bool FocusSim::initProperties() { // Most hardware layers wont actually have indi properties defined // but the simulators are a special case INDI::Focuser::initProperties(); IUFillNumber(&SeeingN[0],"SIM_SEEING","arcseconds","%4.2f",0,60,0,3.5); IUFillNumberVector(&SeeingNP,SeeingN,1,getDeviceName(),"SEEING_SETTINGS","Seeing",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE); IUFillNumber(&FWHMN[0],"SIM_FWHM","arcseconds","%4.2f",0,60,0,7.5); IUFillNumberVector(&FWHMNP,FWHMN,1,getDeviceName(), "FWHM","FWHM",MAIN_CONTROL_TAB,IP_RO,60,IPS_IDLE); ticks = initTicks = sqrt(FWHMN[0].value - SeeingN[0].value) / 0.75; if (isDebug()) IDLog("Initial Ticks is %g\n", ticks); return true; } void FocusSim::ISGetProperties (const char *dev) { // First we let our parent populate INDI::Focuser::ISGetProperties(dev); return; } bool FocusSim::updateProperties() { INDI::Focuser::updateProperties(); if (isConnected()) { defineNumber(&FocusAbsPosNP); defineNumber(&SeeingNP); defineNumber(&FWHMNP); SetupParms(); } else { deleteProperty(FocusAbsPosNP.name); deleteProperty(SeeingNP.name); deleteProperty(FWHMNP.name); } return true; } bool FocusSim::Disconnect() { return true; } void FocusSim::TimerHit() { int nexttimer=1000; if(isConnected() == false) return; // No need to reset timer if we are not connected anymore SetTimer(nexttimer); return; } bool FocusSim::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if(strcmp(name,"SEEING_SETTINGS")==0) { SeeingNP.s = IPS_OK; IUUpdateNumber(&SeeingNP, values, names, n); IDSetNumber(&SeeingNP,NULL); saveConfig(); return true; } } // if we didn't process it, continue up the chain, let somebody else // give it a shot return INDI::Focuser::ISNewNumber(dev,name,values,names,n); } bool FocusSim::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { // Nobody has claimed this, so, ignore it return INDI::Focuser::ISNewSwitch(dev,name,states,names,n); } bool FocusSim::Move(FocusDirection dir, int speed, int duration) { double targetTicks = (speed * duration) / (FocusSpeedN[0].max * FocusTimerN[0].max); double plannedTicks=ticks; double plannedAbsPos=0; if (dir == FOCUS_INWARD) plannedTicks -= targetTicks; else plannedTicks += targetTicks; if (isDebug()) IDLog("Current ticks: %g - target Ticks: %g, plannedTicks %g\n", ticks, targetTicks, plannedTicks); plannedAbsPos = (plannedTicks - initTicks) * 5000 + (FocusAbsPosN[0].max - FocusAbsPosN[0].min)/2; if (plannedAbsPos < FocusAbsPosN[0].min || plannedAbsPos > FocusAbsPosN[0].max) { IDMessage(getDeviceName(), "Error, requested position is out of range."); return false; } ticks = plannedTicks; if (isDebug()) IDLog("Current absolute position: %g, current ticks is %g\n", plannedAbsPos, ticks); FWHMN[0].value = 0.5625*ticks*ticks + SeeingN[0].value; FocusAbsPosN[0].value = plannedAbsPos; if (FWHMN[0].value < SeeingN[0].value) FWHMN[0].value = SeeingN[0].value; IDSetNumber(&FWHMNP, NULL); IDSetNumber(&FocusAbsPosNP, NULL); return true; } int FocusSim::MoveAbs(int targetTicks) { if (targetTicks < FocusAbsPosN[0].min || targetTicks > FocusAbsPosN[0].max) { IDMessage(getDeviceName(), "Error, requested absolute position is out of range."); return -1; } double mid = (FocusAbsPosN[0].max - FocusAbsPosN[0].min)/2; IDMessage(getDeviceName() , "Focuser is moving to requested position..."); // Limit to +/- 10 from initTicks ticks = initTicks + (targetTicks - mid) / 5000.0; if (isDebug()) IDLog("Current ticks: %g\n", ticks); // simulate delay in motion as the focuser moves to the new position usleep( abs(targetTicks - FocusAbsPosN[0].value) * FOCUS_MOTION_DELAY); FWHMN[0].value = 0.5625*ticks*ticks + SeeingN[0].value; if (FWHMN[0].value < SeeingN[0].value) FWHMN[0].value = SeeingN[0].value; IDSetNumber(&FWHMNP, NULL); return 0; } libindi-0.9.7/drivers/focuser/indi_tcfs_sk.xml0000644000175000017500000000572012241463551020435 0ustar jasemjasem Off On /dev/ttyUSB0 Off Off Off Off Off Off Off Off Off 100 0 0 0 Off Off libindi-0.9.7/TODO0000644000175000017500000000017112241463551012613 0ustar jasemjasemTODO: - RTML Support - Multi user Scheduler daemon - Web interface - Vantage Pro/Pro2 Weather Station - More Devices! libindi-0.9.7/examples/0000755000175000017500000000000012241463551013742 5ustar jasemjasemlibindi-0.9.7/examples/tutorial_six/0000755000175000017500000000000012241463551016470 5ustar jasemjasemlibindi-0.9.7/examples/tutorial_six/tutorial_client.cpp0000644000175000017500000001477412241463551022412 0ustar jasemjasem#if 0 Simple Client Tutorial Demonstration of libindi v0.7 capabilities. Copyright (C) 2010 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 /** \file tutorial_client.cpp \brief Construct a basic INDI client that demonstrates INDI::Client capabilities. This client must be used with tutorial_three device "Simple CCD". \author Jasem Mutlaq \example tutorial_client.cpp Construct a basic INDI client that demonstrates INDI::Client capabilities. This client must be used with tutorial_three device "Simple CCD". To run the example, you must first run tutorial_three: \code indiserver tutorial_three \endcode Then in another terminal, run the client: \code tutorial_client \endcode The client will connect to the CCD driver and attempts to change the CCD temperature. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "indibase/baseclient.h" #include "indibase/basedevice.h" #include "indibase/indiproperty.h" /* INDI Common Library Routines */ #include "indicom.h" #include "tutorial_client.h" using namespace std; #define MYCCD "Simple CCD" /* Our client auto pointer */ auto_ptr camera_client(0); int main(int argc, char *argv[]) { if (camera_client.get() == 0) camera_client.reset(new MyClient()); camera_client->setServer("localhost", 7624); camera_client->watchDevice(MYCCD); camera_client->connectServer(); camera_client->setBLOBMode(B_ALSO, MYCCD, NULL); cout << "Press any key to terminate the client.\n"; string term; cin >> term; } /************************************************************************************** ** ***************************************************************************************/ MyClient::MyClient() { ccd_simulator = NULL; } /************************************************************************************** ** ***************************************************************************************/ MyClient::~MyClient() { } /************************************************************************************** ** ***************************************************************************************/ void MyClient::setTemperature() { INumberVectorProperty *ccd_temperature = NULL; ccd_temperature = ccd_simulator->getNumber("CCD_TEMPERATURE"); if (ccd_temperature == NULL) { IDLog("Error: unable to find CCD Simulator CCD_TEMPERATURE property...\n"); return; } ccd_temperature->np[0].value = -20; sendNewNumber(ccd_temperature); } /************************************************************************************** ** ***************************************************************************************/ void MyClient::takeExposure() { INumberVectorProperty *ccd_exposure = NULL; ccd_exposure = ccd_simulator->getNumber("CCD_EXPOSURE"); if (ccd_exposure == NULL) { IDLog("Error: unable to find CCD Simulator CCD_EXPOSURE property...\n"); return; } // Take a 1 second exposure IDLog("Taking a 1 second exposure.\n"); ccd_exposure->np[0].value = 1; sendNewNumber(ccd_exposure); } /************************************************************************************** ** ***************************************************************************************/ void MyClient::newDevice(INDI::BaseDevice *dp) { if (!strcmp(dp->getDeviceName(), MYCCD)) IDLog("Receiving %s Device...\n", dp->getDeviceName()); ccd_simulator = dp; } /************************************************************************************** ** *************************************************************************************/ void MyClient::newProperty(INDI::Property *property) { if (!strcmp(property->getDeviceName(), MYCCD) && !strcmp(property->getName(), "CONNECTION")) { connectDevice(MYCCD); return; } if (!strcmp(property->getDeviceName(), MYCCD) && !strcmp(property->getName(), "CCD_TEMPERATURE")) { if (ccd_simulator->isConnected()) { IDLog("CCD is connected. Setting temperature to -20 C.\n"); setTemperature(); } return; } } /************************************************************************************** ** ***************************************************************************************/ void MyClient::newNumber(INumberVectorProperty *nvp) { // Let's check if we get any new values for CCD_TEMPERATURE if (!strcmp(nvp->name, "CCD_TEMPERATURE")) { IDLog("Receving new CCD Temperature: %g C\n", nvp->np[0].value); if (nvp->np[0].value == -20) { IDLog("CCD temperature reached desired value!\n"); takeExposure(); } } } /************************************************************************************** ** ***************************************************************************************/ void MyClient::newMessage(INDI::BaseDevice *dp, int messageID) { if (strcmp(dp->getDeviceName(), MYCCD)) return; IDLog("Recveing message from Server:\n\n########################\n%s\n########################\n\n", dp->messageQueue(messageID)); } /************************************************************************************** ** ***************************************************************************************/ void MyClient::newBLOB(IBLOB *bp) { // Save FITS file to disk ofstream myfile; myfile.open ("ccd_simulator.fits", ios::out | ios::binary); myfile.write(static_cast (bp->blob), bp->bloblen); myfile.close(); IDLog("Received image, saved as ccd_simulator.fits\n"); } libindi-0.9.7/examples/tutorial_six/tutorial_client.h0000644000175000017500000000457612241463551022056 0ustar jasemjasem/* Tutorial Client Copyright (C) 2010 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef TUTORIAL_CLIENT_H #define TUTORIAL_CLIENT_H /** \file tutorial_client.h \brief Construct a basic INDI client that demonstrates INDI::Client capabilities. This client must be used with tutorial_three device "Simple CCD". \author Jasem Mutlaq \example tutorial_client.h Construct a basic INDI client that demonstrates INDI::Client capabilities. This client must be used with tutorial_three device "Simple CCD". To run the example, you must first run tutorial_three: \code indiserver tutorial_three \endcode Then in another terminal, run the client: \code tutorial_client \endcode The client will connect to the CCD driver and attempts to change the CCD temperature. */ #include "indidevapi.h" #include "indicom.h" #include "indibase/baseclient.h" class MyClient : public INDI::BaseClient { public: MyClient(); ~MyClient(); void setTemperature(); void takeExposure(); protected: virtual void newDevice(INDI::BaseDevice *dp); virtual void newProperty(INDI::Property *property); virtual void removeProperty(INDI::Property *property) {} virtual void newBLOB(IBLOB *bp); virtual void newSwitch(ISwitchVectorProperty *svp) {} virtual void newNumber(INumberVectorProperty *nvp); virtual void newMessage(INDI::BaseDevice *dp, int messageID); virtual void newText(ITextVectorProperty *tvp) {} virtual void newLight(ILightVectorProperty *lvp) {} virtual void serverConnected() {} virtual void serverDisconnected(int exit_code) {} private: INDI::BaseDevice * ccd_simulator; }; #endif libindi-0.9.7/examples/tutorial_one/0000755000175000017500000000000012241463551016446 5ustar jasemjasemlibindi-0.9.7/examples/tutorial_one/simpledevice.cpp0000644000175000017500000001020312241463551021617 0ustar jasemjasem/* INDI Developers Manual Tutorial #1 "Hello INDI" We construct a most basic (and useless) device driver to illustate INDI. Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file simpledevice.cpp \brief Construct a basic INDI device with only one property to connect and disconnect. \author Jasem Mutlaq \example simpledevice.cpp A very minimal device! It also allows you to connect/disconnect and performs no other functions. */ #include #include "simpledevice.h" std::auto_ptr simpleDevice(0); /************************************************************************************** ** Initilize SimpleDevice object ***************************************************************************************/ void ISInit() { static int isInit=0; if (isInit) return; if (simpleDevice.get() == 0) { isInit = 1; simpleDevice.reset(new SimpleDevice()); } } /************************************************************************************** ** Return properties of device. ***************************************************************************************/ void ISGetProperties (const char *dev) { ISInit(); simpleDevice->ISGetProperties(dev); } /************************************************************************************** ** Process new switch from client ***************************************************************************************/ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); simpleDevice->ISNewSwitch(dev, name, states, names, n); } /************************************************************************************** ** Process new text from client ***************************************************************************************/ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); simpleDevice->ISNewText(dev, name, texts, names, n); } /************************************************************************************** ** Process new number from client ***************************************************************************************/ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); simpleDevice->ISNewNumber(dev, name, values, names, n); } /************************************************************************************** ** Process new blob from client ***************************************************************************************/ void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { ISInit(); simpleDevice->ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n); } /************************************************************************************** ** Process snooped property from another driver ***************************************************************************************/ void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } SimpleDevice::SimpleDevice() { } /************************************************************************************** ** Client is asking us to establish connection to the device ***************************************************************************************/ bool SimpleDevice::Connect() { IDMessage(getDeviceName(), "Simple device connected successfully!"); return true; } /************************************************************************************** ** Client is asking us to terminate connection to the device ***************************************************************************************/ bool SimpleDevice::Disconnect() { IDMessage(getDeviceName(), "Simple device disconnected successfully!"); return true; } /************************************************************************************** ** INDI is asking us for our default device name ***************************************************************************************/ const char * SimpleDevice::getDefaultName() { return "Simple Device"; } libindi-0.9.7/examples/tutorial_one/simpledevice.h0000644000175000017500000000146612241463551021277 0ustar jasemjasem#ifndef SIMPLEDEVICE_H #define SIMPLEDEVICE_H /* INDI Developers Manual Tutorial #1 "Hello INDI" We construct a most basic (and useless) device driver to illustate INDI. Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file simpledevice.h \brief Construct a basic INDI device with only one property to connect and disconnect. \author Jasem Mutlaq \example simpledevice.h A very minimal device! It also allows you to connect/disconnect and performs no other functions. */ #include "indibase/defaultdevice.h" class SimpleDevice : public INDI::DefaultDevice { public: SimpleDevice(); protected: bool Connect(); bool Disconnect(); const char *getDefaultName(); }; #endif // SIMPLEDEVICE_H libindi-0.9.7/examples/tutorial_two/0000755000175000017500000000000012241463551016476 5ustar jasemjasemlibindi-0.9.7/examples/tutorial_two/simplescope.h0000644000175000017500000000202112241463551021165 0ustar jasemjasem#ifndef SIMPLESCOPE_H #define SIMPLESCOPE_H /* INDI Developers Manual Tutorial #2 "Simple Telescope Driver" We develop a simple telescope simulator. Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file simplescope.h \brief Construct a basic INDI telescope device that simulates GOTO commands. \author Jasem Mutlaq \example simplescope.h A simple GOTO telescope that simulator slewing operation. */ #include "indibase/inditelescope.h" class SimpleScope : public INDI::Telescope { public: SimpleScope(); protected: // General device functions bool Connect(); bool Disconnect(); const char *getDefaultName(); bool initProperties(); // Telescoe specific functions bool ReadScopeStatus(); bool Goto(double,double); bool Abort(); private: double currentRA; double currentDEC; double targetRA; double targetDEC; unsigned int DBG_SCOPE; }; #endif // SIMPLESCOPE_H libindi-0.9.7/examples/tutorial_two/simplescope.cpp0000644000175000017500000002105412241463551021527 0ustar jasemjasem/* INDI Developers Manual Tutorial #2 "Simple Telescope Driver" We develop a simple telescope simulator. Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file simplescope.cpp \brief Construct a basic INDI telescope device that simulates GOTO commands. \author Jasem Mutlaq \example simplescope.cpp A simple GOTO telescope that simulator slewing operation. */ #include #include #include #include "simplescope.h" #include "indicom.h" const float SIDRATE = 0.004178; /* sidereal rate, degrees/s */ const int SLEW_RATE = 1; /* slew rate, degrees/s */ const int POLLMS = 250; /* poll period, ms */ std::auto_ptr simpleScope(0); /************************************************************************************** ** Initilize SimpleScope object ***************************************************************************************/ void ISInit() { static int isInit=0; if (isInit) return; if (simpleScope.get() == 0) { isInit = 1; simpleScope.reset(new SimpleScope()); } } /************************************************************************************** ** Return properties of device. ***************************************************************************************/ void ISGetProperties (const char *dev) { ISInit(); simpleScope->ISGetProperties(dev); } /************************************************************************************** ** Process new switch from client ***************************************************************************************/ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); simpleScope->ISNewSwitch(dev, name, states, names, n); } /************************************************************************************** ** Process new text from client ***************************************************************************************/ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); simpleScope->ISNewText(dev, name, texts, names, n); } /************************************************************************************** ** Process new number from client ***************************************************************************************/ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); simpleScope->ISNewNumber(dev, name, values, names, n); } /************************************************************************************** ** Process new blob from client ***************************************************************************************/ void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { ISInit(); simpleScope->ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n); } /************************************************************************************** ** Process snooped property from another driver ***************************************************************************************/ void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } SimpleScope::SimpleScope() { currentRA = 0; currentDEC = 90; // We add an additional debug level so we can log verbose scope status DBG_SCOPE = INDI::Logger::getInstance().addDebugLevel("Scope Verbose", "SCOPE"); } /************************************************************************************** ** We init our properties here. The only thing we want to init are the Debug controls ***************************************************************************************/ bool SimpleScope::initProperties() { // ALWAYS call initProperties() of parent first INDI::Telescope::initProperties(); addDebugControl(); } /************************************************************************************** ** Client is asking us to establish connection to the device ***************************************************************************************/ bool SimpleScope::Connect() { DEBUG(INDI::Logger::DBG_SESSION, "Simple Scope connected successfully!"); // Let's set a timer that checks telescopes status every POLLMS milliseconds. SetTimer(POLLMS); return true; } /************************************************************************************** ** Client is asking us to terminate connection to the device ***************************************************************************************/ bool SimpleScope::Disconnect() { DEBUG(INDI::Logger::DBG_SESSION, "Simple Scope disconnected successfully!"); return true; } /************************************************************************************** ** INDI is asking us for our default device name ***************************************************************************************/ const char * SimpleScope::getDefaultName() { return "Simple Scope"; } /************************************************************************************** ** Client is asking us to slew to a new position ***************************************************************************************/ bool SimpleScope::Goto(double ra, double dec) { targetRA=ra; targetDEC=dec; char RAStr[64], DecStr[64]; // Parse the RA/DEC into strings fs_sexa(RAStr, targetRA, 2, 3600); fs_sexa(DecStr, targetDEC, 2, 3600); // Mark state as slewing TrackState = SCOPE_SLEWING; // Inform client we are slewing to a new position DEBUGF(INDI::Logger::DBG_SESSION, "Slewing to RA: %s - DEC: %s", RAStr, DecStr); // Success! return true; } /************************************************************************************** ** Client is asking us to abort our motion ***************************************************************************************/ bool SimpleScope::Abort() { TrackState = SCOPE_IDLE; DEBUG(INDI::Logger::DBG_SESSION, "Simple Scope stopped."); return true; } /************************************************************************************** ** Client is asking us to report telescope status ***************************************************************************************/ bool SimpleScope::ReadScopeStatus() { static struct timeval ltv; struct timeval tv; double dt=0, da_ra=0, da_dec=0, dx=0, dy=0; int nlocked; /* update elapsed time since last poll, don't presume exactly POLLMS */ gettimeofday (&tv, NULL); if (ltv.tv_sec == 0 && ltv.tv_usec == 0) ltv = tv; dt = tv.tv_sec - ltv.tv_sec + (tv.tv_usec - ltv.tv_usec)/1e6; ltv = tv; // Calculate how much we moved since last time da_ra = SLEW_RATE *dt; da_dec = SLEW_RATE *dt; /* Process per current state. We check the state of EQUATORIAL_EOD_COORDS_REQUEST and act acoordingly */ switch (TrackState) { case SCOPE_SLEWING: // Wait until we are "locked" into positon for both RA & DEC axis nlocked = 0; // Calculate diff in RA dx = targetRA - currentRA; // If diff is very small, i.e. smaller than how much we changed since last time, then we reached target RA. if (fabs(dx)*15. <= da_ra) { currentRA = targetRA; nlocked++; } // Otherwise, increase RA else if (dx > 0) currentRA += da_ra/15.; // Otherwise, decrease RA else currentRA -= da_ra/15.; // Calculate diff in DEC dy = targetDEC - currentDEC; // If diff is very small, i.e. smaller than how much we changed since last time, then we reached target DEC. if (fabs(dy) <= da_dec) { currentDEC = targetDEC; nlocked++; } // Otherwise, increase DEC else if (dy > 0) currentDEC += da_dec; // Otherwise, decrease DEC else currentDEC -= da_dec; // Let's check if we recahed position for both RA/DEC if (nlocked == 2) { // Let's set state to TRACKING TrackState = SCOPE_TRACKING; DEBUG(INDI::Logger::DBG_SESSION, "Telescope slew is complete. Tracking..."); } break; default: break; } char RAStr[64], DecStr[64]; // Parse the RA/DEC into strings fs_sexa(RAStr, currentRA, 2, 3600); fs_sexa(DecStr, currentDEC, 2, 3600); DEBUGF(DBG_SCOPE, "Current RA: %s Current DEC: %s", RAStr, DecStr ); NewRaDec(currentRA, currentDEC); return true; } libindi-0.9.7/examples/tutorial_four/0000755000175000017500000000000012241463551016640 5ustar jasemjasemlibindi-0.9.7/examples/tutorial_four/simpleskeleton.h0000644000175000017500000000434012241463551022050 0ustar jasemjasem/* Tutorial Four Copyright (C) 2010 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef SIMPLE_SKELETON_H #define SIMPLE_SKELETON_H /** \file simpleskeleton.h \brief Construct a basic INDI CCD device that demonstrates ability to define properties from a skeleton file. \author Jasem Mutlaq \example simpleskeleton.h A skeleton file is an external XML file with the driver properties already defined. This tutorial illustrates how to create a driver from a skeleton file and parse/process the properties. The skeleton file name is tutorial_four_sk.xml \note Please note that if you create your own skeleton file, you must append _sk postfix to your skeleton file name. */ #include "indidevapi.h" #include "indicom.h" #include "indibase/defaultdevice.h" class SimpleSkeleton : public INDI::DefaultDevice { public: SimpleSkeleton(); ~SimpleSkeleton(); virtual void ISGetProperties (const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n); private: const char *getDefaultName(); virtual bool initProperties(); virtual bool Connect(); virtual bool Disconnect(); }; #endif libindi-0.9.7/examples/tutorial_four/tutorial_four_sk.xml0000644000175000017500000000321412241463551022755 0ustar jasemjasem Off On 3 3 Idle Idle Idle Idle Idle On Off Off Off Off libindi-0.9.7/examples/tutorial_four/simpleskeleton.cpp0000644000175000017500000002540312241463551022406 0ustar jasemjasem#if 0 Simple Skeleton - Tutorial Four Demonstration of libindi v0.7 capabilities. Copyright (C) 2010 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 /** \file simpleskeleton.cpp \brief Construct a basic INDI CCD device that demonstrates ability to define properties from a skeleton file. \author Jasem Mutlaq \example simpleskeleton.cpp A skeleton file is an external XML file with the driver properties already defined. This tutorial illustrates how to create a driver from a skeleton file and parse/process the properties. The skeleton file name is tutorial_four_sk.xml \note Please note that if you create your own skeleton file, you must append _sk postfix to your skeleton file name. */ #include #include #include #include #include /* Our driver header */ #include "simpleskeleton.h" /* Our simpleSkeleton auto pointer */ std::auto_ptr simpleSkeleton(0); const int POLLMS = 1000; // Period of update, 1 second. /************************************************************************************** ** Send client definitions of all properties. ***************************************************************************************/ void ISInit() { static int isInit=0; if (isInit) return; if (simpleSkeleton.get() == 0) { isInit = 1; simpleSkeleton.reset(new SimpleSkeleton()); } } /************************************************************************************** ** ***************************************************************************************/ void ISGetProperties (const char *dev) { ISInit(); simpleSkeleton->ISGetProperties(dev); } /************************************************************************************** ** ***************************************************************************************/ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { ISInit(); simpleSkeleton->ISNewSwitch(dev, name, states, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { ISInit(); simpleSkeleton->ISNewText(dev, name, texts, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { ISInit(); simpleSkeleton->ISNewNumber(dev, name, values, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { ISInit(); simpleSkeleton->ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } /************************************************************************************** ** ***************************************************************************************/ SimpleSkeleton::SimpleSkeleton() { } /************************************************************************************** ** ***************************************************************************************/ SimpleSkeleton::~SimpleSkeleton() { } /************************************************************************************** ** Initialize all properties & set default values. **************************************************************************************/ bool SimpleSkeleton::initProperties() { DefaultDevice::initProperties(); // This is the default driver skeleton file location // Convention is: drivername_sk_xml // Default location is /usr/share/indi const char *skelFileName = "/usr/share/indi/tutorial_four_sk.xml"; struct stat st; char *skel = getenv("INDISKEL"); if (skel) buildSkeleton(skel); else if (stat(skelFileName,&st) == 0) buildSkeleton(skelFileName); else IDLog("No skeleton file was specified. Set environment variable INDISKEL to the skeleton path and try again.\n"); // Optional: Add aux controls for configuration, debug & simulation that get added in the Options tab // of the driver. addAuxControls(); std::vector *pAll = getProperties(); // Let's print a list of all device properties for (int i=0; i < pAll->size(); i++) IDLog("Property #%d: %s\n", i, pAll->at(i)->getName()); return true; } /************************************************************************************** ** Define Basic properties to clients. ***************************************************************************************/ void SimpleSkeleton::ISGetProperties(const char *dev) { static int configLoaded = 0; // Ask the default driver first to send properties. INDI::DefaultDevice::ISGetProperties(dev); // If no configuration is load before, then load it now. if (configLoaded == 0) { loadConfig(); configLoaded = 1; } } /************************************************************************************** ** Process Text properties ***************************************************************************************/ bool SimpleSkeleton::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // Ignore if not ours if (strcmp (dev, getDeviceName())) return false; return false; } /************************************************************************************** ** ***************************************************************************************/ bool SimpleSkeleton::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // Ignore if not ours if (strcmp (dev, getDeviceName())) return false; INumberVectorProperty *nvp = getNumber(name); if (!nvp) return false; if (isConnected() == false) { nvp->s = IPS_ALERT; IDSetNumber(nvp, "Cannot change property while device is disconnected."); return false; } if (!strcmp(nvp->name, "Number Property")) { IUUpdateNumber(nvp, values, names, n); nvp->s = IPS_OK; IDSetNumber(nvp, NULL); return true; } return false; } /************************************************************************************** ** ***************************************************************************************/ bool SimpleSkeleton::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int lightState=0; int lightIndex=0; // ignore if not ours // if (strcmp (dev, getDeviceName())) return false; if (INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n) == true) return true; ISwitchVectorProperty *svp = getSwitch(name); ILightVectorProperty *lvp = getLight("Light Property"); if (isConnected() == false) { svp->s = IPS_ALERT; IDSetSwitch(svp, "Cannot change property while device is disconnected."); return false; } if (!svp || !lvp) return false; if (!strcmp(svp->name, "Menu")) { IUUpdateSwitch(svp, states, names, n); ISwitch *onSW = IUFindOnSwitch(svp); lightIndex = IUFindOnSwitchIndex(svp); if (lightIndex < 0 || lightIndex > lvp->nlp) return false; if (onSW) { lightState = rand() % 4; svp->s = IPS_OK; lvp->s = IPS_OK; lvp->lp[lightIndex].s = (IPState) lightState; IDSetSwitch(svp, "Setting to switch %s is successful. Changing corresponding light property to %s.", onSW->name, pstateStr(lvp->lp[lightIndex].s)); IDSetLight(lvp, NULL); } return true; } return false; } bool SimpleSkeleton::ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { if (strcmp (dev, getDeviceName())) return false; IBLOBVectorProperty *bvp = getBLOB(name); if (!bvp) return false; if (isConnected() == false) { bvp->s = IPS_ALERT; IDSetBLOB(bvp, "Cannot change property while device is disconnected."); return false; } if (!strcmp(bvp->name, "BLOB Test")) { IUUpdateBLOB(bvp, sizes, blobsizes, blobs, formats, names, n); IBLOB *bp = IUFindBLOB(bvp, names[0]); if (!bp) return false; IDLog("Received BLOB with name %s, format %s, and size %d, and bloblen %d\n", bp->name, bp->format, bp->size, bp->bloblen); char *blobBuffer = new char[bp->bloblen+1]; strncpy(blobBuffer, ((char *) bp->blob), bp->bloblen); blobBuffer[bp->bloblen] = '\0'; IDLog("BLOB Content:\n##################################\n%s\n##################################\n", blobBuffer); delete [] blobBuffer; bp->size=0; bvp->s = IPS_OK; IDSetBLOB(bvp, NULL); } return true; } /************************************************************************************** ** ***************************************************************************************/ bool SimpleSkeleton::Connect() { return true; } bool SimpleSkeleton::Disconnect() { return true; } const char * SimpleSkeleton::getDefaultName() { return "Simple Skeleton"; } libindi-0.9.7/examples/README0000644000175000017500000000635612241463551014634 0ustar jasemjasem************************************************* * INDI Developers Manual * Chapter 8: Tutorial ************************************************** Introduction -------------- The tutorials included in the INDI Library can be used with any INDI compatible client. The following instructions are provided to test the drivers with KStars. If you are running a different client, refer to your client documentation. Tutorials ---------- Four tutorials are presented to introduce developers to the INDI architecture. tutorial_one: We construct the most basic device. tutorial_two: We create a simple telescope simulator. tutorial_three: We create a simple CCD simulator, and establish a data channel with the client to transmit randomly generated FITS. tutorial_four: We demonstrate use of skeleton files to define properties. tutorial_five: We create two devices (Rain Detector and Dome) to demonstrate inter-driver communication in INDI. tutorial_six: We create a simple client to set the temperature of a CCD simulator (tutorial_three). Usage -------- 1. Running cmake in the libindi directory should build the examples binary as well. ------------------------------------------------------------------------------------------ 2. Run KStars (v1.1 or above is required) Under KStars, click on the "device" menu, then click on the "device manager". Click on the "client" tab and then click on the "add" button. A dialog box will be displayed with three fields: name, host, and port. You can enter anything in the name field, for example "my device" or "tutorial". Enter "127.0.0.1" in the host name and "8000" in the port entry (without the quotes). This device will be saved in your client menu. So you only to do #2 once. ------------------------------------------------------------------------------------------ 3. In the src/examples directory, run each tutorial $ indiserver -v -p 8000 ./tutorial_NUM where num is the tutorial number (tutorial_one, tutorial_two...etc) ------------------------------------------------------------------------------------------ For the inter-driver communications tutorial, type instead: $ indiserver -v -p 8000 ./tutorial_dome ./tutorial_rain ------------------------------------------------------------------------------------------ For tutorial_client. Run tutorial_three first: $ indiserver -v ./tutorial_three Then open another console tab, and run the client: $ ./tutorial_client You can connect to tutorial_three via a GUI client (e.g. KStars) before running tutorial_client. This will enable you to watch changes in the driver as they occur from tutorial_client. Make sure to set the port to 7624 in KStars. ------------------------------------------------------------------------------------------ 4. In KStars, go the device menu --> device manager --> client and select the host you added in step #2 and hit connect. ------------------------------------------------------------------------------------------ 5. The connection icon should be changed to connected, otherwise, an error message will be displayed. ------------------------------------------------------------------------------------------ 6. Close the device manager, and open the INDI Control Panel in the device menu. You can control your device from there. libindi-0.9.7/examples/tutorial_three/0000755000175000017500000000000012241463551016774 5ustar jasemjasemlibindi-0.9.7/examples/tutorial_three/simpleccd.h0000644000175000017500000000335212241463551021113 0ustar jasemjasem#ifndef SIMPLECCD_H #define SIMPLECCD_H /* INDI Developers Manual Tutorial #3 "Simple CCD Driver" We develop a simple CCD driver. Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file simpleccd.h \brief Construct a basic INDI CCD device that simulates exposure & temperature settings. It also generates a random pattern and uploads it as a FITS file. \author Jasem Mutlaq \example simpleccd.h A simple CCD device that can capture images and control temperature. It returns a FITS image to the client. To build drivers for complex CCDs, please refer to the INDI Generic CCD driver template in INDI SVN (under 3rdparty). */ #include "indibase/indiccd.h" class SimpleCCD : public INDI::CCD { public: SimpleCCD(); bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); void ISGetProperties(const char *dev); protected: // General device functions bool Connect(); bool Disconnect(); const char *getDefaultName(); bool initProperties(); bool updateProperties(); // CCD specific functions int StartExposure(float duration); bool AbortExposure(); void TimerHit(); void addFITSKeywords(fitsfile *fptr, CCDChip *targetChip); private: // Utility functions float CalcTimeLeft(); void setupParams(); void grabImage(); // Are we exposing? bool InExposure; // Struct to keep timing struct timeval ExpStart; float ExposureRequest; float TemperatureRequest; int timerID; // We declare the CCD temperature property INumber TemperatureN[1]; INumberVectorProperty TemperatureNP; }; #endif // SIMPLECCD_H libindi-0.9.7/examples/tutorial_three/simpleccd.cpp0000644000175000017500000003070412241463551021447 0ustar jasemjasem/* INDI Developers Manual Tutorial #3 "Simple CCD Driver" We develop a simple CCD driver. Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file simpleccd.cpp \brief Construct a basic INDI CCD device that simulates exposure & temperature settings. It also generates a random pattern and uploads it as a FITS file. \author Jasem Mutlaq \example simpleccd.cpp A simple CCD device that can capture images and control temperature. It returns a FITS image to the client. To build drivers for complex CCDs, please refer to the INDI Generic CCD driver template in INDI SVN (under 3rdparty). */ #include #include #include "simpleccd.h" const int POLLMS = 500; /* Polling interval 500 ms */ const int MAX_CCD_TEMP = 45; /* Max CCD temperature */ const int MIN_CCD_TEMP = -55; /* Min CCD temperature */ const float TEMP_THRESHOLD = .25; /* Differential temperature threshold (C)*/ /* Macro shortcut to CCD temperature value */ #define currentCCDTemperature TemperatureN[0].value std::auto_ptr simpleCCD(0); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(simpleCCD.get() == 0) simpleCCD.reset(new SimpleCCD()); } void ISGetProperties(const char *dev) { ISInit(); simpleCCD->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); simpleCCD->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); simpleCCD->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); simpleCCD->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); simpleCCD->ISSnoopDevice(root); } SimpleCCD::SimpleCCD() { InExposure = false; } /************************************************************************************** ** Client is asking us to establish connection to the device ***************************************************************************************/ bool SimpleCCD::Connect() { IDMessage(getDeviceName(), "Simple CCD connected successfully!"); // Let's set a timer that checks teleCCDs status every POLLMS milliseconds. SetTimer(POLLMS); return true; } /************************************************************************************** ** Client is asking us to terminate connection to the device ***************************************************************************************/ bool SimpleCCD::Disconnect() { IDMessage(getDeviceName(), "Simple CCD disconnected successfully!"); return true; } /************************************************************************************** ** INDI is asking us for our default device name ***************************************************************************************/ const char * SimpleCCD::getDefaultName() { return "Simple CCD"; } /************************************************************************************** ** INDI is asking us to init our properties. ***************************************************************************************/ bool SimpleCCD::initProperties() { // Must init parent properties first! INDI::CCD::initProperties(); // We init the property details. This is a stanard property of the INDI Library. IUFillNumber(&TemperatureN[0], "CCD_TEMPERATURE_VALUE", "Temperature (C)", "%5.2f", MIN_CCD_TEMP, MAX_CCD_TEMP, 0., 0.); IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "CCD_TEMPERATURE", "Temperature", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE); // Add Debug, Simulator, and Configuration controls addAuxControls(); return true; } /************************************************************************************** ** INDI is asking us to submit list of properties for the device ***************************************************************************************/ void SimpleCCD::ISGetProperties(const char *dev) { INDI::CCD::ISGetProperties(dev); // If we are _already_ connected, let's define our temperature property to the client now if (isConnected()) { // Define our only property temperature defineNumber(&TemperatureNP); } } /******************************************************************************************** ** INDI is asking us to update the properties because there is a change in CONNECTION status ** This fucntion is called whenever the device is connected or disconnected. *********************************************************************************************/ bool SimpleCCD::updateProperties() { // Call parent update properties first INDI::CCD::updateProperties(); if (isConnected()) { // Define our only property temperature defineNumber(&TemperatureNP); // Let's get parameters now from CCD setupParams(); // Start the timer SetTimer(POLLMS); } else // We're disconnected { deleteProperty(TemperatureNP.name); } return true; } /************************************************************************************** ** Setting up CCD parameters ***************************************************************************************/ void SimpleCCD::setupParams() { // Our CCD is an 8 bit CCD, 1280x1024 resolution, with 5.4um square pixels. SetCCDParams(1280, 1024, 8, 5.4, 5.4); // Let's calculate how much memory we need for the primary CCD buffer int nbuf; nbuf=PrimaryCCD.getXRes()*PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8; nbuf+=512; // leave a little extra at the end PrimaryCCD.setFrameBufferSize(nbuf); } /************************************************************************************** ** Client is asking us to start an exposure ***************************************************************************************/ int SimpleCCD::StartExposure(float duration) { ExposureRequest=duration; // Since we have only have one CCD with one chip, we set the exposure duration of the primary CCD PrimaryCCD.setExposureDuration(duration); gettimeofday(&ExpStart,NULL); InExposure=true; // We're done return 0; } /************************************************************************************** ** Client is asking us to abort an exposure ***************************************************************************************/ bool SimpleCCD::AbortExposure() { InExposure = false; return true; } /************************************************************************************** ** How much longer until exposure is done? ***************************************************************************************/ float SimpleCCD::CalcTimeLeft() { double timesince; double timeleft; struct timeval now; gettimeofday(&now,NULL); timesince=(double)(now.tv_sec * 1000.0 + now.tv_usec/1000) - (double)(ExpStart.tv_sec * 1000.0 + ExpStart.tv_usec/1000); timesince=timesince/1000; timeleft=ExposureRequest-timesince; return timeleft; } /************************************************************************************** ** Client is asking us to set a new number ***************************************************************************************/ bool SimpleCCD::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) { INumber *np; if(strcmp(dev,getDeviceName())==0) { /* Temperature*/ if (!strcmp(TemperatureNP.name, name)) { TemperatureNP.s = IPS_IDLE; // Let's find the temperature value np = IUFindNumber(&TemperatureNP, names[0]); // If it doesn't exist... if (np == NULL) { IDSetNumber(&TemperatureNP, "Unknown error. %s is not a member of %s property.", names[0], name); return false; } // If it's out of range ... if (values[0] < MIN_CCD_TEMP || values[0] > MAX_CCD_TEMP) { IDSetNumber(&TemperatureNP, "Error: valid range of temperature is from %d to %d", MIN_CCD_TEMP, MAX_CCD_TEMP); return false; } // All OK, let's set the requested temperature TemperatureRequest = values[0]; TemperatureNP.s = IPS_BUSY; IDSetNumber(&TemperatureNP, "Setting CCD temperature to %+06.2f C", values[0]); return true; } } // If we didn't process anything above, let the parent handle it. return INDI::CCD::ISNewNumber(dev,name,values,names,n); } /************************************************************************************** ** INDI is asking us to add any FITS keywords to the FITS header ***************************************************************************************/ void SimpleCCD::addFITSKeywords(fitsfile *fptr, CCDChip *targetChip) { // Let's first add parent keywords INDI::CCD::addFITSKeywords(fptr, targetChip); // Add temperature to FITS header int status=0; fits_update_key_s(fptr, TDOUBLE, "CCD-TEMP", &(TemperatureN[0].value), "CCD Temperature (Celcius)", &status); fits_write_date(fptr, &status); } /************************************************************************************** ** Main device loop. We check for exposure and temperature progress here ***************************************************************************************/ void SimpleCCD::TimerHit() { long timeleft; if(isConnected() == false) return; // No need to reset timer if we are not connected anymore if (InExposure) { timeleft=CalcTimeLeft(); // Less than a 0.1 second away from exposure completion // This is an over simplified timing method, check CCDSimulator and simpleCCD for better timing checks if(timeleft < 0.1) { /* We're done exposing */ IDMessage(getDeviceName(), "Exposure done, downloading image..."); // Set exposure left to zero PrimaryCCD.setExposureLeft(0); // We're no longer exposing... InExposure = false; /* grab and save image */ grabImage(); } else // Just update time left in client PrimaryCCD.setExposureLeft(timeleft); } switch (TemperatureNP.s) { case IPS_IDLE: case IPS_OK: break; case IPS_BUSY: /* If target temperature is higher, then increase current CCD temperature */ if (currentCCDTemperature < TemperatureRequest) currentCCDTemperature++; /* If target temperature is lower, then decrese current CCD temperature */ else if (currentCCDTemperature > TemperatureRequest) currentCCDTemperature--; /* If they're equal, stop updating */ else { TemperatureNP.s = IPS_OK; IDSetNumber(&TemperatureNP, "Target temperature reached."); break; } IDSetNumber(&TemperatureNP, NULL); break; case IPS_ALERT: break; } SetTimer(POLLMS); return; } /************************************************************************************** ** Create a random image and return it to client ***************************************************************************************/ void SimpleCCD::grabImage() { // Let's get a pointer to the frame buffer char * image = PrimaryCCD.getFrameBuffer(); // Get width and height int width = PrimaryCCD.getSubW() / PrimaryCCD.getBinX() * PrimaryCCD.getBPP()/8; int height = PrimaryCCD.getSubH() / PrimaryCCD.getBinY(); // Fill buffer with random pattern for (int i=0; i < height ; i++) for (int j=0; j < width; j++) image[i*width+j] = rand() % 255; IDMessage(getDeviceName(), "Download complete."); // Let INDI::CCD know we're done filling the image buffer ExposureComplete(&PrimaryCCD); } libindi-0.9.7/examples/tutorial_five/0000755000175000017500000000000012241463551016616 5ustar jasemjasemlibindi-0.9.7/examples/tutorial_five/dome.cpp0000644000175000017500000002025612241463551020253 0ustar jasemjasem/* INDI Developers Manual Tutorial #5 - Snooping Dome Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file dome.cpp \brief Construct a dome device that the user may operate to open or close the dome shutter door. This driver is \e snooping on the Rain Detector rain property status. If rain property state is alert, we close the dome shutter door if it is open, and we prevent the user from opening it until the rain threat passes. \author Jasem Mutlaq \example dome.cpp The dome driver \e snoops on the rain detector signal and watches whether rain is detected or not. If it is detector and the dome is closed, it performs no action, but it also prevents you from opening the dome due to rain. If the dome is open, it will automatically starts closing the shutter. In order snooping to work, both drivers must be started by the same indiserver (or chained INDI servers): \code indiserver tutorial_dome tutorial_rain \endcode The dome driver keeps a copy of RainL light property from the rain driver. This makes it easy to parse the property status once an update from the rain driver arrives in the dome driver. Alternatively, you can directly parse the XML root element in ISSnoopDevice(XMLEle *root) to extract the required data. */ #include #include #include "dome.h" std::auto_ptr dome(0); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(dome.get() == 0) dome.reset(new Dome()); } void ISGetProperties(const char *dev) { ISInit(); dome->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); dome->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); dome->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); dome->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); dome->ISSnoopDevice(root); } Dome::Dome() { } /************************************************************************************** ** Client is asking us to establish connection to the device ***************************************************************************************/ bool Dome::Connect() { IDMessage(getDeviceName(), "Dome connected successfully!"); return true; } /************************************************************************************** ** Client is asking us to terminate connection to the device ***************************************************************************************/ bool Dome::Disconnect() { IDMessage(getDeviceName(), "Dome disconnected successfully!"); return true; } /************************************************************************************** ** INDI is asking us for our default device name ***************************************************************************************/ const char * Dome::getDefaultName() { return "Dome"; } /************************************************************************************** ** INDI is asking us to init our properties. ***************************************************************************************/ bool Dome::initProperties() { // Must init parent properties first! INDI::DefaultDevice::initProperties(); IUFillSwitch(&ShutterS[0], "Open", "", ISS_ON); IUFillSwitch(&ShutterS[1], "Close", "", ISS_OFF); IUFillSwitchVector(&ShutterSP, ShutterS, 2, getDeviceName(), "Shutter Door", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); // We init here the property we wish to "snoop" from the target device IUFillLight(&RainL[0], "Status", "", IPS_IDLE); // Make sure to set the device name to "Rain Detector" since we are snooping on rain detector device. IUFillLightVector(&RainLP, RainL, 1, "Rain Detector", "Rain Alert", "", MAIN_CONTROL_TAB, IPS_IDLE); return true; } /******************************************************************************************** ** INDI is asking us to update the properties because there is a change in CONNECTION status ** This fucntion is called whenever the device is connected or disconnected. *********************************************************************************************/ bool Dome::updateProperties() { // Call parent update properties first INDI::DefaultDevice::updateProperties(); if (isConnected()) { defineSwitch(&ShutterSP); /* Let's listen for Rain Alert property in the device Rain */ IDSnoopDevice("Rain Detector", "Rain Alert"); } else // We're disconnected deleteProperty(ShutterSP.name); return true; } /******************************************************************************************** ** Client is asking us to update a switch *********************************************************************************************/ bool Dome::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if (!strcmp(dev, getDeviceName())) { if (!strcmp(name, ShutterSP.name)) { IUUpdateSwitch(&ShutterSP, states, names, n); ShutterSP.s = IPS_BUSY; if (ShutterS[0].s == ISS_ON) { if (RainL[0].s == IPS_ALERT) { ShutterSP.s = IPS_ALERT; ShutterS[0].s = ISS_OFF; ShutterS[1].s = ISS_ON; IDSetSwitch(&ShutterSP, "It is raining, cannot open Shutter."); return true; } IDSetSwitch(&ShutterSP, "Shutter is opening."); } else IDSetSwitch(&ShutterSP, "Shutter is closing."); sleep(5); ShutterSP.s = IPS_OK; if (ShutterS[0].s == ISS_ON) IDSetSwitch(&ShutterSP, "Shutter is open."); else IDSetSwitch(&ShutterSP, "Shutter is closed."); return true; } } return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n); } /******************************************************************************************** ** We received snooped property update from rain detector device *********************************************************************************************/ bool Dome::ISSnoopDevice(XMLEle *root) { IPState old_state = RainL[0].s; /* If the "Rain Alert" property gets updated in the Rain device, we will receive a notification. We need to process the new values of Rain Alert and update the local version of the property.*/ if (IUSnoopLight(root, &RainLP) == 0) { // If the dome is connected and rain is Alert */ if (RainL[0].s == IPS_ALERT) { // If dome is open, then close it */ if (ShutterS[0].s == ISS_ON) closeShutter(); else IDMessage(getDeviceName(), "Rain Alert Detected! Dome is already closed."); } else if (old_state == IPS_ALERT && RainL[0].s != IPS_ALERT) IDMessage(getDeviceName(), "Rain threat passed. Opening the dome is now safe."); return true; } return false; } /******************************************************************************************** ** Close shutter *********************************************************************************************/ void Dome::closeShutter() { ShutterSP.s = IPS_BUSY; IDSetSwitch(&ShutterSP, "Rain Alert! Shutter is closing..."); sleep(5); ShutterS[0].s = ISS_OFF; ShutterS[1].s = ISS_ON; ShutterSP.s = IPS_OK; IDSetSwitch(&ShutterSP, "Shutter is closed."); } libindi-0.9.7/examples/tutorial_five/raindetector.cpp0000644000175000017500000001255112241463551022011 0ustar jasemjasem/* INDI Developers Manual Tutorial #5 - Snooping Rain Detector Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file raindetector.cpp \brief Construct a rain detector device that the user may operate to raise a rain alert. This rain light property defined by this driver is \e snooped by the Dome driver then takes whatever appropiate action to protect the dome. \author Jasem Mutlaq */ #include #include "raindetector.h" std::auto_ptr rainDetector(0); void ISInit() { static int isInit =0; if (isInit == 1) return; isInit = 1; if(rainDetector.get() == 0) rainDetector.reset(new RainDetector()); } void ISGetProperties(const char *dev) { ISInit(); rainDetector->ISGetProperties(dev); } void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num) { ISInit(); rainDetector->ISNewSwitch(dev, name, states, names, num); } void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num) { ISInit(); rainDetector->ISNewText(dev, name, texts, names, num); } void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num) { ISInit(); rainDetector->ISNewNumber(dev, name, values, names, num); } void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } void ISSnoopDevice (XMLEle *root) { ISInit(); rainDetector->ISSnoopDevice(root); } RainDetector::RainDetector() { } /************************************************************************************** ** Client is asking us to establish connection to the device ***************************************************************************************/ bool RainDetector::Connect() { IDMessage(getDeviceName(), "Rain Detector connected successfully!"); return true; } /************************************************************************************** ** Client is asking us to terminate connection to the device ***************************************************************************************/ bool RainDetector::Disconnect() { IDMessage(getDeviceName(), "Rain Detector disconnected successfully!"); return true; } /************************************************************************************** ** INDI is asking us for our default device name ***************************************************************************************/ const char * RainDetector::getDefaultName() { return "Rain Detector"; } /************************************************************************************** ** INDI is asking us to init our properties. ***************************************************************************************/ bool RainDetector::initProperties() { // Must init parent properties first! INDI::DefaultDevice::initProperties(); IUFillLight(&RainL[0], "Status", "", IPS_IDLE); IUFillLightVector(&RainLP, RainL, 1, getDeviceName(), "Rain Alert", "", MAIN_CONTROL_TAB, IPS_IDLE); IUFillSwitch(&RainS[0], "On", "", ISS_OFF); IUFillSwitch(&RainS[1], "Off", "", ISS_OFF); IUFillSwitchVector(&RainSP, RainS, 2, getDeviceName(), "Control Rain", "", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); return true; } /******************************************************************************************** ** INDI is asking us to update the properties because there is a change in CONNECTION status ** This fucntion is called whenever the device is connected or disconnected. *********************************************************************************************/ bool RainDetector::updateProperties() { // Call parent update properties first INDI::DefaultDevice::updateProperties(); if (isConnected()) { defineLight(&RainLP); defineSwitch(&RainSP); } else // We're disconnected { deleteProperty(RainLP.name); deleteProperty(RainSP.name); } return true; } /******************************************************************************************** ** Client is asking us to update a switch *********************************************************************************************/ bool RainDetector::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if (!strcmp(dev, getDeviceName())) { if (!strcmp(name, RainSP.name)) { IUUpdateSwitch(&RainSP, states, names, n); if (RainS[0].s == ISS_ON) { RainL[0].s = IPS_ALERT; RainLP.s = IPS_ALERT; IDSetLight(&RainLP, "Alert! Alert! Rain detected!"); } else { RainL[0].s = IPS_IDLE; RainLP.s = IPS_OK; IDSetLight(&RainLP, "Rain threat passed. The skies are clear."); } RainSP.s = IPS_OK; IDSetSwitch(&RainSP, NULL); return true; } } return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n); } libindi-0.9.7/examples/tutorial_five/dome.h0000644000175000017500000000370312241463551017716 0ustar jasemjasem#ifndef DOME_H #define DOME_H /* INDI Developers Manual Tutorial #5 - Snooping Dome Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ /** \file dome.h \brief Construct a dome device that the user may operate to open or close the dome shutter door. This driver is \e snooping on the Rain Detector rain property status. If rain property state is alert, we close the dome shutter door if it is open, and we prevent the user from opening it until the rain threat passes. \author Jasem Mutlaq \example dome.h The dome driver \e snoops on the rain detector signal and watches whether rain is detected or not. If it is detector and the dome is closed, it performs no action, but it also prevents you from opening the dome due to rain. If the dome is open, it will automatically starts closing the shutter. In order snooping to work, both drivers must be started by the same indiserver (or chained INDI servers): \code indiserver tutorial_dome tutorial_rain \endcode The dome driver keeps a copy of RainL light property from the rain driver. This makes it easy to parse the property status once an update from the rain driver arrives in the dome driver. Alternatively, you can directly parse the XML root element in ISSnoopDevice(XMLEle *root) to extract the required data. */ #include "indibase/defaultdevice.h" class Dome : public INDI::DefaultDevice { public: Dome(); bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); bool ISSnoopDevice (XMLEle *root); protected: // General device functions bool Connect(); bool Disconnect(); const char *getDefaultName(); bool initProperties(); bool updateProperties(); private: void closeShutter(); ISwitch ShutterS[2]; ISwitchVectorProperty ShutterSP; ILight RainL[1]; ILightVectorProperty RainLP; }; #endif // DOME_H libindi-0.9.7/examples/tutorial_five/raindetector.h0000644000175000017500000000232112241463551021450 0ustar jasemjasem#ifndef RAINDETECTOR_H #define RAINDETECTOR_H /* INDI Developers Manual Tutorial #5 - Snooping Rain Detector Refer to README, which contains instruction on how to build this driver, and use it with an INDI-compatible client. */ #include "indibase/defaultdevice.h" /** \file raindetector.h * \brief Construct a rain detector device that the user may operate to raise a rain alert. This rain light property defined by this driver is \e snooped by the Dome driver * then takes whatever appropiate action to protect the dome. * \author Jasem Mutlaq * * \example raindetector.h * The rain detector emits a signal each time it detects raid. This signal is \e snooped by the dome driver. */ class RainDetector : public INDI::DefaultDevice { public: RainDetector(); bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); protected: // General device functions bool Connect(); bool Disconnect(); const char *getDefaultName(); bool initProperties(); bool updateProperties(); private: ILight RainL[1]; ILightVectorProperty RainLP; ISwitch RainS[2]; ISwitchVectorProperty RainSP; }; #endif // RAINDETECTOR_H libindi-0.9.7/INSTALL0000644000175000017500000000101312241463551013150 0ustar jasemjasemINDI Library Setup 0.9.6 ======================== You must have CMake >= 2.4.7 in order to build this package. 1) $ tar -xzf libindi.tar.gz 2) $ mkdir libindi_build 3) $ cd libindi_build 4) $ cmake -DCMAKE_INSTALL_PREFIX=/usr . ../libindi 5) $ su -c 'make install' or sudo make install Refer to README for instructions on running indiserver and device drivers. Refer to README.drivers for driver-specific information. Dependencies ============ + libusb-dev + libusb-1.0-0-dev + libnova >= 0.12.2 + cfitsio >= 3.0 libindi-0.9.7/AUTHORS0000644000175000017500000000041612241463551013175 0ustar jasemjasemJasem Mutlaq Elwood C. Downey INDI drivers were written by numerous volunteers across the globe. Please refer to each driver to find the author's contact info. Thank you for making INDI such a great software! libindi-0.9.7/fq.c0000644000175000017500000001353212241463551012702 0ustar jasemjasem/* a fifo queue that never fills. * Copyright (C) 2005 Elwood C. Downey ecdowney@clearskyinstitute.com * includes standalone commandline test program, see below. 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 */ /** \file fq.c \brief a fifo queue that never fills. Generic FIFO Queue. an FQ is a FIFO list of pointers to void, each called an "element". elements are added at q[head]. there are (nq) elements in the list. the element to be removed next is q[head-nq]. there are (head-nq) empty slots at the front of the q array. there are (nmem-head) elements available at the end. if the head reaches the end, existing enties are slid to the front of the array and total memory is adjusted up or down as required. example: <-------------------- nmem = 17 ---------------------------------> <-- head - nq = 6 ---> <-- nq = 4 --> <---- nmem - head = 7 --> --------------------------------------------------------------------- | | | | | | | x | x | x | x | | | | | | | | --------------------------------------------------------------------- 0 1 2 3 4 5 6 7 8 9 ^ head = 10 \author Elwood Downey */ #include #include #include "fq.h" struct _FQ { void **q; /* malloced array of (void *) */ int nq; /* number of elements on queue */ int head; /* index into q[] of next empty spot */ int nmem; /* number of total slots in q[] */ int grow; /* n elements to grow when out of room*/ }; /* default memory managers, override with setMemFuncsFQ() */ static void *(*mymalloc)(size_t size) = malloc; static void *(*myrealloc)(void *ptr, size_t size) = realloc; static void (*myfree)(void *ptr) = free; static void chkFQ (FQ *q); /* return pointer to a new FQ, or NULL if no more memory. * grow is an efficiency hint of the number of elements to grow when out of * room, nothing terrible happens if it is wrong. */ FQ * newFQ (int grow) { FQ *q = (FQ *)(*mymalloc)(sizeof(FQ)); memset (q, 0, sizeof(FQ)); q->q = (*mymalloc) (1); /* seed for realloc */ q->grow = grow > 0 ? grow : 1; return (q); } /* delete a FQ no longer needed */ void delFQ (FQ *q) { (*myfree) (q->q); /* guaranteed set in newFQ() */ (*myfree) ((void *)q); } /* push an element onto the given FQ */ void pushFQ (FQ *q, void *e) { chkFQ (q); q->q[q->head++] = e; q->nq++; } /* pop and return the next element in the given FQ, or NULL if empty */ void * popFQ (FQ *q) { return (q->nq > 0 ? q->q[q->head - q->nq--] : NULL); } /* return next element in the given FQ leaving it on the q, or NULL if empty */ void * peekFQ (FQ *q) { return (peekiFQ(q,0)); } /* return ith element from head of the given FQ. * this can be used for iteration as: * for (i = 0; i < nFQ(q); i++) * void *e = peekiFQ(q,i); */ void * peekiFQ (FQ *q, int i) { return (q->nq > 0 ? q->q[q->head - q->nq + i] : NULL); } /* return the number of elements in the given FQ */ int nFQ (FQ *q) { return (q->nq); } /* install new version of malloc/realloc/free. * N.B. don't call after first use of any other FQ function */ void setMemFuncsFQ (void *(*newmalloc)(size_t size), void *(*newrealloc)(void *ptr, size_t size), void (*newfree)(void *ptr)) { mymalloc = newmalloc; myrealloc = newrealloc; myfree = newfree; } /* insure q can hold one more element */ static void chkFQ (FQ *q) { int infront; /* done if still room at end */ if (q->nmem > q->head) return; /* move list to front */ infront = q->head - q->nq; memmove (q->q, &q->q[infront], q->nq * sizeof(void*)); q->head -= infront; /* realloc to minimum number of grow-sized chunks required */ q->nmem = q->grow*(q->head/q->grow+1); q->q = (*myrealloc) (q->q, q->nmem * sizeof(void*)); } #if defined(TEST_FQ) /* to build a stand-alone commandline test program: * cc -DTEST_FQ -o fq fq.c * run ./fq to test push/pop/peek and watch the queue after each operation. * the queue test elements are char, please excuse the ugly casts. */ #include /* draw a simple graphical representation of the given FQ */ static void prFQ (FQ *q) { int i; /* print the q, empty slots print as '.' */ for (i = 0; i < q->nmem; i++) { if (i >= q->head - q->nq && i < q->head) printf ("%c", (char)(int)q->q[i]); else printf ("."); } /* add right-justified stats */ printf ("%*s nmem = %2d head = %2d nq = %2d\n", 50-i, "", q->nmem, q->head, q->nq); } int main (int ac, char *av[]) { FQ *q = newFQ(8); int c, e = -1; void *p; printf ("Commands:\n"); printf (" P = push a letter a-z\n"); printf (" p = pop a letter\n"); printf (" k = peek into queue\n"); while ((c = fgetc(stdin)) != EOF) { switch (c) { case 'P': pushFQ (q, (void*)('a'+(e=(e+1)%26))); prFQ(q); break; case 'p': p = popFQ (q); if (p) printf ("popped %c\n", (char)(int)p); else printf ("popped empty q\n"); prFQ(q); break; case 'k': p = peekFQ (q); if (p) printf ("peeked %c\n", (char)(int)p); else printf ("peeked empty q\n"); prFQ(q); break; default: break; } } return (0); } #endif /* TEST_FQ */ libindi-0.9.7/.cproject0000644000175000017500000007342612241463551013752 0ustar jasemjasem libindi-0.9.7/COPYING.BSD0000644000175000017500000000320012241463551013561 0ustar jasemjasemFiles: cmake/* Copyright: Bryan Donlan Carsten Niehaus 2006, Alexander Neundorf 2006, Allen Winter 2006, 2008, 2011, Jasem Mutlaq 2009, Geoffrey Hausheer License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. libindi-0.9.7/.project0000644000175000017500000000032712241463551013575 0ustar jasemjasem Project-Source@libindi libindi-0.9.7/eventloop.c0000644000175000017500000003034712241463551014312 0ustar jasemjasem#if 0 INDI Copyright (C) 2003 Elwood C. Downey 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 /* suite of functions to implement an event driven program. * * callbacks may be registered that are triggered when a file descriptor * will not block when read; * * timers may be registered that will run no sooner than a specified delay from * the moment they were registered; * * work procedures may be registered that are called when there is nothing * else to do; * #define MAIN_TEST for a stand-alone test program. */ #include #include #include #include #include #include #include #include #include "eventloop.h" /* info about one registered callback. * the malloced array cback is never shrunk, entries are reused. new id's are * the index of first unused slot in array (and thus reused like unix' open(2)). */ typedef struct { int in_use; /* flag to mark this record is active */ int fd; /* fd descriptor to watch for read */ void *ud; /* user's data handle */ CBF *fp; /* callback function */ } CB; static CB *cback; /* malloced list of callbacks */ static int ncback; /* n entries in cback[] */ static int ncbinuse; /* n entries in cback[] marked in_use */ static int lastcb; /* cback index of last cb called */ /* info about one registered timer function. * the entries are kept sorted by decreasing time from epoch, ie, * the next entry to fire is at the end of the array. */ typedef struct { double tgo; /* trigger time, ms from epoch */ void *ud; /* user's data handle */ TCF *fp; /* timer function */ int tid; /* unique id for this timer */ } TF; static TF *timef; /* malloced list of timer functions */ static int ntimef; /* n entries in ntimef[] */ static int tid; /* source of unique timer ids */ #define EPOCHDT(tp) /* ms from epoch to timeval *tp */ \ (((tp)->tv_usec)/1000.0 + ((tp)->tv_sec)*1000.0) /* info about one registered work procedure. * the malloced array wproc is never shrunk, entries are reused. new id's are * the index of first unused slot in array (and thus reused like unix' open(2)). */ typedef struct { int in_use; /* flag to mark this record is active */ void *ud; /* user's data handle */ WPF *fp; /* work proc function function */ } WP; static WP *wproc; /* malloced list of work procedures */ static int nwproc; /* n entries in wproc[] */ static int nwpinuse; /* n entries in wproc[] marked in-use */ static int lastwp; /* wproc index of last workproc called*/ static void runWorkProc (void); static void callCallback(fd_set *rfdp); static void checkTimer(); static void oneLoop(void); static void deferTO (void *p); /* inf loop to dispatch callbacks, work procs and timers as necessary. * never returns. */ void eventLoop() { /* run loop forever */ while (1) oneLoop(); } /* allow other timers/callbacks/workprocs to run until time out in maxms * or *flagp becomes non-0. wait forever if maxms is 0. * return 0 if flag did flip, else -1 if never changed and we timed out. * the expected usage for this is for the caller to arrange for a T/C/W to set * a flag, then give caller an in-line way to wait for the flag to change. */ int deferLoop (int maxms, int *flagp) { int toflag = 0; int totid = maxms ? addTimer (maxms, deferTO, &toflag) : 0; while (!*flagp) { oneLoop(); if (toflag) return (-1); /* totid already dead */ } if (totid) rmTimer (totid); return (0); } /* allow other timers/callbacks/workprocs to run until time out in maxms * or *flagp becomes 0. wait forever if maxms is 0. * return 0 if flag did flip, else -1 if never changed and we timed out. * the expected usage for this is for the caller to arrange for a T/C/W to set * a flag, then give caller an in-line way to wait for the flag to change. */ int deferLoop0 (int maxms, int *flagp) { int toflag = 0; int totid = maxms ? addTimer (maxms, deferTO, &toflag) : 0; while (*flagp) { oneLoop(); if (toflag) return (-1); /* totid already dead */ } if (totid) rmTimer (totid); return (0); } /* register a new callback, fp, to be called with ud as arg when fd is ready. * return a unique callback id for use with rmCallback(). */ int addCallback (int fd, CBF *fp, void *ud) { CB *cp; /* reuse first unused slot or grow */ for (cp = cback; cp < &cback[ncback]; cp++) if (!cp->in_use) break; if (cp == &cback[ncback]) { cback = cback ? (CB *) realloc (cback, (ncback+1)*sizeof(CB)) : (CB *) malloc (sizeof(CB)); cp = &cback[ncback++]; } /* init new entry */ cp->in_use = 1; cp->fp = fp; cp->ud = ud; cp->fd = fd; ncbinuse++; /* id is index into array */ return (cp - cback); } /* remove the callback with the given id, as returned from addCallback(). * silently ignore if id not valid. */ void rmCallback (int cid) { CB *cp; /* validate id */ if (cid < 0 || cid >= ncback) return; cp = &cback[cid]; if (!cp->in_use) return; /* mark for reuse */ cp->in_use = 0; ncbinuse--; } /* register a new timer function, fp, to be called with ud as arg after ms * milliseconds. add to list in order of decreasing time from epoch, ie, * last entry runs soonest. return id for use with rmTimer(). */ int addTimer (int ms, TCF *fp, void *ud) { struct timeval t; TF *tp; /* get time now */ gettimeofday (&t, NULL); /* add one entry */ timef = timef ? (TF *) realloc (timef, (ntimef+1)*sizeof(TF)) : (TF *) malloc (sizeof(TF)); tp = &timef[ntimef++]; /* init new entry */ tp->ud = ud; tp->fp = fp; tp->tgo = EPOCHDT(&t) + ms; /* insert maintaining sort */ for ( ; tp > timef && tp[0].tgo > tp[-1].tgo; tp--) { TF tmptf = tp[-1]; tp[-1] = tp[0]; tp[0] = tmptf; } /* store and return new unique id */ return (tp->tid = ++tid); } /* remove the timer with the given id, as returned from addTimer(). * silently ignore if id not found. */ void rmTimer (int timer_id) { TF *tp; /* find it */ for (tp = timef; tp < &timef[ntimef]; tp++) if (tp->tid == timer_id) break; if (tp == &timef[ntimef]) return; /* bubble it out */ for (++tp; tp < &timef[ntimef]; tp++) tp[-1] = tp[0]; /* shrink list */ timef = (TF *) realloc (timef, (--ntimef)*sizeof(TF)); } /* add a new work procedure, fp, to be called with ud when nothing else to do. * return unique id for use with rmWorkProc(). */ int addWorkProc (WPF *fp, void *ud) { WP *wp; /* reuse first unused slot or grow */ for (wp = wproc; wp < &wproc[nwproc]; wp++) if (!wp->in_use) break; if (wp == &wproc[nwproc]) { wproc = wproc ? (WP *) realloc (wproc, (nwproc+1)*sizeof(WP)) : (WP *) malloc (sizeof(WP)); wp = &wproc[nwproc++]; } /* init new entry */ wp->in_use = 1; wp->fp = fp; wp->ud = ud; nwpinuse++; /* id is index into array */ return (wp - wproc); } /* remove the work proc with the given id, as returned from addWorkProc(). * silently ignore if id not found. */ void rmWorkProc (int wid) { WP *wp; /* validate id */ if (wid < 0 || wid >= nwproc) return; wp = &wproc[wid]; if (!wp->in_use) return; /* mark for reuse */ wp->in_use = 0; nwpinuse--; } /* run next work procedure */ static void runWorkProc () { WP *wp; /* skip if list is empty */ if (!nwpinuse) return; /* find next */ do { lastwp = (lastwp+1) % nwproc; wp = &wproc[lastwp]; } while (!wp->in_use); /* run */ (*wp->fp) (wp->ud); } /* run next callback whose fd is listed as ready to go in rfdp */ static void callCallback(fd_set *rfdp) { CB *cp; /* skip if list is empty */ if (!ncbinuse) return; /* find next */ do { lastcb = (lastcb+1) % ncback; cp = &cback[lastcb]; } while (!cp->in_use || !FD_ISSET (cp->fd, rfdp)); /* run */ (*cp->fp) (cp->fd, cp->ud); } /* run the next timer callback whose time has come, if any. all we have to do * is is check the last entry in timef[] because it is sorted in decreasing * order of time from epoch to run, ie, last entry runs soonest. */ static void checkTimer() { struct timeval now; double tgonow; TF *tp; /* skip if list is empty */ if (!ntimef) return; gettimeofday (&now, NULL); tgonow = EPOCHDT (&now); tp = &timef[ntimef-1]; if (tp->tgo <= tgonow) { ntimef--; /* pop then call */ (*tp->fp) (tp->ud); } } /* check fd's from each active callback. * if any ready, call their callbacks else call each registered work procedure. */ static void oneLoop() { struct timeval tv, *tvp; fd_set rfd; CB *cp; int maxfd, ns; /* build list of callback file descriptors to check */ FD_ZERO (&rfd); maxfd = -1; for (cp = cback; cp < &cback[ncback]; cp++) { if (cp->in_use) { FD_SET (cp->fd, &rfd); if (cp->fd > maxfd) maxfd = cp->fd; } } /* determine timeout: * if there are work procs * set delay = 0 * else if there is at least one timer func * set delay = time until soonest timer func expires * else * set delay = forever */ if (nwpinuse > 0) { tvp = &tv; tvp->tv_sec = tvp->tv_usec = 0; } else if (ntimef > 0) { struct timeval now; double late; gettimeofday (&now, NULL); late = timef[ntimef-1].tgo - EPOCHDT (&now); /* ms late */ if (late < 0) late = 0; late /= 1000.0; /* secs late */ tvp = &tv; tvp->tv_sec = (long)floor(late); tvp->tv_usec = (long)floor((late - tvp->tv_sec)*1000000.0); } else tvp = NULL; /* check file descriptors, timeout depending on pending work */ ns = select (maxfd+1, &rfd, NULL, NULL, tvp); if (ns < 0) { perror ("select"); return; } /* dispatch */ checkTimer(); if (ns == 0) runWorkProc(); else callCallback(&rfd); } /* timer callback used to implement deferLoop(). * arg is pointer to int which we set to 1 */ static void deferTO (void *p) { *(int*)p = 1; } #if defined(MAIN_TEST) /* make a small stand-alone test program. */ #include #include int mycid; int mywid; int mytid; int user_a; int user_b; int counter; void wp (void *ud) { struct timeval tv; gettimeofday (&tv, NULL); printf ("workproc @ %ld.%03ld %d %d\n", (long)tv.tv_sec, (long)tv.tv_usec/1000, counter, ++(*(int*)ud)); } void to (void *ud) { printf ("timeout %d\n", (int)ud); } void stdinCB (int fd, void *ud) { char c; if (read (fd, &c, 1) != 1) { perror ("read"); return; } switch (c) { case '+': counter++; break; case '-': counter--; break; case 'W': mywid = addWorkProc (wp, &user_b); break; case 'w': rmWorkProc (mywid); break; case 'c': rmCallback (mycid); break; case 't': rmTimer (mytid); break; case '1': mytid = addTimer (1000, to, (void *)1); break; case '2': mytid = addTimer (2000, to, (void *)2); break; case '3': mytid = addTimer (3000, to, (void *)3); break; case '4': mytid = addTimer (4000, to, (void *)4); break; case '5': mytid = addTimer (5000, to, (void *)5); break; default: return; /* silently absorb other chars like \n */ } printf ("callback: %d\n", ++(*(int*)ud)); } int main (int ac, char *av[]) { (void) addCallback (0, stdinCB, &user_a); eventLoop(); exit(0); } #endif libindi-0.9.7/tools/0000755000175000017500000000000012241463551013264 5ustar jasemjasemlibindi-0.9.7/tools/setINDIproperty.c0000644000175000017500000003511712241463551016503 0ustar jasemjasem/* connect to an INDI server and set one or more device.property.element. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "indiapi.h" #include "lilxml.h" /* table of INDI definition elements we can set * N.B. do not change defs[] order, they are indexed via -x/-n/-s args */ typedef struct { char *defType; /* defXXXVector name */ char *defOne; /* defXXX name */ char *newType; /* newXXXVector name */ char *oneType; /* oneXXX name */ } INDIDef; static INDIDef defs[] = { {"defTextVector", "defText", "newTextVector", "oneText"}, {"defNumberVector", "defNumber", "newNumberVector", "oneNumber"}, {"defSwitchVector", "defSwitch", "newSwitchVector", "oneSwitch"}, }; #define NDEFS (sizeof(defs)/sizeof(defs[0])) #define INDIPORT 7624 /* default port */ static char host_def[] = "localhost"; /* default host name */ static char *me; /* our name for usage message */ static char *host = host_def; /* working host name */ static int port = INDIPORT; /* working port number */ static int verbose; /* report extra info */ static int directfd = -1; /* direct filedes to server, if >= 0 */ #define TIMEOUT 2 /* default timeout, secs */ static int timeout = TIMEOUT; /* working timeout, secs */ static LilXML *lillp; /* XML parser context */ typedef struct { char *e, *v; /* element name and value */ int ok; /* set when found */ } SetEV; typedef struct { char *d; /* device */ char *p; /* property */ SetEV *ev; /* elements */ int nev; /* n elements */ INDIDef *dp; /* one of defs if known, else NULL */ } SetSpec; static SetSpec *sets; /* set of properties to set */ static int nsets; static void usage (void); static int crackSpec (int *acp, char **avp[]); static void openINDIServer(FILE **rfpp, FILE **wfpp); static void listenINDI (FILE *rfp, FILE *wfp); static int finished (void); static void onAlarm (int dummy); static int readServerChar (FILE *fp); static void findSet (XMLEle *root, FILE *fp); static void scanEV (SetSpec *specp, char ev[]); static void scanEEVV (SetSpec *specp, char *ep, char ev[]); static void scanEVEV (SetSpec *specp, char ev[]); static void sendNew (FILE *fp, INDIDef *dp, SetSpec *sp); static void sendSpecs(FILE *wfp); int main (int ac, char *av[]) { FILE *rfp, *wfp; int stop = 0; int allspeced; /* save our name */ me = av[0]; /* crack args */ while (!stop && --ac && **++av == '-') { char *s = *av; while (*++s) { switch (*s) { case 'd': if (ac < 2) { fprintf (stderr, "-d requires open fileno\n"); usage(); } directfd = atoi(*++av); ac--; break; case 'h': if (directfd >= 0) { fprintf (stderr, "Can not combine -d and -h\n"); usage(); } if (ac < 2) { fprintf (stderr, "-h requires host name\n"); usage(); } host = *++av; ac--; break; case 'p': if (directfd >= 0) { fprintf (stderr, "Can not combine -d and -p\n"); usage(); } if (ac < 2) { fprintf (stderr, "-p requires tcp port number\n"); usage(); } port = atoi(*++av); ac--; break; case 't': if (ac < 2) { fprintf (stderr, "-t requires timeout\n"); usage(); } timeout = atoi(*++av); ac--; break; case 'v': /* verbose */ verbose++; break; case 'x': /* FALLTHRU */ case 'n': /* FALLTHRU */ case 's': /* stop if see one of the property types */ stop = 1; break; default: fprintf (stderr, "Unknown flag: %c\n", *s); usage(); } } } /* now ac args starting at av[0] */ if (ac < 1) usage(); /* crack each property, add to sets[] */ allspeced = 1; do { if (!crackSpec (&ac, &av)) allspeced = 0; } while (ac > 0); /* open connection */ if (directfd >= 0) { wfp = fdopen (directfd, "w"); rfp = fdopen (directfd, "r"); setbuf (rfp, NULL); /* don't absorb next guy's stuff */ if (!rfp || !wfp) { fprintf (stderr, "Direct fd %d: %s\n",directfd,strerror(errno)); exit(1); } if (verbose) fprintf (stderr, "Using direct fd %d\n", directfd); } else { openINDIServer(&rfp, &wfp); if (verbose) fprintf (stderr, "Connected to %s on port %d\n", host, port); } /* build a parser context for cracking XML responses */ lillp = newLilXML(); /* just send it all speced, else check with server */ if (allspeced) { sendSpecs(wfp); } else { /* issue getProperties */ if (verbose) fprintf (stderr, "Querying for properties\n"); fprintf(wfp, "\n", INDIV); fflush (wfp); /* listen for properties, set when see any we recognize */ listenINDI(rfp, wfp); } return (0); } static void usage() { fprintf(stderr, "Purpose: set one or more writable INDI properties\n"); fprintf(stderr, "%s\n", "$Revision: 1.6 $"); fprintf(stderr, "Usage: %s [options] {[type] spec} ...\n", me); fprintf(stderr, "Options:\n"); fprintf(stderr, " -d f : use file descriptor f already open to server\n"); fprintf(stderr, " -h h : alternate host, default is %s\n", host_def); fprintf(stderr, " -p p : alternate port, default is %d\n", INDIPORT); fprintf(stderr, " -t t : max time to wait, default is %d secs\n",TIMEOUT); fprintf(stderr, " -v : verbose (more are cumulative)\n"); fprintf(stderr, "Each spec optionally preceded by its type is sent without first confirming\n"); fprintf(stderr, "its structure. This is much more efficient but there is no error checking.\n"); fprintf(stderr, "Types are indicated with the following flags:\n"); fprintf(stderr, " -x : Text\n"); fprintf(stderr, " -n : Number\n"); fprintf(stderr, " -s : Switch\n"); fprintf(stderr, "Spec may be either:\n"); fprintf(stderr, " device.property.e1[;e2...]=v1[;v2...]\n"); fprintf(stderr, " or\n"); fprintf(stderr, " device.property.e1=v1[;e2=v2...]\n"); fprintf(stderr, "Exit status:\n"); fprintf(stderr, " 0: all settings successful\n"); fprintf(stderr, " 1: at least one setting was invalid\n"); fprintf(stderr, " 2: real trouble, try repeating with -v\n"); exit (2); } /* crack property set spec, add to sets [], move to next spec. * return 1 if see a type */ static int crackSpec (int *acp, char **avp[]) { char d[128], p[128], ev[2048]; char *spec = *avp[0]; INDIDef *dp = NULL; /* check if first arg is type indicator */ if (spec[0] == '-') { switch (spec[1]) { case 'x': dp = &defs[0]; break; case 'n': dp = &defs[1]; break; case 's': dp = &defs[2]; break; default: fprintf (stderr, "Bad property type: %s\n", spec); usage(); } (*acp)--; (*avp)++; spec = *avp[0]; } /* then scan arg for property spec */ if (sscanf (spec, "%[^.].%[^.].%s", d, p, ev) != 3) { fprintf (stderr, "Malformed property spec: %s\n", spec); usage(); } /* add to list */ if (!sets) sets = (SetSpec *) malloc (1); /* seed realloc */ sets = (SetSpec *) realloc (sets, (nsets+1)*sizeof(SetSpec)); sets[nsets].d = strcpy (malloc(strlen(d)+1), d); sets[nsets].p = strcpy (malloc(strlen(p)+1), p); sets[nsets].dp = dp; sets[nsets].ev = (SetEV *) malloc (1); /* seed realloc */ sets[nsets].nev = 0; scanEV (&sets[nsets++], ev); /* update caller's pointers */ (*acp)--; (*avp)++; /* return 1 if saw a spec */ return (dp ? 1 : 0); } /* open a read and write connection to host and port or die. * exit if trouble. */ static void openINDIServer (FILE **rfpp, FILE **wfpp) { struct sockaddr_in serv_addr; struct hostent *hp; int sockfd; /* lookup host address */ hp = gethostbyname (host); if (!hp) { perror ("gethostbyname"); exit (2); } /* create a socket to the INDI server */ (void) memset ((char *)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr_list[0]))->s_addr; serv_addr.sin_port = htons(port); if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); exit(2); } /* connect */ if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){ perror ("connect"); exit(2); } /* prepare for line-oriented i/o to client */ *rfpp = fdopen (sockfd, "r"); *wfpp = fdopen (sockfd, "w"); } /* listen for property reports, send new sets if match */ static void listenINDI (FILE *rfp, FILE *wfp) { char msg[1024]; /* arrange to call onAlarm() if not seeing any more defXXX */ signal (SIGALRM, onAlarm); alarm (timeout); /* read from server, exit if find all properties */ while (1) { XMLEle *root = readXMLEle (lillp, readServerChar(rfp), msg); if (root) { /* found a complete XML element */ if (verbose > 1) prXMLEle (stderr, root, 0); findSet (root, wfp); if (finished() == 0) { shutdown (fileno(wfp), SHUT_WR); /* insure flush */ exit (0); /* found all we want */ } delXMLEle (root); /* not yet, delete and continue */ } else if (msg[0]) { fprintf (stderr, "Bad XML from %s/%d: %s\n", host, port, msg); exit(2); } } } /* return 0 if we are sure we set everything we wanted to, else -1 */ static int finished () { int i, j; for (i = 0; i < nsets; i++) for (j = 0; j < sets[i].nev; j++) if (!sets[i].ev[j].ok) return (-1); return (0); } /* called after timeout seconds because we did not find something we trying * to set. */ static void onAlarm (int dummy) { int i, j; for (i = 0; i < nsets; i++) for (j = 0; j < sets[i].nev; j++) if (!sets[i].ev[j].ok) fprintf (stderr, "No %s.%s.%s from %s:%d\n", sets[i].d, sets[i].p, sets[i].ev[j].e, host, port); exit (1); } static int readServerChar (FILE *fp) { int c = fgetc (fp); if (c == EOF) { if (ferror(fp)) perror ("read"); else fprintf (stderr,"INDI server %s:%d disconnected\n", host, port); exit (2); } if (verbose > 2) fprintf (stderr, "Read %c\n", c); return (c); } /* issue a set command if it matches the given property */ static void findSet (XMLEle *root, FILE *fp) { char *rtype, *rdev, *rprop; XMLEle *ep; int t, s, i; /* check type */ rtype = tagXMLEle (root); for (t = 0; t < NDEFS; t++) if (strcmp (rtype, defs[t].defType) == 0) break; if (t == NDEFS) return; alarm (timeout); /* reset timeout */ /* check each set for matching device and property name, send if ok */ rdev = (char *) findXMLAttValu (root, "device"); rprop = (char *) findXMLAttValu (root, "name"); if (verbose > 1) fprintf (stderr, "Read definition for %s.%s\n", rdev, rprop); for (s = 0; s < nsets; s++) { if (!strcmp (rdev, sets[s].d) && !strcmp (rprop, sets[s].p)) { /* found device and name, check perm */ if (!strchr (findXMLAttValu (root, "perm"), 'w')) { if (verbose) fprintf (stderr, "%s.%s is read-only\n", rdev, rprop); exit (1); } /* check matching elements */ for (i = 0; i < sets[s].nev; i++) { for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (!strcmp(findXMLAttValu (ep,"name"),sets[s].ev[i].e) && !strcmp(tagXMLEle(ep), defs[t].defOne)) { sets[s].ev[i].ok = 1; break; } } if (!ep) return; /* not in this msg, maybe later */ } /* all element names found, send new values */ sendNew (fp, &defs[t], &sets[s]); } } } /* send the given set specification of the given INDI type to channel on fp */ static void sendNew (FILE *fp, INDIDef *dp, SetSpec *sp) { int i; fprintf (fp, "<%s device='%s' name='%s'>\n", dp->newType, sp->d, sp->p); for (i = 0; i < sp->nev; i++) { if (verbose) fprintf (stderr, " %s.%s.%s <- %s\n", sp->d, sp->p, sp->ev[i].e, sp->ev[i].v); fprintf (fp, " <%s name='%s'>%s\n", dp->oneType, sp->ev[i].e, sp->ev[i].v, dp->oneType); } fprintf (fp, "\n", dp->newType); fflush (fp); if (feof(fp) || ferror(fp)) { fprintf (stderr, "Send error\n"); exit(2); } } /* scan ev for element definitions in either of two forms and add to sp: * e1[;e2...]=v1[;v2...] * or * e1=v1[;e2=v2...] * exit if nothing sensible found. */ static void scanEV (SetSpec *specp, char ev[]) { char *ep, *sp; /* pointers to = and ; */ if (verbose > 1) fprintf (stderr, "Scanning assignments %s\n", ev); ep = strchr (ev, '='); sp = strchr (ev, ';'); if (!ep) { fprintf (stderr, "Malformed assignment: %s\n", ev); usage(); } if (sp < ep) scanEEVV (specp, ep, ev); /* including just one E=V */ else scanEVEV (specp, ev); } /* add specs of the form e1[;e2...]=v1[;v2...] to sp. * v is pointer to equal sign. * exit if trouble. * N.B. e[] and v[] are modified in place. */ static void scanEEVV (SetSpec *sp, char *v, char *e) { static char sep[] = ";"; char *ec, *vc; *v++ = '\0'; while (1) { char *e0 = strtok_r (e, sep, &ec); char *v0 = strtok_r (v, sep, &vc); if (!e0 && !v0) break; if (!e0) { fprintf (stderr, "More values than elements for %s.%s\n", sp->d, sp->p); exit(2); } if (!v0) { fprintf (stderr, "More elements than values for %s.%s\n", sp->d, sp->p); exit(2); } sp->ev = (SetEV *) realloc (sp->ev, (sp->nev+1)*sizeof(SetEV)); sp->ev[sp->nev].e = strcpy (malloc(strlen(e0)+1), e0); sp->ev[sp->nev].v = strcpy (malloc(strlen(v0)+1), v0); if (verbose > 1) fprintf (stderr, "Found assignment %s=%s\n", sp->ev[sp->nev].e, sp->ev[sp->nev].v); sp->nev++; e = NULL; v = NULL; } } /* add specs of the form e1=v1[;e2=v2...] to sp. * exit if trouble. * N.B. ev[] is modified in place. */ static void scanEVEV (SetSpec *sp, char ev[]) { char *s, *e; int last = 0; do { s = strchr (ev, ';'); if (s) *s++ = '\0'; else { s = ev + strlen (ev); last = 1; } e = strchr (ev, '='); if (e) *e++ = '\0'; else { fprintf (stderr, "Malformed assignment: %s\n", ev); usage(); } sp->ev = (SetEV *) realloc (sp->ev, (sp->nev+1)*sizeof(SetEV)); sp->ev[sp->nev].e = strcpy (malloc(strlen(ev)+1), ev); sp->ev[sp->nev].v = strcpy (malloc(strlen(e)+1), e); if (verbose > 1) fprintf (stderr, "Found assignment %s=%s\n", sp->ev[sp->nev].e, sp->ev[sp->nev].v); sp->nev++; ev = s; } while (!last); } /* send each SetSpec, all of which have a known type, to wfp */ static void sendSpecs(FILE *wfp) { int i; for (i = 0; i < nsets; i++) sendNew (wfp, sets[i].dp, &sets[i]); } /* For RCS Only -- Do Not Edit */ static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: setINDI.c,v $ $Date: 2010/11/07 07:13:59 $ $Revision: 1.6 $ $Name: $"}; libindi-0.9.7/tools/getINDIproperty.c0000644000175000017500000004032212241463551016461 0ustar jasemjasem/* connect to an INDI server and show all desired device.property.element * with possible wild card * in any category. * All types but BLOBs are handled from their defXXX messages. Receipt of a * defBLOB sends enableBLOB then uses setBLOBVector for the value. BLOBs * are stored in a file dev.nam.elem.format. only .z compression is handled. * exit status: 0 at least some found, 1 some not found, 2 real trouble. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "indiapi.h" #include "lilxml.h" #include "base64.h" #include "zlib.h" /* table of INDI definition elements, plus setBLOB. * we also look for set* if -m */ typedef struct { char *vec; /* vector name */ char *one; /* one element name */ } INDIDef; static INDIDef defs[] = { {"defTextVector", "defText"}, {"defNumberVector", "defNumber"}, {"defSwitchVector", "defSwitch"}, {"defLightVector", "defLight"}, {"defBLOBVector", "defBLOB"}, {"setBLOBVector", "oneBLOB"}, {"setTextVector", "oneText"}, {"setNumberVector", "oneNumber"}, {"setSwitchVector", "oneSwitch"}, {"setLightVector", "oneLight"}, }; static int ndefs = 6; /* or 10 if -m */ /* table of keyword to use in query vs name of INDI defXXX attribute */ typedef struct { char *keyword; char *indiattr; } INDIkwattr; static INDIkwattr kwattr[] = { {"_LABEL", "label"}, {"_GROUP", "group"}, {"_STATE", "state"}, {"_PERM", "perm"}, {"_TO", "timeout"}, {"_TS", "timestamp"}, }; #define NKWA (sizeof(kwattr)/sizeof(kwattr[0])) typedef struct { char *d; /* device to seek */ char *p; /* property to seek */ char *e; /* element to seek */ int wc : 1; /* whether pattern uses wild cards */ int ok : 1; /* something matched this query */ } SearchDef; static SearchDef *srchs; /* properties to look for */ static int nsrchs; static void usage (void); static void crackDPE (char *spec); static void addSearchDef (char *dev, char *prop, char *ele); static void openINDIServer(void); static void getprops(void); static void listenINDI(void); static int finished (void); static void onAlarm (int dummy); static int readServerChar(void); static void findDPE (XMLEle *root); static void findEle (XMLEle *root, char *dev, char *nam, char *defone, SearchDef *sp); static void enableBLOBs(char *dev, char *nam); static void oneBLOB (XMLEle *root, char *dev, char *nam, char *enam, char *p, int plen); static char *me; /* our name for usage() message */ static char host_def[] = "localhost"; /* default host name */ static char *host = host_def; /* working host name */ #define INDIPORT 7624 /* default port */ static int port = INDIPORT; /* working port number */ #define TIMEOUT 2 /* default timeout, secs */ static int timeout = TIMEOUT; /* working timeout, secs */ static int verbose; /* report extra info */ static LilXML *lillp; /* XML parser context */ #define WILDCARD '*' /* show all in this category */ static int onematch; /* only one possible match */ static int justvalue; /* if just one match show only value */ static int monitor; /* keep watching even after seen def */ static int directfd = -1; /* direct filedes to server, if >= 0 */ static FILE *svrwfp; /* FILE * to talk to server */ static FILE *svrrfp; /* FILE * to read from server */ static int wflag; /* show wo properties too */ int main (int ac, char *av[]) { /* save our name */ me = av[0]; /* crack args */ while (--ac && **++av == '-') { char *s = *av; while (*++s) { switch (*s) { case '1': /* just value */ justvalue++; break; case 'd': if (ac < 2) { fprintf (stderr, "-d requires open fileno\n"); usage(); } directfd = atoi(*++av); ac--; break; case 'h': if (directfd >= 0) { fprintf (stderr, "Can not combine -d and -h\n"); usage(); } if (ac < 2) { fprintf (stderr, "-h requires host name\n"); usage(); } host = *++av; ac--; break; case 'm': monitor++; ndefs = 10; /* include set*Vectors too */ break; case 'p': if (directfd >= 0) { fprintf (stderr, "Can not combine -d and -p\n"); usage(); } if (ac < 2) { fprintf (stderr, "-p requires tcp port number\n"); usage(); } port = atoi(*++av); ac--; break; case 't': if (ac < 2) { fprintf (stderr, "-t requires timeout\n"); usage(); } timeout = atoi(*++av); ac--; break; case 'v': /* verbose */ verbose++; break; case 'w': wflag++; break; default: fprintf (stderr, "Unknown flag: %c\n", *s); usage(); } } } /* now ac args starting with av[0] */ if (ac == 0) av[ac++] = "*.*.*"; /* default is get everything */ /* crack each d.p.e */ while (ac--) crackDPE (*av++); onematch = nsrchs == 1 && !srchs[0].wc; /* open connection */ if (directfd >= 0) { svrwfp = fdopen (directfd, "w"); svrrfp = fdopen (directfd, "r"); setbuf (svrrfp, NULL); /* don't absorb next guy's stuff */ if (!svrwfp || !svrrfp) { fprintf (stderr, "Direct fd %d: %s\n",directfd,strerror(errno)); exit(1); } if (verbose) fprintf (stderr, "Using direct fd %d\n", directfd); } else { openINDIServer(); if (verbose) fprintf (stderr, "Connected to %s on port %d\n", host, port); } /* build a parser context for cracking XML responses */ lillp = newLilXML(); /* issue getProperties */ getprops(); /* listen for responses, looking for d.p.e or timeout */ listenINDI(); return (0); } static void usage() { int i; fprintf(stderr, "Purpose: retrieve readable properties from an INDI server\n"); fprintf(stderr, "%s\n", "$Revision: 1.11 $"); fprintf(stderr, "Usage: %s [options] [device.property.element ...]\n",me); fprintf(stderr, " Any component may be \"*\" to match all (beware shell metacharacters).\n"); fprintf(stderr, " Reports all properties if none specified.\n"); fprintf(stderr, " BLOBs are saved in file named device.property.element.format\n"); fprintf(stderr, " In perl try: %s\n", "%props = split (/[=\\n]/, `getINDI`);"); fprintf(stderr, " Set element to one of following to return property attribute:\n"); for (i = 0; i < NKWA; i++) fprintf (stderr, " %10s to report %s\n", kwattr[i].keyword, kwattr[i].indiattr); fprintf(stderr, "Output format: output is fully qualified name=value one per line\n"); fprintf(stderr, " or just value if -1 and exactly one query without wildcards.\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -1 : print just value if expecting exactly one response\n"); fprintf(stderr, " -d f : use file descriptor f already open to server\n"); fprintf(stderr, " -h h : alternate host, default is %s\n", host_def); fprintf(stderr, " -m : keep monitoring for more updates\n"); fprintf(stderr, " -p p : alternate port, default is %d\n", INDIPORT); fprintf(stderr, " -t t : max time to wait, default is %d secs\n",TIMEOUT); fprintf(stderr, " -v : verbose (cumulative)\n"); fprintf(stderr, " -w : show write-only properties too\n"); fprintf(stderr, "Exit status:\n"); fprintf(stderr, " 0: found at least one match for each query\n"); fprintf(stderr, " 1: at least one query returned nothing\n"); fprintf(stderr, " 2: real trouble, try repeating with -v\n"); exit (2); } /* crack spec and add to srchs[], else exit */ static void crackDPE (char *spec) { char d[1024], p[1024], e[1024]; if (verbose) fprintf (stderr, "looking for %s\n", spec); if (sscanf (spec, "%[^.].%[^.].%[^.]", d, p, e) != 3) { fprintf (stderr, "Unknown format for property spec: %s\n", spec); usage(); } addSearchDef (d, p, e); } /* grow srchs[] with the new search */ static void addSearchDef (char *dev, char *prop, char *ele) { if (!srchs) srchs = (SearchDef *) malloc (1); /* realloc seed */ srchs = (SearchDef *) realloc (srchs, (nsrchs+1)*sizeof(SearchDef)); srchs[nsrchs].d = strcpy (malloc(strlen(dev)+1), dev); srchs[nsrchs].p = strcpy (malloc(strlen(prop)+1), prop); srchs[nsrchs].e = strcpy (malloc(strlen(ele)+1), ele); srchs[nsrchs].wc = *dev==WILDCARD || *prop==WILDCARD || *ele==WILDCARD; srchs[nsrchs].ok = 0; nsrchs++; } /* open a connection to the given host and port. * set svrwfp and svrrfp or die. */ static void openINDIServer (void) { struct sockaddr_in serv_addr; struct hostent *hp; int sockfd; /* lookup host address */ hp = gethostbyname (host); if (!hp) { herror ("gethostbyname"); exit (2); } /* create a socket to the INDI server */ (void) memset ((char *)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr_list[0]))->s_addr; serv_addr.sin_port = htons(port); if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); exit(2); } /* connect */ if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){ perror ("connect"); exit(2); } /* prepare for line-oriented i/o with client */ svrwfp = fdopen (sockfd, "w"); svrrfp = fdopen (sockfd, "r"); } /* issue getProperties to svrwfp, possibly constrained to one device */ static void getprops() { char *onedev = NULL; int i; /* find if only need one device */ for (i = 0; i < nsrchs; i++) { char *d = srchs[i].d; if (*d == WILDCARD || (onedev && strcmp(d,onedev))) { onedev = NULL; break; } else onedev = d; } if (onedev) fprintf(svrwfp, "\n", INDIV, onedev); else fprintf(svrwfp, "\n", INDIV); fflush (svrwfp); if (verbose) fprintf (stderr, "Queried properties from %s\n", onedev?onedev:"*"); } /* listen for INDI traffic on svrrfp. * print matching srchs[] and return when see all. * timeout and exit if any trouble. */ static void listenINDI () { char msg[1024]; /* arrange to call onAlarm() if not seeing any more defXXX */ signal (SIGALRM, onAlarm); alarm (timeout); /* read from server, exit if find all requested properties */ while (1) { XMLEle *root = readXMLEle (lillp, readServerChar(), msg); if (root) { /* found a complete XML element */ if (verbose > 1) prXMLEle (stderr, root, 0); findDPE (root); if (finished() == 0) exit (0); /* found all we want */ delXMLEle (root); /* not yet, delete and continue */ } else if (msg[0]) { fprintf (stderr, "Bad XML from %s/%d: %s\n", host, port, msg); exit(2); } } } /* return 0 if we are sure we have everything we are looking for, else -1 */ static int finished () { int i; if (monitor) return(-1); for (i = 0; i < nsrchs; i++) if (srchs[i].wc || !srchs[i].ok) return (-1); return (0); } /* called after timeout seconds either because we are matching wild cards or * there is something still not found */ static void onAlarm (int dummy) { int trouble = 0; int i; for (i = 0; i < nsrchs; i++) { if (!srchs[i].ok) { trouble = 1; fprintf (stderr, "No %s.%s.%s from %s:%d\n", srchs[i].d, srchs[i].p, srchs[i].e, host, port); } } exit (trouble ? 1 : 0); } /* read one char from svrrfp */ static int readServerChar () { int c = fgetc (svrrfp); if (c == EOF) { if (ferror(svrrfp)) perror ("read"); else fprintf (stderr,"INDI server %s/%d disconnected\n", host, port); exit (2); } if (verbose > 2) fprintf (stderr, "Read %c\n", c); return (c); } /* print value if root is any srchs[] we are looking for*/ static void findDPE (XMLEle *root) { int i, j; for (i = 0; i < nsrchs; i++) { /* for each property we are looking for */ for (j = 0; j < ndefs; j++) { /* for each possible type */ if (strcmp (tagXMLEle (root), defs[j].vec) == 0) { /* legal defXXXVector, check device */ char *dev = (char *) findXMLAttValu (root, "device"); char *idev = srchs[i].d; if (idev[0] == WILDCARD || !strcmp (dev,idev)) { /* found device, check name */ char *nam = (char *) findXMLAttValu (root, "name"); char *iprop = srchs[i].p; if (iprop[0] == WILDCARD || !strcmp (nam,iprop)) { /* found device and name, check perm */ char *perm = (char *) findXMLAttValu (root, "perm"); if (!wflag && perm[0] && !strchr (perm, 'r')) { if (verbose) fprintf (stderr, "%s.%s is write-only\n", dev, nam); } else { /* check elements or attr keywords */ if (!strcmp (defs[j].vec, "defBLOBVector")) enableBLOBs (dev,nam); else findEle(root,dev,nam,defs[j].one,&srchs[i]); if (onematch) return; /* only one can match */ if (!strncmp (defs[j].vec, "def", 3)) alarm (timeout); /* reset timer if def */ } } } } } } } /* print elements in root speced in sp (known to be of type defone). * print just value if onematch and justvalue else fully qualified name. */ static void findEle (XMLEle *root, char *dev, char *nam, char *defone, SearchDef *sp) { char *iele = sp->e; XMLEle *ep; int i; /* check for attr keyword */ for (i = 0; i < NKWA; i++) { if (strcmp (iele, kwattr[i].keyword) == 0) { /* just print the property state, not the element values */ char *s = (char *) findXMLAttValu (root, kwattr[i].indiattr); sp->ok = 1; /* progress */ if (onematch && justvalue) printf ("%s\n", s); else printf ("%s.%s.%s=%s\n", dev, nam, kwattr[i].keyword, s); return; } } /* no special attr, look for specific element name */ for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (!strcmp (tagXMLEle (ep), defone)) { /* legal defXXX, check deeper */ char *enam = (char *) findXMLAttValu (ep, "name"); if (iele[0]==WILDCARD || !strcmp(enam,iele)) { /* found it! */ char *p = pcdataXMLEle(ep); sp->ok = 1; /* progress */ if (!strcmp (defone, "oneBLOB")) oneBLOB (ep, dev, nam, enam, p, pcdatalenXMLEle(ep)); else if (onematch && justvalue) printf ("%s\n", p); else printf ("%s.%s.%s=%s\n", dev, nam, enam, p); if (onematch) return; /* only one can match*/ } } } } /* send server command to svrwfp that enables blobs for the given dev nam */ static void enableBLOBs(char *dev, char *nam) { if (verbose) fprintf (stderr, "sending enableBLOB %s.%s\n", dev, nam); fprintf (svrwfp,"Also\n", dev, nam); fflush (svrwfp); } /* given a oneBLOB, save */ static void oneBLOB (XMLEle *root, char *dev, char *nam, char *enam, char *p, int plen) { char *format; FILE *fp; int bloblen; unsigned char *blob; int ucs; int isz; char fn[128]; int i; /* get uncompressed size */ ucs = atoi(findXMLAttValu (root, "size")); if (verbose) fprintf (stderr, "%s.%s.%s reports uncompressed size as %d\n", dev, nam, enam, ucs); /* get format and length */ format = (char *) findXMLAttValu (root, "format"); isz = !strcmp (&format[strlen(format)-2], ".z"); /* decode blob from base64 in p */ blob = malloc (3*plen/4); bloblen = from64tobits ((char *)blob, p); if (bloblen < 0) { fprintf (stderr, "%s.%s.%s bad base64\n", dev, nam, enam); exit(2); } /* uncompress effectively in place if z */ if (isz) { uLong nuncomp = ucs; unsigned char *uncomp = malloc (ucs); int ok = uncompress (uncomp, &nuncomp, blob, bloblen); if (ok != Z_OK) { fprintf (stderr, "%s.%s.%s uncompress error %d\n", dev, nam, enam, ok); exit(2); } free (blob); blob = uncomp; bloblen = nuncomp; } /* rig up a file name from property name */ i = sprintf (fn, "%s.%s.%s%s", dev, nam, enam, format); if (isz) fn[i-2] = '\0'; /* chop off .z */ /* save */ fp = fopen (fn, "w"); if (fp) { if (verbose) fprintf (stderr, "Wrote %s\n", fn); fwrite (blob, bloblen, 1, fp); fclose (fp); } else { fprintf (stderr, "%s: %s\n", fn, strerror(errno)); } /* clean up */ free (blob); } /* For RCS Only -- Do Not Edit */ static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: getINDI.c,v $ $Date: 2007/10/11 20:11:23 $ $Revision: 1.11 $ $Name: $"}; libindi-0.9.7/tools/compiler.c0000644000175000017500000004313012241463551015243 0ustar jasemjasem/* module to compile and execute a c-style arithmetic expression made of INDI * operands. operand names must contain 2 dots and be surrounded by quotes. * The expression is compiled and the names of each operand are stored. The * values of an operand can be set later by name. Evaluation uses the last * known operand value. * * one reason this is so nice and tight is that all opcodes are the same size * (an int) and the tokens the parser returns are directly usable as opcodes. * constants and variables are compiled as an opcode with an offset into the * auxiliary consts and vars arrays. * * this is not reentrant, but new expressions can be compiled as desired. */ #include #include #include #include #include static int next_token (void); static int chk_funcs (void); static void skip_double (void); static int compile (int prec); static int execute (double *result); static int parse_fieldname (char name[], int len); /* parser tokens and opcodes, as necessary */ enum { HALT, /* HALT = 0 serves as good initial default */ /* binary operators (precedences in table, below) */ ADD, SUB, MULT, DIV, AND, OR, GT, GE, EQ, NE, LT, LE, /* unary ops, precedence all UNI_PREC */ NEG, NOT, /* symantically operands, ie, constants, variables and all functions */ CONST, VAR, ABS, FLOOR, SIN, COS, TAN, ASIN, ACOS, ATAN, PITOK, /* built-in constant, pi */ DEGRAD, RADDEG, LOG, LOG10, EXP, SQRT, POW, ATAN2, }; /* purely tokens - never get compiled as such */ #define LPAREN 255 #define RPAREN 254 #define COMMA 253 #define ERR (-1) /* precedence of each of the binary operators. * in case of a tie, compiler associates left-to-right. * N.B. each entry's index must correspond to its #define! */ static int precedence[] = {0,5,5,6,6,2,1,4,4,3,3,4,4}; #define UNI_PREC 7 /* unary ops have highest precedence */ /* execute-time operand stack */ #define MAX_STACK 32 static double stack[MAX_STACK], *sp; /* space for compiled opcodes - the "program". * opcodes go in lower 8 bits. * when an opcode has an operand (as CONST and VAR) it is really an array * index in the remaining upper bits. */ #define MAX_PROG 32 static int program[MAX_PROG], *pc; #define OP_SHIFT 8 #define OP_MASK 0xff /* auxiliary operand info. * the operands (all but lower 8 bits) of CONST and VAR are really indeces * into these arrays. thus, no point in making them any longer than you have * bits more than 8 in your machine's int to index into it, ie, make * MAX_OPX < 1 << ((sizeof(int)-1)*8) */ #define MAX_OPX 64 /* max number of operands */ #define MAXFLDLEN 64 /* longest allowed operand name */ typedef struct { int set; /* 1 when v has been set */ char name[MAXFLDLEN]; /* name of operand */ double v; /* last known value of this operand */ } Var; static Var vars[MAX_OPX]; /* operands */ static int nvars; /* number of vars[] in actual use */ static double consts[MAX_OPX]; /* constants */ static int nconsts; /* number of consts[] in actual use */ /* these are global just for easy/rapid access */ static int parens_nest; /* to check that parens end up nested */ static char *err_msg; /* caller provides storage; we point at it with this */ static char *cexpr, *lcexpr; /* pointers that move along caller's expression */ /* compile the given c-style expression. * return 0 if ok, else return -1 and a reason message in errbuf. */ int compileExpr (char *exp, char *errbuf) { /* init the globals. * also delete any flogs used in the previous program. */ cexpr = exp; err_msg = errbuf; pc = program; nvars = nconsts = 0; parens_nest = 0; pc = program; if (compile(0) == ERR) { (void) sprintf (err_msg + strlen(err_msg), " near `%.10s'", lcexpr); return (-1); } if (pc == program) { (void) sprintf (err_msg, "Null program"); return (-1); } *pc++ = HALT; return (0); } /* execute the expression previously compiled with compileExpr(). * return 0 with *vp set to the answer if ok, else return -1 with a reason * why not message in errbuf. */ int evalExpr (double *vp, char *errbuf) { err_msg = errbuf; sp = stack + MAX_STACK; /* grows towards lower addresses */ pc = program; return (execute(vp)); } /* set the value for an operand with the given name to the given value. * return 0 if found else -1. */ int setOperand (char *name, double valu) { int i; for (i = 0; i < nvars; i++) { if (strcmp (name, vars[i].name) == 0) { vars[i].v = valu; vars[i].set = 1; return(0); } } return (-1); } /* return 0 if all operands are set, else -1 */ int allOperandsSet () { int i; for (i = 0; i < nvars; i++) if (!vars[i].set) return (-1); return (0); } /* return a malloced array of each operand name. * N.B. caller must free array, and not modify names. */ int getAllOperands (char ***ops) { int i; *ops = (char **) malloc (nvars * sizeof(char *)); for (i = 0; i < nvars; i++) (*ops)[i] = vars[i].name; return (nvars); } /* return a malloced array of each initialized operand name. * N.B. caller must free array, and not modify the names. */ int getSetOperands (char ***ops) { int i, n; *ops = (char **) malloc (nvars * sizeof(char *)); for (n = i = 0; i < nvars; i++) if (vars[i].set) (*ops)[n++] = vars[i].name; return (n); } /* return a malloced array of each uninitialized operand name. * N.B. caller must free array, and not modify the names. */ int getUnsetOperands (char ***ops) { int i, n; *ops = (char **) malloc (nvars * sizeof(char *)); for (n = i = 0; i < nvars; i++) if (!vars[i].set) (*ops)[n++] = vars[i].name; return (n); } /* called when each different field is written. * this is just called by srch_log() to hide the fact from users of srch* * that srch is really using our vars array to store values. * since this gets called for all fields, it's not an error to not find name. * don't stop when see the first one because a term might appear more than once. */ void compiler_log (name, value) char *name; double value; { Var *vp; for (vp = vars; vp < &vars[nvars]; vp++) if (vp->name && strcmp (vp->name, name) == 0) vp->v = value; } /* get and return the opcode corresponding to the next token. * leave with lcexpr pointing at the new token, cexpr just after it. * also watch for mismatches parens and proper operator/operand alternation. */ static int next_token () { static const char toomv[] = "More than %d variables"; static const char toomc[] = "More than %d constants"; static const char badop[] = "Illegal operator"; int tok = ERR; /* just something illegal */ char c; while (isspace(c = *cexpr)) cexpr++; lcexpr = cexpr++; /* mainly check for a binary operator */ switch (c) { case ',': tok = COMMA; break; case '\0': --cexpr; tok = HALT; break; /* keep returning HALT */ case '+': tok = ADD; break; /* compiler knows when it's really unary */ case '-': tok = SUB; break; /* compiler knows when it's really negate */ case '*': tok = MULT; break; case '/': tok = DIV; break; case '(': parens_nest++; tok = LPAREN; break; case ')': if (--parens_nest < 0) { (void) sprintf (err_msg, "Too many right parens"); return (ERR); } else tok = RPAREN; break; case '|': if (*cexpr == '|') { cexpr++; tok = OR; } else { (void) strcpy (err_msg, badop); return (ERR); } break; case '&': if (*cexpr == '&') { cexpr++; tok = AND; } else { (void) strcpy (err_msg, badop); return (ERR); } break; case '=': if (*cexpr == '=') { cexpr++; tok = EQ; } else { (void) strcpy (err_msg, badop); return (ERR); } break; case '!': if (*cexpr == '=') { cexpr++; tok = NE; } else { tok = NOT; } break; case '<': if (*cexpr == '=') { cexpr++; tok = LE; } else tok = LT; break; case '>': if (*cexpr == '=') { cexpr++; tok = GE; } else tok = GT; break; } if (tok != ERR) return (tok); /* not op so check for a constant, variable or function */ if (isdigit(c) || c == '.') { /* looks like a constant. * leading +- already handled */ if (nconsts > MAX_OPX) { (void) sprintf (err_msg, toomc, MAX_OPX); return (ERR); } consts[nconsts] = atof (lcexpr); tok = CONST | (nconsts++ << OP_SHIFT); skip_double(); } else if (isalpha(c)) { /* check list of functions */ tok = chk_funcs(); if (tok == ERR) { (void) sprintf (err_msg, "Bad function"); return (ERR); } } else if (c == '"') { /* a variable */ if (nvars > MAX_OPX) { (void) sprintf (err_msg, toomv, MAX_OPX); return (ERR); } if (parse_fieldname (vars[nvars].name, MAXFLDLEN) < 0) { (void) sprintf (err_msg, "Bad field"); return (ERR); } else tok = VAR | (nvars++ << OP_SHIFT); } if (tok != ERR) return (tok); /* what the heck is it? */ (void) sprintf (err_msg, "Syntax error"); return (ERR); } /* return funtion token, else ERR. * if find one, update cexpr too. */ static int chk_funcs() { static struct { char *st_name; int st_tok; } symtab[] = { /* be sure to put short names AFTER longer ones. * otherwise, order does not matter. */ {"abs", ABS}, {"floor", FLOOR}, {"acos", ACOS}, {"asin", ASIN}, {"atan2", ATAN2}, {"atan", ATAN}, {"cos", COS}, {"degrad", DEGRAD}, {"exp", EXP}, {"log10", LOG10}, {"log", LOG}, {"pi", PITOK}, {"pow", POW}, {"raddeg", RADDEG}, {"sin", SIN}, {"sqrt", SQRT}, {"tan", TAN}, }; int i; for (i = 0; i < sizeof(symtab)/sizeof(symtab[0]); i++) { int l = strlen (symtab[i].st_name); if (strncmp (lcexpr, symtab[i].st_name, l) == 0) { cexpr += l-1; return (symtab[i].st_tok); } } return (ERR); } /* move cexpr on past a double. * allow sci notation. * no need to worry about a leading '-' or '+' but allow them after an 'e'. * TODO: this handles all the desired cases, but also admits a bit too much * such as things like 1eee2...3. geeze; to skip a double right you almost * have to go ahead and crack it! */ static void skip_double() { int sawe = 0; /* so we can allow '-' or '+' right after an 'e' */ for (;;) { char c = *cexpr; if (isdigit(c) || c=='.' || (sawe && (c=='-' || c=='+'))) { sawe = 0; cexpr++; } else if (c == 'e') { sawe = 1; cexpr++; } else break; } } /* call this whenever you want to dig out the next (sub)expression. * keep compiling instructions as long as the operators are higher precedence * than prec (or until see HALT, COMMA or RPAREN) then return that * "look-ahead" token. * if error, fill in a message in err_msg[] and return ERR. */ static int compile (prec) int prec; { int expect_binop = 0; /* set after we have seen any operand. * used by SUB so it can tell if it really * should be taken to be a NEG instead. */ int tok = next_token (); int *oldpc; for (;;) { int p; if (tok == ERR) return (ERR); if (pc - program >= MAX_PROG) { (void) sprintf (err_msg, "Program is too long"); return (ERR); } /* check for special things like functions, constants and parens */ switch (tok & OP_MASK) { case COMMA: return (tok); case HALT: return (tok); case ADD: if (expect_binop) break; /* procede with binary addition */ /* just skip a unary positive(?) */ tok = next_token(); if (tok == HALT) { (void) sprintf (err_msg, "Term expected after unary +"); return (ERR); } continue; case SUB: if (expect_binop) break; /* procede with binary subtract */ oldpc = pc; tok = compile (UNI_PREC); if (oldpc == pc) { (void) sprintf (err_msg, "Term expected after unary -"); return (ERR); } *pc++ = NEG; expect_binop = 1; continue; case NOT: oldpc = pc; tok = compile (UNI_PREC); if (oldpc == pc) { (void) sprintf (err_msg, "Term expected after unary !"); return (ERR); } *pc++ = NOT; expect_binop = 1; continue; /* one-arg functions */ case ABS: case FLOOR: case SIN: case COS: case TAN: case ASIN: case ACOS: case ATAN: case DEGRAD: case RADDEG: case LOG: case LOG10: case EXP: case SQRT: /* eat up the function's parenthesized argument */ if (next_token() != LPAREN) { (void) sprintf (err_msg, "expecting '(' after function"); return (ERR); } oldpc = pc; if (compile (0) != RPAREN || oldpc == pc) { (void) sprintf (err_msg, "1-arg function arglist error"); return (ERR); } *pc++ = tok; tok = next_token(); expect_binop = 1; continue; /* two-arg functions */ case POW: case ATAN2: /* eat up the function's parenthesized arguments */ if (next_token() != LPAREN) { (void) sprintf (err_msg, "Saw a built-in function: expecting ("); return (ERR); } oldpc = pc; if (compile (0) != COMMA || oldpc == pc) { (void) sprintf (err_msg, "1st of 2-arg function arglist error"); return (ERR); } oldpc = pc; if (compile (0) != RPAREN || oldpc == pc) { (void) sprintf (err_msg, "2nd of 2-arg function arglist error"); return (ERR); } *pc++ = tok; tok = next_token(); expect_binop = 1; continue; /* constants and variables are just like 0-arg functions w/o ()'s */ case CONST: case PITOK: case VAR: *pc++ = tok; tok = next_token(); expect_binop = 1; continue; case LPAREN: oldpc = pc; if (compile (0) != RPAREN) { (void) sprintf (err_msg, "Unmatched left paren"); return (ERR); } if (oldpc == pc) { (void) sprintf (err_msg, "Null expression"); return (ERR); } tok = next_token(); expect_binop = 1; continue; case RPAREN: return (RPAREN); } /* everything else is a binary operator */ if (tok < ADD || tok > LE) { printf ("Bug! Bogus token: %d\n", tok); abort(); } p = precedence[tok]; if (p > prec) { int newtok; oldpc = pc; newtok = compile (p); if (newtok == ERR) return (ERR); if (oldpc == pc) { (void) strcpy (err_msg, "Term or factor expected"); return (ERR); } *pc++ = tok; expect_binop = 1; tok = newtok; } else return (tok); } } /* "run" the program[] compiled with compile(). * if ok, return 0 and the final result, * else return -1 with a reason why not message in err_msg. */ static int execute(result) double *result; { int instr; do { instr = *pc++; switch (instr & OP_MASK) { /* put these in numberic order so hopefully even the dumbest * compiler will choose to use a jump table, not a cascade of ifs. */ case HALT: break; /* outer loop will stop us */ case ADD: sp[1] = sp[1] + sp[0]; sp++; break; case SUB: sp[1] = sp[1] - sp[0]; sp++; break; case MULT: sp[1] = sp[1] * sp[0]; sp++; break; case DIV: sp[1] = sp[1] / sp[0]; sp++; break; case AND: sp[1] = sp[1] && sp[0] ? 1 : 0; sp++; break; case OR: sp[1] = sp[1] || sp[0] ? 1 : 0; sp++; break; case GT: sp[1] = sp[1] > sp[0] ? 1 : 0; sp++; break; case GE: sp[1] = sp[1] >= sp[0] ? 1 : 0; sp++; break; case EQ: sp[1] = sp[1] == sp[0] ? 1 : 0; sp++; break; case NE: sp[1] = sp[1] != sp[0] ? 1 : 0; sp++; break; case LT: sp[1] = sp[1] < sp[0] ? 1 : 0; sp++; break; case LE: sp[1] = sp[1] <= sp[0] ? 1 : 0; sp++; break; case NEG: *sp = -*sp; break; case NOT: *sp = (double)(*sp==0); break; case CONST: *--sp = consts[instr >> OP_SHIFT]; break; case VAR: *--sp = vars[instr>>OP_SHIFT].v; break; case PITOK: *--sp = 4.0*atan(1.0); break; case ABS: *sp = fabs (*sp); break; case FLOOR: *sp = floor (*sp); break; case SIN: *sp = sin (*sp); break; case COS: *sp = cos (*sp); break; case TAN: *sp = tan (*sp); break; case ASIN: *sp = asin (*sp); break; case ACOS: *sp = acos (*sp); break; case ATAN: *sp = atan (*sp); break; case DEGRAD:*sp *= atan(1.0)/45.0; break; case RADDEG:*sp *= 45.0/atan(1.0); break; case LOG: *sp = log (*sp); break; case LOG10: *sp = log10 (*sp); break; case EXP: *sp = exp (*sp); break; case SQRT: *sp = sqrt (*sp); break; case POW: sp[1] = pow (sp[1], sp[0]); sp++; break; case ATAN2: sp[1] = atan2 (sp[1], sp[0]); sp++; break; default: (void) sprintf (err_msg, "Bug! bad opcode: 0x%x", instr); return (-1); } if (sp < stack) { (void) sprintf (err_msg, "Runtime stack overflow"); return (-1); } else if (sp - stack > MAX_STACK) { (void) sprintf (err_msg, "Bug! runtime stack underflow"); return (-1); } } while (instr != HALT); /* result should now be on top of stack */ if (sp != &stack[MAX_STACK - 1]) { (void) sprintf (err_msg, "Bug! stack has %d items", MAX_STACK - (sp-stack)); return (-1); } *result = *sp; return (0); } /* starting with lcexpr pointing at a string expected to be a field name, * ie, at a '"', fill into up to the next '"' into name[], including trailing 0. * if there IS no '"' within len-1 chars, return -1, else 0. * the only sanity check is the string contains two dots. * when return, leave lcexpr alone but move cexpr to just after the second '"'. */ static int parse_fieldname (name, len) char name[]; int len; { char c = '\0'; int ndots = 0; cexpr = lcexpr + 1; while (--len > 0 && (c = *cexpr++) != '"' && c) { *name++ = c; ndots += c == '.'; } if (len == 0 || c != '"' || ndots != 2) return (-1); *name = '\0'; return (0); } /* For RCS Only -- Do Not Edit */ static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: compiler.c,v $ $Date: 2005/11/21 21:33:32 $ $Revision: 1.1 $ $Name: $"}; libindi-0.9.7/tools/evalINDI.c0000644000175000017500000003563612241463551015040 0ustar jasemjasem/* evaluate an expression of INDI operands */ /* Overall design: * compile expression, building operand table, if trouble exit 2 * open INDI connection, if trouble exit 2 * send getProperties as required to get operands flowing * watch for messages until get initial values of each operand * evaluate expression, repeat if -w each time an op arrives until true * exit val==0 */ #include #include #include #include #include #include #include #include #include #include #include #include #include "indiapi.h" #include "lilxml.h" extern int compileExpr (char *expr, char *errmsg); extern int evalExpr (double *vp, char *errmsg); extern int allOperandsSet (void); extern int getAllOperands (char ***ops); extern int getSetOperands (char ***ops); extern int getUnsetOperands (char ***ops); extern int setOperand (char *name, double valu); static void usage (void); static void compile (char *expr); static FILE *openINDIServer (void); static void getProps(FILE *fp); static void initProps (FILE *fp); static int pstatestr (char *state); static time_t timestamp (char *ts); static int devcmp (char *op1, char *op2); static int runEval (FILE *fp); static int setOp (XMLEle *root); static XMLEle *nxtEle (FILE *fp); static int readServerChar (FILE *fp); static void onAlarm (int dummy); static char *me; static char host_def[] = "localhost"; /* default host name */ static char *host = host_def; /* working host name */ #define INDIPORT 7624 /* default port */ static int port = INDIPORT; /* working port number */ #define TIMEOUT 2 /* default timeout, secs */ static int timeout = TIMEOUT; /* working timeout, secs */ static LilXML *lillp; /* XML parser context */ static int directfd = -1; /* direct filedes to server, if >= 0 */ static int verbose; /* more tracing */ static int eflag; /* print each updated expression value*/ static int fflag; /* print final expression value */ static int iflag; /* read expresion from stdin */ static int oflag; /* print operands as they change */ static int wflag; /* wait for expression to be true */ static int bflag; /* beep when true */ int main (int ac, char *av[]) { FILE *fp; /* save our name for usage() */ me = av[0]; /* crack args */ while (--ac && **++av == '-') { char *s = *av; while (*++s) { switch (*s) { case 'b': /* beep when true */ bflag++; break; case 'd': if (ac < 2) { fprintf (stderr, "-d requires open fileno\n"); usage(); } directfd = atoi(*++av); ac--; break; case 'e': /* print each updated expression value */ eflag++; break; case 'f': /* print final expression value */ fflag++; break; case 'h': if (directfd >= 0) { fprintf (stderr, "Can not combine -d and -h\n"); usage(); } if (ac < 2) { fprintf (stderr, "-h requires host name\n"); usage(); } host = *++av; ac--; break; case 'i': /* read expression from stdin */ iflag++; break; case 'o': /* print operands as they change */ oflag++; break; case 'p': if (directfd >= 0) { fprintf (stderr, "Can not combine -d and -p\n"); usage(); } if (ac < 2) { fprintf (stderr, "-p requires tcp port number\n"); usage(); } port = atoi(*++av); ac--; break; case 't': if (ac < 2) { fprintf (stderr, "-t requires timeout\n"); usage(); } timeout = atoi(*++av); ac--; break; case 'v': /* verbose */ verbose++; break; case 'w': /* wait for expression to be true */ wflag++; break; default: fprintf (stderr, "Unknown flag: %c\n", *s); usage(); } } } /* now there are ac args starting with av[0] */ /* compile expression from av[0] or stdin */ if (ac == 0) compile (NULL); else if (ac == 1) compile (av[0]); else usage(); /* open connection */ if (directfd >= 0) { fp = fdopen (directfd, "r+"); setbuf (fp, NULL); /* don't absorb next guy's stuff */ if (!fp) { fprintf (stderr, "Direct fd %d: %s\n",directfd,strerror(errno)); exit(1); } if (verbose) fprintf (stderr, "Using direct fd %d\n", directfd); } else { fp = openINDIServer(); if (verbose) fprintf (stderr, "Connected to %s on port %d\n", host, port); } /* build a parser context for cracking XML responses */ lillp = newLilXML(); /* set up to catch an io timeout function */ signal (SIGALRM, onAlarm); /* send getProperties */ getProps(fp); /* initialize all properties */ initProps(fp); /* evaluate expression, return depending on flags */ return (runEval(fp)); } static void usage() { fprintf (stderr, "Usage: %s [options] [exp]\n", me); fprintf (stderr, "Purpose: evaluate an expression of INDI operands\n"); fprintf (stderr, "Version: $Revision: 1.5 $\n"); fprintf (stderr, "Options:\n"); fprintf (stderr, " -b : beep when expression evaluates as true\n"); fprintf (stderr, " -d f : use file descriptor f already open to server\n"); fprintf (stderr, " -e : print each updated expression value\n"); fprintf (stderr, " -f : print final expression value\n"); fprintf (stderr, " -h h : alternate host, default is %s\n", host_def); fprintf (stderr, " -i : read expression from stdin\n"); fprintf (stderr, " -o : print operands as they change\n"); fprintf (stderr, " -p p : alternate port, default is %d\n", INDIPORT); fprintf (stderr, " -t t : max secs to wait, 0 is forever, default is %d\n",TIMEOUT); fprintf (stderr, " -v : verbose (cummulative)\n"); fprintf (stderr, " -w : wait for expression to evaluate as true\n"); fprintf (stderr, "[exp] is an arith expression built from the following operators and functons:\n"); fprintf (stderr, " ! + - * / && || > >= == != < <=\n"); fprintf (stderr, " pi sin(rad) cos(rad) tan(rad) asin(x) acos(x) atan(x) atan2(y,x) abs(x)\n"); fprintf (stderr, " degrad(deg) raddeg(rad) floor(x) log(x) log10(x) exp(x) sqrt(x) pow(x,exp)\n"); fprintf (stderr, " operands are of the form \"device.name.element\" (including quotes), where\n"); fprintf (stderr, " element may be:\n"); fprintf (stderr, " _STATE evaluated to 0,1,2,3 from Idle,Ok,Busy,Alert.\n"); fprintf (stderr, " _TS evaluated to UNIX seconds from epoch.\n"); fprintf (stderr, " Switch vectors are evaluated to 0,1 from Off,On.\n"); fprintf (stderr, " Light vectors are evaluated to 0-3 as per _STATE.\n"); fprintf (stderr, "Examples:\n"); fprintf (stderr, " To print 0/1 whether Security.Doors.Front or .Rear are in Alert:\n"); fprintf (stderr, " evalINDI -f '\"Security.Doors.Front\"==3 || \"Security.Doors.Rear\"==3'\n"); fprintf (stderr, " To exit 0 if the Security property as a whole is in a state of Ok:\n"); fprintf (stderr, " evalINDI '\"Security.Security._STATE\"==1'\n"); fprintf (stderr, " To wait for RA and Dec to be near zero and watch their values as they change:\n"); fprintf (stderr, " evalINDI -t 0 -wo 'abs(\"Mount.EqJ2K.RA\")<.01 && abs(\"Mount.EqJ2K.Dec\")<.01'\n"); fprintf (stderr, "Exit 0 if expression evaluates to non-0, 1 if 0, else 2\n"); exit (1); } /* compile the given expression else read from stdin. * exit(2) if trouble. */ static void compile (char *expr) { char errmsg[1024]; char *exp = expr; if (!exp) { /* read expression from stdin */ int nr, nexp = 0; exp = malloc(1024); while ((nr = fread (exp+nexp, 1, 1024, stdin)) > 0) exp = realloc (exp, (nexp+=nr)+1024); exp[nexp] = '\0'; } if (verbose) fprintf (stderr, "Compiling: %s\n", exp); if (compileExpr (exp, errmsg) < 0) { fprintf (stderr, "Compile err: %s\n", errmsg); exit(2); } if (exp != expr) free (exp); } /* open a connection to the given host and port or die. * return FILE pointer to socket. */ static FILE * openINDIServer (void) { struct sockaddr_in serv_addr; struct hostent *hp; int sockfd; /* lookup host address */ hp = gethostbyname (host); if (!hp) { perror ("gethostbyname"); exit (2); } /* create a socket to the INDI server */ (void) memset ((char *)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr_list[0]))->s_addr; serv_addr.sin_port = htons(port); if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); exit(2); } /* connect */ if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){ perror ("connect"); exit(2); } /* prepare for line-oriented i/o with client */ return (fdopen (sockfd, "r+")); } /* invite each device referenced in the expression to report its properties. */ static void getProps(FILE *fp) { char **ops; int nops; int i, j; /* get each operand used in the expression */ nops = getAllOperands (&ops); /* send getProperties for each unique device referenced */ for (i = 0; i < nops; i++) { for (j = 0; j < i; j++) if (devcmp (ops[i], ops[j]) == 0) break; if (j < i) continue; if (verbose) fprintf (stderr, "sending getProperties for %.*s\n", strchr (ops[i],'.')-ops[i], ops[i]); fprintf (fp, "\n", INDIV, strchr (ops[i],'.')-ops[i], ops[i]); } } /* wait for defXXX or setXXX for each property in the expression. * return when find all operands are found or * exit(2) if time out waiting for all known operands. */ static void initProps (FILE *fp) { alarm (timeout); while (allOperandsSet() < 0) { if (setOp (nxtEle (fp)) == 0) alarm(timeout); } alarm (0); } /* pull apart the name and value from the given message, and set operand value. * ignore any other messages. * return 0 if found a recognized operand else -1 */ static int setOp (XMLEle *root) { char *t = tagXMLEle (root); const char *d = findXMLAttValu (root, "device"); const char *n = findXMLAttValu (root, "name"); int nset = 0; double v; char prop[1024]; XMLEle *ep; /* check values */ if (!strcmp (t,"defNumberVector") || !strcmp (t,"setNumberVector")) { for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { char *et = tagXMLEle(ep); if (!strcmp (et,"defNumber") || !strcmp (et,"oneNumber")) { sprintf (prop, "%s.%s.%s", d, n, findXMLAttValu(ep,"name")); v = atof(pcdataXMLEle(ep)); if (setOperand (prop, v) == 0) { nset++; if (oflag) fprintf (stderr, "%s=%g\n", prop, v); } } } } else if(!strcmp(t,"defSwitchVector") || !strcmp(t,"setSwitchVector")){ for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { char *et = tagXMLEle(ep); if (!strcmp (et,"defSwitch") || !strcmp (et,"oneSwitch")) { sprintf (prop, "%s.%s.%s", d, n, findXMLAttValu(ep,"name")); v = (double)!strcmp(pcdataXMLEle(ep),"On"); if (setOperand (prop, v) == 0) { nset++; if (oflag) fprintf (stderr, "%s=%g\n", prop, v); } } } } else if(!strcmp(t,"defLightVector") || !strcmp(t,"setLightVector")){ for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { char *et = tagXMLEle(ep); if (!strcmp (et,"defLight") || !strcmp (et,"oneLight")) { sprintf (prop, "%s.%s.%s", d, n, findXMLAttValu(ep,"name")); v = (double)pstatestr(pcdataXMLEle(ep)); if (setOperand (prop, v) == 0) { nset++; if (oflag) fprintf (stderr, "%s=%g\n", prop, v); } } } } /* check special elements */ t = (char *) findXMLAttValu (root, "state"); if (t[0]) { sprintf (prop, "%s.%s._STATE", d, n); v = (double)pstatestr(t); if (setOperand (prop, v) == 0) { nset++; if (oflag) fprintf (stderr, "%s=%g\n", prop, v); } } t = (char *) findXMLAttValu (root, "timestamp"); if (t[0]) { sprintf (prop, "%s.%s._TS", d, n); v = (double)timestamp(t); if (setOperand (prop, v) == 0) { nset++; if (oflag) fprintf (stderr, "%s=%g\n", prop, v); } } /* return whether any were set */ return (nset > 0 ? 0 : -1); } /* evaluate the expression after seeing any operand change. * return whether expression evaluated to 0. * exit(2) is trouble or timeout waiting for operands we expect. */ static int runEval (FILE *fp) { char errmsg[1024]; double v; alarm(timeout); while (1) { if (evalExpr (&v, errmsg) < 0) { fprintf (stderr, "Eval: %s\n", errmsg); exit(2); } if (bflag && v) fprintf (stderr, "\a"); if (eflag) fprintf (stderr, "%g\n", v); if (!wflag || v != 0) break; while (setOp (nxtEle (fp)) < 0) continue; alarm(timeout); } alarm(0); if (!eflag && fflag) fprintf (stderr, "%g\n", v); return (v == 0); } /* return 0|1|2|3 depending on whether state is Idle|Ok|Busy|. */ static int pstatestr (char *state) { if (!strcmp (state, "Idle")) return (0); if (!strcmp (state, "Ok")) return (1); if (!strcmp (state, "Busy")) return (2); return (3); } /* return UNIX time for the given ISO 8601 time string */ static time_t timestamp (char *ts) { struct tm tm; if (6 == sscanf (ts, "%d-%d-%dT%d:%d:%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec)) { tm.tm_mon -= 1; /* want 0..11 */ tm.tm_year -= 1900; /* want years since 1900 */ return (mktime (&tm)); } else return ((time_t)-1); } /* return 0 if the device portion of the two given property specs match, else 1 */ static int devcmp (char *op1, char *op2) { int n1 = strchr(op1,'.') - op1; int n2 = strchr(op2,'.') - op2; return (n1 != n2 || strncmp (op1,op2,n1)); } /* monitor server and return the next complete XML message. * exit(2) if time out. * N.B. caller must call delXMLEle() */ static XMLEle * nxtEle (FILE *fp) { char msg[1024]; /* read from server, exit if trouble or see malformed XML */ while(1) { XMLEle *root = readXMLEle (lillp, readServerChar(fp), msg); if (root) { /* found a complete XML element */ if (verbose > 1) prXMLEle (stderr, root, 0); return (root); } else if (msg[0]) { fprintf (stderr, "Bad XML from %s/%d: %s\n", host, port, msg); exit(2); } } } /* read next char from the INDI server connected by fp */ static int readServerChar (FILE *fp) { int c = fgetc (fp); if (c == EOF) { if (ferror(fp)) perror ("read"); else fprintf (stderr,"INDI server %s/%d disconnected\n", host, port); exit (2); } if (verbose > 2) fprintf (stderr, "Read %c\n", c); return (c); } /* called after timeout seconds waiting to hear from server. * print reason for trouble and exit(2). */ static void onAlarm (int dummy) { char **ops; int nops; /* report any unseen operands if any, else just say timed out */ if ((nops = getUnsetOperands (&ops)) > 0) { fprintf (stderr, "No values seen for"); while (nops-- > 0) fprintf (stderr, " %s", ops[nops]); fprintf (stderr, "\n"); } else fprintf (stderr, "Timed out waiting for new values\n"); exit (2); } libindi-0.9.7/COPYING.GPL0000644000175000017500000004325412241463551013610 0ustar jasemjasem GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. libindi-0.9.7/COPYRIGHT0000644000175000017500000001306212241463551013421 0ustar jasemjasemFiles: * Copyright: 1996-1998, Patrick Reynolds 2003-2007, Elwood C. Downey 2003-2007, 2010, Jasem Mutlaq 2003, Jason Harris 2003, John Kielkopf 2004, Francois Meyer 2005, Bruce Bockius 2005, Douglas Philipson 2005, Gaetano Vocca 2006-2007, Markus Wildi License: LGPL-2.1+ Files: cmake/* Copyright: Bryan Donlan Carsten Niehaus 2006, Alexander Neundorf 2006, Allen Winter 2006, 2008, 2011, Jasem Mutlaq 2009, Geoffrey Hausheer License: BSD-3-clause Files: libs/webcam/ccvt_c2.c libs/webcam/ccvt.h libs/webcam/ccvt_misc.c libs/webcam/ccvt_types.h libs/webcam/vcvt.h libs/webcam/videodev.h libs/webcam/videodev2.h Copyright: Justin Schoeman 2001, Tony Hague 2002, Nemosoft Unv. 2006, Bill Dirks 2010, Gerry Rozema License: GPL-2+ Files: libs/webcam/port.* libs/webcam/pwc-ioctl.h Copyright: Anders Arpteg Patrick Reynolds Charles Henrich 1996-1998, Patrick Reynolds 2001-2004, Nemosoft Unv. 2004-2006, Luc Saillard License: LGPL-2+ Files: debian/* Copyright: 2011, Pino Toscano License: GPL-2+ License: BSD-3-clause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: . 1. Redistributions of source code must retain the copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. . THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. License: LGPL-2+ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. . 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 Library General Public License for more details. . You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. . On Debian systems, the complete text of the GNU Library General Public License version 2 can be found in `/usr/share/common-licenses/LGPL-2'. License: LGPL-2.1+ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2.1 as published by the Free Software Foundation. . 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 Library General Public License for more details. . You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. . On Debian systems, the complete text of the GNU Library General Public License version 2.1 can be found in `/usr/share/common-licenses/LGPL-2.1'. License: GPL-2+ This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. . This package 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 General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . On Debian systems, the complete texts of the GNU General Public Licenses version 2 and 3 can be found in `/usr/share/common-licenses/GPL-2' and `/usr/share/common-licenses/GPL-3'. libindi-0.9.7/NEWS0000644000175000017500000000035112241463551012622 0ustar jasemjasem------------------------------------------------------------------------- News ------------------------------------------------------------------------- For the latest news on INDI, refer to INDI's website @ http://www.indilib.org libindi-0.9.7/indidrivermain.c0000644000175000017500000000550412241463551015300 0ustar jasemjasem#if 0 INDI Copyright (C) 2003-2006 Elwood C. Downey Updated by Jasem Mutlaq (2003-2010) 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 /* main() for one INDI driver process. * Drivers define IS*() functions we call to deliver INDI XML arriving on stdin. * Drivers call ID*() functions to send INDI XML commands to stdout. * Drivers call IE*() functions to build an event-driver program. * Drivers call IU*() functions to perform various common utility tasks. * Troubles are reported on stderr then we exit. * * This requires liblilxml. */ #include #include #include #include #include #include #include #include #include #include "lilxml.h" #include "base64.h" #include "eventloop.h" #include "indidevapi.h" #include "indicom.h" #include "indidriver.h" #define MAXRBUF 2048 ROSC *roCheck; int nroCheck; /* # of elements in roCheck */ int verbose; /* chatty */ char *me; /* a.out name */ LilXML *clixml; /* XML parser context */ static void usage(void); int main (int ac, char *av[]) { #ifndef _WIN32 setgid( getgid() ); setuid( getuid() ); if (geteuid() != getuid()) exit(255); #endif /* save handy pointer to our base name */ for (me = av[0]; av[0][0]; av[0]++) if (av[0][0] == '/') me = &av[0][1]; /* crack args */ while (--ac && (*++av)[0] == '-') while (*++(*av)) switch (*(*av)) { case 'v': /* verbose */ verbose++; break; default: usage(); } /* ac remaining args starting at av[0] */ if (ac > 0) usage(); /* init */ clixml = newLilXML(); addCallback (0, clientMsgCB, NULL); /* service client */ eventLoop(); /* eh?? */ fprintf (stderr, "%s: inf loop ended\n", me); return (1); } /* print usage message and exit (1) */ static void usage(void) { fprintf (stderr, "Usage: %s [options]\n", me); fprintf (stderr, "Purpose: INDI Device driver framework.\n"); fprintf (stderr, "Options:\n"); fprintf (stderr, " -v : more verbose to stderr\n"); exit (1); } libindi-0.9.7/eventloop.h0000644000175000017500000000663112241463551014316 0ustar jasemjasem#if 0 INDI Copyright (C) 2003 Elwood C. Downey 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 #ifndef EVENT_LOOP_H #define EVENT_LOOP_H /** \file eventloop.h \brief Public interface to INDI's eventloop mechanism. \author Elwood C. Downey */ /* signature of a callback, workproc and timer function */ /** \typedef CBF \brief Signature of a callback function. */ typedef void (CBF) (int fd, void *); /** \typedef WPF \brief Signature of a work procedure function. */ typedef void (WPF) (void *); /** \typedef TCF \brief Signature of a timer function. */ typedef void (TCF) (void *); #ifdef __cplusplus extern "C" { #endif /** \fn void eventLoop(void) \brief Main calls this when ready to hand over control. */ extern void eventLoop(void); /** Register a new callback, \e fp, to be called with \e ud as argument when \e fd is ready. * * \param fd file descriptor. * \param fp a pointer to the callback function. * \param ud a pointer to be passed to the callback function when called. * \return a unique callback id for use with rmCallback(). */ extern int addCallback (int fd, CBF *fp, void *ud); /** Remove a callback function. * * \param cid the callback ID returned from addCallback(). */ extern void rmCallback (int cid); /** Add a new work procedure, fp, to be called with ud when nothing else to do. * * \param fp a pointer to the work procedure callback function. * \param ud a pointer to be passed to the callback function when called. * \return a unique id for use with rmWorkProc(). */ extern int addWorkProc (WPF *fp, void *ud); /** Remove the work procedure with the given \e id, as returned from addWorkProc(). * * \param wid the work procedure callback ID returned from addWorkProc(). */ extern void rmWorkProc (int wid); /** Register a new timer function, \e fp, to be called with \e ud as argument after \e ms. Add to list in order of decreasing time from epoch, ie, last entry runs soonest. The timer will only invoke the callback function \b once. You need to call addTimer again if you want to repeat the process. * * \param ms timer period in milliseconds. * \param fp a pointer to the callback function. * \param ud a pointer to be passed to the callback function when called. * \return a unique id for use with rmTimer(). */ extern int addTimer (int ms, TCF *fp, void *ud); /** Remove the timer with the given \e id, as returned from addTimer(). * * \param tid the timer callback ID returned from addTimer(). */ extern void rmTimer (int tid); /* utility functions */ extern int deferLoop (int maxms, int *flagp); extern int deferLoop0 (int maxms, int *flagp); #ifdef __cplusplus } #endif #endif libindi-0.9.7/indiserver.c0000644000175000017500000014573012241463551014454 0ustar jasemjasem/* INDI Server for protocol version 1.7. * Copyright (C) 2007 Elwood C. Downey 2013 Jasem Mutlaq 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 * argv lists names of Driver programs to run or sockets to connect for Devices. * Drivers are restarted if they exit or connection closes. * Each local Driver's stdin/out are assumed to provide INDI traffic and are * connected here via pipes. Local Drivers' stderr are connected to our * stderr with date stamp and driver name prepended. * We only support Drivers that advertise support for one Device. The problem * with multiple Devices in one Driver is without a way to know what they * _all_ are there is no way to avoid sending all messages to all Drivers. * Outbound messages are limited to Devices and Properties seen inbound. * Messages to Devices on sockets always include Device so the chained * indiserver will only pass back info from that Device. * All newXXX() received from one Client are echoed to all other Clients who * have shown an interest in the same Device and property. * * Implementation notes: * * We fork each driver and open a server socket listening for INDI clients. * Then forever we listen for new clients and pass traffic between clients and * drivers, subject to optimizations based on sniffing messages for matching * Devices and Properties. Since one message might be destined to more than * one client or device, they are queued and only removed after the last * consumer is finished. XMLEle are converted to linear strings before being * sent to optimize write system calls and avoid blocking to slow clients. * Clients that get more than maxqsiz bytes behind are shut down. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "lilxml.h" #include "indiapi.h" #include "fq.h" #define INDIPORT 7624 /* default TCP/IP port to listen */ #define REMOTEDVR (-1234) /* invalid PID to flag remote drivers */ #define MAXSBUF 512 #define MAXRBUF 4096 /* max read buffering here */ #define MAXWSIZ 4096 /* max bytes/write */ #define DEFMAXQSIZ 10 /* default max q behind, MB */ /* associate a usage count with queuded client or device message */ typedef struct { int count; /* number of consumers left */ unsigned int cl; /* content length */ char *cp; /* content: buf or malloced */ char buf[MAXWSIZ]; /* local buf for most messages */ } Msg; /* BLOB handling, NEVER is the default */ typedef enum {B_NEVER=0, B_ALSO, B_ONLY} BLOBHandling; /* device + property name */ typedef struct { char dev[MAXINDIDEVICE]; char name[MAXINDINAME]; BLOBHandling blob; /* when to snoop BLOBs */ } Property; /* record of each snooped property typedef struct { Property prop; BLOBHandling blob; } Property; */ struct { const char *name; /* Path to FIFO for dynamic startups & shutdowns of drivers */ int fd; //FILE *fs; } fifo; /* info for each connected client */ typedef struct { int active; /* 1 when this record is in use */ Property *props; /* malloced array of props we want */ int nprops; /* n entries in props[] */ int allprops; /* saw getProperties w/o device */ BLOBHandling blob; /* when to send setBLOBs */ int s; /* socket for this client */ LilXML *lp; /* XML parsing context */ FQ *msgq; /* Msg queue */ unsigned int nsent; /* bytes of current Msg sent so far */ } ClInfo; static ClInfo *clinfo; /* malloced pool of clients */ static int nclinfo; /* n total (not active) */ /* info for each connected driver */ typedef struct { char name[MAXINDINAME]; /* persistent name */ //char dev[MAXINDIDEVICE]; /* device served by this driver */ char **dev; /* device served by this driver */ int ndev; /* number of devices served by this driver */ int active; /* 1 when this record is in use */ Property *sprops; /* malloced array of props we snoop */ int nsprops; /* n entries in sprops[] */ int pid; /* process id or REMOTEDVR if remote */ int rfd; /* read pipe fd */ int wfd; /* write pipe fd */ int efd; /* stderr from driver, if local */ int restarts; /* times process has been restarted */ LilXML *lp; /* XML parsing context */ FQ *msgq; /* Msg queue */ unsigned int nsent; /* bytes of current Msg sent so far */ } DvrInfo; static DvrInfo *dvrinfo; /* malloced array of drivers */ static int ndvrinfo; /* n total */ static char *me; /* our name */ static int port = INDIPORT; /* public INDI port */ static int verbose; /* chattiness */ static int lsocket; /* listen socket */ static char *ldir; /* where to log driver messages */ static int maxqsiz = (DEFMAXQSIZ*1024*1024); /* kill if these bytes behind */ static void logStartup(int ac, char *av[]); static void usage (void); static void noZombies (void); static void noSIGPIPE (void); static void indiFIFO(void); static void indiRun (void); static void indiListen (void); static void newFIFO(void); static void newClient (void); static int newClSocket (void); static void shutdownClient (ClInfo *cp); static int readFromClient (ClInfo *cp); static void startDvr (DvrInfo *dp); static void startLocalDvr (DvrInfo *dp); static void startRemoteDvr (DvrInfo *dp); static int openINDIServer (char host[], int indi_port); static void shutdownDvr (DvrInfo *dp, int restart); static int isDeviceInDriver(const char *dev, DvrInfo *dp); static void q2RDrivers (const char *dev, Msg *mp, XMLEle *root); static void q2SDrivers (int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root); static int q2Clients (ClInfo *notme, int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root); static void addSDevice (DvrInfo *dp, const char *dev, const char *name); static Property *findSDevice (DvrInfo *dp, const char *dev, const char *name); static void addClDevice (ClInfo *cp, const char *dev, const char *name, int isblob); static int findClDevice (ClInfo *cp, const char *dev, const char *name); static int readFromDriver (DvrInfo *dp); static int stderrFromDriver (DvrInfo *dp); static int msgQSize (FQ *q); static void setMsgXMLEle (Msg *mp, XMLEle *root); static void setMsgStr (Msg *mp, char *str); static void freeMsg (Msg *mp); static Msg *newMsg (void); static int sendClientMsg (ClInfo *cp); static int sendDriverMsg (DvrInfo *cp); static void crackBLOB (const char *enableBLOB, BLOBHandling *bp); static void crackBLOBHandling(const char *dev, const char *name, const char *enableBLOB, ClInfo *cp); static void traceMsg (XMLEle *root); static char *indi_tstamp (char *s); static void logDMsg (XMLEle *root, const char *dev); static void Bye(void); int main (int ac, char *av[]) { /* log startup */ logStartup(ac, av); /* save our name */ me = av[0]; /* crack args */ while ((--ac > 0) && ((*++av)[0] == '-')) { char *s; for (s = av[0]+1; *s != '\0'; s++) switch (*s) { case 'l': if (ac < 2) { fprintf (stderr, "-l requires log directory\n"); usage(); } ldir = *++av; ac--; break; case 'm': if (ac < 2) { fprintf (stderr, "-m requires max MB behind\n"); usage(); } maxqsiz = 1024*1024*atoi(*++av); ac--; break; case 'p': if (ac < 2) { fprintf (stderr, "-p requires port value\n"); usage(); } port = atoi(*++av); ac--; break; case 'f': if (ac < 2) { fprintf (stderr, "-f requires fifo node\n"); usage(); } fifo.name = *++av; ac--; break; case 'v': verbose++; break; default: usage(); } } /* at this point there are ac args in av[] to name our drivers */ if (ac == 0 && !fifo.name) usage(); /* take care of some unixisms */ noZombies(); noSIGPIPE(); /* realloc seed for client pool */ clinfo = (ClInfo *) malloc (1); nclinfo = 0; /* create driver info array all at once since size never changes */ ndvrinfo = ac; dvrinfo = (DvrInfo *) calloc (ndvrinfo, sizeof(DvrInfo)); /* start each driver */ while (ac-- > 0) { strncpy(dvrinfo[ac].name, *av++, MAXINDINAME); startDvr (&dvrinfo[ac]); } /* announce we are online */ indiListen(); /* Load up FIFO, if available */ indiFIFO(); /* handle new clients and all io */ while (1) indiRun(); /* whoa! */ fprintf (stderr, "unexpected return from main\n"); return (1); } /* record we have started and our args */ static void logStartup(int ac, char *av[]) { int i; fprintf (stderr, "%s: startup: ", indi_tstamp(NULL)); for (i = 0; i < ac; i++) fprintf (stderr, "%s ", av[i]); fprintf (stderr, "\n"); } /* print usage message and exit (2) */ static void usage(void) { fprintf (stderr, "Usage: %s [options] driver [driver ...]\n", me); fprintf (stderr, "Purpose: server for local and remote INDI drivers\n"); fprintf (stderr, "INDI Library: %s\nCode %s. Protocol %g.\n", CMAKE_INDI_VERSION_STRING, "$Revision: 726523 $", INDIV); fprintf (stderr, "Options:\n"); fprintf (stderr, " -l d : log driver messages to /YYYY-MM-DD.islog\n"); fprintf (stderr, " -m m : kill client if gets more than this many MB behind, default %d\n", DEFMAXQSIZ); fprintf (stderr, " -p p : alternate IP port, default %d\n", INDIPORT); fprintf (stderr, " -f path : Path to fifo for dynamic startup and shutdown of drivers.\n"); fprintf (stderr, " -v : show key events, no traffic\n"); fprintf (stderr, " -vv : -v + key message content\n"); fprintf (stderr, " -vvv : -vv + complete xml\n"); fprintf (stderr, "driver : executable or device@host[:port]\n"); exit (2); } /* arrange for no zombies if drivers die */ static void noZombies() { struct sigaction sa; sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); #ifdef SA_NOCLDWAIT sa.sa_flags = SA_NOCLDWAIT; #else sa.sa_flags = 0; #endif (void)sigaction(SIGCHLD, &sa, NULL); } /* turn off SIGPIPE on bad write so we can handle it inline */ static void noSIGPIPE() { struct sigaction sa; sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); (void)sigaction(SIGPIPE, &sa, NULL); } static DvrInfo * allocDvr () { DvrInfo *dp = NULL; int dvi; /* try to reuse a drivber slot, else add one */ for (dvi = 0; dvi < ndvrinfo; dvi++) if (!(dp = &dvrinfo[dvi])->active) break; if (dvi == ndvrinfo) { /* grow dvrinfo */ dvrinfo = (DvrInfo *) realloc (dvrinfo, (ndvrinfo+1)*sizeof(DvrInfo)); if (!dvrinfo) { fprintf (stderr, "no memory for new drivers\n"); Bye(); } dp = &dvrinfo[ndvrinfo++]; } /* rig up new dvrinfo entry */ memset (dp, 0, sizeof(*dp)); dp->active = 1; dp->ndev =0; return dp; } /* start the given INDI driver process or connection. * exit if trouble. */ static void startDvr (DvrInfo *dp) { if (strchr (dp->name, '@')) startRemoteDvr (dp); else startLocalDvr (dp); } /* start the given local INDI driver process. * exit if trouble. */ static void startLocalDvr (DvrInfo *dp) { Msg *mp; char buf[32]; int rp[2], wp[2], ep[2]; int pid; /* build three pipes: r, w and error*/ if (pipe (rp) < 0) { fprintf (stderr, "%s: read pipe: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } if (pipe (wp) < 0) { fprintf (stderr, "%s: write pipe: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } if (pipe (ep) < 0) { fprintf (stderr, "%s: stderr pipe: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } /* fork&exec new process */ pid = fork(); if (pid < 0) { fprintf (stderr, "%s: fork: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } if (pid == 0) { /* child: exec name */ int fd; /* rig up pipes */ dup2 (wp[0], 0); /* driver stdin reads from wp[0] */ dup2 (rp[1], 1); /* driver stdout writes to rp[1] */ dup2 (ep[1], 2); /* driver stderr writes to e[]1] */ for (fd = 3; fd < 100; fd++) (void) close (fd); /* go -- should never return */ execlp (dp->name, dp->name, NULL); fprintf (stderr, "%s: Driver %s: execlp: %s\n", indi_tstamp(NULL), dp->name, strerror(errno)); _exit (1); /* parent will notice EOF shortly */ } /* don't need child's side of pipes */ close (wp[0]); close (rp[1]); close (ep[1]); /* record pid, io channels, init lp and snoop list */ dp->pid = pid; dp->rfd = rp[0]; dp->wfd = wp[1]; dp->efd = ep[0]; dp->lp = newLilXML(); dp->msgq = newFQ(1); dp->sprops = (Property*) malloc (1); /* seed for realloc */ dp->nsprops = 0; dp->nsent = 0; dp->active = 1; dp->ndev = 0; dp->dev = (char **) malloc(sizeof(char *)); /* first message primes driver to report its properties -- dev known * if restarting */ mp = newMsg(); pushFQ (dp->msgq, mp); sprintf (buf, "\n", INDIV); setMsgStr (mp, buf); mp->count++; if (verbose > 0) fprintf (stderr, "%s: Driver %s: pid=%d rfd=%d wfd=%d efd=%d\n", indi_tstamp(NULL), dp->name, dp->pid, dp->rfd, dp->wfd, dp->efd); } /* start the given remote INDI driver connection. * exit if trouble. */ static void startRemoteDvr (DvrInfo *dp) { Msg *mp; char dev[1024]; char host[1024]; char buf[1024]; int indi_port, sockfd; /* extract host and port */ indi_port = INDIPORT; if (sscanf (dp->name, "%[^@]@%[^:]:%d", dev, host, &indi_port) < 2) { fprintf (stderr, "Bad remote device syntax: %s\n", dp->name); Bye(); } /* connect */ sockfd = openINDIServer (host, indi_port); /* record flag pid, io channels, init lp and snoop list */ dp->pid = REMOTEDVR; dp->rfd = sockfd; dp->wfd = sockfd; dp->lp = newLilXML(); dp->msgq = newFQ(1); dp->sprops = (Property*) malloc (1); /* seed for realloc */ dp->nsprops = 0; dp->nsent = 0; dp->active = 1; dp->ndev = 1; dp->dev = (char **) malloc(sizeof(char *)); /* N.B. storing name now is key to limiting outbound traffic to this * dev. */ dp->dev[0] = (char *) malloc(MAXINDIDEVICE * sizeof(char)); strncpy (dp->dev[0], dev, MAXINDIDEVICE-1); dp->dev[0][MAXINDIDEVICE-1] = '\0'; /* Sending getProperties with device lets remote server limit its * outbound (and our inbound) traffic on this socket to this device. */ mp = newMsg(); pushFQ (dp->msgq, mp); sprintf (buf, "\n", dp->dev[0], INDIV); setMsgStr (mp, buf); mp->count++; if (verbose > 0) fprintf (stderr, "%s: Driver %s: socket=%d\n", indi_tstamp(NULL), dp->name, sockfd); } /* open a connection to the given host and port or die. * return socket fd. */ static int openINDIServer (char host[], int indi_port) { struct sockaddr_in serv_addr; struct hostent *hp; int sockfd; /* lookup host address */ hp = gethostbyname (host); if (!hp) { fprintf (stderr, "gethostbyname(%s): %s\n", host, strerror(errno)); Bye(); } /* create a socket to the INDI server */ (void) memset ((char *)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr_list[0]))->s_addr; serv_addr.sin_port = htons(indi_port); if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { fprintf (stderr, "socket(%s,%d): %s\n", host, indi_port,strerror(errno)); Bye(); } /* connect */ if (connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){ fprintf (stderr, "connect(%s,%d): %s\n", host,indi_port,strerror(errno)); Bye(); } /* ok */ return (sockfd); } /* create the public INDI Driver endpoint lsocket on port. * return server socket else exit. */ static void indiListen () { struct sockaddr_in serv_socket; int sfd; int reuse = 1; /* make socket endpoint */ if ((sfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { fprintf (stderr, "%s: socket: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } /* bind to given port for any IP address */ memset (&serv_socket, 0, sizeof(serv_socket)); serv_socket.sin_family = AF_INET; #ifdef SSH_TUNNEL serv_socket.sin_addr.s_addr = htonl (INADDR_LOOPBACK); #else serv_socket.sin_addr.s_addr = htonl (INADDR_ANY); #endif serv_socket.sin_port = htons ((unsigned short)port); if (setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0){ fprintf (stderr, "%s: setsockopt: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } if (bind(sfd,(struct sockaddr*)&serv_socket,sizeof(serv_socket)) < 0){ fprintf (stderr, "%s: bind: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } /* willing to accept connections with a backlog of 5 pending */ if (listen (sfd, 5) < 0) { fprintf (stderr, "%s: listen: %s\n", indi_tstamp(NULL), strerror(errno)); Bye(); } /* ok */ lsocket = sfd; if (verbose > 0) fprintf (stderr, "%s: listening to port %d on fd %d\n", indi_tstamp(NULL), port, sfd); } /* Attempt to open up FIFO */ static void indiFIFO(void) { close(fifo.fd); fifo.fd=-1; /* Open up FIFO, if available */ if (fifo.name) { fifo.fd = open(fifo.name, O_RDWR | O_NONBLOCK); if (fifo.fd < 0) { fprintf(stderr, "%s: open(%s): %s.\n", indi_tstamp(NULL), fifo.name, strerror(errno)); Bye(); } } } /* service traffic from clients and drivers */ static void indiRun(void) { fd_set rs, ws; int maxfd=0; int i, s; /* init with no writers or readers */ FD_ZERO(&ws); FD_ZERO(&rs); if (fifo.name && fifo.fd >=0) { FD_SET(fifo.fd, &rs); maxfd = fifo.fd; } /* always listen for new clients */ FD_SET(lsocket, &rs); if (lsocket > maxfd) maxfd = lsocket; /* add all client readers and client writers with work to send */ for (i = 0; i < nclinfo; i++) { ClInfo *cp = &clinfo[i]; if (cp->active) { FD_SET(cp->s, &rs); if (nFQ(cp->msgq) > 0) FD_SET(cp->s, &ws); if (cp->s > maxfd) maxfd = cp->s; } } /* add all driver readers and driver writers with work to send */ for (i = 0; i < ndvrinfo; i++) { DvrInfo *dp = &dvrinfo[i]; if (dp->active) { FD_SET(dp->rfd, &rs); if (dp->rfd > maxfd) maxfd = dp->rfd; if (dp->pid != REMOTEDVR) { FD_SET(dp->efd, &rs); if (dp->efd > maxfd) maxfd = dp->efd; } if (nFQ(dp->msgq) > 0) { FD_SET(dp->wfd, &ws); if (dp->wfd > maxfd) maxfd = dp->wfd; } } } /* wait for action */ s = select (maxfd+1, &rs, &ws, NULL, NULL); if (s < 0) { fprintf (stderr, "%s: select(%d): %s\n", indi_tstamp(NULL), maxfd+1, strerror(errno)); Bye(); } /* new command from FIFO? */ if (s > 0 && fifo.fd >= 0 && FD_ISSET(fifo.fd, &rs)) { newFIFO(); s--; } /* new client? */ if (s > 0 && FD_ISSET(lsocket, &rs)) { newClient(); s--; } /* message to/from client? */ for (i = 0; s > 0 && i < nclinfo; i++) { ClInfo *cp = &clinfo[i]; if (cp->active) { if (FD_ISSET(cp->s, &rs)) { if (readFromClient(cp) < 0) return; /* fds effected */ s--; } if (s > 0 && FD_ISSET(cp->s, &ws)) { if (sendClientMsg(cp) < 0) return; /* fds effected */ s--; } } } /* message to/from driver? */ for (i = 0; s > 0 && i < ndvrinfo; i++) { DvrInfo *dp = &dvrinfo[i]; if (dp->pid != REMOTEDVR && FD_ISSET(dp->efd, &rs)) { if (stderrFromDriver(dp) < 0) return; /* fds effected */ s--; } if (s > 0 && FD_ISSET(dp->rfd, &rs)) { if (readFromDriver(dp) < 0) return; /* fds effected */ s--; } if (s > 0 && FD_ISSET(dp->wfd, &ws) && nFQ(dp->msgq) > 0) { if (sendDriverMsg(dp) < 0) return; /* fds effected */ s--; } } } int isDeviceInDriver(const char *dev, DvrInfo *dp) { int i=0; for (i=0; i ndev; i++) { if (!strcmp(dev, dp->dev[i])) return 1; } return 0; } /* Read commands from FIFO and process them. Start/stop drivers accordingly */ static void newFIFO(void) { //char line[MAXRBUF], tDriver[MAXRBUF], tConfig[MAXRBUF], tDev[MAXRBUF], tSkel[MAXRBUF], envDev[MAXRBUF], envConfig[MAXRBUF], envSkel[MAXR]; char line[MAXRBUF]; DvrInfo *dp = NULL; int startCmd=0, i=0; while (i < MAXRBUF) { if (read(fifo.fd, line+i, 1) <= 0) { // Reset FIFO now, otherwise select will always return with no data from FIFO. indiFIFO(); return; } if (line[i] == '\n') { line[i] = '\0'; i=0; } else { i++; continue; } if (verbose) fprintf(stderr, "FIFO: %s\n", line); char cmd[MAXSBUF], arg[3][1], var[3][MAXSBUF], tDriver[MAXSBUF], tName[MAXSBUF], envDev[MAXSBUF], envConfig[MAXSBUF], envSkel[MAXSBUF]; memset(&tDriver[0], 0, sizeof(MAXSBUF)); memset(&tName[0], 0, sizeof(MAXSBUF)); memset(&envDev[0], 0, sizeof(MAXSBUF)); memset(&envConfig[0], 0, sizeof(MAXSBUF)); memset(&envSkel[0], 0, sizeof(MAXSBUF)); int n = sscanf(line, "%s %s -%1c \"%512[^\"]\" -%1c \"%512[^\"]\" -%1c \"%512[^\"]\"", cmd, tDriver, arg[0], var[0], arg[1], var[1] , arg[2], var[2]); int n_args = (n - 2)/2; int j=0; for (j=0; j < n_args; j++) { //fprintf(stderr, "arg[%d]: %c\n", i, arg[j][0]); //fprintf(stderr, "var[%d]: %s\n", i, var[j]); if (arg[j][0] == 'n') { strncpy(tName, var[j], MAXSBUF-1); tName[MAXSBUF-1] = '\0'; snprintf(envDev, MAXSBUF, "INDIDEV=%s", tName); if (verbose) fprintf(stderr, "With name: %s\n", envDev); putenv(envDev); } else if (arg[j][0] == 'c') { snprintf(envConfig, MAXSBUF, "INDICONFIG=%s", var[j]); if (verbose) fprintf(stderr, "With config: %s\n", envConfig); putenv(envConfig); } else if (arg[j][0] == 's') { snprintf(envSkel, MAXSBUF, "INDISKEL=%s", var[j]); if (verbose) fprintf(stderr, "With skeketon: %s\n", envSkel); putenv(envSkel); } } if (!strcmp(cmd, "start")) startCmd = 1; else startCmd = 0; if (startCmd) { if (verbose) fprintf(stderr, "FIFO: Starting driver %s\n", tDriver); dp = allocDvr(); strncpy(dp->name, tDriver, MAXINDIDEVICE); //strncpy(dp->dev, tName, MAXINDIDEVICE); startDvr (dp); } else { for (dp = dvrinfo; dp < &dvrinfo[ndvrinfo]; dp++) { fprintf(stderr, "dp->name: %s - tDriver: %s\n", dp->name, tDriver); if (!strcmp(dp->name, tDriver) && dp->active==1) { fprintf(stderr, "name: %s - dp->dev[0]: %s\n", tName, dp->dev[0]); /* If device name is given, check against it before shutting down */ //if (tName[0] && strcmp(dp->dev[0], tName)) if (tName[0] && isDeviceInDriver(tName, dp) == 0) continue; if (verbose) fprintf(stderr, "FIFO: Shutting down driver: %s\n", tDriver); shutdownDvr(dp, 0); for (i=0; i < dp->ndev; i++) { /* Inform clients that this driver is dead */ XMLEle *root = addXMLEle (NULL, "delProperty"); addXMLAtt(root, "device", dp->dev[i]); prXMLEle(stderr, root, 0); Msg * mp = newMsg(); q2Clients(NULL, 0, dp->dev[i], NULL, mp, root); if (mp->count > 0) setMsgXMLEle (mp, root); else freeMsg (mp); delXMLEle (root); } break; } } } } } /* prepare for new client arriving on lsocket. * exit if trouble. */ static void newClient() { ClInfo *cp = NULL; int s, cli; /* assign new socket */ s = newClSocket (); /* try to reuse a clinfo slot, else add one */ for (cli = 0; cli < nclinfo; cli++) if (!(cp = &clinfo[cli])->active) break; if (cli == nclinfo) { /* grow clinfo */ clinfo = (ClInfo *) realloc (clinfo, (nclinfo+1)*sizeof(ClInfo)); if (!clinfo) { fprintf (stderr, "no memory for new client\n"); Bye(); } cp = &clinfo[nclinfo++]; } /* rig up new clinfo entry */ memset (cp, 0, sizeof(*cp)); cp->active = 1; cp->s = s; cp->lp = newLilXML(); cp->msgq = newFQ(1); cp->props = malloc (1); cp->nsent = 0; if (verbose > 0) { struct sockaddr_in addr; socklen_t len = sizeof(addr); getpeername(s, (struct sockaddr*)&addr, &len); fprintf(stderr,"%s: Client %d: new arrival from %s:%d - welcome!\n", indi_tstamp(NULL), cp->s, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } } /* read more from the given client, send to each appropriate driver when see * xml closure. also send all newXXX() to all other interested clients. * return -1 if had to shut down anything, else 0. */ static int readFromClient (ClInfo *cp) { char buf[MAXRBUF]; int shutany = 0; int i, nr; /* read client */ nr = read (cp->s, buf, sizeof(buf)); if (nr <= 0) { if (nr < 0) fprintf (stderr, "%s: Client %d: read: %s\n", indi_tstamp(NULL), cp->s, strerror(errno)); else if (verbose > 0) fprintf (stderr, "%s: Client %d: read EOF\n", indi_tstamp(NULL), cp->s); shutdownClient (cp); return (-1); } /* process XML, sending when find closure */ for (i = 0; i < nr; i++) { char err[1024]; XMLEle *root = readXMLEle (cp->lp, buf[i], err); if (root) { char *roottag = tagXMLEle(root); const char *dev = findXMLAttValu (root, "device"); const char *name = findXMLAttValu (root, "name"); int isblob = !strcmp (tagXMLEle(root), "setBLOBVector"); Msg *mp; if (verbose > 2) { fprintf (stderr, "%s: Client %d: read ",indi_tstamp(NULL),cp->s); traceMsg (root); } else if (verbose > 1) { fprintf (stderr, "%s: Client %d: read <%s device='%s' name='%s'>\n", indi_tstamp(NULL), cp->s, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } /* snag interested properties. * N.B. don't open to alldevs if seen specific dev already, else * remote client connections start returning too much. */ if (dev[0]) addClDevice (cp, dev, name, isblob); else if (!strcmp (roottag, "getProperties") && !cp->nprops) cp->allprops = 1; /* snag enableBLOB -- send to remote drivers too */ if (!strcmp (roottag, "enableBLOB")) // crackBLOB (pcdataXMLEle(root), &cp->blob); crackBLOBHandling (dev, name, pcdataXMLEle(root), cp); /* build a new message -- set content iff anyone cares */ mp = newMsg(); /* send message to driver(s) responsible for dev */ q2RDrivers (dev, mp, root); /* echo new* commands back to other clients */ if (!strncmp (roottag, "new", 3)) { if (q2Clients (cp, isblob, dev, name, mp, root) < 0) shutany++; } /* set message content if anyone cares else forget it */ if (mp->count > 0) setMsgXMLEle (mp, root); else freeMsg (mp); delXMLEle (root); } else if (err[0]) { char *ts = indi_tstamp(NULL); fprintf (stderr, "%s: Client %d: XML error: %s\n", ts, cp->s, err); fprintf (stderr, "%s: Client %d: XML read: %.*s\n", ts, cp->s, nr, buf); shutdownClient (cp); return (-1); } } return (shutany ? -1 : 0); } /* read more from the given driver, send to each interested client when see * xml closure. if driver dies, try restarting. * return 0 if ok else -1 if had to shut down anything. */ static int readFromDriver (DvrInfo *dp) { char buf[MAXRBUF]; int shutany = 0; int i, nr; /* read driver */ nr = read (dp->rfd, buf, sizeof(buf)); if (nr <= 0) { if (nr < 0) fprintf (stderr, "%s: Driver %s: stdin %s\n", indi_tstamp(NULL), dp->name, strerror(errno)); else fprintf (stderr, "%s: Driver %s: stdin EOF\n", indi_tstamp(NULL), dp->name); shutdownDvr (dp, 1); return (-1); } /* process XML, sending when find closure */ for (i = 0; i < nr; i++) { char err[1024]; XMLEle *root = readXMLEle (dp->lp, buf[i], err); if (root) { char *roottag = tagXMLEle(root); const char *dev = findXMLAttValu (root, "device"); const char *name = findXMLAttValu (root, "name"); int isblob = !strcmp (tagXMLEle(root), "setBLOBVector"); Msg *mp; if (verbose > 2) { fprintf(stderr, "%s: Driver %s: read ", indi_tstamp(0),dp->name); traceMsg (root); } else if (verbose > 1) { fprintf (stderr, "%s: Driver %s: read <%s device='%s' name='%s'>\n", indi_tstamp(NULL), dp->name, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } /* that's all if driver is just registering a snoop */ if (!strcmp (roottag, "getProperties")) { addSDevice (dp, dev, name); delXMLEle (root); continue; } /* that's all if driver is just registering a BLOB mode */ if (!strcmp (roottag, "enableBLOB")) { Property *sp = findSDevice (dp, dev, name); if (sp) crackBLOB (pcdataXMLEle (root), &sp->blob); delXMLEle (root); continue; } /* Found a new device? Let's add it to driver info */ if (dev[0] && isDeviceInDriver(dev, dp) == 0) { dp->dev = (char **) realloc(dp->dev, (dp->ndev+1) * sizeof(char *)); dp->dev[dp->ndev] = (char *) malloc(MAXINDIDEVICE * sizeof(char)); strncpy (dp->dev[dp->ndev], dev, MAXINDIDEVICE-1); dp->dev[dp->ndev][MAXINDIDEVICE-1] = '\0'; dp->ndev++; } /* log messages if any and wanted */ if (ldir) logDMsg (root, dev); /* build a new message -- set content iff anyone cares */ mp = newMsg(); /* send to interested clients */ if (q2Clients (NULL, isblob, dev, name, mp, root) < 0) shutany++; /* send to snooping drivers */ q2SDrivers (isblob, dev, name, mp, root); /* set message content if anyone cares else forget it */ if (mp->count > 0) setMsgXMLEle (mp, root); else freeMsg (mp); delXMLEle (root); } else if (err[0]) { char *ts = indi_tstamp(NULL); fprintf (stderr, "%s: Driver %s: XML error: %s\n", ts, dp->name, err); fprintf (stderr, "%s: Driver %s: XML read: %.*s\n", ts, dp->name, nr, buf); shutdownDvr (dp, 1); return (-1); } } return (shutany ? -1 : 0); } /* read more from the given driver stderr, add prefix and send to our stderr. * return 0 if ok else -1 if had to restart. */ static int stderrFromDriver (DvrInfo *dp) { static char exbuf[MAXRBUF]; static int nexbuf; int i, nr; /* read more */ nr = read (dp->efd, exbuf+nexbuf, sizeof(exbuf)-nexbuf); if (nr <= 0) { if (nr < 0) fprintf (stderr, "%s: Driver %s: stderr %s\n", indi_tstamp(NULL), dp->name, strerror(errno)); else fprintf (stderr, "%s: Driver %s: stderr EOF\n", indi_tstamp(NULL), dp->name); shutdownDvr (dp, 1); return (-1); } nexbuf += nr; /* prefix each whole line to our stderr, save extra for next time */ for (i = 0; i < nexbuf; i++) { if (exbuf[i] == '\n') { fprintf (stderr, "%s: Driver %s: %.*s\n", indi_tstamp(NULL), dp->name, i, exbuf); i++; /* count including nl */ nexbuf -= i; /* remove from nexbuf */ memmove (exbuf, exbuf+i, nexbuf); /* slide remaining to front */ i = -1; /* restart for loop scan */ } } return (0); } /* close down the given client */ static void shutdownClient (ClInfo *cp) { Msg *mp; /* close connection */ shutdown (cp->s, SHUT_RDWR); close (cp->s); /* free memory */ delLilXML (cp->lp); free (cp->props); /* decrement and possibly free any unsent messages for this client */ while ((mp = (Msg*) popFQ(cp->msgq)) != NULL) if (--mp->count == 0) freeMsg (mp); delFQ (cp->msgq); /* ok now to recycle */ cp->active = 0; if (verbose > 0) fprintf (stderr, "%s: Client %d: shut down complete - bye!\n", indi_tstamp(NULL), cp->s); } /* close down the given driver and restart */ static void shutdownDvr (DvrInfo *dp, int restart) { Msg *mp; /* make sure it's dead, reclaim resources */ if (dp->pid == REMOTEDVR) { /* socket connection */ shutdown (dp->wfd, SHUT_RDWR); close (dp->wfd); /* same as rfd */ } else { /* local pipe connection */ kill (dp->pid, SIGKILL); /* we've insured there are no zombies */ close (dp->wfd); close (dp->rfd); close (dp->efd); } /* free memory */ free (dp->sprops); free(dp->dev); delLilXML (dp->lp); /* ok now to recycle */ dp->active = 0; dp->ndev = 0; /* decrement and possibly free any unsent messages for this client */ while ((mp = (Msg*) popFQ(dp->msgq)) != NULL) if (--mp->count == 0) freeMsg (mp); delFQ (dp->msgq); if (restart) { fprintf (stderr, "%s: Driver %s: restart #%d\n", indi_tstamp(NULL), dp->name, ++dp->restarts); startDvr (dp); } } /* put Msg mp on queue of each driver responsible for dev, or all drivers * if dev not specified. */ static void q2RDrivers (const char *dev, Msg *mp, XMLEle *root) { int sawremote = 0; DvrInfo *dp; /* queue message to each interested driver. * N.B. don't send generic getProps to more than one remote driver, * otherwise they all fan out and we get multiple responses back. */ for (dp = dvrinfo; dp < &dvrinfo[ndvrinfo]; dp++) { int isremote = (dp->pid == REMOTEDVR); if (dp->active == 0) continue; //if (dev[0] && dp->dev[0] && strcmp (dev, dp->dev)) if (dev[0] && isDeviceInDriver(dev, dp) == 0) continue; /* driver known to not support this dev */ if (!dev[0] && isremote && sawremote) continue; /* already sent generic to another remote */ if (isremote) sawremote = 1; /* ok: queue message to this driver */ mp->count++; pushFQ (dp->msgq, mp); if (verbose > 1) fprintf (stderr, "%s: Driver %s: queuing responsible for <%s device='%s' name='%s'>\n", indi_tstamp(NULL), dp->name, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } } /* put Msg mp on queue of each driver snooping dev/name. * if BLOB always honor current mode. */ static void q2SDrivers (int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root) { DvrInfo *dp; for (dp = dvrinfo; dp < &dvrinfo[ndvrinfo]; dp++) { Property *sp = findSDevice (dp, dev, name); /* nothing for dp if not snooping for dev/name or wrong BLOB mode */ if (!sp) continue; if ((isblob && sp->blob==B_NEVER) || (!isblob && sp->blob==B_ONLY)) continue; /* ok: queue message to this device */ mp->count++; pushFQ (dp->msgq, mp); if (verbose > 1) { fprintf (stderr, "%s: Driver %s: queuing snooped <%s device='%s' name='%s'>\n", indi_tstamp(NULL), dp->name, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } } } /* add dev/name to dp's snooping list. * init with blob mode set to B_NEVER. */ static void addSDevice (DvrInfo *dp, const char *dev, const char *name) { Property *sp; char *ip; /* no dups */ sp = findSDevice (dp, dev, name); if (sp) return; /* add dev to sdevs list */ dp->sprops = (Property*) realloc (dp->sprops, (dp->nsprops+1)*sizeof(Property)); sp = &dp->sprops[dp->nsprops++]; ip = sp->dev; strncpy (ip, dev, MAXINDIDEVICE-1); ip[MAXINDIDEVICE-1] = '\0'; ip = sp->name; strncpy (ip, name, MAXINDINAME-1); ip[MAXINDINAME-1] = '\0'; sp->blob = B_NEVER; if (verbose) fprintf (stderr, "%s: Driver %s: snooping on %s.%s\n", indi_tstamp(NULL), dp->name, dev, name); } /* return Property if dp is snooping dev/name, else NULL. */ static Property * findSDevice (DvrInfo *dp, const char *dev, const char *name) { int i; for (i = 0; i < dp->nsprops; i++) { Property *sp = &dp->sprops[i]; if (!strcmp (sp->dev, dev) && (!sp->name[0] || !strcmp(sp->name, name))) return (sp); } return (NULL); } /* put Msg mp on queue of each client interested in dev/name, except notme. * if BLOB always honor current mode. * return -1 if had to shut down any clients, else 0. */ static int q2Clients (ClInfo *notme, int isblob, const char *dev, const char *name, Msg *mp, XMLEle *root) { int shutany = 0; ClInfo *cp; int ql,i=0; /* queue message to each interested client */ for (cp = clinfo; cp < &clinfo[nclinfo]; cp++) { /* cp in use? notme? want this dev/name? blob? */ if (!cp->active || cp == notme) continue; if (findClDevice (cp, dev, name) < 0) continue; //if ((isblob && cp->blob==B_NEVER) || (!isblob && cp->blob==B_ONLY)) if (!isblob && cp->blob==B_ONLY) continue; if (isblob) { if (cp->nprops > 0) { Property *pp = NULL; int blob_found=0; for (i = 0; i < cp->nprops; i++) { pp = &cp->props[i]; if (!strcmp (pp->dev, dev) && (!strcmp(pp->name, name))) { blob_found = 1; break; } } if ( (blob_found && pp->blob == B_NEVER) || (blob_found==0 && cp->blob == B_NEVER) ) continue; } else if (cp->blob == B_NEVER) continue; } /* shut down this client if its q is already too large */ ql = msgQSize(cp->msgq); if (ql > maxqsiz) { if (verbose) fprintf (stderr, "%s: Client %d: %d bytes behind, shutting down\n", indi_tstamp(NULL), cp->s, ql); shutdownClient (cp); shutany++; continue; } /* ok: queue message to this client */ mp->count++; pushFQ (cp->msgq, mp); if (verbose > 1) fprintf (stderr, "%s: Client %d: queuing <%s device='%s' name='%s'>\n", indi_tstamp(NULL), cp->s, tagXMLEle(root), findXMLAttValu (root, "device"), findXMLAttValu (root, "name")); } return (shutany ? -1 : 0); } /* return size of all Msqs on the given q */ static int msgQSize (FQ *q) { int i, l = 0; for (i = 0; i < nFQ(q); i++) { Msg *mp = (Msg *) peekiFQ(q,i); l += mp->cl; } return (l); } /* print root as content in Msg mp. */ static void setMsgXMLEle (Msg *mp, XMLEle *root) { /* want cl to only count content, but need room for final \0 */ mp->cl = sprlXMLEle (root, 0); if (mp->cl < sizeof(mp->buf)) mp->cp = mp->buf; else mp->cp = malloc (mp->cl+1); sprXMLEle (mp->cp, root, 0); } /* save str as content in Msg mp. */ static void setMsgStr (Msg *mp, char *str) { /* want cl to only count content, but need room for final \0 */ mp->cl = strlen (str); if (mp->cl < sizeof(mp->buf)) mp->cp = mp->buf; else mp->cp = malloc (mp->cl+1); strcpy (mp->cp, str); } /* return pointer to one new nulled Msg */ static Msg * newMsg (void) { return ((Msg *) calloc (1, sizeof(Msg))); } /* free Msg mp and everything it contains */ static void freeMsg (Msg *mp) { if (mp->cp && mp->cp != mp->buf) free (mp->cp); free (mp); } /* write the next chunk of the current message in the queue to the given * client. pop message from queue when complete and free the message if we are * the last one to use it. shut down this client if trouble. * N.B. we assume we will never be called with cp->msgq empty. * return 0 if ok else -1 if had to shut down. */ static int sendClientMsg (ClInfo *cp) { int nsend, nw; Msg *mp; /* get current message */ mp = (Msg *) peekFQ (cp->msgq); /* send next chunk, never more than MAXWSIZ to reduce blocking */ nsend = mp->cl - cp->nsent; if (nsend > MAXWSIZ) nsend = MAXWSIZ; nw = write (cp->s, &mp->cp[cp->nsent], nsend); /* shut down if trouble */ if (nw <= 0) { if (nw == 0) fprintf (stderr, "%s: Client %d: write returned 0\n", indi_tstamp(NULL), cp->s); else fprintf (stderr, "%s: Client %d: write: %s\n", indi_tstamp(NULL), cp->s, strerror(errno)); shutdownClient (cp); return (-1); } /* trace */ if (verbose > 2) { fprintf(stderr, "%s: Client %d: sending msg copy %d nq %d:\n%.*s\n", indi_tstamp(NULL), cp->s, mp->count, nFQ(cp->msgq), nw, &mp->cp[cp->nsent]); } else if (verbose > 1) { fprintf(stderr, "%s: Client %d: sending %.50s\n", indi_tstamp(NULL), cp->s, &mp->cp[cp->nsent]); } /* update amount sent. when complete: free message if we are the last * to use it and pop from our queue. */ cp->nsent += nw; if (cp->nsent == mp->cl) { if (--mp->count == 0) freeMsg (mp); popFQ (cp->msgq); cp->nsent = 0; } return (0); } /* write the next chunk of the current message in the queue to the given * driver. pop message from queue when complete and free the message if we are * the last one to use it. restart this driver if touble. * N.B. we assume we will never be called with dp->msgq empty. * return 0 if ok else -1 if had to shut down. */ static int sendDriverMsg (DvrInfo *dp) { int nsend, nw; Msg *mp; /* get current message */ mp = (Msg *) peekFQ (dp->msgq); /* send next chunk, never more than MAXWSIZ to reduce blocking */ nsend = mp->cl - dp->nsent; if (nsend > MAXWSIZ) nsend = MAXWSIZ; nw = write (dp->wfd, &mp->cp[dp->nsent], nsend); /* restart if trouble */ if (nw <= 0) { if (nw == 0) fprintf (stderr, "%s: Driver %s: write returned 0\n", indi_tstamp(NULL), dp->name); else fprintf (stderr, "%s: Driver %s: write: %s\n", indi_tstamp(NULL), dp->name, strerror(errno)); shutdownDvr (dp, 1); return (-1); } /* trace */ if (verbose > 2) { fprintf(stderr, "%s: Driver %s: sending msg copy %d nq %d:\n%.*s\n", indi_tstamp(NULL), dp->name, mp->count, nFQ(dp->msgq), nw, &mp->cp[dp->nsent]); } else if (verbose > 1) { fprintf(stderr, "%s: Driver %s: sending %.50s\n", indi_tstamp(NULL), dp->name, &mp->cp[dp->nsent]); } /* update amount sent. when complete: free message if we are the last * to use it and pop from our queue. */ dp->nsent += nw; if (dp->nsent == mp->cl) { if (--mp->count == 0) freeMsg (mp); popFQ (dp->msgq); dp->nsent = 0; } return (0); } /* return 0 if cp may be interested in dev/name else -1 */ static int findClDevice (ClInfo *cp, const char *dev, const char *name) { int i; if (cp->allprops || !dev[0]) return (0); for (i = 0; i < cp->nprops; i++) { Property *pp = &cp->props[i]; if (!strcmp (pp->dev, dev) && (!pp->name[0] || !strcmp(pp->name, name))) return (0); } return (-1); } /* add the given device and property to the devs[] list of client if new. */ static void addClDevice (ClInfo *cp, const char *dev, const char *name, int isblob) { Property *pp; char *ip; int i=0; if (isblob) { for (i = 0; i < cp->nprops; i++) { Property *pp = &cp->props[i]; if (!strcmp (pp->dev, dev) && (name==NULL || !strcmp(pp->name, name))) return; } } /* no dups */ else if (!findClDevice (cp, dev, name)) return; /* add */ cp->props = (Property *) realloc (cp->props, (cp->nprops+1)*sizeof(Property)); pp = &cp->props[cp->nprops++]; /*ip = pp->dev; strncpy (ip, dev, MAXINDIDEVICE-1); ip[MAXINDIDEVICE-1] = '\0'; ip = pp->name; strncpy (ip, name, MAXINDINAME-1); ip[MAXINDINAME-1] = '\0';*/ strncpy (pp->dev, dev, MAXINDIDEVICE); strncpy (pp->name, name, MAXINDINAME); pp->blob = B_NEVER; } /* block to accept a new client arriving on lsocket. * return private nonblocking socket or exit. */ static int newClSocket () { struct sockaddr_in cli_socket; socklen_t cli_len; int cli_fd; /* get a private connection to new client */ cli_len = sizeof(cli_socket); cli_fd = accept (lsocket, (struct sockaddr *)&cli_socket, &cli_len); if(cli_fd < 0) { fprintf (stderr, "accept: %s\n", strerror(errno)); Bye(); } /* ok */ return (cli_fd); } /* convert the string value of enableBLOB to our B_ state value. * no change if unrecognized */ static void crackBLOB (const char *enableBLOB, BLOBHandling *bp) { if (!strcmp (enableBLOB, "Also")) *bp = B_ALSO; else if (!strcmp (enableBLOB, "Only")) *bp = B_ONLY; else if (!strcmp (enableBLOB, "Never")) *bp = B_NEVER; } /* Update the client property BLOB handling policy */ static void crackBLOBHandling(const char *dev, const char *name, const char *enableBLOB, ClInfo *cp) { int i=0; /* If we have EnableBLOB with property name, we add it to Client device list */ if (name[0]) addClDevice (cp, dev, name, 1); else /* Otherwise, we set the whole client blob handling to what's passed (enableBLOB) */ crackBLOB(enableBLOB, &cp->blob); /* If whole client blob handling policy was updated, we need to pass that also to all children and if the request was for a specific property, then we apply the policy to it */ for (i = 0; i < cp->nprops; i++) { Property *pp = &cp->props[i]; if (!name[0]) crackBLOB(enableBLOB, &pp->blob); else if (!strcmp (pp->dev, dev) && (!strcmp(pp->name, name))) { crackBLOB(enableBLOB, &pp->blob); return; } } } /* print key attributes and values of the given xml to stderr. */ static void traceMsg (XMLEle *root) { static const char *prtags[] = { "defNumber", "oneNumber", "defText", "oneText", "defSwitch", "oneSwitch", "defLight", "oneLight", }; XMLEle *e; const char *msg, *perm, *pcd; unsigned int i; /* print tag header */ fprintf (stderr, "%s %s %s %s", tagXMLEle(root), findXMLAttValu(root,"device"), findXMLAttValu(root,"name"), findXMLAttValu(root,"state")); pcd = pcdataXMLEle (root); if (pcd[0]) fprintf (stderr, " %s", pcd); perm = findXMLAttValu(root,"perm"); if (perm[0]) fprintf (stderr, " %s", perm); msg = findXMLAttValu(root,"message"); if (msg[0]) fprintf (stderr, " '%s'", msg); /* print each array value */ for (e = nextXMLEle(root,1); e; e = nextXMLEle(root,0)) for (i = 0; i < sizeof(prtags)/sizeof(prtags[0]); i++) if (strcmp (prtags[i], tagXMLEle(e)) == 0) fprintf (stderr, "\n %10s='%s'", findXMLAttValu(e,"name"), pcdataXMLEle (e)); fprintf (stderr, "\n"); } /* fill s with current UT string. * if no s, use a static buffer * return s or buffer. * N.B. if use our buffer, be sure to use before calling again */ static char * indi_tstamp (char *s) { static char sbuf[64]; struct tm *tp; time_t t; time (&t); tp = gmtime (&t); if (!s) s = sbuf; strftime (s, sizeof(sbuf), "%Y-%m-%dT%H:%M:%S", tp); return (s); } /* log message in root known to be from device dev to ldir, if any. */ static void logDMsg (XMLEle *root, const char *dev) { char stamp[64]; char logfn[1024]; const char *ts, *ms; FILE *fp; /* get message, if any */ ms = findXMLAttValu (root, "message"); if (!ms[0]) return; /* get timestamp now if not provided */ ts = findXMLAttValu (root, "timestamp"); if (!ts[0]) { indi_tstamp (stamp); ts = stamp; } /* append to log file, name is date portion of time stamp */ sprintf (logfn, "%s/%.10s.islog", ldir, ts); fp = fopen (logfn, "a"); if (!fp) return; /* oh well */ fprintf (fp, "%s: %s: %s\n", ts, dev, ms); fclose (fp); } /* log when then exit */ static void Bye() { fprintf (stderr, "%s: good bye\n", indi_tstamp(NULL)); exit(1); } libindi-0.9.7/ChangeLog0000644000175000017500000001400712241463551013700 0ustar jasemjasemFrom 0.9.6 to 0.9.7 + Support for EQMod mount driver (3rd party). + Support for ATIK CCDs and Filter Wheels (3rd party). + Support for Shoestring Astronomy FCUSB (3rd party). + Support for joysticks and game pads under Linux. + LX200, Celeston, and EQMod drivers support joystick input. + Improved LX200 & Celestron telescope drivers. + Improved simulator drivers. + INDI server support for multiple devices per driver. + New universal logging and debugging framework for INDI developers. + Fixed an issue in TCFS driver where a connect may fail if focuser is put into sleep mode. + Fixed an issue where the client thread in INDI::BaseClient is not being terminated gracefully in blocking mode. + Fixed an issue involving non-English clients that utilize INDI client library to communicate with INDI server. + Fixed an issue where some properties in some drivers are sent before getting defined by INDI. From 0.9.5 to 0.9.6 + Support for Starlight Xpress Adaptive Optics unit. + Improved support for Startlight Xpress CCDs and Filter wheels. + Support for Arduino boards, with customizable drivers for common observatory auxiliary devices. + Support for GPUSB Guide Port Interface. + Improved support for QSI CCDs and Filter wheels. + Support for filters with absolute positioning. + Support for cameras with guiding chip. + Fixed INDI server FIFO CPU utilization bug. + Fixed various bugs with v4l drivers due to code regression. + Improved support for Mac OS X. + Improved simulators. + _REQUEST properties are now deprecated. + Updated tutorials and API. From 0.9 to 0.95 # Focuser simulator driver. # CCD, Telescope, Focuser, and Filter simulators improvements including periodic error effects, FWHM, and more. # Major improvements to INDI Base Library and INDI Client Library. # Fixed minor bugs in LX200 Generic, LX200 FS2, Magellan, and Celestron drivers. # Minor bugfixes and improvements. From 0.8 to 0.9 # iEQ45 GoTo German Equatorial Mount Driver. # INDI::Base drivers are now used for most classes of astrnomical instruments. # New improved QSI CCD & Filter driver. # New improved Starlight Xpress CCD & Filter driver. # New improved RoboFocus driver. # libboost is no longer required to build libindi. # Numerous bug fixes and minor improvements. From 0.7.2 to 0.8 # TCF-S Focuser driver. # Synscan Telescope driver. From 0.7.0 to 0.7.1 # Fixed change filter bug in true technology filter wheel. (JM) # setINDI updated and improved. (ED) # Improved INDI::Mediator functionality. (JM) # Fixed buffer reading in INDI::BaseClient. (JM) # Add new tutorial for INDI::BaseClient. (JM). From 0.6.2 to 0.7.0 # Dynamic renaming of drivers upon run time. # Standard helper API to create and utilize INDI clients. # Ability to load driver properties from an external XML file. # Ability to write/read XML configuration files for driver values to be loaded at run time. # Facilitating debugging and simulation of drivers. # New C++ framework to facilitate the development of new INDI drivers. # Several bug fixes for current drivers and framework. From 0.6.1 to 0.6.2 # Build related updates. From 0.6 to 0.6.1 # Updating drivers.xml to comply to new XML structure for group and devices metadata descriptions. From 0.5 to 0.6 # Devices: + Astrophysics mount is now working. + Apogee driver is now working. # Features: + New libindi structure to streamline development. + Drivers using Standard Property _REQUEST WO to make requests. This facilitates scripting and automation of drivers. + Updated inter-driver communication with INDI SNOOP. From 0.4 to 0.5 # Devices: + True Technology Filter Wheel + SBIG STV # Features: + Added INDI Observer pattern to enable flexible inter-driver communication. + getINDI now supports BLOBs. + LX200 Drivers use client timestamp to update the telescope internal clock. The old behavior was to use to system's time. + Added a new INDI Standard Property: UTC_OFFSET. + Dropping threaded INDI server in favor of the slightly better non-threaded version due to performance considerations. # Bugs + SBIG CCD driver was updated to fix problems with CFITSIO. + Updated TTY API to include error reporting, in addition to fixing a few bugs. + Fixed INDI Mac OSX Crash. # Known Issues + Astrophysics Mount driver (apmount) is not working. It is currently under new development and is intented to be released in the next version as it matures. + Meade LPI exposure is locked to 1 second. The Video4Linux support for timed exposures is limited. A fix should be available in the next release. + The SBIG driver does not allow autoguiding. When one selects the guider CCD, any exposure on the imaging CCD is cancelled and vice-versa. From v0.3 to v0.4: # Devices: + SBIG CCD + SBIG CFW + RoboFocus + FLI Precision Focuser + Orion Atlas / Sky Scan # Other: + Added more API documentation and revised existing documentation for accuracy and consistency. + Fixed UTC correction bug in LX200 driver. + Fixed pallete selection in V4L 2 drivers. + Fixed bug in eventloop that can cause IE timers to crash. + Added variable focus speed for Meade Autostar and GPS. + Added CFITSIO, a mature and robust FITS library. + New RS232 API for common access routines. From v0.2 to v0.3: # Devices: + Apogee CCD (Experimental) + SkyCommander + Temma Takahashi + FLI Filter Wheel + Meade Lunar Planetary Imager (Experimental) + Astrophysics AP # Other: + Support for Video 4 Linux 2 + Multi-threaded INDI server + Binary transfer via BLOB + INDI scripting tools + Various bug fixing INDI Library v1.0 conforms to INDI wire protocol v1.6 libindi-0.9.7/libs/0000755000175000017500000000000012241463551013055 5ustar jasemjasemlibindi-0.9.7/libs/lilxml.c0000644000175000017500000007736112241463551014540 0ustar jasemjasem#if 0 liblilxml Copyright (C) 2003 Elwood C. Downey 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 /* little DOM-style XML parser. * only handles elements, attributes and pcdata content. * and are silently ignored. * pcdata is collected into one string, sans leading whitespace first line. * * #define MAIN_TST to create standalone test program */ #include #include #include #include #include "lilxml.h" /* used to efficiently manage growing malloced string space */ typedef struct { char *s; /* malloced memory for string */ int sl; /* string length, sans trailing \0 */ int sm; /* total malloced bytes */ } String; #define MINMEM 64 /* starting string length */ static int oneXMLchar (LilXML *lp, int c, char ynot[]); static void initParser(LilXML *lp); static void pushXMLEle(LilXML *lp); static void popXMLEle(LilXML *lp); static void resetEndTag(LilXML *lp); static XMLAtt *growAtt(XMLEle *e); static XMLEle *growEle(XMLEle *pe); static void freeAtt (XMLAtt *a); static int isTokenChar (int start, int c); static void growString (String *sp, int c); static void appendString (String *sp, const char *str); static void freeString (String *sp); static void newString (String *sp); static void *moremem (void *old, int n); typedef enum { LOOK4START = 0, /* looking for first element start */ LOOK4TAG, /* looking for element tag */ INTAG, /* reading tag */ LOOK4ATTRN, /* looking for attr name, > or / */ INATTRN, /* reading attr name */ LOOK4ATTRV, /* looking for attr value */ SAWSLASH, /* saw / in element opening */ INATTRV, /* in attr value */ ENTINATTRV, /* in entity in attr value */ LOOK4CON, /* skipping leading content whitespc */ INCON, /* reading content */ ENTINCON, /* in entity in pcdata */ SAWLTINCON, /* saw < in content */ LOOK4CLOSETAG, /* looking for closing tag after < */ INCLOSETAG /* reading closing tag */ } State; /* parsing states */ /* maintain state while parsing */ struct _LilXML { State cs; /* current state */ int ln; /* line number for diags */ XMLEle *ce; /* current element being built */ String endtag; /* to check for match with opening tag*/ String entity; /* collect entity seq */ int delim; /* attribute value delimiter */ int lastc; /* last char (just used wiht skipping)*/ int skipping; /* in comment or declaration */ }; /* internal representation of a (possibly nested) XML element */ struct _xml_ele { String tag; /* element tag */ XMLEle *pe; /* parent element, or NULL if root */ XMLAtt **at; /* list of attributes */ int nat; /* number of attributes */ int ait; /* used to iterate over at[] */ XMLEle **el; /* list of child elements */ int nel; /* number of child elements */ int eit; /* used to iterate over el[] */ String pcdata; /* character data in this element */ int pcdata_hasent; /* 1 if pcdata contains an entity char*/ }; /* internal representation of an attribute */ struct _xml_att { String name; /* name */ String valu; /* value */ XMLEle *ce; /* containing element */ }; /* characters that need escaping as "entities" in attr values and pcdata */ static char entities[] = "&<>'\""; /* default memory managers, override with lilxmlMalloc() */ static void *(*mymalloc)(size_t size) = malloc; static void *(*myrealloc)(void *ptr, size_t size) = realloc; static void (*myfree)(void *ptr) = free; /* install new version of malloc/realloc/free. * N.B. don't call after first use of any other lilxml function */ void lilxmlMalloc (void *(*newmalloc)(size_t size), void *(*newrealloc)(void *ptr, size_t size), void (*newfree)(void *ptr)) { mymalloc = newmalloc; myrealloc = newrealloc; myfree = newfree; } /* pass back a fresh handle for use with our other functions */ LilXML * newLilXML () { LilXML *lp = (LilXML *) moremem (NULL, sizeof(LilXML)); memset (lp, 0, sizeof(LilXML)); initParser(lp); return (lp); } /* discard */ void delLilXML (LilXML *lp) { delXMLEle (lp->ce); freeString (&lp->endtag); (*myfree) (lp); } /* delete ep and all its children and remove from parent's list if known */ void delXMLEle (XMLEle *ep) { int i; /* benign if NULL */ if (!ep) return; /* delete all parts of ep */ freeString (&ep->tag); freeString (&ep->pcdata); if (ep->at) { for (i = 0; i < ep->nat; i++) freeAtt (ep->at[i]); (*myfree) (ep->at); } if (ep->el) { for (i = 0; i < ep->nel; i++) { /* forget parent so deleting doesn't modify _this_ el[] */ ep->el[i]->pe = NULL; delXMLEle (ep->el[i]); } (*myfree) (ep->el); } /* remove from parent's list if known */ if (ep->pe) { XMLEle *pe = ep->pe; for (i = 0; i < pe->nel; i++) { if (pe->el[i] == ep) { memmove (&pe->el[i], &pe->el[i+1], (--pe->nel-i)*sizeof(XMLEle*)); break; } } } /* delete ep itself */ (*myfree) (ep); } /* process one more character of an XML file. * when find closure with outter element return root of complete tree. * when find error return NULL with reason in ynot[]. * when need more return NULL with ynot[0] = '\0'. * N.B. it is up to the caller to delete any tree returned with delXMLEle(). */ XMLEle * readXMLEle (LilXML *lp, int newc, char ynot[]) { XMLEle *root; int s; /* start optimistic */ ynot[0] = '\0'; /* EOF? */ if (newc == 0) { sprintf (ynot, "Line %d: early XML EOF", lp->ln); initParser(lp); return (NULL); } /* new line? */ if (newc == '\n') lp->ln++; /* skip comments and declarations. requires 1 char history */ if (!lp->skipping && lp->lastc == '<' && (newc == '?' || newc == '!')) { lp->skipping = 1; lp->lastc = newc; return (NULL); } if (lp->skipping) { if (newc == '>') lp->skipping = 0; lp->lastc = newc; return (NULL); } if (newc == '<') { lp->lastc = '<'; return (NULL); } /* do a pending '<' first then newc */ if (lp->lastc == '<') { if (oneXMLchar (lp, '<', ynot) < 0) { initParser(lp); return (NULL); } /* N.B. we assume '<' will never result in closure */ } /* process newc (at last!) */ s = oneXMLchar (lp, newc, ynot); if (s == 0) { lp->lastc = newc; return (NULL); } if (s < 0) { initParser(lp); return (NULL); } /* Ok! return ce and we start over. * N.B. up to caller to call delXMLEle with what we return. */ root = lp->ce; lp->ce = NULL; initParser(lp); return (root); } /* parse the given XML string. * return XMLEle* else NULL with reason why in ynot[] */ XMLEle * parseXML (char buf[], char ynot[]) { LilXML *lp = newLilXML(); XMLEle *root; do { root = readXMLEle (lp, *buf++, ynot); } while (!root && !ynot[0]); delLilXML (lp); return (root); } /* return a deep copy of the given XMLEle * */ XMLEle * cloneXMLEle (XMLEle *ep) { char *buf; char ynot[1024]; XMLEle *newep; buf = (*mymalloc) (sprlXMLEle (ep, 0) + 1); sprXMLEle (buf, ep, 0); newep = parseXML (buf, ynot); (*myfree) (buf); return (newep); } /* search ep for an attribute with given name. * return NULL if not found. */ XMLAtt * findXMLAtt (XMLEle *ep, const char *name) { int i; for (i = 0; i < ep->nat; i++) if (!strcmp (ep->at[i]->name.s, name)) return (ep->at[i]); return (NULL); } /* search ep for an element with given tag. * return NULL if not found. */ XMLEle * findXMLEle (XMLEle *ep, const char *tag) { int tl = strlen (tag); int i; for (i = 0; i < ep->nel; i++) { String *sp = &ep->el[i]->tag; if (sp->sl == tl && !strcmp (sp->s, tag)) return (ep->el[i]); } return (NULL); } /* iterate over each child element of ep. * call first time with first set to 1, then 0 from then on. * returns NULL when no more or err */ XMLEle * nextXMLEle (XMLEle *ep, int init) { int eit; if (init) ep->eit = 0; eit = ep->eit++; if (eit < 0 || eit >= ep->nel) return (NULL); return (ep->el[eit]); } /* iterate over each attribute of ep. * call first time with first set to 1, then 0 from then on. * returns NULL when no more or err */ XMLAtt * nextXMLAtt (XMLEle *ep, int init) { int ait; if (init) ep->ait = 0; ait = ep->ait++; if (ait < 0 || ait >= ep->nat) return (NULL); return (ep->at[ait]); } /* return parent of given XMLEle */ XMLEle * parentXMLEle (XMLEle *ep) { return (ep->pe); } /* return parent element of given XMLAtt */ XMLEle * parentXMLAtt (XMLAtt *ap) { return (ap->ce); } /* access functions */ /* return the tag name of the given element */ char * tagXMLEle (XMLEle *ep) { return (ep->tag.s); } /* return the pcdata portion of the given element */ char * pcdataXMLEle (XMLEle *ep) { return (ep->pcdata.s); } /* return the number of characters in the pcdata portion of the given element */ int pcdatalenXMLEle (XMLEle *ep) { return (ep->pcdata.sl); } /* return the name of the given attribute */ char * nameXMLAtt (XMLAtt *ap) { return (ap->name.s); } /* return the value of the given attribute */ char * valuXMLAtt (XMLAtt *ap) { return (ap->valu.s); } /* return the number of child elements of the given element */ int nXMLEle (XMLEle *ep) { return (ep->nel); } /* return the number of attributes in the given element */ int nXMLAtt (XMLEle *ep) { return (ep->nat); } /* search ep for an attribute with the given name and return its value. * return "" if not found. */ const char * findXMLAttValu (XMLEle *ep, const char *name) { XMLAtt *a = findXMLAtt (ep, name); return (a ? a->valu.s : ""); } /* handy wrapper to read one xml file. * return root element else NULL with report in ynot[] */ XMLEle * readXMLFile (FILE *fp, LilXML *lp, char ynot[]) { int c; while ((c = fgetc(fp)) != EOF) { XMLEle *root = readXMLEle (lp, c, ynot); if (root || ynot[0]) return (root); } return (NULL); } /* add an element with the given tag to the given element. * parent can be NULL to make a new root. */ XMLEle * addXMLEle (XMLEle *parent, const char *tag) { XMLEle *ep = growEle (parent); appendString (&ep->tag, tag); return (ep); } /* append an existing element to the given element. * N.B. be mindful of when these are deleted, this is not a deep copy. */ void appXMLEle (XMLEle *ep, XMLEle *newep) { ep->el = (XMLEle **) moremem (ep->el, (ep->nel+1)*sizeof(XMLEle *)); ep->el[ep->nel++] = newep; } /* set the pcdata of the given element */ void editXMLEle (XMLEle *ep, const char *pcdata) { freeString (&ep->pcdata); appendString (&ep->pcdata, pcdata); ep->pcdata_hasent = (strpbrk (pcdata, entities) != NULL); } /* add an attribute to the given XML element */ XMLAtt * addXMLAtt (XMLEle *ep, const char *name, const char *valu) { XMLAtt *ap = growAtt (ep); appendString (&ap->name, name); appendString (&ap->valu, valu); return (ap); } /* remove the named attribute from ep, if any */ void rmXMLAtt (XMLEle *ep, const char *name) { int i; for (i = 0; i < ep->nat; i++) { if (strcmp (ep->at[i]->name.s, name) == 0) { freeAtt (ep->at[i]); memmove (&ep->at[i],&ep->at[i+1],(--ep->nat-i)*sizeof(XMLAtt*)); return; } } } /* change the value of an attribute to str */ void editXMLAtt (XMLAtt *ap, const char *str) { freeString (&ap->valu); appendString (&ap->valu, str); } /* sample print ep to fp * N.B. set level = 0 on first call */ #define PRINDENT 4 /* sample print indent each level */ void prXMLEle (FILE *fp, XMLEle *ep, int level) { int indent = level*PRINDENT; int i; fprintf (fp, "%*s<%s", indent, "", ep->tag.s); for (i = 0; i < ep->nat; i++) fprintf (fp, " %s=\"%s\"", ep->at[i]->name.s, entityXML(ep->at[i]->valu.s)); if (ep->nel > 0) { fprintf (fp, ">\n"); for (i = 0; i < ep->nel; i++) prXMLEle (fp, ep->el[i], level+1); } if (ep->pcdata.sl > 0) { if (ep->nel == 0) fprintf (fp, ">\n"); if (ep->pcdata_hasent) fprintf (fp, "%s", entityXML(ep->pcdata.s)); else fprintf (fp, "%s", ep->pcdata.s); if (ep->pcdata.s[ep->pcdata.sl-1] != '\n') fprintf (fp, "\n"); } if (ep->nel > 0 || ep->pcdata.sl > 0) fprintf (fp, "%*s\n", indent, "", ep->tag.s); else fprintf (fp, "/>\n"); } /* sample print ep to string s. * N.B. s must be at least as large as that reported by sprlXMLEle()+1. * N.B. set level = 0 on first call * return length of resulting string (sans trailing \0) */ int sprXMLEle (char *s, XMLEle *ep, int level) { int indent = level*PRINDENT; int sl = 0; int i; sl += sprintf (s+sl, "%*s<%s", indent, "", ep->tag.s); for (i = 0; i < ep->nat; i++) sl += sprintf (s+sl, " %s=\"%s\"", ep->at[i]->name.s, entityXML(ep->at[i]->valu.s)); if (ep->nel > 0) { sl += sprintf (s+sl, ">\n"); for (i = 0; i < ep->nel; i++) sl += sprXMLEle (s+sl, ep->el[i], level+1); } if (ep->pcdata.sl > 0) { if (ep->nel == 0) sl += sprintf (s+sl, ">\n"); if (ep->pcdata_hasent) sl += sprintf (s+sl, "%s", entityXML(ep->pcdata.s)); else { strcpy (s+sl, ep->pcdata.s); sl += ep->pcdata.sl; } if (ep->pcdata.s[ep->pcdata.sl-1] != '\n') sl += sprintf (s+sl, "\n"); } if (ep->nel > 0 || ep->pcdata.sl > 0) sl += sprintf (s+sl, "%*s\n", indent, "", ep->tag.s); else sl += sprintf (s+sl, "/>\n"); return (sl); } /* return number of bytes in a string guaranteed able to hold result of * sprXLMEle(ep) (sans trailing \0). * N.B. set level = 0 on first call */ int sprlXMLEle (XMLEle *ep, int level) { int indent = level*PRINDENT; int l = 0; int i; l += indent + 1 + ep->tag.sl; for (i = 0; i < ep->nat; i++) l += ep->at[i]->name.sl + 4 + strlen(entityXML(ep->at[i]->valu.s)); if (ep->nel > 0) { l += 2; for (i = 0; i < ep->nel; i++) l += sprlXMLEle (ep->el[i], level+1); } if (ep->pcdata.sl > 0) { if (ep->nel == 0) l += 2; if (ep->pcdata_hasent) l += strlen (entityXML(ep->pcdata.s)); else l += ep->pcdata.sl; if (ep->pcdata.s[ep->pcdata.sl-1] != '\n') l += 1; } if (ep->nel > 0 || ep->pcdata.sl > 0) l += indent + 4 + ep->tag.sl; else l += 3; return (l); } /* return a string with all xml-sensitive characters within the passed string s * replaced with their entity sequence equivalents. * N.B. caller must use the returned string before calling us again. */ char * entityXML (char *s) { static char *malbuf; int nmalbuf = 0; char *sret; char *ep; /* scan for each entity, if any */ for (sret = s; (ep = strpbrk (s, entities)) != NULL; s = ep+1) { /* found another entity, copy preceding to malloced buffer */ int nnew = ep - s; /* all but entity itself */ sret = malbuf = moremem (malbuf, nmalbuf + nnew + 10); memcpy (malbuf+nmalbuf, s, nnew); nmalbuf += nnew; /* replace with entity encoding */ switch (*ep) { case '&': nmalbuf += sprintf (malbuf+nmalbuf, "&"); break; case '<': nmalbuf += sprintf (malbuf+nmalbuf, "<"); break; case '>': nmalbuf += sprintf (malbuf+nmalbuf, ">"); break; case '\'': nmalbuf += sprintf (malbuf+nmalbuf, "'"); break; case '"': nmalbuf += sprintf (malbuf+nmalbuf, """); break; } } /* return s if no entities, else malloc cleaned-up copy */ if (sret == s) { /* using s, so free any malloced memory from last time */ if (malbuf) { free (malbuf); malbuf = NULL; } } else { /* put remaining part of s into malbuf */ int nleft = strlen (s) + 1; /* include \0 */ sret = malbuf = moremem (malbuf, nmalbuf + nleft); memcpy (malbuf+nmalbuf, s, nleft); } return (sret); } /* if ent is a recognized xml entity sequence, set *cp to char and return 1 * else return 0 */ static int decodeEntity (char *ent, int *cp) { static struct { char *ent; char c; } enttable[] = { {"&", '&'}, {"'", '\''}, {"<", '<'}, {">", '>'}, {""", '"'}, }; int i; for (i = 0; i < sizeof(enttable)/sizeof(enttable[0]); i++) { if (strcmp (ent, enttable[i].ent) == 0) { *cp = enttable[i].c; return (1); } } return (0); } /* process one more char in XML file. * if find final closure, return 1 and tree is in ce. * if need more, return 0. * if real trouble, return -1 and put reason in ynot. */ static int oneXMLchar (LilXML *lp, int c, char ynot[]) { switch (lp->cs) { case LOOK4START: /* looking for first element start */ if (c == '<') { pushXMLEle(lp); lp->cs = LOOK4TAG; } /* silently ignore until resync */ break; case LOOK4TAG: /* looking for element tag */ if (isTokenChar (1, c)) { growString (&lp->ce->tag, c); lp->cs = INTAG; } else if (!isspace(c)) { sprintf (ynot, "Line %d: Bogus tag char %c", lp->ln, c); return (-1); } break; case INTAG: /* reading tag */ if (isTokenChar (0, c)) growString (&lp->ce->tag, c); else if (c == '>') lp->cs = LOOK4CON; else if (c == '/') lp->cs = SAWSLASH; else lp->cs = LOOK4ATTRN; break; case LOOK4ATTRN: /* looking for attr name, > or / */ if (c == '>') lp->cs = LOOK4CON; else if (c == '/') lp->cs = SAWSLASH; else if (isTokenChar (1, c)) { XMLAtt *ap = growAtt(lp->ce); growString (&ap->name, c); lp->cs = INATTRN; } else if (!isspace(c)) { sprintf (ynot, "Line %d: Bogus leading attr name char: %c", lp->ln, c); return (-1); } break; case SAWSLASH: /* saw / in element opening */ if (c == '>') { if (!lp->ce->pe) return(1); /* root has no content */ popXMLEle(lp); lp->cs = LOOK4CON; } else { sprintf (ynot, "Line %d: Bogus char %c before >", lp->ln, c); return (-1); } break; case INATTRN: /* reading attr name */ if (isTokenChar (0, c)) growString (&lp->ce->at[lp->ce->nat-1]->name, c); else if (isspace(c) || c == '=') lp->cs = LOOK4ATTRV; else { sprintf (ynot, "Line %d: Bogus attr name char: %c", lp->ln,c); return (-1); } break; case LOOK4ATTRV: /* looking for attr value */ if (c == '\'' || c == '"') { lp->delim = c; lp->cs = INATTRV; } else if (!(isspace(c) || c == '=')) { sprintf (ynot, "Line %d: No value for attribute %s", lp->ln, lp->ce->at[lp->ce->nat-1]->name.s); return (-1); } break; case INATTRV: /* in attr value */ if (c == '&') { newString (&lp->entity); growString (&lp->entity, c); lp->cs = ENTINATTRV; } else if (c == lp->delim) lp->cs = LOOK4ATTRN; else if (!iscntrl(c)) growString (&lp->ce->at[lp->ce->nat-1]->valu, c); break; case ENTINATTRV: /* working on entity in attr valu */ if (c == ';') { /* if find a recongized esp seq, add equiv char else raw seq */ growString (&lp->entity, c); if (decodeEntity (lp->entity.s, &c)) growString (&lp->ce->at[lp->ce->nat-1]->valu, c); else appendString(&lp->ce->at[lp->ce->nat-1]->valu,lp->entity.s); freeString (&lp->entity); lp->cs = INATTRV; } else growString (&lp->entity, c); break; case LOOK4CON: /* skipping leading content whitespace*/ if (c == '<') lp->cs = SAWLTINCON; else if (!isspace(c)) { growString (&lp->ce->pcdata, c); lp->cs = INCON; } break; case INCON: /* reading content */ if (c == '&') { newString (&lp->entity); growString (&lp->entity, c); lp->cs = ENTINCON; } else if (c == '<') { /* chomp trailing whitespace */ while (lp->ce->pcdata.sl > 0 && isspace(lp->ce->pcdata.s[lp->ce->pcdata.sl-1])) lp->ce->pcdata.s[--(lp->ce->pcdata.sl)] = '\0'; lp->cs = SAWLTINCON; } else { growString (&lp->ce->pcdata, c); } break; case ENTINCON: /* working on entity in content */ if (c == ';') { /* if find a recognized esc seq, add equiv char else raw seq */ growString (&lp->entity, c); if (decodeEntity (lp->entity.s, &c)) growString (&lp->ce->pcdata, c); else { appendString(&lp->ce->pcdata, lp->entity.s); lp->ce->pcdata_hasent = 1; } freeString (&lp->entity); lp->cs = INCON; } else growString (&lp->entity, c); break; case SAWLTINCON: /* saw < in content */ if (c == '/') { resetEndTag(lp); lp->cs = LOOK4CLOSETAG; } else { pushXMLEle(lp); if (isTokenChar(1,c)) { growString (&lp->ce->tag, c); lp->cs = INTAG; } else lp->cs = LOOK4TAG; } break; case LOOK4CLOSETAG: /* looking for closing tag after < */ if (isTokenChar (1, c)) { growString (&lp->endtag, c); lp->cs = INCLOSETAG; } else if (!isspace(c)) { sprintf (ynot, "Line %d: Bogus preend tag char %c", lp->ln,c); return (-1); } break; case INCLOSETAG: /* reading closing tag */ if (isTokenChar(0, c)) growString (&lp->endtag, c); else if (c == '>') { if (strcmp (lp->ce->tag.s, lp->endtag.s)) { sprintf (ynot,"Line %d: closing tag %s does not match %s", lp->ln, lp->endtag.s, lp->ce->tag.s); return (-1); } else if (lp->ce->pe) { popXMLEle(lp); lp->cs = LOOK4CON; /* back to content after nested elem */ } else return (1); /* yes! */ } else if (!isspace(c)) { sprintf (ynot, "Line %d: Bogus end tag char %c", lp->ln, c); return (-1); } break; } return (0); } /* set up for a fresh start again */ static void initParser(LilXML *lp) { delXMLEle (lp->ce); freeString (&lp->endtag); memset (lp, 0, sizeof(*lp)); newString (&lp->endtag); lp->cs = LOOK4START; lp->ln = 1; } /* start a new XMLEle. * point ce to a new XMLEle. * if ce already set up, add to its list of child elements too. * endtag no longer valid. */ static void pushXMLEle(LilXML *lp) { lp->ce = growEle (lp->ce); resetEndTag(lp); } /* point ce to parent of current ce. * endtag no longer valid. */ static void popXMLEle(LilXML *lp) { lp->ce = lp->ce->pe; resetEndTag(lp); } /* return one new XMLEle, added to the given element if given */ static XMLEle * growEle (XMLEle *pe) { XMLEle *newe = (XMLEle *) moremem (NULL, sizeof(XMLEle)); memset (newe, 0, sizeof(XMLEle)); newString (&newe->tag); newString (&newe->pcdata); newe->pe = pe; if (pe) { pe->el = (XMLEle **) moremem (pe->el, (pe->nel+1)*sizeof(XMLEle *)); pe->el[pe->nel++] = newe; } return (newe); } /* add room for and return one new XMLAtt to the given element */ static XMLAtt * growAtt(XMLEle *ep) { XMLAtt *newa = (XMLAtt *) moremem (NULL, sizeof(XMLAtt)); memset (newa, 0, sizeof(*newa)); newString(&newa->name); newString(&newa->valu); newa->ce = ep; ep->at = (XMLAtt **) moremem (ep->at, (ep->nat+1)*sizeof(XMLAtt *)); ep->at[ep->nat++] = newa; return (newa); } /* free a and all it holds */ static void freeAtt (XMLAtt *a) { if (!a) return; freeString (&a->name); freeString (&a->valu); (*myfree)(a); } /* reset endtag */ static void resetEndTag(LilXML *lp) { freeString (&lp->endtag); newString (&lp->endtag); } /* 1 if c is a valid token character, else 0. * it can be alpha or '_' or numeric unless start. */ static int isTokenChar (int start, int c) { return (isalpha(c) || c == '_' || (!start && isdigit(c))); } /* grow the String storage at *sp to append c */ static void growString (String *sp, int c) { int l = sp->sl + 2; /* need room for '\0' plus c */ if (l > sp->sm) { if (!sp->s) newString (sp); else sp->s = (char *) moremem (sp->s, sp->sm *= 2); } sp->s[--l] = '\0'; sp->s[--l] = (char)c; sp->sl++; } /* append str to the String storage at *sp */ static void appendString (String *sp, const char *str) { int strl = strlen (str); int l = sp->sl + strl + 1; /* need room for '\0' */ if (l > sp->sm) { if (!sp->s) newString (sp); if (l > sp->sm) sp->s = (char *) moremem (sp->s, (sp->sm = l)); } strcpy (&sp->s[sp->sl], str); sp->sl += strl; } /* init a String with a malloced string containing just \0 */ static void newString(String *sp) { sp->s = (char *)moremem(NULL, MINMEM); sp->sm = MINMEM; *sp->s = '\0'; sp->sl = 0; } /* free memory used by the given String */ static void freeString (String *sp) { if (sp->s) (*myfree) (sp->s); sp->s = NULL; sp->sl = 0; sp->sm = 0; } /* like malloc but knows to use realloc if already started */ static void * moremem (void *old, int n) { return (old ? (*myrealloc)(old, n) : (*mymalloc)(n)); } #if defined(MAIN_TST) int main (int ac, char *av[]) { LilXML *lp = newLilXML(); char ynot[1024]; XMLEle *root; root = readXMLFile (stdin, lp, ynot); if (root) { char *str; int l; if (ac > 1) { XMLEle *theend = addXMLEle (root, "theend"); editXMLEle (theend, "Added to test editing"); addXMLAtt (theend, "hello", "world"); } fprintf (stderr, "::::::::::::: %s\n", tagXMLEle(root)); prXMLEle (stdout, root, 0); l = sprlXMLEle (root, 0); str = malloc (l+1); fprintf (stderr, "::::::::::::: %s : %d : %d", tagXMLEle(root), l, sprXMLEle (str, root, 0)); fprintf (stderr, ": %d\n", printf ("%s", str)); delXMLEle (root); } else if (ynot[0]) { fprintf (stderr, "Error: %s\n", ynot); } delLilXML (lp); return (0); } #endif libindi-0.9.7/libs/indibase/0000755000175000017500000000000012241463551014633 5ustar jasemjasemlibindi-0.9.7/libs/indibase/inditelescope.h0000644000175000017500000002343412241463551017641 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Gerry Rozema, Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDI_TELESCOPE_H #define INDI_TELESCOPE_H #include #include "defaultdevice.h" /** * \class INDI::Telescope \brief Class to provide general functionality of a telescope device. Developers need to subclass INDI::Telescope to implement any driver for telescopes within INDI. Implementing a basic telescope driver involves the child class performing the following steps:
  • If the telescope has additional properties, the child class should override initProperties and initilize the respective additional properties.
  • Once the parent class calls Connect(), the child class attempts to connect to the telescope and return either success of failure
  • INDI::Telescope calls updateProperties() to enable the child class to define which properties to send to the client upon connection
  • INDI::Telescope calls ReadScopeStatus() to check the link to the telescope and update its state and position. The child class should call newRaDec() whenever a new value is read from the telescope.
  • The child class should implmenet Goto() and Sync(), and Park() if applicable.
  • INDI::Telescope calls disconnect() when the client request a disconnection. The child class should remove any additional properties it defined in updateProperties() if applicable
\author Gerry Rozema, Jasem Mutlaq \see TelescopeSimulator and SynScan drivers for examples of implementations of INDI::Telescope. */ class INDI::Telescope : public INDI::DefaultDevice { private: public: Telescope(); virtual ~Telescope(); enum TelescopeStatus { SCOPE_IDLE, SCOPE_SLEWING, SCOPE_TRACKING, SCOPE_PARKING, SCOPE_PARKED }; enum TelescopeMotionNS { MOTION_NORTH, MOTION_SOUTH }; enum TelescopeMotionWE { MOTION_WEST, MOTION_EAST }; virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual void ISGetProperties (const char *dev); virtual bool ISSnoopDevice(XMLEle *root); /** \brief Called to initialize basic properties required all the time */ virtual bool initProperties(); /** \brief Called when connected state changes, to add/remove properties */ virtual bool updateProperties(); /** \brief Called when setTimer() time is up */ virtual void TimerHit(); /** \brief Connect to the telescope. \return True if connection is successful, false otherwise */ virtual bool Connect(); /** \brief Disconnect from telescope \return True if successful, false otherwise */ virtual bool Disconnect(); /** \brief INDI::Telescope implementation of Connect() assumes 9600 baud, 8 bit word, even parity, and no stop bit. Override function if communication paramaters are different \param port Port to connect to \return True if connection is successful, false otherwise \warning Do not call this function directly, it is called by INDI::Telescope Connect() function. */ virtual bool Connect(const char *port); protected: virtual bool saveConfigItems(FILE *fp); /** \brief The child class calls this function when it has updates */ void NewRaDec(double ra,double dec); /** \brief Read telescope status. This function checks the following:
  1. Check if the link to the telescope is alive.
  2. Update telescope status: Idle, Slewing, Parking..etc.
  3. Read coordinates
\return True if reading scope status is OK, false if an error is encounterd. \note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ virtual bool ReadScopeStatus()=0; /** \brief Move the scope to the supplied RA and DEC coordinates \return True if successful, false otherewise \note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ virtual bool Goto(double ra,double dec)=0; /** \brief Does the mount support sync? * \return True if sync is supported, false otherwise. *\note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ virtual bool canSync(); /** \brief Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates \return True if successful, false otherewise *\note This function implemented INDI::Telescope always returns false. Override the function to return true. */ virtual bool Sync(double ra,double dec); /** \brief Move the telescope in the direction dir. \return True if successful, false otherewise \note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ virtual bool MoveNS(TelescopeMotionNS dir); /** \brief Move the telescope in the direction dir. \return True if successful, false otherewise \note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ virtual bool MoveWE(TelescopeMotionWE dir); /** \brief Does the mount support park? * \return True if park is supported, false otherwise. *\note This function defaults to return false unless subclassed by the child class. */ virtual bool canPark(); /** \brief Park the telescope to its home position. \return True if successful, false otherewise *\note This function defaults to return false unless subclassed by the child class. */ virtual bool Park(); /** \brief Abort telescope motion \return True if successful, false otherewise \note This function is not implemented in INDI::Telescope, it must be implemented in the child class */ virtual bool Abort()=0; /** \brief Update telescope time, date, and UTC offset. * \param utc UTC time. * \param utc_offset UTC offset in hours. \return True if successful, false otherewise \note This function performs no action unless subclassed by the child class if required. */ virtual bool updateTime(ln_date *utc, double utc_offset); /** \brief Update telescope location settings * \param latitude Site latitude in degrees. * \param longitude Site latitude in degrees increasing eastward from Greenwich (0 to 360). * \param elevation Site elevation in meters. \return True if successful, false otherewise \note This function performs no action unless subclassed by the child class if required. */ virtual bool updateLocation(double latitude, double longitude, double elevation); // Since every mount I know of actually uses a serial port for control // We put the serial helper into the base telescope class // One less piece to worry about in the hardware specific // low level stuff int PortFD; // This is a variable filled in by the ReadStatus telescope // low level code, used to report current state // are we slewing, tracking, or parked. TelescopeStatus TrackState; // All telescopes should produce equatorial co-ordinates INumberVectorProperty EqNP; INumber EqN[2]; ISwitchVectorProperty AbortSP; // Abort motion ISwitch AbortS[1]; ISwitchVectorProperty CoordSP; // A switch vector that stores how we should readct ISwitch CoordS[3]; // On a coord_set message, sync, or slew ISwitchVectorProperty ConfigSP; // A switch vector that stores how we should readct ISwitch ConfigS[3]; // On a coord_set message, sync, or slew INumberVectorProperty LocationNP; // A number vector that stores lattitude and longitude INumber LocationN[3]; ISwitchVectorProperty ParkSP; // A Switch in the client interface to park the scope ISwitch ParkS[1]; ITextVectorProperty PortTP; // A text vector that stores out physical port name IText PortT[1]; ISwitch MovementNSS[2]; // A switch for North/South motion ISwitchVectorProperty MovementNSSP; ISwitch MovementWES[2]; // A switch for West/East motion ISwitchVectorProperty MovementWESP; INumber ScopeParametersN[4]; INumberVectorProperty ScopeParametersNP; IText TimeT[2]; ITextVectorProperty TimeTP; }; #endif // INDI::Telescope_H libindi-0.9.7/libs/indibase/indiusbdevice.cpp0000644000175000017500000001114112241463551020152 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "indiusbdevice.h" #include INDI::USBDevice::USBDevice() { dev=NULL; usb_handle=NULL; OutputEndpoint=0; InputEndpoint=0; usb_init(); usb_find_busses(); usb_find_devices(); } INDI::USBDevice::~USBDevice() { } struct usb_device * INDI::USBDevice::FindDevice(int vendor, int product, int searchindex) { struct usb_device *dev; struct usb_bus *usb_bus; int index=0; for(usb_bus=usb_busses; usb_bus; usb_bus=usb_bus->next) { for(dev=usb_bus->devices; dev; dev=dev->next) { if(dev->descriptor.idVendor==vendor) { if(dev->descriptor.idProduct==product) { if(index==searchindex) { fprintf(stderr,"Device has %d configurations\n",dev->descriptor.bNumConfigurations); return dev; } else index++; } } } } return NULL; } int INDI::USBDevice::Open() { if(dev==NULL) return -1; usb_handle=usb_open(dev); if(usb_handle != NULL) { //printf("Opened ok\n"); return FindEndpoints(); //return 0; } return -1; } int INDI::USBDevice::FindEndpoints() { int rc=0; struct usb_interface_descriptor *intf; intf=&dev->config[0].interface[0].altsetting[0]; for(int i=0; ibNumEndpoints; i++) { fprintf(stderr,"%04x %04x\n", intf->endpoint[i].bEndpointAddress, intf->endpoint[i].bmAttributes ); int dir; int addr; addr=intf->endpoint[i].bEndpointAddress; addr = addr & (USB_ENDPOINT_DIR_MASK^0xffff); //printf("%02x ",addr); int attr; int tp; attr=intf->endpoint[i].bmAttributes; tp=attr&USB_ENDPOINT_TYPE_MASK; //if(tp==USB_ENDPOINT_TYPE_BULK) printf("Bulk "); //if(tp==USB_ENDPOINT_TYPE_INTERRUPT) printf("Interrupt "); dir=intf->endpoint[i].bEndpointAddress; dir=dir&USB_ENDPOINT_DIR_MASK; if(dir==USB_ENDPOINT_IN) { //printf("Input "); fprintf(stderr,"Got an input endpoint\n"); InputEndpoint=addr; InputType=tp; } if(dir==USB_ENDPOINT_OUT) { //printf("Output "); fprintf(stderr,"got an output endpoint\n"); OutputEndpoint=addr; OutputType=tp; } //printf("\n"); } //printf("claim interface returns %d\n",rc); return rc; } int INDI::USBDevice::ReadInterrupt(char *buf,int c,int timeout) { int rc; rc=usb_interrupt_read(usb_handle,InputEndpoint,buf,c,timeout); //rc=usb_bulk_read(usb_handle,InputEndpoint,buf,c,timeout); return rc; } int INDI::USBDevice::WriteInterrupt(char *buf,int c,int timeout) { int rc; //printf("Writing %02x to endpoint %d\n",buf[0],OutputEndpoint); rc=usb_interrupt_write(usb_handle,OutputEndpoint,buf,c,timeout); return rc; } int INDI::USBDevice::ReadBulk(char *buf,int nbytes,int timeout) { int rc; //rc=usb_interrupt_read(usb_handle,InputEndpoint,buf,c,timeout); rc=usb_bulk_read(usb_handle,InputEndpoint,buf,nbytes,timeout); return rc; } int INDI::USBDevice::WriteBulk(char *buf,int nbytes,int timeout) { int rc; //printf("Writing %02x to endpoint %d\n",buf[0],OutputEndpoint); //rc=usb_interrupt_write(usb_handle,OutputEndpoint,buf,c,timeout); rc=usb_bulk_write(usb_handle,OutputEndpoint,buf,nbytes,timeout); return rc; } int INDI::USBDevice::ControlMessage(unsigned char request_type, unsigned char request, unsigned int value, unsigned int index, char *data, unsigned char len) { int result; //dprintf("Sending %s command 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d bytes\n",(request_type & USB_ENDPOINT_IN) ? "recv" : "send", request_type, request, value, index, len); result = usb_control_msg(usb_handle, request_type, request, value, index, data, len, 5000); /*for(i = 0; i < len; i++) { dprintf(" %02x", (unsigned char)data[i]); } dprintf("\n");*/ return result; } libindi-0.9.7/libs/indibase/indifilterinterface.h0000644000175000017500000001110412241463551021013 0ustar jasemjasem/* Filter Interface Copyright (C) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef INDIFILTERINTERFACE_H #define INDIFILTERINTERFACE_H #include "indibase.h" /** * \class INDI::FilterInterface \brief Provides interface to implement Filter Wheel functionality. A filter wheel can be an independent device, or an embedded filter wheel within another device (e.g. CCD camera). Child class must implement all the pure virtual functions and call SelectFilterDone(int) when selection of a new filter position is complete in the hardware. \e IMPORTANT: initFilterProperties() must be called before any other function to initilize the filter properties. \e IMPORTANT: processFilterSlot() must be called in your driver's ISNewNumber() function. processFilterSlot() will call the driver's SelectFilter() accordingly. \note Filter position starts from 1 and \e not 0 \author Gerry Rozema, Jasem Mutlaq */ class INDI::FilterInterface { public: /** \brief Return current filter position */ virtual int QueryFilter() = 0; /** \brief Select a new filter position \return True if operation is successful, false otherwise */ virtual bool SelectFilter(int position) = 0; /** \brief Set filter names as defined by the client for each filter position. The desired filter names are stored in FilterNameTP property. Filter names should be saved in hardware if possible. \return True if successful, false if supported or failed operation */ virtual bool SetFilterNames() = 0; /** \brief Obtains a list of filter names from the hardware and initilizes the FilterNameTP property. The function should check for the number of filters available in the filter wheel and build the FilterNameTP property accordingly. \param groupName group name for FilterNameTP property to be created. \return True if successful, false if unsupported or failed operation \see QSI CCD implementation of the FilterInterface. QSI CCD is available as a 3rd party INDI driver. */ virtual bool GetFilterNames(const char* groupName) = 0; /** \brief The child class calls this function when the hardware successfully finished selecting a new filter wheel position \param newpos New position of the filter wheel */ void SelectFilterDone(int newpos); protected: FilterInterface(); ~FilterInterface(); /** \brief Initilize filter wheel properties. It is recommended to call this function within initProperties() of your primary device \param deviceName Name of the primary device \param groupName Group or tab name to be used to define filter wheel properties. */ void initFilterProperties(const char *deviceName, const char* groupName); /** \brief Process client request to change filter position. Call this function in the filter wheel implementation class ISNewNumber function. \param deviceName Name of the primary device \param values values from ISNewNumber(). \param names names from ISNewNumber(); */ void processFilterSlot(const char *deviceName, double values[], char *names[]); /** \brief Process client request to change filter name(s). Call this function in the filter wheel implementation class ISNewNumber() function. \param deviceName Name of the primary device \param values values from ISNewNumber(). \param names names from ISNewNumber(); \param n n from ISNewNumber(); */ void processFilterName(const char *deviceName, char *texts[], char *names[], int n); INumberVectorProperty FilterSlotNP; // A number vector for filter slot INumber FilterSlotN[1]; ITextVectorProperty *FilterNameTP; // A text vector that stores out physical port name IText *FilterNameT; int CurrentFilter; int TargetFilter; }; #endif // INDIFILTERINTERFACE_H libindi-0.9.7/libs/indibase/defaultdevice.cpp0000644000175000017500000004253612241463551020155 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include #include #include #include #include "defaultdevice.h" #include "indicom.h" #include "base64.h" #include "indiproperty.h" const char *COMMUNICATION_TAB = "Communication"; const char *MAIN_CONTROL_TAB = "Main Control"; const char *MOTION_TAB = "Motion Control"; const char *DATETIME_TAB = "Date/Time"; const char *SITE_TAB = "Site Management"; const char *OPTIONS_TAB = "Options"; const char *FILTER_TAB = "Filter Wheel"; const char *FOCUS_TAB = "Focuser"; const char *GUIDE_TAB = "Guide"; void timerfunc(void *t) { //fprintf(stderr,"Got a timer hit with %x\n",t); INDI::DefaultDevice *devPtr = static_cast (t); if (devPtr != NULL) { // this was for my device // but we dont have a way of telling // WHICH timer was hit :( devPtr->TimerHit(); } return; } INDI::DefaultDevice::DefaultDevice() { pDebug = false; pSimulation = false; isInit = false; majorVersion = 1; minorVersion = 0; } INDI::DefaultDevice::~DefaultDevice() { } bool INDI::DefaultDevice::loadConfig() { char errmsg[MAXRBUF]; bool pResult = false; pResult = IUReadConfig(NULL, deviceID, errmsg) == 0 ? true : false; if (pResult) IDMessage(deviceID, "Configuration successfully loaded.\n"); else IDMessage(deviceID,"Error loading configuration\n"); IUSaveDefaultConfig(NULL, NULL, deviceID); return pResult; } bool INDI::DefaultDevice::saveConfigItems(FILE *fp) { std::vector::iterator orderi; INDI_TYPE pType; void *pPtr; ISwitchVectorProperty *svp=NULL; INumberVectorProperty *nvp=NULL; ITextVectorProperty *tvp=NULL; IBLOBVectorProperty *bvp=NULL; for (orderi = pAll.begin(); orderi != pAll.end(); orderi++) { pType = (*orderi)->getType(); pPtr = (*orderi)->getProperty(); switch (pType) { case INDI_NUMBER: nvp = static_cast(pPtr); //IDLog("Trying to save config for number %s\n", nvp->name); IUSaveConfigNumber(fp, nvp); break; case INDI_TEXT: tvp = static_cast(pPtr); IUSaveConfigText(fp, tvp); break; case INDI_SWITCH: svp = static_cast(pPtr); /* Never save CONNECTION property. Don't save switches with no switches on if the rule is one of many */ if (!strcmp(svp->name, "CONNECTION") || (svp->r == ISR_1OFMANY && !IUFindOnSwitch(svp))) continue; IUSaveConfigSwitch(fp, svp); break; case INDI_BLOB: bvp = static_cast(pPtr); IUSaveConfigBLOB(fp, bvp); break; } } return true; } bool INDI::DefaultDevice::saveConfig() { //std::vector::iterator orderi; char errmsg[MAXRBUF]; FILE *fp = NULL; fp = IUGetConfigFP(NULL, deviceID, errmsg); if (fp == NULL) { IDMessage(deviceID, "Error saving configuration. %s\n", errmsg); return false; } IUSaveConfigTag(fp, 0); saveConfigItems(fp); IUSaveConfigTag(fp, 1); fclose(fp); IUSaveDefaultConfig(NULL, NULL, deviceID); IDMessage(deviceID, "Configuration successfully saved."); return true; } bool INDI::DefaultDevice::loadDefaultConfig() { char configDefaultFileName[MAXRBUF]; char errmsg[MAXRBUF]; bool pResult = false; if (getenv("INDICONFIG")) snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG")); else snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), deviceID); if (pDebug) IDLog("Requesting to load default config with: %s\n", configDefaultFileName); pResult = IUReadConfig(configDefaultFileName, deviceID, errmsg) == 0 ? true : false; if (pResult) IDMessage(deviceID, "Default configuration loaded."); else IDMessage(deviceID, "Error loading default configuraiton. %s", errmsg); return pResult; } bool INDI::DefaultDevice::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { // ignore if not ours // if (strcmp (dev, deviceID)) return false; ISwitchVectorProperty *svp = getSwitch(name); if (!svp) return false; if(!strcmp(svp->name,ConnectionSP.name)) { bool rc; for (int i=0; i < n; i++) { if ( !strcmp(names[i], "CONNECT") && (states[i] == ISS_ON)) { // If not connected, attempt to connect if (isConnected() == false) { rc = Connect(); // If connection is successful, set it thus if (rc) { setConnected(true, IPS_OK); updateProperties(); } else setConnected(false, IPS_ALERT); } else // Just tell client we're connected yes setConnected(true); } else if ( !strcmp(names[i], "DISCONNECT") && (states[i] == ISS_ON)) { // If connected, then true to disconnect. if (isConnected() == true) rc = Disconnect(); else rc = true; if (rc) { setConnected(false, IPS_IDLE); updateProperties(); } else setConnected(true, IPS_ALERT); } } return true; } if (!strcmp(svp->name, "DEBUG")) { IUUpdateSwitch(svp, states, names, n); ISwitch *sp = IUFindOnSwitch(svp); if (!sp) return false; if (!strcmp(sp->name, "ENABLE")) setDebug(true); else setDebug(false); return true; } if (!strcmp(svp->name, "SIMULATION")) { IUUpdateSwitch(svp, states, names, n); ISwitch *sp = IUFindOnSwitch(svp); if (!sp) return false; if (!strcmp(sp->name, "ENABLE")) setSimulation(true); else setSimulation(false); return true; } if (!strcmp(svp->name, "CONFIG_PROCESS")) { IUUpdateSwitch(svp, states, names, n); ISwitch *sp = IUFindOnSwitch(svp); IUResetSwitch(svp); bool pResult = false; if (!sp) return false; if (!strcmp(sp->name, "CONFIG_LOAD")) pResult = loadConfig(); else if (!strcmp(sp->name, "CONFIG_SAVE")) pResult = saveConfig(); else if (!strcmp(sp->name, "CONFIG_DEFAULT")) pResult = loadDefaultConfig(); if (pResult) svp->s = IPS_OK; else svp->s = IPS_ALERT; IDSetSwitch(svp, NULL); return true; } if (!strcmp(svp->name, "DEBUG_LEVEL") || !strcmp(svp->name, "LOGGING_LEVEL") || !strcmp(svp->name, "LOG_OUTPUT")) { bool rc = Logger::ISNewSwitch(dev, name, states, names, n); if (!strcmp(svp->name, "LOG_OUTPUT")) { ISwitch *sw = IUFindSwitch(svp, "FILE_DEBUG"); if (sw && sw->s == ISS_ON) DEBUGF(Logger::DBG_SESSION, "Session log file %s", Logger::getLogFile().c_str()); } return rc; } return false; } void INDI::DefaultDevice::addDebugControl() { registerProperty(&DebugSP, INDI_SWITCH); pDebug = false; } void INDI::DefaultDevice::addSimulationControl() { registerProperty(&SimulationSP, INDI_SWITCH); pSimulation = false; } void INDI::DefaultDevice::addConfigurationControl() { registerProperty(&ConfigProcessSP, INDI_SWITCH); } void INDI::DefaultDevice::addAuxControls() { addDebugControl(); addSimulationControl(); addConfigurationControl(); } void INDI::DefaultDevice::setDebug(bool enable) { if (pDebug == enable) { DebugSP.s = IPS_OK; IDSetSwitch(&DebugSP, NULL); return; } IUResetSwitch(&DebugSP); if (enable) { ISwitch *sp = IUFindSwitch(&DebugSP, "ENABLE"); if (sp) { sp->s = ISS_ON; IDMessage(deviceID, "Debug is enabled."); } } else { ISwitch *sp = IUFindSwitch(&DebugSP, "DISABLE"); if (sp) { sp->s = ISS_ON; IDMessage(deviceID, "Debug is disabled."); } } pDebug = enable; // Inform logger if (Logger::updateProperties(enable, this) == false) DEBUG(Logger::DBG_WARNING,"setLogDebug: Logger error"); debugTriggered(enable); DebugSP.s = IPS_OK; IDSetSwitch(&DebugSP, NULL); } void INDI::DefaultDevice::setSimulation(bool enable) { if (pSimulation == enable) { SimulationSP.s = IPS_OK; IDSetSwitch(&SimulationSP, NULL); return; } IUResetSwitch(&SimulationSP); if (enable) { ISwitch *sp = IUFindSwitch(&SimulationSP, "ENABLE"); if (sp) { IDMessage(deviceID, "Simulation is enabled."); sp->s = ISS_ON; } } else { ISwitch *sp = IUFindSwitch(&SimulationSP, "DISABLE"); if (sp) { sp->s = ISS_ON; IDMessage(deviceID, "Simulation is disabled."); } } pSimulation = enable; simulationTriggered(enable); SimulationSP.s = IPS_OK; IDSetSwitch(&SimulationSP, NULL); } bool INDI::DefaultDevice::isDebug() { return pDebug; } bool INDI::DefaultDevice::isSimulation() { return pSimulation; } void INDI::DefaultDevice::debugTriggered(bool enable) { INDI_UNUSED(enable); } void INDI::DefaultDevice::simulationTriggered(bool enable) { INDI_UNUSED(enable); } void INDI::DefaultDevice::ISGetProperties (const char *dev) { std::vector::iterator orderi; INDI_TYPE pType; void *pPtr; if(isInit == 0) { if(dev != NULL) setDeviceName(dev); else if (*getDeviceName() == '\0') { char *envDev = getenv("INDIDEV"); if (envDev != NULL) setDeviceName(envDev); else setDeviceName(getDefaultName()); } strncpy(ConnectionSP.device, getDeviceName(), MAXINDIDEVICE); initProperties(); addConfigurationControl(); isInit = 1; } for (orderi = pAll.begin(); orderi != pAll.end(); orderi++) { pType = (*orderi)->getType(); pPtr = (*orderi)->getProperty(); switch (pType) { case INDI_NUMBER: IDDefNumber(static_cast(pPtr) , NULL); break; case INDI_TEXT: IDDefText(static_cast(pPtr) , NULL); break; case INDI_SWITCH: IDDefSwitch(static_cast(pPtr) , NULL); break; case INDI_LIGHT: IDDefLight(static_cast(pPtr) , NULL); break; case INDI_BLOB: IDDefBLOB(static_cast(pPtr) , NULL); break; } } } void INDI::DefaultDevice::resetProperties() { std::vector::iterator orderi; INDI_TYPE pType; void *pPtr; for (orderi = pAll.begin(); orderi != pAll.end(); orderi++) { pType = (*orderi)->getType(); pPtr = (*orderi)->getProperty(); switch (pType) { case INDI_NUMBER: static_cast(pPtr)->s = IPS_IDLE; IDSetNumber(static_cast(pPtr) , NULL); break; case INDI_TEXT: static_cast(pPtr)->s = IPS_IDLE; IDSetText(static_cast(pPtr) , NULL); break; case INDI_SWITCH: static_cast(pPtr)->s = IPS_IDLE; IDSetSwitch(static_cast(pPtr) , NULL); break; case INDI_LIGHT: static_cast(pPtr)->s = IPS_IDLE; IDSetLight(static_cast(pPtr) , NULL); break; case INDI_BLOB: static_cast(pPtr)->s = IPS_IDLE; IDSetBLOB(static_cast(pPtr) , NULL); break; } } } void INDI::DefaultDevice::setConnected(bool status, IPState state, const char *msg) { ISwitch *sp = NULL; ISwitchVectorProperty *svp = getSwitch("CONNECTION"); if (!svp) return; IUResetSwitch(svp); // Connect if (status) { sp = IUFindSwitch(svp, "CONNECT"); if (!sp) return; sp->s = ISS_ON; } // Disconnect else { sp = IUFindSwitch(svp, "DISCONNECT"); if (!sp) return; sp->s = ISS_ON; } svp->s = state; IDSetSwitch(svp, msg, NULL); } // This is a helper function // that just encapsulates the Indi way into our clean c++ way of doing things int INDI::DefaultDevice::SetTimer(int ms) { return IEAddTimer(ms,timerfunc,this); } // Just another helper to help encapsulate indi into a clean class void INDI::DefaultDevice::RemoveTimer(int id) { IERmTimer(id); return; } // This is just a placeholder // This function should be overriden by child classes if they use timers // So we should never get here void INDI::DefaultDevice::TimerHit() { return; } bool INDI::DefaultDevice::updateProperties() { // The base device has no properties to update return true; } bool INDI::DefaultDevice::initProperties() { char versionStr[16]; snprintf(versionStr, 16, "%d.%d", majorVersion, minorVersion); IUFillSwitch(&ConnectionS[0],"CONNECT","Connect",ISS_OFF); IUFillSwitch(&ConnectionS[1],"DISCONNECT","Disconnect",ISS_ON); IUFillSwitchVector(&ConnectionSP,ConnectionS,2,getDeviceName(),"CONNECTION","Connection","Main Control",IP_RW,ISR_1OFMANY,60,IPS_IDLE); registerProperty(&ConnectionSP, INDI_SWITCH); IUFillText(&DriverInfoT[0],"NAME","Name",getDefaultName()); IUFillText(&DriverInfoT[1],"EXEC","Exec",getDriverName()); IUFillText(&DriverInfoT[2],"VERSION","Version",versionStr); IUFillTextVector(&DriverInfoTP,DriverInfoT,3,getDeviceName(),"DRIVER_INFO","Driver Info",OPTIONS_TAB,IP_RO,60,IPS_IDLE); registerProperty(&DriverInfoTP, INDI_TEXT); IUFillSwitch(&DebugS[0], "ENABLE", "Enable", ISS_OFF); IUFillSwitch(&DebugS[1], "DISABLE", "Disable", ISS_ON); IUFillSwitchVector(&DebugSP, DebugS, NARRAY(DebugS), getDeviceName(), "DEBUG", "Debug", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&SimulationS[0], "ENABLE", "Enable", ISS_OFF); IUFillSwitch(&SimulationS[1], "DISABLE", "Disable", ISS_ON); IUFillSwitchVector(&SimulationSP, SimulationS, NARRAY(SimulationS), getDeviceName(), "SIMULATION", "Simulation", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillSwitch(&ConfigProcessS[0], "CONFIG_LOAD", "Load", ISS_OFF); IUFillSwitch(&ConfigProcessS[1], "CONFIG_SAVE", "Save", ISS_OFF); IUFillSwitch(&ConfigProcessS[2], "CONFIG_DEFAULT", "Default", ISS_OFF); IUFillSwitchVector(&ConfigProcessSP, ConfigProcessS, NARRAY(ConfigProcessS), getDeviceName(), "CONFIG_PROCESS", "Configuration", "Options", IP_RW, ISR_1OFMANY, 0, IPS_IDLE); // Ready the logger std::string logFile; logFile += "/tmp/"; logFile += getDriverExec(); DEBUG_CONF(logFile, Logger::file_off|Logger::screen_on, Logger::defaultlevel, Logger::defaultlevel); return true; } bool INDI::DefaultDevice::deleteProperty(const char *propertyName) { char errmsg[MAXRBUF]; removeProperty(propertyName, errmsg); IDDelete(getDeviceName(), propertyName ,NULL); return true; } void INDI::DefaultDevice::defineNumber(INumberVectorProperty *nvp) { registerProperty(nvp, INDI_NUMBER); IDDefNumber(nvp, NULL); } void INDI::DefaultDevice::defineText(ITextVectorProperty *tvp) { registerProperty(tvp, INDI_TEXT); IDDefText(tvp, NULL); } void INDI::DefaultDevice::defineSwitch(ISwitchVectorProperty *svp) { registerProperty(svp, INDI_SWITCH); IDDefSwitch(svp, NULL); } void INDI::DefaultDevice::defineLight(ILightVectorProperty *lvp) { registerProperty(lvp, INDI_LIGHT); IDDefLight(lvp, NULL); } void INDI::DefaultDevice::defineBLOB(IBLOBVectorProperty *bvp) { registerProperty(bvp, INDI_BLOB); IDDefBLOB(bvp, NULL); } libindi-0.9.7/libs/indibase/basedevice.h0000644000175000017500000001560412241463551017104 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDIBASEDRIVER_H #define INDIBASEDRIVER_H #include #include #include #include #include "indiapi.h" #include "indidevapi.h" #include "indibase.h" #include "indiproperty.h" #define MAXRBUF 2048 /** * \class INDI::BaseDevice \brief Class to provide basic INDI device functionality. INDI::BaseDevice is the base device for all INDI devices and contains a list of all properties defined by the device either explicity or via a skeleton file. You don't need to subclass INDI::BaseDevice class directly, it is inheritied by INDI::DefaultDevice which takes care of building a standard INDI device. Moreover, INDI::BaseClient maintains a list of INDI::BaseDevice objects as they get defined from the INDI server, and those objects may be accessed to retrieve information on the object properties or message log. \author Jasem Mutlaq */ class INDI::BaseDevice { public: BaseDevice(); ~BaseDevice(); /*! INDI error codes. */ enum INDI_ERROR { INDI_DEVICE_NOT_FOUND=-1, /*!< INDI Device was not found. */ INDI_PROPERTY_INVALID=-2, /*!< Property has an invalid syntax or attribute. */ INDI_PROPERTY_DUPLICATED = -3, /*!< INDI Device was not found. */ INDI_DISPATCH_ERROR=-4 /*!< Dispatching command to driver failed. */ }; /** \return Return vector number property given its name */ INumberVectorProperty * getNumber(const char *name); /** \return Return vector text property given its name */ ITextVectorProperty * getText(const char *name); /** \return Return vector switch property given its name */ ISwitchVectorProperty * getSwitch(const char *name); /** \return Return vector light property given its name */ ILightVectorProperty * getLight(const char *name); /** \return Return vector BLOB property given its name */ IBLOBVectorProperty * getBLOB(const char *name); void registerProperty(void *p, INDI_TYPE type); /** \brief Remove a property \param name name of property to be removed \param errmsg buffer to store error message. \return 0 if successul, -1 otherwise. */ int removeProperty(const char *name, char *errmsg); /** \brief Return a property and its type given its name. \param name of property to be found. \param type of property found. \return If property is found, the raw void * pointer to the IXXXVectorProperty is returned. To be used you must use static_cast with given the type of property returned. For example, INumberVectorProperty *num = static_cast getRawProperty("FOO", INDI_NUMBER); \note This is a low-level function and should not be called directly unless necessary. Use getXXX instead where XXX is the property type (Number, Text, Switch..etc). */ void * getRawProperty(const char *name, INDI_TYPE type = INDI_UNKNOWN); /** \brief Return a property and its type given its name. \param name of property to be found. \param type of property found. \return If property is found, it is returned. To be used you must use static_cast with given the type of property returned. */ INDI::Property * getProperty(const char *name, INDI_TYPE type = INDI_UNKNOWN); /** \brief Return a list of all properties in the device. */ std::vector * getProperties() { return &pAll; } /** \brief Build driver properties from a skeleton file. \param filename full path name of the file. A skeloton file defines the properties supported by this driver. It is a list of defXXX elements enclosed by @@ and @@ opening and closing tags. After the properties are created, they can be rerieved, manipulated, and defined to other clients. \see An example skeleton file can be found under examples/tutorial_four_sk.xml */ void buildSkeleton(const char *filename); /** \return True if the device is connected (CONNECT=ON), False otherwise */ bool isConnected(); /** \brief Set the device name \param dev new device name */ void setDeviceName(const char *dev); /** \return Returns the device name */ const char *getDeviceName(); /** \brief Add message to the driver's message queue. \param msg Message to add. */ void addMessage(const char *msg); void checkMessage (XMLEle *root); void doMessage (XMLEle *msg); /** \return Returns a specific message. */ const char * messageQueue(int index); /** \return Returns last message message. */ const char * lastMessage(); /** \brief Set the driver's mediator to receive notification of news devices and updated property values. */ void setMediator(INDI::BaseMediator *med) { mediator = med; } /** \returns Get the meditator assigned to this driver */ INDI::BaseMediator * getMediator() { return mediator; } /** \return driver name * \note This can only be valid if DRIVER_INFO is defined by the driver. **/ const char *getDriverName(); /** \return driver executable name * \note This can only be valid if DRIVER_INFO is defined by the driver. **/ const char *getDriverExec(); protected: /** \brief Build a property given the supplied XML element (defXXX) \param root XML element to parse and build. \param errmsg buffer to store error message in parsing fails. \return 0 if parsing is successful, -1 otherwise and errmsg is set */ int buildProp(XMLEle *root, char *errmsg); /** \brief handle SetXXX commands from client */ int setValue (XMLEle *root, char * errmsg); /** \brief Parse and store BLOB in the respective vector */ int setBLOB(IBLOBVectorProperty *pp, XMLEle * root, char * errmsg); private: char *deviceID; std::vector pAll; LilXML *lp; std::vector messageLog; INDI::BaseMediator *mediator; friend class INDI::BaseClient; friend class INDI::DefaultDevice; }; #endif // INDIBASEDRIVER_H libindi-0.9.7/libs/indibase/indidevice.cpp0000644000175000017500000002706012241463551017447 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #include "IndiDevice.h" #include IndiDevice *device=NULL; /************************************************************************************** ** ***************************************************************************************/ void ISGetProperties (const char *dev) { //fprintf(stderr,"Enter ISGetProperties '%s'\n",dev); if(device==NULL) { //IDLog("Create device for %s\n",dev); device=_create_device(); if(dev != NULL) { //fprintf(stderr,"Calling setDeviceName %s\n",dev); device->setDeviceName(dev); //fprintf(stderr,"deviceName() returns %s\n",device->deviceName()); //fprintf(stderr,"getDefaultName() returns %s\n",device->getDefaultName()); } else { //device->setDeviceName("junker"); device->setDeviceName(device->getDefaultName()); } device->addConfigurationControl(); device->init_properties(); } device->ISGetProperties(dev); } /************************************************************************************** ** ***************************************************************************************/ void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { //fprintf(stderr,"Enter ISNewSwitch %s\n",dev); //ISInit(); //fprintf(stderr,"Calling Device->IsNewSwitch for device %0x\n",(void *)device); device->ISNewSwitch(dev, name, states, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { //fprintf(stderr,"Enter ISNewText\n"); //ISInit(); device->ISNewText(dev, name, texts, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { //fprintf(stderr,"OutsideClass::Enter ISNewNumber\n"); //ISInit(); device->ISNewNumber(dev, name, values, names, n); } /************************************************************************************** ** ***************************************************************************************/ void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { INDI_UNUSED(dev); INDI_UNUSED(name); INDI_UNUSED(sizes); INDI_UNUSED(blobsizes); INDI_UNUSED(blobs); INDI_UNUSED(formats); INDI_UNUSED(names); INDI_UNUSED(n); } /************************************************************************************** ** ***************************************************************************************/ void ISSnoopDevice (XMLEle *root) { return device->ISSnoopDevice(root); } void timerfunc(void *t) { //fprintf(stderr,"Got a timer hit with %x\n",t); if(t==device) { // this was for my device // but we dont have a way of telling // WHICH timer was hit :( device->TimerHit(); } return; } IndiDevice::IndiDevice() { //ctor Connected=false; } IndiDevice::~IndiDevice() { //dtor } int IndiDevice::init_properties() { // All devices should have a connection switch defined // so lets create it //IDLog("IndiDevice::init_properties() MyDev=%s\n",deviceName()); IUFillSwitch(&ConnectionS[0],"CONNECT","Connect",ISS_OFF); IUFillSwitch(&ConnectionS[1],"DISCONNECT","Disconnect",ISS_ON); IUFillSwitchVector(&ConnectionSV,ConnectionS,2,deviceName(),"CONNECTION","Connection","Main Control",IP_RW,ISR_1OFMANY,60,IPS_IDLE); return 0; } bool IndiDevice::DeleteProperty(char *n) { IDDelete(deviceName(),n,NULL); return true; } void IndiDevice::ISGetProperties(const char *dev) { // Now lets send the ones we have defined //IDLog("IndiDevice::ISGetProperties %s\n",dev); IDDefSwitch (&ConnectionSV, NULL); if(Connected) UpdateProperties(); // If already connected, send the rest // And now get the default driver to send what it wants to send INDI::DefaultDriver::ISGetProperties(dev); } /************************************************************************************** ** Process Text properties ***************************************************************************************/ bool IndiDevice::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // And this base class doesn't actually process anything return INDI::DefaultDriver::ISNewText(dev,name,texts,names,n); } /************************************************************************************** ** Process Numbers ***************************************************************************************/ bool IndiDevice::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // Our base class doesn't actually do any processing return INDI::DefaultDriver::ISNewNumber(dev,name,values,names,n); } /************************************************************************************** ** Process switches ***************************************************************************************/ bool IndiDevice::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { // Ok, lets Process any switches we actually handle here if(strcmp(dev,deviceName())==0) { // it's for this device if(strcmp(name,ConnectionSV.name)==0) { bool rc; //IDLog("IndiDevice Switch %s\n",names[x]); IUUpdateSwitch(&ConnectionSV,states,names,n); if(ConnectionS[0].s==ISS_ON) { if(!Connected) { rc=Connect(); if(rc) { ConnectionSV.s=IPS_OK; //setConnected(true,"calling setconnected"); //ConnectionS[0].s=ISS_ON; //ConnectionS[1].s=ISS_OFF; Connected=true; } else { //ConnectionS[0].s=ISS_OFF; //ConnectionS[1].s=ISS_ON; ConnectionSV.s=IPS_ALERT; Connected=false; } } UpdateProperties(); IDSetSwitch(&ConnectionSV,NULL); } else { if(Connected) rc=Disconnect(); //ConnectionS[0].s=ISS_OFF; //ConnectionS[1].s=ISS_ON; ConnectionSV.s=IPS_IDLE; Connected=false; UpdateProperties(); IDSetSwitch(&ConnectionSV,NULL); } /* if(strcmp(names[x],"CONNECT")==0) { // We are being requested to make a physical connection to the device rc=Connect(); if(rc) { // Connection Succeeded ConnectionSV.s=IPS_OK; Connected=true; } else { // Connection Failed ConnectionSV.s=IPS_ALERT; Connected=false; } IUUpdateSwitch(&ConnectionSV,states,names,n); IDSetSwitch(&ConnectionSV,NULL); IDLog("Connect ccalling update properties\n"); UpdateProperties(); //return true; } if(strcmp(names[x],"DISCONNECT")==0) { // We are being told to disconnect from the device rc=Disconnect(); if(rc) { ConnectionSV.s=IPS_IDLE; } else { ConnectionSV.s=IPS_ALERT; } Connected=false; IDLog("Disconnect calling update properties\n"); UpdateProperties(); // And now lets tell everybody how it went IUUpdateSwitch(&ConnectionSV,states,names,n); IDSetSwitch(&ConnectionSV,NULL); return true; } */ //} } } // let the default driver have a crack at it return INDI::DefaultDriver::ISNewSwitch(dev, name, states, names, n); } // This is a helper function // that just encapsulates the Indi way into our clean c++ way of doing things int IndiDevice::SetTimer(int t) { return IEAddTimer(t,timerfunc,this); } // Just another helper to help encapsulate indi into a clean class void IndiDevice::RemoveTimer(int t) { IERmTimer(t); return; } // This is just a placeholder // This function should be overriden by child classes if they use timers // So we should never get here void IndiDevice::TimerHit() { return; } bool IndiDevice::Connect() { // We dont actually implement a device here // So we cannot connect to it IDLog("IndiDevice Connect, we should never get here\n"); IDMessage(deviceName(),"IndiDevice:: has no device attached...."); return false; } bool IndiDevice::Disconnect() { // Since we cannot connect, we cant disconnect either IDMessage(deviceName(),"IndiDevice:: has no device to detach...."); return false; } bool IndiDevice::UpdateProperties() { // The base device has no properties to update return true; } void IndiDevice::ISSnoopDevice (XMLEle *root) { INDI_UNUSED(root); } bool IndiDevice::SaveConfig() { // FIXME REMOVE THIS return true; char err[MAXRBUF]; FILE *fp; //int rc; fp=IUGetConfigFP(NULL,deviceName(),err); if(fp != NULL) { IUSaveConfigTag(fp,0); //IUSaveConfigText(fp,&FilterNameTV); // Tell child classes to write any items they want // into persistent storage WritePersistentConfig(fp); IUSaveConfigTag(fp,1); fclose(fp); //IDMessage(deviceName(),"Configuration Saved\n"); return true; } else { IDMessage(deviceName(),"Save config failed\n"); } return false; } bool IndiDevice::WritePersistentConfig(FILE *f) { return false; } bool IndiDevice::LoadConfig() { char err[MAXRBUF]; int rc; rc=IUReadConfig(NULL,deviceName(),err); if(rc==0) return true; return false; } libindi-0.9.7/libs/indibase/indifocuser.h0000644000175000017500000000760512241463551017326 0ustar jasemjasem/******************************************************************************* Copyright(c) 2013 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDIFOCUSSER_H #define INDIFOCUSSER_H #include "defaultdevice.h" /** * \class INDI::Focuser \brief Class to provide general functionality of a focuser device. Both relative and absolute focuser supported. Furthermore, if no position feedback is available from the focuser, an open-loop control is possible using timers, speed presets, and direction of motion. Developers need to subclass INDI::Focuser to implement any driver for focusers within INDI. \author Jasem Mutlaq \author Gerry Rozema */ class INDI::Focuser : public INDI::DefaultDevice { public: Focuser(); virtual ~Focuser(); enum FocusDirection { FOCUS_INWARD, FOCUS_OUTWARD }; virtual bool initProperties(); virtual void ISGetProperties (const char *dev); virtual bool updateProperties(); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISSnoopDevice (XMLEle *root); protected: /** \brief Move the focuser in a particular direction with a specific speed for a finite duration. \param dir Direction of focuser, either FOCUS_INWARD or FOCUS_OUTWARD. \param speed Speed of focuser if supported by the focuser. \param duration The timeout in milliseconds before the focus motion halts. \return True if succssfull, false otherwise. */ virtual bool Move(FocusDirection dir, int speed, int duration); /** \brief Move the focuser to an absolute position. \param ticks The new position of the focuser. \return Return 0 if motion is completed and focuser reached requested position. Return 1 if focuser started motion to requested position and is in progress. Return -1 if there is an error. */ virtual int MoveAbs(int ticks); /** \brief Move the focuser to an relative position. \param dir Direction of focuser, either FOCUS_INWARD or FOCUS_OUTWARD. \param ticks The relative ticks to move. \return Return 0 if motion is completed and focuser reached requested position. Return 1 if focuser started motion to requested position and is in progress. Return -1 if there is an error. */ virtual int MoveRel(FocusDirection dir, unsigned int ticks); INumberVectorProperty FocusSpeedNP; INumber FocusSpeedN[1]; ISwitchVectorProperty FocusMotionSP; // A Switch in the client interface to park the scope ISwitch FocusMotionS[2]; INumberVectorProperty FocusTimerNP; INumber FocusTimerN[1]; INumberVectorProperty FocusAbsPosNP; INumber FocusAbsPosN[1]; INumberVectorProperty FocusRelPosNP; INumber FocusRelPosN[1]; }; #endif // INDIFOCUSSER_H libindi-0.9.7/libs/indibase/indibase.h0000644000175000017500000001145212241463551016565 0ustar jasemjasem#ifndef INDIBASE_H #define INDIBASE_H #include "indiapi.h" #include "indidevapi.h" #define MAXRBUF 2048 /** * \namespace INDI \brief Namespace to encapsulate INDI client, drivers, and mediator classes. Developers can subclass the base devices class to implement device specific functionality. This ensures interoperability and consistency among devices within the same family and reduces code overhead.
  • BaseClient: Base class for INDI clients. By subclassing BaseClient, client can easily connect to INDI server and handle device communication, command, and notifcation.
  • BaseMediator: Abstract class to provide interface for event notifications in INDI::BaseClient.
  • BaseDriver: Base class for all INDI virtual driver as handled and stored in INDI::BaseClient.
  • DefaultDriver: INDI::BaseDriver with extended functionality such as debug, simulation, and configuration support. It is \e only used by drivers directly, it cannot be used by clients.
  • FilterInterface: Basic interface for filter wheels functions.
  • GuiderInterface: Basic interface for guider (ST4) port functions.
  • CCD: Base class for CCD drivers. Provides basic support for single chip CCD and CCDs with a guide head as well.
  • Telescope: Base class for telescope drivers.
  • FilterWheel: Base class for Filter Wheels. It implements the FilterInterface.
  • Focuser: Base class for focusers.
  • USBDevice: Base class for USB devices for direct read/write/control over USB.
  • Controller: Class to handle controller inputs like joysticks and gamepads.
  • Logger: Class to handle debugging and logging of drivers.
\author Jasem Mutlaq \author Gerry Rozema */ namespace INDI { class BaseMediator; class BaseClient; class BaseDevice; class DefaultDevice; class FilterInterface; class GuiderInterface; class CCD; class Telescope; class FilterWheel; class Focuser; class USBDevice; class Property; class Controller; class Logger; } /*! INDI property type */ typedef enum { INDI_NUMBER, /*!< INumberVectorProperty. */ INDI_SWITCH, /*!< ISwitchVectorProperty. */ INDI_TEXT, /*!< ITextVectorProperty. */ INDI_LIGHT, /*!< ILightVectorProperty. */ INDI_BLOB, /*!< IBLOBVectorProperty. */ INDI_UNKNOWN } INDI_TYPE; /** * \class INDI::BaseMediator \brief Meditates event notification as generated by driver and passed to clients. */ class INDI::BaseMediator { public: /** \brief Emmited when a new device is created from INDI server. \param dp Pointer to the base device instance */ virtual void newDevice(INDI::BaseDevice *dp) =0; /** \brief Emmited when a new property is created for an INDI driver. \param property Pointer to the Property Container */ virtual void newProperty(INDI::Property *property) =0; /** \brief Emmited when a property is deleted for an INDI driver. \param property Pointer to the Property Container to remove. */ virtual void removeProperty(INDI::Property *property) =0; /** \brief Emmited when a new BLOB value arrives from INDI server. \param bp Pointer to filled and process BLOB. */ virtual void newBLOB(IBLOB *bp) =0; /** \brief Emmited when a new switch value arrives from INDI server. \param svp Pointer to a switch vector property. */ virtual void newSwitch(ISwitchVectorProperty *svp) =0; /** \brief Emmited when a new number value arrives from INDI server. \param nvp Pointer to a number vector property. */ virtual void newNumber(INumberVectorProperty *nvp) =0; /** \brief Emmited when a new text value arrives from INDI server. \param tvp Pointer to a text vector property. */ virtual void newText(ITextVectorProperty *tvp) =0; /** \brief Emmited when a new light value arrives from INDI server. \param lvp Pointer to a light vector property. */ virtual void newLight(ILightVectorProperty *lvp) =0; /** \brief Emmited when a new message arrives from INDI server. \param dp pointer to the INDI device the message is sent to. \param messageID ID of the message that can be used to retrieve the message from the device's messageQueue() function. */ virtual void newMessage(INDI::BaseDevice *dp, int messageID) =0; /** \brief Emmited when the server is connected. */ virtual void serverConnected() =0; /** \brief Emmited when the server gets disconnected. \param exit_code 0 if client was requested to disconnect from server. -1 if connection to server is terminated due to remote server disconnection. */ virtual void serverDisconnected(int exit_code) =0; virtual ~BaseMediator() {} }; #endif // INDIBASE_H libindi-0.9.7/libs/indibase/indiguiderinterface.h0000644000175000017500000000577112241463551021022 0ustar jasemjasem/* Guider Interface Copyright (C) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #ifndef GUIDERINTERFACE_H #define GUIDERINTERFACE_H #include "indibase.h" /** * \class INDI::GuiderInterface \brief Provides interface to implement guider (ST4) port functionality. \e IMPORTANT: initGuiderProperties() must be called before any other function to initilize the guider properties. \e IMPORATNT: processGuiderProperties() must be called in your driver's ISNewNumber(..) function. processGuiderProperties() will call the guide functions GuideXXXX functions accordingly to the driver. \author Jasem Mutlaq */ class INDI::GuiderInterface { public: /** \brief Guide north for ms milliseconds \return True if OK, false otherwise */ virtual bool GuideNorth(float ms) = 0; /** \brief Guide south for ms milliseconds \return True if OK, false otherwise */ virtual bool GuideSouth(float ms) = 0; /** \brief Guide east for ms milliseconds \return True if OK, false otherwise */ virtual bool GuideEast(float ms) = 0; /** \brief Guide west for ms milliseconds \return True if OK, false otherwise */ virtual bool GuideWest(float ms) = 0; protected: GuiderInterface(); ~GuiderInterface(); /** \brief Initilize guider properties. It is recommended to call this function within initProperties() of your primary device \param deviceName Name of the primary device \param groupName Group or tab name to be used to define guider properties. */ void initGuiderProperties(const char *deviceName, const char* groupName); /** \brief Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device. This function then takes care of issuing the corresponding * GuideXXXX function accordingly. * \param name device name * \param values value as passed by the client * \param names names as passed by the client * \param n number of values and names pair to process. */ void processGuiderProperties(const char *name, double values[], char *names[], int n); INumber GuideNSN[2]; INumberVectorProperty GuideNSNP; INumber GuideWEN[2]; INumberVectorProperty GuideWENP; }; #endif // GUIDERINTERFACE_H libindi-0.9.7/libs/indibase/indiusbdevice.h0000644000175000017500000000411112241463551017616 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef USBDEVICE_H #define USBDEVICE_H #pragma once #include #include #include #include #include #include "indibase.h" /** * \class INDI::USBDevice \brief Class to provide general functionality of a generic USB device. Developers need to subclass INDI::USBDevice to implement any driver within INDI that requires direct read/write/control over USB. \author Gerry Rozema \note This class implements legacy libusb API v0.1 */ class INDI::USBDevice { protected: struct usb_device *dev; struct usb_dev_handle *usb_handle; int ProductId; int VendorId; int OutputType; int OutputEndpoint; int InputType; int InputEndpoint; struct usb_device * FindDevice(int,int,int); public: int WriteInterrupt(char *,int,int); int ReadInterrupt(char *,int,int); int ControlMessage(unsigned char request_type, unsigned char request, unsigned int value, unsigned int index, char *data, unsigned char len); int WriteBulk(char *buf,int nbytes,int timeout); int ReadBulk(char *buf,int nbytes,int timeout); int FindEndpoints(); int Open(); USBDevice(void); USBDevice(struct usb_device *); virtual ~USBDevice(void); }; #endif // USBDEVICE_H libindi-0.9.7/libs/indibase/indifilterwheel.h0000644000175000017500000000436312241463551020170 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010, 2011 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDI_FILTERWHEEL_H #define INDI_FILTERWHEEL_H #include "defaultdevice.h" #include "indifilterinterface.h" /** * \class INDI::FilterWheel \brief Class to provide general functionality of a filter wheel device. Developers need to subclass INDI::FilterWheel to implement any driver for filter wheels within INDI. \author Gerry Rozema, Jasem Mutlaq \see INDI::FilterInterface */ class INDI::FilterWheel: public INDI::DefaultDevice, public INDI::FilterInterface { protected: FilterWheel(); virtual ~FilterWheel(); public: virtual bool initProperties(); virtual bool updateProperties(); virtual void ISGetProperties (const char *dev); virtual bool ISSnoopDevice (XMLEle *root); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); protected: virtual bool saveConfigItems(FILE *fp); virtual int QueryFilter(); virtual bool SelectFilter(int); virtual bool SetFilterNames(); virtual bool GetFilterNames(const char* groupName); }; #endif // INDI::FilterWheel_H libindi-0.9.7/libs/indibase/inditelescope.cpp0000644000175000017500000004400512241463551020171 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Gerry Rozema, Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include #include "inditelescope.h" #include "indicom.h" #define POLLMS 1000 INDI::Telescope::Telescope() { //ctor } INDI::Telescope::~Telescope() { } bool INDI::Telescope::initProperties() { DefaultDevice::initProperties(); IUFillNumber(&EqN[0],"RA","RA (hh:mm:ss)","%010.6m",0,24,0,0); IUFillNumber(&EqN[1],"DEC","DEC (dd:mm:ss)","%010.6m",-90,90,0,0); IUFillNumberVector(&EqNP,EqN,2,getDeviceName(),"EQUATORIAL_EOD_COORD","Eq. Coordinates",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE); IUFillText(&TimeT[0],"UTC","UTC Time",""); IUFillText(&TimeT[1],"OFFSET","UTC Offset",""); IUFillTextVector(&TimeTP,TimeT,2,getDeviceName(),"TIME_UTC","UTC",SITE_TAB,IP_RW,60,IPS_IDLE); IUFillNumber(&LocationN[0],"LAT","Lat (dd:mm:ss)","%010.6m",-90,90,0,0.0); IUFillNumber(&LocationN[1],"LONG","Lon (dd:mm:ss)","%010.6m",0,360,0,0.0 ); IUFillNumber(&LocationN[2],"ELEV","Elevation (m)","%g",-200,10000,0,0 ); IUFillNumberVector(&LocationNP,LocationN,3,getDeviceName(),"GEOGRAPHIC_COORD","Scope Location",SITE_TAB,IP_RW,60,IPS_OK); IUFillSwitch(&CoordS[0],"TRACK","Track",ISS_OFF); IUFillSwitch(&CoordS[1],"SLEW","Slew",ISS_OFF); IUFillSwitch(&CoordS[2],"SYNC","Sync",ISS_OFF); if (canSync()) IUFillSwitchVector(&CoordSP,CoordS,3,getDeviceName(),"ON_COORD_SET","On Set",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); else IUFillSwitchVector(&CoordSP,CoordS,2,getDeviceName(),"ON_COORD_SET","On Set",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillSwitch(&ConfigS[0], "CONFIG_LOAD", "Load", ISS_OFF); IUFillSwitch(&ConfigS[1], "CONFIG_SAVE", "Save", ISS_OFF); IUFillSwitch(&ConfigS[2], "CONFIG_DEFAULT", "Default", ISS_OFF); IUFillSwitchVector(&ConfigSP, ConfigS, 3, getDeviceName(), "CONFIG_PROCESS", "Configuration", "Options", IP_RW, ISR_1OFMANY, 60, IPS_IDLE); IUFillSwitch(&ParkS[0],"PARK","Park",ISS_OFF); IUFillSwitchVector(&ParkSP,ParkS,1,getDeviceName(),"TELESCOPE_PARK","Park",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillSwitch(&AbortS[0],"ABORT","Abort",ISS_OFF); IUFillSwitchVector(&AbortSP,AbortS,1,getDeviceName(),"TELESCOPE_ABORT_MOTION","Abort Motion",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillText(&PortT[0],"PORT","Port","/dev/ttyUSB0"); IUFillTextVector(&PortTP,PortT,1,getDeviceName(),"DEVICE_PORT","Ports",OPTIONS_TAB,IP_RW,60,IPS_IDLE); IUFillSwitch(&MovementNSS[MOTION_NORTH], "MOTION_NORTH", "North", ISS_OFF); IUFillSwitch(&MovementNSS[MOTION_SOUTH], "MOTION_SOUTH", "South", ISS_OFF); IUFillSwitchVector(&MovementNSSP, MovementNSS, 2, getDeviceName(),"TELESCOPE_MOTION_NS", "North/South", MOTION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); IUFillSwitch(&MovementWES[MOTION_WEST], "MOTION_WEST", "West", ISS_OFF); IUFillSwitch(&MovementWES[MOTION_EAST], "MOTION_EAST", "East", ISS_OFF); IUFillSwitchVector(&MovementWESP, MovementWES, 2, getDeviceName(),"TELESCOPE_MOTION_WE", "West/East", MOTION_TAB, IP_RW, ISR_1OFMANY, 60, IPS_IDLE); IUFillNumber(&ScopeParametersN[0],"TELESCOPE_APERTURE","Aperture (mm)","%g",50,4000,0,0.0); IUFillNumber(&ScopeParametersN[1],"TELESCOPE_FOCAL_LENGTH","Focal Length (mm)","%g",100,10000,0,0.0 ); IUFillNumber(&ScopeParametersN[2],"GUIDER_APERTURE","Guider Aperture (mm)","%g",50,4000,0,0.0); IUFillNumber(&ScopeParametersN[3],"GUIDER_FOCAL_LENGTH","Guider Focal Length (mm)","%g",100,10000,0,0.0 ); IUFillNumberVector(&ScopeParametersNP,ScopeParametersN,4,getDeviceName(),"TELESCOPE_INFO","Scope Properties",OPTIONS_TAB,IP_RW,60,IPS_OK); TrackState=SCOPE_PARKED; return true; } void INDI::Telescope::ISGetProperties (const char *dev) { // First we let our parent populate DefaultDevice::ISGetProperties(dev); // We may need the port set before we can connect //IDDefText(&PortTP,NULL); defineText(&PortTP); defineSwitch(&ConfigSP); if(isConnected()) { // Now we add our telescope specific stuff defineSwitch(&CoordSP); defineNumber(&EqNP); defineSwitch(&AbortSP); defineText(&TimeTP); defineNumber(&LocationNP); defineSwitch(&ParkSP); defineSwitch(&MovementNSSP); defineSwitch(&MovementWESP); defineSwitch(&ConfigSP); defineNumber(&ScopeParametersNP); } return; } bool INDI::Telescope::updateProperties() { if(isConnected()) { // Now we add our telescope specific stuff defineSwitch(&CoordSP); defineNumber(&EqNP); defineSwitch(&AbortSP); defineSwitch(&MovementNSSP); defineSwitch(&MovementWESP); defineText(&TimeTP); defineNumber(&LocationNP); if (canPark()) defineSwitch(&ParkSP); defineNumber(&ScopeParametersNP); } else { deleteProperty(CoordSP.name); deleteProperty(EqNP.name); deleteProperty(AbortSP.name); deleteProperty(MovementNSSP.name); deleteProperty(MovementWESP.name); deleteProperty(TimeTP.name); deleteProperty(LocationNP.name); if (canPark()) deleteProperty(ParkSP.name); deleteProperty(ScopeParametersNP.name); } return true; } bool INDI::Telescope::ISSnoopDevice(XMLEle *root) { return INDI::DefaultDevice::ISSnoopDevice(root); } bool INDI::Telescope::saveConfigItems(FILE *fp) { IUSaveConfigText(fp, &PortTP); IUSaveConfigNumber(fp,&LocationNP); IUSaveConfigNumber(fp, &ScopeParametersNP); return true; } void INDI::Telescope::NewRaDec(double ra,double dec) { // Lets set our eq values to these numbers // which came from the hardware static int last_state=-1; switch(TrackState) { case SCOPE_PARKED: case SCOPE_IDLE: EqNP.s=IPS_IDLE; break; case SCOPE_SLEWING: EqNP.s=IPS_BUSY; break; case SCOPE_TRACKING: EqNP.s=IPS_OK; break; default: break; } //IDLog("newRA DEC RA %g - DEC %g --- EqN[0] %g --- EqN[1] %g --- EqN.state %d\n", ra, dec, EqN[0].value, EqN[1].value, EqNP.s); if (EqN[0].value != ra || EqN[1].value != dec || EqNP.s != last_state) { EqN[0].value=ra; EqN[1].value=dec; last_state = EqNP.s; IDSetNumber(&EqNP, NULL); } } bool INDI::Telescope::Sync(double ra,double dec) { // if we get here, our mount doesn't support sync DEBUG(Logger::DBG_ERROR, "Mount does not support Sync."); return false; } bool INDI::Telescope::MoveNS(TelescopeMotionNS dir) { DEBUG(Logger::DBG_ERROR, "Mount does not support North/South motion."); IUResetSwitch(&MovementNSSP); MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); return false; } bool INDI::Telescope::MoveWE(TelescopeMotionWE dir) { DEBUG(Logger::DBG_ERROR,"Mount does not support West/East motion."); IUResetSwitch(&MovementWESP); MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, NULL); return false; } /************************************************************************************** ** Process Text properties ***************************************************************************************/ bool INDI::Telescope::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // first check if it's for our device if(strcmp(dev,getDeviceName())==0) { // This is for our device // Now lets see if it's something we process here if(strcmp(name,PortTP.name)==0) { // This is our port, so, lets process it int rc; PortTP.s=IPS_OK; rc=IUUpdateText(&PortTP,texts,names,n); // Update client display IDSetText(&PortTP,NULL); // We processed this one, so, tell the world we did it return true; } if(strcmp(name,"TIME_UTC")==0) { int utcindex = IUFindIndex("UTC", names, n); int offsetindex= IUFindIndex("OFFSET", names, n); struct ln_date utc; double utc_offset=0; if (extractISOTime(texts[utcindex], &utc) == -1) { TimeTP.s = IPS_ALERT; IDSetText(&TimeTP, "Date/Time is invalid: %s.", texts[utcindex]); return false; } utc_offset = atof(texts[offsetindex]); if (updateTime(&utc, utc_offset)) { IUUpdateText(&TimeTP, texts, names, n); TimeTP.s = IPS_OK; IDSetText(&TimeTP, NULL); return true; } else { TimeTP.s = IPS_ALERT; IDSetText(&TimeTP, NULL); return false; } } } return DefaultDevice::ISNewText(dev,name,texts,names,n); } /************************************************************************************** ** ***************************************************************************************/ bool INDI::Telescope::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // first check if it's for our device if(strcmp(dev,getDeviceName())==0) { if(strcmp(name,"EQUATORIAL_EOD_COORD")==0) { // this is for us, and it is a goto bool rc=false; double ra=-1; double dec=-100; for (int x=0; x=0)&&(ra<=24)&&(dec>=-90)&&(dec<=90)) { // we got an ra and a dec, both in range // And now we let the underlying hardware specific class // perform the goto // Ok, lets see if we should be doing a goto // or a sync if (canSync()) { ISwitch *sw; sw=IUFindSwitch(&CoordSP,"SYNC"); if((sw != NULL)&&( sw->s==ISS_ON )) { rc=Sync(ra,dec); return rc; } } // Ensure we are not showing Parked status ParkSP.s=IPS_IDLE; IUResetSwitch(&ParkSP); rc=Goto(ra,dec); // Ok, now we have to put our switches back } return rc; } if(strcmp(name,"GEOGRAPHIC_COORD")==0) { int latindex = IUFindIndex("LAT", names, n); int longindex= IUFindIndex("LONG", names, n); int elevationindex = IUFindIndex("ELEV", names, n); if (latindex == -1 || longindex==-1 || elevationindex == -1) { LocationNP.s=IPS_ALERT; IDSetNumber(&LocationNP, "Location data missing or corrupted."); } double targetLat = values[latindex]; double targetLong = values[longindex]; double targetElev = values[elevationindex]; if (updateLocation(targetLat, targetLong, targetElev)) { LocationNP.s=IPS_OK; IUUpdateNumber(&LocationNP,values,names,n); // Update client display IDSetNumber(&LocationNP,NULL); } else { LocationNP.s=IPS_ALERT; // Update client display IDSetNumber(&LocationNP,NULL); } } if(strcmp(name,"TELESCOPE_INFO")==0) { ScopeParametersNP.s = IPS_OK; IUUpdateNumber(&ScopeParametersNP,values,names,n); IDSetNumber(&ScopeParametersNP,NULL); return true; } } return DefaultDevice::ISNewNumber(dev,name,values,names,n); } /************************************************************************************** ** ***************************************************************************************/ bool INDI::Telescope::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { // This one is for us if(strcmp(name,"ON_COORD_SET")==0) { // client is telling us what to do with co-ordinate requests CoordSP.s=IPS_OK; IUUpdateSwitch(&CoordSP,states,names,n); // Update client display IDSetSwitch(&CoordSP, NULL); return true; } if(strcmp(name,"TELESCOPE_PARK")==0) { Park(); return true; } if(strcmp(name,"TELESCOPE_MOTION_NS")==0) { IUUpdateSwitch(&MovementNSSP,states,names,n); MovementNSSP.s = IPS_BUSY; if (MovementNSS[MOTION_NORTH].s == ISS_ON) MoveNS(MOTION_NORTH); else MoveNS(MOTION_SOUTH); return true; } if(strcmp(name,"TELESCOPE_MOTION_WE")==0) { IUUpdateSwitch(&MovementWESP,states,names,n); MovementWESP.s = IPS_BUSY; if (MovementWES[MOTION_WEST].s == ISS_ON) MoveWE(MOTION_WEST); else MoveWE(MOTION_EAST); return true; } if(strcmp(name,"TELESCOPE_ABORT_MOTION")==0) { IUResetSwitch(&AbortSP); if (Abort()) { AbortSP.s = IPS_OK; if (ParkSP.s == IPS_BUSY) { ParkSP.s = IPS_IDLE; IDSetSwitch(&ParkSP, NULL); } if (EqNP.s == IPS_BUSY) { EqNP.s = IPS_IDLE; IDSetNumber(&EqNP, NULL); } if (MovementWESP.s == IPS_BUSY) { MovementWESP.s = IPS_IDLE; IDSetSwitch(&MovementWESP, NULL); } if (MovementNSSP.s == IPS_BUSY) { MovementNSSP.s = IPS_IDLE; IDSetSwitch(&MovementNSSP, NULL); } if (EqNP.s == IPS_BUSY) { EqNP.s = IPS_IDLE; IDSetNumber(&EqNP, NULL); } TrackState = SCOPE_IDLE; } else AbortSP.s = IPS_ALERT; IDSetSwitch(&AbortSP, NULL); return true; } } // Nobody has claimed this, so, ignore it return DefaultDevice::ISNewSwitch(dev,name,states,names,n); } bool INDI::Telescope::Connect() { // Parent class is wanting a connection if (isDebug()) IDLog("INDI::Telescope arrived in connect with %s\n",PortT[0].text); bool rc=false; if(isConnected()) return true; if (isDebug()) IDLog("Telescope Calling Connect\n"); rc=Connect(PortT[0].text); if (isDebug()) IDLog("Telescope Connect returns %d\n",rc); if(rc) SetTimer(POLLMS); return rc; } bool INDI::Telescope::Connect(const char *port) { // We want to connect to a port // For now, we will assume it's a serial port int connectrc=0; char errorMsg[MAXRBUF]; bool rc; DEBUGF(Logger::DBG_DEBUG, "INDI::Telescope connecting to %s\n",port); if ( (connectrc = tty_connect(port, 9600, 8, 0, 1, &PortFD)) != TTY_OK) { tty_error_msg(connectrc, errorMsg, MAXRBUF); DEBUGF(Logger::DBG_ERROR,"Failed to connect to port %s. Error: %s", port, errorMsg); return false; } DEBUGF(Logger::DBG_DEBUG, "Port Fd %d\n",PortFD); /* Test connection */ rc=ReadScopeStatus(); if(rc) { // We got a valid scope status read DEBUG(Logger::DBG_SESSION,"Telescope is online."); return rc; } // Ok, we didn't get a valid read // So, we need to close our handle and send error messages tty_disconnect(PortFD); return false; } bool INDI::Telescope::Disconnect() { DEBUG(Logger::DBG_DEBUG, "INDI::Telescope Disconnect\n"); tty_disconnect(PortFD); DEBUG(Logger::DBG_SESSION,"Telescope is offline."); return true; } void INDI::Telescope::TimerHit() { if(isConnected()) { bool rc; rc=ReadScopeStatus(); if(rc == false) { // read was not good EqNP.s=IPS_ALERT; IDSetNumber(&EqNP, NULL); } SetTimer(POLLMS); } } bool INDI::Telescope::Park() { // We want to park our telescope // but the scope doesn't seem to support park // or it wouldn't have gotten here return false; } bool INDI::Telescope::canSync() { return false; } bool INDI::Telescope::canPark() { return false; } bool INDI::Telescope::updateTime(ln_date *utc, double utc_offset) { INDI_UNUSED(utc); INDI_UNUSED(utc_offset); return true; } bool INDI::Telescope::updateLocation(double latitude, double longitude, double elevation) { INDI_UNUSED(latitude); INDI_UNUSED(longitude); INDI_UNUSED(elevation); return true; } libindi-0.9.7/libs/indibase/indifocuser.cpp0000644000175000017500000001734312241463551017661 0ustar jasemjasem/******************************************************************************* Copyright(c) 2013 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "indifocuser.h" #include INDI::Focuser::Focuser() { } INDI::Focuser::~Focuser() { } bool INDI::Focuser::initProperties() { DefaultDevice::initProperties(); // let the base class flesh in what it wants IUFillNumber(&FocusSpeedN[0],"FOCUS_SPEED_VALUE","Focus Speed","%3.0f",0.0,255.0,1.0,255.0); IUFillNumberVector(&FocusSpeedNP,FocusSpeedN,1,getDeviceName(),"FOCUS_SPEED","Speed",MAIN_CONTROL_TAB,IP_RW,60,IPS_OK); IUFillNumber(&FocusTimerN[0],"FOCUS_TIMER_VALUE","Focus Timer","%4.0f",0.0,1000.0,10.0,1000.0); IUFillNumberVector(&FocusTimerNP,FocusTimerN,1,getDeviceName(),"FOCUS_TIMER","Timer",MAIN_CONTROL_TAB,IP_RW,60,IPS_OK); IUFillSwitch(&FocusMotionS[0],"FOCUS_INWARD","Focus In",ISS_ON); IUFillSwitch(&FocusMotionS[1],"FOCUS_OUTWARD","Focus Out",ISS_OFF); IUFillSwitchVector(&FocusMotionSP,FocusMotionS,2,getDeviceName(),"FOCUS_MOTION","Direction",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_OK); // Driver can define those to clients if there is support IUFillNumber(&FocusAbsPosN[0],"FOCUS_ABSOLUTE_POSITION","Ticks","%4.0f",0.0,100000.0,1000.0,50000.0); IUFillNumberVector(&FocusAbsPosNP,FocusAbsPosN,1,getDeviceName(),"ABS_FOCUS_POSITION","Absolute Position",MAIN_CONTROL_TAB,IP_RW,60,IPS_OK); IUFillNumber(&FocusRelPosN[0],"RELATIVE_ABSOLUTE_POSITION","Ticks","%4.0f",0.0,100000.0,1000.0,50000.0); IUFillNumberVector(&FocusRelPosNP,FocusRelPosN,1,getDeviceName(),"REL_FOCUS_POSITION","Relative Position",MAIN_CONTROL_TAB,IP_RW,60,IPS_OK); addDebugControl(); return true; } void INDI::Focuser::ISGetProperties (const char *dev) { // First we let our parent populate DefaultDevice::ISGetProperties(dev); return; } bool INDI::Focuser::updateProperties() { if(isConnected()) { // Now we add our focusser specific stuff defineSwitch(&FocusMotionSP); defineNumber(&FocusSpeedNP); defineNumber(&FocusTimerNP); } else { deleteProperty(FocusMotionSP.name); deleteProperty(FocusSpeedNP.name); deleteProperty(FocusTimerNP.name); } return true; } bool INDI::Focuser::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // first check if it's for our device if(strcmp(dev,getDeviceName())==0) { // This is for our device // Now lets see if it's something we process here if(strcmp(name,"FOCUS_TIMER")==0) { // Ok, gotta move the focusser now FocusDirection dir; int speed; int t; //IDLog(") // first we get all the numbers just sent to us FocusTimerNP.s=IPS_OK; IUUpdateNumber(&FocusTimerNP,values,names,n); // Now lets find what we need for this move speed=FocusSpeedN[0].value; if(FocusMotionS[0].s==ISS_ON) dir=FOCUS_INWARD; else dir=FOCUS_OUTWARD; t=FocusTimerN[0].value; if (Move(dir,speed,t) == false) FocusTimerNP.s = IPS_ALERT; IDSetNumber(&FocusTimerNP,NULL); return true; } if(strcmp(name,"FOCUS_SPEED")==0) { FocusSpeedNP.s=IPS_OK; IUUpdateNumber(&FocusSpeedNP,values,names,n); // Update client display IDSetNumber(&FocusSpeedNP,NULL); return true; } if(strcmp(name,"ABS_FOCUS_POSITION")==0) { int newPos = (int) values[0]; int ret =0; if ( (ret = MoveAbs(newPos)) == 0) { FocusAbsPosNP.s=IPS_OK; IUUpdateNumber(&FocusAbsPosNP,values,names,n); IDSetNumber(&FocusAbsPosNP, "Focuser moved to position %d", newPos); return true; } else if (ret == 1) { FocusAbsPosNP.s=IPS_BUSY; IDSetNumber(&FocusAbsPosNP, "Focuser is moving to position %d", newPos); return true; } FocusAbsPosNP.s = IPS_ALERT; IDSetNumber(&FocusAbsPosNP, "Focuser failed to move to new requested position."); return false; } if(strcmp(name,"REL_FOCUS_POSITION")==0) { int newPos = (int) values[0]; int ret =0; if ( (ret=MoveRel( (FocusMotionS[0].s == ISS_ON ? FOCUS_INWARD : FOCUS_OUTWARD), newPos)) == 0) { FocusRelPosNP.s=IPS_OK; IUUpdateNumber(&FocusRelPosNP,values,names,n); IDSetNumber(&FocusRelPosNP, "Focuser moved %d steps", newPos); IDSetNumber(&FocusAbsPosNP, NULL); return true; } else if (ret == 1) { FocusRelPosNP.s=IPS_BUSY; IDSetNumber(&FocusAbsPosNP, "Focuser is moving %d steps...", newPos); return true; } FocusRelPosNP.s = IPS_ALERT; IDSetNumber(&FocusRelPosNP, "Focuser failed to move to new requested position."); return false; } } return DefaultDevice::ISNewNumber(dev,name,values,names,n); } bool INDI::Focuser::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { // This one is for us if(strcmp(name,"FOCUS_MOTION")==0) { // client is telling us what to do with focus direction FocusMotionSP.s=IPS_OK; IUUpdateSwitch(&FocusMotionSP,states,names,n); // Update client display IDSetSwitch(&FocusMotionSP,NULL); return true; } } // Nobody has claimed this, so, ignore it return DefaultDevice::ISNewSwitch(dev,name,states,names,n); } bool INDI::Focuser::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { return DefaultDevice::ISNewText(dev, name, texts, names, n); } bool INDI::Focuser::Move(FocusDirection dir, int speed, int duration) { // This should be a virtual function, because the low level hardware class // must override this // but it's much easier early development if the method actually // exists for now return false; } int INDI::Focuser::MoveRel(FocusDirection dir, unsigned int ticks) { // This should be a virtual function, because the low level hardware class // must override this // but it's much easier early development if the method actually // exists for now return -1; } int INDI::Focuser::MoveAbs(int ticks) { // This should be a virtual function, because the low level hardware class // must override this // but it's much easier early development if the method actually // exists for now return -1; } bool INDI::Focuser::ISSnoopDevice (XMLEle *root) { return INDI::DefaultDevice::ISSnoopDevice(root); } libindi-0.9.7/libs/indibase/indicontroller.h0000644000175000017500000001552512241463551020043 0ustar jasemjasem/******************************************************************************* Copyright (C) 2013 Jasem Mutlaq This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef CONTROLLER_H #define CONTROLLER_H #include // detect std::lib #ifdef _LIBCPP_VERSION #include #else #include #endif #include #include namespace INDI { /** * \class INDI::Controller * @brief The Controller class provides functionality to access a controller (e.g. joystick) input and send it to the requesting driver. * * - To use the class in an INDI::DefaultDevice based driver: * * -# Set the callback functions for each of input type requested. * * -# Map the properties you wish to /e listen to from the joystick driver by specifying * the type of input requested and the initial default value. * For example: * \code{.cpp} * mapController("ABORT", "Abort Telescope", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1"); * \endcode * After mapping all the desired controls, call the class initProperties() function. * If the user enables joystick support in the driver and presses a button on the joystick, the button * callback function will be invoked with the name & state of the button. * * -# Call the Controller's ISGetProperties(), initProperties(), updateProperties(), saveConfigItems(), and * ISNewXXX functions from the same standard functions in your driver. * * The class communicates with INDI joystick driver which in turn enumerates the game pad and provides * three types of constrcuts: *
    *
  • Joysticks: Each joystick displays a normalized magnitude [0 to 1] and an angle. The angle is measured counter clock wise starting from * the right/east direction [0 to 360]. They are defined as JOYSTICK_# where # is the joystick number.
  • *
  • Axes: Each joystick has two or more axes. Each axis has a raw value and angle. The raw value ranges from -32767.0 to 32767.0 They are * defined as AXIS_# where # is the axis number.
  • *
  • Buttons: Buttons are either on or off. They are defined as BUTTON_# where # is the button number.
  • *
* * \note All indexes start from 1. i.e. There is no BUTTON_0 or JOYSTICK_0. * \see See the LX200 Generic & Celestron GPS drivers for an example implementation. * \warning Both the indi_joystick driver and the driver using this class must be running in the same INDI server * (or chained INDI servers) in order for it to work as it depends on snooping among drivers. * \author Jasem Multaq */ class Controller { public: typedef enum { CONTROLLER_JOYSTICK, CONTROLLER_AXIS, CONTROLLER_BUTTON, CONTROLLER_UNKNOWN } ControllerType; #ifdef _LIBCPP_VERSION /** * @brief joystickFunc Joystick callback function signature. */ typedef std::function joystickFunc; /** * @brief axisFunc Axis callback function signature. */ typedef std::function axisFunc; /** * @brief buttonFunc Button callback function signature. */ typedef std::function buttonFunc; #else /** * @brief joystickFunc Joystick callback function signature. */ typedef std::tr1::function joystickFunc; /** * @brief axisFunc Axis callback function signature. */ typedef std::tr1::function axisFunc; /** * @brief buttonFunc Button callback function signature. */ typedef std::tr1::function buttonFunc; #endif /** * @brief Controller Default ctor * @param cdevice INDI::DefaultDevice device */ Controller(INDI::DefaultDevice *cdevice); virtual ~Controller(); virtual void ISGetProperties(const char *dev); virtual bool initProperties(); virtual bool updateProperties(); virtual bool ISSnoopDevice(XMLEle *root); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool saveConfigItems(FILE *fp); /** * @brief mapController adds a new property to the joystick's settings. * @param propertyName Name * @param propertyLabel Label * @param type The input type of the property. This value cannot be updated. * @param initialValue Initial value for the property. */ void mapController(const char *propertyName, const char *propertyLabel, ControllerType type, const char *initialValue); /** * @brief setJoystickCallback Sets the callback function when a new joystick input is detected. * @param joystickCallback the callback function. */ void setJoystickCallback(joystickFunc joystickCallback); /** * @brief setAxisCallback Sets the callback function when a new axis input is detected. * @param axisCallback the callback function. */ void setAxisCallback(axisFunc axisCallback); /** * @brief setButtonCallback Sets the callback function when a new button input is detected. * @param buttonCallback the callback function. */ void setButtonCallback(buttonFunc buttonCallback); ControllerType getControllerType(const char *name); const char *getControllerSetting(const char *name); protected: static void joystickEvent(const char * joystick_n, double mag, double angle); static void axisEvent(const char * axis_n, int value); static void buttonEvent(const char * button_n, int value); void enableJoystick(); void disableJoystick(); joystickFunc joystickCallbackFunc; buttonFunc buttonCallbackFunc; axisFunc axisCallbackFunc; INDI::DefaultDevice *device; private: /* Joystick Support */ ISwitchVectorProperty UseJoystickSP; ISwitch UseJoystickS[2]; ITextVectorProperty JoystickSettingTP; IText *JoystickSettingT; }; } #endif /* CONTROLLER_H */ libindi-0.9.7/libs/indibase/indilogger.h0000644000175000017500000002034612241463551017134 0ustar jasemjasem/******************************************************************************* Copyright (C) 2012 Evidence Srl - www.evidence.eu.com Adapted to INDI Library by Jasem Mutlaq & Geehalel. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef LOGGER_H #define LOGGER_H #include #include #include #include #include #include #include #include /** * \brief Macro to configure the logger. * Example of configuration of the Logger: * DEBUG_CONF("outputfile", Logger::file_on|Logger::screen_on, DBG_DEBUG, DBG_ERROR); */ #define DEBUG_CONF(outputFile, \ configuration, \ fileVerbosityLevel, \ screenVerbosityLevel) { \ Logger::getInstance().configure(outputFile, \ configuration, \ fileVerbosityLevel, \ screenVerbosityLevel); \ } /** * \brief Macro to print log messages. * Example of usage of the Logger: * DEBUG(DBG_DEBUG, "hello " << "world"); */ /* #define DEBUG(priority, msg) { \ std::ostringstream __debug_stream__; \ __debug_stream__ << msg; \ Logger::getInstance().print(priority, __FILE__, __LINE__, \ __debug_stream__.str()); \ } */ #define DEBUG(priority, msg) INDI::Logger::getInstance().print(getDeviceName(), priority, __FILE__, __LINE__,msg) #define DEBUGF(priority, msg, ...) INDI::Logger::getInstance().print(getDeviceName(), priority, __FILE__, __LINE__, msg, __VA_ARGS__) #define DEBUGDEVICE(device, priority, msg) INDI::Logger::getInstance().print(device, priority, __FILE__, __LINE__, msg) #define DEBUGFDEVICE(device, priority, msg, ...) INDI::Logger::getInstance().print(device, priority, __FILE__, __LINE__, msg, __VA_ARGS__) namespace INDI { /** * \class INDI::Logger * @brief The Logger class is a simple logger to log messages to file and INDI clients. This is the implementation of a simple * logger in C++. It is implemented as a Singleton, so it can be easily called through two DEBUG macros. * It is Pthread-safe. It allows to log on both file and screen, and to specify a verbosity threshold for both of them. * * - By default, the class defines 4 levels of debugging/logging levels: * -# Errors: Use macro DEBUG(INDI::Logger::DBG_ERROR, "My Error Message) * * -# Warnings: Use macro DEBUG(INDI::Logger::DBG_WARNING, "My Warning Message) * * -# Session: Use macro DEBUG(INDI::Logger::DBG_SESSION, "My Message) Session messages are the regular status messages from the driver. * * -# Driver Debug: Use macro DEBUG(INDI::Logger::DBG_DEBUG, "My Driver Debug Message) * * \note Use DEBUGF macro if you have a variable list message. e.g. DEBUGF(INDI::Logger::DBG_SESSION, "Hello %s!", "There") * * The default \e active debug levels are Error, Warning, and Session. Driver Debug can be enabled by the client. * * To add a new debug level, call addDebugLevel(). You can add an additional 4 custom debug/logging levels. * * Check INDI Tutorial two for an example simple implementation. */ class Logger { private: /** * \brief Type used for the configuration */ enum loggerConf_ {L_nofile_ = 1 << 0, L_file_ = 1 << 1, L_noscreen_ = 1 << 2, L_screen_ = 1 << 3}; #ifdef LOGGER_MULTITHREAD /** * \brief Lock for mutual exclusion between different threads */ static pthread_mutex_t lock_; #endif bool configured_; /** * \brief Pointer to the unique Logger (i.e., Singleton) */ static Logger* m_; /** * \brief Initial part of the name of the file used for Logging. * Date and time are automatically appended. */ static std::string logFile_; /** * \brief Current configuration of the logger. * Variable to know if logging on file and on screen are enabled. * Note that if the log on file is enabled, it means that the * logger has been already configured, therefore the stream is * already open. */ static loggerConf_ configuration_; /** * \brief Stream used when logging on a file */ std::ofstream out_; /** * \brief Initial time (used to print relative times) */ struct timeval initialTime_; /** * \brief Verbosity threshold for files */ static unsigned int fileVerbosityLevel_; /** * \brief Verbosity threshold for screen */ static unsigned int screenVerbosityLevel_; static unsigned int rememberscreenlevel_; Logger(); ~Logger(); /** * \brief Method to lock in case of multithreading */ inline static void lock(); /** * \brief Method to unlock in case of multithreading */ inline static void unlock(); public: enum VerbosityLevel {DBG_ERROR=0x1, DBG_WARNING=0x2, DBG_SESSION=0x4, DBG_DEBUG=0x8, DBG_EXTRA_1=0x10, DBG_EXTRA_2=0X20, DBG_EXTRA_3=0x40, DBG_EXTRA_4=0x80}; struct switchinit {char name[MAXINDINAME]; char label[MAXINDILABEL]; ISState state; unsigned int levelmask;}; static const unsigned int defaultlevel=DBG_ERROR | DBG_WARNING | DBG_SESSION; static const unsigned int nlevels=8; static struct switchinit LoggingLevelSInit[nlevels]; static ISwitch LoggingLevelS[nlevels]; static ISwitchVectorProperty LoggingLevelSP; static ISwitch ConfigurationS[2]; static ISwitchVectorProperty ConfigurationSP; typedef loggerConf_ loggerConf; static const loggerConf file_on= L_nofile_; static const loggerConf file_off= L_file_; static const loggerConf screen_on= L_noscreen_; static const loggerConf screen_off= L_screen_; static unsigned int customLevel; static std::string getLogFile() { return logFile_;} static loggerConf_ getConfiguration() {return configuration_;} static Logger& getInstance(); /** * @brief Adds a new debugging level to the driver. * * @param debugLevelName The descriptive debug level defined to the client. e.g. Scope Status * @param LoggingLevelName the short logging level recorded in the logfile. e.g. SCOPE * @return bitmask of the new debugging level to be used for any subsequent calls to DEBUG and DEBUGF to record events to this debug level. */ int addDebugLevel(const char *debugLevelName, const char *LoggingLevelName); void print(const char *devicename, const unsigned int verbosityLevel, const std::string& sourceFile, const int codeLine, //const std::string& message, const char *message, ...); void configure (const std::string& outputFile, const loggerConf configuration, const int fileVerbosityLevel, const int screenVerbosityLevel); static struct switchinit DebugLevelSInit[nlevels]; static ISwitch DebugLevelS[nlevels]; static ISwitchVectorProperty DebugLevelSP; static bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); static bool updateProperties(bool debugenable, INDI::DefaultDevice *device); static char Tags[nlevels][MAXINDINAME]; static unsigned int rank(unsigned int l); }; /* Class logger */ inline Logger::loggerConf operator| (Logger::loggerConf __a, Logger::loggerConf __b) { return Logger::loggerConf(static_cast(__a) | static_cast(__b)); } inline Logger::loggerConf operator& (Logger::loggerConf __a, Logger::loggerConf __b) { return Logger::loggerConf(static_cast(__a) & static_cast(__b)); } } #endif /* LOGGER_H */ libindi-0.9.7/libs/indibase/indiccd.h0000644000175000017500000004641612241463551016414 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010, 2011 Gerry Rozema, Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDI_CCD_H #define INDI_CCD_H #include #include #include "defaultdevice.h" #include "indiguiderinterface.h" extern const char *IMAGE_SETTINGS_TAB; extern const char *IMAGE_INFO_TAB; extern const char *GUIDE_HEAD_TAB; extern const char *GUIDE_CONTROL_TAB; /** * @brief The CCDChip class provides functionality of a CCD Chip within a CCD. * */ class CCDChip { public: CCDChip(); ~CCDChip(); typedef enum { LIGHT_FRAME=0, BIAS_FRAME, DARK_FRAME, FLAT_FRAME } CCD_FRAME; typedef enum { FRAME_X, FRAME_Y, FRAME_W, FRAME_H} CCD_FRAME_INDEX; typedef enum { BIN_W, BIN_H} CCD_BIN_INDEX; typedef enum { CCD_MAX_X, CCD_MAX_Y, CCD_PIXEL_SIZE, CCD_PIXEL_SIZE_X, CCD_PIXEL_SIZE_Y, CCD_BITSPERPIXEL} CCD_INFO_INDEX; /** * @brief getXRes Get the horizontal resolution in pixels of the CCD Chip. * @return the horizontal resolution of the CCD Chip. */ inline int getXRes() { return XRes; } /** * @brief Get the vertical resolution in pixels of the CCD Chip. * @return the horizontal resolution of the CCD Chip. */ inline int getYRes() { return YRes; } /** * @brief getSubX Get the starting left coordinates (X) of the frame. * @return the starting left coordinates (X) of the image. */ inline int getSubX() { return SubX; } /** * @brief getSubY Get the starting top coordinates (Y) of the frame. * @return the starting top coordinates (Y) of the image. */ inline int getSubY() { return SubY; } /** * @brief getSubW Get the width of the frame * @return unbinned width of the frame */ inline int getSubW() { return SubW; } /** * @brief getSubH Get the height of the frame * @return unbinned height of the frame */ inline int getSubH() { return SubH; } /** * @brief getBinX Get horizontal binning of the CCD chip. * @return horizontal binning of the CCD chip. */ inline int getBinX() { return BinX; } /** * @brief getBinY Get vertical binning of the CCD chip. * @return vertical binning of the CCD chip. */ inline int getBinY() { return BinY; } /** * @brief getPixelSizeX Get horizontal pixel size in microns. * @return horizontal pixel size in microns. */ inline float getPixelSizeX() { return PixelSizex; } /** * @brief getPixelSizeY Get vertical pixel size in microns. * @return vertical pixel size in microns. */ inline float getPixelSizeY() { return PixelSizey; } /** * @brief getBPP Get CCD Chip depth (bits per pixel). * @return bits per pixel. */ inline int getBPP() { return BPP; } /** * @brief getFrameBufferSize Get allocated frame buffer size to hold the CCD image frame. * @return allocated frame buffer size to hold the CCD image frame. */ inline int getFrameBufferSize() { return RawFrameSize; } /** * @brief getExposureLeft Get exposure time left in seconds. * @return exposure time left in seconds. */ inline double getExposureLeft() { return ImageExposureN[0].value; } /** * @brief getExposureDuration Get requested exposure duration for the CCD chip in seconds. * @return requested exposure duration for the CCD chip in seconds. */ inline double getExposureDuration() { return exposureDuration; } /** * @brief getExposureStartTime * @return exposure start time in ISO 8601 format. */ const char *getExposureStartTime(); /** * @brief getFrameBuffer Get raw frame buffer of the CCD chip. * @return raw frame buffer of the CCD chip. */ inline char *getFrameBuffer() { return RawFrame; } /** * @brief isCompressed * @return True if frame is compressed, false otherwise. */ inline bool isCompressed() { return SendCompressed; } /** * @brief isInterlaced * @return True if CCD chip is Interlaced, false otherwise. */ inline bool isInterlaced() { return Interlaced; } /** * @brief getFrameType * @return CCD Frame type */ inline CCD_FRAME getFrameType() { return FrameType; } /** * @brief getFrameTypeName returns CCD Frame type name * @param fType type of frame * @return CCD Frame type name */ const char *getFrameTypeName(CCD_FRAME fType); /** * @brief setResolutoin set CCD Chip resolution * @param x width * @param y height */ void setResolutoin(int x, int y); /** * @brief setFrame Set desired frame resolutoin for an exposure. * @param subx Left position. * @param suby Top position. * @param subw unbinned width of the frame. * @param subh unbinned height of the frame. */ void setFrame(int subx, int suby, int subw, int subh); /** * @brief setBin Set CCD Chip binnig * @param hor Horizontal binning. * @param ver Vertical binning. */ void setBin(int hor, int ver); /** * @brief setPixelSize Set CCD Chip pixel size * @param x Horziontal pixel size in microns. * @param y Vertical pixel size in microns. */ void setPixelSize(float x, float y); /** * @brief setCompressed Set whether a frame is compressed after exposure? * @param cmp If true, compress frame. */ void setCompressed (bool cmp); /** * @brief setInterlaced Set whether the CCD chip is interlaced or not? * @param intr If true, the CCD chip is interlaced. */ void setInterlaced(bool intr); /** * @brief setFrameBufferSize Set desired frame buffer size. The function will allocate memory accordingly. The frame size depends on the * desired frame resolution (Left, Top, Width, Height), depth of the CCD chip (bpp), and binning settings. You must set the frame size any time * any of the prior parameters gets updated. * @param nbuf size of buffer in bytes. */ void setFrameBufferSize(int nbuf); /** * @brief setBPP Set depth of CCD chip. * @param bpp bits per pixel */ void setBPP(int bpp); /** * @brief setFrameType Set desired frame type for next exposure. * @param type desired CCD frame type. */ void setFrameType(CCD_FRAME type); /** * @brief setExposureDuration Set desired CCD frame exposure duration for next exposure. You must call this function immediately before * starting the actual exposure as it is used to calculate the timestamp used for the FITS header. * @param duration exposure duration in seconds. */ void setExposureDuration(double duration); /** * @brief setExposureLeft Update exposure time left. Inform the client of the new exposure time left value. * @param duration exposure duration left in seconds. */ void setExposureLeft(double duration); /** * @brief setExposureFailed Alert the client that the exposure failed. */ void setExposureFailed(); private: int XRes; // native resolution of the ccd int YRes; // ditto int SubX; // left side of the subframe we are requesting int SubY; // top of the subframe requested int SubW; // UNBINNED width of the subframe int SubH; // UNBINNED height of the subframe int BinX; // Binning requested in the x direction int BinY; // Binning requested in the Y direction float PixelSizex; // pixel size in microns, x direction float PixelSizey; // pixel size in microns, y direction int BPP; // Bytes per Pixel bool Interlaced; char *RawFrame; int RawFrameSize; bool SendCompressed; CCD_FRAME FrameType; double exposureDuration; timeval startExposureTime; INumberVectorProperty *ImageExposureNP; INumber ImageExposureN[1]; ISwitchVectorProperty *AbortExposureSP; ISwitch AbortExposureS[1]; INumberVectorProperty *ImageFrameNP; INumber ImageFrameN[4]; INumberVectorProperty *ImageBinNP; INumber ImageBinN[2]; INumberVectorProperty *ImagePixelSizeNP; INumber ImagePixelSizeN[6]; ISwitch FrameTypeS[4]; ISwitchVectorProperty *FrameTypeSP; ISwitch CompressS[2]; ISwitchVectorProperty *CompressSP; IBLOB FitsB; IBLOBVectorProperty *FitsBP; friend class INDI::CCD; }; /** * \class INDI::CCD \brief Class to provide general functionality of CCD cameras with a single CCD sensor, or a primary CCD sensor in addition to a secondary CCD guide head. It also implements the interface to perform guiding. The class enable the ability to \e snoop on telescope equatorial coordinates and record them in the FITS file before upload. Developers need to subclass INDI::CCD to implement any driver for CCD cameras within INDI. \author Gerry Rozema, Jasem Mutlaq */ class INDI::CCD : public INDI::DefaultDevice, INDI::GuiderInterface { public: CCD(); virtual ~CCD(); virtual bool initProperties(); virtual bool updateProperties(); virtual void ISGetProperties (const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISSnoopDevice (XMLEle *root); protected: /** \brief Start exposing primary CCD chip \param duration Duration in seconds \return 0 if OK and exposure will take some time to complete, 1 if exposure is short and complete already (e.g. bias), -1 on error. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual int StartExposure(float duration); /** \brief Uploads target Chip exposed buffer as FITS to the client. Dervied classes should class this function when an exposure is complete. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual bool ExposureComplete(CCDChip *targetChip); /** \brief Abort ongoing exposure \return true is abort is successful, false otherwise. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual bool AbortExposure(); /** \brief Start exposing guide CCD chip \param duration Duration in seconds \return 0 if OK and exposure will take some time to complete, 1 if exposure is short and complete already (e.g. bias), -1 on error. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual int StartGuideExposure(float duration); /** \brief Abort ongoing exposure \return true is abort is successful, false otherwise. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual bool AbortGuideExposure(); /** \brief INDI::CCD calls this function when CCD Frame dimension needs to be updated in the hardware. Derived classes should implement this function \param x Subframe X coordinate in pixels. \param y Subframe Y coordinate in pixels. \param w Subframe width in pixels. \param h Subframe height in pixels. \note (0,0) is defined as most left, top pixel in the subframe. \return true is CCD chip update is successful, false otherwise. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual bool updateCCDFrame(int x, int y, int w, int h); /** \brief INDI::CCD calls this function when Guide head frame dimension is updated by the client. Derived classes should implement this function \param x Subframe X coordinate in pixels. \param y Subframe Y coordinate in pixels. \param w Subframe width in pixels. \param h Subframe height in pixels. \note (0,0) is defined as most left, top pixel in the subframe. \return true is CCD chip update is successful, false otherwise. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual bool updateGuideFrame(int x, int y, int w, int h); /** \brief INDI::CCD calls this function when CCD Binning needs to be updated in the hardware. Derived classes should implement this function \param hor Horizontal binning. \param ver Vertical binning. \return true is CCD chip update is successful, false otherwise. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual bool updateCCDBin(int hor, int ver); /** \brief INDI::CCD calls this function when Guide head binning is updated by the client. Derived classes should implement this function \param hor Horizontal binning. \param ver Vertical binning. \return true is CCD chip update is successful, false otherwise. \note This function is not implemented in INDI::CCD, it must be implemented in the child class */ virtual bool updateGuideBin(int hor, int ver); /** \brief INDI::CCD calls this function when CCD frame type needs to be updated in the hardware. \param fType Frame type \return true is CCD chip update is successful, false otherwise. \note It is \e not mandotary to implement this function in the child class. The CCD hardware layer may either set the frame type when this function is called, or (optionally) before an exposure is started. */ virtual bool updateCCDFrameType(CCDChip::CCD_FRAME fType); /** \brief INDI::CCD calls this function when Guide frame type is updated by the client. \param fType Frame type \return true is CCD chip update is successful, false otherwise. \note It is \e not mandotary to implement this function in the child class. The CCD hardware layer may either set the frame type when this function is called, or (optionally) before an exposure is started. */ virtual bool updateGuideFrameType(CCDChip::CCD_FRAME fType); /** \brief Setup CCD paramters for primary CCD. Child classes call this function to update CCD paramaters \param x Frame X coordinates in pixels. \param y Frame Y coordinates in pixels. \param bpp Bits Per Pixels. \param xf X pixel size in microns. \param yf Y pixel size in microns. */ virtual void SetCCDParams(int x,int y,int bpp,float xf,float yf); /** \brief Setup CCD paramters for guide head CCD. Child classes call this function to update CCD paramaters \param x Frame X coordinates in pixels. \param y Frame Y coordinates in pixels. \param bpp Bits Per Pixels. \param xf X pixel size in microns. \param yf Y pixel size in microns. */ virtual void SetGuideHeadParams(int x,int y,int bpp,float xf,float yf); /** \brief Guide northward for ms milliseconds \param ms Duration in milliseconds. \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return True if successful, false otherwise. */ virtual bool GuideNorth(float ms); /** \brief Guide southward for ms milliseconds \param ms Duration in milliseconds. \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return 0 if successful, -1 otherwise. */ virtual bool GuideSouth(float ms); /** \brief Guide easward for ms milliseconds \param ms Duration in milliseconds. \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return 0 if successful, -1 otherwise. */ virtual bool GuideEast(float ms); /** \brief Guide westward for ms milliseconds \param ms Duration in milliseconds. \note This function is not implemented in INDI::CCD, it must be implemented in the child class \return 0 if successful, -1 otherwise. */ virtual bool GuideWest(float ms); /** \brief Add FITS keywords to a fits file \param fptr pointer to a valid FITS file. \param targetChip The target chip to extract the keywords from. \note In additional to the standard FITS keywords, this function write the following keywords the FITS file:
  • EXPTIME: Total Exposure Time (s)
  • DARKTIME (if applicable): Total Exposure Time (s)
  • PIXSIZE1: Pixel Size 1 (microns)
  • PIXSIZE2: Pixel Size 2 (microns)
  • BINNING: Binning HOR x VER
  • FRAME: Frame Type
  • DATAMIN: Minimum value
  • DATAMAX: Maximum value
  • INSTRUME: CCD Name
  • DATE-OBS: UTC start date of observation
To add additional information, override this function in the child class and ensure to call INDI::CCD::addFITSKeywords. */ virtual void addFITSKeywords(fitsfile *fptr, CCDChip *targetChip); /* A function to just remove GCC warnings about deprecated conversion */ void fits_update_key_s(fitsfile* fptr, int type, std::string name, void* p, std::string explanation, int* status); /** * @brief activeDevicesUpdated Inform children that ActiveDevices property was updated so they can snoop on the updated devices if desired. */ virtual void activeDevicesUpdated() {} virtual bool saveConfigItems(FILE *fp); float RA; float Dec; bool HasGuideHead; bool HasSt4Port; bool InExposure; bool InGuideExposure; CCDChip PrimaryCCD; CCDChip GuideCCD; // We are going to snoop these from a telescope INumberVectorProperty EqNP; INumber EqN[2]; ITextVectorProperty *ActiveDeviceTP; IText ActiveDeviceT[2]; private: void getMinMax(double *min, double *max, CCDChip *targetChip); }; #endif // INDI:CCD_H libindi-0.9.7/libs/indibase/baseclient.h0000644000175000017500000001740212241463551017121 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDIBASECLIENT_H #define INDIBASECLIENT_H #include #include #include #include "indiapi.h" #include "indidevapi.h" #include "indibase.h" #define MAXRBUF 2048 using namespace std; /** * \class INDI::BaseClient \brief Class to provide basic client functionality. BaseClient enables accelerated development of INDI Clients by providing a framework that facilitates communication, device handling, and event notification. By subclassing BaseClient, clients can quickly connect to an INDI server, and query for a set of INDI::BaseDevice devices, and read and write properties seamlessly. Event driven programming is possible due to notifications upon reception of new devices or properties. \attention All notifications functions defined in INDI::BaseMediator must be implemented in the client class even if they are not used because these are pure virtual functions. \see INDI Client Tutorial for more details. \author Jasem Mutlaq */ class INDI::BaseClient : public INDI::BaseMediator { public: enum { INDI_DEVICE_NOT_FOUND=-1, INDI_PROPERTY_INVALID=-2, INDI_PROPERTY_DUPLICATED = -3, INDI_DISPATCH_ERROR=-4 }; //typedef boost::shared_ptr devicePtr; BaseClient(); virtual ~BaseClient(); /** \brief Set the server host name and port \param hostname INDI server host name or IP address. \param port INDI server port. */ void setServer(const char * hostname, unsigned int port); /** \brief Add a device to the watch list. A client may select to receive notifications of only a specific device or a set of devices. If the client encounters any of the devices set via this function, it will create a corresponding INDI::BaseDevice object to handle them. If no devices are watched, then all devices owned by INDI server will be created and handled. */ void watchDevice(const char * deviceName); /** \brief Connect to INDI server. \returns True if the connection is successful, false otherwise. \note This function blocks until connection is either successull or unsuccessful. */ bool connectServer(); /** \brief Disconnect from INDI server. Disconnects from INDI servers. Any devices previously created will be deleted and memory cleared. \return True if disconnection is successful, false otherwise. */ bool disconnectServer(); /** \brief Connect to INDI driver \param deviceName Name of the device to connect to. */ void connectDevice(const char *deviceName); /** \brief Disconnect INDI driver \param deviceName Name of the device to disconnect. */ void disconnectDevice(const char *deviceName); /** \param deviceName Name of device to search for in the list of devices owned by INDI server, \returns If \e deviceName exists, it returns an instance of the device. Otherwise, it returns NULL. */ INDI::BaseDevice * getDevice(const char * deviceName); /** \returns Returns a vector of all devices created in the client. */ const vector & getDevices() const { return cDevices; } /** \brief Set Binary Large Object policy mode Set the BLOB handling mode for the client. The client may either receive:
  • Only BLOBS
  • BLOBs mixed with normal messages
  • Normal messages only, no BLOBs
If \e dev and \e prop are supplied, then the BLOB handling policy is set for this particular device and property. if \e prop is NULL, then the BLOB policy applies to the whole device. \param blobH BLOB handling policy \param dev name of device, required. \param prop name of property, optional. */ void setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop = NULL); // Update static void * listenHelper(void *context); const char * getHost() { return cServer.c_str();} int getPort() { return cPort; } /** \brief Send new Text command to server */ void sendNewText (ITextVectorProperty *pp); /** \brief Send new Text command to server */ void sendNewText (const char * deviceName, const char * propertyName, const char* elementName, const char *text); /** \brief Send new Number command to server */ void sendNewNumber (INumberVectorProperty *pp); /** \brief Send new Number command to server */ void sendNewNumber (const char * deviceName, const char *propertyName, const char* elementName, double value); /** \brief Send new Switch command to server */ void sendNewSwitch (ISwitchVectorProperty *pp); /** \brief Send new Switch command to server */ void sendNewSwitch (const char * deviceName, const char *propertyName, const char *elementName); /** \brief Send opening tag for BLOB command to server */ void startBlob( const char *devName, const char *propName, const char *timestamp); /** \brief Send ONE blob content to server */ void sendOneBlob( const char *blobName, unsigned int blobSize, const char *blobFormat, void * blobBuffer); /** \brief Send closing tag for BLOB command to server */ void finishBlob(); protected: /** \brief Dispatch command received from INDI server to respective devices handled by the client */ int dispatchCommand(XMLEle *root, char* errmsg); /** \brief Remove device */ int removeDevice( const char * devName, char * errmsg ); /** \brief Delete property command */ int delPropertyCmd (XMLEle *root, char * errmsg); /** \brief Find and return a particular device */ INDI::BaseDevice * findDev( const char * devName, char * errmsg); /** \brief Add a new device */ INDI::BaseDevice * addDevice (XMLEle *dep, char * errmsg); /** \brief Find a device, and if it doesn't exist, create it if create is set to 1 */ INDI::BaseDevice * findDev (XMLEle *root, int create, char * errmsg); /** Process messages */ int messageCmd (XMLEle *root, char * errmsg); private: /** \brief Connect/Disconnect to INDI driver \param status If true, the client will attempt to turn on CONNECTION property within the driver (i.e. turn on the device). Otherwise, CONNECTION will be turned off. \param deviceName Name of the device to connect to. */ void setDriverConnection(bool status, const char *deviceName); // Listen to INDI server and process incoming messages void listenINDI(); // Thread for listenINDI() pthread_t listen_thread; vector cDevices; vector cDeviceNames; string cServer; unsigned int cPort; bool sConnected; // Parse & FILE buffers for IO int sockfd; LilXML *lillp; /* XML parser context */ FILE *svrwfp; /* FILE * to talk to server */ int m_receiveFd; int m_sendFd; }; #endif // INDIBASECLIENT_H libindi-0.9.7/libs/indibase/indifilterinterface.cpp0000644000175000017500000000624512241463551021360 0ustar jasemjasem/* Filter Interface Copyright (C) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include #include "indifilterinterface.h" #include "indilogger.h" INDI::FilterInterface::FilterInterface() { FilterNameTP = new ITextVectorProperty; FilterNameT = NULL; } void INDI::FilterInterface::initFilterProperties(const char *deviceName, const char* groupName) { IUFillNumber(&FilterSlotN[0],"FILTER_SLOT_VALUE","Filter","%3.0f",1.0,12.0,1.0,1.0); IUFillNumberVector(&FilterSlotNP,FilterSlotN,1,deviceName,"FILTER_SLOT","Filter",groupName,IP_RW,60,IPS_IDLE); } INDI::FilterInterface::~FilterInterface() { delete FilterNameTP; } void INDI::FilterInterface::SelectFilterDone(int f) { // The hardware has finished changing // filters FilterSlotN[0].value=f; FilterSlotNP.s=IPS_OK; // Tell the clients we are done, and // filter is now useable IDSetNumber(&FilterSlotNP,NULL); } void INDI::FilterInterface::processFilterSlot(const char *deviceName, double values[], char *names[]) { TargetFilter = values[0]; INumber *np = IUFindNumber(&FilterSlotNP, names[0]); if (!np) { FilterSlotNP.s = IPS_ALERT; DEBUGFDEVICE(deviceName, Logger::DBG_ERROR, "Unknown error. %s is not a member of %s property.", names[0], FilterSlotNP.name); IDSetNumber(&FilterSlotNP, NULL); return; } if (TargetFilter < FilterSlotN[0].min || TargetFilter > FilterSlotN[0].max) { FilterSlotNP.s = IPS_ALERT; DEBUGFDEVICE(deviceName, Logger::DBG_ERROR, "Error: valid range of filter is from %g to %g", FilterSlotN[0].min, FilterSlotN[0].max); IDSetNumber(&FilterSlotNP, NULL); return; } FilterSlotNP.s = IPS_BUSY; DEBUGFDEVICE(deviceName, Logger::DBG_SESSION, "Setting current filter to slot %d", TargetFilter); IDSetNumber(&FilterSlotNP, NULL); SelectFilter(TargetFilter); return; } void INDI::FilterInterface::processFilterName(const char *deviceName, char *texts[], char *names[], int n) { int rc; FilterNameTP->s=IPS_OK; rc=IUUpdateText(FilterNameTP,texts,names,n); if (SetFilterNames() == true) IDSetText(FilterNameTP,NULL); else { FilterNameTP->s = IPS_ALERT; DEBUGDEVICE(deviceName, Logger::DBG_ERROR, "Error updating names of filters."); IDSetText(FilterNameTP, NULL); } } libindi-0.9.7/libs/indibase/indiccd.cpp0000644000175000017500000010402012241463551016731 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010, 2011 Gerry Rozema, Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "indiccd.h" #include #include #include #include #include const char *IMAGE_SETTINGS_TAB = "Image Settings"; const char *IMAGE_INFO_TAB = "Image Info"; const char *GUIDE_HEAD_TAB = "Guide Head"; const char *GUIDE_CONTROL_TAB = "Guider Control"; CCDChip::CCDChip() { SendCompressed=false; Interlaced=false; RawFrame=NULL; RawFrameSize=0; BinX = BinY = 1; FrameType=LIGHT_FRAME; ImageFrameNP = new INumberVectorProperty; AbortExposureSP = new ISwitchVectorProperty; FrameTypeSP = new ISwitchVectorProperty; ImageExposureNP = new INumberVectorProperty; ImageBinNP = new INumberVectorProperty; ImagePixelSizeNP = new INumberVectorProperty; CompressSP = new ISwitchVectorProperty; FitsBP = new IBLOBVectorProperty; } CCDChip::~CCDChip() { delete RawFrame; RawFrameSize=0; RawFrame=NULL; delete ImageFrameNP; delete AbortExposureSP; delete FrameTypeSP; delete ImageExposureNP; delete ImageBinNP; delete ImagePixelSizeNP; delete CompressSP; delete FitsBP; } void CCDChip::setFrameType(CCD_FRAME type) { FrameType=type; } void CCDChip::setResolutoin(int x, int y) { XRes = x; YRes = y; ImagePixelSizeN[0].value=x; ImagePixelSizeN[1].value=y; IDSetNumber(ImagePixelSizeNP, NULL); ImageFrameN[FRAME_X].min = 0; ImageFrameN[FRAME_X].max = x-1; ImageFrameN[FRAME_Y].min = 0; ImageFrameN[FRAME_Y].max = y-1; ImageFrameN[FRAME_W].min = 1; ImageFrameN[FRAME_W].max = x; ImageFrameN[FRAME_H].max = 1; ImageFrameN[FRAME_H].max = y; IUUpdateMinMax(ImageFrameNP); } void CCDChip::setFrame(int subx, int suby, int subw, int subh) { SubX = subx; SubY = suby; SubW = subw; SubH = subh; ImageFrameN[FRAME_X].value = SubX; ImageFrameN[FRAME_Y].value = SubY; ImageFrameN[FRAME_W].value = SubW; ImageFrameN[FRAME_H].value = SubH; IDSetNumber(ImageFrameNP, NULL); } void CCDChip::setBin(int hor, int ver) { BinX = hor; BinY = ver; ImageBinN[BIN_W].value = BinX; ImageBinN[BIN_H].value = BinY; IDSetNumber(ImageBinNP, NULL); } void CCDChip::setPixelSize(float x, float y) { PixelSizex = x; PixelSizey = y; ImagePixelSizeN[2].value=x; ImagePixelSizeN[3].value=x; ImagePixelSizeN[4].value=y; IDSetNumber(ImagePixelSizeNP, NULL); } void CCDChip::setBPP(int bbp) { BPP = bbp; ImagePixelSizeN[5].value = BPP; IDSetNumber(ImagePixelSizeNP, NULL); } void CCDChip::setFrameBufferSize(int nbuf) { if (nbuf == RawFrameSize) return; if (RawFrame != NULL) delete RawFrame; RawFrameSize = nbuf; RawFrame = new char[nbuf]; } void CCDChip::setExposureLeft(double duration) { ImageExposureN[0].value = duration; IDSetNumber(ImageExposureNP, NULL); } void CCDChip::setExposureDuration(double duration) { exposureDuration = duration; gettimeofday(&startExposureTime,NULL); } const char *CCDChip::getFrameTypeName(CCD_FRAME fType) { return FrameTypeS[fType].name; } const char * CCDChip::getExposureStartTime() { static char ts[32]; struct tm *tp; time_t t = (time_t) startExposureTime.tv_sec; //time (&t); tp = gmtime (&t); strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp); return (ts); } void CCDChip::setInterlaced(bool intr) { Interlaced = intr; } void CCDChip::setExposureFailed() { ImageExposureNP->s = IPS_ALERT; IDSetNumber(ImageExposureNP, NULL); } INDI::CCD::CCD() { //ctor HasGuideHead=false; HasSt4Port=false; InExposure=false; InGuideExposure=false; RA=0.0; Dec=90.0; ActiveDeviceTP = new ITextVectorProperty; } INDI::CCD::~CCD() { delete ActiveDeviceTP; } bool INDI::CCD::initProperties() { DefaultDevice::initProperties(); // let the base class flesh in what it wants // PRIMARY CCD Init IUFillNumber(&PrimaryCCD.ImageFrameN[0],"X","Left ","%4.0f",0,1392.0,0,0); IUFillNumber(&PrimaryCCD.ImageFrameN[1],"Y","Top","%4.0f",0,1040,0,0); IUFillNumber(&PrimaryCCD.ImageFrameN[2],"WIDTH","Width","%4.0f",0,1392.0,0,1392.0); IUFillNumber(&PrimaryCCD.ImageFrameN[3],"HEIGHT","Height","%4.0f",0,1392,0,1392.0); IUFillNumberVector(PrimaryCCD.ImageFrameNP,PrimaryCCD.ImageFrameN,4,getDeviceName(),"CCD_FRAME","Frame",IMAGE_SETTINGS_TAB,IP_RW,60,IPS_IDLE); IUFillSwitch(&PrimaryCCD.FrameTypeS[0],"FRAME_LIGHT","Light",ISS_ON); IUFillSwitch(&PrimaryCCD.FrameTypeS[1],"FRAME_BIAS","Bias",ISS_OFF); IUFillSwitch(&PrimaryCCD.FrameTypeS[2],"FRAME_DARK","Dark",ISS_OFF); IUFillSwitch(&PrimaryCCD.FrameTypeS[3],"FRAME_FLAT","Flat",ISS_OFF); IUFillSwitchVector(PrimaryCCD.FrameTypeSP,PrimaryCCD.FrameTypeS,4,getDeviceName(),"CCD_FRAME_TYPE","FrameType",IMAGE_SETTINGS_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillNumber(&PrimaryCCD.ImageExposureN[0],"CCD_EXPOSURE_VALUE","Duration (s)","%5.2f",0,36000,0,1.0); IUFillNumberVector(PrimaryCCD.ImageExposureNP,PrimaryCCD.ImageExposureN,1,getDeviceName(),"CCD_EXPOSURE","Expose",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE); IUFillSwitch(&PrimaryCCD.AbortExposureS[0],"ABORT","Abort",ISS_OFF); IUFillSwitchVector(PrimaryCCD.AbortExposureSP,PrimaryCCD.AbortExposureS,1,getDeviceName(),"CCD_ABORT_EXPOSURE","Expose Abort",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillNumber(&PrimaryCCD.ImageBinN[0],"HOR_BIN","X","%2.0f",1,4,1,1); IUFillNumber(&PrimaryCCD.ImageBinN[1],"VER_BIN","Y","%2.0f",1,4,1,1); IUFillNumberVector(PrimaryCCD.ImageBinNP,PrimaryCCD.ImageBinN,2,getDeviceName(),"CCD_BINNING","Binning",IMAGE_SETTINGS_TAB,IP_RW,60,IPS_IDLE); IUFillNumber(&PrimaryCCD.ImagePixelSizeN[0],"CCD_MAX_X","Resolution x","%4.0f",1,40,0,6.45); IUFillNumber(&PrimaryCCD.ImagePixelSizeN[1],"CCD_MAX_Y","Resolution y","%4.0f",1,40,0,6.45); IUFillNumber(&PrimaryCCD.ImagePixelSizeN[2],"CCD_PIXEL_SIZE","Pixel size (um)","%5.2f",1,40,0,6.45); IUFillNumber(&PrimaryCCD.ImagePixelSizeN[3],"CCD_PIXEL_SIZE_X","Pixel size X","%5.2f",1,40,0,6.45); IUFillNumber(&PrimaryCCD.ImagePixelSizeN[4],"CCD_PIXEL_SIZE_Y","Pixel size Y","%5.2f",1,40,0,6.45); IUFillNumber(&PrimaryCCD.ImagePixelSizeN[5],"CCD_BITSPERPIXEL","Bits per pixel","%3.0f",1,40,0,6.45); IUFillNumberVector(PrimaryCCD.ImagePixelSizeNP,PrimaryCCD.ImagePixelSizeN,6,getDeviceName(),"CCD_INFO","CCD Information",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE); IUFillSwitch(&PrimaryCCD.CompressS[0],"COMPRESS","Compress",ISS_ON); IUFillSwitch(&PrimaryCCD.CompressS[1],"RAW","Raw",ISS_OFF); IUFillSwitchVector(PrimaryCCD.CompressSP,PrimaryCCD.CompressS,2,getDeviceName(),"CCD_COMPRESSION","Image",IMAGE_SETTINGS_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillBLOB(&PrimaryCCD.FitsB,"CCD1","Image",""); IUFillBLOBVector(PrimaryCCD.FitsBP,&PrimaryCCD.FitsB,1,getDeviceName(),"CCD1","Image Data",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE); // GUIDER CCD Init IUFillNumber(&GuideCCD.ImageFrameN[0],"X","Left ","%4.0f",0,1392.0,0,0); IUFillNumber(&GuideCCD.ImageFrameN[1],"Y","Top","%4.0f",0,1040,0,0); IUFillNumber(&GuideCCD.ImageFrameN[2],"WIDTH","Width","%4.0f",0,1392.0,0,1392.0); IUFillNumber(&GuideCCD.ImageFrameN[3],"HEIGHT","Height","%4.0f",0,1040,0,1040); IUFillNumberVector(GuideCCD.ImageFrameNP,GuideCCD.ImageFrameN,4,getDeviceName(),"GUIDER_FRAME","Frame",GUIDE_HEAD_TAB,IP_RW,60,IPS_IDLE); IUFillNumber(&GuideCCD.ImageBinN[0],"HOR_BIN","X","%2.0f",1,4,1,1); IUFillNumber(&GuideCCD.ImageBinN[1],"VER_BIN","Y","%2.0f",1,4,1,1); IUFillNumberVector(GuideCCD.ImageBinNP,GuideCCD.ImageBinN,2,getDeviceName(),"GUIDE_BINNING","Binning",GUIDE_HEAD_TAB,IP_RW,60,IPS_IDLE); IUFillNumber(&GuideCCD.ImagePixelSizeN[0],"CCD_MAX_X","Resolution x","%4.0f",1,40,0,6.45); IUFillNumber(&GuideCCD.ImagePixelSizeN[1],"CCD_MAX_Y","Resolution y","%4.0f",1,40,0,6.45); IUFillNumber(&GuideCCD.ImagePixelSizeN[2],"CCD_PIXEL_SIZE","Pixel size (um)","%5.2f",1,40,0,6.45); IUFillNumber(&GuideCCD.ImagePixelSizeN[3],"CCD_PIXEL_SIZE_X","Pixel size X","%5.2f",1,40,0,6.45); IUFillNumber(&GuideCCD.ImagePixelSizeN[4],"CCD_PIXEL_SIZE_Y","Pixel size Y","%5.2f",1,40,0,6.45); IUFillNumber(&GuideCCD.ImagePixelSizeN[5],"CCD_BITSPERPIXEL","Bits per pixel","%3.0f",1,40,0,6.45); IUFillNumberVector(GuideCCD.ImagePixelSizeNP,GuideCCD.ImagePixelSizeN,6,getDeviceName(),"GUIDER_INFO", "Guide Info",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE); IUFillSwitch(&GuideCCD.FrameTypeS[0],"FRAME_LIGHT","Light",ISS_ON); IUFillSwitch(&GuideCCD.FrameTypeS[1],"FRAME_BIAS","Bias",ISS_OFF); IUFillSwitch(&GuideCCD.FrameTypeS[2],"FRAME_DARK","Dark",ISS_OFF); IUFillSwitch(&GuideCCD.FrameTypeS[3],"FRAME_FLAT","Flat",ISS_OFF); IUFillSwitchVector(GuideCCD.FrameTypeSP,GuideCCD.FrameTypeS,4,getDeviceName(),"GUIDE_FRAME_TYPE","FrameType",GUIDE_HEAD_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillNumber(&GuideCCD.ImageExposureN[0],"GUIDER_EXPOSURE_VALUE","Duration (s)","%5.2f",0,36000,0,1.0); IUFillNumberVector(GuideCCD.ImageExposureNP,GuideCCD.ImageExposureN,1,getDeviceName(),"GUIDER_EXPOSURE","Guide Head",MAIN_CONTROL_TAB,IP_RW,60,IPS_IDLE); IUFillSwitch(&GuideCCD.AbortExposureS[0],"ABORT","Abort",ISS_OFF); IUFillSwitchVector(GuideCCD.AbortExposureSP,GuideCCD.AbortExposureS,1,getDeviceName(),"GUIDER_ABORT_EXPOSURE","Guide Abort",MAIN_CONTROL_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillSwitch(&GuideCCD.CompressS[0],"GCOMPRESS","Compress",ISS_ON); IUFillSwitch(&GuideCCD.CompressS[1],"GRAW","Raw",ISS_OFF); IUFillSwitchVector(GuideCCD.CompressSP,GuideCCD.CompressS,2,getDeviceName(),"GUIDER_COMPRESSION","Image",GUIDE_HEAD_TAB,IP_RW,ISR_1OFMANY,60,IPS_IDLE); IUFillBLOB(&GuideCCD.FitsB,"CCD2","Guider Image",""); IUFillBLOBVector(GuideCCD.FitsBP,&GuideCCD.FitsB,1,getDeviceName(),"CCD2","Image Data",IMAGE_INFO_TAB,IP_RO,60,IPS_IDLE); // CCD Class Init IUFillText(&ActiveDeviceT[0],"ACTIVE_TELESCOPE","Telescope","Telescope Simulator"); IUFillText(&ActiveDeviceT[1],"ACTIVE_FOCUSER","Focuser","Focuser Simulator"); IUFillTextVector(ActiveDeviceTP,ActiveDeviceT,2,getDeviceName(),"ACTIVE_DEVICES","Snoop devices",OPTIONS_TAB,IP_RW,60,IPS_IDLE); IUFillNumber(&EqN[0],"RA","Ra (hh:mm:ss)","%010.6m",0,24,0,0); IUFillNumber(&EqN[1],"DEC","Dec (dd:mm:ss)","%010.6m",-90,90,0,0); IUFillNumberVector(&EqNP,EqN,2,ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD","EQ Coord","Main Control",IP_RW,60,IPS_IDLE); IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD"); // Guider Interface initGuiderProperties(getDeviceName(), GUIDE_CONTROL_TAB); return true; } void INDI::CCD::ISGetProperties (const char *dev) { // First we let our parent populate //IDLog("INDI::CCD IsGetProperties with %s\n",dev); DefaultDevice::ISGetProperties(dev); return; } bool INDI::CCD::updateProperties() { //IDLog("INDI::CCD UpdateProperties isConnected returns %d %d\n",isConnected(),Connected); if(isConnected()) { defineNumber(PrimaryCCD.ImageExposureNP); defineSwitch(PrimaryCCD.AbortExposureSP); defineNumber(PrimaryCCD.ImageFrameNP); defineNumber(PrimaryCCD.ImageBinNP); if(HasGuideHead) { // IDLog("Sending Guider Stuff\n"); defineNumber(GuideCCD.ImageExposureNP); defineSwitch(GuideCCD.AbortExposureSP); defineNumber(GuideCCD.ImageFrameNP); } defineNumber(PrimaryCCD.ImagePixelSizeNP); if(HasGuideHead) { defineNumber(GuideCCD.ImagePixelSizeNP); defineNumber(GuideCCD.ImageBinNP); } defineSwitch(PrimaryCCD.CompressSP); defineBLOB(PrimaryCCD.FitsBP); if(HasGuideHead) { defineSwitch(GuideCCD.CompressSP); defineBLOB(GuideCCD.FitsBP); } if(HasSt4Port) { defineNumber(&GuideNSNP); defineNumber(&GuideWENP); } defineSwitch(PrimaryCCD.FrameTypeSP); if (HasGuideHead) defineSwitch(GuideCCD.FrameTypeSP); defineText(ActiveDeviceTP); } else { deleteProperty(PrimaryCCD.ImageFrameNP->name); deleteProperty(PrimaryCCD.ImageBinNP->name); deleteProperty(PrimaryCCD.ImagePixelSizeNP->name); deleteProperty(PrimaryCCD.ImageExposureNP->name); deleteProperty(PrimaryCCD.AbortExposureSP->name); deleteProperty(PrimaryCCD.FitsBP->name); deleteProperty(PrimaryCCD.CompressSP->name); if(HasGuideHead) { deleteProperty(GuideCCD.ImageExposureNP->name); deleteProperty(GuideCCD.AbortExposureSP->name); deleteProperty(GuideCCD.ImageFrameNP->name); deleteProperty(GuideCCD.ImagePixelSizeNP->name); deleteProperty(GuideCCD.FitsBP->name); deleteProperty(GuideCCD.ImageBinNP->name); deleteProperty(GuideCCD.CompressSP->name); deleteProperty(GuideCCD.FrameTypeSP->name); } if(HasSt4Port) { deleteProperty(GuideNSNP.name); deleteProperty(GuideWENP.name); } deleteProperty(PrimaryCCD.FrameTypeSP->name); deleteProperty(ActiveDeviceTP->name); } return true; } bool INDI::CCD::ISSnoopDevice (XMLEle *root) { if(IUSnoopNumber(root,&EqNP)==0) { float newra,newdec; newra=EqN[0].value; newdec=EqN[1].value; if((newra != RA)||(newdec != Dec)) { //IDLog("RA %4.2f Dec %4.2f Snooped RA %4.2f Dec %4.2f\n",RA,Dec,newra,newdec); RA=newra; Dec=newdec; } } else { //fprintf(stderr,"Snoop Failed\n"); } return INDI::DefaultDevice::ISSnoopDevice(root); } bool INDI::CCD::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // first check if it's for our device if(strcmp(dev,getDeviceName())==0) { // This is for our device // Now lets see if it's something we process here if(strcmp(name,ActiveDeviceTP->name)==0) { int rc; ActiveDeviceTP->s=IPS_OK; rc=IUUpdateText(ActiveDeviceTP,texts,names,n); // Update client display IDSetText(ActiveDeviceTP,NULL); saveConfig(); // Update the property name! strncpy(EqNP.device, ActiveDeviceT[0].text, MAXINDIDEVICE); IDSnoopDevice(ActiveDeviceT[0].text,"EQUATORIAL_EOD_COORD"); // Tell children active devices was updated. activeDevicesUpdated(); // We processed this one, so, tell the world we did it return true; } } return INDI::DefaultDevice::ISNewText(dev,name,texts,names,n); } bool INDI::CCD::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // first check if it's for our device //IDLog("INDI::CCD::ISNewNumber %s\n",name); if(strcmp(dev,getDeviceName())==0) { // This is for our device // Now lets see if it's something we process here if(strcmp(name,"CCD_EXPOSURE")==0) { float n; int rc; n=values[0]; PrimaryCCD.ImageExposureN[0].value=n; if (PrimaryCCD.ImageExposureNP->s==IPS_BUSY) AbortExposure(); PrimaryCCD.ImageExposureNP->s=IPS_BUSY; // now we have a new number, this is our requested exposure time // Tell the clients we are busy with this exposure // And now call the physical hardware layer to start the exposure rc=StartExposure(n); switch(rc) { case 0: // normal case, exposure running on timers, callbacks when it's finished PrimaryCCD.ImageExposureNP->s=IPS_BUSY; break; case 1: // Short exposure, it's already done PrimaryCCD.ImageExposureNP->s=IPS_OK; break; case -1: // error condition PrimaryCCD.ImageExposureNP->s=IPS_ALERT; break; } IDSetNumber(PrimaryCCD.ImageExposureNP,NULL); return true; } if(strcmp(name,"GUIDER_EXPOSURE")==0) { float n; int rc; n=values[0]; GuideCCD.ImageExposureN[0].value=n; GuideCCD.ImageExposureNP->s=IPS_BUSY; // now we have a new number, this is our requested exposure time // Tell the clients we are busy with this exposure // And now call the physical hardware layer to start the exposure // change of plans, this is just changing exposure time // the start/stop stream buttons do the rest rc=StartGuideExposure(n); //rc=1; // set it to ok switch(rc) { case 0: // normal case, exposure running on timers, callbacks when it's finished GuideCCD.ImageExposureNP->s=IPS_BUSY; break; case 1: // Short exposure, it's already done GuideCCD.ImageExposureNP->s=IPS_OK; break; case -1: // error condition GuideCCD.ImageExposureNP->s=IPS_ALERT; break; } IDSetNumber(GuideCCD.ImageExposureNP,NULL); return true; } if(strcmp(name,"CCD_BINNING")==0) { // We are being asked to set camera binning PrimaryCCD.ImageBinNP->s=IPS_OK; IUUpdateNumber(PrimaryCCD.ImageBinNP,values,names,n); if (updateCCDBin(PrimaryCCD.ImageBinN[0].value, PrimaryCCD.ImageBinN[1].value) == false) { PrimaryCCD.ImageBinNP->s = IPS_ALERT; IDSetNumber (PrimaryCCD.ImageBinNP, NULL); } return true; } if(strcmp(name,"GUIDE_BINNING")==0) { // We are being asked to set camera binning GuideCCD.ImageBinNP->s=IPS_OK; IUUpdateNumber(GuideCCD.ImageBinNP,values,names,n); if (updateGuideBin(GuideCCD.ImageBinN[0].value, GuideCCD.ImageBinN[1].value) == false) { GuideCCD.ImageBinNP->s = IPS_ALERT; IDSetNumber (GuideCCD.ImageBinNP, NULL); } return true; } if(strcmp(name,"CCD_FRAME")==0) { // We are being asked to set camera binning PrimaryCCD.ImageFrameNP->s=IPS_OK; IUUpdateNumber(PrimaryCCD.ImageFrameNP,values,names,n); if (updateCCDFrame(PrimaryCCD.ImageFrameN[0].value, PrimaryCCD.ImageFrameN[1].value, PrimaryCCD.ImageFrameN[2].value, PrimaryCCD.ImageFrameN[3].value) == false) PrimaryCCD.ImageFrameNP->s = IPS_ALERT; IDSetNumber(PrimaryCCD.ImageFrameNP, NULL); return true; } if(strcmp(name,"GUIDER_FRAME")==0) { // We are being asked to set camera binning GuideCCD.ImageFrameNP->s=IPS_OK; IUUpdateNumber(GuideCCD.ImageFrameNP,values,names,n); DEBUGF(Logger::DBG_DEBUG, "GuiderFrame set to %4.0f,%4.0f %4.0f x %4.0f", GuideCCD.ImageFrameN[0].value,GuideCCD.ImageFrameN[1].value,GuideCCD.ImageFrameN[2].value,GuideCCD.ImageFrameN[3].value); if (updateGuideFrame(GuideCCD.ImageFrameN[0].value, GuideCCD.ImageFrameN[1].value, GuideCCD.ImageFrameN[2].value, GuideCCD.ImageFrameN[3].value) == false) GuideCCD.ImageFrameNP->s = IPS_ALERT; IDSetNumber(GuideCCD.ImageFrameNP, NULL); return true; } if (!strcmp(name,GuideNSNP.name) || !strcmp(name,GuideWENP.name)) { processGuiderProperties(name, values, names, n); return true; } } // if we didn't process it, continue up the chain, let somebody else // give it a shot return DefaultDevice::ISNewNumber(dev,name,values,names,n); } bool INDI::CCD::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if(strcmp(dev,getDeviceName())==0) { if(strcmp(name,PrimaryCCD.AbortExposureSP->name)==0) { IUResetSwitch(PrimaryCCD.AbortExposureSP); if (AbortExposure()) { PrimaryCCD.AbortExposureSP->s = IPS_OK; PrimaryCCD.ImageExposureNP->s = IPS_IDLE; PrimaryCCD.ImageExposureN[0].value = 0; } else { PrimaryCCD.AbortExposureSP->s = IPS_ALERT; PrimaryCCD.ImageExposureNP->s = IPS_ALERT; } IDSetSwitch(PrimaryCCD.AbortExposureSP, NULL); IDSetNumber(PrimaryCCD.ImageExposureNP, NULL); return true; } if(strcmp(name,GuideCCD.AbortExposureSP->name)==0) { IUResetSwitch(GuideCCD.AbortExposureSP); if (AbortGuideExposure()) { GuideCCD.AbortExposureSP->s = IPS_OK; GuideCCD.ImageExposureNP->s = IPS_IDLE; GuideCCD.ImageExposureN[0].value = 0; } else { GuideCCD.AbortExposureSP->s = IPS_ALERT; GuideCCD.ImageExposureNP->s = IPS_ALERT; } IDSetSwitch(GuideCCD.AbortExposureSP, NULL); IDSetNumber(GuideCCD.ImageExposureNP, NULL); return true; } if(strcmp(name,PrimaryCCD.CompressSP->name)==0) { IUUpdateSwitch(PrimaryCCD.CompressSP,states,names,n); IDSetSwitch(PrimaryCCD.CompressSP,NULL); if(PrimaryCCD.CompressS[0].s==ISS_ON ) { PrimaryCCD.SendCompressed=true; } else { PrimaryCCD.SendCompressed=false; } return true; } if(strcmp(name,GuideCCD.CompressSP->name)==0) { IUUpdateSwitch(GuideCCD.CompressSP,states,names,n); IDSetSwitch(GuideCCD.CompressSP,NULL); if(GuideCCD.CompressS[0].s==ISS_ON ) { GuideCCD.SendCompressed=true; } else { GuideCCD.SendCompressed=false; } return true; } if(strcmp(name,PrimaryCCD.FrameTypeSP->name)==0) { // Compression Update IUUpdateSwitch(PrimaryCCD.FrameTypeSP,states,names,n); PrimaryCCD.FrameTypeSP->s=IPS_OK; if(PrimaryCCD.FrameTypeS[0].s==ISS_ON) PrimaryCCD.setFrameType(CCDChip::LIGHT_FRAME); else if(PrimaryCCD.FrameTypeS[1].s==ISS_ON) PrimaryCCD.setFrameType(CCDChip::BIAS_FRAME); else if(PrimaryCCD.FrameTypeS[2].s==ISS_ON) PrimaryCCD.setFrameType(CCDChip::DARK_FRAME); else if(PrimaryCCD.FrameTypeS[3].s==ISS_ON) PrimaryCCD.setFrameType(CCDChip::FLAT_FRAME); if (updateCCDFrameType(PrimaryCCD.getFrameType()) == false) PrimaryCCD.FrameTypeSP->s = IPS_ALERT; IDSetSwitch(PrimaryCCD.FrameTypeSP,NULL); return true; } if(strcmp(name,GuideCCD.FrameTypeSP->name)==0) { // Compression Update IUUpdateSwitch(GuideCCD.FrameTypeSP,states,names,n); GuideCCD.FrameTypeSP->s=IPS_OK; if(GuideCCD.FrameTypeS[0].s==ISS_ON) GuideCCD.setFrameType(CCDChip::LIGHT_FRAME); else if(GuideCCD.FrameTypeS[1].s==ISS_ON) GuideCCD.setFrameType(CCDChip::BIAS_FRAME); else if(GuideCCD.FrameTypeS[2].s==ISS_ON) GuideCCD.setFrameType(CCDChip::DARK_FRAME); else if(GuideCCD.FrameTypeS[3].s==ISS_ON) GuideCCD.setFrameType(CCDChip::FLAT_FRAME); if (updateGuideFrameType(GuideCCD.getFrameType()) == false) GuideCCD.FrameTypeSP->s = IPS_ALERT; IDSetSwitch(GuideCCD.FrameTypeSP,NULL); return true; } } // let the default driver have a crack at it return DefaultDevice::ISNewSwitch(dev, name, states, names, n); } int INDI::CCD::StartExposure(float duration) { IDLog("INDI::CCD::StartExposure %4.2f - Should never get here\n",duration); return -1; } int INDI::CCD::StartGuideExposure(float duration) { IDLog("INDI::CCD::StartGuide Exposure %4.2f - Should never get here\n",duration); return -1; } bool INDI::CCD::AbortExposure() { IDLog("INDI::CCD::AbortExposure - Should never get here\n"); return false; } bool INDI::CCD::updateCCDFrame(int x, int y, int w, int h) { // Just set value, unless HW layer overrides this and performs its own processing PrimaryCCD.setFrame(x, y, w, h); return true; } bool INDI::CCD::updateGuideFrame(int x, int y, int w, int h) { GuideCCD.setFrame(x,y, w,h); return true; } bool INDI::CCD::updateCCDBin(int hor, int ver) { // Just set value, unless HW layer overrides this and performs its own processing PrimaryCCD.setBin(hor, ver); return true; } bool INDI::CCD::updateGuideBin(int hor, int ver) { // Just set value, unless HW layer overrides this and performs its own processing GuideCCD.setBin(hor, ver); return true; } bool INDI::CCD::updateCCDFrameType(CCDChip::CCD_FRAME fType) { INDI_UNUSED(fType); // Child classes can override this return true; } bool INDI::CCD::updateGuideFrameType(CCDChip::CCD_FRAME fType) { INDI_UNUSED(fType); // Child classes can override this return true; } void INDI::CCD::addFITSKeywords(fitsfile *fptr, CCDChip *targetChip) { int status=0; char frame_s[32]; char dev_name[32]; char exp_start[32]; double min_val, max_val; double exposureDuration; double pixSize1,pixSize2; unsigned int xbin, ybin; getMinMax(&min_val, &max_val, targetChip); xbin = targetChip->getBinX(); ybin = targetChip->getBinY(); switch (targetChip->getFrameType()) { case CCDChip::LIGHT_FRAME: strcpy(frame_s, "Light"); break; case CCDChip::BIAS_FRAME: strcpy(frame_s, "Bias"); break; case CCDChip::FLAT_FRAME: strcpy(frame_s, "Flat Field"); break; case CCDChip::DARK_FRAME: strcpy(frame_s, "Dark"); break; } exposureDuration = targetChip->getExposureDuration(); pixSize1 = targetChip->getPixelSizeX(); pixSize2 = targetChip->getPixelSizeY(); strncpy(dev_name, getDeviceName(), 32); strncpy(exp_start, targetChip->getExposureStartTime(), 32); fits_update_key_s(fptr, TDOUBLE, "EXPTIME", &(exposureDuration), "Total Exposure Time (s)", &status); if(targetChip->getFrameType() == CCDChip::DARK_FRAME) fits_update_key_s(fptr, TDOUBLE, "DARKTIME", &(exposureDuration), "Total Exposure Time (s)", &status); fits_update_key_s(fptr, TDOUBLE, "PIXSIZE1", &(pixSize1), "Pixel Size 1 (microns)", &status); fits_update_key_s(fptr, TDOUBLE, "PIXSIZE2", &(pixSize2), "Pixel Size 2 (microns)", &status); fits_update_key_s(fptr, TUINT, "XBINNING", &(xbin) , "Binning factor in width", &status); fits_update_key_s(fptr, TUINT, "YBINNING", &(ybin), "Binning factor in height", &status); fits_update_key_s(fptr, TSTRING, "FRAME", frame_s, "Frame Type", &status); fits_update_key_s(fptr, TDOUBLE, "DATAMIN", &min_val, "Minimum value", &status); fits_update_key_s(fptr, TDOUBLE, "DATAMAX", &max_val, "Maximum value", &status); fits_update_key_s(fptr, TSTRING, "INSTRUME", dev_name, "CCD Name", &status); fits_update_key_s(fptr, TSTRING, "DATE-OBS", exp_start, "UTC start date of observation", &status); } void INDI::CCD::fits_update_key_s(fitsfile* fptr, int type, std::string name, void* p, std::string explanation, int* status) { // this function is for removing warnings about deprecated string conversion to char* (from arg 5) fits_update_key(fptr,type,name.c_str(),p, const_cast(explanation.c_str()), status); } bool INDI::CCD::ExposureComplete(CCDChip *targetChip) { void *memptr; size_t memsize; int img_type=0; int byte_type=0; int status=0; long naxes[2]; long naxis=2; int nelements=0; std::string bit_depth; fitsfile *fptr=NULL; naxes[0]=targetChip->getSubW()/targetChip->getBinX(); naxes[1]=targetChip->getSubH()/targetChip->getBinY(); switch (targetChip->getBPP()) { case 8: byte_type = TBYTE; img_type = BYTE_IMG; bit_depth = "8 bits per pixel"; break; case 16: byte_type = TUSHORT; img_type = USHORT_IMG; bit_depth = "16 bits per pixel"; break; case 32: byte_type = TULONG; img_type = ULONG_IMG; bit_depth = "32 bits per pixel"; break; default: DEBUGF(Logger::DBG_WARNING, "Unsupported bits per pixel value %d\n", targetChip->getBPP() ); return false; break; } nelements = naxes[0] * naxes[1]; DEBUGF(Logger::DBG_DEBUG, "Exposure complete. Image Depth: %s. Width: %d Height: %d nelements: %d", bit_depth.c_str(), naxes[0], naxes[1], nelements); // Now we have to send fits format data to the client memsize=5760; memptr=malloc(memsize); if(!memptr) { IDLog("Error: failed to allocate memory: %lu\n",(unsigned long)memsize); } fits_create_memfile(&fptr,&memptr,&memsize,2880,realloc,&status); if(status) { IDLog("Error: Failed to create FITS image\n"); fits_report_error(stderr, status); /* print out any error messages */ return false; } fits_create_img(fptr, img_type , naxis, naxes, &status); if (status) { IDLog("Error: Failed to create FITS image\n"); fits_report_error(stderr, status); /* print out any error messages */ return false; } addFITSKeywords(fptr, targetChip); fits_write_img(fptr,byte_type,1,nelements,targetChip->getFrameBuffer(),&status); if (status) { IDLog("Error: Failed to write FITS image\n"); fits_report_error(stderr, status); /* print out any error messages */ return false; } fits_close_file(fptr,&status); targetChip->ImageExposureNP->s=IPS_OK; IDSetNumber(targetChip->ImageExposureNP,NULL); targetChip->FitsB.blob=memptr; targetChip->FitsB.bloblen=memsize; targetChip->FitsB.size=memsize; strcpy(targetChip->FitsB.format,".fits"); targetChip->FitsBP->s=IPS_OK; //IDLog("Enter Uploadfile with %d total sending via %s, and format %s\n",total,targetChip->FitsB.name, targetChip->FitsB.format); IDSetBLOB(targetChip->FitsBP,NULL); free(memptr); return true; } void INDI::CCD::SetCCDParams(int x,int y,int bpp,float xf,float yf) { PrimaryCCD.setResolutoin(x, y); PrimaryCCD.setFrame(0, 0, x, y); PrimaryCCD.setBin(1,1); PrimaryCCD.setPixelSize(xf, yf); PrimaryCCD.setBPP(bpp); } void INDI::CCD::SetGuideHeadParams(int x,int y,int bpp,float xf,float yf) { HasGuideHead=true; GuideCCD.setResolutoin(x, y); GuideCCD.setFrame(0, 0, x, y); GuideCCD.setPixelSize(xf, yf); GuideCCD.setBPP(bpp); } bool INDI::CCD::AbortGuideExposure() { return false; } bool INDI::CCD::saveConfigItems(FILE *fp) { IUSaveConfigText(fp, ActiveDeviceTP); return true; } bool INDI::CCD::GuideNorth(float ms) { return false; } bool INDI::CCD::GuideSouth(float ms) { return false; } bool INDI::CCD::GuideEast(float ms) { return false; } bool INDI::CCD::GuideWest(float ms) { return false; } void INDI::CCD::getMinMax(double *min, double *max, CCDChip *targetChip) { int ind=0, i, j; int imageHeight = targetChip->getSubH() / targetChip->getBinY(); int imageWidth = targetChip->getSubW() / targetChip->getBinX(); double lmin, lmax; switch (targetChip->getBPP()) { case 8: { unsigned char *imageBuffer = (unsigned char *) targetChip->getFrameBuffer(); lmin = lmax = imageBuffer[0]; for (i= 0; i < imageHeight ; i++) for (j= 0; j < imageWidth; j++) { ind = (i * imageWidth) + j; if (imageBuffer[ind] < lmin) lmin = imageBuffer[ind]; else if (imageBuffer[ind] > lmax) lmax = imageBuffer[ind]; } } break; case 16: { unsigned short *imageBuffer = (unsigned short* ) targetChip->getFrameBuffer(); lmin = lmax = imageBuffer[0]; for (i= 0; i < imageHeight ; i++) for (j= 0; j < imageWidth; j++) { ind = (i * imageWidth) + j; if (imageBuffer[ind] < lmin) lmin = imageBuffer[ind]; else if (imageBuffer[ind] > lmax) lmax = imageBuffer[ind]; } } break; case 32: { unsigned int *imageBuffer = (unsigned int* ) targetChip->getFrameBuffer(); lmin = lmax = imageBuffer[0]; for (i= 0; i < imageHeight ; i++) for (j= 0; j < imageWidth; j++) { ind = (i * imageWidth) + j; if (imageBuffer[ind] < lmin) lmin = imageBuffer[ind]; else if (imageBuffer[ind] > lmax) lmax = imageBuffer[ind]; } } break; } *min = lmin; *max = lmax; } libindi-0.9.7/libs/indibase/indiproperty.cpp0000644000175000017500000001403312241463551020070 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include #include "basedevice.h" #include "baseclient.h" #include "indicom.h" #include "base64.h" #include "indiproperty.h" INDI::Property::Property() { pPtr = NULL; pRegistered = false; pDynamic = false; pType = INDI_UNKNOWN; } INDI::Property::~Property() { // Only delete properties if they were created dynamically via the buildSkeleton // function. Other drivers are responsible for their own memory allocation. if (pDynamic) { switch (pType) { case INDI_NUMBER: delete ((INumberVectorProperty *) pPtr); break; case INDI_TEXT: delete ((ITextVectorProperty *) pPtr); break; case INDI_SWITCH: delete ((ISwitchVectorProperty *) pPtr); break; case INDI_LIGHT: delete ((ILightVectorProperty *) pPtr); break; case INDI_BLOB: delete ((IBLOBVectorProperty *) pPtr); break; } } } void INDI::Property::setProperty(void *p) { pRegistered = true; pPtr = p; } void INDI::Property::setType(INDI_TYPE t) { pType = t; } void INDI::Property::setRegistered(bool r) { pRegistered = r; } void INDI::Property::setDynamic(bool d) { pDynamic = d; } void INDI::Property::setBaseDevice(BaseDevice *idp) { dp = idp; } const char * INDI::Property::getName() { if (pPtr == NULL) return NULL; switch (pType) { case INDI_NUMBER: return ((INumberVectorProperty *) pPtr)->name; break; case INDI_TEXT: return ((ITextVectorProperty *) pPtr)->name; break; case INDI_SWITCH: return ((ISwitchVectorProperty *) pPtr)->name; break; case INDI_LIGHT: return ((ILightVectorProperty *) pPtr)->name; break; case INDI_BLOB: return ((IBLOBVectorProperty *) pPtr)->name; break; } return NULL; } const char * INDI::Property::getLabel() { if (pPtr == NULL) return NULL; switch (pType) { case INDI_NUMBER: return ((INumberVectorProperty *) pPtr)->label; break; case INDI_TEXT: return ((ITextVectorProperty *) pPtr)->label; break; case INDI_SWITCH: return ((ISwitchVectorProperty *) pPtr)->label; break; case INDI_LIGHT: return ((ILightVectorProperty *) pPtr)->label; break; case INDI_BLOB: return ((IBLOBVectorProperty *) pPtr)->label; break; } return NULL; } const char * INDI::Property::getGroupName() { if (pPtr == NULL) return NULL; switch (pType) { case INDI_NUMBER: return ((INumberVectorProperty *) pPtr)->group; break; case INDI_TEXT: return ((ITextVectorProperty *) pPtr)->group; break; case INDI_SWITCH: return ((ISwitchVectorProperty *) pPtr)->group; break; case INDI_LIGHT: return ((ILightVectorProperty *) pPtr)->group; break; case INDI_BLOB: return ((IBLOBVectorProperty *) pPtr)->group; break; } return NULL; } const char * INDI::Property::getDeviceName() { if (pPtr == NULL) return NULL; switch (pType) { case INDI_NUMBER: return ((INumberVectorProperty *) pPtr)->device; break; case INDI_TEXT: return ((ITextVectorProperty *) pPtr)->device; break; case INDI_SWITCH: return ((ISwitchVectorProperty *) pPtr)->device; break; case INDI_LIGHT: return ((ILightVectorProperty *) pPtr)->device; break; case INDI_BLOB: return ((IBLOBVectorProperty *) pPtr)->device; break; } return NULL; } IPState INDI::Property::getState() { switch (pType) { case INDI_NUMBER: return ((INumberVectorProperty *) pPtr)->s; break; case INDI_TEXT: return ((ITextVectorProperty *) pPtr)->s; break; case INDI_SWITCH: return ((ISwitchVectorProperty *) pPtr)->s; break; case INDI_LIGHT: return ((ILightVectorProperty *) pPtr)->s; break; case INDI_BLOB: return ((IBLOBVectorProperty *) pPtr)->s; break; } return IPS_IDLE; } IPerm INDI::Property::getPermission() { switch (pType) { case INDI_NUMBER: return ((INumberVectorProperty *) pPtr)->p; break; case INDI_TEXT: return ((ITextVectorProperty *) pPtr)->p; break; case INDI_SWITCH: return ((ISwitchVectorProperty *) pPtr)->p; break; case INDI_LIGHT: break; case INDI_BLOB: return ((IBLOBVectorProperty *) pPtr)->p; break; } return IP_RO; } INumberVectorProperty *INDI::Property::getNumber() { if (pType == INDI_NUMBER) return ((INumberVectorProperty *) pPtr); return NULL; } ITextVectorProperty *INDI::Property::getText() { if (pType == INDI_TEXT) return ((ITextVectorProperty *) pPtr); return NULL; } ISwitchVectorProperty *INDI::Property::getSwitch() { if (pType == INDI_SWITCH) return ((ISwitchVectorProperty *) pPtr); return NULL; } ILightVectorProperty *INDI::Property::getLight() { if (pType == INDI_LIGHT) return ((ILightVectorProperty *) pPtr); return NULL; } IBLOBVectorProperty *INDI::Property::getBLOB() { if (pType == INDI_BLOB) return ((IBLOBVectorProperty *) pPtr); return NULL; } libindi-0.9.7/libs/indibase/indiproperty.h0000644000175000017500000000374712241463551017547 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDI_INDIPROPERTY_H #define INDI_INDIPROPERTY_H #include "indibase.h" namespace INDI { class BaseDevice; class Property { public: Property(); ~Property(); void setProperty(void *); void setType(INDI_TYPE t); void setRegistered(bool r); void setDynamic(bool d); void setBaseDevice(BaseDevice *idp); void *getProperty() { return pPtr; } INDI_TYPE getType() { return pType; } bool getRegistered() { return pRegistered; } bool isDynamic() { return pDynamic; } BaseDevice *getBaseDevice() { return dp; } // Convenience Functions const char *getName(); const char *getLabel(); const char *getGroupName(); const char *getDeviceName(); IPState getState(); IPerm getPermission(); INumberVectorProperty *getNumber(); ITextVectorProperty *getText(); ISwitchVectorProperty *getSwitch(); ILightVectorProperty *getLight(); IBLOBVectorProperty *getBLOB(); private: void *pPtr; BaseDevice *dp; INDI_TYPE pType; bool pRegistered; bool pDynamic; }; } // namespace INDI #endif // INDI_INDIPROPERTY_H libindi-0.9.7/libs/indibase/indicontroller.cpp0000644000175000017500000002116112241463551020367 0ustar jasemjasem/******************************************************************************* Copyright (C) 2013 Jasem Mutlaq This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "indicontroller.h" #include namespace INDI { Controller::Controller(DefaultDevice *cdevice) { device = cdevice; JoystickSettingT = NULL; JoystickSettingTP.ntp = 0; joystickCallbackFunc = joystickEvent; axisCallbackFunc = axisEvent; buttonCallbackFunc = buttonEvent; } Controller::~Controller() { for (int i=0; i < JoystickSettingTP.ntp; i++) free(JoystickSettingT[i].aux0); } void Controller::mapController(const char *propertyName, const char *propertyLabel, ControllerType type, const char *initialValue) { if (JoystickSettingT == NULL) JoystickSettingT = (IText *) malloc(sizeof(IText)); JoystickSettingT = (IText *) realloc(JoystickSettingT, (JoystickSettingTP.ntp+1) * sizeof(IText)); ControllerType *ctype = (ControllerType *) malloc(sizeof(ControllerType)); *ctype = type; IUFillText(&JoystickSettingT[JoystickSettingTP.ntp], propertyName, propertyLabel, initialValue); JoystickSettingT[JoystickSettingTP.ntp++].aux0 = ctype; } bool Controller::initProperties() { IUFillSwitch(&UseJoystickS[0], "ENABLE", "Enable", ISS_OFF); IUFillSwitch(&UseJoystickS[1], "DISABLE", "Disable", ISS_ON); IUFillSwitchVector(&UseJoystickSP, UseJoystickS, 2, device->getDeviceName(), "USEJOYSTICK", "Joystick", OPTIONS_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE); IUFillTextVector(&JoystickSettingTP, JoystickSettingT, JoystickSettingTP.ntp, device->getDeviceName(), "JOYSTICKSETTINGS", "Settings", "Joystick", IP_RW, 0, IPS_IDLE); } void Controller::ISGetProperties(const char *dev) { if(dev && strcmp(dev,device->getDeviceName())) return; if (device->isConnected()) { device->defineSwitch(&UseJoystickSP); if (JoystickSettingT && UseJoystickS[0].s == ISS_ON) device->defineText(&JoystickSettingTP); } } bool Controller::updateProperties() { if (device->isConnected()) { device->defineSwitch(&UseJoystickSP); if (JoystickSettingT && UseJoystickS[0].s == ISS_ON) device->defineText(&JoystickSettingTP); } else { device->deleteProperty(UseJoystickSP.name); device->deleteProperty(JoystickSettingTP.name); } return true; } bool Controller::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { if(strcmp(dev,device->getDeviceName())==0) { // Enable joystick support if (!strcmp(name, UseJoystickSP.name)) { IUUpdateSwitch(&UseJoystickSP, states, names, n); UseJoystickSP.s = IPS_OK; if (UseJoystickSP.sp[0].s == ISS_ON) enableJoystick(); else disableJoystick(); IDSetSwitch(&UseJoystickSP, NULL); } } return true; } bool Controller::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { if(strcmp(dev,device->getDeviceName())==0) { if (!strcmp(name, "JOYSTICKSETTINGS")) { for (int i=0; i < JoystickSettingTP.ntp; i++) { IText *tp = IUFindText(&JoystickSettingTP, names[i]); if (tp) { ControllerType cType = getControllerType(texts[i]); ControllerType myType = *((ControllerType *) JoystickSettingT[i].aux0); if (cType != myType) { JoystickSettingTP.s = IPS_ALERT; IDSetText(&JoystickSettingTP, NULL); DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Cannot change controller type to %s.", texts[i]); return false; } } } IUUpdateText(&JoystickSettingTP, texts, names, n); for (int i=0; i < JoystickSettingTP.ntp; i++) { if (strstr(JoystickSettingT[i].text, "JOYSTICK_")) IDSnoopDevice("Joystick", JoystickSettingT[i].text); } JoystickSettingTP.s = IPS_OK; IDSetText(&JoystickSettingTP, NULL); return true; } } return true; } bool Controller::ISSnoopDevice(XMLEle *root) { XMLEle *ep=NULL; double mag=0, angle=0; const char *propName = findXMLAttValu(root, "name"); // Check axis if (!strcmp("JOYSTICK_AXIS", propName)) { for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0)) { const char *elemName = findXMLAttValu(ep, "name"); const char *setting = getControllerSetting(elemName); if (setting == NULL) return false; mag = atof(pcdataXMLEle(ep)); axisCallbackFunc(setting, mag); } } // Check buttons else if (!strcmp("JOYSTICK_BUTTONS", propName)) { for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0)) { const char *elemName = findXMLAttValu(ep, "name"); const char *setting = getControllerSetting(elemName); if (setting == NULL) return false; buttonCallbackFunc(setting, strcmp(pcdataXMLEle(ep), "Off") ? ISS_ON : ISS_OFF); } } // Check joysticks else if (strstr(propName, "JOYSTICK_")) { const char *setting = getControllerSetting(propName); // We don't have this here, so let's not process it if (setting == NULL) return false; for (ep = nextXMLEle(root, 1) ; ep != NULL ; ep = nextXMLEle(root, 0)) { if (!strcmp("JOYSTICK_MAGNITUDE", findXMLAttValu(ep, "name"))) mag = atof(pcdataXMLEle(ep)); else if (!strcmp("JOYSTICK_ANGLE", findXMLAttValu(ep, "name"))) angle = atof(pcdataXMLEle(ep)); } joystickCallbackFunc(setting, mag, angle); } } bool Controller::saveConfigItems(FILE *fp) { IUSaveConfigSwitch(fp, &UseJoystickSP); IUSaveConfigText(fp, &JoystickSettingTP); return true; } void Controller::enableJoystick() { device->defineText(&JoystickSettingTP); for (int i=0; i < JoystickSettingTP.ntp; i++) { if (strstr(JoystickSettingTP.tp[i].text, "JOYSTICK_")) IDSnoopDevice("Joystick", JoystickSettingTP.tp[i].text); } IDSnoopDevice("Joystick", "JOYSTICK_AXIS"); IDSnoopDevice("Joystick", "JOYSTICK_BUTTONS"); } void Controller::disableJoystick() { device->deleteProperty(JoystickSettingTP.name); } void Controller::setJoystickCallback(joystickFunc JoystickCallback) { joystickCallbackFunc = JoystickCallback; } void Controller::setAxisCallback(axisFunc AxisCallback) { axisCallbackFunc = AxisCallback; } void Controller::setButtonCallback(buttonFunc buttonCallback) { buttonCallbackFunc = buttonCallback; } void Controller::joystickEvent(const char * joystick_n, double mag, double angle) { (void)joystick_n; (void)mag; (void)angle; } void Controller::axisEvent(const char *axis_n, int value) { (void)axis_n; (void)value; } void Controller::buttonEvent(const char *button_n, int button_value) { (void)button_n; (void)button_value; } Controller::ControllerType Controller::getControllerType(const char *name) { ControllerType targetType = CONTROLLER_UNKNOWN; if (strstr(name, "JOYSTICK_")) targetType = CONTROLLER_JOYSTICK; else if (strstr(name, "AXIS_")) targetType = CONTROLLER_AXIS; else if (strstr(name, "BUTTON_")) targetType = CONTROLLER_BUTTON; return targetType; } const char *Controller::getControllerSetting(const char *name) { for (int i=0; i < JoystickSettingTP.ntp; i++) if (!strcmp(JoystickSettingT[i].text, name)) return JoystickSettingT[i].name; return NULL; } } libindi-0.9.7/libs/indibase/indifilterwheel.cpp0000644000175000017500000001004412241463551020514 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010, 2011 Gerry Rozema. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "indifilterwheel.h" #include INDI::FilterWheel::FilterWheel() { //ctor } INDI::FilterWheel::~FilterWheel() { //dtor } bool INDI::FilterWheel::initProperties() { DefaultDevice::initProperties(); initFilterProperties(getDeviceName(), FILTER_TAB); return true; } void INDI::FilterWheel::ISGetProperties (const char *dev) { // First we let our parent populate //IDLog("INDI::FilterWheel::ISGetProperties %s\n",dev); DefaultDevice::ISGetProperties(dev); if(isConnected()) { defineNumber(&FilterSlotNP); if (GetFilterNames(FILTER_TAB)) defineText(FilterNameTP); } return; } bool INDI::FilterWheel::updateProperties() { // Define more properties after we are connected // first we want to update the values to reflect our actual wheel if(isConnected()) { //initFilterProperties(getDeviceName(), FILTER_TAB); defineNumber(&FilterSlotNP); if (GetFilterNames(FILTER_TAB)) defineText(FilterNameTP); } else { deleteProperty(FilterSlotNP.name); deleteProperty(FilterNameTP->name); } return true; } bool INDI::FilterWheel::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { return DefaultDevice::ISNewSwitch(dev, name, states, names,n); } bool INDI::FilterWheel::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) { // first check if it's for our device //IDLog("INDI::FilterWheel::ISNewNumber %s\n",name); if(strcmp(dev,getDeviceName())==0) { // This is for our device // Now lets see if it's something we process here if(strcmp(name,"FILTER_SLOT")==0) { processFilterSlot(dev, values, names); return true; } } // if we didn't process it, continue up the chain, let somebody else // give it a shot return DefaultDevice::ISNewNumber(dev,name,values,names,n); } bool INDI::FilterWheel::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) { // Ok, lets see if this is a property wer process //IDLog("INDI::FilterWheel got %d new text items name %s\n",n,name); // first check if it's for our device if(strcmp(dev,getDeviceName())==0) { // This is for our device // Now lets see if it's something we process here if(strcmp(name,FilterNameTP->name)==0) { processFilterName(dev, texts, names, n); return true; } } return DefaultDevice::ISNewText(dev,name,texts,names,n); } bool INDI::FilterWheel::saveConfigItems(FILE *fp) { IUSaveConfigNumber(fp, &FilterSlotNP); IUSaveConfigText(fp, FilterNameTP); return true; } int INDI::FilterWheel::QueryFilter() { return -1; } bool INDI::FilterWheel::SelectFilter(int) { return false; } bool INDI::FilterWheel::SetFilterNames() { return true; } bool INDI::FilterWheel::GetFilterNames(const char* groupName) { INDI_UNUSED(groupName); return false; } bool INDI::FilterWheel::ISSnoopDevice (XMLEle *root) { return INDI::DefaultDevice::ISSnoopDevice(root); } libindi-0.9.7/libs/indibase/indiguiderinterface.cpp0000644000175000017500000000572112241463551021350 0ustar jasemjasem/* Guider Interface Copyright (C) 2011 Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include "indiguiderinterface.h" #include #include INDI::GuiderInterface::GuiderInterface() { } INDI::GuiderInterface::~GuiderInterface() { } void INDI::GuiderInterface::initGuiderProperties(const char *deviceName, const char* groupName) { IUFillNumber(&GuideNSN[0],"TIMED_GUIDE_N","North (msec)","%g",0,60000,10,0); IUFillNumber(&GuideNSN[1],"TIMED_GUIDE_S","South (msec)","%g",0,60000,10,0); IUFillNumberVector(&GuideNSNP,GuideNSN,2,deviceName,"TELESCOPE_TIMED_GUIDE_NS","Guide North/South",groupName,IP_RW,60,IPS_IDLE); IUFillNumber(&GuideWEN[0],"TIMED_GUIDE_E","East (msec)","%g",0,60000,10,0); IUFillNumber(&GuideWEN[1],"TIMED_GUIDE_W","West (msec)","%g",0,60000,10,0); IUFillNumberVector(&GuideWENP,GuideWEN,2,deviceName,"TELESCOPE_TIMED_GUIDE_WE","Guide East/West",groupName,IP_RW,60,IPS_IDLE); } void INDI::GuiderInterface::processGuiderProperties(const char *name, double values[], char *names[], int n) { if(strcmp(name,GuideNSNP.name)==0) { // We are being asked to send a guide pulse north/south on the st4 port GuideNSNP.s=IPS_BUSY; IUUpdateNumber(&GuideNSNP,values,names,n); // Update client display IDSetNumber(&GuideNSNP,NULL); if(GuideNSN[0].value != 0) { GuideNorth(GuideNSN[0].value); } if(GuideNSN[1].value != 0) { GuideSouth(GuideNSN[1].value); } GuideNSN[0].value=0; GuideNSN[1].value=0; GuideNSNP.s=IPS_OK; IDSetNumber(&GuideNSNP,NULL); return; } if(strcmp(name,GuideWENP.name)==0) { // We are being asked to send a guide pulse north/south on the st4 port GuideWENP.s=IPS_BUSY; IUUpdateNumber(&GuideWENP,values,names,n); // Update client display IDSetNumber(&GuideWENP,NULL); if(GuideWEN[0].value != 0) { GuideEast(GuideWEN[0].value); } else { GuideWest(GuideWEN[1].value); } GuideWEN[0].value=0; GuideWEN[1].value=0; GuideWENP.s=IPS_OK; IDSetNumber(&GuideWENP,NULL); return; } } libindi-0.9.7/libs/indibase/indilogger.cpp0000644000175000017500000003035112241463551017464 0ustar jasemjasem/******************************************************************************* Copyright (C) 2012 Evidence Srl - www.evidence.eu.com Adapted to INDI Library by Jasem Mutlaq & Geehalel. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include "indilogger.h" #include #include namespace INDI { char Logger::Tags[Logger::nlevels][MAXINDINAME]= { "ERROR", "WARNING", "INFO", "DEBUG", "DBG_EXTRA_1", "DBG_EXTRA_2", "DBG_EXTRA_3", "DBG_EXTRA_4" }; struct Logger::switchinit Logger::DebugLevelSInit[]= { {"DBG_ERROR", "Errors", ISS_ON, DBG_ERROR}, {"DBG_WARNING", "Warnings", ISS_ON, DBG_WARNING}, {"DBG_SESSION", "Messages", ISS_ON, DBG_SESSION}, {"DBG_DEBUG", "Driver Debug", ISS_OFF, DBG_DEBUG}, {"DBG_EXTRA_1", "Debug Extra 1", ISS_OFF, DBG_EXTRA_1}, {"DBG_EXTRA_2", "Debug Extra 2", ISS_OFF, DBG_EXTRA_2}, {"DBG_EXTRA_3", "Debug Extra 3", ISS_OFF, DBG_EXTRA_3}, {"DBG_EXTRA_4", "Debug Extra 4", ISS_OFF, DBG_EXTRA_4} }; struct Logger::switchinit Logger::LoggingLevelSInit[]= { {"LOG_ERROR", "Errors", ISS_ON, DBG_ERROR}, {"LOG_WARNING", "Warnings", ISS_ON, DBG_WARNING}, {"LOG_SESSION", "Messages", ISS_ON, DBG_SESSION}, {"LOG_DEBUG", "Driver Debug", ISS_OFF, DBG_DEBUG}, {"LOG_EXTRA_1", "Log Extra 1", ISS_OFF, DBG_EXTRA_1}, {"LOG_EXTRA_2", "Log Extra 2", ISS_OFF, DBG_EXTRA_2}, {"LOG_EXTRA_3", "Log Extra 3", ISS_OFF, DBG_EXTRA_3}, {"LOG_EXTRA_4", "Log Extra 4", ISS_OFF, DBG_EXTRA_4} }; ISwitch Logger::DebugLevelS[Logger::nlevels]; ISwitchVectorProperty Logger::DebugLevelSP; ISwitch Logger::LoggingLevelS[Logger::nlevels]; ISwitchVectorProperty Logger::LoggingLevelSP; ISwitch Logger::ConfigurationS[2]; ISwitchVectorProperty Logger::ConfigurationSP; unsigned int Logger::fileVerbosityLevel_=Logger::defaultlevel; unsigned int Logger::screenVerbosityLevel_=Logger::defaultlevel; unsigned int Logger::rememberscreenlevel_=Logger::defaultlevel; Logger::loggerConf Logger::configuration_= Logger::screen_on | Logger::file_off; std::string Logger::logFile_; unsigned int Logger::customLevel=4; int Logger::addDebugLevel(const char *debugLevelName, const char * loggingLevelName) { // Cannot create any more levels if (customLevel == nlevels) return -1; strncpy(Tags[customLevel], loggingLevelName, MAXINDINAME); strncpy(DebugLevelSInit[customLevel].label, debugLevelName, MAXINDINAME); strncpy(LoggingLevelSInit[customLevel].label, debugLevelName, MAXINDINAME); return DebugLevelSInit[customLevel++].levelmask; } bool Logger::updateProperties(bool debugenable, INDI::DefaultDevice *device) { if (debugenable) { unsigned int i; for (i=0; igetDeviceName(), "DEBUG_LEVEL" , "Debug Levels", OPTIONS_TAB, IP_RW, ISR_NOFMANY, 0, IPS_IDLE); IUFillSwitchVector(&LoggingLevelSP, LoggingLevelS, customLevel, device->getDeviceName(), "LOGGING_LEVEL" , "Logging Levels", OPTIONS_TAB, IP_RW, ISR_NOFMANY, 0, IPS_IDLE); device->defineSwitch(&DebugLevelSP); device->defineSwitch(&LoggingLevelSP); screenVerbosityLevel_=rememberscreenlevel_; IUFillSwitch(&ConfigurationS[0], "CLIENT_DEBUG", "To Client", ISS_ON); IUFillSwitch(&ConfigurationS[1], "FILE_DEBUG", "To Log File", ISS_OFF); IUFillSwitchVector(&ConfigurationSP, ConfigurationS, 2, device->getDeviceName(), "LOG_OUTPUT", "Log Output", OPTIONS_TAB, IP_RW, ISR_NOFMANY, 0, IPS_IDLE); device->defineSwitch(&ConfigurationSP); } else { device->deleteProperty(DebugLevelSP.name); device->deleteProperty(LoggingLevelSP.name); device->deleteProperty(ConfigurationSP.name); rememberscreenlevel_=screenVerbosityLevel_; screenVerbosityLevel_=defaultlevel; } return true; } bool Logger::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n) { int debug_level=0, log_level=0, bitmask=0, verbose_level=0; if(strcmp(name,"DEBUG_LEVEL")==0) { ISwitch *sw; IUUpdateSwitch(&DebugLevelSP,states,names,n); sw=IUFindOnSwitch(&DebugLevelSP); if (sw == NULL) { DebugLevelSP.s=IPS_IDLE; IDSetSwitch(&DebugLevelSP,NULL); screenVerbosityLevel_ = 0; return true; } for (int i=0; i < DebugLevelSP.nsp; i++) { sw = &DebugLevelSP.sp[i]; bitmask = *((unsigned int *)sw->aux); if (sw->s == ISS_ON) { debug_level = i; verbose_level |= bitmask; } else verbose_level &= ~bitmask; } screenVerbosityLevel_ = verbose_level; DEBUGFDEVICE(dev, Logger::DBG_DEBUG, "Toggle Debug Level -- %s", DebugLevelSInit[debug_level].label); DebugLevelSP.s=IPS_OK; IDSetSwitch(&DebugLevelSP,NULL); return true; } if(strcmp(name,"LOGGING_LEVEL")==0) { ISwitch *sw; IUUpdateSwitch(&LoggingLevelSP,states,names,n); sw=IUFindOnSwitch(&LoggingLevelSP); if (sw == NULL) { fileVerbosityLevel_ =0; LoggingLevelSP.s=IPS_IDLE; IDSetSwitch(&LoggingLevelSP,NULL); return true; } for (int i=0; i < LoggingLevelSP.nsp; i++) { sw = &LoggingLevelSP.sp[i]; bitmask = *((unsigned int *)sw->aux); if (sw->s == ISS_ON) { log_level = i; fileVerbosityLevel_ |= bitmask; } else fileVerbosityLevel_ &= ~bitmask; } DEBUGFDEVICE(dev, Logger::DBG_DEBUG, "Toggle Logging Level -- %s", LoggingLevelSInit[log_level].label); LoggingLevelSP.s=IPS_OK; IDSetSwitch(&LoggingLevelSP,NULL); return true; } if (!strcmp(name, "LOG_OUTPUT")) { ISwitch *sw; IUUpdateSwitch(&ConfigurationSP,states,names,n); sw=IUFindOnSwitch(&ConfigurationSP); if (sw == NULL) { configuration_ = screen_off | file_off; ConfigurationSP.s = IPS_IDLE; IDSetSwitch(&ConfigurationSP, NULL); return true; } bool wasFileOff = configuration_ & file_off; configuration_ = (loggerConf) 0; if (ConfigurationS[1].s == ISS_ON) configuration_ = configuration_ | file_on; else configuration_ = configuration_ | file_off; if (ConfigurationS[0].s == ISS_ON) configuration_ = configuration_ | screen_on; else configuration_ = configuration_ | screen_off; // If file was off, then on again if (wasFileOff && (configuration_&file_on)) Logger::getInstance().configure(logFile_, configuration_, fileVerbosityLevel_, screenVerbosityLevel_); ConfigurationSP.s = IPS_OK; IDSetSwitch(&ConfigurationSP, NULL); return true; } return true; } // Definition (and initialization) of static attributes Logger* Logger::m_ = 0; #ifdef LOGGER_MULTITHREAD pthread_mutex_t Logger::lock_ = PTHREAD_MUTEX_INITIALIZER; inline void Logger::lock() { pthread_mutex_lock(&lock_); } inline void Logger::unlock() { pthread_mutex_unlock(&lock_); } #else void Logger::lock(){} void Logger::unlock(){} #endif /** * \brief Constructor. * It is a private constructor, called only by getInstance() and only the * first time. It is called inside a lock, so lock inside this method * is not required. * It only initializes the initial time. All configuration is done inside the * configure() method. */ Logger::Logger(): configured_(false) { gettimeofday(&initialTime_, NULL); } /** * \brief Method to configure the logger. Called by the DEBUG_CONF() macro. To make implementation easier, the old stream is always closed. * Then, in case, it is open again in append mode. * @param outputFile of the file used for logging * @param configuration (i.e., log on file and on screen on or off) * @param fileVerbosityLevel threshold for file * @param screenVerbosityLevel threshold for screen */ void Logger::configure (const std::string& outputFile, const loggerConf configuration, const int fileVerbosityLevel, const int screenVerbosityLevel) { Logger::lock(); fileVerbosityLevel_ = fileVerbosityLevel; screenVerbosityLevel_ = screenVerbosityLevel; rememberscreenlevel_= screenVerbosityLevel_; // Close the old stream, if needed if (configuration_&file_on) out_.close(); // Compute a new file name, if needed if (outputFile != logFile_){ std::ostringstream oss; time_t currTime; time(&currTime); //struct tm *currTm = localtime(&currTime); oss << outputFile << "_" << timestamp() << ".log"; // currTm->tm_mday << "_" << // currTm->tm_mon << "_" << // (1900 + currTm->tm_year) << "_" << // currTm->tm_hour << "-" << // currTm->tm_min << "-" << // currTm->tm_sec << ".log"; logFile_ = oss.str().c_str(); } // Open a new stream, if needed if (configuration&file_on) out_.open(logFile_.c_str(), std::ios::app); configuration_ = configuration; configured_ = true; Logger::unlock(); } /** * \brief Destructor. * It only closes the file, if open, and cleans memory. */ Logger::~Logger() { Logger::lock(); if (configuration_&file_on) out_.close(); delete m_; Logger::unlock(); } /** * \brief Method to get a reference to the object (i.e., Singleton) * It is a static method. * @return Reference to the object. */ Logger& Logger::getInstance() { Logger::lock(); if (m_ == 0) m_ = new Logger; Logger::unlock(); return *m_; } /** * \brief Method used to print message called by the DEBUG() macro. @ param i which debugging to query its rank. The lower the rank, the more priority it is. @ return rank of debugging level requested. */ unsigned int Logger::rank(unsigned int l) { switch(l) { case DBG_ERROR: return 0; case DBG_WARNING: return 1; case DBG_SESSION: return 2; case DBG_DEBUG: return 3; case DBG_EXTRA_1: return 4; case DBG_EXTRA_2: return 5; case DBG_EXTRA_3: return 6; case DBG_EXTRA_4: return 7; } } void Logger::print(const char *devicename, const unsigned int verbosityLevel, const std::string& file, const int line, //const std::string& message, const char *message, ...) { bool filelog = (verbosityLevel & fileVerbosityLevel_) != 0; bool screenlog = (verbosityLevel & screenVerbosityLevel_) != 0; va_list ap; char msg[257]; char usec[7]; msg[256]='\0'; va_start(ap, message); vsnprintf(msg, 257, message, ap); va_end(ap); if (!configured_) { std::cerr << "ERROR: Logger not configured!" << std::endl; return; } struct timeval currentTime, resTime; usec[6]='\0'; gettimeofday(¤tTime, NULL); timersub(¤tTime, &initialTime_, &resTime); snprintf(usec, 7, "%06ld", resTime.tv_usec); Logger::lock(); if ((configuration_&file_on) && filelog) //out_ << Tags[rank(verbosityLevel)] << "\t["<< file << ":" << line << "]\t" << out_ << Tags[rank(verbosityLevel)] << "\t" << (resTime.tv_sec) <<"."<<(usec) << " sec"<< "\t: " << msg << std::endl; if ((configuration_&screen_on) && screenlog) IDMessage(devicename, "%s", msg); /* std::cerr << "DEBUG [" << file << ":" << line << "] @ " << (currentTime.tv_sec - initialTime_.tv_sec) << ":" << message << std::endl; */ Logger::unlock(); } } libindi-0.9.7/libs/indibase/basedevice.cpp0000644000175000017500000007735412241463551017451 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include #include #include #include #include #include "basedevice.h" #include "baseclient.h" #include "indicom.h" #include "base64.h" #include "indiproperty.h" INDI::BaseDevice::BaseDevice() { mediator = NULL; lp = newLilXML(); deviceID = new char[MAXINDIDEVICE]; memset(deviceID, 0, MAXINDIDEVICE); char indidev[MAXINDIDEVICE]; strncpy(indidev, "INDIDEV=", MAXINDIDEVICE); if (getenv("INDIDEV") != NULL) { strncpy(deviceID, getenv("INDIDEV"), MAXINDIDEVICE); putenv(indidev); } } INDI::BaseDevice::~BaseDevice() { delLilXML (lp); while(!pAll.empty()) { delete pAll.back(); pAll.pop_back(); } delete[] deviceID; } INumberVectorProperty * INDI::BaseDevice::getNumber(const char *name) { INumberVectorProperty * nvp = NULL; nvp = static_cast (getRawProperty(name, INDI_NUMBER)); return nvp; } ITextVectorProperty * INDI::BaseDevice::getText(const char *name) { ITextVectorProperty * tvp = NULL; tvp = static_cast (getRawProperty(name, INDI_TEXT)); return tvp; } ISwitchVectorProperty * INDI::BaseDevice::getSwitch(const char *name) { ISwitchVectorProperty * svp = NULL; svp = static_cast (getRawProperty(name, INDI_SWITCH)); return svp; } ILightVectorProperty * INDI::BaseDevice::getLight(const char *name) { ILightVectorProperty * lvp = NULL; lvp = static_cast (getRawProperty(name, INDI_LIGHT)); return lvp; } IBLOBVectorProperty * INDI::BaseDevice::getBLOB(const char *name) { IBLOBVectorProperty * bvp = NULL; bvp = static_cast (getRawProperty(name, INDI_BLOB)); return bvp; } void * INDI::BaseDevice::getRawProperty(const char *name, INDI_TYPE type) { INDI_TYPE pType; void *pPtr; bool pRegistered = false; typename std::vector::iterator orderi = pAll.begin(); INumberVectorProperty *nvp; ITextVectorProperty *tvp; ISwitchVectorProperty *svp; ILightVectorProperty *lvp; IBLOBVectorProperty *bvp; for (; orderi != pAll.end(); ++orderi) { pType = (*orderi)->getType(); pPtr = (*orderi)->getProperty(); pRegistered = (*orderi)->getRegistered(); if (type != INDI_UNKNOWN && pType != type) continue; switch (pType) { case INDI_NUMBER: nvp = static_cast(pPtr); if (nvp == NULL) continue; if (!strcmp(name, nvp->name) && pRegistered) return pPtr; break; case INDI_TEXT: tvp = static_cast(pPtr); if (tvp == NULL) continue; if (!strcmp(name, tvp->name) && pRegistered) return pPtr; break; case INDI_SWITCH: svp = static_cast(pPtr); if (svp == NULL) continue; //IDLog("Switch %s and aux value is now %d\n", svp->name, regStatus ); if (!strcmp(name, svp->name) && pRegistered) return pPtr; break; case INDI_LIGHT: lvp = static_cast(pPtr); if (lvp == NULL) continue; if (!strcmp(name, lvp->name) && pRegistered) return pPtr; break; case INDI_BLOB: bvp = static_cast(pPtr); if (bvp == NULL) continue; if (!strcmp(name, bvp->name) && pRegistered) return pPtr; break; } } return NULL; } INDI::Property * INDI::BaseDevice::getProperty(const char *name, INDI_TYPE type) { INDI_TYPE pType; void *pPtr; bool pRegistered = false; std::vector::iterator orderi; INumberVectorProperty *nvp; ITextVectorProperty *tvp; ISwitchVectorProperty *svp; ILightVectorProperty *lvp; IBLOBVectorProperty *bvp; for (orderi = pAll.begin(); orderi != pAll.end(); ++orderi) { pType = (*orderi)->getType(); pPtr = (*orderi)->getProperty(); pRegistered = (*orderi)->getRegistered(); if (type != INDI_UNKNOWN && pType != type) continue; switch (pType) { case INDI_NUMBER: nvp = static_cast(pPtr); if (nvp == NULL) continue; if (!strcmp(name, nvp->name) && pRegistered) return *orderi; break; case INDI_TEXT: tvp = static_cast(pPtr); if (tvp == NULL) continue; if (!strcmp(name, tvp->name) && pRegistered) return *orderi; break; case INDI_SWITCH: svp = static_cast(pPtr); if (svp == NULL) continue; //IDLog("Switch %s and aux value is now %d\n", svp->name, regStatus ); if (!strcmp(name, svp->name) && pRegistered) return *orderi; break; case INDI_LIGHT: lvp = static_cast(pPtr); if (lvp == NULL) continue; if (!strcmp(name, lvp->name) && pRegistered) return *orderi; break; case INDI_BLOB: bvp = static_cast(pPtr); if (bvp == NULL) continue; if (!strcmp(name, bvp->name) && pRegistered) return *orderi; break; } } return NULL; } int INDI::BaseDevice::removeProperty(const char *name, char *errmsg) { std::vector::iterator orderi; INDI_TYPE pType; void *pPtr; INumberVectorProperty *nvp; ITextVectorProperty *tvp; ISwitchVectorProperty *svp; ILightVectorProperty *lvp; IBLOBVectorProperty *bvp; for (orderi = pAll.begin(); orderi != pAll.end(); ++orderi) { pType = (*orderi)->getType(); pPtr = (*orderi)->getProperty(); switch (pType) { case INDI_NUMBER: nvp = static_cast(pPtr); if (!strcmp(name, nvp->name)) { (*orderi)->setRegistered(false); delete *orderi; orderi = pAll.erase(orderi); return 0; } break; case INDI_TEXT: tvp = static_cast(pPtr); if (!strcmp(name, tvp->name)) { (*orderi)->setRegistered(false); delete *orderi; orderi = pAll.erase(orderi); return 0; } break; case INDI_SWITCH: svp = static_cast(pPtr); if (!strcmp(name, svp->name)) { (*orderi)->setRegistered(false); delete *orderi; orderi = pAll.erase(orderi); return 0; } break; case INDI_LIGHT: lvp = static_cast(pPtr); if (!strcmp(name, lvp->name)) { (*orderi)->setRegistered(false); delete *orderi; orderi = pAll.erase(orderi); return 0; } break; case INDI_BLOB: bvp = static_cast(pPtr); if (!strcmp(name, bvp->name)) { (*orderi)->setRegistered(false); delete *orderi; orderi = pAll.erase(orderi); return 0; } break; } } snprintf(errmsg, MAXRBUF, "Error: Property %s not found in device %s.", name, deviceID); return INDI_PROPERTY_INVALID; } void INDI::BaseDevice::buildSkeleton(const char *filename) { char errmsg[MAXRBUF]; FILE *fp = NULL; XMLEle *root = NULL, *fproot = NULL; fp = fopen(filename, "r"); if (fp == NULL) { IDLog("Unable to build skeleton. Error loading file %s: %s\n", filename, strerror(errno)); return; } fproot = readXMLFile(fp, lp, errmsg); if (fproot == NULL) { IDLog("Unable to parse skeleton XML: %s", errmsg); return; } //prXMLEle(stderr, fproot, 0); for (root = nextXMLEle (fproot, 1); root != NULL; root = nextXMLEle (fproot, 0)) buildProp(root, errmsg); /**************************************************************************/ } int INDI::BaseDevice::buildProp(XMLEle *root, char *errmsg) { IPerm perm; IPState state; XMLEle *ep = NULL; char *rtag, *rname, *rdev; double timeout=0; rtag = tagXMLEle(root); /* pull out device and name */ if (crackDN (root, &rdev, &rname, errmsg) < 0) return -1; if (!deviceID[0]) strncpy(deviceID, rdev, MAXINDINAME); //if (getProperty(rname, type) != NULL) if (getProperty(rname) != NULL) return INDI::BaseClient::INDI_PROPERTY_DUPLICATED; if (strcmp (rtag, "defLightVector") && crackIPerm(findXMLAttValu(root, "perm"), &perm) < 0) { IDLog("Error extracting %s permission (%s)\n", rname, findXMLAttValu(root, "perm")); return -1; } timeout = atoi(findXMLAttValu(root, "timeout")); if (crackIPState (findXMLAttValu(root, "state"), &state) < 0) { IDLog("Error extracting %s state (%s)\n", rname, findXMLAttValu(root, "state")); return -1; } if (!strcmp (rtag, "defNumberVector")) { INDI::Property *indiProp = new INDI::Property(); INumberVectorProperty *nvp = new INumberVectorProperty; INumber *np = NULL; int n=0; strncpy(nvp->device, deviceID, MAXINDIDEVICE); strncpy(nvp->name, rname, MAXINDINAME); strncpy(nvp->label, findXMLAttValu(root, "label"), MAXINDILABEL); strncpy(nvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP); nvp->p = perm; nvp->s = state; nvp->timeout = timeout; /* pull out each name/value pair */ for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++) { if (!strcmp (tagXMLEle(ep), "defNumber")) { np = (INumber *) realloc(np, (n+1) * sizeof(INumber)); np[n].nvp = nvp; XMLAtt *na = findXMLAtt (ep, "name"); if (na) { if (f_scansexa (pcdataXMLEle(ep), &(np[n].value)) < 0) IDLog("%s: Bad format %s\n", rname, pcdataXMLEle(ep)); else { strncpy(np[n].name, valuXMLAtt(na), MAXINDINAME); na = findXMLAtt (ep, "label"); if (na) strncpy(np[n].label, valuXMLAtt(na),MAXINDILABEL); na = findXMLAtt (ep, "format"); if (na) strncpy(np[n].format, valuXMLAtt(na), MAXINDIFORMAT); na = findXMLAtt (ep, "min"); if (na) np[n].min = atof(valuXMLAtt(na)); na = findXMLAtt (ep, "max"); if (na) np[n].max = atof(valuXMLAtt(na)); na = findXMLAtt (ep, "step"); if (na) np[n].step = atof(valuXMLAtt(na)); } } } } if (n > 0) { nvp->nnp = n; nvp->np = np; indiProp->setBaseDevice(this); indiProp->setProperty(nvp); indiProp->setDynamic(true); indiProp->setType(INDI_NUMBER); pAll.push_back(indiProp); //IDLog("Adding number property %s to list.\n", nvp->name); if (mediator) mediator->newProperty(indiProp); } else IDLog("%s: newNumberVector with no valid members\n",rname); } else if (!strcmp (rtag, "defSwitchVector")) { INDI::Property *indiProp = new INDI::Property(); ISwitchVectorProperty *svp = new ISwitchVectorProperty; ISwitch *sp = NULL; int n=0; strncpy(svp->device, deviceID, MAXINDIDEVICE); strncpy(svp->name, rname, MAXINDINAME); strncpy(svp->label, findXMLAttValu(root, "label"), MAXINDILABEL); strncpy(svp->group, findXMLAttValu(root, "group"), MAXINDIGROUP); if (crackISRule(findXMLAttValu(root, "rule"), (&svp->r)) < 0) svp->r = ISR_1OFMANY; svp->p = perm; svp->s = state; svp->timeout = timeout; /* pull out each name/value pair */ for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++) { if (!strcmp (tagXMLEle(ep), "defSwitch")) { sp = (ISwitch *) realloc(sp, (n+1) * sizeof(ISwitch)); sp[n].svp = svp; XMLAtt *na = findXMLAtt (ep, "name"); if (na) { crackISState(pcdataXMLEle(ep), &(sp[n].s)); strncpy(sp[n].name, valuXMLAtt(na), MAXINDINAME); na = findXMLAtt (ep, "label"); if (na) strncpy(sp[n].label, valuXMLAtt(na),MAXINDILABEL); } } } if (n > 0) { svp->nsp = n; svp->sp = sp; indiProp->setBaseDevice(this); indiProp->setProperty(svp); indiProp->setDynamic(true); indiProp->setType(INDI_SWITCH); pAll.push_back(indiProp); //IDLog("Adding Switch property %s to list.\n", svp->name); if (mediator) mediator->newProperty(indiProp); } else IDLog("%s: newSwitchVector with no valid members\n",rname); } else if (!strcmp (rtag, "defTextVector")) { INDI::Property *indiProp = new INDI::Property(); ITextVectorProperty *tvp = new ITextVectorProperty; IText *tp = NULL; int n=0; strncpy(tvp->device, deviceID, MAXINDIDEVICE); strncpy(tvp->name, rname, MAXINDINAME); strncpy(tvp->label, findXMLAttValu(root, "label"), MAXINDILABEL); strncpy(tvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP); tvp->p = perm; tvp->s = state; tvp->timeout = timeout; // pull out each name/value pair for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++) { if (!strcmp (tagXMLEle(ep), "defText")) { tp = (IText *) realloc(tp, (n+1) * sizeof(IText)); tp[n].tvp = tvp; XMLAtt *na = findXMLAtt (ep, "name"); if (na) { tp[n].text = (char *) malloc( (pcdatalenXMLEle(ep)*sizeof(char)) + 1); strncpy(tp[n].text, pcdataXMLEle(ep), pcdatalenXMLEle(ep)); tp[n].text[pcdatalenXMLEle(ep)] = '\0'; strncpy(tp[n].name, valuXMLAtt(na), MAXINDINAME); na = findXMLAtt (ep, "label"); if (na) strncpy(tp[n].label, valuXMLAtt(na),MAXINDILABEL); } } } if (n > 0) { tvp->ntp = n; tvp->tp = tp; indiProp->setBaseDevice(this); indiProp->setProperty(tvp); indiProp->setDynamic(true); indiProp->setType(INDI_TEXT); pAll.push_back(indiProp); //IDLog("Adding Text property %s to list with initial value of %s.\n", tvp->name, tvp->tp[0].text); if (mediator) mediator->newProperty(indiProp); } else IDLog("%s: newTextVector with no valid members\n",rname); } else if (!strcmp (rtag, "defLightVector")) { INDI::Property *indiProp = new INDI::Property(); ILightVectorProperty *lvp = new ILightVectorProperty; ILight *lp = NULL; int n=0; strncpy(lvp->device, deviceID, MAXINDIDEVICE); strncpy(lvp->name, rname, MAXINDINAME); strncpy(lvp->label, findXMLAttValu(root, "label"), MAXINDILABEL); strncpy(lvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP); lvp->s = state; /* pull out each name/value pair */ for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++) { if (!strcmp (tagXMLEle(ep), "defLight")) { lp = (ILight *) realloc(lp, (n+1) * sizeof(ILight)); lp[n].lvp = lvp; XMLAtt *na = findXMLAtt (ep, "name"); if (na) { crackIPState(pcdataXMLEle(ep), &(lp[n].s)); strncpy(lp[n].name, valuXMLAtt(na), MAXINDINAME); na = findXMLAtt (ep, "label"); if (na) strncpy(lp[n].label, valuXMLAtt(na),MAXINDILABEL); } } } if (n > 0) { lvp->nlp = n; lvp->lp = lp; indiProp->setBaseDevice(this); indiProp->setProperty(lvp); indiProp->setDynamic(true); indiProp->setType(INDI_LIGHT); pAll.push_back(indiProp); //IDLog("Adding Light property %s to list.\n", lvp->name); if (mediator) mediator->newProperty(indiProp); } else IDLog("%s: newLightVector with no valid members\n",rname); } else if (!strcmp (rtag, "defBLOBVector")) { INDI::Property *indiProp = new INDI::Property(); IBLOBVectorProperty *bvp = new IBLOBVectorProperty; IBLOB *bp = NULL; int n=0; strncpy(bvp->device, deviceID, MAXINDIDEVICE); strncpy(bvp->name, rname, MAXINDINAME); strncpy(bvp->label, findXMLAttValu(root, "label"), MAXINDILABEL); strncpy(bvp->group, findXMLAttValu(root, "group"), MAXINDIGROUP); bvp->s = state; bvp->p = perm; /* pull out each name/value pair */ for (n = 0, ep = nextXMLEle(root,1); ep != NULL; ep = nextXMLEle(root,0), n++) { if (!strcmp (tagXMLEle(ep), "defBLOB")) { bp = (IBLOB *) realloc(bp, (n+1) * sizeof(IBLOB)); bp[n].bvp = bvp; XMLAtt *na = findXMLAtt (ep, "name"); if (na) { strncpy(bp[n].name, valuXMLAtt(na), MAXINDINAME); na = findXMLAtt (ep, "label"); if (na) strncpy(bp[n].label, valuXMLAtt(na),MAXINDILABEL); na = findXMLAtt (ep, "format"); if (na) strncpy(bp[n].label, valuXMLAtt(na),MAXINDIBLOBFMT); // Initialize everything to zero bp[n].blob = NULL; bp[n].size = 0; bp[n].bloblen = 0; } } } if (n > 0) { bvp->nbp = n; bvp->bp = bp; indiProp->setBaseDevice(this); indiProp->setProperty(bvp); indiProp->setDynamic(true); indiProp->setType(INDI_BLOB); pAll.push_back(indiProp); //IDLog("Adding BLOB property %s to list.\n", bvp->name); if (mediator) mediator->newProperty(indiProp); } else IDLog("%s: newBLOBVector with no valid members\n",rname); } return (0); } bool INDI::BaseDevice::isConnected() { ISwitchVectorProperty *svp = getSwitch("CONNECTION"); if (!svp) return false; ISwitch * sp = IUFindSwitch(svp, "CONNECT"); if (!sp) return false; if (sp->s == ISS_ON) return true; else return false; } /* * return 0 if ok else -1 with reason in errmsg */ int INDI::BaseDevice::setValue (XMLEle *root, char * errmsg) { XMLAtt *ap; XMLEle *ep; char *rtag, *name; double timeout; IPState state; bool stateSet=false, timeoutSet=false; rtag = tagXMLEle(root); ap = findXMLAtt (root, "name"); if (!ap) { snprintf(errmsg, MAXRBUF, "INDI: <%s> unable to find name attribute", tagXMLEle(root)); return (-1); } name = valuXMLAtt(ap); /* set overall property state, if any */ ap = findXMLAtt (root, "state"); if (ap) { if (crackIPState(valuXMLAtt(ap), &state) != 0) { snprintf(errmsg, MAXRBUF, "INDI: <%s> bogus state %s for %s", tagXMLEle(root), valuXMLAtt(ap), name); return (-1); } stateSet = true; } setlocale(LC_NUMERIC,"C"); /* allow changing the timeout */ ap = findXMLAtt (root, "timeout"); if (ap) { timeout = atof(valuXMLAtt(ap)); timeoutSet = true; } checkMessage (root); if (!strcmp(rtag, "setNumberVector")) { INumberVectorProperty *nvp = getNumber(name); if (nvp == NULL) { snprintf(errmsg, MAXRBUF, "INDI: Could not find property %s in %s", name, deviceID); return -1; } if (stateSet) nvp->s = state; if (timeoutSet) nvp->timeout = timeout; for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0)) { INumber *np = IUFindNumber(nvp, findXMLAttValu(ep, "name")); if (!np) continue; np->value = atof(pcdataXMLEle(ep)); // Permit changing of min/max if (findXMLAtt(ep, "min")) np->min = atof(findXMLAttValu(ep, "min")); if (findXMLAtt(ep, "max")) np->max = atof(findXMLAttValu(ep, "max")); } setlocale(LC_NUMERIC,""); if (mediator) mediator->newNumber(nvp); return 0; } else if (!strcmp(rtag, "setTextVector")) { ITextVectorProperty *tvp = getText(name); if (tvp == NULL) return -1; if (stateSet) tvp->s = state; if (timeoutSet) tvp->timeout = timeout; for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0)) { IText *tp = IUFindText(tvp, findXMLAttValu(ep, "name")); if (!tp) continue; IUSaveText(tp, pcdataXMLEle(ep)); } if (mediator) mediator->newText(tvp); return 0; } else if (!strcmp(rtag, "setSwitchVector")) { ISState swState; ISwitchVectorProperty *svp = getSwitch(name); if (svp == NULL) return -1; if (stateSet) svp->s = state; if (timeoutSet) svp->timeout = timeout; for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0)) { ISwitch *sp = IUFindSwitch(svp, findXMLAttValu(ep, "name")); if (!sp) continue; if (crackISState(pcdataXMLEle(ep), &swState) == 0) sp->s = swState; } if (mediator) mediator->newSwitch(svp); return 0; } else if (!strcmp(rtag, "setLightVector")) { IPState lState; ILightVectorProperty *lvp = getLight(name); if (lvp == NULL) return -1; if (stateSet) lvp->s = state; for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0)) { ILight *lp = IUFindLight(lvp, findXMLAttValu(ep, "name")); if (!lp) continue; if (crackIPState(pcdataXMLEle(ep), &lState) == 0) lp->s = lState; } if (mediator) mediator->newLight(lvp); return 0; } else if (!strcmp(rtag, "setBLOBVector")) { IBLOBVectorProperty *bvp = getBLOB(name); if (bvp == NULL) return -1; if (stateSet) bvp->s = state; if (timeoutSet) bvp->timeout = timeout; return setBLOB(bvp, root, errmsg); } snprintf(errmsg, MAXRBUF, "INDI: <%s> Unable to process tag", tagXMLEle(root)); return -1; } /* Set BLOB vector. Process incoming data stream * Return 0 if okay, -1 if error */ int INDI::BaseDevice::setBLOB(IBLOBVectorProperty *bvp, XMLEle * root, char * errmsg) { IBLOB *blobEL; unsigned char * dataBuffer=NULL; XMLEle *ep; int n=0, r=0; uLongf dataSize=0; /* pull out each name/BLOB pair, decode */ for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (strcmp (tagXMLEle(ep), "oneBLOB") == 0) { XMLAtt *na = findXMLAtt (ep, "name"); blobEL = IUFindBLOB(bvp, findXMLAttValu (ep, "name")); XMLAtt *fa = findXMLAtt (ep, "format"); XMLAtt *sa = findXMLAtt (ep, "size"); if (na && fa && sa) { blobEL->size = atoi(valuXMLAtt(sa)); /* Blob size = 0 when only state changes */ if (blobEL->size == 0) continue; blobEL->blob = (unsigned char *) realloc (blobEL->blob, 3*pcdatalenXMLEle(ep)/4); blobEL->bloblen = from64tobits( static_cast (blobEL->blob), pcdataXMLEle(ep)); strncpy(blobEL->format, valuXMLAtt(fa), MAXINDIFORMAT); if (strstr(blobEL->format, ".z")) { blobEL->format[strlen(blobEL->format)-2] = '\0'; dataSize = blobEL->size * sizeof(unsigned char); dataBuffer = (unsigned char *) malloc(dataSize); if (dataBuffer == NULL) { strncpy(errmsg, "Unable to allocate memory for data buffer", MAXRBUF); return (-1); } r = uncompress(dataBuffer, &dataSize, static_cast (blobEL->blob), (uLong) blobEL->bloblen); if (r != Z_OK) { snprintf(errmsg, MAXRBUF, "INDI: %s.%s.%s compression error: %d", blobEL->bvp->device, blobEL->bvp->name, blobEL->name, r); free (dataBuffer); return -1; } blobEL->size = dataSize; free(blobEL->blob); blobEL->blob = dataBuffer; } if (mediator) mediator->newBLOB(blobEL); } else { snprintf(errmsg, MAXRBUF, "INDI: %s.%s.%s No valid members.", blobEL->bvp->device, blobEL->bvp->name, blobEL->name); return -1; } } } return 0; } void INDI::BaseDevice::setDeviceName(const char *dev) { strncpy(deviceID, dev, MAXINDINAME); } const char * INDI::BaseDevice::getDeviceName() { return deviceID; } /* add message to queue * N.B. don't put carriage control in msg, we take care of that. */ void INDI::BaseDevice::checkMessage (XMLEle *root) { XMLAtt *ap; ap = findXMLAtt(root, "message"); if (ap) doMessage(root); } /* Store msg in queue */ void INDI::BaseDevice::doMessage (XMLEle *msg) { XMLAtt *message; XMLAtt *time_stamp; // FIXME: delete the buffer in the destructor! char * msgBuffer = new char[MAXRBUF]; /* prefix our timestamp if not with msg */ time_stamp = findXMLAtt (msg, "timestamp"); /* finally! the msg */ message = findXMLAtt(msg, "message"); if (!message) return; if (time_stamp) snprintf(msgBuffer, MAXRBUF, "%s: %s ", valuXMLAtt(time_stamp), valuXMLAtt(message)); else snprintf(msgBuffer, MAXRBUF, "%s: %s ", timestamp(), valuXMLAtt(message)); // Prepend to the log addMessage(msgBuffer); } void INDI::BaseDevice::addMessage(const char *msg) { messageLog.push_back(msg); if (mediator) mediator->newMessage(this, messageLog.size()-1); } const char * INDI::BaseDevice::messageQueue(int index) { if (index >= messageLog.size()) return NULL; return messageLog.at(index); } const char * INDI::BaseDevice::lastMessage() { return messageLog.back(); } void INDI::BaseDevice::registerProperty(void *p, INDI_TYPE type) { INDI::Property *pContainer; if (type == INDI_NUMBER) { INumberVectorProperty *nvp = static_cast (p); if ( (pContainer = getProperty(nvp->name, INDI_NUMBER)) != NULL) { pContainer->setRegistered(true); return; } pContainer = new INDI::Property(); pContainer->setProperty(p); pContainer->setType(type); pAll.push_back(pContainer); } else if (type == INDI_TEXT) { ITextVectorProperty *tvp = static_cast (p); if ( (pContainer = getProperty(tvp->name, INDI_TEXT)) != NULL) { pContainer->setRegistered(true); return; } pContainer = new INDI::Property(); pContainer->setProperty(p); pContainer->setType(type); pAll.push_back(pContainer); } else if (type == INDI_SWITCH) { ISwitchVectorProperty *svp = static_cast (p); if ( (pContainer = getProperty(svp->name, INDI_SWITCH)) != NULL) { pContainer->setRegistered(true); return; } pContainer = new INDI::Property(); pContainer->setProperty(p); pContainer->setType(type); pAll.push_back(pContainer); } else if (type == INDI_LIGHT) { ILightVectorProperty *lvp = static_cast (p); if ( (pContainer = getProperty(lvp->name, INDI_LIGHT)) != NULL) { pContainer->setRegistered(true); return; } pContainer = new INDI::Property(); pContainer->setProperty(p); pContainer->setType(type); pAll.push_back(pContainer); } else if (type == INDI_BLOB) { IBLOBVectorProperty *bvp = static_cast (p); if ( (pContainer = getProperty(bvp->name, INDI_BLOB)) != NULL) { pContainer->setRegistered(true); return; } pContainer = new INDI::Property(); pContainer->setProperty(p); pContainer->setType(type); pAll.push_back(pContainer); } } const char *INDI::BaseDevice::getDriverName() { ITextVectorProperty *driverInfo = getText("DRIVER_INFO"); if (driverInfo == NULL) return NULL; IText *driverName = IUFindText(driverInfo, "NAME"); if (driverName) return driverName->text; return NULL; } const char *INDI::BaseDevice::getDriverExec() { ITextVectorProperty *driverInfo = getText("DRIVER_INFO"); if (driverInfo == NULL) return NULL; IText *driverExec = IUFindText(driverInfo, "EXEC"); if (driverExec) return driverExec->text; return NULL; } libindi-0.9.7/libs/indibase/defaultdevice.h0000644000175000017500000003264312241463551017620 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #ifndef INDIDEFAULTDRIVER_H #define INDIDEFAULTDRIVER_H #include "basedevice.h" #include "indidriver.h" #include "indilogger.h" #include /** * @brief COMMUNICATION_TAB Where all the properties required to connect/disconnect from a device are located. * Usually such properties may include port number, IP address, or any property necessarily to establish a * connection to the device. */ extern const char *COMMUNICATION_TAB; /** * @brief MAIN_CONTROL_TAB Where all the primary controls for the device are located. */ extern const char *MAIN_CONTROL_TAB; /** * @brief MOTION_TAB Where all the motion control properties of the device are located. */ extern const char *MOTION_TAB; /** * @brief DATETIME_TAB Where all date and time setting properties are located. */ extern const char *DATETIME_TAB; /** * @brief SITE_TAB Where all site information setting are located. */ extern const char *SITE_TAB; /** * @brief OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls, driver * metadata, version information..etc. */ extern const char *OPTIONS_TAB; /** * @brief FILTER_TAB Where all the properties for filter wheels are located. */ extern const char *FILTER_TAB; /** * @brief FOCUS_TAB Where all the properties for focuser are located. */ extern const char *FOCUS_TAB; /** * @brief GUIDE_TAB Where all the properties for guiding are located. */ extern const char *GUIDE_TAB; /** * \class INDI::DefaultDevice \brief Class to provide extended functionality for devices in addition to the functionality provided by INDI::BaseDevice. This class should \e only be subclassed by drivers directly as it is linked with main(). Virtual drivers cannot employ INDI::DefaultDevice. INDI::DefaultDevice provides capability to add Debug, Simulation, and Configuration controls. These controls (switches) are defined to the client. Configuration options permit saving and loading of AS-IS property values. \see Tutorial Four \author Jasem Mutlaq */ class INDI::DefaultDevice : public INDI::BaseDevice { public: DefaultDevice(); virtual ~DefaultDevice(); /** \brief Add Debug, Simulation, and Configuration options to the driver */ void addAuxControls(); /** \brief Add Debug control to the driver */ void addDebugControl(); /** \brief Add Simulation control to the driver */ void addSimulationControl(); /** \brief Add Configuration control to the driver */ void addConfigurationControl(); /** \brief Set all properties to IDLE state */ void resetProperties(); /** \brief Define number vector to client & register it. Alternatively, IDDefNumber can be used but the property will not get registered and the driver will not be able to save configuration files. \param nvp The number vector property to be defined */ void defineNumber(INumberVectorProperty *nvp); /** \brief Define text vector to client & register it. Alternatively, IDDefText can be used but the property will not get registered and the driver will not be able to save configuration files. \param tvp The text vector property to be defined */ void defineText(ITextVectorProperty *tvp); /** \brief Define switch vector to client & register it. Alternatively, IDDefswitch can be used but the property will not get registered and the driver will not be able to save configuration files. \param svp The switch vector property to be defined */ void defineSwitch(ISwitchVectorProperty *svp); /** \brief Define light vector to client & register it. Alternatively, IDDeflight can be used but the property will not get registered and the driver will not be able to save configuration files. \param lvp The light vector property to be defined */ void defineLight(ILightVectorProperty *lvp); /** \brief Define BLOB vector to client & register it. Alternatively, IDDefBLOB can be used but the property will not get registered and the driver will not be able to save configuration files. \param bvp The BLOB vector property to be defined */ void defineBLOB(IBLOBVectorProperty *bvp); /** \brief Delete a property and unregister it. It will also be deleted from all clients. \param propertyName name of property to be deleted. */ virtual bool deleteProperty(const char *propertyName); /** \brief Set connection switch status in the client. \param status If true, the driver will attempt to connect to the device (CONNECT=ON). If false, it will attempt to disconnect the device. \param status True to set CONNECT on, false to set DISCONNECT on. \param state State of CONNECTION properti, by default IPS_OK. \param msg A message to be sent along with connect/disconnect command, by default NULL. */ virtual void setConnected(bool status, IPState state=IPS_OK, const char *msg = NULL); /** \brief Set a timer to call the function TimerHit after ms milliseconds \param ms timer duration in milliseconds. \return id of the timer to be used with RemoveTimer */ int SetTimer(int ms); /** \brief Remove timer added with SetTimer \param id ID of the timer as returned from SetTimer */ void RemoveTimer(int id); /** \brief Callback function to be called once SetTimer duration elapses. */ virtual void TimerHit(); /** \return driver name (executable filename) */ virtual const char *getDriverName() { return me; } /** \brief Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor * \param vMajor major revision number * \param vMinor minor revision number */ void setVersion(unsigned int vMajor, unsigned int vMinor) { majorVersion = vMajor; minorVersion = vMinor;} /** \return Major driver version number. */ unsigned int getMajorVersion() { return majorVersion;} /** \return Minor driver version number. */ unsigned int getMinorVersion() { return minorVersion;} /** \brief define the driver's properties to the client. * Usually, only a minumum set of properties are defined to the client in this function if the device is in disconnected state. * Those properties should be enough to enable the client to establish a connection to the device. In addition to * CONNECT/DISCONNECT, such properties may include port name, IP address, etc... * You should check if the device is already connected, and if this is true, then you must define the remainder of the * the properties to the client in this function. Otherweise, the remainder of the driver's properties are defined to the * client in updateProperties() function which is called when a client connects/disconnects from a device. \param dev name of the device \note This function is called by the INDI framework, do not call it directly. See LX200 Generic driver for an example implementation */ virtual void ISGetProperties (const char *dev); /** \brief Process the client newSwitch command \note This function is called by the INDI framework, do not call it directly. \returns True if any property was successfully processed, false otherwise. */ virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); /** \brief Process the client newNumber command \note This function is called by the INDI framework, do not call it directly. \returns True if any property was successfully processed, false otherwise. */ virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n) {return false;} /** \brief Process the client newSwitch command \note This function is called by the INDI framework, do not call it directly. \returns True if any property was successfully processed, false otherwise. */ virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n) {return false;} /** \brief Process the client newBLOB command \note This function is called by the INDI framework, do not call it directly. \returns True if any property was successfully processed, false otherwise. */ virtual bool ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { return false;} /** \brief Process a snoop event from INDI server. This function is called when a snooped property is updated in a snooped driver. \note This function is called by the INDI framework, do not call it directly. \returns True if any property was successfully processed, false otherwise. */ virtual bool ISSnoopDevice (XMLEle *root) { return false;} protected: // Configuration /** \brief Load the last saved configuration file \return True if successful, false otherwise. */ virtual bool loadConfig(); /** \brief Save the current properties in a configuration file \return True if successful, false otherwise. */ virtual bool saveConfig(); virtual bool saveConfigItems(FILE *fp); /** \brief Load the default configuration file \return True if successful, false otherwise. */ virtual bool loadDefaultConfig(); // Simulatin & Debug /** \brief Toggle driver debug status A driver can be more verbose if Debug option is enabled by the client. \param enable If true, the Debug option is set to ON. */ void setDebug(bool enable); /** \brief Toggle driver simulation status A driver can run in simulation mode if Simulation option is enabled by the client. \param enable If true, the Simulation option is set to ON. */ void setSimulation(bool enable); /** \brief Inform driver that the debug option was triggered. This function is called after setDebug is triggered by the client. Reimplement this function if your driver needs to take specific action after debug is enabled/disabled. Otherwise, you can use isDebug() to check if simulation is enabled or disabled. \param enable If true, the debug option is set to ON. */ virtual void debugTriggered(bool enable); /** \brief Inform driver that the simulation option was triggered. This function is called after setSimulation is triggered by the client. Reimplement this function if your driver needs to take specific action after simulation is enabled/disabled. Otherwise, you can use isSimulation() to check if simulation is enabled or disabled. \param enable If true, the simulation option is set to ON. */ virtual void simulationTriggered(bool enable); /** \return True if Debug is on, False otherwise. */ bool isDebug(); /** \return True if Simulation is on, False otherwise. */ bool isSimulation(); /** \brief Initilize properties initial state and value. The child class must implement this function. \return True if initilization is successful, false otherwise. */ virtual bool initProperties(); /** \brief updateProperties is called whenever there is a change in the CONNECTION status of the driver. This will enable the driver to react to changes of switching ON/OFF a device. For example, a driver may only define a set of properties after a device is connected, but not before. \return True if update is successful, false otherwise. */ virtual bool updateProperties(); /** \brief Connect to a device. Child classes must implement this function and perform the connection routine in the function. \return True if connection to device is successful, false otherwise. */ virtual bool Connect()=0; /** \brief Disconnect from a device. Child classes must implement this function and perform the disconnection routine in the function. \return True if disconnection from a device is successful, false otherwise. */ virtual bool Disconnect()=0; /** \return Default name of the device. */ virtual const char *getDefaultName()=0; private: bool isInit; bool pDebug; bool pSimulation; unsigned int majorVersion; unsigned int minorVersion; ISwitch DebugS[2]; ISwitch SimulationS[2]; ISwitch ConfigProcessS[3]; ISwitch ConnectionS[2]; ISwitchVectorProperty DebugSP; ISwitchVectorProperty SimulationSP; ISwitchVectorProperty ConfigProcessSP; ISwitchVectorProperty ConnectionSP; IText DriverInfoT[3]; ITextVectorProperty DriverInfoTP; }; #endif // INDIDEFAULTDRIVER_H libindi-0.9.7/libs/indibase/indidevice.h0000644000175000017500000000632612241463551017116 0ustar jasemjasem/******************************************************************************* Copyright(c) 2010 Gerry Rozema. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. *******************************************************************************/ #ifndef INDIDEVICE_H #define INDIDEVICE_H #include #include #include class IndiDevice : public INDI::DefaultDriver { private: protected: public: IndiDevice(); virtual ~IndiDevice(); // These are the properties we define, that are generic to pretty much all devices // They are public to make them available to all dervied classes and thier children ISwitchVectorProperty ConnectionSV; // Vector of switches for our connection stuff ISwitch ConnectionS[2]; // Helper functions that encapsulate the indi way of doing things // and give us a clean c++ class method virtual int init_properties(); // This will be called after connecting // to flesh out and update properties to the // client when the device is connected virtual bool UpdateProperties(); // A helper for child classes virtual bool DeleteProperty(char *); // A state variable applicable to all devices // and I cant get any intelligent result from the parent // class calling isConnected or setConnected, so, we wont use it bool Connected; int SetTimer(int); void RemoveTimer(int); virtual void TimerHit(); // The function dispatchers required for all drivers virtual void ISGetProperties (const char *dev); virtual bool ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n); virtual bool ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); virtual bool ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); virtual void ISSnoopDevice (XMLEle *root); // some virtual functions that our underlying classes are meant to override virtual bool Connect(); virtual bool Disconnect(); virtual char *getDefaultName()=0; virtual bool SaveConfig(); virtual bool LoadConfig(); virtual bool WritePersistentConfig(FILE *); }; extern IndiDevice *device; extern IndiDevice *_create_device(); #endif // INDIDEVICE_H libindi-0.9.7/libs/indibase/baseclient.cpp0000644000175000017500000004335212241463551017457 0ustar jasemjasem/******************************************************************************* Copyright(c) 2011 Jasem Mutlaq. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "baseclient.h" #include "basedevice.h" #include "indicom.h" #include #define MAXINDIBUF 256 INDI::BaseClient::BaseClient() { cServer = "localhost"; cPort = 7624; svrwfp = NULL; sConnected = false; } INDI::BaseClient::~BaseClient() { // close(m_sendFd); // close(m_receiveFd); } void INDI::BaseClient::setServer(const char * hostname, unsigned int port) { cServer = hostname; cPort = port; } void INDI::BaseClient::watchDevice(const char * deviceName) { cDeviceNames.push_back(deviceName); } bool INDI::BaseClient::connectServer() { struct sockaddr_in serv_addr; struct hostent *hp; int pipefd[2]; int ret = 0; /* lookup host address */ hp = gethostbyname(cServer.c_str()); if (!hp) { herror ("gethostbyname"); return false; } /* create a socket to the INDI server */ (void) memset ((char *)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = ((struct in_addr *)(hp->h_addr_list[0]))->s_addr; serv_addr.sin_port = htons(cPort); if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); return false; } /* connect */ if (::connect (sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0) { perror ("connect"); return false; } /* prepare for line-oriented i/o with client */ svrwfp = fdopen (sockfd, "w"); if (svrwfp == NULL) { perror("fdopen"); return false; } ret = socketpair(PF_UNIX,SOCK_STREAM,0,pipefd); if (ret < 0) { IDLog("notify pipe: %s\n", strerror(errno)); return false; } m_receiveFd = pipefd[0]; m_sendFd = pipefd[1]; int result = pthread_create( &listen_thread, NULL, &INDI::BaseClient::listenHelper, this); if (result != 0) { perror("thread"); return false; } sConnected = true; serverConnected(); return true; } bool INDI::BaseClient::disconnectServer() { //IDLog("Server disconnected called\n"); if (sConnected == false) return true; sConnected = false; shutdown(sockfd, SHUT_RDWR); while (write(m_sendFd,"1",1) <= 0) if (svrwfp != NULL) fclose(svrwfp); svrwfp = NULL; pthread_join(listen_thread, NULL); return true; } void INDI::BaseClient::connectDevice(const char *deviceName) { setDriverConnection(true, deviceName); } void INDI::BaseClient::disconnectDevice(const char *deviceName) { setDriverConnection(false, deviceName); } void INDI::BaseClient::setDriverConnection(bool status, const char *deviceName) { INDI::BaseDevice *drv = getDevice(deviceName); ISwitchVectorProperty *drv_connection = NULL; if (drv == NULL) { IDLog("INDI::BaseClient: Error. Unable to find driver %s\n", deviceName); return; } drv_connection = drv->getSwitch("CONNECTION"); if (drv_connection == NULL) return; // If we need to connect if (status) { // If there is no need to do anything, i.e. already connected. if (drv_connection->sp[0].s == ISS_ON) return; IUResetSwitch(drv_connection); drv_connection->s = IPS_BUSY; drv_connection->sp[0].s = ISS_ON; drv_connection->sp[1].s = ISS_OFF; sendNewSwitch(drv_connection); } else { // If there is no need to do anything, i.e. already disconnected. if (drv_connection->sp[1].s == ISS_ON) return; IUResetSwitch(drv_connection); drv_connection->s = IPS_BUSY; drv_connection->sp[0].s = ISS_OFF; drv_connection->sp[1].s = ISS_ON; sendNewSwitch(drv_connection); } } INDI::BaseDevice * INDI::BaseClient::getDevice(const char * deviceName) { vector::const_iterator devi; for ( devi = cDevices.begin(); devi != cDevices.end(); devi++) if (!strcmp(deviceName, (*devi)->getDeviceName())) return (*devi); return NULL; } void * INDI::BaseClient::listenHelper(void *context) { (static_cast (context))->listenINDI(); return NULL; } void INDI::BaseClient::listenINDI() { char buffer[MAXINDIBUF]; char msg[MAXRBUF]; int n=0, err_code=0; int maxfd=0; fd_set rs; if (cDeviceNames.empty()) fprintf(svrwfp, "\n", INDIV); else { vector::const_iterator stri; for ( stri = cDeviceNames.begin(); stri != cDeviceNames.end(); stri++) fprintf(svrwfp, "\n", INDIV, (*stri).c_str()); } fflush (svrwfp); FD_ZERO(&rs); FD_SET(sockfd, &rs); if (sockfd > maxfd) maxfd = sockfd; FD_SET(m_receiveFd, &rs); if (m_receiveFd > maxfd) maxfd = m_receiveFd; lillp = newLilXML(); /* read from server, exit if find all requested properties */ while (sConnected) { n = select (maxfd+1, &rs, NULL, NULL, NULL); if (n < 0) { fprintf (stderr,"INDI server %s/%d disconnected.\n", cServer.c_str(), cPort); close(sockfd); break; } // Received terminiation string from main thread if (n > 0 && FD_ISSET(m_receiveFd, &rs)) { sConnected = false; break; } if (n > 0 && FD_ISSET(sockfd, &rs)) { n = recv(sockfd, buffer, MAXINDIBUF, MSG_DONTWAIT); if (n<=0) { if (n==0) { fprintf (stderr,"INDI server %s/%d disconnected.\n", cServer.c_str(), cPort); close(sockfd); break; } else continue; } for (int i=0; i < n; i++) { // IDLog("Getting #%d bytes in for loop, calling readXMLEle for byte %d\n", n, i); XMLEle *root = readXMLEle (lillp, buffer[i], msg); //IDLog("############# BLOCK # POST READ XML ELE #####################\n"); if (root) { if ( (err_code = dispatchCommand(root, msg)) < 0) { // Silenty ignore property duplication errors if (err_code != INDI_PROPERTY_DUPLICATED) { IDLog("Dispatch command error(%d): %s\n", err_code, msg); prXMLEle (stderr, root, 0); } } delXMLEle (root); // not yet, delete and continue } else if (msg[0]) { fprintf (stderr, "Bad XML from %s/%d: %s\n%s\n", cServer.c_str(), cPort, msg, buffer); return; } } } } delLilXML(lillp); serverDisconnected( (sConnected == false) ? 0 : -1); sConnected = false; pthread_exit(0); } int INDI::BaseClient::dispatchCommand(XMLEle *root, char * errmsg) { if (!strcmp (tagXMLEle(root), "message")) return messageCmd(root, errmsg); else if (!strcmp (tagXMLEle(root), "delProperty")) return delPropertyCmd(root, errmsg); /* Get the device, if not available, create it */ INDI::BaseDevice *dp = findDev (root, 1, errmsg); if (dp == NULL) { strcpy(errmsg,"No device available and none was created"); return INDI_DEVICE_NOT_FOUND; } // FIXME REMOVE THIS // Ignore echoed newXXX if (strstr(tagXMLEle(root), "new")) return 0; if ((!strcmp (tagXMLEle(root), "defTextVector")) || (!strcmp (tagXMLEle(root), "defNumberVector")) || (!strcmp (tagXMLEle(root), "defSwitchVector")) || (!strcmp (tagXMLEle(root), "defLightVector")) || (!strcmp (tagXMLEle(root), "defBLOBVector"))) return dp->buildProp(root, errmsg); else if (!strcmp (tagXMLEle(root), "setTextVector") || !strcmp (tagXMLEle(root), "setNumberVector") || !strcmp (tagXMLEle(root), "setSwitchVector") || !strcmp (tagXMLEle(root), "setLightVector") || !strcmp (tagXMLEle(root), "setBLOBVector")) return dp->setValue(root, errmsg); return INDI_DISPATCH_ERROR; } /* delete the property in the given device, including widgets and data structs. * when last property is deleted, delete the device too. * if no property name attribute at all, delete the whole device regardless. * return 0 if ok, else -1 with reason in errmsg[]. */ int INDI::BaseClient::delPropertyCmd (XMLEle *root, char * errmsg) { XMLAtt *ap; INDI::BaseDevice *dp; /* dig out device and optional property name */ dp = findDev (root, 0, errmsg); if (!dp) return INDI_DEVICE_NOT_FOUND; dp->checkMessage(root); ap = findXMLAtt (root, "name"); /* Delete property if it exists, otherwise, delete the whole device */ if (ap) { INDI::Property *rProp = dp->getProperty(valuXMLAtt(ap)); removeProperty(rProp); int errCode = dp->removeProperty(valuXMLAtt(ap), errmsg); return errCode; } // delete the whole device else return removeDevice(dp->getDeviceName(), errmsg); } int INDI::BaseClient::removeDevice( const char * devName, char * errmsg ) { std::vector::iterator devicei; for (devicei =cDevices.begin(); devicei != cDevices.end();) { if (!strcmp(devName, (*devicei)->getDeviceName())) { delete *devicei; devicei = cDevices.erase(devicei); return 0; } else ++devicei; } snprintf(errmsg, MAXRBUF, "Device %s not found", devName); return INDI_DEVICE_NOT_FOUND; } INDI::BaseDevice * INDI::BaseClient::findDev( const char * devName, char * errmsg ) { std::vector::const_iterator devicei; for (devicei = cDevices.begin(); devicei != cDevices.end(); devicei++) { if (!strcmp(devName, (*devicei)->getDeviceName())) return (*devicei); } snprintf(errmsg, MAXRBUF, "Device %s not found", devName); return NULL; } /* add new device */ INDI::BaseDevice * INDI::BaseClient::addDevice (XMLEle *dep, char * errmsg) { //devicePtr dp(new INDI::BaseDriver()); INDI::BaseDevice *dp = new INDI::BaseDevice(); XMLAtt *ap; char * device_name; /* allocate new INDI::BaseDriver */ ap = findXMLAtt (dep, "device"); if (!ap) { strncpy(errmsg, "Unable to find device attribute in XML element. Cannot add device.", MAXRBUF); return NULL; } device_name = valuXMLAtt(ap); dp->setMediator(this); dp->setDeviceName(device_name); cDevices.push_back(dp); newDevice(dp); /* ok */ return dp; } INDI::BaseDevice * INDI::BaseClient::findDev (XMLEle *root, int create, char * errmsg) { XMLAtt *ap; INDI::BaseDevice *dp; char *dn; /* get device name */ ap = findXMLAtt (root, "device"); if (!ap) { snprintf(errmsg, MAXRBUF, "No device attribute found in element %s", tagXMLEle(root)); return (NULL); } dn = valuXMLAtt(ap); dp = findDev(dn, errmsg); if (dp) return dp; /* not found, create if ok */ if (create) return (addDevice (root, errmsg)); snprintf(errmsg, MAXRBUF, "INDI: <%s> no such device %s", tagXMLEle(root), dn); return NULL; } /* a general message command received from the device. * return 0 if ok, else -1 with reason in errmsg[]. */ int INDI::BaseClient::messageCmd (XMLEle *root, char * errmsg) { INDI::BaseDevice *dp =findDev (root, 0, errmsg); if (dp) dp->checkMessage(root); return (0); } void INDI::BaseClient::sendNewText (ITextVectorProperty *tvp) { tvp->s = IPS_BUSY; fprintf(svrwfp, "device); fprintf(svrwfp, " name='%s'\n>", tvp->name); for (int i=0; i < tvp->ntp; i++) { fprintf(svrwfp, " \n", tvp->tp[i].name); fprintf(svrwfp, " %s\n", tvp->tp[i].text); fprintf(svrwfp, " \n"); } fprintf(svrwfp, "\n"); fflush(svrwfp); } void INDI::BaseClient::sendNewText (const char * deviceName, const char * propertyName, const char* elementName, const char *text) { INDI::BaseDevice *drv = getDevice(deviceName); if (drv == NULL) return; ITextVectorProperty *tvp = drv->getText(propertyName); if (tvp == NULL) return; IText * tp = IUFindText(tvp, elementName); if (tp == NULL) return; IUSaveText(tp, text); sendNewText(tvp); } void INDI::BaseClient::sendNewNumber (INumberVectorProperty *nvp) { setlocale(LC_NUMERIC,"C"); nvp->s = IPS_BUSY; fprintf(svrwfp, "device); fprintf(svrwfp, " name='%s'\n>", nvp->name); for (int i=0; i < nvp->nnp; i++) { fprintf(svrwfp, " \n", nvp->np[i].name); fprintf(svrwfp, " %g\n", nvp->np[i].value); fprintf(svrwfp, " \n"); } fprintf(svrwfp, "\n"); fflush(svrwfp); setlocale(LC_NUMERIC,""); } void INDI::BaseClient::sendNewNumber (const char *deviceName, const char *propertyName, const char* elementName, double value) { INDI::BaseDevice *drv = getDevice(deviceName); if (drv == NULL) return; INumberVectorProperty *nvp = drv->getNumber(propertyName); if (nvp == NULL) return; INumber * np = IUFindNumber(nvp, elementName); if (np == NULL) return; np->value = value; sendNewNumber(nvp); } void INDI::BaseClient::sendNewSwitch (ISwitchVectorProperty *svp) { svp->s = IPS_BUSY; ISwitch *onSwitch = IUFindOnSwitch(svp); fprintf(svrwfp, "device); fprintf(svrwfp, " name='%s'>\n", svp->name); if (svp->r == ISR_1OFMANY && onSwitch) { fprintf(svrwfp, " \n", onSwitch->name); fprintf(svrwfp, " %s\n", (onSwitch->s == ISS_ON) ? "On" : "Off"); fprintf(svrwfp, " \n"); } else { for (int i=0; i < svp->nsp; i++) { fprintf(svrwfp, " \n", svp->sp[i].name); fprintf(svrwfp, " %s\n", (svp->sp[i].s == ISS_ON) ? "On" : "Off"); fprintf(svrwfp, " \n"); } } fprintf(svrwfp, "\n"); fflush(svrwfp); } void INDI::BaseClient::sendNewSwitch (const char *deviceName, const char *propertyName, const char *elementName) { INDI::BaseDevice *drv = getDevice(deviceName); if (drv == NULL) return; ISwitchVectorProperty *svp = drv->getSwitch(propertyName); if (svp == NULL) return; ISwitch * sp = IUFindSwitch(svp, elementName); if (sp == NULL) return; sp->s = ISS_ON; sendNewSwitch(svp); } void INDI::BaseClient::startBlob( const char *devName, const char *propName, const char *timestamp) { fprintf(svrwfp, "\n", timestamp); } void INDI::BaseClient::sendOneBlob( const char *blobName, unsigned int blobSize, const char *blobFormat, void * blobBuffer) { fprintf(svrwfp, " \n", blobFormat); for (unsigned i = 0; i < blobSize; i += 72) fprintf(svrwfp, " %.72s\n", ((char *) blobBuffer+i)); fprintf(svrwfp, " \n"); } void INDI::BaseClient::finishBlob() { fprintf(svrwfp, "\n"); fflush(svrwfp); } void INDI::BaseClient::setBLOBMode(BLOBHandling blobH, const char *dev, const char *prop) { char blobOpenTag[MAXRBUF]; if (!dev[0]) return; if (prop != NULL) snprintf(blobOpenTag, MAXRBUF, "", dev, prop); else snprintf(blobOpenTag, MAXRBUF, "", dev); switch (blobH) { case B_NEVER: fprintf(svrwfp, "%sNever\n", blobOpenTag); break; case B_ALSO: fprintf(svrwfp, "%sAlso\n", blobOpenTag); break; case B_ONLY: fprintf(svrwfp, "%sOnly\n", blobOpenTag); break; } fflush(svrwfp); } libindi-0.9.7/libs/lilxml.h0000644000175000017500000002442712241463551014540 0ustar jasemjasem#if 0 liblilxml Copyright (C) 2003 Elwood C. Downey 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 /** \file lilxml.h \brief A little DOM-style library to handle parsing and processing an XML file. It only handles elements, attributes and pcdata content. and are silently ignored. pcdata is collected into one string, sans leading whitespace first line. \n The following is an example of a cannonical usage for the lilxml library. Initialize a lil xml context and read an XML file in a root element. \code #include LilXML *lp = newLilXML(); char errmsg[1024]; XMLEle *root, *ep; int c; while ((c = fgetc(stdin)) != EOF) { root = readXMLEle (lp, c, errmsg); if (root) break; if (errmsg[0]) error ("Error: %s\n", errmsg); } // print the tag and pcdata content of each child element within the root for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0)) printf ("%s: %s\n", tagXMLEle(ep), pcdataXMLEle(ep)); // finished with root element and with lil xml context delXMLEle (root); delLilXML (lp); \endcode */ #ifndef LILXML_H #define LILXML_H #include #ifdef __cplusplus extern "C" { #endif /* opaque handle types */ typedef struct _xml_att XMLAtt; typedef struct _xml_ele XMLEle; typedef struct _LilXML LilXML; /** * \defgroup lilxmlFunctions XML Functions: Functions to parse, process, and search XML. */ /*@{*/ /* creation and destruction functions */ /** \brief Create a new lilxml parser. \return a pointer to the lilxml parser on success. NULL on failure. */ extern LilXML *newLilXML(void); /** \brief Delete a lilxml parser. \param lp a pointer to a lilxml parser to be deleted. */ extern void delLilXML (LilXML *lp); /** \brief Delete an XML element. \return a pointer to the XML Element to be deleted. */ extern void delXMLEle (XMLEle *e); /** \brief Process an XML one char at a time. \param lp a pointer to a lilxml parser. \param c one character to process. \param errmsg a buffer to store error messages if an error in parsing is encounterd. \return When the function parses a complete valid XML element, it will return a pointer to the XML element. A NULL is returned when parsing the element is still in progress, or if a parsing error occurs. Check errmsg for errors if NULL is returned. */ extern XMLEle *readXMLEle (LilXML *lp, int c, char errmsg[]); /* search functions */ /** \brief Find an XML attribute within an XML element. \param e a pointer to the XML element to search. \param name the attribute name to search for. \return A pointer to the XML attribute if found or NULL on failure. */ extern XMLAtt *findXMLAtt (XMLEle *e, const char *name); /** \brief Find an XML element within an XML element. \param e a pointer to the XML element to search. \param tag the element tag to search for. \return A pointer to the XML element if found or NULL on failure. */ extern XMLEle *findXMLEle (XMLEle *e, const char *tag); /* iteration functions */ /** \brief Iterate an XML element for a list of nesetd XML elements. \param ep a pointer to the XML element to iterate. \param first the index of the starting XML element. Pass 1 to start iteration from the beginning of the XML element. Pass 0 to get the next element thereater. \return On success, a pointer to the next XML element is returned. NULL when there are no more elements. */ extern XMLEle *nextXMLEle (XMLEle *ep, int first); /** \brief Iterate an XML element for a list of XML attributes. \param ep a pointer to the XML element to iterate. \param first the index of the starting XML attribute. Pass 1 to start iteration from the beginning of the XML element. Pass 0 to get the next attribute thereater. \return On success, a pointer to the next XML attribute is returned. NULL when there are no more attributes. */ extern XMLAtt *nextXMLAtt (XMLEle *ep, int first); /* tree functions */ /** \brief Return the parent of an XML element. \return a pointer to the XML element parent. */ extern XMLEle *parentXMLEle (XMLEle *ep); /** \brief Return the parent of an XML attribute. \return a pointer to the XML element parent. */ extern XMLEle *parentXMLAtt (XMLAtt *ap); /* access functions */ /** \brief Return the tag of an XML element. \param ep a pointer to an XML element. \return the tag string. */ extern char *tagXMLEle (XMLEle *ep); /** \brief Return the pcdata of an XML element. \param ep a pointer to an XML element. \return the pcdata string on success. */ extern char *pcdataXMLEle (XMLEle *ep); /** \brief Return the name of an XML attribute. \param ap a pointer to an XML attribute. \return the name string of the attribute. */ extern char *nameXMLAtt (XMLAtt *ap); /** \brief Return the value of an XML attribute. \param ap a pointer to an XML attribute. \return the value string of the attribute. */ extern char *valuXMLAtt (XMLAtt *ap); /** \brief Return the number of characters in pcdata in an XML element. \param ep a pointer to an XML element. \return the length of the pcdata string. */ extern int pcdatalenXMLEle (XMLEle *ep); /** \brief Return the number of nested XML elements in a parent XML element. \param ep a pointer to an XML element. \return the number of nested XML elements. */ extern int nXMLEle (XMLEle *ep); /** \brief Return the number of XML attributes in a parent XML element. \param ep a pointer to an XML element. \return the number of XML attributes within the XML element. */ extern int nXMLAtt (XMLEle *ep); /* editing functions */ /** \brief add an element with the given tag to the given element. parent can be NULL to make a new root. \return if parent is NULL, a new root is returned, otherwise, parent is returned. */ extern XMLEle *addXMLEle (XMLEle *parent, const char *tag); /** \brief set the pcdata of the given element \param ep pointer to an XML element. \param pcdata pcdata to set. */ extern void editXMLEle (XMLEle *ep, const char *pcdata); /** \brief Add an XML attribute to an existing XML element. \param ep pointer to an XML element \param name the name of the XML attribute to add. \param value the value of the XML attribute to add. */ extern XMLAtt* addXMLAtt (XMLEle *ep, const char *name, const char *value); /** \brief Remove an XML attribute from an XML element. \param ep pointer to an XML element. \param name the name of the XML attribute to remove */ extern void rmXMLAtt (XMLEle *ep, const char *name); /** \brief change the value of an attribute to str. * \param ap pointer to XML attribute * \param str new attribute value */ extern void editXMLAtt (XMLAtt *ap, const char *str); /** \brief return a string with all xml-sensitive characters within the passed string replaced with their entity sequence equivalents. * N.B. caller must use the returned string before calling us again. */ extern char *entityXML (char *str); /* convenience functions */ /** \brief Find an XML element's attribute value. \param ep a pointer to an XML element. \param name the name of the XML attribute to retrieve its value. \return the value string of an XML element on success. NULL on failure. */ extern const char *findXMLAttValu (XMLEle *ep, const char *name); /** \brief Handy wrapper to read one xml file. \param fp pointer to FILE to read. \param lp pointer to lilxml parser. \param errmsg a buffer to store error messages on failure. \return root element else NULL with report in errmsg[]. */ extern XMLEle *readXMLFile (FILE *fp, LilXML *lp, char errmsg[]); /** \brief Print an XML element. \param fp a pointer to FILE where the print output is directed. \param e the XML element to print. \param level the printing level, set to 0 to print the whole element. */ extern void prXMLEle (FILE *fp, XMLEle *e, int level); /** \brief sample print ep to string s. * N.B. s must be at least as large as that reported by sprlXMLEle()+1. * N.B. set level = 0 on first call. * \return return length of resulting string (sans trailing @\0@) */ extern int sprXMLEle (char *s, XMLEle *ep, int level); /** \brief return number of bytes in a string guaranteed able to hold result of sprXLMEle(ep) (sans trailing @\0@). * N.B. set level = 0 on first call. */ extern int sprlXMLEle (XMLEle *ep, int level); /* install alternatives to malloc/realloc/free */ extern void indi_xmlMalloc (void *(*newmalloc)(size_t size), void *(*newrealloc)(void *ptr, size_t size), void (*newfree)(void *ptr)); /*@}*/ #ifdef __cplusplus } #endif /* examples. initialize a lil xml context and read an XML file in a root element LilXML *lp = newLilXML(); char errmsg[1024]; XMLEle *root, *ep; int c; while ((c = fgetc(stdin)) != EOF) { root = readXMLEle (lp, c, errmsg); if (root) break; if (errmsg[0]) error ("Error: %s\n", errmsg); } print the tag and pcdata content of each child element within the root for (ep = nextXMLEle (root, 1); ep != NULL; ep = nextXMLEle (root, 0)) printf ("%s: %s\n", tagXMLEle(ep), pcdataXMLEle(ep)); finished with root element and with lil xml context delXMLEle (root); delLilXML (lp); */ /* For RCS Only -- Do Not Edit * @(#) $RCSfile$ $Date: 2007-09-17 16:34:48 +0300 (Mon, 17 Sep 2007) $ $Revision: 713418 $ $Name: $ */ #endif /* LILXML_H */ libindi-0.9.7/libs/webcam/0000755000175000017500000000000012241463551014313 5ustar jasemjasemlibindi-0.9.7/libs/webcam/pwc-ioctl.h0000644000175000017500000002523712241463551016376 0ustar jasemjasem#ifndef PWC_IOCTL_H #define PWC_IOCTL_H /* (C) 2001-2004 Nemosoft Unv. (C) 2004-2006 Luc Saillard (luc@saillard.org) NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx driver and thus may have bugs that are not present in the original version. Please send bug reports and support requests to . The decompression routines have been implemented by reverse-engineering the Nemosoft binary pwcx module. Caveat emptor. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* This is pwc-ioctl.h belonging to PWC 10.0.10 It contains structures and defines to communicate from user space directly to the driver. */ /* Changes 2001/08/03 Alvarado Added ioctl constants to access methods for changing white balance and red/blue gains 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE 2003/12/13 Nemosft Unv. Some modifications to make interfacing to PWCX easier 2006/01/01 Luc Saillard Add raw format definition */ /* These are private ioctl() commands, specific for the Philips webcams. They contain functions not found in other webcams, and settings not specified in the Video4Linux API. The #define names are built up like follows: VIDIOC VIDeo IOCtl prefix PWC Philps WebCam G optional: Get S optional: Set ... the function */ #include /* Enumeration of image sizes */ #define PSZ_SQCIF 0x00 #define PSZ_QSIF 0x01 #define PSZ_QCIF 0x02 #define PSZ_SIF 0x03 #define PSZ_CIF 0x04 #define PSZ_VGA 0x05 #define PSZ_MAX 6 /* The frame rate is encoded in the video_window.flags parameter using the upper 16 bits, since some flags are defined nowadays. The following defines provide a mask and shift to filter out this value. This value can also be passing using the private flag when using v4l2 and VIDIOC_S_FMT ioctl. In 'Snapshot' mode the camera freezes its automatic exposure and colour balance controls. */ #define PWC_FPS_SHIFT 16 #define PWC_FPS_MASK 0x00FF0000 #define PWC_FPS_FRMASK 0x003F0000 #define PWC_FPS_SNAPSHOT 0x00400000 #define PWC_QLT_MASK 0x03000000 #define PWC_QLT_SHIFT 24 /* structure for transferring x & y coordinates */ struct pwc_coord { int x, y; /* guess what */ int size; /* size, or offset */ }; /* Used with VIDIOCPWCPROBE */ struct pwc_probe { char name[32]; int type; }; struct pwc_serial { char serial[30]; /* String with serial number. Contains terminating 0 */ }; /* pwc_whitebalance.mode values */ #define PWC_WB_INDOOR 0 #define PWC_WB_OUTDOOR 1 #define PWC_WB_FL 2 #define PWC_WB_MANUAL 3 #define PWC_WB_AUTO 4 /* Used with VIDIOCPWC[SG]AWB (Auto White Balance). Set mode to one of the PWC_WB_* values above. *red and *blue are the respective gains of these colour components inside the camera; range 0..65535 When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; otherwise undefined. 'read_red' and 'read_blue' are read-only. */ struct pwc_whitebalance { int mode; int manual_red, manual_blue; /* R/W */ int read_red, read_blue; /* R/O */ }; /* 'control_speed' and 'control_delay' are used in automatic whitebalance mode, and tell the camera how fast it should react to changes in lighting, and with how much delay. Valid values are 0..65535. */ struct pwc_wb_speed { int control_speed; int control_delay; }; /* Used with VIDIOCPWC[SG]LED */ struct pwc_leds { int led_on; /* Led on-time; range = 0..25000 */ int led_off; /* Led off-time; range = 0..25000 */ }; /* Image size (used with GREALSIZE) */ struct pwc_imagesize { int width; int height; }; /* Defines and structures for Motorized Pan & Tilt */ #define PWC_MPT_PAN 0x01 #define PWC_MPT_TILT 0x02 #define PWC_MPT_TIMEOUT 0x04 /* for status */ /* Set angles; when absolute != 0, the angle is absolute and the driver calculates the relative offset for you. This can only be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns absolute angles. */ struct pwc_mpt_angles { int absolute; /* write-only */ int pan; /* degrees * 100 */ int tilt; /* degress * 100 */ }; /* Range of angles of the camera, both horizontally and vertically. */ struct pwc_mpt_range { int pan_min, pan_max; /* degrees * 100 */ int tilt_min, tilt_max; }; struct pwc_mpt_status { int status; int time_pan; int time_tilt; }; /* This is used for out-of-kernel decompression. With it, you can get all the necessary information to initialize and use the decompressor routines in standalone applications. */ struct pwc_video_command { int type; /* camera type (645, 675, 730, etc.) */ int release; /* release number */ int size; /* one of PSZ_* */ int alternate; int command_len; /* length of USB video command */ unsigned char command_buf[13]; /* Actual USB video command */ int bandlength; /* >0 = compressed */ int frame_size; /* Size of one (un)compressed frame */ }; /* Flags for PWCX subroutines. Not all modules honor all flags. */ #define PWCX_FLAG_PLANAR 0x0001 #define PWCX_FLAG_BAYER 0x0008 /* IOCTL definitions */ /* Restore user settings */ #define VIDIOCPWCRUSER _IO('v', 192) /* Save user settings */ #define VIDIOCPWCSUSER _IO('v', 193) /* Restore factory settings */ #define VIDIOCPWCFACTORY _IO('v', 194) /* You can manipulate the compression factor. A compression preference of 0 means use uncompressed modes when available; 1 is low compression, 2 is medium and 3 is high compression preferred. Of course, the higher the compression, the lower the bandwidth used but more chance of artefacts in the image. The driver automatically chooses a higher compression when the preferred mode is not available. */ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ #define VIDIOCPWCSCQUAL _IOW('v', 195, int) /* Get preferred compression quality */ #define VIDIOCPWCGCQUAL _IOR('v', 195, int) /* Retrieve serial number of camera */ #define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) /* This is a probe function; since so many devices are supported, it becomes difficult to include all the names in programs that want to check for the enhanced Philips stuff. So in stead, try this PROBE; it returns a structure with the original name, and the corresponding Philips type. To use, fill the structure with zeroes, call PROBE and if that succeeds, compare the name with that returned from VIDIOCGCAP; they should be the same. If so, you can be assured it is a Philips (OEM) cam and the type is valid. */ #define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ #define VIDIOCPWCSAGC _IOW('v', 200, int) /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ #define VIDIOCPWCGAGC _IOR('v', 200, int) /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ #define VIDIOCPWCSSHUTTER _IOW('v', 201, int) /* Color compensation (Auto White Balance) */ #define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) #define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) /* Auto WB speed */ #define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) #define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) /* LEDs on/off/blink; int range 0..65535 */ #define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) #define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ #define VIDIOCPWCSCONTOUR _IOW('v', 206, int) #define VIDIOCPWCGCONTOUR _IOR('v', 206, int) /* Backlight compensation; 0 = off, otherwise on */ #define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) #define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) /* Flickerless mode; = 0 off, otherwise on */ #define VIDIOCPWCSFLICKER _IOW('v', 208, int) #define VIDIOCPWCGFLICKER _IOR('v', 208, int) /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ #define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) #define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ #define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) /* Motorized pan & tilt functions */ #define VIDIOCPWCMPTRESET _IOW('v', 211, int) #define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) #define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) #define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) #define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) /* Get the USB set-video command; needed for initializing libpwcx */ #define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) struct pwc_table_init_buffer { int len; char *buffer; }; #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) /* * This is private command used when communicating with v4l2. * In the future all private ioctl will be remove/replace to * use interface offer by v4l2. */ #define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) #define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) #define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) #define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) #define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) #define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) #define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) #define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) #define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) struct pwc_raw_frame { unsigned short type; /* type of the webcam */ unsigned short vbandlength; /* Size of 4lines compressed (used by the decompressor) */ unsigned char cmd[4]; /* the four byte of the command (in case of nala version, only the first 3 bytes is filled) */ #ifndef __cplusplus unsigned char rawframe[0]; /* frame_size = H/4*vbandlength */ #endif } __attribute__ ((packed)); #endif libindi-0.9.7/libs/webcam/vcvt.h0000644000175000017500000000454512241463551015456 0ustar jasemjasem/* (C) 2001 Nemosoft Unv. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* 'Viewport' conversion routines. These functions convert from one colour space to another, taking into account that the source image has a smaller size than the view, and is placed inside the view: +-------view.x------------+ | | | +---image.x---+ | | | | | | | | | | +-------------+ | | | +-------------------------+ The image should always be smaller than the view. The offset (top-left corner of the image) should be precomputed, so you can place the image anywhere in the view. The functions take these parameters: - width image width (in pixels) - height image height (in pixels) - plus view width (in pixels) *src pointer at start of image *dst pointer at offset (!) in view */ #ifndef VCVT_H #define VCVT_H #ifdef __cplusplus extern "C" { #endif /* Functions in vcvt_i386.S/vcvt_c.c */ /* 4:2:0 YUV interlaced to RGB/BGR */ void vcvt_420i_bgr24(int width, int height, int plus, void *src, void *dst); void vcvt_420i_rgb24(int width, int height, int plus, void *src, void *dst); void vcvt_420i_bgr32(int width, int height, int plus, void *src, void *dst); void vcvt_420i_rgb32(int width, int height, int plus, void *src, void *dst); /* Go from 420i to other yuv formats */ void vcvt_420i_420p(int width, int height, int plus, void *src, void *dsty, void *dstu, void *dstv); void vcvt_420i_yuyv(int width, int height, int plus, void *src, void *dst); #if 0 #endif #ifdef __cplusplus } #endif #endif libindi-0.9.7/libs/webcam/PPort.h0000644000175000017500000000512112241463551015527 0ustar jasemjasem/* Copyright (C) 2004 by Jasem Mutlaq 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 */ #ifndef _PPort_hpp_ #define _PPort_hpp_ class port_t; /** To access and share the parallel port between severa objects. */ class PPort { public: PPort(); PPort(int ioPort); ~PPort(); /** set the ioport associated to the // port. \return true if the binding was possible */ bool setPort(int ioPort); /** set a data bit of the // port. \return false if IO port not set, or bit not registered by ID. \param ID the identifier used to register the bit \param stat the stat wanted for the given bit \param bit the bit to set. They are numbered from 0 to 7. */ bool setBit(const void * ID,int bit,bool stat); /** register a bit for object ID. \param ID the identifier used to register the bit it should be the 'this' pointer. \param bit the bit of the // port to register \return false if the bit is already register with an other ID, or if the // port is not initialised. */ bool registerBit(const void * ID,int bit); /** release a bit. \param ID the identifier used to register the bit \param bit the bit to register. \return false if the bit was not registered by ID or if the if the // port is not initialised. */ bool unregisterBit(const void * ID,int bit); /** test if a bit is registerd. \param ID the identifier used to register the bit \param bit the bit to test. \return false if the bit was not registered by ID or if the if the // port is not initialised. */ bool isRegisterBit(const void * ID,int bit) const; /** set the bits off the // port according to previous call to setBit(). */ bool commit(); private: void reset(); unsigned char bitArray; const void * assignedBit[8]; port_t * currentPort; }; #endif libindi-0.9.7/libs/webcam/ccvt_types.h0000644000175000017500000000275212241463551016655 0ustar jasemjasem/* CCVT: ColourConVerT: simple library for converting colourspaces Copyright (C) 2002 Nemosoft Unv. Email:athomas@nemsoft.co.uk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA For questions, remarks, patches, etc. for this program, the author can be reached at nemosoft@smcc.demon.nl. */ #ifndef CCVT_TYPES_H #define CCVT_TYPES_H typedef struct { unsigned char b; unsigned char g; unsigned char r; unsigned char z; } PIXTYPE_bgr32; typedef struct { unsigned char b; unsigned char g; unsigned char r; } PIXTYPE_bgr24; typedef struct { unsigned char r; unsigned char g; unsigned char b; unsigned char z; } PIXTYPE_rgb32; typedef struct { unsigned char r; unsigned char g; unsigned char b; } PIXTYPE_rgb24; #define SAT(c) \ if (c & (~255)) { if (c < 0) c = 0; else c = 255; } #endif libindi-0.9.7/libs/webcam/PPort.cpp0000644000175000017500000000455612241463551016075 0ustar jasemjasem/* Copyright (C) 1996-1998 by Patrick Reynolds Email: 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 */ #include "PPort.h" #include "port.h" #include #include #include using namespace std; #define TEST_VALIDITY {if (this==NULL) return false;} PPort::PPort() { reset(); } PPort::PPort(int ioPort) { reset(); setPort(ioPort); } PPort::~PPort() { delete currentPort; } void PPort::reset() { bitArray=0; for (int i=0;i<8;++i) { assignedBit[i]=NULL; } currentPort=NULL; } bool PPort::setPort(int ioPort) { TEST_VALIDITY; if (geteuid() != 0) { cerr << "must be setuid root control parallel port"<write_data(bitArray); return true; } else { return false; } } bool PPort::setBit(const void * ID,int bit,bool stat) { TEST_VALIDITY; if (ID != assignedBit[bit]) { return false; } if (stat) { bitArray |= (1< * Justin Schoeman * Hans Verkuil * et al. */ #ifndef __LINUX_VIDEODEV2_H #define __LINUX_VIDEODEV2_H #include #include #include /* * Common stuff for both V4L1 and V4L2 * Moved from videodev.h */ #define VIDEO_MAX_FRAME 32 #define VIDEO_MAX_PLANES 8 /* These defines are V4L1 specific and should not be used with the V4L2 API! They will be removed from this header in the future. */ #define VID_TYPE_CAPTURE 1 /* Can capture */ #define VID_TYPE_TUNER 2 /* Can tune */ #define VID_TYPE_TELETEXT 4 /* Does teletext */ #define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ #define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ #define VID_TYPE_CLIPPING 32 /* Can clip */ #define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ #define VID_TYPE_SCALES 128 /* Scalable */ #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ #define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ #define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ #define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ #define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ #define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ /* * M I S C E L L A N E O U S */ /* Four-character-code (FOURCC) */ #define v4l2_fourcc(a, b, c, d)\ ((__u32)(a) | ((__u32)(b) << 8) | ((__u32)(c) << 16) | ((__u32)(d) << 24)) /* * E N U M S */ enum v4l2_field { V4L2_FIELD_ANY = 0, /* driver can choose from none, top, bottom, interlaced depending on whatever it thinks is approximate ... */ V4L2_FIELD_NONE = 1, /* this device has no fields ... */ V4L2_FIELD_TOP = 2, /* top field only */ V4L2_FIELD_BOTTOM = 3, /* bottom field only */ V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one buffer, top-bottom order */ V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ V4L2_FIELD_ALTERNATE = 7, /* both fields alternating into separate buffers */ V4L2_FIELD_INTERLACED_TB = 8, /* both fields interlaced, top field first and the top field is transmitted first */ V4L2_FIELD_INTERLACED_BT = 9, /* both fields interlaced, top field first and the bottom field is transmitted first */ }; #define V4L2_FIELD_HAS_TOP(field) \ ((field) == V4L2_FIELD_TOP ||\ (field) == V4L2_FIELD_INTERLACED ||\ (field) == V4L2_FIELD_INTERLACED_TB ||\ (field) == V4L2_FIELD_INTERLACED_BT ||\ (field) == V4L2_FIELD_SEQ_TB ||\ (field) == V4L2_FIELD_SEQ_BT) #define V4L2_FIELD_HAS_BOTTOM(field) \ ((field) == V4L2_FIELD_BOTTOM ||\ (field) == V4L2_FIELD_INTERLACED ||\ (field) == V4L2_FIELD_INTERLACED_TB ||\ (field) == V4L2_FIELD_INTERLACED_BT ||\ (field) == V4L2_FIELD_SEQ_TB ||\ (field) == V4L2_FIELD_SEQ_BT) #define V4L2_FIELD_HAS_BOTH(field) \ ((field) == V4L2_FIELD_INTERLACED ||\ (field) == V4L2_FIELD_INTERLACED_TB ||\ (field) == V4L2_FIELD_INTERLACED_BT ||\ (field) == V4L2_FIELD_SEQ_TB ||\ (field) == V4L2_FIELD_SEQ_BT) enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, V4L2_BUF_TYPE_VBI_CAPTURE = 4, V4L2_BUF_TYPE_VBI_OUTPUT = 5, V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, #if 1 /* Experimental */ V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8, #endif V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE = 10, V4L2_BUF_TYPE_PRIVATE = 0x80, }; #define V4L2_TYPE_IS_MULTIPLANAR(type) \ ((type) == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE \ || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) #define V4L2_TYPE_IS_OUTPUT(type) \ ((type) == V4L2_BUF_TYPE_VIDEO_OUTPUT \ || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE \ || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY \ || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY \ || (type) == V4L2_BUF_TYPE_VBI_OUTPUT \ || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) enum v4l2_tuner_type { V4L2_TUNER_RADIO = 1, V4L2_TUNER_ANALOG_TV = 2, V4L2_TUNER_DIGITAL_TV = 3, }; enum v4l2_memory { V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR = 2, V4L2_MEMORY_OVERLAY = 3, }; /* see also http://vektor.theorem.ca/graphics/ycbcr/ */ enum v4l2_colorspace { /* ITU-R 601 -- broadcast NTSC/PAL */ V4L2_COLORSPACE_SMPTE170M = 1, /* 1125-Line (US) HDTV */ V4L2_COLORSPACE_SMPTE240M = 2, /* HD and modern captures. */ V4L2_COLORSPACE_REC709 = 3, /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ V4L2_COLORSPACE_BT878 = 4, /* These should be useful. Assume 601 extents. */ V4L2_COLORSPACE_470_SYSTEM_M = 5, V4L2_COLORSPACE_470_SYSTEM_BG = 6, /* I know there will be cameras that send this. So, this is * unspecified chromaticities and full 0-255 on each of the * Y'CbCr components */ V4L2_COLORSPACE_JPEG = 7, /* For RGB colourspaces, this is probably a good start. */ V4L2_COLORSPACE_SRGB = 8, }; enum v4l2_priority { V4L2_PRIORITY_UNSET = 0, /* not initialized */ V4L2_PRIORITY_BACKGROUND = 1, V4L2_PRIORITY_INTERACTIVE = 2, V4L2_PRIORITY_RECORD = 3, V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE, }; struct v4l2_rect { __s32 left; __s32 top; __s32 width; __s32 height; }; struct v4l2_fract { __u32 numerator; __u32 denominator; }; /** * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP * * @driver: name of the driver module (e.g. "bttv") * @card: name of the card (e.g. "Hauppauge WinTV") * @bus_info: name of the bus (e.g. "PCI:" + pci_name(pci_dev) ) * @version: KERNEL_VERSION * @capabilities: capabilities of the physical device as a whole * @device_caps: capabilities accessed via this particular device (node) * @reserved: reserved fields for future extensions */ struct v4l2_capability { __u8 driver[16]; __u8 card[32]; __u8 bus_info[32]; __u32 version; __u32 capabilities; __u32 device_caps; __u32 reserved[3]; }; /* Values for 'capabilities' field */ #define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ #define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ #define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ #define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a raw VBI capture device */ #define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a raw VBI output device */ #define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /* Is a sliced VBI capture device */ #define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */ #define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ #define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */ #define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */ #define V4L2_CAP_RDS_OUTPUT 0x00000800 /* Is an RDS encoder */ /* Is a video capture device that supports multiplanar formats */ #define V4L2_CAP_VIDEO_CAPTURE_MPLANE 0x00001000 /* Is a video output device that supports multiplanar formats */ #define V4L2_CAP_VIDEO_OUTPUT_MPLANE 0x00002000 #define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ #define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ #define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ #define V4L2_CAP_MODULATOR 0x00080000 /* has a modulator */ #define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ #define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ #define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ #define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */ /* * V I D E O I M A G E F O R M A T */ struct v4l2_pix_format { __u32 width; __u32 height; __u32 pixelformat; __u32 field; /* enum v4l2_field */ __u32 bytesperline; /* for padding, zero if unused */ __u32 sizeimage; __u32 colorspace; /* enum v4l2_colorspace */ __u32 priv; /* private data, depends on pixelformat */ }; /* Pixel format FOURCC depth Description */ /* RGB formats */ #define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R', 'G', 'B', '1') /* 8 RGB-3-3-2 */ #define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ #define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */ #define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */ #define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */ #define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */ #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */ /* Grey formats */ #define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */ #define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */ #define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */ #define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */ #define V4L2_PIX_FMT_Y12 v4l2_fourcc('Y', '1', '2', ' ') /* 12 Greyscale */ #define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */ /* Grey bit-packed formats */ #define V4L2_PIX_FMT_Y10BPACK v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */ /* Palette formats */ #define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */ /* Luminance+Chrominance formats */ #define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y', 'V', 'U', '9') /* 9 YVU 4:1:0 */ #define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */ #define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y', 'Y', 'U', 'V') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ #define V4L2_PIX_FMT_UYVY v4l2_fourcc('U', 'Y', 'V', 'Y') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_VYUY v4l2_fourcc('V', 'Y', 'U', 'Y') /* 16 YUV 4:2:2 */ #define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4', '2', '2', 'P') /* 16 YVU422 planar */ #define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4', '1', '1', 'P') /* 16 YVU411 planar */ #define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y', '4', '1', 'P') /* 12 YUV 4:1:1 */ #define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y', '4', '4', '4') /* 16 xxxxyyyy uuuuvvvv */ #define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y', 'U', 'V', 'O') /* 16 YUV-5-5-5 */ #define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y', 'U', 'V', 'P') /* 16 YUV-5-6-5 */ #define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y', 'U', 'V', '4') /* 32 YUV-8-8-8-8 */ #define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y', 'U', 'V', '9') /* 9 YUV 4:1:0 */ #define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */ #define V4L2_PIX_FMT_HI240 v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */ #define V4L2_PIX_FMT_HM12 v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */ #define V4L2_PIX_FMT_M420 v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */ /* two planes -- one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */ #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ #define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ #define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ #define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ #define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ /* two non contiguous planes - one Y, one Cr + Cb interleaved */ #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ #define V4L2_PIX_FMT_NV12MT v4l2_fourcc('T', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 64x32 macroblocks */ /* three non contiguous planes - Y, Cb, Cr */ #define V4L2_PIX_FMT_YUV420M v4l2_fourcc('Y', 'M', '1', '2') /* 12 YUV420 planar */ /* Bayer formats - see http://www.siliconimaging.com/RGB%20Bayer.htm */ #define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */ #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */ #define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10 BGBG.. GRGR.. */ #define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */ #define V4L2_PIX_FMT_SBGGR12 v4l2_fourcc('B', 'G', '1', '2') /* 12 BGBG.. GRGR.. */ #define V4L2_PIX_FMT_SGBRG12 v4l2_fourcc('G', 'B', '1', '2') /* 12 GBGB.. RGRG.. */ #define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ /* 10bit raw bayer DPCM compressed to 8 bits */ #define V4L2_PIX_FMT_SBGGR10DPCM8 v4l2_fourcc('b', 'B', 'A', '8') #define V4L2_PIX_FMT_SGBRG10DPCM8 v4l2_fourcc('b', 'G', 'A', '8') #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0') #define V4L2_PIX_FMT_SRGGB10DPCM8 v4l2_fourcc('b', 'R', 'A', '8') /* * 10bit raw bayer, expanded to 16 bits * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb... */ #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ /* compressed formats */ #define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ #define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG */ #define V4L2_PIX_FMT_DV v4l2_fourcc('d', 'v', 's', 'd') /* 1394 */ #define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 Multiplexed */ #define V4L2_PIX_FMT_H264 v4l2_fourcc('H', '2', '6', '4') /* H264 with start codes */ #define V4L2_PIX_FMT_H264_NO_SC v4l2_fourcc('A', 'V', 'C', '1') /* H264 without start codes */ #define V4L2_PIX_FMT_H263 v4l2_fourcc('H', '2', '6', '3') /* H263 */ #define V4L2_PIX_FMT_MPEG1 v4l2_fourcc('M', 'P', 'G', '1') /* MPEG-1 ES */ #define V4L2_PIX_FMT_MPEG2 v4l2_fourcc('M', 'P', 'G', '2') /* MPEG-2 ES */ #define V4L2_PIX_FMT_MPEG4 v4l2_fourcc('M', 'P', 'G', '4') /* MPEG-4 ES */ #define V4L2_PIX_FMT_XVID v4l2_fourcc('X', 'V', 'I', 'D') /* Xvid */ #define V4L2_PIX_FMT_VC1_ANNEX_G v4l2_fourcc('V', 'C', '1', 'G') /* SMPTE 421M Annex G compliant stream */ #define V4L2_PIX_FMT_VC1_ANNEX_L v4l2_fourcc('V', 'C', '1', 'L') /* SMPTE 421M Annex L compliant stream */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ #define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */ #define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */ #define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */ #define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P', 'W', 'C', '1') /* pwc older webcam */ #define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P', 'W', 'C', '2') /* pwc newer webcam */ #define V4L2_PIX_FMT_ET61X251 v4l2_fourcc('E', '6', '2', '5') /* ET61X251 compression */ #define V4L2_PIX_FMT_SPCA501 v4l2_fourcc('S', '5', '0', '1') /* YUYV per line */ #define V4L2_PIX_FMT_SPCA505 v4l2_fourcc('S', '5', '0', '5') /* YYUV per line */ #define V4L2_PIX_FMT_SPCA508 v4l2_fourcc('S', '5', '0', '8') /* YUVY per line */ #define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ #define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ #define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */ #define V4L2_PIX_FMT_JL2005BCD v4l2_fourcc('J', 'L', '2', '0') /* compressed RGGB bayer */ #define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */ #define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */ #define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ #define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */ #define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */ #define V4L2_PIX_FMT_STV0680 v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */ #define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */ #define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */ #define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */ #define V4L2_PIX_FMT_JPGL v4l2_fourcc('J', 'P', 'G', 'L') /* JPEG-Lite */ #define V4L2_PIX_FMT_SE401 v4l2_fourcc('S', '4', '0', '1') /* se401 janggu compressed rgb */ /* * F O R M A T E N U M E R A T I O N */ struct v4l2_fmtdesc { __u32 index; /* Format number */ __u32 type; /* enum v4l2_buf_type */ __u32 flags; __u8 description[32]; /* Description string */ __u32 pixelformat; /* Format fourcc */ __u32 reserved[4]; }; #define V4L2_FMT_FLAG_COMPRESSED 0x0001 #define V4L2_FMT_FLAG_EMULATED 0x0002 #if 1 /* Experimental Frame Size and frame rate enumeration */ /* * F R A M E S I Z E E N U M E R A T I O N */ enum v4l2_frmsizetypes { V4L2_FRMSIZE_TYPE_DISCRETE = 1, V4L2_FRMSIZE_TYPE_CONTINUOUS = 2, V4L2_FRMSIZE_TYPE_STEPWISE = 3, }; struct v4l2_frmsize_discrete { __u32 width; /* Frame width [pixel] */ __u32 height; /* Frame height [pixel] */ }; struct v4l2_frmsize_stepwise { __u32 min_width; /* Minimum frame width [pixel] */ __u32 max_width; /* Maximum frame width [pixel] */ __u32 step_width; /* Frame width step size [pixel] */ __u32 min_height; /* Minimum frame height [pixel] */ __u32 max_height; /* Maximum frame height [pixel] */ __u32 step_height; /* Frame height step size [pixel] */ }; struct v4l2_frmsizeenum { __u32 index; /* Frame size number */ __u32 pixel_format; /* Pixel format */ __u32 type; /* Frame size type the device supports. */ union { /* Frame size */ struct v4l2_frmsize_discrete discrete; struct v4l2_frmsize_stepwise stepwise; }; __u32 reserved[2]; /* Reserved space for future use */ }; /* * F R A M E R A T E E N U M E R A T I O N */ enum v4l2_frmivaltypes { V4L2_FRMIVAL_TYPE_DISCRETE = 1, V4L2_FRMIVAL_TYPE_CONTINUOUS = 2, V4L2_FRMIVAL_TYPE_STEPWISE = 3, }; struct v4l2_frmival_stepwise { struct v4l2_fract min; /* Minimum frame interval [s] */ struct v4l2_fract max; /* Maximum frame interval [s] */ struct v4l2_fract step; /* Frame interval step size [s] */ }; struct v4l2_frmivalenum { __u32 index; /* Frame format index */ __u32 pixel_format; /* Pixel format */ __u32 width; /* Frame width */ __u32 height; /* Frame height */ __u32 type; /* Frame interval type the device supports. */ union { /* Frame interval */ struct v4l2_fract discrete; struct v4l2_frmival_stepwise stepwise; }; __u32 reserved[2]; /* Reserved space for future use */ }; #endif /* * T I M E C O D E */ struct v4l2_timecode { __u32 type; __u32 flags; __u8 frames; __u8 seconds; __u8 minutes; __u8 hours; __u8 userbits[4]; }; /* Type */ #define V4L2_TC_TYPE_24FPS 1 #define V4L2_TC_TYPE_25FPS 2 #define V4L2_TC_TYPE_30FPS 3 #define V4L2_TC_TYPE_50FPS 4 #define V4L2_TC_TYPE_60FPS 5 /* Flags */ #define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ #define V4L2_TC_FLAG_COLORFRAME 0x0002 #define V4L2_TC_USERBITS_field 0x000C #define V4L2_TC_USERBITS_USERDEFINED 0x0000 #define V4L2_TC_USERBITS_8BITCHARS 0x0008 /* The above is based on SMPTE timecodes */ struct v4l2_jpegcompression { int quality; int APPn; /* Number of APP segment to be written, * must be 0..15 */ int APP_len; /* Length of data in JPEG APPn segment */ char APP_data[60]; /* Data in the JPEG APPn segment. */ int COM_len; /* Length of data in JPEG COM segment */ char COM_data[60]; /* Data in JPEG COM segment */ __u32 jpeg_markers; /* Which markers should go into the JPEG * output. Unless you exactly know what * you do, leave them untouched. * Inluding less markers will make the * resulting code smaller, but there will * be fewer applications which can read it. * The presence of the APP and COM marker * is influenced by APP_len and COM_len * ONLY, not by this property! */ #define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ #define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ #define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ #define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ #define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will * allways use APP0 */ }; /* * M E M O R Y - M A P P I N G B U F F E R S */ struct v4l2_requestbuffers { __u32 count; __u32 type; /* enum v4l2_buf_type */ __u32 memory; /* enum v4l2_memory */ __u32 reserved[2]; }; /** * struct v4l2_plane - plane info for multi-planar buffers * @bytesused: number of bytes occupied by data in the plane (payload) * @length: size of this plane (NOT the payload) in bytes * @mem_offset: when memory in the associated struct v4l2_buffer is * V4L2_MEMORY_MMAP, equals the offset from the start of * the device memory for this plane (or is a "cookie" that * should be passed to mmap() called on the video node) * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer * pointing to this plane * @data_offset: offset in the plane to the start of data; usually 0, * unless there is a header in front of the data * * Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer * with two planes can have one plane for Y, and another for interleaved CbCr * components. Each plane can reside in a separate memory buffer, or even in * a completely separate memory node (e.g. in embedded devices). */ struct v4l2_plane { __u32 bytesused; __u32 length; union { __u32 mem_offset; unsigned long userptr; } m; __u32 data_offset; __u32 reserved[11]; }; /** * struct v4l2_buffer - video buffer info * @index: id number of the buffer * @type: enum v4l2_buf_type; buffer type (type == *_MPLANE for * multiplanar buffers); * @bytesused: number of bytes occupied by data in the buffer (payload); * unused (set to 0) for multiplanar buffers * @flags: buffer informational flags * @field: enum v4l2_field; field order of the image in the buffer * @timestamp: frame timestamp * @timecode: frame timecode * @sequence: sequence count of this frame * @memory: enum v4l2_memory; the method, in which the actual video data is * passed * @offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP; * offset from the start of the device memory for this plane, * (or a "cookie" that should be passed to mmap() as offset) * @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR; * a userspace pointer pointing to this buffer * @planes: for multiplanar buffers; userspace pointer to the array of plane * info structs for this buffer * @length: size in bytes of the buffer (NOT its payload) for single-plane * buffers (when type != *_MPLANE); number of elements in the * planes array for multi-plane buffers * @input: input number from which the video data has has been captured * * Contains data exchanged by application and driver using one of the Streaming * I/O methods. */ struct v4l2_buffer { __u32 index; __u32 type; __u32 bytesused; __u32 flags; __u32 field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence; /* memory location */ __u32 memory; union { __u32 offset; unsigned long userptr; struct v4l2_plane *planes; } m; __u32 length; __u32 input; __u32 reserved; }; /* Flags for 'flags' field */ #define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ #define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ #define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ #define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ #define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ #define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ /* Buffer is ready, but the data contained within is corrupted. */ #define V4L2_BUF_FLAG_ERROR 0x0040 #define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ #define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */ #define V4L2_BUF_FLAG_PREPARED 0x0400 /* Buffer is prepared for queuing */ /* Cache handling flags */ #define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800 #define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000 /* * O V E R L A Y P R E V I E W */ struct v4l2_framebuffer { __u32 capability; __u32 flags; /* FIXME: in theory we should pass something like PCI device + memory * region + offset instead of some physical address */ void *base; struct v4l2_pix_format fmt; }; /* Flags for the 'capability' field. Read only */ #define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 #define V4L2_FBUF_CAP_CHROMAKEY 0x0002 #define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 #define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 #define V4L2_FBUF_CAP_LOCAL_ALPHA 0x0010 #define V4L2_FBUF_CAP_GLOBAL_ALPHA 0x0020 #define V4L2_FBUF_CAP_LOCAL_INV_ALPHA 0x0040 #define V4L2_FBUF_CAP_SRC_CHROMAKEY 0x0080 /* Flags for the 'flags' field. */ #define V4L2_FBUF_FLAG_PRIMARY 0x0001 #define V4L2_FBUF_FLAG_OVERLAY 0x0002 #define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 #define V4L2_FBUF_FLAG_LOCAL_ALPHA 0x0008 #define V4L2_FBUF_FLAG_GLOBAL_ALPHA 0x0010 #define V4L2_FBUF_FLAG_LOCAL_INV_ALPHA 0x0020 #define V4L2_FBUF_FLAG_SRC_CHROMAKEY 0x0040 struct v4l2_clip { struct v4l2_rect c; struct v4l2_clip *next; }; struct v4l2_window { struct v4l2_rect w; __u32 field; /* enum v4l2_field */ __u32 chromakey; struct v4l2_clip *clips; __u32 clipcount; void *bitmap; __u8 global_alpha; }; /* * C A P T U R E P A R A M E T E R S */ struct v4l2_captureparm { __u32 capability; /* Supported modes */ __u32 capturemode; /* Current mode */ struct v4l2_fract timeperframe; /* Time per frame in .1us units */ __u32 extendedmode; /* Driver-specific extensions */ __u32 readbuffers; /* # of buffers for read */ __u32 reserved[4]; }; /* Flags for 'capability' and 'capturemode' fields */ #define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ #define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ struct v4l2_outputparm { __u32 capability; /* Supported modes */ __u32 outputmode; /* Current mode */ struct v4l2_fract timeperframe; /* Time per frame in seconds */ __u32 extendedmode; /* Driver-specific extensions */ __u32 writebuffers; /* # of buffers for write */ __u32 reserved[4]; }; /* * I N P U T I M A G E C R O P P I N G */ struct v4l2_cropcap { __u32 type; /* enum v4l2_buf_type */ struct v4l2_rect bounds; struct v4l2_rect defrect; struct v4l2_fract pixelaspect; }; struct v4l2_crop { __u32 type; /* enum v4l2_buf_type */ struct v4l2_rect c; }; /* Hints for adjustments of selection rectangle */ #define V4L2_SEL_FLAG_GE 0x00000001 #define V4L2_SEL_FLAG_LE 0x00000002 /* Selection targets */ /* Current cropping area */ #define V4L2_SEL_TGT_CROP_ACTIVE 0x0000 /* Default cropping area */ #define V4L2_SEL_TGT_CROP_DEFAULT 0x0001 /* Cropping bounds */ #define V4L2_SEL_TGT_CROP_BOUNDS 0x0002 /* Current composing area */ #define V4L2_SEL_TGT_COMPOSE_ACTIVE 0x0100 /* Default composing area */ #define V4L2_SEL_TGT_COMPOSE_DEFAULT 0x0101 /* Composing bounds */ #define V4L2_SEL_TGT_COMPOSE_BOUNDS 0x0102 /* Current composing area plus all padding pixels */ #define V4L2_SEL_TGT_COMPOSE_PADDED 0x0103 /** * struct v4l2_selection - selection info * @type: buffer type (do not use *_MPLANE types) * @target: selection target, used to choose one of possible rectangles * @flags: constraints flags * @r: coordinates of selection window * @reserved: for future use, rounds structure size to 64 bytes, set to zero * * Hardware may use multiple helper windows to process a video stream. * The structure is used to exchange this selection areas between * an application and a driver. */ struct v4l2_selection { __u32 type; __u32 target; __u32 flags; struct v4l2_rect r; __u32 reserved[9]; }; /* * A N A L O G V I D E O S T A N D A R D */ typedef __u64 v4l2_std_id; /* one bit for each */ #define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) #define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) #define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) #define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) #define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) #define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) #define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) #define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) #define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) #define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) #define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) #define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) #define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) /* BTSC */ #define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) /* EIA-J */ #define V4L2_STD_NTSC_443 ((v4l2_std_id)0x00004000) #define V4L2_STD_NTSC_M_KR ((v4l2_std_id)0x00008000) /* FM A2 */ #define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) #define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) #define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) #define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) #define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) #define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) #define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) #define V4L2_STD_SECAM_LC ((v4l2_std_id)0x00800000) /* ATSC/HDTV */ #define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) #define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) /* FIXME: Although std_id is 64 bits, there is an issue on PPC32 architecture that makes switch(__u64) to break. So, there's a hack on v4l2-common.c rounding this value to 32 bits. As, currently, the max value is for V4L2_STD_ATSC_16_VSB (30 bits wide), it should work fine. However, if needed to add more than two standards, v4l2-common.c should be fixed. */ /* * Some macros to merge video standards in order to make live easier for the * drivers and V4L2 applications */ /* * "Common" NTSC/M - It should be noticed that V4L2_STD_NTSC_443 is * Missing here. */ #define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ V4L2_STD_NTSC_M_JP |\ V4L2_STD_NTSC_M_KR) /* Secam macros */ #define V4L2_STD_SECAM_DK (V4L2_STD_SECAM_D |\ V4L2_STD_SECAM_K |\ V4L2_STD_SECAM_K1) /* All Secam Standards */ #define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ V4L2_STD_SECAM_G |\ V4L2_STD_SECAM_H |\ V4L2_STD_SECAM_DK |\ V4L2_STD_SECAM_L |\ V4L2_STD_SECAM_LC) /* PAL macros */ #define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ V4L2_STD_PAL_B1 |\ V4L2_STD_PAL_G) #define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ V4L2_STD_PAL_D1 |\ V4L2_STD_PAL_K) /* * "Common" PAL - This macro is there to be compatible with the old * V4L1 concept of "PAL": /BGDKHI. * Several PAL standards are mising here: /M, /N and /Nc */ #define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ V4L2_STD_PAL_DK |\ V4L2_STD_PAL_H |\ V4L2_STD_PAL_I) /* Chroma "agnostic" standards */ #define V4L2_STD_B (V4L2_STD_PAL_B |\ V4L2_STD_PAL_B1 |\ V4L2_STD_SECAM_B) #define V4L2_STD_G (V4L2_STD_PAL_G |\ V4L2_STD_SECAM_G) #define V4L2_STD_H (V4L2_STD_PAL_H |\ V4L2_STD_SECAM_H) #define V4L2_STD_L (V4L2_STD_SECAM_L |\ V4L2_STD_SECAM_LC) #define V4L2_STD_GH (V4L2_STD_G |\ V4L2_STD_H) #define V4L2_STD_DK (V4L2_STD_PAL_DK |\ V4L2_STD_SECAM_DK) #define V4L2_STD_BG (V4L2_STD_B |\ V4L2_STD_G) #define V4L2_STD_MN (V4L2_STD_PAL_M |\ V4L2_STD_PAL_N |\ V4L2_STD_PAL_Nc |\ V4L2_STD_NTSC) /* Standards where MTS/BTSC stereo could be found */ #define V4L2_STD_MTS (V4L2_STD_NTSC_M |\ V4L2_STD_PAL_M |\ V4L2_STD_PAL_N |\ V4L2_STD_PAL_Nc) /* Standards for Countries with 60Hz Line frequency */ #define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ V4L2_STD_PAL_60 |\ V4L2_STD_NTSC |\ V4L2_STD_NTSC_443) /* Standards for Countries with 50Hz Line frequency */ #define V4L2_STD_625_50 (V4L2_STD_PAL |\ V4L2_STD_PAL_N |\ V4L2_STD_PAL_Nc |\ V4L2_STD_SECAM) #define V4L2_STD_ATSC (V4L2_STD_ATSC_8_VSB |\ V4L2_STD_ATSC_16_VSB) /* Macros with none and all analog standards */ #define V4L2_STD_UNKNOWN 0 #define V4L2_STD_ALL (V4L2_STD_525_60 |\ V4L2_STD_625_50) struct v4l2_standard { __u32 index; v4l2_std_id id; __u8 name[24]; struct v4l2_fract frameperiod; /* Frames, not fields */ __u32 framelines; __u32 reserved[4]; }; /* The DV Preset API is deprecated in favor of the DV Timings API. New drivers shouldn't use this anymore! */ /* * V I D E O T I M I N G S D V P R E S E T */ struct v4l2_dv_preset { __u32 preset; __u32 reserved[4]; }; /* * D V P R E S E T S E N U M E R A T I O N */ struct v4l2_dv_enum_preset { __u32 index; __u32 preset; __u8 name[32]; /* Name of the preset timing */ __u32 width; __u32 height; __u32 reserved[4]; }; /* * D V P R E S E T V A L U E S */ #define V4L2_DV_INVALID 0 #define V4L2_DV_480P59_94 1 /* BT.1362 */ #define V4L2_DV_576P50 2 /* BT.1362 */ #define V4L2_DV_720P24 3 /* SMPTE 296M */ #define V4L2_DV_720P25 4 /* SMPTE 296M */ #define V4L2_DV_720P30 5 /* SMPTE 296M */ #define V4L2_DV_720P50 6 /* SMPTE 296M */ #define V4L2_DV_720P59_94 7 /* SMPTE 274M */ #define V4L2_DV_720P60 8 /* SMPTE 274M/296M */ #define V4L2_DV_1080I29_97 9 /* BT.1120/ SMPTE 274M */ #define V4L2_DV_1080I30 10 /* BT.1120/ SMPTE 274M */ #define V4L2_DV_1080I25 11 /* BT.1120 */ #define V4L2_DV_1080I50 12 /* SMPTE 296M */ #define V4L2_DV_1080I60 13 /* SMPTE 296M */ #define V4L2_DV_1080P24 14 /* SMPTE 296M */ #define V4L2_DV_1080P25 15 /* SMPTE 296M */ #define V4L2_DV_1080P30 16 /* SMPTE 296M */ #define V4L2_DV_1080P50 17 /* BT.1120 */ #define V4L2_DV_1080P60 18 /* BT.1120 */ /* * D V B T T I M I N G S */ /** struct v4l2_bt_timings - BT.656/BT.1120 timing data * @width: total width of the active video in pixels * @height: total height of the active video in lines * @interlaced: Interlaced or progressive * @polarities: Positive or negative polarities * @pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000 * @hfrontporch:Horizontal front porch in pixels * @hsync: Horizontal Sync length in pixels * @hbackporch: Horizontal back porch in pixels * @vfrontporch:Vertical front porch in lines * @vsync: Vertical Sync length in lines * @vbackporch: Vertical back porch in lines * @il_vfrontporch:Vertical front porch for the even field * (aka field 2) of interlaced field formats * @il_vsync: Vertical Sync length for the even field * (aka field 2) of interlaced field formats * @il_vbackporch:Vertical back porch for the even field * (aka field 2) of interlaced field formats * @standards: Standards the timing belongs to * @flags: Flags * @reserved: Reserved fields, must be zeroed. * * A note regarding vertical interlaced timings: height refers to the total * height of the active video frame (= two fields). The blanking timings refer * to the blanking of each field. So the height of the total frame is * calculated as follows: * * tot_height = height + vfrontporch + vsync + vbackporch + * il_vfrontporch + il_vsync + il_vbackporch * * The active height of each field is height / 2. */ struct v4l2_bt_timings { __u32 width; __u32 height; __u32 interlaced; __u32 polarities; __u64 pixelclock; __u32 hfrontporch; __u32 hsync; __u32 hbackporch; __u32 vfrontporch; __u32 vsync; __u32 vbackporch; __u32 il_vfrontporch; __u32 il_vsync; __u32 il_vbackporch; __u32 standards; __u32 flags; __u32 reserved[14]; } __attribute__ ((packed)); /* Interlaced or progressive format */ #define V4L2_DV_PROGRESSIVE 0 #define V4L2_DV_INTERLACED 1 /* Polarities. If bit is not set, it is assumed to be negative polarity */ #define V4L2_DV_VSYNC_POS_POL 0x00000001 #define V4L2_DV_HSYNC_POS_POL 0x00000002 /* Timings standards */ #define V4L2_DV_BT_STD_CEA861 (1 << 0) /* CEA-861 Digital TV Profile */ #define V4L2_DV_BT_STD_DMT (1 << 1) /* VESA Discrete Monitor Timings */ #define V4L2_DV_BT_STD_CVT (1 << 2) /* VESA Coordinated Video Timings */ #define V4L2_DV_BT_STD_GTF (1 << 3) /* VESA Generalized Timings Formula */ /* Flags */ /* CVT/GTF specific: timing uses reduced blanking (CVT) or the 'Secondary GTF' curve (GTF). In both cases the horizontal and/or vertical blanking intervals are reduced, allowing a higher resolution over the same bandwidth. This is a read-only flag. */ #define V4L2_DV_FL_REDUCED_BLANKING (1 << 0) /* CEA-861 specific: set for CEA-861 formats with a framerate of a multiple of six. These formats can be optionally played at 1 / 1.001 speed. This is a read-only flag. */ #define V4L2_DV_FL_CAN_REDUCE_FPS (1 << 1) /* CEA-861 specific: only valid for video transmitters, the flag is cleared by receivers. If the framerate of the format is a multiple of six, then the pixelclock used to set up the transmitter is divided by 1.001 to make it compatible with 60 Hz based standards such as NTSC and PAL-M that use a framerate of 29.97 Hz. Otherwise this flag is cleared. If the transmitter can't generate such frequencies, then the flag will also be cleared. */ #define V4L2_DV_FL_REDUCED_FPS (1 << 2) /* Specific to interlaced formats: if set, then field 1 is really one half-line longer and field 2 is really one half-line shorter, so each field has exactly the same number of half-lines. Whether half-lines can be detected or used depends on the hardware. */ #define V4L2_DV_FL_HALF_LINE (1 << 0) /** struct v4l2_dv_timings - DV timings * @type: the type of the timings * @bt: BT656/1120 timings */ struct v4l2_dv_timings { __u32 type; union { struct v4l2_bt_timings bt; __u32 reserved[32]; }; } __attribute__ ((packed)); /* Values for the type field */ #define V4L2_DV_BT_656_1120 0 /* BT.656/1120 timing type */ /** struct v4l2_enum_dv_timings - DV timings enumeration * @index: enumeration index * @reserved: must be zeroed * @timings: the timings for the given index */ struct v4l2_enum_dv_timings { __u32 index; __u32 reserved[3]; struct v4l2_dv_timings timings; }; /** struct v4l2_bt_timings_cap - BT.656/BT.1120 timing capabilities * @min_width: width in pixels * @max_width: width in pixels * @min_height: height in lines * @max_height: height in lines * @min_pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000 * @max_pixelclock: Pixel clock in HZ. Ex. 74.25MHz->74250000 * @standards: Supported standards * @capabilities: Supported capabilities * @reserved: Must be zeroed */ struct v4l2_bt_timings_cap { __u32 min_width; __u32 max_width; __u32 min_height; __u32 max_height; __u64 min_pixelclock; __u64 max_pixelclock; __u32 standards; __u32 capabilities; __u32 reserved[16]; } __attribute__ ((packed)); /* Supports interlaced formats */ #define V4L2_DV_BT_CAP_INTERLACED (1 << 0) /* Supports progressive formats */ #define V4L2_DV_BT_CAP_PROGRESSIVE (1 << 1) /* Supports CVT/GTF reduced blanking */ #define V4L2_DV_BT_CAP_REDUCED_BLANKING (1 << 2) /* Supports custom formats */ #define V4L2_DV_BT_CAP_CUSTOM (1 << 3) /** struct v4l2_dv_timings_cap - DV timings capabilities * @type: the type of the timings (same as in struct v4l2_dv_timings) * @bt: the BT656/1120 timings capabilities */ struct v4l2_dv_timings_cap { __u32 type; __u32 reserved[3]; union { struct v4l2_bt_timings_cap bt; __u32 raw_data[32]; }; }; /* * V I D E O I N P U T S */ struct v4l2_input { __u32 index; /* Which input */ __u8 name[32]; /* Label */ __u32 type; /* Type of input */ __u32 audioset; /* Associated audios (bitfield) */ __u32 tuner; /* enum v4l2_tuner_type */ v4l2_std_id std; __u32 status; __u32 capabilities; __u32 reserved[3]; }; /* Values for the 'type' field */ #define V4L2_INPUT_TYPE_TUNER 1 #define V4L2_INPUT_TYPE_CAMERA 2 /* field 'status' - general */ #define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ #define V4L2_IN_ST_NO_SIGNAL 0x00000002 #define V4L2_IN_ST_NO_COLOR 0x00000004 /* field 'status' - sensor orientation */ /* If sensor is mounted upside down set both bits */ #define V4L2_IN_ST_HFLIP 0x00000010 /* Frames are flipped horizontally */ #define V4L2_IN_ST_VFLIP 0x00000020 /* Frames are flipped vertically */ /* field 'status' - analog */ #define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ #define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ /* field 'status' - digital */ #define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ #define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ #define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ /* field 'status' - VCR and set-top box */ #define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ #define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ #define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ /* capabilities flags */ #define V4L2_IN_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ #define V4L2_IN_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */ /* * V I D E O O U T P U T S */ struct v4l2_output { __u32 index; /* Which output */ __u8 name[32]; /* Label */ __u32 type; /* Type of output */ __u32 audioset; /* Associated audios (bitfield) */ __u32 modulator; /* Associated modulator */ v4l2_std_id std; __u32 capabilities; __u32 reserved[3]; }; /* Values for the 'type' field */ #define V4L2_OUTPUT_TYPE_MODULATOR 1 #define V4L2_OUTPUT_TYPE_ANALOG 2 #define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 /* capabilities flags */ #define V4L2_OUT_CAP_PRESETS 0x00000001 /* Supports S_DV_PRESET */ #define V4L2_OUT_CAP_CUSTOM_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */ #define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */ /* * C O N T R O L S */ struct v4l2_control { __u32 id; __s32 value; }; struct v4l2_ext_control { __u32 id; __u32 size; __u32 reserved2[1]; union { __s32 value; __s64 value64; char *string; }; } __attribute__ ((packed)); struct v4l2_ext_controls { __u32 ctrl_class; __u32 count; __u32 error_idx; __u32 reserved[2]; struct v4l2_ext_control *controls; }; /* Values for ctrl_class field */ #define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */ #define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */ #define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */ #define V4L2_CTRL_CLASS_FM_TX 0x009b0000 /* FM Modulator control class */ #define V4L2_CTRL_CLASS_FLASH 0x009c0000 /* Camera flash controls */ #define V4L2_CTRL_CLASS_JPEG 0x009d0000 /* JPEG-compression controls */ #define V4L2_CTRL_CLASS_IMAGE_SOURCE 0x009e0000 /* Image source controls */ #define V4L2_CTRL_CLASS_IMAGE_PROC 0x009f0000 /* Image processing controls */ #define V4L2_CTRL_ID_MASK (0x0fffffff) #define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL) #define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000) enum v4l2_ctrl_type { V4L2_CTRL_TYPE_INTEGER = 1, V4L2_CTRL_TYPE_BOOLEAN = 2, V4L2_CTRL_TYPE_MENU = 3, V4L2_CTRL_TYPE_BUTTON = 4, V4L2_CTRL_TYPE_INTEGER64 = 5, V4L2_CTRL_TYPE_CTRL_CLASS = 6, V4L2_CTRL_TYPE_STRING = 7, V4L2_CTRL_TYPE_BITMASK = 8, V4L2_CTRL_TYPE_INTEGER_MENU = 9, }; /* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ struct v4l2_queryctrl { __u32 id; __u32 type; /* enum v4l2_ctrl_type */ __u8 name[32]; /* Whatever */ __s32 minimum; /* Note signedness */ __s32 maximum; __s32 step; __s32 default_value; __u32 flags; __u32 reserved[2]; }; /* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ struct v4l2_querymenu { __u32 id; __u32 index; union { __u8 name[32]; /* Whatever */ __s64 value; }; __u32 reserved; } __attribute__ ((packed)); /* Control flags */ #define V4L2_CTRL_FLAG_DISABLED 0x0001 #define V4L2_CTRL_FLAG_GRABBED 0x0002 #define V4L2_CTRL_FLAG_READ_ONLY 0x0004 #define V4L2_CTRL_FLAG_UPDATE 0x0008 #define V4L2_CTRL_FLAG_INACTIVE 0x0010 #define V4L2_CTRL_FLAG_SLIDER 0x0020 #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 #define V4L2_CTRL_FLAG_VOLATILE 0x0080 /* Query flag, to be ORed with the control ID */ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 /* User-class control IDs defined by V4L2 */ #define V4L2_CID_MAX_CTRLS 1024 #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) #define V4L2_CID_USER_BASE V4L2_CID_BASE /* IDs reserved for driver specific controls */ #define V4L2_CID_PRIVATE_BASE 0x08000000 #define V4L2_CID_USER_CLASS (V4L2_CTRL_CLASS_USER | 1) #define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) #define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) #define V4L2_CID_SATURATION (V4L2_CID_BASE+2) #define V4L2_CID_HUE (V4L2_CID_BASE+3) #define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) #define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) #define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) #define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) #define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) #define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) #define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) /* Deprecated */ #define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) #define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) #define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) #define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) #define V4L2_CID_GAMMA (V4L2_CID_BASE+16) #define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* Deprecated */ #define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) #define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) #define V4L2_CID_GAIN (V4L2_CID_BASE+19) #define V4L2_CID_HFLIP (V4L2_CID_BASE+20) #define V4L2_CID_VFLIP (V4L2_CID_BASE+21) /* Deprecated; use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */ #define V4L2_CID_HCENTER (V4L2_CID_BASE+22) #define V4L2_CID_VCENTER (V4L2_CID_BASE+23) #define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+24) enum v4l2_power_line_frequency { V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0, V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1, V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2, V4L2_CID_POWER_LINE_FREQUENCY_AUTO = 3, }; #define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25) #define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26) #define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27) #define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+28) #define V4L2_CID_CHROMA_AGC (V4L2_CID_BASE+29) #define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30) #define V4L2_CID_COLORFX (V4L2_CID_BASE+31) enum v4l2_colorfx { V4L2_COLORFX_NONE = 0, V4L2_COLORFX_BW = 1, V4L2_COLORFX_SEPIA = 2, V4L2_COLORFX_NEGATIVE = 3, V4L2_COLORFX_EMBOSS = 4, V4L2_COLORFX_SKETCH = 5, V4L2_COLORFX_SKY_BLUE = 6, V4L2_COLORFX_GRASS_GREEN = 7, V4L2_COLORFX_SKIN_WHITEN = 8, V4L2_COLORFX_VIVID = 9, V4L2_COLORFX_AQUA = 10, V4L2_COLORFX_ART_FREEZE = 11, V4L2_COLORFX_SILHOUETTE = 12, V4L2_COLORFX_SOLARIZATION = 13, V4L2_COLORFX_ANTIQUE = 14, V4L2_COLORFX_SET_CBCR = 15, }; #define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32) #define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33) #define V4L2_CID_ROTATE (V4L2_CID_BASE+34) #define V4L2_CID_BG_COLOR (V4L2_CID_BASE+35) #define V4L2_CID_CHROMA_GAIN (V4L2_CID_BASE+36) #define V4L2_CID_ILLUMINATORS_1 (V4L2_CID_BASE+37) #define V4L2_CID_ILLUMINATORS_2 (V4L2_CID_BASE+38) #define V4L2_CID_MIN_BUFFERS_FOR_CAPTURE (V4L2_CID_BASE+39) #define V4L2_CID_MIN_BUFFERS_FOR_OUTPUT (V4L2_CID_BASE+40) #define V4L2_CID_ALPHA_COMPONENT (V4L2_CID_BASE+41) #define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42) /* last CID + 1 */ #define V4L2_CID_LASTP1 (V4L2_CID_BASE+43) /* MPEG-class control IDs defined by V4L2 */ #define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900) #define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1) /* MPEG streams, specific to multiplexed streams */ #define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_MPEG_BASE+0) enum v4l2_mpeg_stream_type { V4L2_MPEG_STREAM_TYPE_MPEG2_PS = 0, /* MPEG-2 program stream */ V4L2_MPEG_STREAM_TYPE_MPEG2_TS = 1, /* MPEG-2 transport stream */ V4L2_MPEG_STREAM_TYPE_MPEG1_SS = 2, /* MPEG-1 system stream */ V4L2_MPEG_STREAM_TYPE_MPEG2_DVD = 3, /* MPEG-2 DVD-compatible stream */ V4L2_MPEG_STREAM_TYPE_MPEG1_VCD = 4, /* MPEG-1 VCD-compatible stream */ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */ }; #define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_MPEG_BASE+1) #define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_MPEG_BASE+2) #define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_MPEG_BASE+3) #define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_MPEG_BASE+4) #define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_MPEG_BASE+5) #define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_MPEG_BASE+6) #define V4L2_CID_MPEG_STREAM_VBI_FMT (V4L2_CID_MPEG_BASE+7) enum v4l2_mpeg_stream_vbi_fmt { V4L2_MPEG_STREAM_VBI_FMT_NONE = 0, /* No VBI in the MPEG stream */ V4L2_MPEG_STREAM_VBI_FMT_IVTV = 1, /* VBI in private packets, IVTV format */ }; /* MPEG audio controls specific to multiplexed streams */ #define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_MPEG_BASE+100) enum v4l2_mpeg_audio_sampling_freq { V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0, V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1, V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2, }; #define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_MPEG_BASE+101) enum v4l2_mpeg_audio_encoding { V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0, V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2, V4L2_MPEG_AUDIO_ENCODING_AAC = 3, V4L2_MPEG_AUDIO_ENCODING_AC3 = 4, }; #define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102) enum v4l2_mpeg_audio_l1_bitrate { V4L2_MPEG_AUDIO_L1_BITRATE_32K = 0, V4L2_MPEG_AUDIO_L1_BITRATE_64K = 1, V4L2_MPEG_AUDIO_L1_BITRATE_96K = 2, V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3, V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4, V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5, V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6, V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7, V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8, V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9, V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10, V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11, V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12, V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13, }; #define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_MPEG_BASE+103) enum v4l2_mpeg_audio_l2_bitrate { V4L2_MPEG_AUDIO_L2_BITRATE_32K = 0, V4L2_MPEG_AUDIO_L2_BITRATE_48K = 1, V4L2_MPEG_AUDIO_L2_BITRATE_56K = 2, V4L2_MPEG_AUDIO_L2_BITRATE_64K = 3, V4L2_MPEG_AUDIO_L2_BITRATE_80K = 4, V4L2_MPEG_AUDIO_L2_BITRATE_96K = 5, V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6, V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7, V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8, V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9, V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10, V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11, V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12, V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13, }; #define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_MPEG_BASE+104) enum v4l2_mpeg_audio_l3_bitrate { V4L2_MPEG_AUDIO_L3_BITRATE_32K = 0, V4L2_MPEG_AUDIO_L3_BITRATE_40K = 1, V4L2_MPEG_AUDIO_L3_BITRATE_48K = 2, V4L2_MPEG_AUDIO_L3_BITRATE_56K = 3, V4L2_MPEG_AUDIO_L3_BITRATE_64K = 4, V4L2_MPEG_AUDIO_L3_BITRATE_80K = 5, V4L2_MPEG_AUDIO_L3_BITRATE_96K = 6, V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7, V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8, V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9, V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10, V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11, V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12, V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13, }; #define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_MPEG_BASE+105) enum v4l2_mpeg_audio_mode { V4L2_MPEG_AUDIO_MODE_STEREO = 0, V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1, V4L2_MPEG_AUDIO_MODE_DUAL = 2, V4L2_MPEG_AUDIO_MODE_MONO = 3, }; #define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_MPEG_BASE+106) enum v4l2_mpeg_audio_mode_extension { V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 = 0, V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 = 1, V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2, V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3, }; #define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_MPEG_BASE+107) enum v4l2_mpeg_audio_emphasis { V4L2_MPEG_AUDIO_EMPHASIS_NONE = 0, V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1, V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 = 2, }; #define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_MPEG_BASE+108) enum v4l2_mpeg_audio_crc { V4L2_MPEG_AUDIO_CRC_NONE = 0, V4L2_MPEG_AUDIO_CRC_CRC16 = 1, }; #define V4L2_CID_MPEG_AUDIO_MUTE (V4L2_CID_MPEG_BASE+109) #define V4L2_CID_MPEG_AUDIO_AAC_BITRATE (V4L2_CID_MPEG_BASE+110) #define V4L2_CID_MPEG_AUDIO_AC3_BITRATE (V4L2_CID_MPEG_BASE+111) enum v4l2_mpeg_audio_ac3_bitrate { V4L2_MPEG_AUDIO_AC3_BITRATE_32K = 0, V4L2_MPEG_AUDIO_AC3_BITRATE_40K = 1, V4L2_MPEG_AUDIO_AC3_BITRATE_48K = 2, V4L2_MPEG_AUDIO_AC3_BITRATE_56K = 3, V4L2_MPEG_AUDIO_AC3_BITRATE_64K = 4, V4L2_MPEG_AUDIO_AC3_BITRATE_80K = 5, V4L2_MPEG_AUDIO_AC3_BITRATE_96K = 6, V4L2_MPEG_AUDIO_AC3_BITRATE_112K = 7, V4L2_MPEG_AUDIO_AC3_BITRATE_128K = 8, V4L2_MPEG_AUDIO_AC3_BITRATE_160K = 9, V4L2_MPEG_AUDIO_AC3_BITRATE_192K = 10, V4L2_MPEG_AUDIO_AC3_BITRATE_224K = 11, V4L2_MPEG_AUDIO_AC3_BITRATE_256K = 12, V4L2_MPEG_AUDIO_AC3_BITRATE_320K = 13, V4L2_MPEG_AUDIO_AC3_BITRATE_384K = 14, V4L2_MPEG_AUDIO_AC3_BITRATE_448K = 15, V4L2_MPEG_AUDIO_AC3_BITRATE_512K = 16, V4L2_MPEG_AUDIO_AC3_BITRATE_576K = 17, V4L2_MPEG_AUDIO_AC3_BITRATE_640K = 18, }; #define V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK (V4L2_CID_MPEG_BASE+112) enum v4l2_mpeg_audio_dec_playback { V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO = 0, V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO = 1, V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT = 2, V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT = 3, V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO = 4, V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO = 5, }; #define V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK (V4L2_CID_MPEG_BASE+113) /* MPEG video controls specific to multiplexed streams */ #define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200) enum v4l2_mpeg_video_encoding { V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0, V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1, V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC = 2, }; #define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201) enum v4l2_mpeg_video_aspect { V4L2_MPEG_VIDEO_ASPECT_1x1 = 0, V4L2_MPEG_VIDEO_ASPECT_4x3 = 1, V4L2_MPEG_VIDEO_ASPECT_16x9 = 2, V4L2_MPEG_VIDEO_ASPECT_221x100 = 3, }; #define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_MPEG_BASE+202) #define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_MPEG_BASE+203) #define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_MPEG_BASE+204) #define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_MPEG_BASE+205) #define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_MPEG_BASE+206) enum v4l2_mpeg_video_bitrate_mode { V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1, }; #define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207) #define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208) #define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209) #define V4L2_CID_MPEG_VIDEO_MUTE (V4L2_CID_MPEG_BASE+210) #define V4L2_CID_MPEG_VIDEO_MUTE_YUV (V4L2_CID_MPEG_BASE+211) #define V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE (V4L2_CID_MPEG_BASE+212) #define V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER (V4L2_CID_MPEG_BASE+213) #define V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB (V4L2_CID_MPEG_BASE+214) #define V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE (V4L2_CID_MPEG_BASE+215) #define V4L2_CID_MPEG_VIDEO_HEADER_MODE (V4L2_CID_MPEG_BASE+216) enum v4l2_mpeg_video_header_mode { V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE = 0, V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME = 1, }; #define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC (V4L2_CID_MPEG_BASE+217) #define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE (V4L2_CID_MPEG_BASE+218) #define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES (V4L2_CID_MPEG_BASE+219) #define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB (V4L2_CID_MPEG_BASE+220) #define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE (V4L2_CID_MPEG_BASE+221) enum v4l2_mpeg_video_multi_slice_mode { V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0, V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB = 1, V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, }; #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) #define V4L2_CID_MPEG_VIDEO_DEC_FRAME (V4L2_CID_MPEG_BASE+224) #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) #define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP (V4L2_CID_MPEG_BASE+302) #define V4L2_CID_MPEG_VIDEO_H263_MIN_QP (V4L2_CID_MPEG_BASE+303) #define V4L2_CID_MPEG_VIDEO_H263_MAX_QP (V4L2_CID_MPEG_BASE+304) #define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP (V4L2_CID_MPEG_BASE+350) #define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP (V4L2_CID_MPEG_BASE+351) #define V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP (V4L2_CID_MPEG_BASE+352) #define V4L2_CID_MPEG_VIDEO_H264_MIN_QP (V4L2_CID_MPEG_BASE+353) #define V4L2_CID_MPEG_VIDEO_H264_MAX_QP (V4L2_CID_MPEG_BASE+354) #define V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM (V4L2_CID_MPEG_BASE+355) #define V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE (V4L2_CID_MPEG_BASE+356) #define V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE (V4L2_CID_MPEG_BASE+357) enum v4l2_mpeg_video_h264_entropy_mode { V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC = 0, V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC = 1, }; #define V4L2_CID_MPEG_VIDEO_H264_I_PERIOD (V4L2_CID_MPEG_BASE+358) #define V4L2_CID_MPEG_VIDEO_H264_LEVEL (V4L2_CID_MPEG_BASE+359) enum v4l2_mpeg_video_h264_level { V4L2_MPEG_VIDEO_H264_LEVEL_1_0 = 0, V4L2_MPEG_VIDEO_H264_LEVEL_1B = 1, V4L2_MPEG_VIDEO_H264_LEVEL_1_1 = 2, V4L2_MPEG_VIDEO_H264_LEVEL_1_2 = 3, V4L2_MPEG_VIDEO_H264_LEVEL_1_3 = 4, V4L2_MPEG_VIDEO_H264_LEVEL_2_0 = 5, V4L2_MPEG_VIDEO_H264_LEVEL_2_1 = 6, V4L2_MPEG_VIDEO_H264_LEVEL_2_2 = 7, V4L2_MPEG_VIDEO_H264_LEVEL_3_0 = 8, V4L2_MPEG_VIDEO_H264_LEVEL_3_1 = 9, V4L2_MPEG_VIDEO_H264_LEVEL_3_2 = 10, V4L2_MPEG_VIDEO_H264_LEVEL_4_0 = 11, V4L2_MPEG_VIDEO_H264_LEVEL_4_1 = 12, V4L2_MPEG_VIDEO_H264_LEVEL_4_2 = 13, V4L2_MPEG_VIDEO_H264_LEVEL_5_0 = 14, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 = 15, }; #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (V4L2_CID_MPEG_BASE+360) #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (V4L2_CID_MPEG_BASE+361) #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE (V4L2_CID_MPEG_BASE+362) enum v4l2_mpeg_video_h264_loop_filter_mode { V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED = 0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED = 1, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY = 2, }; #define V4L2_CID_MPEG_VIDEO_H264_PROFILE (V4L2_CID_MPEG_BASE+363) enum v4l2_mpeg_video_h264_profile { V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE = 0, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE = 1, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN = 2, V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED = 3, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH = 4, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10 = 5, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422 = 6, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE = 7, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA = 8, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA = 9, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA = 10, V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA = 11, V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE = 12, V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH = 13, V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA = 14, V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH = 15, V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH = 16, }; #define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT (V4L2_CID_MPEG_BASE+364) #define V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH (V4L2_CID_MPEG_BASE+365) #define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE (V4L2_CID_MPEG_BASE+366) #define V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC (V4L2_CID_MPEG_BASE+367) enum v4l2_mpeg_video_h264_vui_sar_idc { V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED = 0, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 = 1, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 = 2, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 = 3, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 = 4, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 = 5, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 = 6, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 = 7, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 = 8, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 = 9, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 = 10, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 = 11, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 = 12, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 = 13, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 = 14, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 = 15, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 = 16, V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED = 17, }; #define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_MPEG_BASE+400) #define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_MPEG_BASE+401) #define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_MPEG_BASE+402) #define V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP (V4L2_CID_MPEG_BASE+403) #define V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP (V4L2_CID_MPEG_BASE+404) #define V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL (V4L2_CID_MPEG_BASE+405) enum v4l2_mpeg_video_mpeg4_level { V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 = 0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B = 1, V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 = 2, V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 = 3, V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 = 4, V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B = 5, V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 = 6, V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 = 7, }; #define V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE (V4L2_CID_MPEG_BASE+406) enum v4l2_mpeg_video_mpeg4_profile { V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE = 0, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE = 1, V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE = 2, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE = 3, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY = 4, }; #define V4L2_CID_MPEG_VIDEO_MPEG4_QPEL (V4L2_CID_MPEG_BASE+407) /* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */ #define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000) #define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0) enum v4l2_mpeg_cx2341x_video_spatial_filter_mode { V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0, V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO = 1, }; #define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+1) #define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+2) enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type { V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF = 0, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT = 2, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE = 3, V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4, }; #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+3) enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type { V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF = 0, V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1, }; #define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+4) enum v4l2_mpeg_cx2341x_video_temporal_filter_mode { V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0, V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO = 1, }; #define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+5) #define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+6) enum v4l2_mpeg_cx2341x_video_median_filter_type { V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF = 0, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR = 1, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT = 2, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3, V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG = 4, }; #define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+7) #define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8) #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9) #define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10) #define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11) /* MPEG-class control IDs specific to the Samsung MFC 5.1 driver as defined by V4L2 */ #define V4L2_CID_MPEG_MFC51_BASE (V4L2_CTRL_CLASS_MPEG | 0x1100) #define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY (V4L2_CID_MPEG_MFC51_BASE+0) #define V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE (V4L2_CID_MPEG_MFC51_BASE+1) #define V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE (V4L2_CID_MPEG_MFC51_BASE+2) enum v4l2_mpeg_mfc51_video_frame_skip_mode { V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED = 0, V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT = 1, V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT = 2, }; #define V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE (V4L2_CID_MPEG_MFC51_BASE+3) enum v4l2_mpeg_mfc51_video_force_frame_type { V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED = 0, V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME = 1, V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED = 2, }; #define V4L2_CID_MPEG_MFC51_VIDEO_PADDING (V4L2_CID_MPEG_MFC51_BASE+4) #define V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV (V4L2_CID_MPEG_MFC51_BASE+5) #define V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT (V4L2_CID_MPEG_MFC51_BASE+6) #define V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF (V4L2_CID_MPEG_MFC51_BASE+7) #define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY (V4L2_CID_MPEG_MFC51_BASE+50) #define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK (V4L2_CID_MPEG_MFC51_BASE+51) #define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH (V4L2_CID_MPEG_MFC51_BASE+52) #define V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC (V4L2_CID_MPEG_MFC51_BASE+53) #define V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P (V4L2_CID_MPEG_MFC51_BASE+54) /* Camera class control IDs */ #define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) #define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1) #define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_CAMERA_CLASS_BASE+1) enum v4l2_exposure_auto_type { V4L2_EXPOSURE_AUTO = 0, V4L2_EXPOSURE_MANUAL = 1, V4L2_EXPOSURE_SHUTTER_PRIORITY = 2, V4L2_EXPOSURE_APERTURE_PRIORITY = 3 }; #define V4L2_CID_EXPOSURE_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+2) #define V4L2_CID_EXPOSURE_AUTO_PRIORITY (V4L2_CID_CAMERA_CLASS_BASE+3) #define V4L2_CID_PAN_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+4) #define V4L2_CID_TILT_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+5) #define V4L2_CID_PAN_RESET (V4L2_CID_CAMERA_CLASS_BASE+6) #define V4L2_CID_TILT_RESET (V4L2_CID_CAMERA_CLASS_BASE+7) #define V4L2_CID_PAN_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+8) #define V4L2_CID_TILT_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+9) #define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10) #define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11) #define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12) #define V4L2_CID_ZOOM_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+13) #define V4L2_CID_ZOOM_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+14) #define V4L2_CID_ZOOM_CONTINUOUS (V4L2_CID_CAMERA_CLASS_BASE+15) #define V4L2_CID_PRIVACY (V4L2_CID_CAMERA_CLASS_BASE+16) #define V4L2_CID_IRIS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+17) #define V4L2_CID_IRIS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+18) #define V4L2_CID_AUTO_EXPOSURE_BIAS (V4L2_CID_CAMERA_CLASS_BASE+19) #define V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE (V4L2_CID_CAMERA_CLASS_BASE+20) enum v4l2_auto_n_preset_white_balance { V4L2_WHITE_BALANCE_MANUAL = 0, V4L2_WHITE_BALANCE_AUTO = 1, V4L2_WHITE_BALANCE_INCANDESCENT = 2, V4L2_WHITE_BALANCE_FLUORESCENT = 3, V4L2_WHITE_BALANCE_FLUORESCENT_H = 4, V4L2_WHITE_BALANCE_HORIZON = 5, V4L2_WHITE_BALANCE_DAYLIGHT = 6, V4L2_WHITE_BALANCE_FLASH = 7, V4L2_WHITE_BALANCE_CLOUDY = 8, V4L2_WHITE_BALANCE_SHADE = 9, }; #define V4L2_CID_WIDE_DYNAMIC_RANGE (V4L2_CID_CAMERA_CLASS_BASE+21) #define V4L2_CID_IMAGE_STABILIZATION (V4L2_CID_CAMERA_CLASS_BASE+22) #define V4L2_CID_ISO_SENSITIVITY (V4L2_CID_CAMERA_CLASS_BASE+23) #define V4L2_CID_ISO_SENSITIVITY_AUTO (V4L2_CID_CAMERA_CLASS_BASE+24) enum v4l2_iso_sensitivity_auto_type { V4L2_ISO_SENSITIVITY_MANUAL = 0, V4L2_ISO_SENSITIVITY_AUTO = 1, }; #define V4L2_CID_EXPOSURE_METERING (V4L2_CID_CAMERA_CLASS_BASE+25) enum v4l2_exposure_metering { V4L2_EXPOSURE_METERING_AVERAGE = 0, V4L2_EXPOSURE_METERING_CENTER_WEIGHTED = 1, V4L2_EXPOSURE_METERING_SPOT = 2, }; #define V4L2_CID_SCENE_MODE (V4L2_CID_CAMERA_CLASS_BASE+26) enum v4l2_scene_mode { V4L2_SCENE_MODE_NONE = 0, V4L2_SCENE_MODE_BACKLIGHT = 1, V4L2_SCENE_MODE_BEACH_SNOW = 2, V4L2_SCENE_MODE_CANDLE_LIGHT = 3, V4L2_SCENE_MODE_DAWN_DUSK = 4, V4L2_SCENE_MODE_FALL_COLORS = 5, V4L2_SCENE_MODE_FIREWORKS = 6, V4L2_SCENE_MODE_LANDSCAPE = 7, V4L2_SCENE_MODE_NIGHT = 8, V4L2_SCENE_MODE_PARTY_INDOOR = 9, V4L2_SCENE_MODE_PORTRAIT = 10, V4L2_SCENE_MODE_SPORTS = 11, V4L2_SCENE_MODE_SUNSET = 12, V4L2_SCENE_MODE_TEXT = 13, }; #define V4L2_CID_3A_LOCK (V4L2_CID_CAMERA_CLASS_BASE+27) #define V4L2_LOCK_EXPOSURE (1 << 0) #define V4L2_LOCK_WHITE_BALANCE (1 << 1) #define V4L2_LOCK_FOCUS (1 << 2) #define V4L2_CID_AUTO_FOCUS_START (V4L2_CID_CAMERA_CLASS_BASE+28) #define V4L2_CID_AUTO_FOCUS_STOP (V4L2_CID_CAMERA_CLASS_BASE+29) #define V4L2_CID_AUTO_FOCUS_STATUS (V4L2_CID_CAMERA_CLASS_BASE+30) #define V4L2_AUTO_FOCUS_STATUS_IDLE (0 << 0) #define V4L2_AUTO_FOCUS_STATUS_BUSY (1 << 0) #define V4L2_AUTO_FOCUS_STATUS_REACHED (1 << 1) #define V4L2_AUTO_FOCUS_STATUS_FAILED (1 << 2) #define V4L2_CID_AUTO_FOCUS_RANGE (V4L2_CID_CAMERA_CLASS_BASE+31) enum v4l2_auto_focus_range { V4L2_AUTO_FOCUS_RANGE_AUTO = 0, V4L2_AUTO_FOCUS_RANGE_NORMAL = 1, V4L2_AUTO_FOCUS_RANGE_MACRO = 2, V4L2_AUTO_FOCUS_RANGE_INFINITY = 3, }; /* FM Modulator class control IDs */ #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900) #define V4L2_CID_FM_TX_CLASS (V4L2_CTRL_CLASS_FM_TX | 1) #define V4L2_CID_RDS_TX_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 1) #define V4L2_CID_RDS_TX_PI (V4L2_CID_FM_TX_CLASS_BASE + 2) #define V4L2_CID_RDS_TX_PTY (V4L2_CID_FM_TX_CLASS_BASE + 3) #define V4L2_CID_RDS_TX_PS_NAME (V4L2_CID_FM_TX_CLASS_BASE + 5) #define V4L2_CID_RDS_TX_RADIO_TEXT (V4L2_CID_FM_TX_CLASS_BASE + 6) #define V4L2_CID_AUDIO_LIMITER_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 64) #define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 65) #define V4L2_CID_AUDIO_LIMITER_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 66) #define V4L2_CID_AUDIO_COMPRESSION_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 80) #define V4L2_CID_AUDIO_COMPRESSION_GAIN (V4L2_CID_FM_TX_CLASS_BASE + 81) #define V4L2_CID_AUDIO_COMPRESSION_THRESHOLD (V4L2_CID_FM_TX_CLASS_BASE + 82) #define V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME (V4L2_CID_FM_TX_CLASS_BASE + 83) #define V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME (V4L2_CID_FM_TX_CLASS_BASE + 84) #define V4L2_CID_PILOT_TONE_ENABLED (V4L2_CID_FM_TX_CLASS_BASE + 96) #define V4L2_CID_PILOT_TONE_DEVIATION (V4L2_CID_FM_TX_CLASS_BASE + 97) #define V4L2_CID_PILOT_TONE_FREQUENCY (V4L2_CID_FM_TX_CLASS_BASE + 98) #define V4L2_CID_TUNE_PREEMPHASIS (V4L2_CID_FM_TX_CLASS_BASE + 112) enum v4l2_preemphasis { V4L2_PREEMPHASIS_DISABLED = 0, V4L2_PREEMPHASIS_50_uS = 1, V4L2_PREEMPHASIS_75_uS = 2, }; #define V4L2_CID_TUNE_POWER_LEVEL (V4L2_CID_FM_TX_CLASS_BASE + 113) #define V4L2_CID_TUNE_ANTENNA_CAPACITOR (V4L2_CID_FM_TX_CLASS_BASE + 114) /* Flash and privacy (indicator) light controls */ #define V4L2_CID_FLASH_CLASS_BASE (V4L2_CTRL_CLASS_FLASH | 0x900) #define V4L2_CID_FLASH_CLASS (V4L2_CTRL_CLASS_FLASH | 1) #define V4L2_CID_FLASH_LED_MODE (V4L2_CID_FLASH_CLASS_BASE + 1) enum v4l2_flash_led_mode { V4L2_FLASH_LED_MODE_NONE, V4L2_FLASH_LED_MODE_FLASH, V4L2_FLASH_LED_MODE_TORCH, }; #define V4L2_CID_FLASH_STROBE_SOURCE (V4L2_CID_FLASH_CLASS_BASE + 2) enum v4l2_flash_strobe_source { V4L2_FLASH_STROBE_SOURCE_SOFTWARE, V4L2_FLASH_STROBE_SOURCE_EXTERNAL, }; #define V4L2_CID_FLASH_STROBE (V4L2_CID_FLASH_CLASS_BASE + 3) #define V4L2_CID_FLASH_STROBE_STOP (V4L2_CID_FLASH_CLASS_BASE + 4) #define V4L2_CID_FLASH_STROBE_STATUS (V4L2_CID_FLASH_CLASS_BASE + 5) #define V4L2_CID_FLASH_TIMEOUT (V4L2_CID_FLASH_CLASS_BASE + 6) #define V4L2_CID_FLASH_INTENSITY (V4L2_CID_FLASH_CLASS_BASE + 7) #define V4L2_CID_FLASH_TORCH_INTENSITY (V4L2_CID_FLASH_CLASS_BASE + 8) #define V4L2_CID_FLASH_INDICATOR_INTENSITY (V4L2_CID_FLASH_CLASS_BASE + 9) #define V4L2_CID_FLASH_FAULT (V4L2_CID_FLASH_CLASS_BASE + 10) #define V4L2_FLASH_FAULT_OVER_VOLTAGE (1 << 0) #define V4L2_FLASH_FAULT_TIMEOUT (1 << 1) #define V4L2_FLASH_FAULT_OVER_TEMPERATURE (1 << 2) #define V4L2_FLASH_FAULT_SHORT_CIRCUIT (1 << 3) #define V4L2_FLASH_FAULT_OVER_CURRENT (1 << 4) #define V4L2_FLASH_FAULT_INDICATOR (1 << 5) #define V4L2_CID_FLASH_CHARGE (V4L2_CID_FLASH_CLASS_BASE + 11) #define V4L2_CID_FLASH_READY (V4L2_CID_FLASH_CLASS_BASE + 12) /* JPEG-class control IDs defined by V4L2 */ #define V4L2_CID_JPEG_CLASS_BASE (V4L2_CTRL_CLASS_JPEG | 0x900) #define V4L2_CID_JPEG_CLASS (V4L2_CTRL_CLASS_JPEG | 1) #define V4L2_CID_JPEG_CHROMA_SUBSAMPLING (V4L2_CID_JPEG_CLASS_BASE + 1) enum v4l2_jpeg_chroma_subsampling { V4L2_JPEG_CHROMA_SUBSAMPLING_444 = 0, V4L2_JPEG_CHROMA_SUBSAMPLING_422 = 1, V4L2_JPEG_CHROMA_SUBSAMPLING_420 = 2, V4L2_JPEG_CHROMA_SUBSAMPLING_411 = 3, V4L2_JPEG_CHROMA_SUBSAMPLING_410 = 4, V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY = 5, }; #define V4L2_CID_JPEG_RESTART_INTERVAL (V4L2_CID_JPEG_CLASS_BASE + 2) #define V4L2_CID_JPEG_COMPRESSION_QUALITY (V4L2_CID_JPEG_CLASS_BASE + 3) #define V4L2_CID_JPEG_ACTIVE_MARKER (V4L2_CID_JPEG_CLASS_BASE + 4) #define V4L2_JPEG_ACTIVE_MARKER_APP0 (1 << 0) #define V4L2_JPEG_ACTIVE_MARKER_APP1 (1 << 1) #define V4L2_JPEG_ACTIVE_MARKER_COM (1 << 16) #define V4L2_JPEG_ACTIVE_MARKER_DQT (1 << 17) #define V4L2_JPEG_ACTIVE_MARKER_DHT (1 << 18) /* Image source controls */ #define V4L2_CID_IMAGE_SOURCE_CLASS_BASE (V4L2_CTRL_CLASS_IMAGE_SOURCE | 0x900) #define V4L2_CID_IMAGE_SOURCE_CLASS (V4L2_CTRL_CLASS_IMAGE_SOURCE | 1) #define V4L2_CID_VBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 1) #define V4L2_CID_HBLANK (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 2) #define V4L2_CID_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 3) /* Image processing controls */ #define V4L2_CID_IMAGE_PROC_CLASS_BASE (V4L2_CTRL_CLASS_IMAGE_PROC | 0x900) #define V4L2_CID_IMAGE_PROC_CLASS (V4L2_CTRL_CLASS_IMAGE_PROC | 1) #define V4L2_CID_LINK_FREQ (V4L2_CID_IMAGE_PROC_CLASS_BASE + 1) #define V4L2_CID_PIXEL_RATE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 2) /* * T U N I N G */ struct v4l2_tuner { __u32 index; __u8 name[32]; __u32 type; /* enum v4l2_tuner_type */ __u32 capability; __u32 rangelow; __u32 rangehigh; __u32 rxsubchans; __u32 audmode; __s32 signal; __s32 afc; __u32 reserved[4]; }; struct v4l2_modulator { __u32 index; __u8 name[32]; __u32 capability; __u32 rangelow; __u32 rangehigh; __u32 txsubchans; __u32 reserved[4]; }; /* Flags for the 'capability' field */ #define V4L2_TUNER_CAP_LOW 0x0001 #define V4L2_TUNER_CAP_NORM 0x0002 #define V4L2_TUNER_CAP_STEREO 0x0010 #define V4L2_TUNER_CAP_LANG2 0x0020 #define V4L2_TUNER_CAP_SAP 0x0020 #define V4L2_TUNER_CAP_LANG1 0x0040 #define V4L2_TUNER_CAP_RDS 0x0080 #define V4L2_TUNER_CAP_RDS_BLOCK_IO 0x0100 #define V4L2_TUNER_CAP_RDS_CONTROLS 0x0200 /* Flags for the 'rxsubchans' field */ #define V4L2_TUNER_SUB_MONO 0x0001 #define V4L2_TUNER_SUB_STEREO 0x0002 #define V4L2_TUNER_SUB_LANG2 0x0004 #define V4L2_TUNER_SUB_SAP 0x0004 #define V4L2_TUNER_SUB_LANG1 0x0008 #define V4L2_TUNER_SUB_RDS 0x0010 /* Values for the 'audmode' field */ #define V4L2_TUNER_MODE_MONO 0x0000 #define V4L2_TUNER_MODE_STEREO 0x0001 #define V4L2_TUNER_MODE_LANG2 0x0002 #define V4L2_TUNER_MODE_SAP 0x0002 #define V4L2_TUNER_MODE_LANG1 0x0003 #define V4L2_TUNER_MODE_LANG1_LANG2 0x0004 struct v4l2_frequency { __u32 tuner; __u32 type; /* enum v4l2_tuner_type */ __u32 frequency; __u32 reserved[8]; }; struct v4l2_hw_freq_seek { __u32 tuner; __u32 type; /* enum v4l2_tuner_type */ __u32 seek_upward; __u32 wrap_around; __u32 spacing; __u32 reserved[7]; }; /* * R D S */ struct v4l2_rds_data { __u8 lsb; __u8 msb; __u8 block; } __attribute__ ((packed)); #define V4L2_RDS_BLOCK_MSK 0x7 #define V4L2_RDS_BLOCK_A 0 #define V4L2_RDS_BLOCK_B 1 #define V4L2_RDS_BLOCK_C 2 #define V4L2_RDS_BLOCK_D 3 #define V4L2_RDS_BLOCK_C_ALT 4 #define V4L2_RDS_BLOCK_INVALID 7 #define V4L2_RDS_BLOCK_CORRECTED 0x40 #define V4L2_RDS_BLOCK_ERROR 0x80 /* * A U D I O */ struct v4l2_audio { __u32 index; __u8 name[32]; __u32 capability; __u32 mode; __u32 reserved[2]; }; /* Flags for the 'capability' field */ #define V4L2_AUDCAP_STEREO 0x00001 #define V4L2_AUDCAP_AVL 0x00002 /* Flags for the 'mode' field */ #define V4L2_AUDMODE_AVL 0x00001 struct v4l2_audioout { __u32 index; __u8 name[32]; __u32 capability; __u32 mode; __u32 reserved[2]; }; /* * M P E G S E R V I C E S * * NOTE: EXPERIMENTAL API */ #if 1 #define V4L2_ENC_IDX_FRAME_I (0) #define V4L2_ENC_IDX_FRAME_P (1) #define V4L2_ENC_IDX_FRAME_B (2) #define V4L2_ENC_IDX_FRAME_MASK (0xf) struct v4l2_enc_idx_entry { __u64 offset; __u64 pts; __u32 length; __u32 flags; __u32 reserved[2]; }; #define V4L2_ENC_IDX_ENTRIES (64) struct v4l2_enc_idx { __u32 entries; __u32 entries_cap; __u32 reserved[4]; struct v4l2_enc_idx_entry entry[V4L2_ENC_IDX_ENTRIES]; }; #define V4L2_ENC_CMD_START (0) #define V4L2_ENC_CMD_STOP (1) #define V4L2_ENC_CMD_PAUSE (2) #define V4L2_ENC_CMD_RESUME (3) /* Flags for V4L2_ENC_CMD_STOP */ #define V4L2_ENC_CMD_STOP_AT_GOP_END (1 << 0) struct v4l2_encoder_cmd { __u32 cmd; __u32 flags; union { struct { __u32 data[8]; } raw; }; }; /* Decoder commands */ #define V4L2_DEC_CMD_START (0) #define V4L2_DEC_CMD_STOP (1) #define V4L2_DEC_CMD_PAUSE (2) #define V4L2_DEC_CMD_RESUME (3) /* Flags for V4L2_DEC_CMD_START */ #define V4L2_DEC_CMD_START_MUTE_AUDIO (1 << 0) /* Flags for V4L2_DEC_CMD_PAUSE */ #define V4L2_DEC_CMD_PAUSE_TO_BLACK (1 << 0) /* Flags for V4L2_DEC_CMD_STOP */ #define V4L2_DEC_CMD_STOP_TO_BLACK (1 << 0) #define V4L2_DEC_CMD_STOP_IMMEDIATELY (1 << 1) /* Play format requirements (returned by the driver): */ /* The decoder has no special format requirements */ #define V4L2_DEC_START_FMT_NONE (0) /* The decoder requires full GOPs */ #define V4L2_DEC_START_FMT_GOP (1) /* The structure must be zeroed before use by the application This ensures it can be extended safely in the future. */ struct v4l2_decoder_cmd { __u32 cmd; __u32 flags; union { struct { __u64 pts; } stop; struct { /* 0 or 1000 specifies normal speed, 1 specifies forward single stepping, -1 specifies backward single stepping, >1: playback at speed/1000 of the normal speed, <-1: reverse playback at (-speed/1000) of the normal speed. */ __s32 speed; __u32 format; } start; struct { __u32 data[16]; } raw; }; }; #endif /* * D A T A S E R V I C E S ( V B I ) * * Data services API by Michael Schimek */ /* Raw VBI */ struct v4l2_vbi_format { __u32 sampling_rate; /* in 1 Hz */ __u32 offset; __u32 samples_per_line; __u32 sample_format; /* V4L2_PIX_FMT_* */ __s32 start[2]; __u32 count[2]; __u32 flags; /* V4L2_VBI_* */ __u32 reserved[2]; /* must be zero */ }; /* VBI flags */ #define V4L2_VBI_UNSYNC (1 << 0) #define V4L2_VBI_INTERLACED (1 << 1) /* Sliced VBI * * This implements is a proposal V4L2 API to allow SLICED VBI * required for some hardware encoders. It should change without * notice in the definitive implementation. */ struct v4l2_sliced_vbi_format { __u16 service_set; /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field (equals frame lines 313-336 for 625 line video standards, 263-286 for 525 line standards) */ __u16 service_lines[2][24]; __u32 io_size; __u32 reserved[2]; /* must be zero */ }; /* Teletext World System Teletext (WST), defined on ITU-R BT.653-2 */ #define V4L2_SLICED_TELETEXT_B (0x0001) /* Video Program System, defined on ETS 300 231*/ #define V4L2_SLICED_VPS (0x0400) /* Closed Caption, defined on EIA-608 */ #define V4L2_SLICED_CAPTION_525 (0x1000) /* Wide Screen System, defined on ITU-R BT1119.1 */ #define V4L2_SLICED_WSS_625 (0x4000) #define V4L2_SLICED_VBI_525 (V4L2_SLICED_CAPTION_525) #define V4L2_SLICED_VBI_625 (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625) struct v4l2_sliced_vbi_cap { __u16 service_set; /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field (equals frame lines 313-336 for 625 line video standards, 263-286 for 525 line standards) */ __u16 service_lines[2][24]; __u32 type; /* enum v4l2_buf_type */ __u32 reserved[3]; /* must be 0 */ }; struct v4l2_sliced_vbi_data { __u32 id; __u32 field; /* 0: first field, 1: second field */ __u32 line; /* 1-23 */ __u32 reserved; /* must be 0 */ __u8 data[48]; }; /* * Sliced VBI data inserted into MPEG Streams */ /* * V4L2_MPEG_STREAM_VBI_FMT_IVTV: * * Structure of payload contained in an MPEG 2 Private Stream 1 PES Packet in an * MPEG-2 Program Pack that contains V4L2_MPEG_STREAM_VBI_FMT_IVTV Sliced VBI * data * * Note, the MPEG-2 Program Pack and Private Stream 1 PES packet header * definitions are not included here. See the MPEG-2 specifications for details * on these headers. */ /* Line type IDs */ #define V4L2_MPEG_VBI_IVTV_TELETEXT_B (1) #define V4L2_MPEG_VBI_IVTV_CAPTION_525 (4) #define V4L2_MPEG_VBI_IVTV_WSS_625 (5) #define V4L2_MPEG_VBI_IVTV_VPS (7) struct v4l2_mpeg_vbi_itv0_line { __u8 id; /* One of V4L2_MPEG_VBI_IVTV_* above */ __u8 data[42]; /* Sliced VBI data for the line */ } __attribute__ ((packed)); struct v4l2_mpeg_vbi_itv0 { __le32 linemask[2]; /* Bitmasks of VBI service lines present */ struct v4l2_mpeg_vbi_itv0_line line[35]; } __attribute__ ((packed)); struct v4l2_mpeg_vbi_ITV0 { struct v4l2_mpeg_vbi_itv0_line line[36]; } __attribute__ ((packed)); #define V4L2_MPEG_VBI_IVTV_MAGIC0 "itv0" #define V4L2_MPEG_VBI_IVTV_MAGIC1 "ITV0" struct v4l2_mpeg_vbi_fmt_ivtv { __u8 magic[4]; union { struct v4l2_mpeg_vbi_itv0 itv0; struct v4l2_mpeg_vbi_ITV0 ITV0; }; } __attribute__ ((packed)); /* * A G G R E G A T E S T R U C T U R E S */ /** * struct v4l2_plane_pix_format - additional, per-plane format definition * @sizeimage: maximum size in bytes required for data, for which * this plane will be used * @bytesperline: distance in bytes between the leftmost pixels in two * adjacent lines */ struct v4l2_plane_pix_format { __u32 sizeimage; __u16 bytesperline; __u16 reserved[7]; } __attribute__ ((packed)); /** * struct v4l2_pix_format_mplane - multiplanar format definition * @width: image width in pixels * @height: image height in pixels * @pixelformat: little endian four character code (fourcc) * @field: enum v4l2_field; field order (for interlaced video) * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @plane_fmt: per-plane information * @num_planes: number of planes for this format */ struct v4l2_pix_format_mplane { __u32 width; __u32 height; __u32 pixelformat; __u32 field; __u32 colorspace; struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES]; __u8 num_planes; __u8 reserved[11]; } __attribute__ ((packed)); /** * struct v4l2_format - stream data format * @type: enum v4l2_buf_type; type of the data stream * @pix: definition of an image format * @pix_mp: definition of a multiplanar image format * @win: definition of an overlaid image * @vbi: raw VBI capture or output parameters * @sliced: sliced VBI capture or output parameters * @raw_data: placeholder for future extensions and custom formats */ struct v4l2_format { __u32 type; union { struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ struct v4l2_pix_format_mplane pix_mp; /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */ struct v4l2_window win; /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ struct v4l2_vbi_format vbi; /* V4L2_BUF_TYPE_VBI_CAPTURE */ struct v4l2_sliced_vbi_format sliced; /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ __u8 raw_data[200]; /* user-defined */ } fmt; }; /* Stream type-dependent parameters */ struct v4l2_streamparm { __u32 type; /* enum v4l2_buf_type */ union { struct v4l2_captureparm capture; struct v4l2_outputparm output; __u8 raw_data[200]; /* user-defined */ } parm; }; /* * E V E N T S */ #define V4L2_EVENT_ALL 0 #define V4L2_EVENT_VSYNC 1 #define V4L2_EVENT_EOS 2 #define V4L2_EVENT_CTRL 3 #define V4L2_EVENT_FRAME_SYNC 4 #define V4L2_EVENT_PRIVATE_START 0x08000000 /* Payload for V4L2_EVENT_VSYNC */ struct v4l2_event_vsync { /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */ __u8 field; } __attribute__ ((packed)); /* Payload for V4L2_EVENT_CTRL */ #define V4L2_EVENT_CTRL_CH_VALUE (1 << 0) #define V4L2_EVENT_CTRL_CH_FLAGS (1 << 1) struct v4l2_event_ctrl { __u32 changes; __u32 type; union { __s32 value; __s64 value64; }; __u32 flags; __s32 minimum; __s32 maximum; __s32 step; __s32 default_value; }; struct v4l2_event_frame_sync { __u32 frame_sequence; }; struct v4l2_event { __u32 type; union { struct v4l2_event_vsync vsync; struct v4l2_event_ctrl ctrl; struct v4l2_event_frame_sync frame_sync; __u8 data[64]; } u; __u32 pending; __u32 sequence; struct timespec timestamp; __u32 id; __u32 reserved[8]; }; #define V4L2_EVENT_SUB_FL_SEND_INITIAL (1 << 0) #define V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK (1 << 1) struct v4l2_event_subscription { __u32 type; __u32 id; __u32 flags; __u32 reserved[5]; }; /* * A D V A N C E D D E B U G G I N G * * NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS! * FOR DEBUGGING, TESTING AND INTERNAL USE ONLY! */ /* VIDIOC_DBG_G_REGISTER and VIDIOC_DBG_S_REGISTER */ #define V4L2_CHIP_MATCH_HOST 0 /* Match against chip ID on host (0 for the host) */ #define V4L2_CHIP_MATCH_I2C_DRIVER 1 /* Match against I2C driver name */ #define V4L2_CHIP_MATCH_I2C_ADDR 2 /* Match against I2C 7-bit address */ #define V4L2_CHIP_MATCH_AC97 3 /* Match against anciliary AC97 chip */ struct v4l2_dbg_match { __u32 type; /* Match type */ union { /* Match this chip, meaning determined by type */ __u32 addr; char name[32]; }; } __attribute__ ((packed)); struct v4l2_dbg_register { struct v4l2_dbg_match match; __u32 size; /* register size in bytes */ __u64 reg; __u64 val; } __attribute__ ((packed)); /* VIDIOC_DBG_G_CHIP_IDENT */ struct v4l2_dbg_chip_ident { struct v4l2_dbg_match match; __u32 ident; /* chip identifier as specified in */ __u32 revision; /* chip revision, chip specific */ } __attribute__ ((packed)); /** * struct v4l2_create_buffers - VIDIOC_CREATE_BUFS argument * @index: on return, index of the first created buffer * @count: entry: number of requested buffers, * return: number of created buffers * @memory: enum v4l2_memory; buffer memory type * @format: frame format, for which buffers are requested * @reserved: future extensions */ struct v4l2_create_buffers { __u32 index; __u32 count; __u32 memory; struct v4l2_format format; __u32 reserved[8]; }; /* * I O C T L C O D E S F O R V I D E O D E V I C E S * */ #define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) #define VIDIOC_RESERVED _IO('V', 1) #define VIDIOC_ENUM_FMT _IOWR('V', 2, struct v4l2_fmtdesc) #define VIDIOC_G_FMT _IOWR('V', 4, struct v4l2_format) #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) #define VIDIOC_REQBUFS _IOWR('V', 8, struct v4l2_requestbuffers) #define VIDIOC_QUERYBUF _IOWR('V', 9, struct v4l2_buffer) #define VIDIOC_G_FBUF _IOR('V', 10, struct v4l2_framebuffer) #define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer) #define VIDIOC_OVERLAY _IOW('V', 14, int) #define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) #define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer) #define VIDIOC_STREAMON _IOW('V', 18, int) #define VIDIOC_STREAMOFF _IOW('V', 19, int) #define VIDIOC_G_PARM _IOWR('V', 21, struct v4l2_streamparm) #define VIDIOC_S_PARM _IOWR('V', 22, struct v4l2_streamparm) #define VIDIOC_G_STD _IOR('V', 23, v4l2_std_id) #define VIDIOC_S_STD _IOW('V', 24, v4l2_std_id) #define VIDIOC_ENUMSTD _IOWR('V', 25, struct v4l2_standard) #define VIDIOC_ENUMINPUT _IOWR('V', 26, struct v4l2_input) #define VIDIOC_G_CTRL _IOWR('V', 27, struct v4l2_control) #define VIDIOC_S_CTRL _IOWR('V', 28, struct v4l2_control) #define VIDIOC_G_TUNER _IOWR('V', 29, struct v4l2_tuner) #define VIDIOC_S_TUNER _IOW('V', 30, struct v4l2_tuner) #define VIDIOC_G_AUDIO _IOR('V', 33, struct v4l2_audio) #define VIDIOC_S_AUDIO _IOW('V', 34, struct v4l2_audio) #define VIDIOC_QUERYCTRL _IOWR('V', 36, struct v4l2_queryctrl) #define VIDIOC_QUERYMENU _IOWR('V', 37, struct v4l2_querymenu) #define VIDIOC_G_INPUT _IOR('V', 38, int) #define VIDIOC_S_INPUT _IOWR('V', 39, int) #define VIDIOC_G_OUTPUT _IOR('V', 46, int) #define VIDIOC_S_OUTPUT _IOWR('V', 47, int) #define VIDIOC_ENUMOUTPUT _IOWR('V', 48, struct v4l2_output) #define VIDIOC_G_AUDOUT _IOR('V', 49, struct v4l2_audioout) #define VIDIOC_S_AUDOUT _IOW('V', 50, struct v4l2_audioout) #define VIDIOC_G_MODULATOR _IOWR('V', 54, struct v4l2_modulator) #define VIDIOC_S_MODULATOR _IOW('V', 55, struct v4l2_modulator) #define VIDIOC_G_FREQUENCY _IOWR('V', 56, struct v4l2_frequency) #define VIDIOC_S_FREQUENCY _IOW('V', 57, struct v4l2_frequency) #define VIDIOC_CROPCAP _IOWR('V', 58, struct v4l2_cropcap) #define VIDIOC_G_CROP _IOWR('V', 59, struct v4l2_crop) #define VIDIOC_S_CROP _IOW('V', 60, struct v4l2_crop) #define VIDIOC_G_JPEGCOMP _IOR('V', 61, struct v4l2_jpegcompression) #define VIDIOC_S_JPEGCOMP _IOW('V', 62, struct v4l2_jpegcompression) #define VIDIOC_QUERYSTD _IOR('V', 63, v4l2_std_id) #define VIDIOC_TRY_FMT _IOWR('V', 64, struct v4l2_format) #define VIDIOC_ENUMAUDIO _IOWR('V', 65, struct v4l2_audio) #define VIDIOC_ENUMAUDOUT _IOWR('V', 66, struct v4l2_audioout) #define VIDIOC_G_PRIORITY _IOR('V', 67, __u32) /* enum v4l2_priority */ #define VIDIOC_S_PRIORITY _IOW('V', 68, __u32) /* enum v4l2_priority */ #define VIDIOC_G_SLICED_VBI_CAP _IOWR('V', 69, struct v4l2_sliced_vbi_cap) #define VIDIOC_LOG_STATUS _IO('V', 70) #define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls) #define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls) #define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls) #if 1 #define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum) #define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum) #define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx) #define VIDIOC_ENCODER_CMD _IOWR('V', 77, struct v4l2_encoder_cmd) #define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd) #endif #if 1 /* Experimental, meant for debugging, testing and internal use. Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined. You must be root to use these ioctls. Never use these in applications! */ #define VIDIOC_DBG_S_REGISTER _IOW('V', 79, struct v4l2_dbg_register) #define VIDIOC_DBG_G_REGISTER _IOWR('V', 80, struct v4l2_dbg_register) /* Experimental, meant for debugging, testing and internal use. Never use this ioctl in applications! */ #define VIDIOC_DBG_G_CHIP_IDENT _IOWR('V', 81, struct v4l2_dbg_chip_ident) #endif #define VIDIOC_S_HW_FREQ_SEEK _IOW('V', 82, struct v4l2_hw_freq_seek) /* These four DV Preset ioctls are deprecated in favor of the DV Timings ioctls. */ #define VIDIOC_ENUM_DV_PRESETS _IOWR('V', 83, struct v4l2_dv_enum_preset) #define VIDIOC_S_DV_PRESET _IOWR('V', 84, struct v4l2_dv_preset) #define VIDIOC_G_DV_PRESET _IOWR('V', 85, struct v4l2_dv_preset) #define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset) #define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings) #define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings) #define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event) #define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription) #define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription) /* Experimental, the below two ioctls may change over the next couple of kernel versions */ #define VIDIOC_CREATE_BUFS _IOWR('V', 92, struct v4l2_create_buffers) #define VIDIOC_PREPARE_BUF _IOWR('V', 93, struct v4l2_buffer) /* Experimental selection API */ #define VIDIOC_G_SELECTION _IOWR('V', 94, struct v4l2_selection) #define VIDIOC_S_SELECTION _IOWR('V', 95, struct v4l2_selection) /* Experimental, these two ioctls may change over the next couple of kernel versions. */ #define VIDIOC_DECODER_CMD _IOWR('V', 96, struct v4l2_decoder_cmd) #define VIDIOC_TRY_DECODER_CMD _IOWR('V', 97, struct v4l2_decoder_cmd) /* Experimental, these three ioctls may change over the next couple of kernel versions. */ #define VIDIOC_ENUM_DV_TIMINGS _IOWR('V', 98, struct v4l2_enum_dv_timings) #define VIDIOC_QUERY_DV_TIMINGS _IOR('V', 99, struct v4l2_dv_timings) #define VIDIOC_DV_TIMINGS_CAP _IOWR('V', 100, struct v4l2_dv_timings_cap) /* Reminder: when adding new ioctls please add support for them to drivers/media/video/v4l2-compat-ioctl32.c as well! */ #define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ #endif /* __LINUX_VIDEODEV2_H */ libindi-0.9.7/libs/webcam/videodev.h0000644000175000017500000003107612241463551016300 0ustar jasemjasem/* Copyright 2006 Bill Dirks Justin Schoeman et al. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __LINUX_VIDEODEV_H #define __LINUX_VIDEODEV_H #define VID_TYPE_CAPTURE 1 /* Can capture */ #define VID_TYPE_TUNER 2 /* Can tune */ #define VID_TYPE_TELETEXT 4 /* Does teletext */ #define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ #define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ #define VID_TYPE_CLIPPING 32 /* Can clip */ #define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ #define VID_TYPE_SCALES 128 /* Scalable */ #define VID_TYPE_MONOCHROME 256 /* Monochrome only */ #define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ #define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ #define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ #define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ #define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ struct video_capability { char name[32]; int type; int channels; /* Num channels */ int audios; /* Num audio devices */ int maxwidth; /* Supported width */ int maxheight; /* And height */ int minwidth; /* Supported width */ int minheight; /* And height */ }; struct video_channel { int channel; char name[32]; int tuners; unsigned int flags; #define VIDEO_VC_TUNER 1 /* Channel has a tuner */ #define VIDEO_VC_AUDIO 2 /* Channel has audio */ unsigned short type; #define VIDEO_TYPE_TV 1 #define VIDEO_TYPE_CAMERA 2 unsigned short norm; /* Norm set by channel */ }; struct video_tuner { int tuner; char name[32]; unsigned long rangelow, rangehigh; /* Tuner range */ unsigned int flags; #define VIDEO_TUNER_PAL 1 #define VIDEO_TUNER_NTSC 2 #define VIDEO_TUNER_SECAM 4 #define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ #define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ #define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ #define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ #define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ unsigned short mode; /* PAL/NTSC/SECAM/OTHER */ #define VIDEO_MODE_PAL 0 #define VIDEO_MODE_NTSC 1 #define VIDEO_MODE_SECAM 2 #define VIDEO_MODE_AUTO 3 unsigned short signal; /* Signal strength 16bit scale */ }; struct video_picture { unsigned short brightness; unsigned short hue; unsigned short colour; unsigned short contrast; unsigned short whiteness; /* Black and white only */ unsigned short depth; /* Capture depth */ unsigned short palette; /* Palette in use */ #define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ #define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ #define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ #define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ #define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ #define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ #define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ #define VIDEO_PALETTE_YUYV 8 #define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ #define VIDEO_PALETTE_YUV420 10 #define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ #define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ #define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ #define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ #define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ #define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ #define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ #define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ }; struct video_audio { int audio; /* Audio channel */ unsigned short volume; /* If settable */ unsigned short bass, treble; unsigned int flags; #define VIDEO_AUDIO_MUTE 1 #define VIDEO_AUDIO_MUTABLE 2 #define VIDEO_AUDIO_VOLUME 4 #define VIDEO_AUDIO_BASS 8 #define VIDEO_AUDIO_TREBLE 16 #define VIDEO_AUDIO_BALANCE 32 char name[16]; #define VIDEO_SOUND_MONO 1 #define VIDEO_SOUND_STEREO 2 #define VIDEO_SOUND_LANG1 4 #define VIDEO_SOUND_LANG2 8 unsigned short mode; unsigned short balance; /* Stereo balance */ unsigned short step; /* Step actual volume uses */ }; struct video_clip { int x,y; int width, height; struct video_clip *next; /* For user use/driver use only */ }; struct video_window { unsigned int x,y; /* Position of window */ unsigned int width,height; /* Its size */ unsigned int chromakey; unsigned int flags; struct video_clip *clips; /* Set only */ int clipcount; #define VIDEO_WINDOW_INTERLACE 1 #define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ #define VIDEO_CLIP_BITMAP -1 /* bitmap is 1024x625, a '1' bit represents a clipped pixel */ #define VIDEO_CLIPMAP_SIZE (128 * 625) }; struct video_capture { unsigned int x,y; /* Offsets into image */ unsigned int width, height; /* Area to capture */ unsigned short decimation; /* Decimation divider */ unsigned short flags; /* Flags for capture */ #define VIDEO_CAPTURE_ODD 0 /* Temporal */ #define VIDEO_CAPTURE_EVEN 1 }; struct video_buffer { void *base; int height,width; int depth; int bytesperline; }; struct video_mmap { unsigned int frame; /* Frame (0 - n) for double buffer */ int height,width; unsigned int format; /* should be VIDEO_PALETTE_* */ }; struct video_key { unsigned char key[8]; unsigned int flags; }; #define VIDEO_MAX_FRAME 32 struct video_mbuf { int size; /* Total memory to map */ int frames; /* Frames */ int offsets[VIDEO_MAX_FRAME]; }; #define VIDEO_NO_UNIT (-1) struct video_unit { int video; /* Video minor */ int vbi; /* VBI minor */ int radio; /* Radio minor */ int audio; /* Audio minor */ int teletext; /* Teletext minor */ }; struct vbi_format { unsigned int sampling_rate; /* in Hz */ unsigned int samples_per_line; unsigned int sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ int start[2]; /* starting line for each frame */ unsigned int count[2]; /* count of lines for each frame */ unsigned int flags; #define VBI_UNSYNC 1 /* can distingues between top/bottom field */ #define VBI_INTERLACED 2 /* lines are interlaced */ }; /* video_info is biased towards hardware mpeg encode/decode */ /* but it could apply generically to any hardware compressor/decompressor */ struct video_info { unsigned int frame_count; /* frames output since decode/encode began */ unsigned int h_size; /* current unscaled horizontal size */ unsigned int v_size; /* current unscaled veritcal size */ unsigned int smpte_timecode; /* current SMPTE timecode (for current GOP) */ unsigned int picture_type; /* current picture type */ unsigned int temporal_reference; /* current temporal reference */ unsigned char user_data[256]; /* user data last found in compressed stream */ /* user_data[0] contains user data flags, user_data[1] has count */ }; /* generic structure for setting playback modes */ struct video_play_mode { int mode; int p1; int p2; }; /* for loading microcode / fpga programming */ struct video_code { char loadwhat[16]; /* name or tag of file being passed */ int datasize; unsigned char *data; }; #define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ #define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ #define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ #define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ #define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ #define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ #define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ #define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ #define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ #define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ #define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ #define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ #define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ #define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ #define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ #define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ #define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ #define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ #define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ #define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ #define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ #define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ #define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ #define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ #define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ #define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ #define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ #define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ #define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ #define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ /* VIDIOCSWRITEMODE */ #define VID_WRITE_MPEG_AUD 0 #define VID_WRITE_MPEG_VID 1 #define VID_WRITE_OSD 2 #define VID_WRITE_TTX 3 #define VID_WRITE_CC 4 #define VID_WRITE_MJPEG 5 /* VIDIOCSPLAYMODE */ #define VID_PLAY_VID_OUT_MODE 0 /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ #define VID_PLAY_GENLOCK 1 /* p1: 0 = OFF, 1 = ON */ /* p2: GENLOCK FINE DELAY value */ #define VID_PLAY_NORMAL 2 #define VID_PLAY_PAUSE 3 #define VID_PLAY_SINGLE_FRAME 4 #define VID_PLAY_FAST_FORWARD 5 #define VID_PLAY_SLOW_MOTION 6 #define VID_PLAY_IMMEDIATE_NORMAL 7 #define VID_PLAY_SWITCH_CHANNELS 8 #define VID_PLAY_FREEZE_FRAME 9 #define VID_PLAY_STILL_MODE 10 #define VID_PLAY_MASTER_MODE 11 /* p1: see below */ #define VID_PLAY_MASTER_NONE 1 #define VID_PLAY_MASTER_VIDEO 2 #define VID_PLAY_MASTER_AUDIO 3 #define VID_PLAY_ACTIVE_SCANLINES 12 /* p1 = first active; p2 = last active */ #define VID_PLAY_RESET 13 #define VID_PLAY_END_MARK 14 #define VID_HARDWARE_BT848 1 #define VID_HARDWARE_QCAM_BW 2 #define VID_HARDWARE_PMS 3 #define VID_HARDWARE_QCAM_C 4 #define VID_HARDWARE_PSEUDO 5 #define VID_HARDWARE_SAA5249 6 #define VID_HARDWARE_AZTECH 7 #define VID_HARDWARE_SF16MI 8 #define VID_HARDWARE_RTRACK 9 #define VID_HARDWARE_ZOLTRIX 10 #define VID_HARDWARE_SAA7146 11 #define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */ #define VID_HARDWARE_RTRACK2 13 #define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */ #define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */ #define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */ #define VID_HARDWARE_BROADWAY 17 /* Broadway project */ #define VID_HARDWARE_GEMTEK 18 #define VID_HARDWARE_TYPHOON 19 #define VID_HARDWARE_VINO 20 /* SGI Indy Vino */ #define VID_HARDWARE_CADET 21 /* Cadet radio */ #define VID_HARDWARE_TRUST 22 /* Trust FM Radio */ #define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */ #define VID_HARDWARE_CPIA 24 #define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */ #define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ #define VID_HARDWARE_OV511 27 #define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ #define VID_HARDWARE_W9966 29 #define VID_HARDWARE_SE401 30 /* SE401 USB webcams */ #define VID_HARDWARE_PWC 31 /* Philips webcams */ #define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ #define VID_HARDWARE_CPIA2 33 #define VID_HARDWARE_VICAM 34 #define VID_HARDWARE_SF16FMR2 35 #define VID_HARDWARE_W9968CF 36 #endif /* __LINUX_VIDEODEV_H */ /* * Local variables: * c-basic-offset: 8 * End: */ libindi-0.9.7/libs/webcam/ccvt_misc.c0000644000175000017500000003515012241463551016435 0ustar jasemjasem/* CCVT: ColourConVerT: simple library for converting colourspaces Copyright (C) 2002 Nemosoft Unv. Email:athomas@nemsoft.co.uk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA For questions, remarks, patches, etc. for this program, the author can be reached at nemosoft@smcc.demon.nl. */ /* This file contains CCVT functions that aren't available in assembly yet (or are not worth programming) */ /* * $Log$ * Revision 1.2 2005/04/29 16:51:20 mutlaqja * Adding initial support for Video 4 Linux 2 drivers. This mean that KStars can probably control Meade Lunar Planetary Imager (LPI). V4L2 requires a fairly recent kernel (> 2.6.9) and many drivers don't fully support it yet. It will take sometime. KStars still supports V4L1 and will continue so until V4L1 is obselete. Please test KStars video drivers if you can. Any comments welcomed. * * CCMAIL: kstars-devel@kde.org * * Revision 1.1 2004/06/26 23:12:03 mutlaqja * Hopefully this will fix compile issues on 64bit archs, and FreeBSD, among others. The assembly code is replaced with a more portable, albeit slower C implementation. I imported the videodev.h header after cleaning it for user space. * * Anyone who has problems compiling this, please report the problem to kstars-devel@kde.org * * I noticed one odd thing after updating my kdelibs, the LEDs don't change color when state is changed. Try that by starting any INDI device, and hit connect, if the LED turns to yellow and back to grey then it works fine, otherwise, we've got a problem. * * CCMAIL: kstars-devel@kde.org * * Revision 1.7 2003/01/02 04:10:19 nemosoft * Adding ''upside down" conversion to rgb/bgr routines * * Revision 1.6 2002/12/03 23:29:11 nemosoft * *** empty log message *** * * Revision 1.5 2002/12/03 23:27:41 nemosoft * fixing log messages (gcc 3.2 complaining) * Revision 1.4 2002/12/03 22:29:07 nemosoft Fixing up FTP stuff and some video Revision 1.3 2002/11/03 22:46:25 nemosoft Adding various RGB to RGB functions. Adding proper copyright header too. */ #include "ccvt.h" #include "ccvt_types.h" #include static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256]; static float RGBYUV01684[256], RGBYUV03316[256]; static float RGBYUV04187[256], RGBYUV00813[256]; void InitLookupTable(void); /* YUYV: two Y's and one U/V */ void ccvt_yuyv_rgb32(int width, int height, const void *src, void *dst) { width=width; height=height; src=src; dst=dst; } void ccvt_yuyv_bgr32(int width, int height, const void *src, void *dst) { const unsigned char *s; PIXTYPE_bgr32 *d; int l, c; int r, g, b, cr, cg, cb, y1, y2; l = height; s = src; d = dst; while (l--) { c = width >> 1; while (c--) { y1 = *s++; cb = ((*s - 128) * 454) >> 8; cg = (*s++ - 128) * 88; y2 = *s++; cr = ((*s - 128) * 359) >> 8; cg = (cg + (*s++ - 128) * 183) >> 8; r = y1 + cr; b = y1 + cb; g = y1 - cg; SAT(r); SAT(g); SAT(b); d->b = b; d->g = g; d->r = r; d++; r = y2 + cr; b = y2 + cb; g = y2 - cg; SAT(r); SAT(g); SAT(b); d->b = b; d->g = g; d->r = r; d++; } } } void ccvt_yuyv_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv) { int n, l, j; const unsigned char *s1, *s2; unsigned char *dy, *du, *dv; dy = (unsigned char *)dsty; du = (unsigned char *)dstu; dv = (unsigned char *)dstv; s1 = (unsigned char *)src; s2 = s1; /* keep pointer */ n = width * height; for (; n > 0; n--) { *dy = *s1; dy++; s1 += 2; } /* Two options here: average U/V values, or skip every second row */ s1 = s2; /* restore pointer */ s1++; /* point to U */ for (l = 0; l < height; l += 2) { s2 = s1 + width * 2; /* odd line */ for (j = 0; j < width; j += 2) { *du = (*s1 + *s2) / 2; du++; s1 += 2; s2 += 2; *dv = (*s1 + *s2) / 2; dv++; s1 += 2; s2 += 2; } s1 = s2; } } void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT) { long int i; unsigned char *rawpt, *scanpt; long int size; rawpt = src; scanpt = dst; size = WIDTH*HEIGHT; for ( i = 0; i < size; i++ ) { if ( (i/WIDTH) % 2 == 0 ) { if ( (i % 2) == 0 ) { /* B */ if ( (i > WIDTH) && ((i % WIDTH) > 0) ) { *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ *(rawpt+WIDTH)+*(rawpt-WIDTH))/4; /* G */ *scanpt++ = *rawpt; /* B */ } else { /* first line or left column */ *scanpt++ = *(rawpt+WIDTH+1); /* R */ *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; /* G */ *scanpt++ = *rawpt; /* B */ } } else { /* (B)G */ if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) { *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ } else { /* first line or right column */ *scanpt++ = *(rawpt+WIDTH); /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt-1); /* B */ } } } else { if ( (i % 2) == 0 ) { /* G(R) */ if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) { *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* B */ } else { /* bottom line or left column */ *scanpt++ = *(rawpt+1); /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt-WIDTH); /* B */ } } else { /* R */ if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) { *scanpt++ = *rawpt; /* R */ *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ *(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* B */ } else { /* bottom line or right column */ *scanpt++ = *rawpt; /* R */ *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */ *scanpt++ = *(rawpt-WIDTH-1); /* B */ } } } rawpt++; } } /* following lines are an Ilia Platone contribute, */ void rggb2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT) { long int i; unsigned char *rawpt, *scanpt; long int size; rawpt = src; scanpt = dst; size = WIDTH*HEIGHT; for ( i = 0; i < size; i++ ) { if ( (i/WIDTH) % 2 == 0 ) { if ( (i % 2) == 0 ) { /* B */ if ( (i > WIDTH) && ((i % WIDTH) > 0) ) { *scanpt++ = *rawpt; /* R */ *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ *(rawpt+WIDTH)+*(rawpt-WIDTH))/4; /* G */ *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* B */ } else { /* first line or left column */ *scanpt++ = *rawpt; /* R */ *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2; /* G */ *scanpt++ = *(rawpt+WIDTH+1); /* B */ } } else { /* (B)G */ if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) { *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* B */ } else { /* first line or right column */ *scanpt++ = *(rawpt-1); /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt+WIDTH); /* B */ } } } else { if ( (i % 2) == 0 ) { /* G(R) */ if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) { *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2; /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2; /* B */ } else { /* bottom line or left column */ *scanpt++ = *(rawpt-WIDTH); /* R */ *scanpt++ = *rawpt; /* G */ *scanpt++ = *(rawpt+1); /* B */ } } else { /* R */ if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) { *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+ *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4; /* R */ *scanpt++ = (*(rawpt-1)+*(rawpt+1)+ *(rawpt-WIDTH)+*(rawpt+WIDTH))/4; /* G */ *scanpt++ = *rawpt; /* B */ } else { /* bottom line or right column */ *scanpt++ = *(rawpt-WIDTH-1); /* R */ *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2; /* G */ *scanpt++ = *rawpt; /* B */ } } } rawpt++; } } void grey2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT) { long int i; unsigned char *destination, *source; long int size; source = src; destination = dst; size = WIDTH*HEIGHT; for ( i = 0; i < size; i++ ) { *destination++ = *(source + i); *destination++ = *(source + i); *destination++ = *(source + i); } } /************** end of contribute, more to come hopefully *****************/ /************************************************************************ * * int RGB2YUV (int x_dim, int y_dim, void *bmp, YUV *yuv) * * Purpose : It takes a 24-bit RGB bitmap and convert it into * YUV (4:2:0) format * * Input : x_dim the x dimension of the bitmap * y_dim the y dimension of the bitmap * bmp pointer to the buffer of the bitmap * yuv pointer to the YUV structure * * Output : 0 OK * 1 wrong dimension * 2 memory allocation error * * Side Effect : * None * * Date : 09/28/2000 * * Contacts: * * Adam Li * * DivX Advance Research Center * ************************************************************************/ int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip) { static int init_done = 0; long i, j, size; unsigned char *r, *g, *b; unsigned char *y, *u, *v; unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv; unsigned char *y_buffer, *u_buffer, *v_buffer; unsigned char *sub_u_buf, *sub_v_buf; if (init_done == 0) { InitLookupTable(); init_done = 1; } /* check to see if x_dim and y_dim are divisible by 2*/ if ((x_dim % 2) || (y_dim % 2)) return 1; size = x_dim * y_dim; /* allocate memory*/ y_buffer = (unsigned char *)y_out; sub_u_buf = (unsigned char *)u_out; sub_v_buf = (unsigned char *)v_out; u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char)); v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char)); if (!(u_buffer && v_buffer)) { if (u_buffer) free(u_buffer); if (v_buffer) free(v_buffer); return 2; } b = (unsigned char *)bmp; y = y_buffer; u = u_buffer; v = v_buffer; /* convert RGB to YUV*/ if (!flip) { for (j = 0; j < y_dim; j ++) { y = y_buffer + (y_dim - j - 1) * x_dim; u = u_buffer + (y_dim - j - 1) * x_dim; v = v_buffer + (y_dim - j - 1) * x_dim; for (i = 0; i < x_dim; i ++) { g = b + 1; r = b + 2; *y = (unsigned char)( RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]); *u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2 + 128); *v = (unsigned char)( (*r)/2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128); b += 3; y ++; u ++; v ++; } } } else { for (i = 0; i < size; i++) { g = b + 1; r = b + 2; *y = (unsigned char)( RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]); *u = (unsigned char)(- RGBYUV01684[*r] - RGBYUV03316[*g] + (*b)/2 + 128); *v = (unsigned char)( (*r)/2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128); b += 3; y ++; u ++; v ++; } } /* subsample UV*/ for (j = 0; j < y_dim/2; j ++) { psu = sub_u_buf + j * x_dim / 2; psv = sub_v_buf + j * x_dim / 2; pu1 = u_buffer + 2 * j * x_dim; pu2 = u_buffer + (2 * j + 1) * x_dim; pv1 = v_buffer + 2 * j * x_dim; pv2 = v_buffer + (2 * j + 1) * x_dim; for (i = 0; i < x_dim/2; i ++) { *psu = (*pu1 + *(pu1+1) + *pu2 + *(pu2+1)) / 4; *psv = (*pv1 + *(pv1+1) + *pv2 + *(pv2+1)) / 4; psu ++; psv ++; pu1 += 2; pu2 += 2; pv1 += 2; pv2 += 2; } } free(u_buffer); free(v_buffer); return 0; } void InitLookupTable() { int i; for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i; for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i; for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i; for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i; for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i; for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i; for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i; } /* RGB/BGR to RGB/BGR */ #define RGBBGR_BODY24(TIN, TOUT) \ void ccvt_ ## TIN ## _ ## TOUT (int width, int height, const void *const src, void *dst) \ { \ const PIXTYPE_ ## TIN *in = src; \ PIXTYPE_ ## TOUT *out = dst; \ int l, c, stride = 0; \ \ stride = width; \ out += ((height - 1) * width); \ stride *= 2; \ for (l = 0; l < height; l++) { \ for (c = 0; c < width; c++) { \ out->r = in->r; \ out->g = in->g; \ out->b = in->b; \ in++; \ out++; \ } \ out -= stride; \ } \ } #define RGBBGR_BODY32(TIN, TOUT) \ void ccvt_ ## TIN ## _ ## TOUT (int width, int height, const void *const src, void *dst) \ { \ const PIXTYPE_ ## TIN *in = src; \ PIXTYPE_ ## TOUT *out = dst; \ int l, c, stride = 0; \ \ stride = width;\ out += ((height - 1) * width); \ stride *= 2; \ for (l = 0; l < height; l++) { \ for (c = 0; c < width; c++) { \ out->r = in->r; \ out->g = in->g; \ out->b = in->b; \ out->z = 0; \ in++; \ out++; \ } \ out -= stride; \ } \ } RGBBGR_BODY32(bgr24, bgr32) RGBBGR_BODY32(bgr24, rgb32) RGBBGR_BODY32(rgb24, bgr32) RGBBGR_BODY32(rgb24, rgb32) RGBBGR_BODY24(bgr32, bgr24) RGBBGR_BODY24(bgr32, rgb24) RGBBGR_BODY24(rgb32, bgr24) RGBBGR_BODY24(rgb32, rgb24) libindi-0.9.7/libs/webcam/v4l2_base.h0000644000175000017500000000731012241463551016246 0ustar jasemjasem/* Copyright (C) 2005 by Jasem Mutlaq Based on V4L 2 Example http://v4l2spec.bytesex.org/spec-single/v4l2.html#CAPTURE-EXAMPLE 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 */ #ifndef V4L2_BASE_H #define V4L2_BASE_H #include #include #include "videodev2.h" #include "eventloop.h" #include "indidevapi.h" #define VIDEO_COMPRESSION_LEVEL 4 class V4L2_Base { public: V4L2_Base(); virtual ~V4L2_Base(); typedef enum { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR } io_method; struct buffer { void * start; size_t length; }; /* Connection */ virtual int connectCam(const char * devpath, char *errmsg, int pixelFormat = -1 , int width = -1, int height = -1); virtual void disconnectCam(); char * getDeviceName(); /* Image settings */ int getBrightness(); int getContrast(); int getColor(); int getHue(); int getWhiteness(); void setContrast(int val); void setBrightness(int val); void setColor(int val); void setHue(int val); void setWhiteness(int val); /* Updates */ void callFrame(void *p); void setPictureSettings(); void getPictureSettings(); /* Image Size */ int getWidth(); int getHeight(); virtual int setSize(int x, int y); virtual void getMaxMinSize(int & x_max, int & y_max, int & x_min, int & y_min); /* Frame rate */ void setFPS(int fps); int getFPS(); void allocBuffers(); unsigned char * getY(); unsigned char * getU(); unsigned char * getV(); unsigned char * getColorBuffer(); void registerCallback(WPF *fp, void *ud); int start_capturing(char *errmsg); int stop_capturing(char *errmsg); static void newFrame(int fd, void *p); void enumerate_ctrl (void); void enumerate_menu (void); int queryINTControls(INumberVectorProperty *nvp); int setINTControl(unsigned int ctrl_id, double new_value, char *errmsg); int query_ctrl(unsigned int ctrl_id, double & ctrl_min, double & ctrl_max, double & ctrl_step, double & ctrl_value, char *errmsg); protected: int xioctl(int fd, int request, void *arg); int read_frame(char *errsg); int uninit_device(char *errmsg); int open_device(const char *devpath, char *errmsg); int init_device(char *errmsg, int pixelFormat , int width, int height); int init_mmap(char *errmsg); int errno_exit(const char *s, char *errmsg); void close_device(void); void init_userp(unsigned int buffer_size); void init_read(unsigned int buffer_size); void findMinMax(); struct v4l2_capability cap; struct v4l2_cropcap cropcap; struct v4l2_crop crop; struct v4l2_format fmt; struct v4l2_queryctrl queryctrl; struct v4l2_querymenu querymenu; WPF *callback; void *uptr; char dev_name[64]; io_method io; int fd; struct buffer *buffers; unsigned int n_buffers; bool dropFrame; int frameRate; int xmax, xmin, ymax, ymin; int selectCallBackID; unsigned char * YBuf,*UBuf,*VBuf, *colorBuffer, *rgb24_buffer; }; #endif libindi-0.9.7/libs/webcam/port.h0000644000175000017500000001013312241463551015446 0ustar jasemjasem/* libcqcam - shared Color Quickcam routines * Copyright (C) 1996-1998 by Patrick Reynolds * Email: * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. */ // I/O ports wrapper definitions and prototypes // This file might need tweaking if you're trying to port my code to other // x86 Unix platforms. Code is already available for Linux, FreeBSD, and // QNX; see the Makefile. // // QNX code by: Anders Arpteg // FreeBSD code by: Patrick Reynolds and Charles // Henrich // Inlining implemented by: Philip Blundell #ifndef PORT_H #define PORT_H //#include "config.h" #include #ifdef __linux__ #if !defined(arm) && !defined(__hppa__) && !defined(__sparc__) && !defined(__ppc__) && !defined(__powerpc__) && !defined(__s390__) && !defined(__s390x__) && !defined(__mips__) && !defined(__mc68000__) #include #endif /* !arm */ #elif defined(QNX) #include #elif defined(__FreeBSD__) #include #include #elif defined(BSDI) #include #elif defined(OPENBSD) #include #elif defined(LYNX) #include "lynx-io.h" #elif defined(SOLARIS) #include "solaris-io.h" #else #error Please define a platform in the Makefile #endif #if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__) static char ports_temp; #ifdef inb #undef inb #endif /* inb */ #define inb(port) \ lseek(devport, port, SEEK_SET), \ read(devport, &ports_temp, 1), \ ports_temp #ifdef outb #undef outb #endif /* inb */ #define outb(data, port) \ lseek(devport, port, SEEK_SET); \ ports_temp = data; \ write(devport, &ports_temp, 1); #endif /* arm, hppa */ class port_t { public: port_t(int iport); ~port_t(void); inline int read_data(void) { return inb(port); } inline int read_status(void) { return inb(port1); } inline int read_control(void) { return inb(port2); } #if defined(LINUX) || defined(LYNX) inline void write_data(int data) { outb(data, port); } inline void write_control(int data) { outb(control_reg = data, port2); } inline void setbit_control(int data) { outb(control_reg |= data, port2); } inline void clearbit_control(int data) { outb(control_reg &= ~data, port2); } #else // Solaris, QNX, and *BSD use (port, data) instead inline void write_data(int data) { outb(port, data); } inline void write_control(int data) { outb(port2, control_reg = data); } inline void setbit_control(int data) { outb(port2, control_reg |= data); } inline void clearbit_control(int data) { outb(port2, control_reg &= ~data); } #endif inline int get_port() { return port; } inline operator bool () const { return port != -1; } private: int port; // number of the base port int port1; // port+1, precalculated for speed int port2; // port+2, precalculated for speed int control_reg; // current contents of the control register #ifdef LOCKING int lock_fd; int lock(int portnum); void unlock(int portnum); #endif #ifdef FREEBSD FILE *devio; #endif #if defined(__linux__) && (defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) || defined(__powerpc__) || defined(__s390__) || defined(__s390x__) || defined(__mips__) || defined(__mc68000__)) int devport; #endif }; #endif libindi-0.9.7/libs/webcam/ccvt_c2.c0000644000175000017500000000647312241463551016014 0ustar jasemjasem/* CCVT_C2: Convert an image from yuv colourspace to rgb Copyright (C) 2001 Tony Hague This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA For questions, remarks, patches, etc. for this program, the author can be reached at nemosoft@smcc.demon.nl. */ #include "ccvt.h" #include "ccvt_types.h" /* by suitable definition of PIXTYPE, can do yuv to rgb or bgr, with or without word alignment */ /* This doesn't exactly earn a prize in a programming beauty contest. */ #define WHOLE_FUNC2RGB(type) \ const unsigned char *y1, *y2, *u, *v; \ PIXTYPE_##type *l1, *l2; \ int r, g, b, cr, cg, cb, yp, j, i; \ \ if ((width & 1) || (height & 1)) \ return; \ \ l1 = (PIXTYPE_##type *)dst; \ l2 = l1 + width; \ y1 = (unsigned char *)src; \ y2 = y1 + width; \ u = (unsigned char *)src + width * height; \ v = u + (width * height) / 4; \ j = height / 2; \ while (j--) { \ i = width / 2; \ while (i--) { \ /* Since U & V are valid for 4 pixels, repeat code 4 \ times for different Y */ \ cb = ((*u-128) * 454)>>8; \ cr = ((*v-128) * 359)>>8; \ cg = ((*v-128) * 183 + (*u-128) * 88)>>8; \ \ yp = *(y1++); \ r = yp + cr; \ b = yp + cb; \ g = yp - cg; \ SAT(r); \ SAT(g); \ SAT(b); \ l1->b = b; \ l1->g = g; \ l1->r = r; \ l1++; \ \ yp = *(y1++); \ r = yp + cr; \ b = yp + cb; \ g = yp - cg; \ SAT(r); \ SAT(g); \ SAT(b); \ l1->b = b; \ l1->g = g; \ l1->r = r; \ l1++; \ \ yp = *(y2++); \ r = yp + cr; \ b = yp + cb; \ g = yp - cg; \ SAT(r); \ SAT(g); \ SAT(b); \ l2->b = b; \ l2->g = g; \ l2->r = r; \ l2++; \ \ yp = *(y2++); \ r = yp + cr; \ b = yp + cb; \ g = yp - cg; \ SAT(r); \ SAT(g); \ SAT(b); \ l2->b = b; \ l2->g = g; \ l2->r = r; \ l2++; \ \ u++; \ v++; \ } \ y1 = y2; \ y2 += width; \ l1 = l2; \ l2 += width; \ } void ccvt_420p_bgr32(int width, int height, const void *src, void *dst) { WHOLE_FUNC2RGB(bgr32) } void ccvt_420p_bgr24(int width, int height, const void *src, void *dst) { WHOLE_FUNC2RGB(bgr24) } void ccvt_420p_rgb32(int width, int height, const void *src, void *dst) { WHOLE_FUNC2RGB(rgb32) } void ccvt_420p_rgb24(int width, int height, const void *src, void *dst) { WHOLE_FUNC2RGB(rgb24) } libindi-0.9.7/libs/webcam/port.cpp0000644000175000017500000001224312241463551016005 0ustar jasemjasem/* libcqcam - shared Color Quickcam routines * Copyright (C) 1996-1998 by Patrick Reynolds * Email: * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library 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. */ // I/O ports wrapper code // This file might need tweaking if you're trying to port my code to other // x86 Unix platforms. Code is already available for Linux, FreeBSD, and // QNX; see the Makefile. // // QNX code by: Anders Arpteg // FreeBSD code by: Patrick Reynolds and Charles // Henrich //#include "config.h" #include #include #ifdef LOCKING #include #include #endif /* LOCKING */ #ifdef __linux__ #if defined(arm) || defined(__hppa__) || defined(__sparc__) || defined(__ppc__) \ || defined(__powerpc__) || defined(__s390__) || defined(__s390x__)\ || defined(__mips__) || defined(__mc68000__) || defined(__sh__) #define NO_SYSIO #endif /* architechtures */ #endif /* __linux__ */ #ifdef __linux__ #if defined(NO_SYSIO) #include #else #include #endif /* NO_SYSIO */ #elif defined(QNX) #include #elif defined(__FreeBSD__) #include #include #elif defined(BSDI) #include #elif defined(OPENBSD) #include #elif defined(LYNX) #include "lynx-io.h" #elif defined(SOLARIS) #include "solaris-io.h" #else #error Please define a platform in the Makefile #endif /* which OS */ #include "port.h" port_t::port_t(int iport) { port = -1; #ifdef LOCKING if (lock(iport) == -1) { #ifdef DEBUG fprintf(stderr, "port 0x%x already locked\n", iport); #endif /* DEBUG */ return; } #endif /* LOCKING */ #ifdef LINUX #ifdef NO_SYSIO if ((devport = open("/dev/port", O_RDWR)) < 0) { perror("open /dev/port"); return; } #else if (ioperm(iport, 3, 1) == -1) { perror("ioperm()"); return; } #endif /* NO_SYSIO */ #elif defined(FREEBSD) if ((devio = fopen("/dev/io", "r+")) == NULL) { perror("fopen /dev/io"); return; } #elif defined(OPENBSD) if (i386_iopl(1) == -1) { perror("i386_iopl"); return; } #elif defined(LYNX) if (io_access() < 0) { perror("io_access"); return; } #elif defined(SOLARIS) if (openiop()) { perror("openiop"); return; } #endif /* which OS */ port = iport; port1 = port + 1; port2 = port + 2; control_reg = read_control(); } port_t::~port_t(void) { #ifdef LOCKING unlock(port); #endif /* LOCKING */ #ifdef LINUX #ifdef NO_SYSIO if (devport >= 0) close(devport); #else if (port > 0 && geteuid() == 0) if (ioperm(port, 3, 0) != 0) // drop port permissions -- still must // be root perror("ioperm()"); #endif /* NO_SYSIO */ #elif defined(FREEBSD) if (devio != NULL) fclose(devio); #elif defined(SOLARIS) close(iopfd); #endif /* which OS */ } #ifdef LOCKING int port_t::lock(int portnum) { char lockfile[80]; sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum); while ((lock_fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == -1) { if (errno != EEXIST) { perror(lockfile); return -1; } struct stat stat_buf; if (lstat(lockfile, &stat_buf) < 0) continue; if (S_ISLNK(stat_buf.st_mode) || stat_buf.st_uid != 0) { if (unlink(lockfile)) { if (errno == ENOENT) continue; if (errno != EISDIR || (rmdir(lockfile) && errno != ENOENT)) { /* known problem: if lockfile exists and is a non-empty directory, we give up instead of doing an rm-r of it */ perror(lockfile); return -1; } } continue; } lock_fd = open(lockfile, O_WRONLY, 0600); if (lock_fd == -1) { perror(lockfile); return -1; } break; } static struct flock lock_info; lock_info.l_type = F_WRLCK; #ifdef LOCK_FAIL if (fcntl(lock_fd, F_SETLK, &lock_info) != 0) { #else if (fcntl(lock_fd, F_SETLKW, &lock_info) != 0) { #endif /* LOCK_FAIL */ if (errno != EAGAIN) perror("fcntl"); return -1; } chown(lockfile, getuid(), getgid()); #ifdef DEBUG fprintf(stderr, "Locked port 0x%x\n", portnum); #endif /* DEBUG */ return 0; } void port_t::unlock(int portnum) { if (portnum == -1) return; close(lock_fd); // this clears the lock char lockfile[80]; sprintf(lockfile, "/tmp/LOCK.qcam.0x%x", portnum); if (unlink(lockfile)) perror(lockfile); #ifdef DEBUG fprintf(stderr, "Unlocked port 0x%x\n", portnum); #endif /* DEBUG */ } #endif /* LOCKING */ libindi-0.9.7/libs/webcam/v4l2_base.cpp0000644000175000017500000010062712241463551016606 0ustar jasemjasem/* Copyright (C) 2005 by Jasem Mutlaq Based on V4L 2 Example http://v4l2spec.bytesex.org/spec-single/v4l2.html#CAPTURE-EXAMPLE 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 */ #include #include #include #include #include #include #include #include #include #include #include #include /* for videodev2.h */ #include "ccvt.h" #include "v4l2_base.h" #include "eventloop.h" #include "indidevapi.h" #define ERRMSGSIZ 1024 #define CLEAR(x) memset (&(x), 0, sizeof (x)) using namespace std; V4L2_Base::V4L2_Base() { frameRate=10; selectCallBackID = -1; dropFrame = false; xmax = xmin = 160; ymax = ymin = 120; io = IO_METHOD_MMAP; fd = -1; buffers = NULL; n_buffers = 0; YBuf = NULL; UBuf = NULL; VBuf = NULL; colorBuffer = NULL; rgb24_buffer = NULL; callback = NULL; } V4L2_Base::~V4L2_Base() { delete (YBuf); delete (UBuf); delete (VBuf); delete (colorBuffer); delete (rgb24_buffer); } int V4L2_Base::xioctl(int fd, int request, void *arg) { int r; do r = ioctl (fd, request, arg); while (-1 == r && EINTR == errno); return r; } int V4L2_Base::errno_exit(const char *s, char *errmsg) { fprintf (stderr, "%s error %d, %s\n", s, errno, strerror (errno)); snprintf(errmsg, ERRMSGSIZ, "%s error %d, %s\n", s, errno, strerror (errno)); return -1; } int V4L2_Base::connectCam(const char * devpath, char *errmsg , int pixelFormat , int width , int height ) { frameRate=10; selectCallBackID = -1; dropFrame = false; if (open_device (devpath, errmsg) < 0) return -1; if (init_device(errmsg, pixelFormat, width, height) < 0) return -1; cerr << "V4L 2 - All successful, returning\n"; return fd; } void V4L2_Base::disconnectCam() { char errmsg[ERRMSGSIZ]; delete YBuf; delete UBuf; delete VBuf; YBuf = UBuf = VBuf = NULL; if (selectCallBackID != -1) rmCallback(selectCallBackID); stop_capturing (errmsg); uninit_device (errmsg); close_device (); fprintf(stderr, "Disconnect cam\n"); } int V4L2_Base::read_frame(char *errmsg) { struct v4l2_buffer buf; unsigned int i; //cerr << "in read Frame" << endl; switch (io) { case IO_METHOD_READ: if (-1 == read (fd, buffers[0].start, buffers[0].length)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: return errno_exit ("read", errmsg); } } //process_image (buffers[0].start); break; case IO_METHOD_MMAP: CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: return errno_exit ("VIDIOC_DQBUF", errmsg); } } assert (buf.index < n_buffers); switch (fmt.fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: memcpy(YBuf,((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width * fmt.fmt.pix.height); memcpy(UBuf,((unsigned char *) buffers[buf.index].start) + fmt.fmt.pix.width * fmt.fmt.pix.height, (fmt.fmt.pix.width/2) * (fmt.fmt.pix.height/2)); memcpy(VBuf,((unsigned char *) buffers[buf.index].start) + fmt.fmt.pix.width * fmt.fmt.pix.height + (fmt.fmt.pix.width/2) * (fmt.fmt.pix.height/2), (fmt.fmt.pix.width/2) * (fmt.fmt.pix.width/2)); break; case V4L2_PIX_FMT_YUYV: ccvt_yuyv_420p( fmt.fmt.pix.width , fmt.fmt.pix.height, buffers[buf.index].start, YBuf, UBuf, VBuf); break; case V4L2_PIX_FMT_RGB24: RGB2YUV(fmt.fmt.pix.width, fmt.fmt.pix.height, buffers[buf.index].start, YBuf, UBuf, VBuf, 0); break; case V4L2_PIX_FMT_SBGGR8: bayer2rgb24(rgb24_buffer, ((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width, fmt.fmt.pix.height); break; case V4L2_PIX_FMT_SRGGB8: rggb2rgb24(rgb24_buffer, ((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width, fmt.fmt.pix.height); break; case V4L2_PIX_FMT_GREY: grey2rgb24(rgb24_buffer, ((unsigned char *) buffers[buf.index].start), fmt.fmt.pix.width, fmt.fmt.pix.height); break; } /*if (dropFrame) { dropFrame = false; return 0; } */ /* Call provided callback function if any */ if (callback) (*callback)(uptr); if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) return errno_exit ("ReadFrame IO_METHOD_MMAP: VIDIOC_QBUF", errmsg); break; case IO_METHOD_USERPTR: CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; if (-1 == xioctl (fd, VIDIOC_DQBUF, &buf)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: errno_exit ("VIDIOC_DQBUF", errmsg); } } for (i = 0; i < n_buffers; ++i) if (buf.m.userptr == (unsigned long) buffers[i].start && buf.length == buffers[i].length) break; assert (i < n_buffers); //process_image ((void *) buf.m.userptr); if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) errno_exit ("ReadFrame IO_METHOD_USERPTR: VIDIOC_QBUF", errmsg); break; } return 0; } int V4L2_Base::stop_capturing(char *errmsg) { enum v4l2_buf_type type; switch (io) { case IO_METHOD_READ: /* Nothing to do. */ break; case IO_METHOD_MMAP: case IO_METHOD_USERPTR: type = V4L2_BUF_TYPE_VIDEO_CAPTURE; IERmCallback(selectCallBackID); selectCallBackID = -1; // N.B. I used this as a hack to solve a problem with capturing a frame // long time ago. I recently tried taking this hack off, and it worked fine! //dropFrame = true; if (-1 == xioctl (fd, VIDIOC_STREAMOFF, &type)) return errno_exit ("VIDIOC_STREAMOFF", errmsg); break; } return 0; } int V4L2_Base::start_capturing(char * errmsg) { unsigned int i; enum v4l2_buf_type type; switch (io) { case IO_METHOD_READ: /* Nothing to do. */ break; case IO_METHOD_MMAP: for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) return errno_exit ("StartCapturing IO_METHOD_MMAP: VIDIOC_QBUF", errmsg); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) return errno_exit ("VIDIOC_STREAMON", errmsg); selectCallBackID = IEAddCallback(fd, newFrame, this); break; case IO_METHOD_USERPTR: for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_USERPTR; buf.m.userptr = (unsigned long) buffers[i].start; buf.length = buffers[i].length; if (-1 == xioctl (fd, VIDIOC_QBUF, &buf)) return errno_exit ("StartCapturing IO_METHOD_USERPTR: VIDIOC_QBUF", errmsg); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_STREAMON, &type)) return errno_exit ("VIDIOC_STREAMON", errmsg); break; } return 0; } void V4L2_Base::newFrame(int /*fd*/, void *p) { char errmsg[ERRMSGSIZ]; ( (V4L2_Base *) (p))->read_frame(errmsg); } int V4L2_Base::uninit_device(char *errmsg) { switch (io) { case IO_METHOD_READ: free (buffers[0].start); break; case IO_METHOD_MMAP: for (unsigned int i = 0; i < n_buffers; ++i) if (-1 == munmap (buffers[i].start, buffers[i].length)) return errno_exit ("munmap", errmsg); break; case IO_METHOD_USERPTR: for (unsigned int i = 0; i < n_buffers; ++i) free (buffers[i].start); break; } free (buffers); return 0; } void V4L2_Base::init_read(unsigned int buffer_size) { buffers = (buffer *) calloc (1, sizeof (*buffers)); if (!buffers) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } buffers[0].length = buffer_size; buffers[0].start = malloc (buffer_size); if (!buffers[0].start) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } } int V4L2_Base::init_mmap(char *errmsg) { struct v4l2_requestbuffers req; CLEAR (req); req.count = 4; //req.count = 1; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf (stderr, "%s does not support " "memory mapping\n", dev_name); snprintf(errmsg, ERRMSGSIZ, "%s does not support " "memory mapping\n", dev_name); return -1; } else { return errno_exit ("VIDIOC_REQBUFS", errmsg); } } if (req.count < 2) { fprintf (stderr, "Insufficient buffer memory on %s\n", dev_name); snprintf(errmsg, ERRMSGSIZ, "Insufficient buffer memory on %s\n", dev_name); return -1; } buffers = (buffer *) calloc (req.count, sizeof (*buffers)); if (!buffers) { fprintf (stderr, "buffers. Out of memory\n"); strncpy(errmsg, "buffers. Out of memory\n", ERRMSGSIZ); return -1; } for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; if (-1 == xioctl (fd, VIDIOC_QUERYBUF, &buf)) return errno_exit ("VIDIOC_QUERYBUF", errmsg); buffers[n_buffers].length = buf.length; buffers[n_buffers].start = mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); if (MAP_FAILED == buffers[n_buffers].start) return errno_exit ("mmap", errmsg); } return 0; } void V4L2_Base::init_userp(unsigned int buffer_size) { struct v4l2_requestbuffers req; char errmsg[ERRMSGSIZ]; CLEAR (req); req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_USERPTR; if (-1 == xioctl (fd, VIDIOC_REQBUFS, &req)) { if (EINVAL == errno) { fprintf (stderr, "%s does not support " "user pointer i/o\n", dev_name); exit (EXIT_FAILURE); } else { errno_exit ("VIDIOC_REQBUFS", errmsg); } } buffers = (buffer *) calloc (4, sizeof (*buffers)); if (!buffers) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } for (n_buffers = 0; n_buffers < 4; ++n_buffers) { buffers[n_buffers].length = buffer_size; buffers[n_buffers].start = malloc (buffer_size); if (!buffers[n_buffers].start) { fprintf (stderr, "Out of memory\n"); exit (EXIT_FAILURE); } } } int V4L2_Base::init_device(char *errmsg, int pixelFormat , int width, int height) { unsigned int min; if (-1 == xioctl (fd, VIDIOC_QUERYCAP, &cap)) { if (EINVAL == errno) { fprintf (stderr, "%s is no V4L2 device\n", dev_name); snprintf(errmsg, ERRMSGSIZ, "%s is no V4L2 device\n", dev_name); return -1; } else { return errno_exit ("VIDIOC_QUERYCAP", errmsg); } } if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf (stderr, "%s is no video capture device\n", dev_name); snprintf(errmsg, ERRMSGSIZ, "%s is no video capture device\n", dev_name); return -1; } switch (io) { case IO_METHOD_READ: if (!(cap.capabilities & V4L2_CAP_READWRITE)) { fprintf (stderr, "%s does not support read i/o\n", dev_name); snprintf(errmsg, ERRMSGSIZ, "%s does not support read i/o\n", dev_name); return -1; } break; case IO_METHOD_MMAP: case IO_METHOD_USERPTR: if (!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf (stderr, "%s does not support streaming i/o\n", dev_name); snprintf(errmsg, ERRMSGSIZ, "%s does not support streaming i/o\n", dev_name); return -1; } break; } /* Select video input, video standard and tune here. */ cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_CROPCAP, &cropcap)) { /* Errors ignored. */ } crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect; /* reset to default */ if (-1 == xioctl (fd, VIDIOC_S_CROP, &crop)) { switch (errno) { case EINVAL: /* Cropping not supported. */ break; default: /* Errors ignored. */ break; } } CLEAR (fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt)) return errno_exit ("VIDIOC_G_FMT", errmsg); fmt.fmt.pix.width = (width == -1) ? fmt.fmt.pix.width : width; fmt.fmt.pix.height = (height == -1) ? fmt.fmt.pix.height : height; fmt.fmt.pix.pixelformat = (pixelFormat == -1) ? fmt.fmt.pix.pixelformat : pixelFormat; //fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) return errno_exit ("VIDIOC_S_FMT", errmsg); /* Note VIDIOC_S_FMT may change width and height. */ /* Buggy driver paranoia. */ min = fmt.fmt.pix.width * 2; if (fmt.fmt.pix.bytesperline < min) fmt.fmt.pix.bytesperline = min; min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; if (fmt.fmt.pix.sizeimage < min) fmt.fmt.pix.sizeimage = min; /* Let's get the actual size */ CLEAR(fmt); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (fd, VIDIOC_G_FMT, &fmt)) return errno_exit ("VIDIOC_G_FMT", errmsg); cerr << "width: " << fmt.fmt.pix.width << " - height: " << fmt.fmt.pix.height << endl; switch (pixelFormat) { case V4L2_PIX_FMT_YUV420: cerr << "pixel format: V4L2_PIX_FMT_YUV420" << endl; break; case V4L2_PIX_FMT_YUYV: cerr << "pixel format: V4L2_PIX_FMT_YUYV" << endl; break; case V4L2_PIX_FMT_RGB24: cerr << "pixel format: V4L2_PIX_FMT_RGB24" << endl; break; case V4L2_PIX_FMT_SBGGR8: cerr << "pixel format: V4L2_PIX_FMT_SBGGR8" << endl; break; case V4L2_PIX_FMT_SRGGB8: cerr << "pixel format: V4L2_PIX_FMT_SRGGB8" << endl; break; case V4L2_PIX_FMT_GREY: cerr << "pixel format: V4L2_PIX_FMT_GREY" << endl; break; } findMinMax(); allocBuffers(); switch (io) { case IO_METHOD_READ: init_read (fmt.fmt.pix.sizeimage); break; case IO_METHOD_MMAP: return init_mmap(errmsg); break; case IO_METHOD_USERPTR: init_userp (fmt.fmt.pix.sizeimage); break; } return 0; } void V4L2_Base::close_device(void) { char errmsg[ERRMSGSIZ]; if (-1 == close (fd)) errno_exit ("close", errmsg); fd = -1; } int V4L2_Base::open_device(const char *devpath, char *errmsg) { struct stat st; strncpy(dev_name, devpath, 64); if (-1 == stat (dev_name, &st)) { fprintf (stderr, "Cannot identify '%s': %d, %s\n", dev_name, errno, strerror (errno)); snprintf(errmsg, ERRMSGSIZ, "Cannot identify '%s': %d, %s\n", dev_name, errno, strerror (errno)); return -1; } if (!S_ISCHR (st.st_mode)) { fprintf (stderr, "%s is no device\n", dev_name); snprintf(errmsg, ERRMSGSIZ, "%s is no device\n", dev_name); return -1; } fd = open (dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); if (-1 == fd) { fprintf (stderr, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror (errno)); snprintf(errmsg, ERRMSGSIZ, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror (errno)); return -1; } return 0; } int V4L2_Base::getWidth() { return fmt.fmt.pix.width; } int V4L2_Base::getHeight() { return fmt.fmt.pix.height; } void V4L2_Base::setFPS(int fps) { frameRate = 15;//fps; } int V4L2_Base::getFPS() { return 15; } char * V4L2_Base::getDeviceName() { return ((char *) cap.card); } void V4L2_Base::allocBuffers() { delete (YBuf); YBuf = NULL; delete (UBuf); UBuf = NULL; delete (VBuf); VBuf = NULL; delete (colorBuffer); colorBuffer = NULL; delete (rgb24_buffer); rgb24_buffer = NULL; YBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height]; UBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height]; VBuf= new unsigned char[ fmt.fmt.pix.width * fmt.fmt.pix.height]; colorBuffer = new unsigned char[fmt.fmt.pix.width * fmt.fmt.pix.height * 4]; if ( fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8 || fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SRGGB8 || fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_GREY) rgb24_buffer = new unsigned char[fmt.fmt.pix.width * fmt.fmt.pix.height * 3]; } void V4L2_Base::getMaxMinSize(int & x_max, int & y_max, int & x_min, int & y_min) { x_max = xmax; y_max = ymax; x_min = xmin; y_min = ymin; } int V4L2_Base::setSize(int x, int y) { char errmsg[ERRMSGSIZ]; int oldW, oldH; oldW = fmt.fmt.pix.width; oldH = fmt.fmt.pix.height; fmt.fmt.pix.width = x; fmt.fmt.pix.height = y; if (-1 == xioctl (fd, VIDIOC_S_FMT, &fmt)) { fmt.fmt.pix.width = oldW; fmt.fmt.pix.height = oldH; return errno_exit ("VIDIOC_S_FMT", errmsg); } /* PWC bug? It seems that setting the "wrong" width and height will mess something in the driver. Only 160x120, 320x280, and 640x480 are accepted. If I try to set it for example to 300x200, it wii get set to 320x280, which is fine, but then the video information is messed up for some reason. */ xioctl (fd, VIDIOC_S_FMT, &fmt); allocBuffers(); return 0; } void V4L2_Base::setContrast(int val) { /*picture_.contrast=val; updatePictureSettings();*/ } int V4L2_Base::getContrast() { return 255;//picture_.contrast; } void V4L2_Base::setBrightness(int val) { /*picture_.brightness=val; updatePictureSettings();*/ } int V4L2_Base::getBrightness() { return 255;//picture_.brightness; } void V4L2_Base::setColor(int val) { /*picture_.colour=val; updatePictureSettings();*/ } int V4L2_Base::getColor() { return 255; //picture_.colour; } void V4L2_Base::setHue(int val) { /*picture_.hue=val; updatePictureSettings();*/ } int V4L2_Base::getHue() { return 255;//picture_.hue; } void V4L2_Base::setWhiteness(int val) { /*picture_.whiteness=val; updatePictureSettings();*/ } int V4L2_Base::getWhiteness() { return 255;//picture_.whiteness; } void V4L2_Base::setPictureSettings() { /*if (ioctl(device_, VIDIOCSPICT, &picture_) ) { cerr << "updatePictureSettings" << endl; } ioctl(device_, VIDIOCGPICT, &picture_);*/ } void V4L2_Base::getPictureSettings() { /*if (ioctl(device_, VIDIOCGPICT, &picture_) ) { cerr << "refreshPictureSettings" << endl; }*/ } unsigned char * V4L2_Base::getY() { if ( fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SBGGR8 || fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_SRGGB8 || fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_GREY) RGB2YUV(fmt.fmt.pix.width, fmt.fmt.pix.height, rgb24_buffer, YBuf, UBuf, VBuf, 0); return YBuf; } unsigned char * V4L2_Base::getU() { return UBuf; } unsigned char * V4L2_Base::getV() { return VBuf; } unsigned char * V4L2_Base::getColorBuffer() { //cerr << "in get color buffer " << endl; switch (fmt.fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUV420: ccvt_420p_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height, buffers[0].start, (void*)colorBuffer); break; case V4L2_PIX_FMT_YUYV: ccvt_yuyv_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height, buffers[0].start, (void*)colorBuffer); break; case V4L2_PIX_FMT_RGB24: ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height, buffers[0].start, (void*)colorBuffer); break; case V4L2_PIX_FMT_SBGGR8: ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height, rgb24_buffer, (void*)colorBuffer); break; case V4L2_PIX_FMT_SRGGB8: ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height, rgb24_buffer, (void*)colorBuffer); break; case V4L2_PIX_FMT_GREY: ccvt_rgb24_bgr32(fmt.fmt.pix.width, fmt.fmt.pix.height, rgb24_buffer, (void*)colorBuffer); break; default: break; } return colorBuffer; } void V4L2_Base::registerCallback(WPF *fp, void *ud) { callback = fp; uptr = ud; } void V4L2_Base::findMinMax() { char errmsg[ERRMSGSIZ]; struct v4l2_format tryfmt; CLEAR(tryfmt); xmin = xmax = fmt.fmt.pix.width; ymin = ymax = fmt.fmt.pix.height; tryfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; tryfmt.fmt.pix.width = 10; tryfmt.fmt.pix.height = 10; tryfmt.fmt.pix.pixelformat = fmt.fmt.pix.pixelformat; tryfmt.fmt.pix.field = fmt.fmt.pix.field; if (-1 == xioctl (fd, VIDIOC_TRY_FMT, &tryfmt)) { errno_exit ("VIDIOC_TRY_FMT 1", errmsg); return; } xmin = tryfmt.fmt.pix.width; ymin = tryfmt.fmt.pix.height; tryfmt.fmt.pix.width = 1600; tryfmt.fmt.pix.height = 1200; if (-1 == xioctl (fd, VIDIOC_TRY_FMT, &tryfmt)) { errno_exit ("VIDIOC_TRY_FMT 2", errmsg); return; } xmax = tryfmt.fmt.pix.width; ymax = tryfmt.fmt.pix.height; cerr << "Min X: " << xmin << " - Max X: " << xmax << " - Min Y: " << ymin << " - Max Y: " << ymax << endl; } void V4L2_Base::enumerate_ctrl (void) { char errmsg[ERRMSGSIZ]; CLEAR(queryctrl); for (queryctrl.id = V4L2_CID_BASE; queryctrl.id < V4L2_CID_LASTP1; queryctrl.id++) { if (0 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { cerr << "Control " << queryctrl.name << endl; if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) continue; cerr << "Control " << queryctrl.name << endl; if (queryctrl.type == V4L2_CTRL_TYPE_MENU) enumerate_menu (); } else { if (errno == EINVAL) continue; errno_exit("VIDIOC_QUERYCTRL", errmsg); return; } } for (queryctrl.id = V4L2_CID_PRIVATE_BASE; ; queryctrl.id++) { if (0 == xioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { cerr << "Private Control " << queryctrl.name << endl; if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) continue; if (queryctrl.type == V4L2_CTRL_TYPE_MENU) enumerate_menu (); } else { if (errno == EINVAL) break; errno_exit ("VIDIOC_QUERYCTRL", errmsg); return; } } } void V4L2_Base::enumerate_menu (void) { char errmsg[ERRMSGSIZ]; cerr << " Menu items:" << endl; CLEAR(querymenu); querymenu.id = queryctrl.id; for (querymenu.index = queryctrl.minimum; querymenu.index <= queryctrl.maximum; querymenu.index++) { if (0 == xioctl (fd, VIDIOC_QUERYMENU, &querymenu)) { cerr << " " << querymenu.name << endl; } else { errno_exit("VIDIOC_QUERYMENU", errmsg); return; } } } int V4L2_Base::query_ctrl(unsigned int ctrl_id, double & ctrl_min, double & ctrl_max, double & ctrl_step, double & ctrl_value, char *errmsg) { struct v4l2_control control; CLEAR(queryctrl); queryctrl.id = ctrl_id; if (-1 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { if (errno != EINVAL) return errno_exit ("VIDIOC_QUERYCTRL", errmsg); else { cerr << "#" << ctrl_id << " is not supported" << endl; snprintf(errmsg, ERRMSGSIZ, "# %d is not supported", ctrl_id); return -1; } } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { cerr << "#" << ctrl_id << " is disabled" << endl; snprintf(errmsg, ERRMSGSIZ, "# %d is disabled", ctrl_id); return -1; } ctrl_min = queryctrl.minimum; ctrl_max = queryctrl.maximum; ctrl_step = queryctrl.step; ctrl_value = queryctrl.default_value; /* Get current value */ CLEAR(control); control.id = ctrl_id; if (0 == xioctl(fd, VIDIOC_G_CTRL, &control)) ctrl_value = control.value; cerr << queryctrl.name << " -- min: " << ctrl_min << " max: " << ctrl_max << " step: " << ctrl_step << " value: " << ctrl_value << endl; return 0; } int V4L2_Base::queryINTControls(INumberVectorProperty *nvp) { struct v4l2_control control; char errmsg[ERRMSGSIZ]; CLEAR(queryctrl); INumber *numbers = NULL; unsigned int *num_ctrls = NULL; int nnum=0; for (queryctrl.id = V4L2_CID_BASE; queryctrl.id < V4L2_CID_LASTP1; queryctrl.id++) { if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { cerr << queryctrl.name << " is disabled." << endl; continue; } if (queryctrl.type == V4L2_CTRL_TYPE_INTEGER) { numbers = (numbers == NULL) ? (INumber *) malloc (sizeof(INumber)) : (INumber *) realloc (numbers, (nnum+1) * sizeof (INumber)); num_ctrls = (num_ctrls == NULL) ? (unsigned int *) malloc (sizeof (unsigned int)) : (unsigned int *) realloc (num_ctrls, (nnum+1) * sizeof (unsigned int)); strncpy(numbers[nnum].name, ((char *) queryctrl.name) , MAXINDINAME); strncpy(numbers[nnum].label, ((char *) queryctrl.name), MAXINDILABEL); strncpy(numbers[nnum].format, "%0.f", MAXINDIFORMAT); numbers[nnum].min = queryctrl.minimum; numbers[nnum].max = queryctrl.maximum; numbers[nnum].step = queryctrl.step; numbers[nnum].value = queryctrl.default_value; /* Get current value if possible */ CLEAR(control); control.id = queryctrl.id; if (0 == xioctl(fd, VIDIOC_G_CTRL, &control)) numbers[nnum].value = control.value; /* Store ID info in INumber. This is the first time ever I make use of aux0!! */ num_ctrls[nnum] = queryctrl.id; cerr << queryctrl.name << " -- min: " << queryctrl.minimum << " max: " << queryctrl.maximum << " step: " << queryctrl.step << " value: " << numbers[nnum].value << endl; nnum++; } } else if (errno != EINVAL) { if(numbers) free(numbers); return errno_exit ("VIDIOC_QUERYCTRL", errmsg); } } for (queryctrl.id = V4L2_CID_PRIVATE_BASE; ; queryctrl.id++) { if (0 == ioctl (fd, VIDIOC_QUERYCTRL, &queryctrl)) { if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { cerr << queryctrl.name << " is disabled." << endl; continue; } if (queryctrl.type == V4L2_CTRL_TYPE_INTEGER) { numbers = (numbers == NULL) ? (INumber *) malloc (sizeof(INumber)) : (INumber *) realloc (numbers, (nnum+1) * sizeof (INumber)); num_ctrls = (num_ctrls == NULL) ? (unsigned int *) malloc (sizeof (unsigned int)) : (unsigned int *) realloc (num_ctrls, (nnum+1) * sizeof (unsigned int)); strncpy(numbers[nnum].name, ((char *) queryctrl.name) , MAXINDINAME); strncpy(numbers[nnum].label, ((char *) queryctrl.name), MAXINDILABEL); strncpy(numbers[nnum].format, "%0.f", MAXINDIFORMAT); numbers[nnum].min = queryctrl.minimum; numbers[nnum].max = queryctrl.maximum; numbers[nnum].step = queryctrl.step; numbers[nnum].value = queryctrl.default_value; /* Get current value if possible */ CLEAR(control); control.id = queryctrl.id; if (0 == xioctl(fd, VIDIOC_G_CTRL, &control)) numbers[nnum].value = control.value; /* Store ID info in INumber. This is the first time ever I make use of aux0!! */ num_ctrls[nnum] = queryctrl.id; nnum++; } } else break; } /* Store numbers in aux0 */ for (int i=0; i < nnum; i++) numbers[i].aux0 = &num_ctrls[i]; nvp->np = numbers; nvp->nnp = nnum; return nnum; } int V4L2_Base::setINTControl(unsigned int ctrl_id, double new_value, char *errmsg) { struct v4l2_control control; CLEAR(control); //cerr << "The id is " << ctrl_id << " new value is " << new_value << endl; control.id = ctrl_id; control.value = (int) new_value; if (-1 == xioctl(fd, VIDIOC_S_CTRL, &control)) return errno_exit ("VIDIOC_S_CTRL", errmsg); return 0; } libindi-0.9.7/libs/webcam/ccvt.h0000644000175000017500000001707512241463551015435 0ustar jasemjasem/* CCVT: ColourConVerT: simple library for converting colourspaces Copyright (C) 2002 Nemosoft Unv. Email:athomas@nemsoft.co.uk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA For questions, remarks, patches, etc. for this program, the author can be reached at nemosoft@smcc.demon.nl. */ /* $Log$ Revision 1.4 2005/04/29 16:51:20 mutlaqja Adding initial support for Video 4 Linux 2 drivers. This mean that KStars can probably control Meade Lunar Planetary Imager (LPI). V4L2 requires a fairly recent kernel (> 2.6.9) and many drivers don't fully support it yet. It will take sometime. KStars still supports V4L1 and will continue so until V4L1 is obselete. Please test KStars video drivers if you can. Any comments welcomed. CCMAIL: kstars-devel@kde.org Revision 1.3 2004/06/26 23:12:03 mutlaqja Hopefully this will fix compile issues on 64bit archs, and FreeBSD, among others. The assembly code is replaced with a more portable, albeit slower C implementation. I imported the videodev.h header after cleaning it for user space. Anyone who has problems compiling this, please report the problem to kstars-devel@kde.org I noticed one odd thing after updating my kdelibs, the LEDs don't change color when state is changed. Try that by starting any INDI device, and hit connect, if the LED turns to yellow and back to grey then it works fine, otherwise, we've got a problem. CCMAIL: kstars-devel@kde.org Revision 1.10 2003/10/24 16:55:18 nemosoft removed erronous log messages Revision 1.9 2002/11/03 22:46:25 nemosoft Adding various RGB to RGB functions. Adding proper copyright header too. Revision 1.8 2002/04/14 01:00:27 nemosoft Finishing touches: adding const, adding libs for 'show' */ #ifndef CCVT_H #define CCVT_H #ifdef __cplusplus extern "C" { #endif /* Colour ConVerT: going from one colour space to another. ** NOTE: the set of available functions is far from complete! ** Format descriptions: 420i = "4:2:0 interlaced" YYYY UU YYYY UU even lines YYYY VV YYYY VV odd lines U/V data is subsampled by 2 both in horizontal and vertical directions, and intermixed with the Y values. 420p = "4:2:0 planar" YYYYYYYY N lines UUUU N/2 lines VVVV N/2 lines U/V is again subsampled, but all the Ys, Us and Vs are placed together in separate buffers. The buffers may be placed in one piece of contiguous memory though, with Y buffer first, followed by U, followed by V. yuyv = "4:2:2 interlaced" YUYV YUYV YUYV ... N lines The U/V data is subsampled by 2 in horizontal direction only. bgr24 = 3 bytes per pixel, in the order Blue Green Red (whoever came up with that idea...) rgb24 = 3 bytes per pixel, in the order Red Green Blue (which is sensible) rgb32 = 4 bytes per pixel, in the order Red Green Blue Alpha, with Alpha really being a filler byte (0) bgr32 = last but not least, 4 bytes per pixel, in the order Blue Green Red Alpha, Alpha again a filler byte (0) */ /* 4:2:0 YUV planar to RGB/BGR */ void ccvt_420p_bgr24(int width, int height, const void *src, void *dst); void ccvt_420p_rgb24(int width, int height, const void *src, void *dst); void ccvt_420p_bgr32(int width, int height, const void *src, void *dst); void ccvt_420p_rgb32(int width, int height, const void *src, void *dst); /* 4:2:2 YUYV interlaced to RGB/BGR */ void ccvt_yuyv_rgb32(int width, int height, const void *src, void *dst); void ccvt_yuyv_bgr32(int width, int height, const void *src, void *dst); /* 4:2:2 YUYV interlaced to 4:2:0 YUV planar */ void ccvt_yuyv_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); /* RGB/BGR to 4:2:0 YUV interlaced */ /* RGB/BGR to 4:2:0 YUV planar */ void ccvt_rgb24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); void ccvt_bgr24_420p(int width, int height, const void *src, void *dsty, void *dstu, void *dstv); /* RGB/BGR to RGB/BGR */ void ccvt_bgr24_bgr32(int width, int height, const void *const src, void *const dst); void ccvt_bgr24_rgb32(int width, int height, const void *const src, void *const dst); void ccvt_bgr32_bgr24(int width, int height, const void *const src, void *const dst); void ccvt_bgr32_rgb24(int width, int height, const void *const src, void *const dst); void ccvt_rgb24_bgr32(int width, int height, const void *const src, void *const dst); void ccvt_rgb24_rgb32(int width, int height, const void *const src, void *const dst); void ccvt_rgb32_bgr24(int width, int height, const void *const src, void *const dst); void ccvt_rgb32_rgb24(int width, int height, const void *const src, void *const dst); int RGB2YUV (int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip); /* * BAYER2RGB24 ROUTINE TAKEN FROM: * * Sonix SN9C101 based webcam basic I/F routines * Copyright (C) 2004 Takafumi Mizuno * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT); /* following lines are an Ilia Platone contribute, */ void rggb2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT); //based on the above bayer2rgb24 function void grey2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT); /************** end of contribute, more to come hopefully *****************/ #ifdef __cplusplus } #endif enum Options { ioNoBlock=(1<<0), ioUseSelect=(1<<1), haveBrightness=(1<<2), haveContrast=(1<<3), haveHue=(1<<4), haveColor=(1<<5), haveWhiteness=(1<<6) }; #endif libindi-0.9.7/libs/indicom.h0000644000175000017500000001572112241463551014656 0ustar jasemjasem/* INDI LIB Common routines used by all drivers Copyright (C) 2003 by Jason Harris (jharris@30doradus.org) Elwood C. Downey Jasem Mutlaq 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 */ /** \file indicom.h \brief Implementations for common driver routines. The INDI Common Routine Library provides formatting and serial routines employed by many INDI drivers. Currently, the library is composed of the following sections:
  • Formatting Functions
  • Conversion Functions
  • TTY Functions
\author Jason Harris \author Elwood C. Downey \author Jasem Mutlaq */ #ifndef INDICOM_H #define INDICOM_H #include #define J2000 2451545.0 #define ERRMSG_SIZE 1024 #define INDI_DEBUG extern const char * Direction[]; extern const char * SolarSystem[]; struct ln_date; /* TTY Error Codes */ enum TTY_ERROR { TTY_OK=0, TTY_READ_ERROR=-1, TTY_WRITE_ERROR=-2, TTY_SELECT_ERROR=-3, TTY_TIME_OUT=-4, TTY_PORT_FAILURE=-5, TTY_PARAM_ERROR=-6, TTY_ERRNO = -7}; #ifdef __cplusplus extern "C" { #endif /** * \defgroup ttyFunctions TTY Functions: Functions to perform common terminal access routines. */ /*@{*/ /** \brief read buffer from terminal \param fd file descriptor \param buf pointer to store data. Must be initilized and big enough to hold data. \param nbytes number of bytes to read. \param timeout number of seconds to wait for terminal before a timeout error is issued. \param nbytes_read the number of bytes read. \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code. */ int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read); /** \brief read buffer from terminal with a delimiter \param fd file descriptor \param buf pointer to store data. Must be initilized and big enough to hold data. \param stop_char if the function encounters \e stop_char then it stops reading and returns the buffer. \param timeout number of seconds to wait for terminal before a timeout error is issued. \param nbytes_read the number of bytes read. \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code. */ int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read); /** \brief Writes a buffer to fd. \param fd file descriptor \param buffer a null-terminated buffer to write to fd. \param nbytes number of bytes to write from \e buffer \param nbytes_written the number of bytes written \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code. */ int tty_write(int fd, const char * buffer, int nbytes, int *nbytes_written); /** \brief Writes a null terminated string to fd. \param fd file descriptor \param buffer the buffer to write to fd. \param nbytes_written the number of bytes written \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code. */ int tty_write_string(int fd, const char * buffer, int *nbytes_written); /** \brief Establishes a tty connection to a terminal device. \param device the device node. e.g. /dev/ttyS0 \param bit_rate bit rate \param word_size number of data bits, 7 or 8, USE 8 DATA BITS with modbus \param parity 0=no parity, 1=parity EVEN, 2=parity ODD \param stop_bits number of stop bits : 1 or 2 \param fd \e fd is set to the file descriptor value on success. \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code. \author Wildi Markus */ int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd); /** \brief Closes a tty connection and flushes the bus. \param fd the file descriptor to close. \return On success, it returns TTY_OK, otherwise, a TTY_ERROR code. */ int tty_disconnect(int fd); /** \brief Retrieve the tty error message \param err_code the error code return by any TTY function. \param err_msg an initialized buffer to hold the error message. \param err_msg_len length in bytes of \e err_msg */ void tty_error_msg(int err_code, char *err_msg, int err_msg_len); int tty_timeout(int fd, int timeout); /*@}*/ /** * \defgroup convertFunctions Formatting Functions: Functions to perform handy formatting and conversion routines. */ /*@{*/ /** \brief Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[]. \param out a pointer to store the sexagesimal number. \param a the sexagesimal number to convert. \param w the number of spaces in the whole part. \param fracbase is the number of pieces a whole is to broken into; valid options:\n \li 360000: \:mm:ss.ss \li 36000: \:mm:ss.s \li 3600: \:mm:ss \li 600: \:mm.m \li 60: \:mm \return number of characters written to out, not counting final null terminator. */ int fs_sexa (char *out, double a, int w, int fracbase); /** \brief convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A, B or C will be assumed 0. Optional - and + can be anywhere. \param str0 string containing sexagesimal number. \param dp pointer to a double to store the sexagesimal number. \return return 0 if ok, -1 if can't find a thing. */ int f_scansexa (const char *str0, double *dp); /** \brief Extract ISO 8601 time and store it in a tm struct. \param timestr a string containing date and time in ISO 8601 format. \param iso_date a pointer to a \e ln_date structure to store the extracted time and date (libnova). \return 0 on success, -1 on failure. */ int extractISOTime(char *timestr, struct ln_date *iso_date); void getSexComponents(double value, int *d, int *m, int *s); /** \brief Fill buffer with properly formatted INumber string. \param buf to store the formatted string. \param format format in sprintf style. \param value the number to format. \return length of string. */ int numberFormat (char *buf, const char *format, double value); /** \brief Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS \return The formatted time stamp. */ const char *timestamp (void); /*@}*/ #ifdef __cplusplus } #endif #endif libindi-0.9.7/libs/indicom.c0000644000175000017500000007614712241463551014662 0ustar jasemjasem/* INDI LIB Common routines used by all drivers Copyright (C) 2003 by Jason Harris (jharris@30doradus.org) Elwood C. Downey This is the C version of the astronomical library in KStars modified by Jasem Mutlaq (mutlaqja@ikarustech.com) 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 */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_NOVA_H #include #endif #include "indicom.h" #ifdef _WIN32 #undef CX #undef CY #endif #ifndef _WIN32 #include #define PARITY_NONE 0 #define PARITY_EVEN 1 #define PARITY_ODD 2 #endif #define MAXRBUF 2048 #include "indidevapi.h" void getSexComponents(double value, int *d, int *m, int *s); int extractISOTime(char *timestr, struct ln_date *iso_date) { #ifdef HAVE_NOVA_H struct tm utm; if (strptime(timestr, "%Y/%m/%dT%H:%M:%S", &utm)) { ln_get_date_from_tm(&utm, iso_date); return (0); } if (strptime(timestr, "%Y-%m-%dT%H:%M:%S", &utm)) { ln_get_date_from_tm(&utm, iso_date); return (0); } #endif return (-1); } /* sprint the variable a in sexagesimal format into out[]. * w is the number of spaces for the whole part. * fracbase is the number of pieces a whole is to broken into; valid options: * 360000: :mm:ss.ss * 36000: :mm:ss.s * 3600: :mm:ss * 600: :mm.m * 60: :mm * return number of characters written to out, not counting finaif (NOVA_FOUND) include_directories(${NOVA_INCLUDE_DIR}) endif (NOVA_FOUND)l '\0'. */ int fs_sexa (char *out, double a, int w, int fracbase) { char *out0 = out; unsigned long n; int d; int f; int m; int s; int isneg; /* save whether it's negative but do all the rest with a positive */ isneg = (a < 0); if (isneg) a = -a; /* convert to an integral number of whole portions */ n = (unsigned long)(a * fracbase + 0.5); d = n/fracbase; f = n%fracbase; /* form the whole part; "negative 0" is a special case */ if (isneg && d == 0) out += sprintf (out, "%*s-0", w-2, ""); else out += sprintf (out, "%*d", w, isneg ? -d : d); /* do the rest */ switch (fracbase) { case 60: /* dd:mm */ m = f/(fracbase/60); out += sprintf (out, ":%02d", m); break; case 600: /* dd:mm.m */ out += sprintf (out, ":%02d.%1d", f/10, f%10); break; case 3600: /* dd:mm:ss */ m = f/(fracbase/60); s = f%(fracbase/60); out += sprintf (out, ":%02d:%02d", m, s); break; case 36000: /* dd:mm:ss.s*/ m = f/(fracbase/60); s = f%(fracbase/60); out += sprintf (out, ":%02d:%02d.%1d", m, s/10, s%10); break; case 360000: /* dd:mm:ss.ss */ m = f/(fracbase/60); s = f%(fracbase/60); out += sprintf (out, ":%02d:%02d.%02d", m, s/100, s%100); break; default: printf ("fs_sexa: unknown fracbase: %d\n", fracbase); return -1; } return (out - out0); } /* convert sexagesimal string str AxBxC to double. * x can be anything non-numeric. Any missing A, B or C will be assumed 0. * optional - and + can be anywhere. * return 0 if ok, -1 if can't find a thing. */ int f_scansexa ( const char *str0, /* input string */ double *dp) /* cracked value, if return 0 */ { double a = 0, b = 0, c = 0; char str[128]; char *neg; int r; /* copy str0 so we can play with it */ strncpy (str, str0, sizeof(str)-1); str[sizeof(str)-1] = '\0'; neg = strchr(str, '-'); if (neg) *neg = ' '; r = sscanf (str, "%lf%*[^0-9]%lf%*[^0-9]%lf", &a, &b, &c); if (r < 1) return (-1); *dp = a + b/60 + c/3600; if (neg) *dp *= -1; return (0); } void getSexComponents(double value, int *d, int *m, int *s) { *d = (int) fabs(value); *m = (int) ((fabs(value) - *d) * 60.0); *s = (int) rint(((fabs(value) - *d) * 60.0 - *m) *60.0); if (value < 0) *d *= -1; } /* fill buf with properly formatted INumber string. return length */ int numberFormat (char *buf, const char *format, double value) { int w, f, s; char m; if (sscanf (format, "%%%d.%d%c", &w, &f, &m) == 3 && m == 'm') { /* INDI sexi format */ switch (f) { case 9: s = 360000; break; case 8: s = 36000; break; case 6: s = 3600; break; case 5: s = 600; break; default: s = 60; break; } return (fs_sexa (buf, value, w-f, s)); } else { /* normal printf format */ return (sprintf (buf, format, value)); } } /* log message locally. * this has nothing to do with XML or any Clients. */ void IDLog (const char *fmt, ...) { va_list ap; /* JM: Since all INDI's stderr are timestampped now, we don't need to time stamp ID Log */ /*fprintf (stderr, "%s ", timestamp());*/ va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); } /* return current system time in message format */ const char * timestamp() { static char ts[32]; struct tm *tp; time_t t; time (&t); tp = gmtime (&t); strftime (ts, sizeof(ts), "%Y-%m-%dT%H:%M:%S", tp); return (ts); } int tty_timeout(int fd, int timeout) { if (fd == -1) return TTY_ERRNO; 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 TTY_OK; /* Return -1 due to an error */ else if (retval == -1) return TTY_SELECT_ERROR; /* Return -2 if time expires before anything interesting happens */ else return TTY_TIME_OUT; } int tty_write(int fd, const char * buf, int nbytes, int *nbytes_written) { if (fd == -1) return TTY_ERRNO; int bytes_w = 0; *nbytes_written = 0; while (nbytes > 0) { bytes_w = write(fd, buf, nbytes); if (bytes_w < 0) return TTY_WRITE_ERROR; *nbytes_written += bytes_w; buf += bytes_w; nbytes -= bytes_w; } return TTY_OK; } int tty_write_string(int fd, const char * buf, int *nbytes_written) { if (fd == -1) return TTY_ERRNO; unsigned int nbytes; int bytes_w = 0; *nbytes_written = 0; nbytes = strlen(buf); while (nbytes > 0) { bytes_w = write(fd, buf, nbytes); if (bytes_w < 0) return TTY_WRITE_ERROR; *nbytes_written += bytes_w; buf += bytes_w; nbytes -= bytes_w; } return TTY_OK; } int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read) { if (fd == -1) return TTY_ERRNO; int bytesRead = 0; int err = 0; *nbytes_read =0; if (nbytes <=0) return TTY_PARAM_ERROR; while (nbytes > 0) { if ( (err = tty_timeout(fd, timeout)) ) return err; bytesRead = read(fd, buf, ((unsigned) nbytes)); if (bytesRead < 0 ) return TTY_READ_ERROR; buf += bytesRead; *nbytes_read += bytesRead; nbytes -= bytesRead; } return TTY_OK; } int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read) { if (fd == -1) return TTY_ERRNO; int bytesRead = 0; int err = TTY_OK; *nbytes_read = 0; for (;;) { if ( (err = tty_timeout(fd, timeout)) ) return err; bytesRead = read(fd, buf, 1); if (bytesRead < 0 ) return TTY_READ_ERROR; if (bytesRead) (*nbytes_read)++; if (*buf == stop_char) return TTY_OK; buf += bytesRead; } return TTY_TIME_OUT; } #if defined(BSD) && !defined(__GNU__) // BSD - OSX version int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd) { int t_fd = -1; int bps; char msg[80]; int handshake; struct termios tty_setting; // Open the serial port read/write, with no controlling terminal, and don't wait for a connection. // The O_NONBLOCK flag also causes subsequent I/O on the device to be non-blocking. // See open(2) ("man 2 open") for details. t_fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK); if (t_fd == -1) { printf("Error opening serial port %s - %s(%d).\n", device, strerror(errno), errno); goto error; } // Note that open() follows POSIX semantics: multiple open() calls to the same file will succeed // unless the TIOCEXCL ioctl is issued. This will prevent additional opens except by root-owned // processes. // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details. if (ioctl(t_fd, TIOCEXCL) == -1) { printf("Error setting TIOCEXCL on %s - %s(%d).\n", device, strerror(errno), errno); goto error; } // Now that the device is open, clear the O_NONBLOCK flag so subsequent I/O will block. // See fcntl(2) ("man 2 fcntl") for details. if (fcntl(t_fd, F_SETFL, 0) == -1) { printf("Error clearing O_NONBLOCK %s - %s(%d).\n", device, strerror(errno), errno); goto error; } // Get the current options and save them so we can restore the default settings later. if (tcgetattr(t_fd, &tty_setting) == -1) { printf("Error getting tty attributes %s - %s(%d).\n", device, strerror(errno), errno); goto error; } // Set raw input (non-canonical) mode, with reads blocking until either a single character // has been received or a one second timeout expires. // See tcsetattr(4) ("man 4 tcsetattr") and termios(4) ("man 4 termios") for details. cfmakeraw(&tty_setting); tty_setting.c_cc[VMIN] = 1; tty_setting.c_cc[VTIME] = 10; // The baud rate, word length, and handshake options can be set as follows: switch (bit_rate) { case 0: bps = B0; break; case 50: bps = B50; break; case 75: bps = B75; break; case 110: bps = B110; break; case 134: bps = B134; break; case 150: bps = B150; break; case 200: bps = B200; break; case 300: bps = B300; break; case 600: bps = B600; break; case 1200: bps = B1200; break; case 1800: bps = B1800; break; case 2400: bps = B2400; break; case 4800: bps = B4800; break; case 9600: bps = B9600; break; case 19200: bps = B19200; break; case 38400: bps = B38400; break; case 57600: bps = B57600; break; case 115200: bps = B115200; break; case 230400: bps = B230400; break; default: if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } cfsetspeed(&tty_setting, bps); // Set baud rate /* word size */ switch (word_size) { case 5: tty_setting.c_cflag |= CS5; break; case 6: tty_setting.c_cflag |= CS6; break; case 7: tty_setting.c_cflag |= CS7; break; case 8: tty_setting.c_cflag |= CS8; break; default: fprintf( stderr, "Default\n") ; if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } /* parity */ switch (parity) { case PARITY_NONE: break; case PARITY_EVEN: tty_setting.c_cflag |= PARENB; break; case PARITY_ODD: tty_setting.c_cflag |= PARENB | PARODD; break; default: fprintf( stderr, "Default1\n") ; if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } /* stop_bits */ switch (stop_bits) { case 1: break; case 2: tty_setting.c_cflag |= CSTOPB; break; default: fprintf( stderr, "Default2\n") ; if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } #if defined(MAC_OS_X_VERSION_10_4) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_4) // Starting with Tiger, the IOSSIOSPEED ioctl can be used to set arbitrary baud rates // other than those specified by POSIX. The driver for the underlying serial hardware // ultimately determines which baud rates can be used. This ioctl sets both the input // and output speed. speed_t speed = 14400; // Set 14400 baud if (ioctl(fileDescriptor, IOSSIOSPEED, &speed) == -1) { printf("Error calling ioctl(..., IOSSIOSPEED, ...) %s - %s(%d).\n", bsdPath, strerror(errno), errno); } #endif // Cause the new options to take effect immediately. if (tcsetattr(t_fd, TCSANOW, &tty_setting) == -1) { printf("Error setting tty attributes %s - %s(%d).\n", device, strerror(errno), errno); goto error; } // To set the modem handshake lines, use the following ioctls. // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details. if (ioctl(t_fd, TIOCSDTR) == -1) // Assert Data Terminal Ready (DTR) { printf("Error asserting DTR %s - %s(%d).\n", device, strerror(errno), errno); } if (ioctl(t_fd, TIOCCDTR) == -1) // Clear Data Terminal Ready (DTR) { printf("Error clearing DTR %s - %s(%d).\n", device, strerror(errno), errno); } handshake = TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR; if (ioctl(t_fd, TIOCMSET, &handshake) == -1) // Set the modem lines depending on the bits set in handshake { printf("Error setting handshake lines %s - %s(%d).\n", device, strerror(errno), errno); } // To read the state of the modem lines, use the following ioctl. // See tty(4) ("man 4 tty") and ioctl(2) ("man 2 ioctl") for details. if (ioctl(t_fd, TIOCMGET, &handshake) == -1) // Store the state of the modem lines in handshake { printf("Error getting handshake lines %s - %s(%d).\n", device, strerror(errno), errno); } printf("Handshake lines currently set to %d\n", handshake); #if defined(MAC_OS_X_VERSION_10_3) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3) unsigned long mics = 1UL; // Set the receive latency in microseconds. Serial drivers use this value to determine how often to // dequeue characters received by the hardware. Most applications don't need to set this value: if an // app reads lines of characters, the app can't do anything until the line termination character has been // received anyway. The most common applications which are sensitive to read latency are MIDI and IrDA // applications. if (ioctl(t_fd, IOSSDATALAT, &mics) == -1) { // set latency to 1 microsecond printf("Error setting read latency %s - %s(%d).\n", device, strerror(errno), errno); goto error; } #endif *fd = t_fd; /* return success */ return TTY_OK; // Failure path error: if (t_fd != -1) { close(t_fd); *fd = -1; } return TTY_PORT_FAILURE; } #else int tty_connect(const char *device, int bit_rate, int word_size, int parity, int stop_bits, int *fd) { #ifdef _WIN32 return TTY_PORT_FAILURE; #else int t_fd=-1; char msg[80]; int bps; struct termios tty_setting; if ( (t_fd = open(device, O_RDWR | O_NOCTTY )) == -1) { *fd = -1; return TTY_PORT_FAILURE; } /* Control Modes Set bps rate */ switch (bit_rate) { case 0: bps = B0; break; case 50: bps = B50; break; case 75: bps = B75; break; case 110: bps = B110; break; case 134: bps = B134; break; case 150: bps = B150; break; case 200: bps = B200; break; case 300: bps = B300; break; case 600: bps = B600; break; case 1200: bps = B1200; break; case 1800: bps = B1800; break; case 2400: bps = B2400; break; case 4800: bps = B4800; break; case 9600: bps = B9600; break; case 19200: bps = B19200; break; case 38400: bps = B38400; break; case 57600: bps = B57600; break; case 115200: bps = B115200; break; case 230400: bps = B230400; break; default: if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid bit rate.", bit_rate) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } if ((cfsetispeed(&tty_setting, bps) < 0) || (cfsetospeed(&tty_setting, bps) < 0)) { perror("tty_connect: failed setting bit rate."); return TTY_PORT_FAILURE; } /* Control Modes set no flow control word size, parity and stop bits. Also don't hangup automatically and ignore modem status. Finally enable receiving characters. */ tty_setting.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | HUPCL | CRTSCTS); tty_setting.c_cflag |= (CLOCAL | CREAD); /* word size */ switch (word_size) { case 5: tty_setting.c_cflag |= CS5; break; case 6: tty_setting.c_cflag |= CS6; break; case 7: tty_setting.c_cflag |= CS7; break; case 8: tty_setting.c_cflag |= CS8; break; default: fprintf( stderr, "Default\n") ; if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid data bit count.", word_size) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } /* parity */ switch (parity) { case PARITY_NONE: break; case PARITY_EVEN: tty_setting.c_cflag |= PARENB; break; case PARITY_ODD: tty_setting.c_cflag |= PARENB | PARODD; break; default: fprintf( stderr, "Default1\n") ; if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid parity selection value.", parity) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } /* stop_bits */ switch (stop_bits) { case 1: break; case 2: tty_setting.c_cflag |= CSTOPB; break; default: fprintf( stderr, "Default2\n") ; if (snprintf(msg, sizeof(msg), "tty_connect: %d is not a valid stop bit count.", stop_bits) < 0) perror(NULL); else perror(msg); return TTY_PARAM_ERROR; } /* Control Modes complete */ /* Ignore bytes with parity errors and make terminal raw and dumb.*/ tty_setting.c_iflag &= ~(PARMRK | ISTRIP | IGNCR | ICRNL | INLCR | IXOFF | IXON | IXANY); tty_setting.c_iflag |= INPCK | IGNPAR | IGNBRK; /* Raw output.*/ tty_setting.c_oflag &= ~(OPOST | ONLCR); /* Local Modes Don't echo characters. Don't generate signals. Don't process any characters.*/ tty_setting.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN | NOFLSH | TOSTOP); tty_setting.c_lflag |= NOFLSH; /* blocking read until 1 char arrives */ tty_setting.c_cc[VMIN] = 1; tty_setting.c_cc[VTIME] = 0; /* now clear input and output buffers and activate the new terminal settings */ tcflush(t_fd, TCIOFLUSH); if (tcsetattr(t_fd, TCSANOW, &tty_setting)) { perror("tty_connect: failed setting attributes on serial port."); tty_disconnect(t_fd); return TTY_PORT_FAILURE; } *fd = t_fd; /* return success */ return TTY_OK; #endif } // Unix - Linux version #endif int tty_disconnect(int fd) { if (fd == -1) return TTY_ERRNO; #ifdef _WIN32 return TTY_ERRNO; #else int err; tcflush(fd, TCIOFLUSH); err = close(fd); if (err != 0) return TTY_ERRNO; return TTY_OK; #endif } void tty_error_msg(int err_code, char *err_msg, int err_msg_len) { char error_string[512]; switch (err_code) { case TTY_OK: strncpy(err_msg, "No Error", err_msg_len); break; case TTY_READ_ERROR: snprintf(error_string, 512, "Read Error: %s", strerror(errno)); strncpy(err_msg, error_string, err_msg_len); break; case TTY_WRITE_ERROR: snprintf(error_string, 512, "Write Error: %s", strerror(errno)); strncpy(err_msg, error_string, err_msg_len); break; case TTY_SELECT_ERROR: snprintf(error_string, 512, "Select Error: %s", strerror(errno)); strncpy(err_msg, error_string, err_msg_len); break; case TTY_TIME_OUT: strncpy(err_msg, "Timeout error", err_msg_len); break; case TTY_PORT_FAILURE: if (errno == EACCES) snprintf(error_string, 512, "Port failure Error: %s. Try adding your user to the dialout group and restart (sudo adduser $USER dialout)", strerror(errno)); else snprintf(error_string, 512, "Port failure Error: %s. Check if device is connected to this port.", strerror(errno)); strncpy(err_msg, error_string, err_msg_len); break; case TTY_PARAM_ERROR: strncpy(err_msg, "Parameter error", err_msg_len); break; case TTY_ERRNO: snprintf(error_string, 512, "%s", strerror(errno)); strncpy(err_msg, error_string, err_msg_len); break; default: strncpy(err_msg, "Error: unrecognized error code", err_msg_len); break; } } /* return static string corresponding to the given property or light state */ const char * pstateStr (IPState s) { switch (s) { case IPS_IDLE: return ("Idle"); case IPS_OK: return ("Ok"); case IPS_BUSY: return ("Busy"); case IPS_ALERT: return ("Alert"); default: fprintf (stderr, "Impossible IPState %d\n", s); return NULL; } } /* crack string into IPState. * return 0 if ok, else -1 */ int crackIPState (const char *str, IPState *ip) { if (!strcmp (str, "Idle")) *ip = IPS_IDLE; else if (!strcmp (str, "Ok")) *ip = IPS_OK; else if (!strcmp (str, "Busy")) *ip = IPS_BUSY; else if (!strcmp (str, "Alert")) *ip = IPS_ALERT; else return (-1); return (0); } /* crack string into ISState. * return 0 if ok, else -1 */ int crackISState (const char *str, ISState *ip) { if (!strcmp (str, "On")) *ip = ISS_ON; else if (!strcmp (str, "Off")) *ip = ISS_OFF; else return (-1); return (0); } int crackIPerm (const char *str, IPerm *ip) { if (!strcmp (str, "rw")) *ip = IP_RW; else if (!strcmp (str, "ro")) *ip = IP_RO; else if (!strcmp (str, "wo")) *ip = IP_WO; else return (-1); return (0); } int crackISRule (const char *str, ISRule *ip) { if (!strcmp (str, "OneOfMany")) *ip = ISR_1OFMANY; else if (!strcmp (str, "AtMostOne")) *ip = ISR_ATMOST1; else if (!strcmp (str, "AnyOfMany")) *ip = ISR_NOFMANY; else return (-1); return (0); } /* return static string corresponding to the given switch state */ const char * sstateStr (ISState s) { switch (s) { case ISS_ON: return ("On"); case ISS_OFF: return ("Off"); default: fprintf (stderr, "Impossible ISState %d\n", s); return NULL; } } /* return static string corresponding to the given Rule */ const char * ruleStr (ISRule r) { switch (r) { case ISR_1OFMANY: return ("OneOfMany"); case ISR_ATMOST1: return ("AtMostOne"); case ISR_NOFMANY: return ("AnyOfMany"); default: fprintf (stderr, "Impossible ISRule %d\n", r); return NULL; } } /* return static string corresponding to the given IPerm */ const char * permStr (IPerm p) { switch (p) { case IP_RO: return ("ro"); case IP_WO: return ("wo"); case IP_RW: return ("rw"); default: fprintf (stderr, "Impossible IPerm %d\n", p); return NULL; } } /* print the boilerplate comment introducing xml */ void xmlv1() { printf ("\n"); } /* pull out device and name attributes from root. * return 0 if ok else -1 with reason in msg[]. */ int crackDN (XMLEle *root, char **dev, char **name, char msg[]) { XMLAtt *ap; ap = findXMLAtt (root, "device"); if (!ap) { sprintf (msg, "%s requires 'device' attribute", tagXMLEle(root)); return (-1); } *dev = valuXMLAtt(ap); ap = findXMLAtt (root, "name"); if (!ap) { sprintf (msg, "%s requires 'name' attribute", tagXMLEle(root)); return (-1); } *name = valuXMLAtt(ap); return (0); } /* find a member of an IText vector, else NULL */ IText * IUFindText (const ITextVectorProperty *tvp, const char *name) { int i; for (i = 0; i < tvp->ntp; i++) if (strcmp (tvp->tp[i].name, name) == 0) return (&tvp->tp[i]); fprintf (stderr, "No IText '%s' in %s.%s\n",name,tvp->device,tvp->name); return (NULL); } /* find a member of an INumber vector, else NULL */ INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name) { int i; for (i = 0; i < nvp->nnp; i++) if (strcmp (nvp->np[i].name, name) == 0) return (&nvp->np[i]); fprintf(stderr,"No INumber '%s' in %s.%s\n",name,nvp->device,nvp->name); return (NULL); } /* find a member of an ISwitch vector, else NULL */ ISwitch * IUFindSwitch(const ISwitchVectorProperty *svp, const char *name) { int i; for (i = 0; i < svp->nsp; i++) if (strcmp (svp->sp[i].name, name) == 0) return (&svp->sp[i]); fprintf(stderr,"No ISwitch '%s' in %s.%s\n",name,svp->device,svp->name); return (NULL); } /* find a member of an ILight vector, else NULL */ ILight * IUFindLight(const ILightVectorProperty *lvp, const char *name) { int i; for (i = 0; i < lvp->nlp; i++) if (strcmp (lvp->lp[i].name, name) == 0) return (&lvp->lp[i]); fprintf(stderr,"No ILight '%s' in %s.%s\n",name,lvp->device,lvp->name); return (NULL); } /* find a member of an IBLOB vector, else NULL */ IBLOB * IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name) { int i; for (i = 0; i < bvp->nbp; i++) if (strcmp (bvp->bp[i].name, name) == 0) return (&bvp->bp[i]); fprintf(stderr,"No IBLOB '%s' in %s.%s\n",name,bvp->device,bvp->name); return (NULL); } /* find an ON member of an ISwitch vector, else NULL. * N.B. user must make sense of result with ISRule in mind. */ ISwitch * IUFindOnSwitch(const ISwitchVectorProperty *svp) { int i; for (i = 0; i < svp->nsp; i++) if (svp->sp[i].s == ISS_ON) return (&svp->sp[i]); /*fprintf(stderr, "No ISwitch On in %s.%s\n", svp->device, svp->name);*/ return (NULL); } /* Find index of the ON member of an ISwitchVectorProperty */ int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp) { int i; for (i = 0; i < svp->nsp; i++) if (svp->sp[i].s == ISS_ON) return i; return -1; } /* Set all switches to off */ void IUResetSwitch(ISwitchVectorProperty *svp) { int i; for (i = 0; i < svp->nsp; i++) svp->sp[i].s = ISS_OFF; } /* save malloced copy of newtext in tp->text, reusing if not first time */ void IUSaveText (IText *tp, const char *newtext) { /* seed for realloc */ if (tp->text == NULL) tp->text = malloc (1); /* copy in fresh string */ tp->text = strcpy (realloc (tp->text, strlen(newtext)+1), newtext); } libindi-0.9.7/indidriver.c0000644000175000017500000014024412241463551014434 0ustar jasemjasem#if 0 INDI Copyright (C) 2003-2006 Elwood C. Downey Updated by Jasem Mutlaq (2003-2010) 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 #include #include #include #include #include #include #include #include #include "lilxml.h" #include "base64.h" #include "eventloop.h" #include "indidevapi.h" #include "indicom.h" #include "indidriver.h" #define MAXRBUF 2048 /* tell Client to delete the property with given name on given device, or * entire device if !name */ void IDDelete (const char *dev, const char *name, const char *fmt, ...) { xmlv1(); printf ("\n"); fflush (stdout); } /* tell indiserver we want to snoop on the given device/property. * name ignored if NULL or empty. */ void IDSnoopDevice (const char *snooped_device_name, const char *snooped_property_name) { xmlv1(); if (snooped_property_name && snooped_property_name[0]) printf ("\n", snooped_device_name, snooped_property_name); else printf ("\n", snooped_device_name); fflush (stdout); } /* tell indiserver whether we want BLOBs from the given snooped device. * silently ignored if given device is not already registered for snooping. */ void IDSnoopBLOBs (const char *snooped_device, BLOBHandling bh) { const char *how; switch (bh) { case B_NEVER: how = "Never"; break; case B_ALSO: how = "Also"; break; case B_ONLY: how = "Only"; break; default: return; } xmlv1(); printf ("%s\n", snooped_device, how); fflush (stdout); } /* "INDI" wrappers to the more generic eventloop facility. */ int IEAddCallback (int readfiledes, IE_CBF *fp, void *p) { return (addCallback (readfiledes, (CBF*)fp, p)); } void IERmCallback (int callbackid) { rmCallback (callbackid); } int IEAddTimer (int millisecs, IE_TCF *fp, void *p) { return (addTimer (millisecs, (TCF*)fp, p)); } void IERmTimer (int timerid) { rmTimer (timerid); } int IEAddWorkProc (IE_WPF *fp, void *p) { return (addWorkProc ((WPF*)fp, p)); } void IERmWorkProc (int workprocid) { rmWorkProc (workprocid); } int IEDeferLoop (int maxms, int *flagp) { return (deferLoop (maxms, flagp)); } int IEDeferLoop0 (int maxms, int *flagp) { return (deferLoop0 (maxms, flagp)); } /* Update property switches in accord with states and names. */ int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n) { int i=0; ISwitch *sp; char sn[MAXINDINAME]; /* store On switch name */ if (svp->r == ISR_1OFMANY) { sp = IUFindOnSwitch(svp); if (sp) strncpy(sn, sp->name, MAXINDINAME); IUResetSwitch(svp); } for (i = 0; i < n ; i++) { sp = IUFindSwitch(svp, names[i]); if (!sp) { svp->s = IPS_IDLE; IDSetSwitch(svp, "Error: %s is not a member of %s property.", names[i], svp->name); return -1; } sp->s = states[i]; } /* Consistency checks for ISR_1OFMANY after update. */ if (svp->r == ISR_1OFMANY) { int t_count=0; for (i=0; i < svp->nsp; i++) { if (svp->sp[i].s == ISS_ON) t_count++; } if (t_count != 1) { IUResetSwitch(svp); sp = IUFindSwitch(svp, sn); if (sp) sp->s = ISS_ON; svp->s = IPS_IDLE; IDSetSwitch(svp, "Error: invalid state switch for property %s. %s.", svp->name, t_count == 0 ? "No switch is on" : "Too many switches are on"); return -1; } } return 0; } /* Update property numbers in accord with values and names */ int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n) { int i=0; INumber *np; for (i = 0; i < n; i++) { np = IUFindNumber(nvp, names[i]); if (!np) { nvp->s = IPS_IDLE; IDSetNumber(nvp, "Error: %s is not a member of %s property.", names[i], nvp->name); return -1; } if (values[i] < np->min || values[i] > np->max) { nvp->s = IPS_IDLE; IDSetNumber(nvp, "Error: Invalid range. Valid range is from %g to %g", np->min, np->max); return -1; } } /* First loop checks for error, second loop set all values atomically*/ for (i=0; i < n; i++) { np = IUFindNumber(nvp, names[i]); np->value = values[i]; } return 0; } /* Update property text in accord with texts and names */ int IUUpdateText(ITextVectorProperty *tvp, char * texts[], char *names[], int n) { int i=0; IText *tp; for (i = 0; i < n; i++) { tp = IUFindText(tvp, names[i]); if (!tp) { tvp->s = IPS_IDLE; IDSetText(tvp, "Error: %s is not a member of %s property.", names[i], tvp->name); return -1; } } /* First loop checks for error, second loop set all values atomically*/ for (i=0; i < n; i++) { tp = IUFindText(tvp, names[i]); IUSaveText(tp, texts[i]); } return 0; } /* Update property BLOB in accord with BLOBs and names */ int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n) { int i=0; IBLOB *bp; for (i = 0; i < n; i++) { bp = IUFindBLOB(bvp, names[i]); if (!bp) { bvp->s = IPS_IDLE; IDSetBLOB(bvp, "Error: %s is not a member of %s property.", names[i], bvp->name); return -1; } } /* First loop checks for error, second loop set all values atomically*/ for (i=0; i < n; i++) { bp = IUFindBLOB(bvp, names[i]); IUSaveBLOB(bp, sizes[i], blobsizes[i], blobs[i], formats[i]); } return 0; } int IUSaveBLOB(IBLOB *bp, int size, int blobsize, char *blob, char *format) { bp->bloblen = blobsize; bp->size = size; bp->blob = blob; strncpy(bp->format, format, MAXINDIFORMAT); return 0; } void IUFillSwitch(ISwitch *sp, const char *name, const char * label, ISState s) { strncpy(sp->name, name, MAXINDINAME); strncpy(sp->label, label, MAXINDILABEL); sp->s = s; sp->svp = NULL; sp->aux = NULL; } void IUFillLight(ILight *lp, const char *name, const char * label, IPState s) { strncpy(lp->name, name, MAXINDINAME); strncpy(lp->label, label, MAXINDILABEL); lp->s = s; lp->lvp = NULL; lp->aux = NULL; } void IUFillNumber(INumber *np, const char *name, const char * label, const char *format, double min, double max, double step, double value) { strncpy(np->name, name, MAXINDINAME); strncpy(np->label, label, MAXINDILABEL); strncpy(np->format, format, MAXINDIFORMAT); np->min = min; np->max = max; np->step = step; np->value = value; np->nvp = NULL; np->aux0 = NULL; np->aux1 = NULL; } void IUFillText(IText *tp, const char *name, const char * label, const char *initialText) { strncpy(tp->name, name, MAXINDINAME); strncpy(tp->label, label, MAXINDILABEL); tp->text = NULL; tp->tvp = NULL; tp->aux0 = NULL; tp->aux1 = NULL; if (initialText && strlen(initialText) > 0) IUSaveText(tp, initialText); } void IUFillBLOB(IBLOB *bp, const char *name, const char * label, const char *format) { memset(bp, 0, sizeof(IBLOB)); strncpy(bp->name, name, MAXINDINAME); strncpy(bp->label, label, MAXINDILABEL); strncpy(bp->format, label, MAXINDIBLOBFMT); bp->blob = 0; bp->bloblen = 0; bp->size = 0; bp->bvp = 0; bp->aux0 = 0; bp->aux1 = 0; bp->aux2 = 0; } void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char * dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s) { strncpy(svp->device, dev, MAXINDIDEVICE); strncpy(svp->name, name, MAXINDINAME); strncpy(svp->label, label, MAXINDILABEL); strncpy(svp->group, group, MAXINDIGROUP); svp->p = p; svp->r = r; svp->timeout = timeout; svp->s = s; svp->sp = sp; svp->nsp = nsp; } void IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char * dev, const char *name, const char *label, const char *group, IPState s) { strncpy(lvp->device, dev, MAXINDIDEVICE); strncpy(lvp->name, name, MAXINDINAME); strncpy(lvp->label, label, MAXINDILABEL); strncpy(lvp->group, group, MAXINDIGROUP); strcpy(lvp->timestamp, ""); lvp->s = s; lvp->lp = lp; lvp->nlp = nlp; } void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s) { strncpy(nvp->device, dev, MAXINDIDEVICE); strncpy(nvp->name, name, MAXINDINAME); strncpy(nvp->label, label, MAXINDILABEL); strncpy(nvp->group, group, MAXINDIGROUP); strcpy(nvp->timestamp, ""); nvp->p = p; nvp->timeout = timeout; nvp->s = s; nvp->np = np; nvp->nnp = nnp; } void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s) { strncpy(tvp->device, dev, MAXINDIDEVICE); strncpy(tvp->name, name, MAXINDINAME); strncpy(tvp->label, label, MAXINDILABEL); strncpy(tvp->group, group, MAXINDIGROUP); strcpy(tvp->timestamp, ""); tvp->p = p; tvp->timeout = timeout; tvp->s = s; tvp->tp = tp; tvp->ntp = ntp; } void IUFillBLOBVector(IBLOBVectorProperty *bvp, IBLOB *bp, int nbp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s) { memset(bvp, 0, sizeof(IBLOBVectorProperty)); strncpy(bvp->device, dev, MAXINDIDEVICE); strncpy(bvp->name, name, MAXINDINAME); strncpy(bvp->label, label, MAXINDILABEL); strncpy(bvp->group, group, MAXINDIGROUP); strcpy(bvp->timestamp, ""); bvp->p = p; bvp->timeout = timeout; bvp->s = s; bvp->bp = bp; bvp->nbp = nbp; } /***************************************************************************** * convenience functions for use in your implementation of ISSnoopDevice(). */ /* crack the snooped driver setNumberVector or defNumberVector message into * the given INumberVectorProperty. * return 0 if type, device and name match and all members are present, else * return -1 */ int IUSnoopNumber (XMLEle *root, INumberVectorProperty *nvp) { char *dev, *name; XMLEle *ep; int i; /* check and crack type, device, name and state */ if (strcmp (tagXMLEle(root)+3, "NumberVector") || crackDN (root, &dev, &name, NULL) < 0) return (-1); if (strcmp (dev, nvp->device) || strcmp (name, nvp->name)) return (-1); /* not this property */ (void) crackIPState (findXMLAttValu (root,"state"), &nvp->s); /* match each INumber with a oneNumber */ for (i = 0; i < nvp->nnp; i++) { for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (!strcmp (tagXMLEle(ep)+3, "Number") && !strcmp (nvp->np[i].name, findXMLAttValu(ep, "name"))) { if (f_scansexa (pcdataXMLEle(ep), &nvp->np[i].value) < 0) return (-1); /* bad number format */ break; } } if (!ep) return (-1); /* element not found */ } /* ok */ return (0); } /* crack the snooped driver setTextVector or defTextVector message into * the given ITextVectorProperty. * return 0 if type, device and name match and all members are present, else * return -1 */ int IUSnoopText (XMLEle *root, ITextVectorProperty *tvp) { char *dev, *name; XMLEle *ep; int i; /* check and crack type, device, name and state */ if (strcmp (tagXMLEle(root)+3, "TextVector") || crackDN (root, &dev, &name, NULL) < 0) return (-1); if (strcmp (dev, tvp->device) || strcmp (name, tvp->name)) return (-1); /* not this property */ (void) crackIPState (findXMLAttValu (root,"state"), &tvp->s); /* match each IText with a oneText */ for (i = 0; i < tvp->ntp; i++) { for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (!strcmp (tagXMLEle(ep)+3, "Text") && !strcmp (tvp->tp[i].name, findXMLAttValu(ep, "name"))) { IUSaveText (&tvp->tp[i], pcdataXMLEle(ep)); break; } } if (!ep) return (-1); /* element not found */ } /* ok */ return (0); } /* crack the snooped driver setLightVector or defLightVector message into * the given ILightVectorProperty. it is not necessary that all ILight names * be found. * return 0 if type, device and name match, else return -1. */ int IUSnoopLight (XMLEle *root, ILightVectorProperty *lvp) { char *dev, *name; XMLEle *ep; int i; /* check and crack type, device, name and state */ if (strcmp (tagXMLEle(root)+3, "LightVector") || crackDN (root, &dev, &name, NULL) < 0) return (-1); if (strcmp (dev, lvp->device) || strcmp (name, lvp->name)) return (-1); /* not this property */ (void) crackIPState (findXMLAttValu (root,"state"), &lvp->s); /* match each oneLight with one ILight */ for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (!strcmp (tagXMLEle(ep)+3, "Light")) { const char *name = findXMLAttValu (ep, "name"); for (i = 0; i < lvp->nlp; i++) { if (!strcmp (lvp->lp[i].name, name)) { if (crackIPState(pcdataXMLEle(ep), &lvp->lp[i].s) < 0) { return (-1); /* unrecognized state */ } break; } } } } /* ok */ return (0); } /* crack the snooped driver setSwitchVector or defSwitchVector message into the * given ISwitchVectorProperty. it is not necessary that all ISwitch names be * found. * return 0 if type, device and name match, else return -1. */ int IUSnoopSwitch (XMLEle *root, ISwitchVectorProperty *svp) { char *dev, *name; XMLEle *ep; int i; /* check and crack type, device, name and state */ if (strcmp (tagXMLEle(root)+3, "SwitchVector") || crackDN (root, &dev, &name, NULL) < 0) return (-1); if (strcmp (dev, svp->device) || strcmp (name, svp->name)) return (-1); /* not this property */ (void) crackIPState (findXMLAttValu (root,"state"), &svp->s); /* match each oneSwitch with one ISwitch */ for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (!strcmp (tagXMLEle(ep)+3, "Switch")) { const char *name = findXMLAttValu (ep, "name"); for (i = 0; i < svp->nsp; i++) { if (!strcmp (svp->sp[i].name, name)) { if (crackISState(pcdataXMLEle(ep), &svp->sp[i].s) < 0) { return (-1); /* unrecognized state */ } break; } } } } /* ok */ return (0); } /* crack the snooped driver setBLOBVector message into the given * IBLOBVectorProperty. it is not necessary that all IBLOB names be found. * return 0 if type, device and name match, else return -1. * N.B. we assume any existing blob in bvp has been malloced, which we free * and replace with a newly malloced blob if found. */ int IUSnoopBLOB (XMLEle *root, IBLOBVectorProperty *bvp) { char *dev, *name; XMLEle *ep; int i; /* check and crack type, device, name and state */ if (strcmp (tagXMLEle(root), "setBLOBVector") || crackDN (root, &dev, &name, NULL) < 0) return (-1); if (strcmp (dev, bvp->device) || strcmp (name, bvp->name)) return (-1); /* not this property */ (void) crackIPState (findXMLAttValu (root,"state"), &bvp->s); /* match each oneBLOB with one IBLOB */ for (ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (!strcmp (tagXMLEle(ep)+3, "BLOB")) { const char *name = findXMLAttValu (ep, "name"); for (i = 0; i < bvp->nbp; i++) { IBLOB *bp = &bvp->bp[i]; if (!strcmp (bp->name, name)) { strcpy (bp->format, findXMLAttValu (ep,"format")); bp->size = atof (findXMLAttValu (ep,"size")); bp->bloblen = pcdatalenXMLEle(ep)+1; if (bp->blob) free (bp->blob); bp->blob = strcpy(malloc(bp->bloblen),pcdataXMLEle(ep)); break; } } } } /* ok */ return (0); } /* callback when INDI client message arrives on stdin. * collect and dispatch when see outter element closure. * exit if OS trouble or see incompatable INDI version. * arg is not used. */ void clientMsgCB (int fd, void *arg) { char buf[1024], msg[1024], *bp; int nr; arg=arg; /* one read */ nr = read (fd, buf, sizeof(buf)); if (nr < 0) { fprintf (stderr, "%s: %s\n", me, strerror(errno)); exit(1); } if (nr == 0) { fprintf (stderr, "%s: EOF\n", me); exit(1); } /* crack and dispatch when complete */ for (bp = buf; nr-- > 0; bp++) { XMLEle *root = readXMLEle (clixml, *bp, msg); if (root) { if (dispatch (root, msg) < 0) fprintf (stderr, "%s dispatch error: %s\n", me, msg); delXMLEle (root); } else if (msg[0]) fprintf (stderr, "%s XML error: %s\n", me, msg); } } /* crack the given INDI XML element and call driver's IS* entry points as they * are recognized. * return 0 if ok else -1 with reason in msg[]. * N.B. exit if getProperties does not proclaim a compatible version. */ int dispatch (XMLEle *root, char msg[]) { char *rtag = tagXMLEle(root); XMLEle *ep; int n,i=0; if (verbose) prXMLEle (stderr, root, 0); /* check tag in surmised decreasing order of likelyhood */ if (!strcmp (rtag, "newNumberVector")) { static double *doubles; static char **names; static int maxn; char *dev, *name; /* pull out device and name */ if (crackDN (root, &dev, &name, msg) < 0) return (-1); /* seed for reallocs */ if (!doubles) { doubles = (double *) malloc (1); names = (char **) malloc (1); } /* pull out each name/value pair */ for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (strcmp (tagXMLEle(ep), "oneNumber") == 0) { XMLAtt *na = findXMLAtt (ep, "name"); if (na) { if (n >= maxn) { /* grow for this and another */ int newsz = (maxn=n+1)*sizeof(double); doubles = (double *) realloc(doubles,newsz); newsz = maxn*sizeof(char *); names = (char **) realloc (names, newsz); } if (f_scansexa (pcdataXMLEle(ep), &doubles[n]) < 0) IDMessage (dev,"%s: Bad format %s", name, pcdataXMLEle(ep)); else names[n++] = valuXMLAtt(na); } } } /* insure property is not RO */ for (i=0; i < nroCheck; i++) { if (!strcmp(roCheck[i].propName, name)) { if (roCheck[i].perm == IP_RO) return -1; } } /* invoke driver if something to do, but not an error if not */ if (n > 0) ISNewNumber (dev, name, doubles, names, n); else IDMessage(dev,"%s: newNumberVector with no valid members",name); return (0); } if (!strcmp (rtag, "newSwitchVector")) { static ISState *states; static char **names; static int maxn; char *dev, *name; XMLEle *ep; /* pull out device and name */ if (crackDN (root, &dev, &name, msg) < 0) return (-1); /* seed for reallocs */ if (!states) { states = (ISState *) malloc (1); names = (char **) malloc (1); } /* pull out each name/state pair */ for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (strcmp (tagXMLEle(ep), "oneSwitch") == 0) { XMLAtt *na = findXMLAtt (ep, "name"); if (na) { if (n >= maxn) { int newsz = (maxn=n+1)*sizeof(ISState); states = (ISState *) realloc(states, newsz); newsz = maxn*sizeof(char *); names = (char **) realloc (names, newsz); } if (strcmp (pcdataXMLEle(ep),"On") == 0) { states[n] = ISS_ON; names[n] = valuXMLAtt(na); n++; } else if (strcmp (pcdataXMLEle(ep),"Off") == 0) { states[n] = ISS_OFF; names[n] = valuXMLAtt(na); n++; } else IDMessage (dev, "%s: must be On or Off: %s", name, pcdataXMLEle(ep)); } } } /* insure property is not RO */ for (i=0; i < nroCheck; i++) { if (!strcmp(roCheck[i].propName, name)) { if (roCheck[i].perm == IP_RO) return -1; } } /* invoke driver if something to do, but not an error if not */ if (n > 0) ISNewSwitch (dev, name, states, names, n); else IDMessage(dev,"%s: newSwitchVector with no valid members",name); return (0); } if (!strcmp (rtag, "newTextVector")) { static char **texts; static char **names; static int maxn; char *dev, *name; /* pull out device and name */ if (crackDN (root, &dev, &name, msg) < 0) return (-1); /* seed for reallocs */ if (!texts) { texts = (char **) malloc (1); names = (char **) malloc (1); } /* pull out each name/text pair */ for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (strcmp (tagXMLEle(ep), "oneText") == 0) { XMLAtt *na = findXMLAtt (ep, "name"); if (na) { if (n >= maxn) { int newsz = (maxn=n+1)*sizeof(char *); texts = (char **) realloc (texts, newsz); names = (char **) realloc (names, newsz); } texts[n] = pcdataXMLEle(ep); names[n] = valuXMLAtt(na); n++; } } } /* insure property is not RO */ for (i=0; i < nroCheck; i++) { if (!strcmp(roCheck[i].propName, name)) { if (roCheck[i].perm == IP_RO) return -1; } } /* invoke driver if something to do, but not an error if not */ if (n > 0) ISNewText (dev, name, texts, names, n); else IDMessage (dev, "%s: set with no valid members", name); return (0); } if (!strcmp (rtag, "newBLOBVector")) { static char **blobs; static char **names; static char **formats; static int *blobsizes; static int *sizes; static int maxn; char *dev, *name; int i; /* pull out device and name */ if (crackDN (root, &dev, &name, msg) < 0) return (-1); /* seed for reallocs */ if (!blobs) { blobs = (char **) malloc (1); names = (char **) malloc (1); formats = (char **) malloc (1); blobsizes = (int *) malloc (1); sizes = (int *) malloc (1); } /* pull out each name/BLOB pair, decode */ for (n = 0, ep = nextXMLEle(root,1); ep; ep = nextXMLEle(root,0)) { if (strcmp (tagXMLEle(ep), "oneBLOB") == 0) { XMLAtt *na = findXMLAtt (ep, "name"); XMLAtt *fa = findXMLAtt (ep, "format"); XMLAtt *sa = findXMLAtt (ep, "size"); if (na && fa && sa) { if (n >= maxn) { int newsz = (maxn=n+1)*sizeof(char *); blobs = (char **) realloc (blobs, newsz); names = (char **) realloc (names, newsz); formats = (char **) realloc(formats,newsz); newsz = maxn*sizeof(int); sizes = (int *) realloc(sizes,newsz); blobsizes = (int *) realloc(blobsizes,newsz); } blobs[n] = malloc (3*pcdatalenXMLEle(ep)/4); blobsizes[n] = from64tobits(blobs[n], pcdataXMLEle(ep)); names[n] = valuXMLAtt(na); formats[n] = valuXMLAtt(fa); sizes[n] = atoi(valuXMLAtt(sa)); n++; } } } /* invoke driver if something to do, but not an error if not */ if (n > 0) { ISNewBLOB (dev, name, sizes, blobsizes, blobs, formats,names,n); for (i = 0; i < n; i++) free (blobs[i]); } else IDMessage (dev, "%s: newBLOBVector with no valid members",name); return (0); } if (!strcmp (rtag, "getProperties")) { XMLAtt *ap; double v; /* check version */ ap = findXMLAtt (root, "version"); if (!ap) { fprintf (stderr, "%s: getProperties missing version\n", me); exit(1); } v = atof (valuXMLAtt(ap)); if (v > INDIV) { fprintf (stderr, "%s: client version %g > %g\n", me, v, INDIV); exit(1); } /* ok */ ap = findXMLAtt (root, "device"); ISGetProperties (ap ? valuXMLAtt(ap) : NULL); return (0); } /* other commands might be from a snooped device. * we don't know here which devices are being snooped so we send * all remaining valid messages */ if ( !strcmp (rtag, "setNumberVector") || !strcmp (rtag, "setTextVector") || !strcmp (rtag, "setLightVector") || !strcmp (rtag, "setSwitchVector") || !strcmp (rtag, "setBLOBVector") || !strcmp (rtag, "defNumberVector") || !strcmp (rtag, "defTextVector") || !strcmp (rtag, "defLightVector") || !strcmp (rtag, "defSwitchVector") || !strcmp (rtag, "defBLOBVector") || !strcmp (rtag, "message") || !strcmp (rtag, "delProperty")) { ISSnoopDevice (root); return (0); } sprintf (msg, "Unknown command: %s", rtag); return(1); } int IUReadConfig(const char *filename, const char *dev, char errmsg[]) { char configFileName[MAXRBUF], configDefaultFileName[MAXRBUF]; char *rname, *rdev; XMLEle *root = NULL, *fproot = NULL; LilXML *lp = newLilXML(); FILE *fp = NULL; if (filename) strncpy(configFileName, filename, MAXRBUF); else { if (getenv("INDICONFIG")) strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF); else snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev); } fp = fopen(configFileName, "r"); if (fp == NULL) { snprintf(errmsg, MAXRBUF, "Unable to read config file. Error loading file %s: %s\n", filename, strerror(errno)); return -1; } fproot = readXMLFile(fp, lp, errmsg); if (fproot == NULL) { snprintf(errmsg, MAXRBUF, "Unable to parse config XML: %s", errmsg); return -1; } for (root = nextXMLEle (fproot, 1); root != NULL; root = nextXMLEle (fproot, 0)) { /* pull out device and name */ if (crackDN (root, &rdev, &rname, errmsg) < 0) return -1; // It doesn't belong to our device?? if (strcmp(dev, rdev)) continue; dispatch(root, errmsg); } fclose(fp); delXMLEle(fproot); delXMLEle(root); delLilXML(lp); return (0); } void IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev) { char configFileName[MAXRBUF], configDefaultFileName[MAXRBUF]; if (source_config) strncpy(configFileName, source_config, MAXRBUF); else { if (getenv("INDICONFIG")) strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF); else snprintf(configFileName, MAXRBUF, "%s/.indi/%s_config.xml", getenv("HOME"), dev); } if (dest_config) strncpy(configDefaultFileName, dest_config, MAXRBUF); else if (getenv("INDICONFIG")) snprintf(configDefaultFileName, MAXRBUF, "%s.default", getenv("INDICONFIG")); else snprintf(configDefaultFileName, MAXRBUF, "%s/.indi/%s_config.xml.default", getenv("HOME"), dev); // If the default doesn't exist, create it. if (access(configDefaultFileName, F_OK)) { FILE *fpin = fopen(configFileName, "r"); if(fpin != NULL) { FILE *fpout = fopen(configDefaultFileName, "w"); if(fpout != NULL) { int ch = 0; while((ch = getc(fpin)) != EOF) putc(ch, fpout); fclose(fpin); fclose(fpout); } } } } /* send client a message for a specific device or at large if !dev */ void IDMessage (const char *dev, const char *fmt, ...) { xmlv1(); printf ("\n"); fflush (stdout); } FILE * IUGetConfigFP(const char *filename, const char *dev, char errmsg[]) { char configFileName[MAXRBUF]; char configDir[MAXRBUF]; struct stat st; FILE *fp = NULL; snprintf(configDir, MAXRBUF, "%s/.indi/", getenv("HOME")); if (filename) strncpy(configFileName, filename, MAXRBUF); else { if (getenv("INDICONFIG")) strncpy(configFileName, getenv("INDICONFIG"), MAXRBUF); else snprintf(configFileName, MAXRBUF, "%s%s_config.xml", configDir, dev); } if(stat(configDir,&st) != 0) { if (mkdir(configDir, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) < 0) { snprintf(errmsg, MAXRBUF, "Unable to create config directory. Error %s: %s\n", configDir, strerror(errno)); return NULL; } } fp = fopen(configFileName, "w"); if (fp == NULL) { snprintf(errmsg, MAXRBUF, "Unable to open config file. Error loading file %s: %s\n", configFileName, strerror(errno)); return NULL; } return fp; } void IUSaveConfigTag(FILE *fp, int ctag) { if (!fp) return; /* Opening tag */ if (ctag == 0) fprintf(fp, "\n"); /* Closing tag */ else fprintf(fp, "\n"); } void IUSaveConfigNumber (FILE *fp, const INumberVectorProperty *nvp) { int i; fprintf (fp, "\n", nvp->device, nvp->name); for (i = 0; i < nvp->nnp; i++) { INumber *np = &nvp->np[i]; fprintf (fp, " \n", np->name); fprintf (fp, " %.20g\n", np->value); fprintf (fp, " \n"); } fprintf (fp, "\n"); } void IUSaveConfigText (FILE *fp, const ITextVectorProperty *tvp) { int i; fprintf (fp, "\n", tvp->device, tvp->name); for (i = 0; i < tvp->ntp; i++) { IText *tp = &tvp->tp[i]; fprintf (fp, " \n", tp->name); fprintf (fp, " %s\n", tp->text ? tp->text : ""); fprintf (fp, " \n"); } fprintf (fp, "\n"); } void IUSaveConfigSwitch (FILE *fp, const ISwitchVectorProperty *svp) { int i; fprintf (fp, "\n", svp->device, svp->name); for (i = 0; i < svp->nsp; i++) { ISwitch *sp = &svp->sp[i]; fprintf (fp, " \n", sp->name); fprintf (fp, " %s\n", sstateStr(sp->s)); fprintf (fp, " \n"); } fprintf (fp, "\n"); } void IUSaveConfigBLOB (FILE *fp, const IBLOBVectorProperty *bvp) { int i; fprintf (fp, "\n", bvp->device, bvp->name); for (i = 0; i < bvp->nbp; i++) { IBLOB *bp = &bvp->bp[i]; unsigned char *encblob; int j, l; fprintf (fp, " name); fprintf (fp, " size='%d'\n", bp->size); fprintf (fp, " format='%s'>\n", bp->format); encblob = malloc (4*bp->bloblen/3+4); l = to64frombits(encblob, bp->blob, bp->bloblen); for (j = 0; j < l; j += 72) fprintf (fp, "%.72s\n", encblob+j); free (encblob); fprintf (fp, " \n"); } fprintf (fp, "\n"); } /* tell client to create a text vector property */ void IDDefText (const ITextVectorProperty *tvp, const char *fmt, ...) { int i; ROSC *SC; xmlv1(); printf ("device); printf (" name='%s'\n", tvp->name); printf (" label='%s'\n", tvp->label); printf (" group='%s'\n", tvp->group); printf (" state='%s'\n", pstateStr(tvp->s)); printf (" perm='%s'\n", permStr(tvp->p)); printf (" timeout='%g'\n", tvp->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < tvp->ntp; i++) { IText *tp = &tvp->tp[i]; printf (" name); printf (" label='%s'>\n", tp->label); printf (" %s\n", tp->text ? tp->text : ""); printf (" \n"); } printf ("\n"); if (!isPropDefined(tvp->name)) { /* Add this property to insure proper sanity check */ roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1)) : (ROSC *) malloc ( sizeof(ROSC)); SC = &roCheck[nroCheck++]; strcpy(SC->propName, tvp->name); SC->perm = tvp->p; } fflush (stdout); } /* tell client to create a new numeric vector property */ void IDDefNumber (const INumberVectorProperty *n, const char *fmt, ...) { int i; ROSC *SC; xmlv1(); printf ("device); printf (" name='%s'\n", n->name); printf (" label='%s'\n", n->label); printf (" group='%s'\n", n->group); printf (" state='%s'\n", pstateStr(n->s)); printf (" perm='%s'\n", permStr(n->p)); printf (" timeout='%g'\n", n->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < n->nnp; i++) { INumber *np = &n->np[i]; printf (" name); printf (" label='%s'\n", np->label); printf (" format='%s'\n", np->format); printf (" min='%.20g'\n", np->min); printf (" max='%.20g'\n", np->max); printf (" step='%.20g'>\n", np->step); printf (" %.20g\n", np->value); printf (" \n"); } printf ("\n"); if (!isPropDefined(n->name)) { /* Add this property to insure proper sanity check */ roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1)) : (ROSC *) malloc ( sizeof(ROSC)); SC = &roCheck[nroCheck++]; strcpy(SC->propName, n->name); SC->perm = n->p; } fflush (stdout); } /* tell client to create a new switch vector property */ void IDDefSwitch (const ISwitchVectorProperty *s, const char *fmt, ...) { int i; ROSC *SC; xmlv1(); printf ("device); printf (" name='%s'\n", s->name); printf (" label='%s'\n", s->label); printf (" group='%s'\n", s->group); printf (" state='%s'\n", pstateStr(s->s)); printf (" perm='%s'\n", permStr(s->p)); printf (" rule='%s'\n", ruleStr (s->r)); printf (" timeout='%g'\n", s->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < s->nsp; i++) { ISwitch *sp = &s->sp[i]; printf (" name); printf (" label='%s'>\n", sp->label); printf (" %s\n", sstateStr(sp->s)); printf (" \n"); } printf ("\n"); if (!isPropDefined(s->name)) { /* Add this property to insure proper sanity check */ roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1)) : (ROSC *) malloc ( sizeof(ROSC)); SC = &roCheck[nroCheck++]; strcpy(SC->propName, s->name); SC->perm = s->p; } fflush (stdout); } /* tell client to create a new lights vector property */ void IDDefLight (const ILightVectorProperty *lvp, const char *fmt, ...) { int i; xmlv1(); printf ("device); printf (" name='%s'\n", lvp->name); printf (" label='%s'\n", lvp->label); printf (" group='%s'\n", lvp->group); printf (" state='%s'\n", pstateStr(lvp->s)); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < lvp->nlp; i++) { ILight *lp = &lvp->lp[i]; printf (" name); printf (" label='%s'>\n", lp->label); printf (" %s\n", pstateStr(lp->s)); printf (" \n"); } printf ("\n"); fflush (stdout); } /* tell client to create a new BLOB vector property */ void IDDefBLOB (const IBLOBVectorProperty *b, const char *fmt, ...) { int i; ROSC *SC; xmlv1(); printf ("device); printf (" name='%s'\n", b->name); printf (" label='%s'\n", b->label); printf (" group='%s'\n", b->group); printf (" state='%s'\n", pstateStr(b->s)); printf (" perm='%s'\n", permStr(b->p)); printf (" timeout='%g'\n", b->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < b->nbp; i++) { IBLOB *bp = &b->bp[i]; printf (" name); printf (" label='%s'\n", bp->label); printf (" />\n"); } printf ("\n"); if (!isPropDefined(b->name)) { /* Add this property to insure proper sanity check */ roCheck = roCheck ? (ROSC *) realloc ( roCheck, sizeof(ROSC) * (nroCheck+1)) : (ROSC *) malloc ( sizeof(ROSC)); SC = &roCheck[nroCheck++]; strcpy(SC->propName, b->name); SC->perm = b->p; } fflush (stdout); } /* tell client to update an existing text vector property */ void IDSetText (const ITextVectorProperty *tvp, const char *fmt, ...) { int i; xmlv1(); printf ("device); printf (" name='%s'\n", tvp->name); printf (" state='%s'\n", pstateStr(tvp->s)); printf (" timeout='%g'\n", tvp->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < tvp->ntp; i++) { IText *tp = &tvp->tp[i]; printf (" \n", tp->name); printf (" %s\n", tp->text ? tp->text : ""); printf (" \n"); } printf ("\n"); fflush (stdout); } /* tell client to update an existing numeric vector property */ void IDSetNumber (const INumberVectorProperty *nvp, const char *fmt, ...) { int i; xmlv1(); printf ("device); printf (" name='%s'\n", nvp->name); printf (" state='%s'\n", pstateStr(nvp->s)); printf (" timeout='%g'\n", nvp->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < nvp->nnp; i++) { INumber *np = &nvp->np[i]; printf (" \n", np->name); printf (" %.20g\n", np->value); printf (" \n"); } printf ("\n"); fflush (stdout); } /* tell client to update an existing switch vector property */ void IDSetSwitch (const ISwitchVectorProperty *svp, const char *fmt, ...) { int i; xmlv1(); printf ("device); printf (" name='%s'\n", svp->name); printf (" state='%s'\n", pstateStr(svp->s)); printf (" timeout='%g'\n", svp->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < svp->nsp; i++) { ISwitch *sp = &svp->sp[i]; printf (" \n", sp->name); printf (" %s\n", sstateStr(sp->s)); printf (" \n"); } printf ("\n"); fflush (stdout); } /* tell client to update an existing lights vector property */ void IDSetLight (const ILightVectorProperty *lvp, const char *fmt, ...) { int i; xmlv1(); printf ("device); printf (" name='%s'\n", lvp->name); printf (" state='%s'\n", pstateStr(lvp->s)); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < lvp->nlp; i++) { ILight *lp = &lvp->lp[i]; printf (" \n", lp->name); printf (" %s\n", pstateStr(lp->s)); printf (" \n"); } printf ("\n"); fflush (stdout); } /* tell client to update an existing BLOB vector property */ void IDSetBLOB (const IBLOBVectorProperty *bvp, const char *fmt, ...) { int i; xmlv1(); printf ("device); printf (" name='%s'\n", bvp->name); printf (" state='%s'\n", pstateStr(bvp->s)); printf (" timeout='%g'\n", bvp->timeout); printf (" timestamp='%s'\n", timestamp()); if (fmt) { va_list ap; va_start (ap, fmt); printf (" message='"); vprintf (fmt, ap); printf ("'\n"); va_end (ap); } printf (">\n"); for (i = 0; i < bvp->nbp; i++) { IBLOB *bp = &bvp->bp[i]; unsigned char *encblob; int j, l; printf (" name); printf (" size='%d'\n", bp->size); printf (" format='%s'>\n", bp->format); encblob = malloc (4*bp->bloblen/3+4); l = to64frombits(encblob, bp->blob, bp->bloblen); for (j = 0; j < l; j += 72) printf ("%.72s\n", encblob+j); free (encblob); printf (" \n"); } printf ("\n"); fflush (stdout); } /* tell client to update min/max elements of an existing number vector property */ void IUUpdateMinMax(const INumberVectorProperty *nvp) { int i; xmlv1(); printf ("device); printf (" name='%s'\n", nvp->name); printf (" state='%s'\n", pstateStr(nvp->s)); printf (" timeout='%g'\n", nvp->timeout); printf (" timestamp='%s'\n", timestamp()); printf (">\n"); for (i = 0; i < nvp->nnp; i++) { INumber *np = &nvp->np[i]; printf (" name); printf (" min='%g'\n", np->min); printf (" max='%g'\n", np->max); printf (" step='%g'\n", np->step); printf(">\n"); printf (" %g\n", np->value); printf (" \n"); } printf ("\n"); fflush (stdout); } /* Return 1 is property is already cached, 0 otherwise */ int isPropDefined(const char *property_name) { int i=0; for (i=0; i < nroCheck; i++) if (!strcmp(property_name, roCheck[i].propName)) return 1; return 0; } int IUFindIndex (const char *needle, char **hay, unsigned int n) { int i=0; for (i=0; i < n; i++) if (!strcmp(hay[i], needle)) return i; return -1; } libindi-0.9.7/fq.h0000644000175000017500000000232112241463551012701 0ustar jasemjasem/* a fifo queue that never fills. * Copyright (C) 2005 Elwood C. Downey ecdowney@clearskyinstitute.com 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 */ typedef struct _FQ FQ; extern FQ *newFQ(int grow); extern void delFQ (FQ *q); extern void pushFQ (FQ *q, void *e); extern void *popFQ (FQ *q); extern void *peekFQ (FQ *q); extern void *peekiFQ (FQ *q, int i); extern int nFQ (FQ *q); extern void setMemFuncsFQ (void *(*newmalloc)(size_t size), void *(*newrealloc)(void *ptr, size_t size), void (*newfree)(void *ptr)); libindi-0.9.7/CMakeLists.txt0000644000175000017500000006247612241463551014703 0ustar jasemjasemcmake_minimum_required(VERSION 2.4.7) PROJECT(libindi C CXX) ################## INDI version ################################ set(INDI_SOVERSION "0") set(CMAKE_INDI_VERSION_MAJOR 0) set(CMAKE_INDI_VERSION_MINOR 9) set(CMAKE_INDI_VERSION_RELEASE 7) set(CMAKE_INDI_VERSION_STRING "${CMAKE_INDI_VERSION_MAJOR}.${CMAKE_INDI_VERSION_MINOR}.${CMAKE_INDI_VERSION_RELEASE}") ################## Paths ################################ set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake_modules/") set(DATA_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/indi/") set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin") set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include") IF(APPLE) set(CMAKE_SHARED_LINKER_FLAGS "-undefined dynamic_lookup") ENDIF(APPLE) ################## setup install directories ################################ set (LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" ) set (LIB_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE STRING "Library directory name") ## the following are directories where stuff will be installed to set(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include/" CACHE PATH "The subdirectory to the header prefix") set(PKGCONFIG_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/pkgconfig/" CACHE STRING "Base directory for pkgconfig files") set(UDEVRULES_INSTALL_DIR "/lib/udev/rules.d" CACHE STRING "Base directory for udev rules") ################## Includes ################################ Include (CheckCXXSourceCompiles) include (MacroOptionalFindPackage) include (MacroLogFeature) include (MacroBoolTo01) include (CheckIncludeFiles) FIND_PACKAGE(ZLIB REQUIRED) FIND_PACKAGE(USB REQUIRED) FIND_PACKAGE(CFITSIO REQUIRED) FIND_PACKAGE(Nova REQUIRED) if (NOT CFITSIO_FOUND OR CFITSIO_VERSION_MAJOR LESS 3) message(FATAL_ERROR "CFITSIO version too old, Please install cfitsio 3.x and try again. http://heasarc.gsfc.nasa.gov/fitsio/fitsio.html") endif (NOT CFITSIO_FOUND OR CFITSIO_VERSION_MAJOR LESS 3) macro_bool_to_01(CFITSIO_FOUND HAVE_CFITSIO_H) macro_log_feature(CFITSIO_FOUND "libcfitsio" "A library for reading and writing data files in FITS (Flexible Image Transport System) data format" "http://heasarc.gsfc.nasa.gov/fitsio/fitsio.html" FALSE "3.03" "Provides INDI with FITS I/O support.") macro_bool_to_01(NOVA_FOUND HAVE_NOVA_H) macro_log_feature(NOVA_FOUND "libnova" "A general purpose, double precision, Celestial Mechanics, Astrometry and Astrodynamics library" "http://libnova.sourceforge.net" FALSE "0.12.1" "Provides INDI with astrodynamics library.") check_include_files(linux/videodev2.h HAVE_LINUX_VIDEODEV2_H) check_include_files(termios.h TERMIOS_FOUND) macro_bool_to_01(TERMIOS_FOUND HAVE_TERMIOS_H) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h ) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) include_directories( ${CMAKE_CURRENT_BINARY_DIR}) include_directories( ${CMAKE_SOURCE_DIR}) include_directories( ${CMAKE_SOURCE_DIR}/libs) include_directories( ${CMAKE_SOURCE_DIR}/libs/indibase) include_directories( ${CMAKE_SOURCE_DIR}/libs/webcam) if (CFITSIO_FOUND) include_directories(${CFITSIO_INCLUDE_DIR}) endif (CFITSIO_FOUND) include_directories(${NOVA_INCLUDE_DIR}) set(liblilxml_SRCS ${CMAKE_SOURCE_DIR}/libs/lilxml.c ) set(libindicom_SRCS ${CMAKE_SOURCE_DIR}/libs/indicom.c ${CMAKE_SOURCE_DIR}/base64.c ) set(libwebcam_SRCS ${CMAKE_SOURCE_DIR}/libs/webcam/PPort.cpp ${CMAKE_SOURCE_DIR}/libs/webcam/port.cpp ${CMAKE_SOURCE_DIR}/libs/webcam/v4l2_base.cpp ${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_c2.c ${CMAKE_SOURCE_DIR}/libs/webcam/ccvt_misc.c ) set (indimain_SRCS ${CMAKE_SOURCE_DIR}/indidriver.c ${CMAKE_SOURCE_DIR}/indidrivermain.c ${CMAKE_SOURCE_DIR}/eventloop.c ) set (indiclient_SRCS ${CMAKE_SOURCE_DIR}/libs/indibase/basedevice.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/baseclient.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indiproperty.cpp ) set (indidriver_SRCS ${CMAKE_SOURCE_DIR}/libs/indibase/basedevice.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/defaultdevice.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indiproperty.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indiccd.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/inditelescope.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indifilterwheel.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indifocuser.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indiusbdevice.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indiguiderinterface.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indifilterinterface.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indilogger.cpp ${CMAKE_SOURCE_DIR}/libs/indibase/indicontroller.cpp ) ###################################### ########### INDI SERVER ############## ###################################### set(indiserver_SRCS indiserver.c fq.c) add_executable(indiserver ${indiserver_SRCS} ${liblilxml_SRCS}) target_link_libraries(indiserver ${NOVA_LIBRARIES} pthread) install(TARGETS indiserver RUNTIME DESTINATION bin) ################################################# ############# INDI Shared Library ############### # To offer lilxml and communination routines # # Mostly used by generic clients # ################################################# add_library(indi SHARED ${libindicom_SRCS} ${liblilxml_SRCS}) target_link_libraries(indi ${NOVA_LIBRARIES} m z) if (CFITSIO_FOUND) target_link_libraries(indi ${CFITSIO_LIBRARIES}) endif(CFITSIO_FOUND) install(TARGETS indi LIBRARY DESTINATION ${LIB_DESTINATION}) set_target_properties(indi PROPERTIES VERSION ${CMAKE_INDI_VERSION_STRING} SOVERSION ${INDI_SOVERSION}) ################################################### ############ INDI Main Shared Library ############# # To link with main() for 3rd party legacy drivers# ################################################### add_library(indimain SHARED ${indimain_SRCS} ${libindicom_SRCS} ${liblilxml_SRCS}) target_link_libraries(indimain ${NOVA_LIBRARIES}) if (CFITSIO_FOUND) target_link_libraries(indimain ${CFITSIO_LIBRARIES}) endif(CFITSIO_FOUND) install(TARGETS indimain LIBRARY DESTINATION ${LIB_DESTINATION}) set_target_properties(indimain PROPERTIES VERSION ${CMAKE_INDI_VERSION_STRING} SOVERSION ${INDI_SOVERSION}) ################################################## ########## INDI Default Driver Library ########### # To link with main() and indibase classes ###### ################################################## add_library(indidriver SHARED ${libindicom_SRCS} ${liblilxml_SRCS} ${indimain_SRCS} ${indidriver_SRCS}) target_link_libraries(indidriver ${LIBUSB_LIBRARIES} ${NOVA_LIBRARIES}) if (CFITSIO_FOUND) target_link_libraries(indidriver ${CFITSIO_LIBRARIES}) endif(CFITSIO_FOUND) install(TARGETS indidriver LIBRARY DESTINATION ${LIB_DESTINATION}) set_target_properties(indidriver PROPERTIES VERSION ${CMAKE_INDI_VERSION_STRING} SOVERSION ${INDI_SOVERSION}) #install(TARGETS indidriver ARCHIVE DESTINATION ${LIB_DESTINATION}) ################################################## ########### INDI Client Static Library ########### ################################################## add_library(indiclient STATIC ${indiclient_SRCS}) target_link_libraries(indiclient indi pthread) install(TARGETS indiclient ARCHIVE DESTINATION ${LIB_DESTINATION}) ##################################### ########## TELESCOPE GROUP ########## ##################################### ########### LX200 Basic ############# set(lx200basic_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200basic.cpp ) add_executable(indi_lx200basic ${lx200basic_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_lx200basic ${NOVA_LIBRARIES} ${NOVA_LIBRARIES}) install(TARGETS indi_lx200basic RUNTIME DESTINATION bin ) ################################################################################# ########### LX200 Generic ########### set(lx200generic_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200autostar.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200_16.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200gps.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200generic.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200classic.cpp) add_executable(indi_lx200generic ${lx200generic_SRCS}) target_link_libraries(indi_lx200generic indidriver ${NOVA_LIBRARIES} m ) install(TARGETS indi_lx200generic RUNTIME DESTINATION bin ) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_lx200generic_symlink.cmake "exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200classic)\n exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200autostar)\n exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200_16)\n exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200generic \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200gps)\n ") set_target_properties(indi_lx200generic PROPERTIES POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/make_lx200generic_symlink.cmake) ################################################################################# ########### LX200 Generic Legacy ########### set(lx200genericlegacy_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200genericlegacy.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200apdriver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200ap.cpp ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200fs2.cpp) add_executable(indi_lx200genericlegacy ${lx200genericlegacy_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_lx200genericlegacy ${NOVA_LIBRARIES} m ) install(TARGETS indi_lx200genericlegacy RUNTIME DESTINATION bin ) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_lx200genericlegacy_symlink.cmake "exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200genericlegacy \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200ap)\n exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_lx200genericlegacy \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_lx200fs2)\n ") set_target_properties(indi_lx200genericlegacy PROPERTIES POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/make_lx200genericlegacy_symlink.cmake) ################################################################################# ########### Celestron GPS ############ set(celestrongps_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/celestronprotocol.c ${CMAKE_SOURCE_DIR}/drivers/telescope/celestrongps.cpp ) add_executable(indi_celestron_gps ${celestrongps_SRCS}) target_link_libraries(indi_celestron_gps indidriver ${NOVA_LIBRARIES} m ) install(TARGETS indi_celestron_gps RUNTIME DESTINATION bin ) ################################################################################# ########### Takahashi Temma ########## set(temma_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/temmadriver.c ) add_executable(indi_temma ${temma_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_temma ${NOVA_LIBRARIES} m ) install(TARGETS indi_temma RUNTIME DESTINATION bin ) ################################################################################# ########### Sky Commander ############# set(skycommander_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/skycommander.c ) add_executable(indi_skycommander ${skycommander_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_skycommander ${NOVA_LIBRARIES} m ) install(TARGETS indi_skycommander RUNTIME DESTINATION bin ) ################################################################################# ########### Intelliscope ############### set(intelliscope_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/lx200driver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/intelliscope.c ) add_executable(indi_intelliscope ${intelliscope_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_intelliscope ${NOVA_LIBRARIES} m ) install(TARGETS indi_intelliscope RUNTIME DESTINATION bin ) ########### Syncscan ############### set(synscan_SRCS ${CMAKE_SOURCE_DIR}/drivers/telescope/synscanmount.cpp ) add_executable(indi_synscan ${synscan_SRCS}) target_link_libraries(indi_synscan indidriver m z) install(TARGETS indi_synscan RUNTIME DESTINATION bin ) ########### Magellan I ############# set(magellan_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/magellandriver.c ${CMAKE_SOURCE_DIR}/drivers/telescope/magellan1.cpp ) add_executable(indi_magellan1 ${magellan_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_magellan1 ${NOVA_LIBRARIES}) install(TARGETS indi_magellan1 RUNTIME DESTINATION bin ) ########### IEQ45 ############# ###Handheld 8406 version set(ieq45_8406_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45driver8406.c ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45.cpp ) add_executable(indi_ieq45_8406 ${ieq45_8406_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_ieq45_8406 ${NOVA_LIBRARIES}) install(TARGETS indi_ieq45_8406 RUNTIME DESTINATION bin ) ###Handheld 8407 version set(ieq45_8407_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45driver8407.c ${CMAKE_SOURCE_DIR}/drivers/telescope/ieq45.cpp ) add_executable(indi_ieq45_8407 ${ieq45_8407_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_ieq45_8407 ${NOVA_LIBRARIES}) install(TARGETS indi_ieq45_8407 RUNTIME DESTINATION bin ) ########### Telescope Simulator ############## set(telescopesimulator_SRCS ${CMAKE_SOURCE_DIR}/drivers/telescope/telescope_simulator.cpp ) add_executable(indi_simulator_telescope ${telescopesimulator_SRCS}) target_link_libraries(indi_simulator_telescope indidriver m z pthread) install(TARGETS indi_simulator_telescope RUNTIME DESTINATION bin ) ########### CCD Simulator ############## if (CFITSIO_FOUND) set(ccdsimulator_SRCS ${CMAKE_SOURCE_DIR}/drivers/ccd/ccd_simulator.cpp ) add_executable(indi_simulator_ccd ${ccdsimulator_SRCS}) target_link_libraries(indi_simulator_ccd indidriver m z pthread) install(TARGETS indi_simulator_ccd RUNTIME DESTINATION bin ) endif (CFITSIO_FOUND) ##################################### ########## FOCUSER GROUP ############ ##################################### ################################################################################# ################ Focuser Simulator ################ set(focussimulator_SRCS ${CMAKE_SOURCE_DIR}/drivers/focuser/focus_simulator.cpp ) add_executable(indi_simulator_focus ${focussimulator_SRCS}) target_link_libraries(indi_simulator_focus indidriver m z) install(TARGETS indi_simulator_focus RUNTIME DESTINATION bin ) ################ Robo Focuser ################ set(robofocus_SRCS ${CMAKE_SOURCE_DIR}/drivers/focuser/robofocus.cpp ) add_executable(indi_robo_focus ${robofocus_SRCS}) target_link_libraries(indi_robo_focus indidriver m z) install(TARGETS indi_robo_focus RUNTIME DESTINATION bin ) ################ Optec TCF-S ################ set(tcfs_SRCS ${CMAKE_SOURCE_DIR}/drivers/focuser/tcfs.cpp ) add_executable(indi_tcfs_focus ${tcfs_SRCS}) target_link_libraries(indi_tcfs_focus indidriver m z) install(TARGETS indi_tcfs_focus RUNTIME DESTINATION bin ) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/make_tcfs_symlink.cmake "exec_program(\"${CMAKE_COMMAND}\" ARGS -E create_symlink ${BIN_INSTALL_DIR}/indi_tcfs_focus \$ENV{DESTDIR}${BIN_INSTALL_DIR}/indi_tcfs3_focus)\n") set_target_properties(indi_tcfs_focus PROPERTIES POST_INSTALL_SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/make_tcfs_symlink.cmake) ################################################################################# ##################################### ######## FILTER WHEEL GROUP ######### ##################################### ########## True Technology Wheel ############ set(trutechwheel_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/filter_wheel/trutech_wheel.c ) add_executable(indi_trutech_wheel ${trutechwheel_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_trutech_wheel ${NOVA_LIBRARIES} m) install(TARGETS indi_trutech_wheel RUNTIME DESTINATION bin ) ########### Filter Simulator ############## set(filtersimulator_SRCS ${CMAKE_SOURCE_DIR}/drivers/filter_wheel/filter_simulator.cpp ) add_executable(indi_simulator_wheel ${filtersimulator_SRCS}) target_link_libraries(indi_simulator_wheel indidriver m z pthread) install(TARGETS indi_simulator_wheel RUNTIME DESTINATION bin ) ################################################################################# ######################################### ########### VIDEO GROUP ############### ######################################### ########### STV ####################### if (CFITSIO_FOUND) set(stv_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/video/stvdriver.c ${CMAKE_SOURCE_DIR}/drivers/video/stv.c ) add_executable(indi_sbig_stv ${stv_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_sbig_stv z m ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES} pthread) install(TARGETS indi_sbig_stv RUNTIME DESTINATION bin ) endif(CFITSIO_FOUND) ################################################################################# ### Meade Lunar Planetary Imager ######## if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (CFITSIO_FOUND) ADD_DEFINITIONS(-DHAVE_LINUX_VIDEODEV2_H) set(meade_lpi_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp ${CMAKE_SOURCE_DIR}/drivers/video/indi_lpi.cpp ) add_executable(indi_meade_lpi ${meade_lpi_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_meade_lpi z ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES} pthread) install(TARGETS indi_meade_lpi RUNTIME DESTINATION bin ) endif (CFITSIO_FOUND) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") ################################################################################# ########### V4L Philips ############## if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (CFITSIO_FOUND) set(v4lphilips_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp ${CMAKE_SOURCE_DIR}/drivers/video/v4lphilips.cpp ${CMAKE_SOURCE_DIR}/drivers/video/indi_philips.cpp ) add_executable(indi_v4l_philips ${v4lphilips_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_v4l_philips m z ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES} pthread) install(TARGETS indi_v4l_philips RUNTIME DESTINATION bin ) endif (CFITSIO_FOUND) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") ################################################################################# ########### Generic V4L Driver ############### if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") if (CFITSIO_FOUND) set(v4ldriver_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/drivers/video/v4ldriver.cpp ${CMAKE_SOURCE_DIR}/drivers/video/indi_v4l.cpp ) add_executable(indi_v4l_generic ${v4ldriver_SRCS} ${libwebcam_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_v4l_generic m z ${NOVA_LIBRARIES} ${CFITSIO_LIBRARIES} pthread) install(TARGETS indi_v4l_generic RUNTIME DESTINATION bin ) endif (CFITSIO_FOUND) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") ################################################################################# ##################################### ############ AUX GROUP ############## ##################################### if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") ########### GPUSB Driver ############### set(gpusb_SRCS ${CMAKE_SOURCE_DIR}/drivers/auxiliary/gpdriver.cpp ${CMAKE_SOURCE_DIR}/drivers/auxiliary/gpusb.cpp ) add_executable(indi_gpusb ${gpusb_SRCS}) target_link_libraries(indi_gpusb indidriver m z pthread) install(TARGETS indi_gpusb RUNTIME DESTINATION bin ) install(FILES ${CMAKE_SOURCE_DIR}/drivers/auxiliary/99-gpusb.rules DESTINATION ${UDEVRULES_INSTALL_DIR}) ########### Joystick Driver ############### set(joystick_SRCS ${CMAKE_SOURCE_DIR}/drivers/auxiliary/joystickdriver.cpp ${CMAKE_SOURCE_DIR}/drivers/auxiliary/joystick.cpp ) add_executable(indi_joystick ${joystick_SRCS}) target_link_libraries(indi_joystick indidriver m z pthread) install(TARGETS indi_joystick RUNTIME DESTINATION bin ) endif (${CMAKE_SYSTEM_NAME} MATCHES "Linux") ########### getINDI ############## set(getindi_SRCS ${CMAKE_SOURCE_DIR}/eventloop.c ${CMAKE_SOURCE_DIR}/tools/getINDIproperty.c ) add_executable(indi_getprop ${getindi_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_getprop ${NOVA_LIBRARIES} m z) install(TARGETS indi_getprop RUNTIME DESTINATION bin ) ################################################################################# ########### setINDI ############## set(setindi_SRCS ${CMAKE_SOURCE_DIR}/eventloop.c ${CMAKE_SOURCE_DIR}/tools/setINDIproperty.c ) add_executable(indi_setprop ${setindi_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_setprop ${NOVA_LIBRARIES} m z) install(TARGETS indi_setprop RUNTIME DESTINATION bin ) ################################################################################# ########### evelINDI ############## set(evalindi_SRCS ${CMAKE_SOURCE_DIR}/eventloop.c ${CMAKE_SOURCE_DIR}/tools/compiler.c ${CMAKE_SOURCE_DIR}/tools/evalINDI.c ) add_executable(indi_eval ${evalindi_SRCS} ${liblilxml_SRCS} ${libindicom_SRCS}) target_link_libraries(indi_eval ${NOVA_LIBRARIES} m z) install(TARGETS indi_eval RUNTIME DESTINATION bin ) ################################################################################# ## Build Examples. Not installation ########### Tutorial one ############## set(tutorialone_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/examples/tutorial_one/simpledevice.cpp ) add_executable(tutorial_one ${tutorialone_SRCS}) target_link_libraries(tutorial_one indidriver m) ########### Tutorial two ############## set(tutorialtwo_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/examples/tutorial_two/simplescope.cpp ) add_executable(tutorial_two ${tutorialtwo_SRCS}) target_link_libraries(tutorial_two indidriver m) ########### Tutorial three ############## if (CFITSIO_FOUND) set(tutorialthree_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/examples/tutorial_three/simpleccd.cpp ) add_executable(tutorial_three ${tutorialthree_SRCS}) target_link_libraries(tutorial_three indidriver m) endif (CFITSIO_FOUND) ########### Tutorial four ############## set(tutorialfour_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/examples/tutorial_four/simpleskeleton.cpp ) add_executable(tutorial_four ${tutorialfour_SRCS}) target_link_libraries(tutorial_four indidriver m) ########### Tutorial five - dome driver ############## set(tutorialdome_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/examples/tutorial_five/dome.cpp ) add_executable(tutorial_dome ${tutorialdome_SRCS}) target_link_libraries(tutorial_dome indidriver) ########### Tutorial five - rain driver ############## set(tutorialrain_SRCS ${indimain_SRCS} ${CMAKE_SOURCE_DIR}/examples/tutorial_five/raindetector.cpp ) add_executable(tutorial_rain ${tutorialrain_SRCS}) target_link_libraries(tutorial_rain indidriver) ########### Client Tutorial ############## set(tutorialclient_SRCS ${CMAKE_SOURCE_DIR}/examples/tutorial_six/tutorial_client.cpp ) add_executable(tutorial_client ${tutorialclient_SRCS}) target_link_libraries(tutorial_client indiclient) ################################################################################# install( FILES drivers.xml ${CMAKE_SOURCE_DIR}/drivers/focuser/indi_tcfs_sk.xml DESTINATION ${DATA_INSTALL_DIR}) install( FILES indiapi.h indidevapi.h base64.h eventloop.h indidriver.h ${CMAKE_SOURCE_DIR}/libs/lilxml.h ${CMAKE_SOURCE_DIR}/libs/indibase/indibase.h ${CMAKE_SOURCE_DIR}/libs/indibase/basedevice.h ${CMAKE_SOURCE_DIR}/libs/indibase/defaultdevice.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiccd.h ${CMAKE_SOURCE_DIR}/libs/indibase/indifilterwheel.h ${CMAKE_SOURCE_DIR}/libs/indibase/indifocuser.h ${CMAKE_SOURCE_DIR}/libs/indibase/inditelescope.h ${CMAKE_SOURCE_DIR}/libs/indibase/baseclient.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiguiderinterface.h ${CMAKE_SOURCE_DIR}/libs/indibase/indifilterinterface.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiproperty.h ${CMAKE_SOURCE_DIR}/libs/indicom.h ${CMAKE_SOURCE_DIR}/libs/indibase/indiusbdevice.h ${CMAKE_SOURCE_DIR}/libs/indibase/indilogger.h ${CMAKE_SOURCE_DIR}/libs/indibase/indicontroller.h DESTINATION ${INCLUDE_INSTALL_DIR}/libindi COMPONENT Devel) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/libindi.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/libindi.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libindi.pc DESTINATION ${PKGCONFIG_INSTALL_PREFIX}) libindi-0.9.7/LICENSE0000644000175000017500000006351012241463551013136 0ustar jasemjasem GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libindi-0.9.7/indiapi.h0000644000175000017500000003515212241463551013720 0ustar jasemjasem#if 0 INDI Copyright (C) 2003 Elwood C. Downey 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 #ifndef INDI_API_H #define INDI_API_H /** \mainpage Instrument Neutral Distributed Interface INDI * \section Introduction INDI is a simple XML-like communications protocol described for interactive and automated remote control of diverse instrumentation.\n INDI is small, easy to parse, and stateless. In the INDI paradigm each Device poses all command and status functions in terms of settings and getting Properties. Each Property is a vector of one or more names members. Each property has a current value vector; a target value vector; provides information about how it should be sequenced with respect to other Properties to accomplish one coordinated unit of observation; and provides hints as to how it might be displayed for interactive manipulation in a GUI.\n Clients learn the Properties of a particular Device at runtime using introspection. This decouples Client and Device implementation histories. Devices have a complete authority over whether to accept commands from Clients. INDI accommadates intermediate servers, broadcasting, and connection topologies ranging from one-to-one on a single system to many-to-many between systems of different genre.\n The INDI protocol can be nested within other XML elements such as constraints for automatic scheduling and execution.\n For a complete review on the INDI protocol, please refer to the INDI white paper. \section Audience Intended Audience INDI is intended for developers who seek a scalable API for device control and automation. Hardware drivers written under INDI can be used under any INDI-compatible client. INDI serves as a backend only, you need frontend clients to control devices. Current clients include KStars, Xephem, DCD, and Cartes du Ciel. \section Development Developing under INDI

Please refere to the INDI Developers Manual for a complete guide on INDI's driver developemnt framework.

The INDI Library API is divided into the following main sections:

\section Tutorials INDI Library includes a number of tutorials to illustrate development of INDI drivers. Check out the examples provided with INDI library. \section Simulators Simulators provide a great framework to test drivers and equipment alike. INDI Library provides the following simulators:
  • Telescope Simulator: Offers GOTO capability, motion control, guiding, and ability to set Periodic Error (PE) which is read by the CCD simulator when generating images.
  • CCD Simulator: Offers a very flexible CCD simulator with a primary CCD chip and a guide chip. The simulator generate images based on the RA & DEC coordinates it snoops from the telescope driver using General Star Catalog (GSC). Please note that you must install GSC for the CCD simulator to work properly. Furthermore, The simulator snoops FWHM from the focuser simulator which affects the generated images focus. All images are generated in standard FITS format.
  • Filter Wheel Simulator: Offers a simple simulator to change filter wheels and their corresponding designations.
  • Focuser Simulator: Offers a simple simualtor for an absolute position focuser. It generates a simulated FWHM value that may be used by other simulator such as the CCD simulator.
\section Help You can find information on INDI development in the INDI Library site. Furthermore, you can discuss INDI related issues on the INDI development mailing list. \author Jasem Mutlaq \author Elwood Downey */ /** \file indiapi.h \brief Constants and Data structure definitions for the interface to the reference INDI C API implementation. \author Elwood C. Downey */ /******************************************************************************* * INDI wire protocol version implemented by this API. * N.B. this is indepedent of the API itself. */ #define INDIV 1.7 /* INDI Library version */ #define INDI_LIBV 0.9 /******************************************************************************* * Manifest constants */ /** \typedef ISState \brief Switch state. */ typedef enum { ISS_OFF, /*!< Switch is OFF */ ISS_ON /*!< Switch is ON */ } ISState; /* switch state */ /** \typedef IPState \brief Property state. */ typedef enum { IPS_IDLE, /*!< State is idle */ IPS_OK, /*!< State is ok */ IPS_BUSY, /*!< State is busy */ IPS_ALERT /*!< State is alert */ } IPState; /* property state */ /** \typedef ISRule \brief Switch vector rule hint. */ typedef enum { ISR_1OFMANY, /*!< Only 1 switch of many can be ON (e.g. radio buttons) */ ISR_ATMOST1, /*!< There is only ONE switch */ ISR_NOFMANY /*!< Any number of switches can be ON (e.g. check boxes) */ } ISRule; /* switch vector rule hint */ /** \typedef IPerm \brief Permission hint, with respect to client. */ typedef enum { IP_RO, /*!< Read Only */ IP_WO, /*!< Write Only */ IP_RW /*!< Read & Write */ } IPerm; /* permission hint, WRT client */ /* The XML strings for these attributes may be any length but implementations * are only obligued to support these lengths for the various string attributes. */ #define MAXINDINAME 64 #define MAXINDILABEL 64 #define MAXINDIDEVICE 64 #define MAXINDIGROUP 64 #define MAXINDIFORMAT 64 #define MAXINDIBLOBFMT 64 #define MAXINDITSTAMP 64 /******************************************************************************* * Typedefs for each INDI Property type. * * INumber.format may be any printf-style appropriate for double * or style "m" to create sexigesimal using the form "%.m" where * is the total field width. * is the width of the fraction. valid values are: * 9 -> :mm:ss.ss * 8 -> :mm:ss.s * 6 -> :mm:ss * 5 -> :mm.m * 3 -> :mm * * examples: * * to produce use * * "-123:45" %7.3m * " 0:01:02" %9.6m */ /** \struct IText \brief One text descriptor. */ typedef struct { /** index name */ char name[MAXINDINAME]; /** short description */ char label[MAXINDILABEL]; /** malloced text string */ char *text; /** pointer to parent */ struct _ITextVectorProperty *tvp; /** handy place to hang helper info */ void *aux0; /** handy place to hang helper info */ void *aux1; } IText; /** \struct _ITextVectorProperty \brief Text vector property descriptor. */ typedef struct _ITextVectorProperty { /** device name */ char device[MAXINDIDEVICE]; /** property name */ char name[MAXINDINAME]; /** short description */ char label[MAXINDILABEL]; /** GUI grouping hint */ char group[MAXINDIGROUP]; /** client accessibility hint */ IPerm p; /** current max time to change, secs */ double timeout; /** current property state */ IPState s; /** texts comprising this vector */ IText *tp; /** dimension of tp[] */ int ntp; /** ISO 8601 timestamp of this event */ char timestamp[MAXINDITSTAMP]; /** handy place to hang helper info */ void *aux; } ITextVectorProperty; /** \struct INumber \brief One number descriptor. */ typedef struct { char name[MAXINDINAME]; /** index name */ char label[MAXINDILABEL]; /** short description */ char format[MAXINDIFORMAT]; /** GUI display format, see above */ double min, max; /** range, ignore if min == max */ double step; /** step size, ignore if step == 0 */ double value; /** current value */ struct _INumberVectorProperty *nvp; /** pointer to parent */ void *aux0, *aux1; /** handy place to hang helper info */ } INumber; /** \struct _INumberVectorProperty \brief Number vector property descriptor. INumber.format may be any printf-style appropriate for double or style "m" to create sexigesimal using the form "%\.\m" where:\n \ is the total field width.\n \ is the width of the fraction. valid values are:\n 9 -> \:mm:ss.ss \n 8 -> \:mm:ss.s \n 6 -> \:mm:ss \n 5 -> \:mm.m \n 3 -> \:mm \n examples:\n To produce "-123:45", use \%7.3m \n To produce " 0:01:02", use \%9.6m */ typedef struct _INumberVectorProperty { /** device name */ char device[MAXINDIDEVICE]; /** property name */ char name[MAXINDINAME]; /** short description */ char label[MAXINDILABEL]; /** GUI grouping hint */ char group[MAXINDIGROUP]; /** client accessibility hint */ IPerm p; /** current max time to change, secs */ double timeout; /** current property state */ IPState s; /** numbers comprising this vector */ INumber *np; /** dimension of np[] */ int nnp; /** ISO 8601 timestamp of this event */ char timestamp[MAXINDITSTAMP]; /** handy place to hang helper info */ void *aux; } INumberVectorProperty; /** \struct ISwitch \brief One switch descriptor. */ typedef struct { char name[MAXINDINAME]; /** index name */ char label[MAXINDILABEL]; /** this switch's label */ ISState s; /** this switch's state */ struct _ISwitchVectorProperty *svp; /** pointer to parent */ void *aux; /** handy place to hang helper info */ } ISwitch; /** \struct _ISwitchVectorProperty \brief Switch vector property descriptor. */ typedef struct _ISwitchVectorProperty { /** device name */ char device[MAXINDIDEVICE]; /** property name */ char name[MAXINDINAME]; /** short description */ char label[MAXINDILABEL]; /** GUI grouping hint */ char group[MAXINDIGROUP]; /** client accessibility hint */ IPerm p; /** switch behavior hint */ ISRule r; /** current max time to change, secs */ double timeout; /** current property state */ IPState s; /** switches comprising this vector */ ISwitch *sp; /** dimension of sp[] */ int nsp; /** ISO 8601 timestamp of this event */ char timestamp[MAXINDITSTAMP]; /** handy place to hang helper info */ void *aux; } ISwitchVectorProperty; /** \struct ILight \brief One light descriptor. */ typedef struct { char name[MAXINDINAME]; /** index name */ char label[MAXINDILABEL]; /** this lights's label */ IPState s; /** this lights's state */ struct _ILightVectorProperty *lvp; /** pointer to parent */ void *aux; /** handy place to hang helper info */ } ILight; /** \struct _ILightVectorProperty \brief Light vector property descriptor. */ typedef struct _ILightVectorProperty { /** device name */ char device[MAXINDIDEVICE]; /** property name */ char name[MAXINDINAME]; /** short description */ char label[MAXINDILABEL]; /** GUI grouping hint */ char group[MAXINDIGROUP]; /** current property state */ IPState s; /** lights comprising this vector */ ILight *lp; /** dimension of lp[] */ int nlp; /** ISO 8601 timestamp of this event */ char timestamp[MAXINDITSTAMP]; /** handy place to hang helper info */ void *aux; } ILightVectorProperty; /** \struct IBLOB \brief One Blob (Binary Large Object) descriptor. */ typedef struct { /* one BLOB descriptor */ /** index name */ char name[MAXINDINAME]; /** this BLOB's label */ char label[MAXINDILABEL]; /** format attr */ char format[MAXINDIBLOBFMT]; /** malloced binary large object bytes */ void *blob; /** bytes in blob */ int bloblen; /** n uncompressed bytes */ int size; /** pointer to parent */ struct _IBLOBVectorProperty *bvp; /** handy place to hang helper info */ void *aux0, *aux1, *aux2; } IBLOB; /** \struct _IBLOBVectorProperty \brief BLOB (Binary Large Object) vector property descriptor. */ typedef struct _IBLOBVectorProperty { /* BLOB vector property descriptor */ /** device name */ char device[MAXINDIDEVICE]; /** property name */ char name[MAXINDINAME]; /** short description */ char label[MAXINDILABEL]; /** GUI grouping hint */ char group[MAXINDIGROUP]; /** client accessibility hint */ IPerm p; /** current max time to change, secs */ double timeout; /** current property state */ IPState s; /** BLOBs comprising this vector */ IBLOB *bp; /** dimension of bp[] */ int nbp; /** ISO 8601 timestamp of this event */ char timestamp[MAXINDITSTAMP]; /** handy place to hang helper info */ void *aux; } IBLOBVectorProperty; /** \brief Handy macro to find the number of elements in array a[]. Must be used with actual array, not pointer. */ #define NARRAY(a) (sizeof(a)/sizeof(a[0])) #endif libindi-0.9.7/Doxyfile0000644000175000017500000002570412241463551013642 0ustar jasemjasem# Doxyfile 1.7.1 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "Instrument Neutral Distributed Interface INDI" PROJECT_NUMBER = 0.9.7 OUTPUT_DIRECTORY = /home/jasem/Projects/doc CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES TYPEDEF_HIDES_STRUCT = NO SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = /home/jasem/Projects/indi/trunk/libindi INPUT_ENCODING = UTF-8 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.C \ *.H \ *.tlh \ *.diff \ *.patch \ *.moc \ *.xpm \ *.dox RECURSIVE = YES EXCLUDE = /home/jasem/Projects/indi/trunk/libindi/drivers \ /home/jasem/Projects/indi/trunk/libindi/tools \ /home/jasem/Projects/indi/trunk/libindi/libs/webcam \ /home/jasem/Projects/indi/trunk/libindi/libs/base64.c \ /home/jasem/Projects/indi/trunk/libindi/libs/fq.c \ /home/jasem/Projects/indi/trunk/libindi/indidrivermain.c \ /home/jasem/Projects/indi/trunk/libindi/indiserver.c EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = /home/jasem/Projects/indi/trunk/libindi/examples EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = YES IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = YES INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = doc HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES HTML_ALIGN_MEMBERS = YES HTML_DYNAMIC_SECTIONS = NO GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO USE_INLINE_TREES = NO TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES SEARCHENGINE = NO SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = FreeSans.ttf DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES libindi-0.9.7/libindi.pc.cmake0000644000175000017500000000051412241463551015141 0ustar jasemjasemprefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=@LIB_DESTINATION@ includedir=@INCLUDE_INSTALL_DIR@ Name: libindi Description: Instrument Neutral Distributed Interface URL: http://www.indilib.org/ Version: @CMAKE_INDI_VERSION_STRING@ Libs: -L${libdir} -lindi Cflags: -I${includedir} -I${includedir}/libindi libindi-0.9.7/indidriver.h0000644000175000017500000001773412241463551014450 0ustar jasemjasem#if 0 INDI Copyright (C) 2003-2006 Elwood C. Downey Updated by Jasem Mutlaq (2003-2010) 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 #ifndef INDIDRIVER_H #define INDIDRIVER_H #ifdef __cplusplus extern "C" { #endif /* insure RO properties are never modified. RO Sanity Check */ typedef struct { char propName[MAXINDINAME]; IPerm perm; } ROSC; extern ROSC *roCheck; extern int nroCheck; /* # of elements in roCheck */ extern int verbose; /* chatty */ extern char *me; /* a.out name */ extern LilXML *clixml; /* XML parser context */ extern int dispatch (XMLEle *root, char msg[]); extern void clientMsgCB(int fd, void *arg); /** * \defgroup configFunctions Configuration Functions: Functions drivers call to save and load configuraion options.

Drivers can save properties states and values in an XML configuration file. The following functions take an optional filename parameter which specifies the full path of the configuration file. If the filename is set to NULL, the configuration file is locally stored in ~/.indi. By default, two configuration files may exist for each driver:

  • Last Saved Configuration: ~/.indi/driver_name_config.xml
  • Default Configuration: ~/.indi/driver_name_config.xml.default

libindi stores the configuration parameters enclosed in newXXX commands. Therefore, if a configuration file is loaded, the driver property gets updated as if a client is setting these values. This is important to note since some configuration options may only available when the device is powered up or is in a particular state.

If no filename is supplied, each function will try to create the configuration files in the following order:

  1. INDICONFIG environment variable: The functions checks if the envrionment variable is defined, and if so, it shall be used as the configuration filename
  2. Generate filename: If the device_name is supplied, the function will attempt to set the configuration filename to ~/.indi/device_name_config.xml
\author Jasem Mutlaq \note Drivers subclassing INDI::DefaultDevice do not need to call the configuration functions directly as it is handled internally by the class. \version libindi 0.7+ */ /*@{*/ /** \brief Open a configuration file for writing and return a configuration file FILE pointer. \param filename full path of the configuration file. If set, the function will attempt to open it for writing. If set to NULL, it will attempt to generate the filename as described in the Detailed Description introduction and then open it for writing. \param dev device name. This is used if the filename parameter is NULL, and INDICONFIG environment variable is not set as described in the Detailed Description introduction. \param errmsg In case of errors, store the error message in this buffer. The size of the buffer must be at least MAXRBUF. \return pointer to FILE if configuration file is opened successful, otherwise NULL and errmsg is set. */ extern FILE * IUGetConfigFP(const char *filename, const char *dev, char errmsg[]); /** \brief Loads and processes a configuration file. Once a configuration file is successful loaded, the function will iterate over the enclosed newXXX commands, and dispatches each command to the driver. Subsequently, the driver receives the updated property value in the driver's ISNewXXX functions. The driver may call this function at any time. However, it is usually called either on driver startup or on device power up. \param filename full path of the configuration file. If set, the function will attempt to load the file. If set to NULL, it will attempt to generate the filename as described in the Detailed Description introduction and then load it. \param dev device name. This is used if the filename parameter is NULL, and INDICONFIG environment variable is not set as described in the Detailed Description introduction. \param errmsg In case of errors, store the error message in this buffer. The size of the buffer must be at least MAXRBUF. \return 0 on successful, -1 if there is an error and errmsg is set. */ extern int IUReadConfig(const char *filename, const char *dev, char errmsg[]); /** \brief Copies an existing configuration file into a default configuration file. If no default configuration file for the supplied dev exists, it gets created and its contentes copied from an exiting source configuration file. Usually, when the user saves the configuration file of a driver for the first time, IUSaveDefaultConfig is called to create the default configuration file. If the default configuration file already exists, the function performs no action and returns. \param source_config full path of the source configuration file to read. If set, the function will attempt to load the file. If set to NULL, it will attempt to generate the filename as described in the Detailed Description introduction and then load it. \param dest_config full path of the destination default configuration file to write. If set, the function will attempt to load the file. If set to NULL, it will attempt to generate the filename as described in the Detailed Description introduction and then load it. If the file already exists, the function returns. If the file doesn't exist, it gets created and its contents copied from the source_config file. \param dev device name. This is used if either the source_config or desg_config are NULL, and INDICONFIG environment variable is not set as described in the Detailed Description introduction. */ extern void IUSaveDefaultConfig(const char *source_config, const char *dest_config, const char *dev); /** \brief Add opening or closing tag to a configuration file. A configuration file root XML element is @@. This functions add @@ or @@ as required. \param fp file pointer to a configuration file. \param ctag If 0, @@ is appened to the configuration file, otherwise @@ is appeneded and the fp is closed. */ extern void IUSaveConfigTag(FILE *fp, int ctag); /** \brief Add a number vector property value to the configuration file \param fp file pointer to a configuration file. \param nvp pointer to a number vector property. */ extern void IUSaveConfigNumber (FILE *fp, const INumberVectorProperty *nvp); /** \brief Add a text vector property value to the configuration file \param fp file pointer to a configuration file. \param tvp pointer to a text vector property. */ extern void IUSaveConfigText (FILE *fp, const ITextVectorProperty *tvp); /** \brief Add a switch vector property value to the configuration file \param fp file pointer to a configuration file. \param svp pointer to a switch vector property. */ extern void IUSaveConfigSwitch (FILE *fp, const ISwitchVectorProperty *svp); /** \brief Add a BLOB vector property value to the configuration file \param fp file pointer to a configuration file. \param bvp pointer to a BLOB vector property. \note If the BLOB size is large, this function will block until the BLOB contents are written to the file. */ extern void IUSaveConfigBLOB (FILE *fp, const IBLOBVectorProperty *bvp); /*@}*/ #ifdef __cplusplus } #endif #endif libindi-0.9.7/config.h.cmake0000644000175000017500000000074612241463551014630 0ustar jasemjasem/* Define to 1 if you have the header file. */ #cmakedefine HAVE_LINUX_VIDEODEV2_H 1 /* The symbol timezone is an int, not a function */ #define TIMEZONE_IS_INT 1 /* Define if you have termios.h */ #cmakedefine HAVE_TERMIOS_H 1 /* Define if you have fitsio.h */ #cmakedefine HAVE_CFITSIO_H 1 /* Define if you have libnova.h */ #cmakedefine HAVE_NOVA_H 1 /* Set INDI Library version */ #cmakedefine CMAKE_INDI_VERSION_STRING "@CMAKE_INDI_VERSION_STRING@" libindi-0.9.7/README0000644000175000017500000001023112241463551013001 0ustar jasemjasemlibindi v0.9 ============ The code here demonstrates the use of INDI, an Instrument-Neutral Device Interface protocol. See http://www.clearskyinstitute.com/INDI/INDI.pdf. Architecture: Typical INDI Client / Server / Driver / Device connectivity: INDI Client 1 ----| |---- INDI Driver A ---- Dev X | | INDI Client 2 ----| |---- INDI Driver B ---- Dev Y | | | ... |--- indiserver ---| |-- Dev Z | | | | INDI Client n ----| |---- INDI Driver C ---- Dev T Client INET Server UNIX Driver Hardware processes sockets process pipes processes devices Indiserver is the public network access point where one or more INDI Clients may contact one or more INDI Drivers. Indiserver launches each driver process and arranges for it to receive the INDI protocol from Clients on its stdin and expects to find commands destined for Clients on the driver's stdout. Anything arriving from a driver process' stderr is copied to indiserver's stderr. Indiserver only provides convenient port, fork and data steering services. If desired, a Client may run and connect to INDI Drivers directly. Construction: An INDI driver typically consists of one .c file, eg, mydriver.c, which #includes indiapi.h to access the reference API declarations. It is compiled then linked with indidrivermain.o, eventloop.o and liblilxml.a to form an INDI process. These supporting files contain the implementation of the INDI Driver API and need not be changed in any way. Note that evenloop.[ch] provide a nice callback facility independent of INDI which may be used in other projects if desired. The driver implementation, again in our example mydriver.c, does not contain a main() but is expected to operate as an event-driver program. The driver must implement each ISxxx() function but never call them. The IS() functions are called by the reference implementation main() as messages arrive from Clients. Within each IS function the driver performs the desired tasks then may report back to the Client by calling the IDxxx() functions. The reference API provides IE() functions to allow the driver to add its own callback functions if desired. The driver can arrange for functions to be called when reading a file descriptor will not block; when a time interval has expired; or when there is no other client traffic in progress. The sample indiserver is a stand alone process that may be used to run one or more INDI-compliant drivers. It takes the names of each driver process to run in its command line args. To build indiserver type 'make indiserver'; to build all the sample drivers type 'make drivers'; to run the sample server with all drivers type 'make run'. Killing indiserver will also kill all the drivers it started. Secure remote operation: Suppose we want to run indiserver and its clients on a remote machine, r, and connect them to our favorite INDI client, XEphem, running on the local machine. From the local machine log onto the remote machine, r, by typing: ssh2 -L 7624:s:7624 r after logging in, run indiserver on the remote machine: make run Back on the local machine, start XEphem, then open Views -> Sky View -> Telescope -> INDI panel. XEphem will connect to the remote INDI server securely and automatically begin running. Sweet. Testing: A low-level way to test the socket, forking and data steering abilities of indiserver is to use the 'hose' command from the netpipes collection (http://web.purplefrog.com/~thoth/netpipes/netpipes.html): 1. start indiserver using UNIX' cat program as the only INDI "device": % indiserver cat & 2. use hose to connect to the "cat" device driver which just copies back: % hose localhost 7624 --slave hello world hello world more stuff more stuff libindi-0.9.7/cmake_modules/0000755000175000017500000000000012241463551014734 5ustar jasemjasemlibindi-0.9.7/cmake_modules/FindSBIG.cmake0000644000175000017500000000236612241463551017272 0ustar jasemjasem# - Try to find SBIG (Santa Barbara Instruments Group Library for CCDs & Filter Wheels). # Once done this will define # # SBIG_FOUND - system has SBIG # SBIG_LIBRARIES - Link these to use SBIG # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (SBIG_LIBRARIES) # in cache already set(SBIG_FOUND TRUE) message(STATUS "Found SBIG: ${SBIG_LIBRARIES}") else (SBIG_LIBRARIES) find_library(SBIG_LIBRARIES NAMES sbigudrv PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_LIBRARIES ${SBIG_LIBRARIES}) if(SBIG_LIBRARIES) set(SBIG_FOUND TRUE) else (SBIG_LIBRARIES) set(SBIG_FOUND FALSE) endif(SBIG_LIBRARIES) if (SBIG_FOUND) if (NOT SBIG_FIND_QUIETLY) message(STATUS "Found SBIG: ${SBIG_LIBRARIES}") endif (NOT SBIG_FIND_QUIETLY) else (SBIG_FOUND) if (SBIG_FIND_REQUIRED) message(FATAL_ERROR "SBIG not found. Please install SBIG library. http://indi.sf.net") endif (SBIG_FIND_REQUIRED) endif (SBIG_FOUND) mark_as_advanced(SBIG_LIBRARIES) endif (SBIG_LIBRARIES) libindi-0.9.7/cmake_modules/FindALUT.cmake0000644000175000017500000000504212241463551017305 0ustar jasemjasem# - Locate ALUT # This module defines # ALUT_LIBRARY # ALUT_FOUND, if false, do not try to link to OpenAL # ALUT_INCLUDE_DIR, where to find the headers # # $OPENALDIR is an environment variable that would # correspond to the ./configure --prefix=$OPENALDIR # used in building OpenAL. # # Created by Bryan Donlan, based on the FindOpenAL.cmake module by Eric Wang. FIND_PATH(ALUT_INCLUDE_DIR alut.h $ENV{OPENALDIR}/include ~/Library/Frameworks/OpenAL.framework/Headers /Library/Frameworks/OpenAL.framework/Headers /System/Library/Frameworks/OpenAL.framework/Headers # Tiger /usr/local/include/AL /usr/local/include/OpenAL /usr/local/include /usr/include/AL /usr/include/OpenAL /usr/include /sw/include/AL # Fink /sw/include/OpenAL /sw/include /opt/local/include/AL # DarwinPorts /opt/local/include/OpenAL /opt/local/include /opt/csw/include/AL # Blastwave /opt/csw/include/OpenAL /opt/csw/include /opt/include/AL /opt/include/OpenAL /opt/include ) # I'm not sure if I should do a special casing for Apple. It is # unlikely that other Unix systems will find the framework path. # But if they do ([Next|Open|GNU]Step?), # do they want the -framework option also? IF(${ALUT_INCLUDE_DIR} MATCHES ".framework") STRING(REGEX REPLACE "(.*)/.*\\.framework/.*" "\\1" ALUT_FRAMEWORK_PATH_TMP ${ALUT_INCLUDE_DIR}) IF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" ) # String is in default search path, don't need to use -F SET (ALUT_LIBRARY "-framework OpenAL" CACHE STRING "OpenAL framework for OSX") ELSE("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" ) # String is not /Library/Frameworks, need to use -F SET(ALUT_LIBRARY "-F${ALUT_FRAMEWORK_PATH_TMP} -framework OpenAL" CACHE STRING "OpenAL framework for OSX") ENDIF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" ) # Clear the temp variable so nobody can see it SET(ALUT_FRAMEWORK_PATH_TMP "" CACHE INTERNAL "") ELSE(${ALUT_INCLUDE_DIR} MATCHES ".framework") FIND_LIBRARY(ALUT_LIBRARY NAMES alut PATHS $ENV{OPENALDIR}/lib $ENV{OPENALDIR}/libs /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib ) ENDIF(${ALUT_INCLUDE_DIR} MATCHES ".framework") SET(ALUT_FOUND "NO") IF(ALUT_LIBRARY) SET(ALUT_FOUND "YES") ENDIF(ALUT_LIBRARY) libindi-0.9.7/cmake_modules/MacroOptionalFindPackage.cmake0000644000175000017500000000205212241463551022561 0ustar jasemjasem# - MACRO_OPTIONAL_FIND_PACKAGE() combines FIND_PACKAGE() with an OPTION() # MACRO_OPTIONAL_FIND_PACKAGE( [QUIT] ) # This macro is a combination of OPTION() and FIND_PACKAGE(), it # works like FIND_PACKAGE(), but additionally it automatically creates # an option name WITH_, which can be disabled via the cmake GUI. # or via -DWITH_=OFF # The standard _FOUND variables can be used in the same way # as when using the normal FIND_PACKAGE() # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO (MACRO_OPTIONAL_FIND_PACKAGE _name ) OPTION(WITH_${_name} "Search for ${_name} package" ON) if (WITH_${_name}) FIND_PACKAGE(${_name} ${ARGN}) else (WITH_${_name}) set(${_name}_FOUND) set(${_name}_INCLUDE_DIR) set(${_name}_INCLUDES) set(${_name}_LIBRARY) set(${_name}_LIBRARIES) endif (WITH_${_name}) ENDMACRO (MACRO_OPTIONAL_FIND_PACKAGE) libindi-0.9.7/cmake_modules/FindAPOGEE.cmake0000644000175000017500000000367412241463551017511 0ustar jasemjasem# - Try to find Apogee Instruments Library # Once done this will define # # APOGEE_FOUND - system has APOGEE # APOGEE_INCLUDE_DIR - the APOGEE include directory # APOGEE_LIBRARIES - Link these to use APOGEE # Copyright (c) 2008, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) # in cache already set(APOGEE_FOUND TRUE) message(STATUS "Found libapogee: ${APOGEEU_LIBRARIES}, ${APOGEEE_LIBRARIES}") else (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) find_path(APOGEE_INCLUDE_DIR libapogee.h PATH_SUFFIXES libapogee ${_obIncDir} ${GNUWIN32_DIR}/include ) # Find Apogee Alta-U Library find_library(APOGEEU_LIBRARIES NAMES apogeeu PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) # Find Apogee Alta-U Library find_library(APOGEEE_LIBRARIES NAMES apogeee PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) set(APOGEE_FOUND TRUE) else (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) set(APOGEE_FOUND FALSE) endif(APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) if (APOGEE_FOUND) if (NOT APOGEE_FIND_QUIETLY) message(STATUS "Found APOGEE: ${APOGEEU_LIBRARIES}, ${APOGEEE_LIBRARIES}") endif (NOT APOGEE_FIND_QUIETLY) else (APOGEE_FOUND) if (APOGEE_FIND_REQUIRED) message(FATAL_ERROR "libapogee not found. Cannot compile Apogee CCD Driver. Please install libapogee and try again. http://www.indilib.org") endif (APOGEE_FIND_REQUIRED) endif (APOGEE_FOUND) mark_as_advanced(APOGEE_INCLUDE_DIR APOGEEU_LIBRARIES APOGEEE_LIBRARIES) endif (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) libindi-0.9.7/cmake_modules/FindNova.cmake0000644000175000017500000000303312241463551017441 0ustar jasemjasem# - Try to find NOVA # Once done this will define # # NOVA_FOUND - system has NOVA # NOVA_INCLUDE_DIR - the NOVA include directory # NOVA_LIBRARIES - Link these to use NOVA # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) # in cache already set(NOVA_FOUND TRUE) message(STATUS "Found libnova: ${NOVA_LIBRARIES}") else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) find_path(NOVA_INCLUDE_DIR libnova.h PATH_SUFFIXES libnova ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(NOVA_LIBRARIES NAMES nova PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_INCLUDES ${NOVA_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${NOVA_LIBRARIES}) if(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) set(NOVA_FOUND TRUE) else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) set(NOVA_FOUND FALSE) endif(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) if (NOVA_FOUND) if (NOT Nova_FIND_QUIETLY) message(STATUS "Found NOVA: ${NOVA_LIBRARIES}") endif (NOT Nova_FIND_QUIETLY) else (NOVA_FOUND) if (Nova_FIND_REQUIRED) message(FATAL_ERROR "libnova not found. Please install libnova0-devel. http://indi.sf.net") endif (Nova_FIND_REQUIRED) endif (NOVA_FOUND) mark_as_advanced(NOVA_INCLUDE_DIR NOVA_LIBRARIES) endif (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) libindi-0.9.7/cmake_modules/FindUSB.cmake0000644000175000017500000000174712241463551017201 0ustar jasemjasem# - Try to find the USB library # Once done this defines # # LIBUSB_FOUND - system has libusb # LIBUSB_INCLUDE_DIR - the libusb include directory # LIBUSB_LIBRARIES - Link these to use libusb # Copyright (c) 2006, 2008 Laurent Montel, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (NOT WIN32) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls find_package(PkgConfig) pkg_check_modules(PC_LIBUSB QUIET libusb) endif(NOT WIN32) find_path(LIBUSB_INCLUDE_DIR usb.h HINTS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}) find_library(LIBUSB_LIBRARIES NAMES usb HINTS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) libindi-0.9.7/cmake_modules/MacroLogFeature.cmake0000644000175000017500000001157712241463551020770 0ustar jasemjasem# This file defines the Feature Logging macros. # # MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]]) # Logs the information so that it can be displayed at the end # of the configure run # VAR : TRUE or FALSE, indicating whether the feature is supported # FEATURE: name of the feature, e.g. "libjpeg" # DESCRIPTION: description what this feature provides # URL: home page # REQUIRED: TRUE or FALSE, indicating whether the featue is required # MIN_VERSION: minimum version number. empty string if unneeded # COMMENTS: More info you may want to provide. empty string if unnecessary # # MACRO_DISPLAY_FEATURE_LOG() # Call this to display the collected results. # Exits CMake with a FATAL error message if a required feature is missing # # Example: # # INCLUDE(MacroLogFeature) # # FIND_PACKAGE(JPEG) # MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "") # ... # MACRO_DISPLAY_FEATURE_LOG() # Copyright (c) 2006, Alexander Neundorf, # Copyright (c) 2006, Allen Winter, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF (NOT _macroLogFeatureAlreadyIncluded) SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_macroLogFeatureAlreadyIncluded TRUE) ENDIF (NOT _macroLogFeatureAlreadyIncluded) MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments) SET(_required "${ARGV4}") SET(_minvers "${ARGV5}") SET(_comments "${ARGV6}") IF (${_var}) SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) ELSE (${_var}) IF (${_required} MATCHES "[Tt][Rr][Uu][Ee]") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt) ELSE (${_required} MATCHES "[Tt][Rr][Uu][Ee]") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) ENDIF (${_required} MATCHES "[Tt][Rr][Uu][Ee]") ENDIF (${_var}) SET(_logtext "+ ${_package}") IF (NOT ${_var}) IF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext}, ${_minvers}") ENDIF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext}: ${_description} <${_url}>") IF (${_comments} MATCHES ".*") SET(_logtext "${_logtext}\n${_comments}") ENDIF (${_comments} MATCHES ".*") # SET(_logtext "${_logtext}\n") #double-space missing features? ENDIF (NOT ${_var}) FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n") ENDMACRO(MACRO_LOG_FEATURE) MACRO(MACRO_DISPLAY_FEATURE_LOG) SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) IF (EXISTS ${_file}) FILE(READ ${_file} _requirements) MESSAGE(STATUS "\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- Please install them before continuing this software installation.\n-----------------------------------------------------------------------------\n${_requirements}-----------------------------------------------------------------------------") FILE(REMOVE ${_file}) MESSAGE(FATAL_ERROR "Exiting: Missing Requirements") ENDIF (EXISTS ${_file}) SET(_summary "\n") SET(_elist 0) SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) IF (EXISTS ${_file}) SET(_elist 1) FILE(READ ${_file} _enabled) FILE(REMOVE ${_file}) SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n${_enabled}") ENDIF (EXISTS ${_file}) SET(_dlist 0) SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_file}) SET(_dlist 1) FILE(READ ${_file} _disabled) FILE(REMOVE ${_file}) SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n${_disabled}") ELSE (EXISTS ${_file}) IF (${_elist}) SET(_summary "${_summary}Congratulations! All external packages have been found.\n") ENDIF (${_elist}) ENDIF (EXISTS ${_file}) IF (${_elist} OR ${_dlist}) SET(_summary "${_summary}-----------------------------------------------------------------------------\n") ENDIF (${_elist} OR ${_dlist}) MESSAGE(STATUS "${_summary}") ENDMACRO(MACRO_DISPLAY_FEATURE_LOG) libindi-0.9.7/cmake_modules/FindFLI.cmake0000644000175000017500000000264512241463551017160 0ustar jasemjasem# - Try to find Finger Lakes Instruments Library # Once done this will define # # FLI_FOUND - system has FLI # FLI_INCLUDE_DIR - the FLI include directory # FLI_LIBRARIES - Link these to use FLI # Copyright (c) 2008, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (FLI_INCLUDE_DIR AND FLI_LIBRARIES) # in cache already set(FLI_FOUND TRUE) message(STATUS "Found libfli: ${FLI_LIBRARIES}") else (FLI_INCLUDE_DIR AND FLI_LIBRARIES) find_path(FLI_INCLUDE_DIR libfli.h PATH_SUFFIXES fli ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(FLI_LIBRARIES NAMES fli PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(FLI_INCLUDE_DIR AND FLI_LIBRARIES) set(FLI_FOUND TRUE) else (FLI_INCLUDE_DIR AND FLI_LIBRARIES) set(FLI_FOUND FALSE) endif(FLI_INCLUDE_DIR AND FLI_LIBRARIES) if (FLI_FOUND) if (NOT FLI_FIND_QUIETLY) message(STATUS "Found FLI: ${FLI_LIBRARIES}") endif (NOT FLI_FIND_QUIETLY) else (FLI_FOUND) if (FLI_FIND_REQUIRED) message(FATAL_ERROR "FLI not found. Please install libfli-dev. http://www.indilib.org") endif (FLI_FIND_REQUIRED) endif (FLI_FOUND) mark_as_advanced(FLI_INCLUDE_DIR FLI_LIBRARIES) endif (FLI_INCLUDE_DIR AND FLI_LIBRARIES) libindi-0.9.7/cmake_modules/FindCFITSIO.cmake0000644000175000017500000000440512241463551017642 0ustar jasemjasem# - Try to find CFITSIO # Once done this will define # # CFITSIO_FOUND - system has CFITSIO # CFITSIO_INCLUDE_DIR - the CFITSIO include directory # CFITSIO_LIBRARIES - Link these to use CFITSIO # CFITSIO_VERSION_STRING - Human readable version number of cfitsio # CFITSIO_VERSION_MAJOR - Major version number of cfitsio # CFITSIO_VERSION_MINOR - Minor version number of cfitsio # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) # in cache already set(CFITSIO_FOUND TRUE) message(STATUS "Found CFITSIO: ${CFITSIO_LIBRARIES}") else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) # JM: Packages from different distributions have different suffixes find_path(CFITSIO_INCLUDE_DIR fitsio.h PATH_SUFFIXES libcfitsio3 libcfitsio0 cfitsio ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(CFITSIO_LIBRARIES NAMES cfitsio PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) set(CFITSIO_FOUND TRUE) else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) set(CFITSIO_FOUND FALSE) endif(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) if (CFITSIO_FOUND) # Find the version of the cfitsio header execute_process(COMMAND egrep CFITSIO_VERSION ${CFITSIO_INCLUDE_DIR}/fitsio.h OUTPUT_VARIABLE CFITSIO_VERSION_STRING) STRING(REGEX REPLACE "[^0-9.]" "" CFITSIO_VERSION_STRING ${CFITSIO_VERSION_STRING}) STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\1" CFITSIO_VERSION_MAJOR ${CFITSIO_VERSION_STRING}) STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\2" CFITSIO_VERSION_MINOR ${CFITSIO_VERSION_STRING}) if (NOT CFITSIO_FIND_QUIETLY) message(STATUS "Found CFITSIO ${CFITSIO_VERSION_STRING}: ${CFITSIO_LIBRARIES}") endif (NOT CFITSIO_FIND_QUIETLY) else (CFITSIO_FOUND) if (CFITSIO_FIND_REQUIRED) message(STATUS "CFITSIO not found.") endif (CFITSIO_FIND_REQUIRED) endif (CFITSIO_FOUND) mark_as_advanced(CFITSIO_INCLUDE_DIR CFITSIO_LIBRARIES) endif (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) libindi-0.9.7/cmake_modules/MacroBoolTo01.cmake0000644000175000017500000000121312241463551020254 0ustar jasemjasem# MACRO_BOOL_TO_01( VAR RESULT0 ... RESULTN ) # This macro evaluates its first argument # and sets all the given vaiables either to 0 or 1 # depending on the value of the first one # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO(MACRO_BOOL_TO_01 FOUND_VAR ) FOREACH (_current_VAR ${ARGN}) IF(${FOUND_VAR}) SET(${_current_VAR} 1) ELSE(${FOUND_VAR}) SET(${_current_VAR} 0) ENDIF(${FOUND_VAR}) ENDFOREACH(_current_VAR) ENDMACRO(MACRO_BOOL_TO_01) libindi-0.9.7/cmake_modules/FindINDI.cmake0000644000175000017500000000474412241463551017273 0ustar jasemjasem# - Try to find INDI # Once done this will define # # INDI_FOUND - system has INDI # INDI_INCLUDE_DIR - the INDI include directory # INDI_LIBRARIES - Link these to use INDI # INDI_MAIN_LIBRARIES - Link to these to build INDI drivers with main() # INDI_DRIVER_LIBRARIES - Link to these to build INDI drivers with indibase support # INDI_CLIENT_LIBRARIES - Link to these to build INDI clients # INDI_DATA_DIR - INDI shared data dir. # Copyright (c) 2011, Jasem Mutlaq # Copyright (c) 2012, Pino Toscano # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) # in cache already set(INDI_FOUND TRUE) message(STATUS "Found INDI: ${INDI_LIBRARIES}") else (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) find_package(PkgConfig) if (PKG_CONFIG_FOUND) if (INDI_FIND_VERSION) set(version_string ">=${INDI_FIND_VERSION}") endif() pkg_check_modules(PC_INDI libindi${version_string}) else() # assume it was found set(PC_INDI_FOUND TRUE) endif() if (PC_INDI_FOUND) find_path(INDI_INCLUDE_DIR indidevapi.h PATH_SUFFIXES libindi HINTS ${PC_INDI_INCLUDE_DIRS} ) find_library(INDI_LIBRARIES NAMES indi HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_DRIVER_LIBRARIES NAMES indidriver HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_MAIN_LIBRARIES NAMES indimain HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_CLIENT_LIBRARIES NAMES indiclient HINTS ${PC_INDI_LIBRARY_DIRS} ) find_path(INDI_DATA_DIR drivers.xml PATH_SUFFIXES share/indi ) set(INDI_VERSION "${PC_INDI_VERSION}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(INDI REQUIRED_VARS INDI_INCLUDE_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES VERSION_VAR INDI_VERSION ) mark_as_advanced(INDI_INCLUDE_DIR INDI_DATA_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES) endif (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) libindi-0.9.7/cmake_modules/FindQSI.cmake0000644000175000017500000000245512241463551017201 0ustar jasemjasem# - Try to find Quantum Scientific Imaging Library # Once done this will define # # QSI_FOUND - system has QSI # QSI_INCLUDE_DIR - the QSI include directory # QSI_LIBRARIES - Link these to use QSI # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (QSI_INCLUDE_DIR AND QSI_LIBRARIES) # in cache already set(QSI_FOUND TRUE) message(STATUS "Found libqsiapi: ${QSI_LIBRARIES}") else (QSI_INCLUDE_DIR AND QSI_LIBRARIES) find_path(QSI_INCLUDE_DIR qsiapi.h PATH_SUFFIXES qsiapi ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(QSI_LIBRARIES NAMES qsiapi PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(QSI_INCLUDE_DIR AND QSI_LIBRARIES) set(QSI_FOUND TRUE) else (QSI_INCLUDE_DIR AND QSI_LIBRARIES) set(QSI_FOUND FALSE) endif(QSI_INCLUDE_DIR AND QSI_LIBRARIES) if (QSI_FOUND) if (NOT QSI_FIND_QUIETLY) message(STATUS "Found QSI: ${QSI_LIBRARIES}") endif (NOT QSI_FIND_QUIETLY) else (QSI_FOUND) if (QSI_FIND_REQUIRED) message(FATAL_ERROR "QSI not found. Please install libqsi http://www.indilib.org") endif (QSI_FIND_REQUIRED) endif (QSI_FOUND) mark_as_advanced(QSI_INCLUDE_DIR QSI_LIBRARIES) endif (QSI_INCLUDE_DIR AND QSI_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/0000755000175000017500000000000012241463551015620 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/0000755000175000017500000000000012241463551017455 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/8d/0000755000175000017500000000000012241463551017770 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/8d/8d61d234c6b0af0e49b879a117e98bf520e646f8.svn-base0000644000175000017500000000121312241463551027024 0ustar jasemjasem# MACRO_BOOL_TO_01( VAR RESULT0 ... RESULTN ) # This macro evaluates its first argument # and sets all the given vaiables either to 0 or 1 # depending on the value of the first one # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO(MACRO_BOOL_TO_01 FOUND_VAR ) FOREACH (_current_VAR ${ARGN}) IF(${FOUND_VAR}) SET(${_current_VAR} 1) ELSE(${FOUND_VAR}) SET(${_current_VAR} 0) ENDIF(${FOUND_VAR}) ENDFOREACH(_current_VAR) ENDMACRO(MACRO_BOOL_TO_01) libindi-0.9.7/cmake_modules/.svn/pristine/a5/0000755000175000017500000000000012241463551017762 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/a5/a59f5398e9cbfe4cb78ed21bd94732b0b1ccbfb7.svn-base0000644000175000017500000000240212241463551027452 0ustar jasemjasem# - Try to find FTDI # Once done this will define # # FTDI_FOUND - system has FTDI # FTDI_INCLUDE_DIR - the FTDI include directory # FTDI_LIBRARIES - Link these to use FTDI # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) # in cache already set(FTDI_FOUND TRUE) message(STATUS "Found libftdi: ${FTDI_LIBRARIES}") else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) find_path(FTDI_INCLUDE_DIR ftdi.h ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(FTDI_LIBRARIES NAMES ftdi PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) set(FTDI_FOUND TRUE) else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) set(FTDI_FOUND FALSE) endif(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) if (FTDI_FOUND) if (NOT FTDI_FIND_QUIETLY) message(STATUS "Found FTDI: ${FTDI_LIBRARIES}") endif (NOT FTDI_FIND_QUIETLY) else (FTDI_FOUND) if (FTDI_FIND_REQUIRED) message(FATAL_ERROR "FTDI not found. Please install libftdi-dev") endif (FTDI_FIND_REQUIRED) endif (FTDI_FOUND) mark_as_advanced(FTDI_INCLUDE_DIR FTDI_LIBRARIES) endif (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/4d/0000755000175000017500000000000012241463551017764 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/4d/4ddf9e65ea9cf819925428199ce93e8ed441fc74.svn-base0000644000175000017500000000754112241463551027147 0ustar jasemjasem# - Try to find libusb-1.0 # Once done this will define # # LIBUSB_1_FOUND - system has libusb # LIBUSB_1_INCLUDE_DIRS - the libusb include directory # LIBUSB_1_LIBRARIES - Link these to use libusb # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb # # Adapted from cmake-modules Google Code project # # Copyright (c) 2006 Andreas Schneider # # (Changes for libusb) Copyright (c) 2008 Kyle Machulis # # Redistribution and use is allowed according to the terms of the New BSD license. # # CMake-Modules Project New BSD License # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of the CMake-Modules Project nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) # in cache already set(LIBUSB_FOUND TRUE) else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) find_path(LIBUSB_1_INCLUDE_DIR NAMES libusb.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include PATH_SUFFIXES libusb-1.0 ) find_library(LIBUSB_1_LIBRARY NAMES usb-1.0 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR} ) set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY} ) if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) set(LIBUSB_1_FOUND TRUE) endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) if (LIBUSB_1_FOUND) if (NOT USB-1_FIND_QUIETLY) message(STATUS "Found libusb-1.0:") message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") endif (NOT USB-1_FIND_QUIETLY) set(CMAKE_REQUIRED_INCLUDES ${LIBUSB_1_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${LIBUSB_1_LIBRARIES}) include (CheckCXXSourceCompiles) check_cxx_source_compiles("#include int main() { libusb_error_name(0); return 0; }" ERROR_NAME_COMPILE) if (NOT ERROR_NAME_COMPILE) add_definitions("-DNO_ERROR_NAME") message(STATUS " - 1.0.8 or older") endif (NOT ERROR_NAME_COMPILE) else (LIBUSB_1_FOUND) if (USB-1_FIND_REQUIRED) message(FATAL_ERROR "Could not find libusb-1.0. Please install libusb-1.0 along with the development package.") endif (USB-1_FIND_REQUIRED) endif (LIBUSB_1_FOUND) # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) libindi-0.9.7/cmake_modules/.svn/pristine/81/0000755000175000017500000000000012241463551017705 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/81/813425deb369dbc58825058ac44bdf9bc81fe133.svn-base0000644000175000017500000000303312241463551027012 0ustar jasemjasem# - Try to find NOVA # Once done this will define # # NOVA_FOUND - system has NOVA # NOVA_INCLUDE_DIR - the NOVA include directory # NOVA_LIBRARIES - Link these to use NOVA # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) # in cache already set(NOVA_FOUND TRUE) message(STATUS "Found libnova: ${NOVA_LIBRARIES}") else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) find_path(NOVA_INCLUDE_DIR libnova.h PATH_SUFFIXES libnova ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(NOVA_LIBRARIES NAMES nova PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_INCLUDES ${NOVA_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${NOVA_LIBRARIES}) if(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) set(NOVA_FOUND TRUE) else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) set(NOVA_FOUND FALSE) endif(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) if (NOVA_FOUND) if (NOT Nova_FIND_QUIETLY) message(STATUS "Found NOVA: ${NOVA_LIBRARIES}") endif (NOT Nova_FIND_QUIETLY) else (NOVA_FOUND) if (Nova_FIND_REQUIRED) message(FATAL_ERROR "libnova not found. Please install libnova0-devel. http://indi.sf.net") endif (Nova_FIND_REQUIRED) endif (NOVA_FOUND) mark_as_advanced(NOVA_INCLUDE_DIR NOVA_LIBRARIES) endif (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/7b/0000755000175000017500000000000012241463551017765 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/7b/7b1a38d9fa9107795a6137e22f83bf9955fe9760.svn-base0000644000175000017500000000660412241463551026713 0ustar jasemjasem# Locate OpenAL # This module defines # OPENAL_LIBRARY # OPENAL_FOUND, if false, do not try to link to OpenAL # OPENAL_INCLUDE_DIR, where to find the headers # # $OPENALDIR is an environment variable that would # correspond to the ./configure --prefix=$OPENALDIR # used in building OpenAL. # # Created by Eric Wing. This was influenced by the FindSDL.cmake module. # This makes the presumption that you are include al.h like # #include "al.h" # and not # #include # The reason for this is that the latter is not entirely portable. # Windows/Creative Labs does not by default put their headers in AL/ and # OS X uses the convention . # # For Windows, Creative Labs seems to have added a registry key for their # OpenAL 1.1 installer. I have added that key to the list of search paths, # however, the key looks like it could be a little fragile depending on # if they decide to change the 1.00.0000 number for bug fix releases. # Also, they seem to have laid down groundwork for multiple library platforms # which puts the library in an extra subdirectory. Currently there is only # Win32 and I have hardcoded that here. This may need to be adjusted as # platforms are introduced. # The OpenAL 1.0 installer doesn't seem to have a useful key I can use. # I do not know if the Nvidia OpenAL SDK has a registry key. # # For OS X, remember that OpenAL was added by Apple in 10.4 (Tiger). # To support the framework, I originally wrote special framework detection # code in this module which I have now removed with CMake's introduction # of native support for frameworks. # In addition, OpenAL is open source, and it is possible to compile on Panther. # Furthermore, due to bugs in the initial OpenAL release, and the # transition to OpenAL 1.1, it is common to need to override the built-in # framework. # Per my request, CMake should search for frameworks first in # the following order: # ~/Library/Frameworks/OpenAL.framework/Headers # /Library/Frameworks/OpenAL.framework/Headers # /System/Library/Frameworks/OpenAL.framework/Headers # # On OS X, this will prefer the Framework version (if found) over others. # People will have to manually change the cache values of # OPENAL_LIBRARY to override this selection or set the CMake environment # CMAKE_INCLUDE_PATH to modify the search paths. FIND_PATH(OPENAL_INCLUDE_DIR al.h PATHS $ENV{OPENALDIR} NO_DEFAULT_PATH PATH_SUFFIXES include/AL include/OpenAL include ) FIND_PATH(OPENAL_INCLUDE_DIR al.h PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave /opt [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir] PATH_SUFFIXES include/AL include/OpenAL include ) FIND_LIBRARY(OPENAL_LIBRARY NAMES OpenAL al openal OpenAL32 PATHS $ENV{OPENALDIR} NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64 ) FIND_LIBRARY(OPENAL_LIBRARY NAMES OpenAL al openal OpenAL32 PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw /opt/local /opt/csw /opt [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir] PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64 ) SET(OPENAL_FOUND "NO") IF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR) SET(OPENAL_FOUND "YES") ENDIF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR) libindi-0.9.7/cmake_modules/.svn/pristine/7c/0000755000175000017500000000000012241463551017766 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/7c/7cd6db08dc18116d79ddc4819320b05915510a60.svn-base0000644000175000017500000000311612241463551026635 0ustar jasemjasem# - Try to find libgphoto2 # Once done this will define # # LIBGPHOTO2_FOUND - system has libgphoto2 # LIBGPHOTO2_INCLUDE_DIR - the libgphoto2 include directory # LIBGPHOTO2_LIBRARIES - Link these to use libghoto2 # Copyright (c) 2009, Geoffrey Hausheer # Based on FindINDI by Jasem Mutlaq # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) # in cache already set(LIBGPHOTO2_FOUND TRUE) message(STATUS "Found libgphoto2: ${LIBGPHOTO2_LIBRARIES}") else (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) find_path(LIBGPHOTO2_INCLUDE_DIR gphoto2.h PATH_SUFFIXES gphoto2 ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(LIBGPHOTO2_LIBRARIES NAMES gphoto2 PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) set(LIBGPHOTO2_FOUND TRUE) else (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) set(LIBGPHOTO2_FOUND FALSE) endif(LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) if (LIBGPHOTO2_FOUND) if (NOT LIBGPHOTO2_FIND_QUIETLY) message(STATUS "Found libgphoto2: ${LIBGPHOTO2_LIBRARIES}") endif (NOT LIBGPHOTO2_FIND_QUIETLY) else (LIBGPHOTO2_FOUND) if (LIBGPHOTO2_FIND_REQUIRED) message(FATAL_ERROR "libgphoto2 not found.") endif (LIBGPHOTO2_FIND_REQUIRED) endif (LIBGPHOTO2_FOUND) mark_as_advanced(LIBGPHOTO2_INCLUDE_DIR LIBGPHOTO2_LIBRARIES) endif (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/15/0000755000175000017500000000000012241463551017702 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/15/154b987e24e4b658c85049db4a9dc2b5f6f64d01.svn-base0000644000175000017500000001157712241463551026753 0ustar jasemjasem# This file defines the Feature Logging macros. # # MACRO_LOG_FEATURE(VAR FEATURE DESCRIPTION URL [REQUIRED [MIN_VERSION [COMMENTS]]]) # Logs the information so that it can be displayed at the end # of the configure run # VAR : TRUE or FALSE, indicating whether the feature is supported # FEATURE: name of the feature, e.g. "libjpeg" # DESCRIPTION: description what this feature provides # URL: home page # REQUIRED: TRUE or FALSE, indicating whether the featue is required # MIN_VERSION: minimum version number. empty string if unneeded # COMMENTS: More info you may want to provide. empty string if unnecessary # # MACRO_DISPLAY_FEATURE_LOG() # Call this to display the collected results. # Exits CMake with a FATAL error message if a required feature is missing # # Example: # # INCLUDE(MacroLogFeature) # # FIND_PACKAGE(JPEG) # MACRO_LOG_FEATURE(JPEG_FOUND "libjpeg" "Support JPEG images" "http://www.ijg.org" TRUE "3.2a" "") # ... # MACRO_DISPLAY_FEATURE_LOG() # Copyright (c) 2006, Alexander Neundorf, # Copyright (c) 2006, Allen Winter, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. IF (NOT _macroLogFeatureAlreadyIncluded) SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_file}) FILE(REMOVE ${_file}) ENDIF (EXISTS ${_file}) SET(_macroLogFeatureAlreadyIncluded TRUE) ENDIF (NOT _macroLogFeatureAlreadyIncluded) MACRO(MACRO_LOG_FEATURE _var _package _description _url ) # _required _minvers _comments) SET(_required "${ARGV4}") SET(_minvers "${ARGV5}") SET(_comments "${ARGV6}") IF (${_var}) SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) ELSE (${_var}) IF (${_required} MATCHES "[Tt][Rr][Uu][Ee]") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/MissingRequirements.txt) ELSE (${_required} MATCHES "[Tt][Rr][Uu][Ee]") SET(_LOGFILENAME ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) ENDIF (${_required} MATCHES "[Tt][Rr][Uu][Ee]") ENDIF (${_var}) SET(_logtext "+ ${_package}") IF (NOT ${_var}) IF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext}, ${_minvers}") ENDIF (${_minvers} MATCHES ".*") SET(_logtext "${_logtext}: ${_description} <${_url}>") IF (${_comments} MATCHES ".*") SET(_logtext "${_logtext}\n${_comments}") ENDIF (${_comments} MATCHES ".*") # SET(_logtext "${_logtext}\n") #double-space missing features? ENDIF (NOT ${_var}) FILE(APPEND "${_LOGFILENAME}" "${_logtext}\n") ENDMACRO(MACRO_LOG_FEATURE) MACRO(MACRO_DISPLAY_FEATURE_LOG) SET(_file ${CMAKE_BINARY_DIR}/MissingRequirements.txt) IF (EXISTS ${_file}) FILE(READ ${_file} _requirements) MESSAGE(STATUS "\n-----------------------------------------------------------------------------\n-- The following REQUIRED packages could NOT be located on your system.\n-- Please install them before continuing this software installation.\n-----------------------------------------------------------------------------\n${_requirements}-----------------------------------------------------------------------------") FILE(REMOVE ${_file}) MESSAGE(FATAL_ERROR "Exiting: Missing Requirements") ENDIF (EXISTS ${_file}) SET(_summary "\n") SET(_elist 0) SET(_file ${CMAKE_BINARY_DIR}/EnabledFeatures.txt) IF (EXISTS ${_file}) SET(_elist 1) FILE(READ ${_file} _enabled) FILE(REMOVE ${_file}) SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following external packages were located on your system.\n-- This installation will have the extra features provided by these packages.\n${_enabled}") ENDIF (EXISTS ${_file}) SET(_dlist 0) SET(_file ${CMAKE_BINARY_DIR}/DisabledFeatures.txt) IF (EXISTS ${_file}) SET(_dlist 1) FILE(READ ${_file} _disabled) FILE(REMOVE ${_file}) SET(_summary "${_summary}-----------------------------------------------------------------------------\n-- The following OPTIONAL packages could NOT be located on your system.\n-- Consider installing them to enable more features from this software.\n${_disabled}") ELSE (EXISTS ${_file}) IF (${_elist}) SET(_summary "${_summary}Congratulations! All external packages have been found.\n") ENDIF (${_elist}) ENDIF (EXISTS ${_file}) IF (${_elist} OR ${_dlist}) SET(_summary "${_summary}-----------------------------------------------------------------------------\n") ENDIF (${_elist} OR ${_dlist}) MESSAGE(STATUS "${_summary}") ENDMACRO(MACRO_DISPLAY_FEATURE_LOG) libindi-0.9.7/cmake_modules/.svn/pristine/de/0000755000175000017500000000000012241463551020045 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/de/dec4f6d462f3dd5911461f1ddda2c9f2a11be794.svn-base0000644000175000017500000000320112241463551027360 0ustar jasemjasem# - Try to find libmodbus # Once done this will define # # MODBUS_FOUND - system has MODBUS # MODBUS_INCLUDE_DIR - the MODBUS include directory # MODBUS_LIBRARIES - Link these to use MODBUS # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) # in cache already set(MODBUS_FOUND TRUE) message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}") else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) find_path(MODBUS_INCLUDE_DIR modbus.h PATH_SUFFIXES modbus ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(MODBUS_LIBRARIES NAMES modbus PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_INCLUDES ${MODBUS_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${MODBUS_LIBRARIES}) if(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) set(MODBUS_FOUND TRUE) else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) set(MODBUS_FOUND FALSE) endif(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) if (MODBUS_FOUND) if (NOT MODBUS_FIND_QUIETLY) message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}") endif (NOT MODBUS_FIND_QUIETLY) else (MODBUS_FOUND) if (MODBUS_FIND_REQUIRED) message(FATAL_ERROR "libmodbus not found. Please install libmodbus-devel. https://launchpad.net/libmodbus/") endif (MODBUS_FIND_REQUIRED) endif (MODBUS_FOUND) mark_as_advanced(MODBUS_INCLUDE_DIR MODBUS_LIBRARIES) endif (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/32/0000755000175000017500000000000012241463551017701 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/32/3215a9796455b10d5fa42058acaea6d4d6d9b3d5.svn-base0000644000175000017500000000474412241463551027006 0ustar jasemjasem# - Try to find INDI # Once done this will define # # INDI_FOUND - system has INDI # INDI_INCLUDE_DIR - the INDI include directory # INDI_LIBRARIES - Link these to use INDI # INDI_MAIN_LIBRARIES - Link to these to build INDI drivers with main() # INDI_DRIVER_LIBRARIES - Link to these to build INDI drivers with indibase support # INDI_CLIENT_LIBRARIES - Link to these to build INDI clients # INDI_DATA_DIR - INDI shared data dir. # Copyright (c) 2011, Jasem Mutlaq # Copyright (c) 2012, Pino Toscano # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) # in cache already set(INDI_FOUND TRUE) message(STATUS "Found INDI: ${INDI_LIBRARIES}") else (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) find_package(PkgConfig) if (PKG_CONFIG_FOUND) if (INDI_FIND_VERSION) set(version_string ">=${INDI_FIND_VERSION}") endif() pkg_check_modules(PC_INDI libindi${version_string}) else() # assume it was found set(PC_INDI_FOUND TRUE) endif() if (PC_INDI_FOUND) find_path(INDI_INCLUDE_DIR indidevapi.h PATH_SUFFIXES libindi HINTS ${PC_INDI_INCLUDE_DIRS} ) find_library(INDI_LIBRARIES NAMES indi HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_DRIVER_LIBRARIES NAMES indidriver HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_MAIN_LIBRARIES NAMES indimain HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_CLIENT_LIBRARIES NAMES indiclient HINTS ${PC_INDI_LIBRARY_DIRS} ) find_path(INDI_DATA_DIR drivers.xml PATH_SUFFIXES share/indi ) set(INDI_VERSION "${PC_INDI_VERSION}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(INDI REQUIRED_VARS INDI_INCLUDE_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES VERSION_VAR INDI_VERSION ) mark_as_advanced(INDI_INCLUDE_DIR INDI_DATA_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES) endif (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/32/327c35cff6ca2c8002d5ef3034effe3d9af4eea9.svn-base0000644000175000017500000000205212241463551027361 0ustar jasemjasem# - MACRO_OPTIONAL_FIND_PACKAGE() combines FIND_PACKAGE() with an OPTION() # MACRO_OPTIONAL_FIND_PACKAGE( [QUIT] ) # This macro is a combination of OPTION() and FIND_PACKAGE(), it # works like FIND_PACKAGE(), but additionally it automatically creates # an option name WITH_, which can be disabled via the cmake GUI. # or via -DWITH_=OFF # The standard _FOUND variables can be used in the same way # as when using the normal FIND_PACKAGE() # Copyright (c) 2006, Alexander Neundorf, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. MACRO (MACRO_OPTIONAL_FIND_PACKAGE _name ) OPTION(WITH_${_name} "Search for ${_name} package" ON) if (WITH_${_name}) FIND_PACKAGE(${_name} ${ARGN}) else (WITH_${_name}) set(${_name}_FOUND) set(${_name}_INCLUDE_DIR) set(${_name}_INCLUDES) set(${_name}_LIBRARY) set(${_name}_LIBRARIES) endif (WITH_${_name}) ENDMACRO (MACRO_OPTIONAL_FIND_PACKAGE) libindi-0.9.7/cmake_modules/.svn/pristine/16/0000755000175000017500000000000012241463551017703 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/16/16b690cf365f8630ac442ebf7f833af70d1cd377.svn-base0000644000175000017500000000367412241463551027023 0ustar jasemjasem# - Try to find Apogee Instruments Library # Once done this will define # # APOGEE_FOUND - system has APOGEE # APOGEE_INCLUDE_DIR - the APOGEE include directory # APOGEE_LIBRARIES - Link these to use APOGEE # Copyright (c) 2008, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) # in cache already set(APOGEE_FOUND TRUE) message(STATUS "Found libapogee: ${APOGEEU_LIBRARIES}, ${APOGEEE_LIBRARIES}") else (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) find_path(APOGEE_INCLUDE_DIR libapogee.h PATH_SUFFIXES libapogee ${_obIncDir} ${GNUWIN32_DIR}/include ) # Find Apogee Alta-U Library find_library(APOGEEU_LIBRARIES NAMES apogeeu PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) # Find Apogee Alta-U Library find_library(APOGEEE_LIBRARIES NAMES apogeee PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) set(APOGEE_FOUND TRUE) else (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) set(APOGEE_FOUND FALSE) endif(APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) if (APOGEE_FOUND) if (NOT APOGEE_FIND_QUIETLY) message(STATUS "Found APOGEE: ${APOGEEU_LIBRARIES}, ${APOGEEE_LIBRARIES}") endif (NOT APOGEE_FIND_QUIETLY) else (APOGEE_FOUND) if (APOGEE_FIND_REQUIRED) message(FATAL_ERROR "libapogee not found. Cannot compile Apogee CCD Driver. Please install libapogee and try again. http://www.indilib.org") endif (APOGEE_FIND_REQUIRED) endif (APOGEE_FOUND) mark_as_advanced(APOGEE_INCLUDE_DIR APOGEEU_LIBRARIES APOGEEE_LIBRARIES) endif (APOGEE_INCLUDE_DIR AND APOGEEU_LIBRARIES AND APOGEEE_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/f1/0000755000175000017500000000000012241463551017763 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/f1/f11698c011f8a2415f2dc91ca0346f409c570a3b.svn-base0000644000175000017500000000656012241463551026712 0ustar jasemjasem# - Try to find libusb-1.0 # Once done this will define # # LIBUSB_1_FOUND - system has libusb # LIBUSB_1_INCLUDE_DIRS - the libusb include directory # LIBUSB_1_LIBRARIES - Link these to use libusb # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb # # Adapted from cmake-modules Google Code project # # Copyright (c) 2006 Andreas Schneider # # (Changes for libusb) Copyright (c) 2008 Kyle Machulis # # Redistribution and use is allowed according to the terms of the New BSD license. # # CMake-Modules Project New BSD License # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of the CMake-Modules Project nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) # in cache already set(LIBUSB_FOUND TRUE) else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) find_path(LIBUSB_1_INCLUDE_DIR NAMES libusb.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include PATH_SUFFIXES libusb-1.0 ) find_library(LIBUSB_1_LIBRARY NAMES usb-1.0 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR} ) set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY} ) if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) set(LIBUSB_1_FOUND TRUE) endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) if (LIBUSB_1_FOUND) if (NOT libusb_1_FIND_QUIETLY) message(STATUS "Found libusb-1.0:") message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") endif (NOT libusb_1_FIND_QUIETLY) else (LIBUSB_1_FOUND) if (libusb_1_FIND_REQUIRED) message(FATAL_ERROR "Could not find libusb") endif (libusb_1_FIND_REQUIRED) endif (LIBUSB_1_FOUND) # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) libindi-0.9.7/cmake_modules/.svn/pristine/5f/0000755000175000017500000000000012241463551017767 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/5f/5f2ff8077502e5f711cd28daa42c780a78673a0f.svn-base0000644000175000017500000000210412241463551027010 0ustar jasemjasem# - Find vorbis # Find the native vorbis includes and libraries # # VORBIS_INCLUDE_DIR - where to find vorbis.h, etc. # VORBIS_LIBRARIES - List of libraries when using vorbis(file). # VORBIS_FOUND - True if vorbis found. if(VORBIS_INCLUDE_DIR) # Already in cache, be silent set(VORBIS_FIND_QUIETLY TRUE) endif(VORBIS_INCLUDE_DIR) find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h) find_library(OGG_LIBRARY NAMES ogg) find_library(VORBIS_LIBRARY NAMES vorbis) find_library(VORBISFILE_LIBRARY NAMES vorbisfile) # Handle the QUIETLY and REQUIRED arguments and set VORBIS_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) find_package_handle_standard_args(VORBIS DEFAULT_MSG VORBIS_INCLUDE_DIR OGG_LIBRARY VORBIS_LIBRARY VORBIS_LIBRARY) if(VORBIS_FOUND) set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY}) else(VORBIS_FOUND) set(VORBIS_LIBRARIES) endif(VORBIS_FOUND) mark_as_advanced(VORBIS_INCLUDE_DIR) mark_as_advanced(OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY) libindi-0.9.7/cmake_modules/.svn/pristine/d4/0000755000175000017500000000000012241463551017764 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/d4/d4842f31c51b5c5c8defb304e71673a873540823.svn-base0000644000175000017500000000246312241463551026651 0ustar jasemjasem# - Try to find FISHCAMP CCD # Once done this will define # # FISHCAMP_FOUND - system has FISHCAMP # FISHCAMP_LIBRARIES - Link these to use FISHCAMP # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (FISHCAMP_LIBRARIES) # in cache already set(FISHCAMP_FOUND TRUE) message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}") else (FISHCAMP_LIBRARIES) find_library(FISHCAMP_LIBRARIES NAMES fishcamp PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_LIBRARIES ${FISHCAMP_LIBRARIES}) if(FISHCAMP_LIBRARIES) set(FISHCAMP_FOUND TRUE) else (FISHCAMP_LIBRARIES) set(FISHCAMP_FOUND FALSE) endif(FISHCAMP_LIBRARIES) if (FISHCAMP_FOUND) if (NOT FISHCAMP_FIND_QUIETLY) message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}") endif (NOT FISHCAMP_FIND_QUIETLY) else (FISHCAMP_FOUND) if (FISHCAMP_FIND_REQUIRED) message(FATAL_ERROR "FISHCAMP not found. Please install FISHCAMP library. http://www.indilib.org") endif (FISHCAMP_FIND_REQUIRED) endif (FISHCAMP_FOUND) mark_as_advanced(FISHCAMP_LIBRARIES) endif (FISHCAMP_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/6e/0000755000175000017500000000000012241463551017767 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/6e/6e2aa21c1cb029a5a194a1cc844dd9fca050dcf8.svn-base0000644000175000017500000000174712241463551027347 0ustar jasemjasem# - Try to find the USB library # Once done this defines # # LIBUSB_FOUND - system has libusb # LIBUSB_INCLUDE_DIR - the libusb include directory # LIBUSB_LIBRARIES - Link these to use libusb # Copyright (c) 2006, 2008 Laurent Montel, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (NOT WIN32) # use pkg-config to get the directories and then use these values # in the FIND_PATH() and FIND_LIBRARY() calls find_package(PkgConfig) pkg_check_modules(PC_LIBUSB QUIET libusb) endif(NOT WIN32) find_path(LIBUSB_INCLUDE_DIR usb.h HINTS ${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS}) find_library(LIBUSB_LIBRARIES NAMES usb HINTS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS}) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIR) mark_as_advanced(LIBUSB_INCLUDE_DIR LIBUSB_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/33/0000755000175000017500000000000012241463551017702 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/33/33ceb4e5ec77adccc3d040ac30e22a3d53230ec1.svn-base0000644000175000017500000000504212241463551027235 0ustar jasemjasem# - Locate ALUT # This module defines # ALUT_LIBRARY # ALUT_FOUND, if false, do not try to link to OpenAL # ALUT_INCLUDE_DIR, where to find the headers # # $OPENALDIR is an environment variable that would # correspond to the ./configure --prefix=$OPENALDIR # used in building OpenAL. # # Created by Bryan Donlan, based on the FindOpenAL.cmake module by Eric Wang. FIND_PATH(ALUT_INCLUDE_DIR alut.h $ENV{OPENALDIR}/include ~/Library/Frameworks/OpenAL.framework/Headers /Library/Frameworks/OpenAL.framework/Headers /System/Library/Frameworks/OpenAL.framework/Headers # Tiger /usr/local/include/AL /usr/local/include/OpenAL /usr/local/include /usr/include/AL /usr/include/OpenAL /usr/include /sw/include/AL # Fink /sw/include/OpenAL /sw/include /opt/local/include/AL # DarwinPorts /opt/local/include/OpenAL /opt/local/include /opt/csw/include/AL # Blastwave /opt/csw/include/OpenAL /opt/csw/include /opt/include/AL /opt/include/OpenAL /opt/include ) # I'm not sure if I should do a special casing for Apple. It is # unlikely that other Unix systems will find the framework path. # But if they do ([Next|Open|GNU]Step?), # do they want the -framework option also? IF(${ALUT_INCLUDE_DIR} MATCHES ".framework") STRING(REGEX REPLACE "(.*)/.*\\.framework/.*" "\\1" ALUT_FRAMEWORK_PATH_TMP ${ALUT_INCLUDE_DIR}) IF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" ) # String is in default search path, don't need to use -F SET (ALUT_LIBRARY "-framework OpenAL" CACHE STRING "OpenAL framework for OSX") ELSE("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" ) # String is not /Library/Frameworks, need to use -F SET(ALUT_LIBRARY "-F${ALUT_FRAMEWORK_PATH_TMP} -framework OpenAL" CACHE STRING "OpenAL framework for OSX") ENDIF("${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/Library/Frameworks" OR "${ALUT_FRAMEWORK_PATH_TMP}" STREQUAL "/System/Library/Frameworks" ) # Clear the temp variable so nobody can see it SET(ALUT_FRAMEWORK_PATH_TMP "" CACHE INTERNAL "") ELSE(${ALUT_INCLUDE_DIR} MATCHES ".framework") FIND_LIBRARY(ALUT_LIBRARY NAMES alut PATHS $ENV{OPENALDIR}/lib $ENV{OPENALDIR}/libs /usr/local/lib /usr/lib /sw/lib /opt/local/lib /opt/csw/lib /opt/lib ) ENDIF(${ALUT_INCLUDE_DIR} MATCHES ".framework") SET(ALUT_FOUND "NO") IF(ALUT_LIBRARY) SET(ALUT_FOUND "YES") ENDIF(ALUT_LIBRARY) libindi-0.9.7/cmake_modules/.svn/pristine/24/0000755000175000017500000000000012241463551017702 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/24/24d962a5a4a382eb6f41aff987fd67dc6572e3b0.svn-base0000644000175000017500000000245512241463551027104 0ustar jasemjasem# - Try to find Quantum Scientific Imaging Library # Once done this will define # # QSI_FOUND - system has QSI # QSI_INCLUDE_DIR - the QSI include directory # QSI_LIBRARIES - Link these to use QSI # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (QSI_INCLUDE_DIR AND QSI_LIBRARIES) # in cache already set(QSI_FOUND TRUE) message(STATUS "Found libqsiapi: ${QSI_LIBRARIES}") else (QSI_INCLUDE_DIR AND QSI_LIBRARIES) find_path(QSI_INCLUDE_DIR qsiapi.h PATH_SUFFIXES qsiapi ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(QSI_LIBRARIES NAMES qsiapi PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(QSI_INCLUDE_DIR AND QSI_LIBRARIES) set(QSI_FOUND TRUE) else (QSI_INCLUDE_DIR AND QSI_LIBRARIES) set(QSI_FOUND FALSE) endif(QSI_INCLUDE_DIR AND QSI_LIBRARIES) if (QSI_FOUND) if (NOT QSI_FIND_QUIETLY) message(STATUS "Found QSI: ${QSI_LIBRARIES}") endif (NOT QSI_FIND_QUIETLY) else (QSI_FOUND) if (QSI_FIND_REQUIRED) message(FATAL_ERROR "QSI not found. Please install libqsi http://www.indilib.org") endif (QSI_FIND_REQUIRED) endif (QSI_FOUND) mark_as_advanced(QSI_INCLUDE_DIR QSI_LIBRARIES) endif (QSI_INCLUDE_DIR AND QSI_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/a8/0000755000175000017500000000000012241463551017765 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/a8/a8db819badbb1fba4e2abbba441c3b159d4dce6b.svn-base0000644000175000017500000000236612241463551027720 0ustar jasemjasem# - Try to find SBIG (Santa Barbara Instruments Group Library for CCDs & Filter Wheels). # Once done this will define # # SBIG_FOUND - system has SBIG # SBIG_LIBRARIES - Link these to use SBIG # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (SBIG_LIBRARIES) # in cache already set(SBIG_FOUND TRUE) message(STATUS "Found SBIG: ${SBIG_LIBRARIES}") else (SBIG_LIBRARIES) find_library(SBIG_LIBRARIES NAMES sbigudrv PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_LIBRARIES ${SBIG_LIBRARIES}) if(SBIG_LIBRARIES) set(SBIG_FOUND TRUE) else (SBIG_LIBRARIES) set(SBIG_FOUND FALSE) endif(SBIG_LIBRARIES) if (SBIG_FOUND) if (NOT SBIG_FIND_QUIETLY) message(STATUS "Found SBIG: ${SBIG_LIBRARIES}") endif (NOT SBIG_FIND_QUIETLY) else (SBIG_FOUND) if (SBIG_FIND_REQUIRED) message(FATAL_ERROR "SBIG not found. Please install SBIG library. http://indi.sf.net") endif (SBIG_FIND_REQUIRED) endif (SBIG_FOUND) mark_as_advanced(SBIG_LIBRARIES) endif (SBIG_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/d3/0000755000175000017500000000000012241463551017763 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/d3/d3c033542b5bca99854b388b368ca9928e279151.svn-base0000644000175000017500000000264512241463551026612 0ustar jasemjasem# - Try to find Finger Lakes Instruments Library # Once done this will define # # FLI_FOUND - system has FLI # FLI_INCLUDE_DIR - the FLI include directory # FLI_LIBRARIES - Link these to use FLI # Copyright (c) 2008, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (FLI_INCLUDE_DIR AND FLI_LIBRARIES) # in cache already set(FLI_FOUND TRUE) message(STATUS "Found libfli: ${FLI_LIBRARIES}") else (FLI_INCLUDE_DIR AND FLI_LIBRARIES) find_path(FLI_INCLUDE_DIR libfli.h PATH_SUFFIXES fli ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(FLI_LIBRARIES NAMES fli PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(FLI_INCLUDE_DIR AND FLI_LIBRARIES) set(FLI_FOUND TRUE) else (FLI_INCLUDE_DIR AND FLI_LIBRARIES) set(FLI_FOUND FALSE) endif(FLI_INCLUDE_DIR AND FLI_LIBRARIES) if (FLI_FOUND) if (NOT FLI_FIND_QUIETLY) message(STATUS "Found FLI: ${FLI_LIBRARIES}") endif (NOT FLI_FIND_QUIETLY) else (FLI_FOUND) if (FLI_FIND_REQUIRED) message(FATAL_ERROR "FLI not found. Please install libfli-dev. http://www.indilib.org") endif (FLI_FIND_REQUIRED) endif (FLI_FOUND) mark_as_advanced(FLI_INCLUDE_DIR FLI_LIBRARIES) endif (FLI_INCLUDE_DIR AND FLI_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/da/0000755000175000017500000000000012241463551020041 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/da/da9a7b326f32fd39ebe175557dc202f1d5d080ac.svn-base0000644000175000017500000000473612241463551027303 0ustar jasemjasem# - Try to find INDI # Once done this will define # # INDI_FOUND - system has INDI # INDI_INCLUDE_DIR - the INDI include directory # INDI_LIBRARIES - Link these to use INDI # INDI_MAIN_LIBRARIES - Link to these to build INDI drivers with main() # INDI_DRIVER_LIBRARIES - Link to these to build INDI drivers with indibase support # INDI_CLIENT_LIBRARIES - Link to these to build INDI clients # INDI_DATA_DIR - INDI shared data dir. # Copyright (c) 2011, Jasem Mutlaq # Copyright (c) 2012, Pino Toscano # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) # in cache already set(INDI_FOUND TRUE) message(STATUS "Found INDI: ${INDI_LIBRARIES}") else (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) find_package(PkgConfig) if (PKG_CONFIG_FOUND) if (INDI_FIND_VERSION) set(version_string ">=${INDI_FIND_VERSION}") endif() pkg_check_modules(PC_INDI libindi${version_string}) else() # assume it was found set(PC_INDI_FOUND TRUE) endif() if (PC_INDI_FOUND) find_path(INDI_INCLUDE_DIR indidevapi.h PATH_SUFFIXES libindi HINTS ${PC_INDI_INCLUDE_DIRS} ) find_library(INDI_LIBRARIES NAMES indi HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_DRIVER_LIBRARIES NAMES indidriver HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_MAIN_LIBRARIES NAMES indimain HINTS ${PC_INDI_LIBRARY_DIRS} ) find_library(INDI_CLIENT_LIBRARIES NAMES indiclient HINTS ${PC_INDI_LIBRARY_DIRS} ) find_path(INDI_DATA_DIR drivers.xml PATH_SUFFIXES indi ) set(INDI_VERSION "${PC_INDI_VERSION}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(INDI REQUIRED_VARS INDI_INCLUDE_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES VERSION_VAR INDI_VERSION ) mark_as_advanced(INDI_INCLUDE_DIR INDI_DATA_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES) endif (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/19/0000755000175000017500000000000012241463551017706 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/19/19887b6ec14ec33603e1b607b7b9a46465f28fdc.svn-base0000644000175000017500000000664712241463551026757 0ustar jasemjasem# - Try to find libusb-1.0 # Once done this will define # # LIBUSB_1_FOUND - system has libusb # LIBUSB_1_INCLUDE_DIRS - the libusb include directory # LIBUSB_1_LIBRARIES - Link these to use libusb # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb # # Adapted from cmake-modules Google Code project # # Copyright (c) 2006 Andreas Schneider # # (Changes for libusb) Copyright (c) 2008 Kyle Machulis # # Redistribution and use is allowed according to the terms of the New BSD license. # # CMake-Modules Project New BSD License # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of the CMake-Modules Project nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) # in cache already set(LIBUSB_FOUND TRUE) else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) find_path(LIBUSB_1_INCLUDE_DIR NAMES libusb.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include PATH_SUFFIXES libusb-1.0 ) find_library(LIBUSB_1_LIBRARY NAMES usb-1.0 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR} ) set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY} ) if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) set(LIBUSB_1_FOUND TRUE) endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) if (LIBUSB_1_FOUND) if (NOT USB-1_FIND_QUIETLY) message(STATUS "Found libusb-1.0:") message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") endif (NOT USB-1_FIND_QUIETLY) else (LIBUSB_1_FOUND) if (USB-1_FIND_REQUIRED) message(FATAL_ERROR "Could not find libusb-1.0. Please install libusb-1.0 along with the development package.") endif (USB-1_FIND_REQUIRED) endif (LIBUSB_1_FOUND) # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) libindi-0.9.7/cmake_modules/.svn/pristine/e2/0000755000175000017500000000000012241463551017763 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/e2/e265b9aa0e214f93895ea72dfb47721d6b0d388b.svn-base0000644000175000017500000000540512241463551027076 0ustar jasemjasem# - Try to find INDI # Once done this will define # # INDI_FOUND - system has INDI # INDI_INCLUDE_DIR - the INDI include directory # INDI_LIBRARIES - Link these to use INDI # INDI_MAIN_LIBRARIES - Link to these to build INDI drivers with main() # INDI_DRIVER_LIBRARIES - Link to these to build INDI drivers with indibase support # INDI_CLIENT_LIBRARIES - Link to these to build INDI clients # INDI_DATA_DIR - INDI shared data dir. # Copyright (c) 2011, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) # in cache already set(INDI_FOUND TRUE) message(STATUS "Found INDI: ${INDI_LIBRARIES}") else (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) find_path(INDI_INCLUDE_DIR indidevapi.h PATH_SUFFIXES libindi ${_obIncDir} ${GNUWIN32_DIR}/include ) find_path(INDI_DATA_DIR drivers.xml PATHS ${CMAKE_INSTALL_PREFIX} /usr /usr/local /opt /opt/local ${GNUWIN32_DIR} PATH_SUFFIXES share/indi ) find_library(INDI_LIBRARIES NAMES indi PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) find_library(INDI_DRIVER_LIBRARIES NAMES indidriver PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) find_library(INDI_MAIN_LIBRARIES NAMES indimain PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) find_library(INDI_CLIENT_LIBRARIES NAMES indiclient PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) # Find pkg-config FIND_PROGRAM(PKGCONFIG_EXECUTABLE NAMES pkg-config PATHS /usr/bin/ /usr/local/bin ) # query pkg-config asking for a libindi >= 0.8.0 EXEC_PROGRAM(${PKGCONFIG_EXECUTABLE} ARGS --atleast-version=0.8.0 libindi RETURN_VALUE _return_VALUE OUTPUT_VARIABLE _pkgconfigDevNull ) if(_return_VALUE STREQUAL "0") set(INDI_FOUND TRUE) else(_return_VALUE STREQUAL "0") set(INDI_FOUND FALSE) message(STATUS "Could NOT find libindi. pkg-config indicates that libindi >= 0.8.0 is not installed.") endif(_return_VALUE STREQUAL "0") if (INDI_FOUND) if (NOT INDI_FIND_QUIETLY) message(STATUS "Found INDI: ${INDI_LIBRARIES}, ${INDI_MAIN_LIBRARIES}") message(STATUS "INDI Include: ${INDI_INCLUDE_DIR}, INDI Data: ${INDI_DATA_DIR}") endif (NOT INDI_FIND_QUIETLY) endif (INDI_FOUND) mark_as_advanced(INDI_INCLUDE_DIR INDI_DATA_DIR INDI_LIBRARIES INDI_DRIVER_LIBRARIES INDI_MAIN_LIBRARIES INDI_CLIENT_LIBRARIES) endif (INDI_INCLUDE_DIR AND INDI_DATA_DIR AND INDI_LIBRARIES AND INDI_DRIVER_LIBRARIES AND INDI_MAIN_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/52/0000755000175000017500000000000012241463551017703 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/52/52e62155c2e72ac59c0de18e4c9f41cdc8243823.svn-base0000644000175000017500000000440512241463551026726 0ustar jasemjasem# - Try to find CFITSIO # Once done this will define # # CFITSIO_FOUND - system has CFITSIO # CFITSIO_INCLUDE_DIR - the CFITSIO include directory # CFITSIO_LIBRARIES - Link these to use CFITSIO # CFITSIO_VERSION_STRING - Human readable version number of cfitsio # CFITSIO_VERSION_MAJOR - Major version number of cfitsio # CFITSIO_VERSION_MINOR - Minor version number of cfitsio # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) # in cache already set(CFITSIO_FOUND TRUE) message(STATUS "Found CFITSIO: ${CFITSIO_LIBRARIES}") else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) # JM: Packages from different distributions have different suffixes find_path(CFITSIO_INCLUDE_DIR fitsio.h PATH_SUFFIXES libcfitsio3 libcfitsio0 cfitsio ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(CFITSIO_LIBRARIES NAMES cfitsio PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) set(CFITSIO_FOUND TRUE) else (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) set(CFITSIO_FOUND FALSE) endif(CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) if (CFITSIO_FOUND) # Find the version of the cfitsio header execute_process(COMMAND egrep CFITSIO_VERSION ${CFITSIO_INCLUDE_DIR}/fitsio.h OUTPUT_VARIABLE CFITSIO_VERSION_STRING) STRING(REGEX REPLACE "[^0-9.]" "" CFITSIO_VERSION_STRING ${CFITSIO_VERSION_STRING}) STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\1" CFITSIO_VERSION_MAJOR ${CFITSIO_VERSION_STRING}) STRING(REGEX REPLACE "^([0-9]+)[.]([0-9]+)" "\\2" CFITSIO_VERSION_MINOR ${CFITSIO_VERSION_STRING}) if (NOT CFITSIO_FIND_QUIETLY) message(STATUS "Found CFITSIO ${CFITSIO_VERSION_STRING}: ${CFITSIO_LIBRARIES}") endif (NOT CFITSIO_FIND_QUIETLY) else (CFITSIO_FOUND) if (CFITSIO_FIND_REQUIRED) message(STATUS "CFITSIO not found.") endif (CFITSIO_FIND_REQUIRED) endif (CFITSIO_FOUND) mark_as_advanced(CFITSIO_INCLUDE_DIR CFITSIO_LIBRARIES) endif (CFITSIO_INCLUDE_DIR AND CFITSIO_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/pristine/02/0000755000175000017500000000000012241463551017676 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/02/02e4bbe108ba9212080964375af2c597018def82.svn-base0000644000175000017500000000344212241463551026553 0ustar jasemjasem# - Try to find NOVA # Once done this will define # # NOVA_FOUND - system has NOVA # NOVA_INCLUDE_DIR - the NOVA include directory # NOVA_LIBRARIES - Link these to use NOVA # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE) # in cache already set(NOVA_FOUND TRUE) message(STATUS "Found libnova: ${NOVA_LIBRARIES}") else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES) find_path(NOVA_INCLUDE_DIR libnova.h PATH_SUFFIXES libnova ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(NOVA_LIBRARIES NAMES nova PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_INCLUDES ${NOVA_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${NOVA_LIBRARIES}) check_cxx_source_compiles("#include int main() { ln_get_date_from_tm(NULL, NULL); return 0; }" NOVA_FUNCTION_COMPILE) if(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE) set(NOVA_FOUND TRUE) else (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE) set(NOVA_FOUND FALSE) endif(NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE) if (NOVA_FOUND) if (NOT Nova_FIND_QUIETLY) message(STATUS "Found NOVA: ${NOVA_LIBRARIES}") endif (NOT Nova_FIND_QUIETLY) else (NOVA_FOUND) if (Nova_FIND_REQUIRED) message(FATAL_ERROR "libnova not found. Please install libnova0-devel. http://indi.sf.net") endif (Nova_FIND_REQUIRED) endif (NOVA_FOUND) mark_as_advanced(NOVA_INCLUDE_DIR NOVA_LIBRARIES) endif (NOVA_INCLUDE_DIR AND NOVA_LIBRARIES AND NOVA_FUNCTION_COMPILE) libindi-0.9.7/cmake_modules/.svn/pristine/3f/0000755000175000017500000000000012241463551017765 5ustar jasemjasemlibindi-0.9.7/cmake_modules/.svn/pristine/3f/3fdf934be5b9e2c0986d00772be02b625f83dd99.svn-base0000644000175000017500000000247712241463551027120 0ustar jasemjasem# - Try to find Meade DSI Library. # Once done this will define # # MEADEDSI_FOUND - system has Meade DSI # MEADEDSI_LIBRARIES - Link these to use Meade DSI # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (MEADEDSI_LIBRARIES) # in cache already set(MEADEDSI_FOUND TRUE) message(STATUS "Found MEADEDSI: ${MEADEDSI_LIBRARIES}") else (MEADEDSI_LIBRARIES) find_library(MEADEDSI_LIBRARIES NAMES dsi PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_LIBRARIES ${MEADEDSI_LIBRARIES}) if(MEADEDSI_LIBRARIES) set(MEADEDSI_FOUND TRUE) else (MEADEDSI_LIBRARIES) set(MEADEDSI_FOUND FALSE) endif(MEADEDSI_LIBRARIES) if (MEADEDSI_FOUND) if (NOT MEADEDSI_FIND_QUIETLY) message(STATUS "Found Meade DSI: ${MEADEDSI_LIBRARIES}") endif (NOT MEADEDSI_FIND_QUIETLY) else (MEADEDSI_FOUND) if (MEADEDSI_FIND_REQUIRED) message(FATAL_ERROR "Meade DSI not found. Please install Meade DSI library. http://linuxdsi.sourceforge.net") endif (MEADEDSI_FIND_REQUIRED) endif (MEADEDSI_FOUND) mark_as_advanced(MEADEDSI_LIBRARIES) endif (MEADEDSI_LIBRARIES) libindi-0.9.7/cmake_modules/.svn/wc.db0000644000175000017500000013400012241463551016536 0ustar jasemjasemSQLite format 3@ c.c-â)â"ûöñìçâ h³hIOUsvn://svn.code.sf.net/p/indi/code14e3e35b-4bd0-4918-bbf4-08149c233275KSUhttps://svn.code.sf.net/p/indi/code14e3e35b-4bd0-4918-bbf4-08149c233275 ³Ù³%Osvn://svn.code.sf.net/p/indi/code&S https://svn.code.sf.net/p/indi/code ñÆÆæÖ!REPOSITORY!WORK_QUEUE  WCROOT ¯Ø¯(U14e3e35b-4bd0-4918-bbf4-08149c233275'U 14e3e35b-4bd0-4918-bbf4-08149c233275 ³Ù³%Osvn://svn.code.sf.net/p/indi/code&S https://svn.code.sf.net/p/indi/code ûû üü üü ö-ûö'& É,É+2i$sha1$5f2ff8077502e5f711cd28daa42c780a78673a0f xxJœâ(¢Ï0!!tableREPOSITORYREPOSITORYCREATE TABLE REPOSITORY ( id INTEGER PRIMARY KEY AUTOINCREMENT, root TEXT UNIQUE NOT NULL, uuid TEXT NOT NULL )3G!indexsqlite_autoindex_REPOSITORY_1REPOSITORYP++Ytablesqlite_sequencesqlite_sequenceCREATE TABLE sqlite_sequence(name,seq)D!]indexI_UUIDREPOSITORYCREATE INDEX I_UUID ON REPOSITORY (uuid)D!]indexI_ROOTREPOSITORYCREATE INDEX I_ROOT ON REPOSITORY (root)xKtableWCROOTWCROOTCREATE TABLE WCROOT ( id INTEGER PRIMARY KEY AUTOINCREMENT, local_abspath TEXT UNIQUE )+?indexsqlite_autoindex_WCROOT_1WCROOT_+indexI_LOCAL_ABSPATHWCROOT CREATE UNIQUE INDEX I_LOCAL_ABSPATH ON WCROOT (local_abspath)M ‚mtablePRISTINEPRISTINE CREATE TABLE PRISTINE ( checksum TEXT NOT NULL PRIMARY KEY, compression INTEGER, size INTEGER NOT NULL, refcount INTEGER NOT NULL, md5_checksum TEXT NOT NULL )   „„µô+—/ Cindexsqlite_autoindex_PRISTINE_1PRISTINE „< ##ˆ?tableACTUAL_NODEACTUAL_NODE CREATE TABLE ACTUAL_NODE ( wc_id INTEGER NOT NULL REFERENCES WCROOT (id), local_relpath TEXT NOT NULL, parent_relpath TEXT, properties BLOB, conflict_old TEXT, conflict_new TEXT, conflict_working TEXT, prop_reject TEXT, changelist TEXT, text_mod TEXT, tree_conflict_data TEXT, conflict_data BLOB, older_checksum TEXT REFERENCES PRISTINE (checksum), left_checksum TEXT REFERENCES PRISTINE (checksum), right_checksum TEXT REFERENCES PRISTINE (checksum), PRIMARY KEY (wc_id, local_relpath) )5 I#indexsqlite_autoindex_ACTUAL_NODE_1ACTUAL_NODEj +#indexI_ACTUAL_PARENTACTUAL_NODECREATE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath)g3#indexI_ACTUAL_CHANGELISTACTUAL_NODECREATE INDEX I_ACTUAL_CHANGELIST ON ACTUAL_NODE (changelist)     77DmìÑ‚ ƒwtableLOCKLOCKCREATE TABLE LOCK ( repos_id INTEGER NOT NULL REFERENCES REPOSITORY (id), repos_relpath TEXT NOT NULL, lock_token TEXT NOT NULL, lock_owner TEXT, lock_comment TEXT, lock_date INTEGER, PRIMARY KEY (repos_id, repos_relpath) )';indexsqlite_autoindex_LOCK_1LOCK}!!EtableWORK_QUEUEWORK_QUEUECREATE TABLE WORK_QUEUE ( id INTEGER PRIMARY KEY AUTOINCREMENT, work BLOB NOT NULL )bƒtableWC_LOCKWC_LOCKCREATE TABLE WC_LOCK ( wc_id INTEGER NOT NULL REFERENCES WCROOT (id), local_dir_relpath TEXT NOT NULL, locked_levels INTEGER NOT NULL DEFAULT -1, PRIMARY KEY (wc_id, local_dir_relpath) )-Aindexsqlite_autoindex_WC_LOCK_1WC_LOCK ¦¦::::::::::::::ÆtHäº^-Ù¯ƒZ, ù ûâ.ûöçñìâ)A% (* $# ú"}ŠãË"vRý`¬¶;„Ãg˜Ÿ*DØ 1FindFISHCAMP.cmakeH -FindOpenAL.cmakeG )FindFTDI.cmake; +FindUSB-1.cmake8 I 'FindQSI.cmake 'FindUSB.cmake -FindMODBUS.cmake )FindSBIG.cmake$ IMacroOptionalFindPackage.cmake  )FindINDI.cmake /FindGPHOTO2.cmake  3MacroBoolTo01.cmake  7MacroLogFeature.cmake  +FindMEADE.cmake 'FindFLI.cmake )FindALUT.cmake -FindVorbis.cmake )FindNova.cmakeA /FindCFITSIO.cmake -FindAPOGEE.cmake ±±m˜…9ŠQtableNODESNODESCREATE TABLE NODES ( wc_id INTEGER NOT NULL REFERENCES WCROOT (id), local_relpath TEXT NOT NULL, op_depth INTEGER NOT NULL, parent_relpath TEXT, repos_id INTEGER REFERENCES REPOSITORY (id), repos_path TEXT, revision INTEGER, presence TEXT NOT NULL, moved_here INTEGER, moved_to TEXT, kind TEXT NOT NULL, properties BLOB, depth TEXT, checksum TEXT REFERENCES PRISTINE (checksum), symlink_target TEXT, changed_revision INTEGER, changed_date INTEGER, changed_author TEXT, translated_size INTEGER, last_mod_time INTEGER, dav_cache BLOB, file_external TEXT, PRIMARY KEY (wc_id, local_relpath, op_depth) ))=indexsqlite_autoindex_NODES_1NODESf)indexI_NODES_PARENTNODESCREATE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, op_depth) úgƒóìÞ×ÐÉ»´¦Ÿ˜‘Š­|uång H G ; 8 I                  A   ÝÝçL&‚''ƒQviewNODES_CURRENTNODES_CURRENTCREATE VIEW NODES_CURRENT AS SELECT * FROM nodes AS n WHERE op_depth = (SELECT MAX(op_depth) FROM nodes AS n2 WHERE n2.wc_id = n.wc_id AND n2.local_relpath = n.local_relpath)c!!viewNODES_BASENODES_BASECREATE VIEW NODES_BASE AS SELECT * FROM nodes WHERE op_depth = 0W5‚mtriggernodes_insert_triggernodesCREATE TRIGGER nodes_insert_trigger AFTER INSERT ON nodes WHEN NEW.checksum IS NOT NULL BEGIN UPDATE pristine SET refcount = refcount + 1 WHERE checksum = NEW.checksum; ENDW5‚mtriggernodes_delete_triggernodesCREATE TRIGGER nodes_delete_trigger AFTER DELETE ON nodes WHEN OLD.checksum IS NOT NULL BEGIN UPDATE pristine SET refcount = refcount - 1 WHERE checksum = OLD.checksum; END ØØ'‚LG„Etriggernodes_update_checksum_triggernodesCREATE TRIGGER nodes_update_checksum_trigger AFTER UPDATE OF checksum ON nodes WHEN NEW.checksum IS NOT OLD.checksum BEGIN UPDATE pristine SET refcount = refcount + 1 WHERE checksum = NEW.checksum; UPDATE pristine SET refcount = refcount - 1 WHERE checksum = OLD.checksum; ENDƒV†{tableEXTERNALSEXTERNALSCREATE TABLE EXTERNALS ( wc_id INTEGER NOT NULL REFERENCES WCROOT (id), local_relpath TEXT NOT NULL, parent_relpath TEXT NOT NULL, repos_id INTEGER NOT NULL REFERENCES REPOSITORY (id), presence TEXT NOT NULL, kind TEXT NOT NULL, def_local_relpath TEXT NOT NULL, def_repos_relpath TEXT NOT NULL, def_operational_revision TEXT, def_revision TEXT, PRIMARY KEY (wc_id, local_relpath) )     iiœ 1Eindexsqlite_autoindex_EXTERNALS_1EXTERNALSl1indexI_EXTERNALS_PARENTEXTERNALS CREATE INDEX I_EXTERNALS_PARENT ON EXTERNALS (wc_id, parent_relpath)s3ƒ!indexI_EXTERNALS_DEFINEDEXTERNALS!CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id, def_local_relpath, local_relpath) ¶¶Z]I! - UiFindAPOGEE.cmaketrunk/cmake_modules/FindAPOGEE.cmakeVnormalfile()$sha1$16b690cf365f8630ac442ebf7f833af70d1cd377ç©ÊÅ8ãIslovin¼ÌϤ Äa# / WiFindCFITSIO.cmaketrunk/cmake_modules/FindCFITSIO.cmakeVnormalfile()$sha1$52e62155c2e72ac59c0de18e4c9f41cdc8243823Õi•n"øslovin ÌϤ Äa Ábÿ! - UiFindVorbis.cmaketrunk/cmake_modules/FindVorbis.cmakeVnormalfile()$sha1$5f2ff8077502e5f711cd28daa42c780a78673a0fØi˜´sÇslovinDÌϤ Äa ) QiFindALUT.cmaketrunk/cmake_modules/FindALUT.cmakeVnormalfile()$sha1$33ceb4e5ec77adccc3d040ac30e22a3d53230ec1Øi˜´sÇslovin "ÌϤ Äa ' OiFindFLI.cmaketrunk/cmake_modules/FindFLI.cmakeVnormalfile()$sha1$d3c033542b5bca99854b388b368ca9928e279151Ò Îχ slovin¥ÌϤ Äa ©[©p.  7 _iMacroLogFeature.cmaketrunk/cmake_modules/MacroLogFeature.cmakeVnormalfile()$sha1$154b987e24e4b658c85049db4a9dc2b5f6f64d01Ôi^»z·¿rbrobertsÌϤ Äa" + SiFindMEADE.cmaketrunk/cmake_modules/FindMEADE.cmakeVnormalfile()$sha1$3fdf934be5b9e2c0986d00772be02b625f83dd99|[˜žâØrbroberts?ÌϤ Äa T¢Dæˆ*Ìn²T\ i Y$sha1$7cd6db08dc18116d79ddc4819320b05915510a60N$md5 $58a6d92484c0c5636b77ced170fe689c\ i Y$sha1$8d61d234c6b0af0e49b879a117e98bf520e646f8‹$md5 $2afb892b59b99d4a893515fd23f4e77d\i Y$sha1$154b987e24e4b658c85049db4a9dc2b5f6f64d01$md5 $d75b540ccf922fcae9ae879336a0b931\i Y$sha1$3fdf934be5b9e2c0986d00772be02b625f83dd99?$md5 $584f4af5e70a4fdd408b2237165c1d04\i Y$sha1$d3c033542b5bca99854b388b368ca9928e279151¥$md5 $01fb8c7d22ef411a2809af8a28491dd8\i Y$sha1$33ceb4e5ec77adccc3d040ac30e22a3d53230ec1 "$md5 $aa0df244413337f4d9d909671ed1fc14\i Y$sha1$5f2ff8077502e5f711cd28daa42c780a78673a0fD$md5 $075abd0e8f39648eca50a2b4b7868f81\iY$sha1$02e4bbe108ba9212080964375af2c597018def82"$md5 $cacb8f9fc879d884c81b93cda0734bd2\i Y$sha1$52e62155c2e72ac59c0de18e4c9f41cdc8243823 $md5 $97be6df253358722ebaa01a2546218c8\i Y$sha1$16b690cf365f8630ac442ebf7f833af70d1cd377¼$md5 $d4735dd4b2fd1cf22fc53c4a10a66903 T¢Dæˆ*Ìn²T\iY$sha1$19887b6ec14ec33603e1b607b7b9a46465f28fdc §$md5 $0d39e839da62d31afd64ac168b92d5ba\iY$sha1$f11698c011f8a2415f2dc91ca0346f409c570a3b p$md5 $00256acc48eeb42f9ed828a78edf36af\i Y$sha1$3215a9796455b10d5fa42058acaea6d4d6d9b3d5 ä$md5 $a737d46f1ac7762d8cdae27fc8f28f1c\iY$sha1$da9a7b326f32fd39ebe175557dc202f1d5d080ac Þ$md5 $6544e9eb08e43a24959810a78d39a4c8\i Y$sha1$24d962a5a4a382eb6f41aff987fd67dc6572e3b0-$md5 $57c7bd35bd09015203f5742dd75624b2\i Y$sha1$6e2aa21c1cb029a5a194a1cc844dd9fca050dcf8ç$md5 $bd5835de74f1b9fb95b4018ac435ed01\i Y$sha1$dec4f6d462f3dd5911461f1ddda2c9f2a11be794$md5 $9c4d0a35e319350e38b7c9448a759398\ i Y$sha1$a8db819badbb1fba4e2abbba441c3b159d4dce6bö$md5 $4a68369ed26739a39b4853639a4e3783\ i Y$sha1$327c35cff6ca2c8002d5ef3034effe3d9af4eea9*$md5 $20c7d061dc7250f67d2121f4d9c90892\ iY$sha1$e265b9aa0e214f93895ea72dfb47721d6b0d388b $md5 $b437271ef8dfe4fc617389fb93bc7aad ½½€ Äb@  I qiMacroOptionalFindPackage.cmaketrunk/cmake_modules/MacroOptionalFindPackage.cmakeVnormalfile()$sha1$327c35cff6ca2c8002d5ef3034effe3d9af4eea9Ôi^»z·¿rbroberts*ÌϤ Ô ) QiFindSBIG.cmaketrunk/cmake_modules/FindSBIG.cmakeVnormalfile()$sha1$a8db819badbb1fba4e2abbba441c3b159d4dce6bàjSixçkslovinöÌϤ Ô! - UiFindMODBUS.cmaketrunk/cmake_modules/FindMODBUS.cmakeVnormalfile()$sha1$dec4f6d462f3dd5911461f1ddda2c9f2a11be794åj„ªCslovinÌϤ Ô ' OiFindUSB.cmaketrunk/cmake_modules/FindUSB.cmakeVnormalfile()$sha1$6e2aa21c1cb029a5a194a1cc844dd9fca050dcf8½ÉÿÄB=slovinçÌϤ Ô ' OiFindQSI.cmaketrunk/cmake_modules/FindQSI.cmakeVnormalfile()$sha1$24d962a5a4a382eb6f41aff987fd67dc6572e3b0½ÉÿÄB=slovin-ÌϤ ã¡ ¾¾^ ) QiFindINDI.cmaketrunk/cmake_modules/FindINDI.cmakeVnormalfile()$sha1$3215a9796455b10d5fa42058acaea6d4d6d9b3d5TÎ ŒÀ'—slovin äÎäÄË|"8 + SiFindUSB-1.cmaketrunk/cmake_modules/FindUSB-1.cmakeVnormalfile()$sha1$4ddf9e65ea9cf819925428199ce93e8ed441fc74ûê&Ps'wpolakovicaê,žŒÞ¶z; ) QiDFindFTDI.cmaketrunk/cmake_modules/FindFTDI.cmakeVnormalfile()$sha1$a59f5398e9cbfe4cb78ed21bd94732b0b1ccbfb7ê-'ü{çslovinê-/žî.(svn:wc:ra_dav:version-url 61 /p/indi/code/!svn/ver/1025/trunk/cmake_modules/FindFTDI.cmake)}A ) QiDFindNova.cmaketrunk/cmake_modules/FindNova.cmakeVnormalfile()$sha1$813425deb369dbc58825058ac44bdf9bc81fe133êm[Dº8polakovicêpá“*(svn:wc:ra_dav:version-url 61 /p/indi/code/!svn/ver/1055/trunk/cmake_modules/FindNova.cmake) ¬S¬e#  / WiFindGPHOTO2.cmaketrunk/cmake_modules/FindGPHOTO2.cmakeVnormalfile()$sha1$7cd6db08dc18116d79ddc4819320b05915510a60\¶kÀ7&tslovinNÌϤ Äa*  3 [iMacroBoolTo01.cmaketrunk/cmake_modules/MacroBoolTo01.cmakeVnormalfile()$sha1$8d61d234c6b0af0e49b879a117e98bf520e646f8Ôi^»z·¿rbroberts‹ÌϤ Äa Ð6i›Î4gšÐÍ2i$sha1$4ddf9e65ea9cf819925428199ce93e8ed441fc742i$sha1$02e4bbe108ba9212080964375af2c597018def822i$sha1$154b987e24e4b658c85049db4a9dc2b5f6f64d011i $sha1$16b690cf365f8630ac442ebf7f833af70d1cd3772i$sha1$19887b6ec14ec33603e1b607b7b9a46465f28fdc2i$sha1$24d962a5a4a382eb6f41aff987fd67dc6572e3b02i$sha1$3215a9796455b10d5fa42058acaea6d4d6d9b3d52i$sha1$327c35cff6ca2c8002d5ef3034effe3d9af4eea9 2i$sha1$33ceb4e5ec77adccc3d040ac30e22a3d53230ec12i$sha1$3fdf934be5b9e2c0986d00772be02b625f83dd992i$sha1$52e62155c2e72ac59c0de18e4c9f41cdc8243823 i5œhÏ›Îi4gšÍ2i$sha1$d4842f31c51b5c5c8defb304e71673a8735408232i$sha1$7b1a38d9fa9107795a6137e22f83bf9955fe97602i$sha1$813425deb369dbc58825058ac44bdf9bc81fe1332i$sha1$a59f5398e9cbfe4cb78ed21bd94732b0b1ccbfb72i$sha1$6e2aa21c1cb029a5a194a1cc844dd9fca050dcf82i$sha1$7cd6db08dc18116d79ddc4819320b05915510a60 2i$sha1$8d61d234c6b0af0e49b879a117e98bf520e646f8 2i$sha1$a8db819badbb1fba4e2abbba441c3b159d4dce6b 2i$sha1$d3c033542b5bca99854b388b368ca9928e2791512i$sha1$da9a7b326f32fd39ebe175557dc202f1d5d080ac2i$sha1$dec4f6d462f3dd5911461f1ddda2c9f2a11be7942i$sha1$e265b9aa0e214f93895ea72dfb47721d6b0d388b 2i$sha1$f11698c011f8a2415f2dc91ca0346f409c570a3b *¢Dæˆ*\i Y$sha1$d4842f31c51b5c5c8defb304e71673a8735408233$md5 $0d7bf3e59fc40328a82955c8ec2f2d4a\i Y$sha1$7b1a38d9fa9107795a6137e22f83bf9955fe9760 „$md5 $b90d4e4e4ff94bd12a38192d2f3b6dcb\i Y$sha1$813425deb369dbc58825058ac44bdf9bc81fe133$md5 $38c8493dedf498937ee9f347c3187e87\i Y$sha1$a59f5398e9cbfe4cb78ed21bd94732b0b1ccbfb7$md5 $928a62289f1e8ba1d27a69b3895ad518\i Y$sha1$4ddf9e65ea9cf819925428199ce93e8ed441fc74a$md5 $33ba594d3fd2af8e82b4f9d3b5547bd5 LIIBK‚G - UiHFindOpenAL.cmaketrunk/cmake_modules/FindOpenAL.cmakeVnormalfile()$sha1$7b1a38d9fa9107795a6137e22f83bf9955fe9760Lë(J(]Fslovin „ë;0 ª(svn:wc:ra_dav:version-url 63 /p/indi/code/!svn/ver/1100/trunk/cmake_modules/FindOpenAL.cmake)ö‚H 1 YiLFindFISHCAMP.cmaketrunk/cmake_modules/FindFISHCAMP.cmakeVnormalfile()$sha1$d4842f31c51b5c5c8defb304e71673a873540823Ië#Xr¹slovin3ë;0 ¹¶(svn:wc:ra_dav:version-url 65 /p/indi/code/!svn/ver/1097/trunk/cmake_modules/FindFISHCAMP.cmake)2I  3:&trunk/cmake_modulesVnormaldir(svn:ignore 8 *.user* )infinityLë(J(]Fslovin(svn:wc:ra_dav:version-url 46 /p/indi/code/!svn/ver/1100/trunk/cmake_modules)libindi-0.9.7/cmake_modules/.svn/entries0000644000175000017500000000000312241463551017205 0ustar jasemjasem12 libindi-0.9.7/cmake_modules/.svn/format0000644000175000017500000000000312241463551017024 0ustar jasemjasem12 libindi-0.9.7/cmake_modules/.svn/tmp/0000755000175000017500000000000012241463551016420 5ustar jasemjasemlibindi-0.9.7/cmake_modules/FindMODBUS.cmake0000644000175000017500000000320112241463551017524 0ustar jasemjasem# - Try to find libmodbus # Once done this will define # # MODBUS_FOUND - system has MODBUS # MODBUS_INCLUDE_DIR - the MODBUS include directory # MODBUS_LIBRARIES - Link these to use MODBUS # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) # in cache already set(MODBUS_FOUND TRUE) message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}") else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) find_path(MODBUS_INCLUDE_DIR modbus.h PATH_SUFFIXES modbus ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(MODBUS_LIBRARIES NAMES modbus PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_INCLUDES ${MODBUS_INCLUDE_DIR}) set(CMAKE_REQUIRED_LIBRARIES ${MODBUS_LIBRARIES}) if(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) set(MODBUS_FOUND TRUE) else (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) set(MODBUS_FOUND FALSE) endif(MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) if (MODBUS_FOUND) if (NOT MODBUS_FIND_QUIETLY) message(STATUS "Found libmodbus: ${MODBUS_LIBRARIES}") endif (NOT MODBUS_FIND_QUIETLY) else (MODBUS_FOUND) if (MODBUS_FIND_REQUIRED) message(FATAL_ERROR "libmodbus not found. Please install libmodbus-devel. https://launchpad.net/libmodbus/") endif (MODBUS_FIND_REQUIRED) endif (MODBUS_FOUND) mark_as_advanced(MODBUS_INCLUDE_DIR MODBUS_LIBRARIES) endif (MODBUS_INCLUDE_DIR AND MODBUS_LIBRARIES) libindi-0.9.7/cmake_modules/FindGPHOTO2.cmake0000644000175000017500000000311612241463551017622 0ustar jasemjasem# - Try to find libgphoto2 # Once done this will define # # LIBGPHOTO2_FOUND - system has libgphoto2 # LIBGPHOTO2_INCLUDE_DIR - the libgphoto2 include directory # LIBGPHOTO2_LIBRARIES - Link these to use libghoto2 # Copyright (c) 2009, Geoffrey Hausheer # Based on FindINDI by Jasem Mutlaq # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) # in cache already set(LIBGPHOTO2_FOUND TRUE) message(STATUS "Found libgphoto2: ${LIBGPHOTO2_LIBRARIES}") else (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) find_path(LIBGPHOTO2_INCLUDE_DIR gphoto2.h PATH_SUFFIXES gphoto2 ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(LIBGPHOTO2_LIBRARIES NAMES gphoto2 PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) set(LIBGPHOTO2_FOUND TRUE) else (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) set(LIBGPHOTO2_FOUND FALSE) endif(LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) if (LIBGPHOTO2_FOUND) if (NOT LIBGPHOTO2_FIND_QUIETLY) message(STATUS "Found libgphoto2: ${LIBGPHOTO2_LIBRARIES}") endif (NOT LIBGPHOTO2_FIND_QUIETLY) else (LIBGPHOTO2_FOUND) if (LIBGPHOTO2_FIND_REQUIRED) message(FATAL_ERROR "libgphoto2 not found.") endif (LIBGPHOTO2_FIND_REQUIRED) endif (LIBGPHOTO2_FOUND) mark_as_advanced(LIBGPHOTO2_INCLUDE_DIR LIBGPHOTO2_LIBRARIES) endif (LIBGPHOTO2_INCLUDE_DIR AND LIBGPHOTO2_LIBRARIES) libindi-0.9.7/cmake_modules/FindOpenAL.cmake0000644000175000017500000000660412241463551017663 0ustar jasemjasem# Locate OpenAL # This module defines # OPENAL_LIBRARY # OPENAL_FOUND, if false, do not try to link to OpenAL # OPENAL_INCLUDE_DIR, where to find the headers # # $OPENALDIR is an environment variable that would # correspond to the ./configure --prefix=$OPENALDIR # used in building OpenAL. # # Created by Eric Wing. This was influenced by the FindSDL.cmake module. # This makes the presumption that you are include al.h like # #include "al.h" # and not # #include # The reason for this is that the latter is not entirely portable. # Windows/Creative Labs does not by default put their headers in AL/ and # OS X uses the convention . # # For Windows, Creative Labs seems to have added a registry key for their # OpenAL 1.1 installer. I have added that key to the list of search paths, # however, the key looks like it could be a little fragile depending on # if they decide to change the 1.00.0000 number for bug fix releases. # Also, they seem to have laid down groundwork for multiple library platforms # which puts the library in an extra subdirectory. Currently there is only # Win32 and I have hardcoded that here. This may need to be adjusted as # platforms are introduced. # The OpenAL 1.0 installer doesn't seem to have a useful key I can use. # I do not know if the Nvidia OpenAL SDK has a registry key. # # For OS X, remember that OpenAL was added by Apple in 10.4 (Tiger). # To support the framework, I originally wrote special framework detection # code in this module which I have now removed with CMake's introduction # of native support for frameworks. # In addition, OpenAL is open source, and it is possible to compile on Panther. # Furthermore, due to bugs in the initial OpenAL release, and the # transition to OpenAL 1.1, it is common to need to override the built-in # framework. # Per my request, CMake should search for frameworks first in # the following order: # ~/Library/Frameworks/OpenAL.framework/Headers # /Library/Frameworks/OpenAL.framework/Headers # /System/Library/Frameworks/OpenAL.framework/Headers # # On OS X, this will prefer the Framework version (if found) over others. # People will have to manually change the cache values of # OPENAL_LIBRARY to override this selection or set the CMake environment # CMAKE_INCLUDE_PATH to modify the search paths. FIND_PATH(OPENAL_INCLUDE_DIR al.h PATHS $ENV{OPENALDIR} NO_DEFAULT_PATH PATH_SUFFIXES include/AL include/OpenAL include ) FIND_PATH(OPENAL_INCLUDE_DIR al.h PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw # Fink /opt/local # DarwinPorts /opt/csw # Blastwave /opt [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir] PATH_SUFFIXES include/AL include/OpenAL include ) FIND_LIBRARY(OPENAL_LIBRARY NAMES OpenAL al openal OpenAL32 PATHS $ENV{OPENALDIR} NO_DEFAULT_PATH PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64 ) FIND_LIBRARY(OPENAL_LIBRARY NAMES OpenAL al openal OpenAL32 PATHS ~/Library/Frameworks /Library/Frameworks /usr/local /usr /sw /opt/local /opt/csw /opt [HKEY_LOCAL_MACHINE\\SOFTWARE\\Creative\ Labs\\OpenAL\ 1.1\ Software\ Development\ Kit\\1.00.0000;InstallDir] PATH_SUFFIXES lib64 lib libs64 libs libs/Win32 libs/Win64 ) SET(OPENAL_FOUND "NO") IF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR) SET(OPENAL_FOUND "YES") ENDIF(OPENAL_LIBRARY AND OPENAL_INCLUDE_DIR) libindi-0.9.7/cmake_modules/FindUSB-1.cmake0000644000175000017500000000754112241463551017335 0ustar jasemjasem# - Try to find libusb-1.0 # Once done this will define # # LIBUSB_1_FOUND - system has libusb # LIBUSB_1_INCLUDE_DIRS - the libusb include directory # LIBUSB_1_LIBRARIES - Link these to use libusb # LIBUSB_1_DEFINITIONS - Compiler switches required for using libusb # # Adapted from cmake-modules Google Code project # # Copyright (c) 2006 Andreas Schneider # # (Changes for libusb) Copyright (c) 2008 Kyle Machulis # # Redistribution and use is allowed according to the terms of the New BSD license. # # CMake-Modules Project New BSD License # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the name of the CMake-Modules Project nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # if (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) # in cache already set(LIBUSB_FOUND TRUE) else (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) find_path(LIBUSB_1_INCLUDE_DIR NAMES libusb.h PATHS /usr/include /usr/local/include /opt/local/include /sw/include PATH_SUFFIXES libusb-1.0 ) find_library(LIBUSB_1_LIBRARY NAMES usb-1.0 PATHS /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) set(LIBUSB_1_INCLUDE_DIRS ${LIBUSB_1_INCLUDE_DIR} ) set(LIBUSB_1_LIBRARIES ${LIBUSB_1_LIBRARY} ) if (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) set(LIBUSB_1_FOUND TRUE) endif (LIBUSB_1_INCLUDE_DIRS AND LIBUSB_1_LIBRARIES) if (LIBUSB_1_FOUND) if (NOT USB-1_FIND_QUIETLY) message(STATUS "Found libusb-1.0:") message(STATUS " - Includes: ${LIBUSB_1_INCLUDE_DIRS}") message(STATUS " - Libraries: ${LIBUSB_1_LIBRARIES}") endif (NOT USB-1_FIND_QUIETLY) set(CMAKE_REQUIRED_INCLUDES ${LIBUSB_1_INCLUDE_DIRS}) set(CMAKE_REQUIRED_LIBRARIES ${LIBUSB_1_LIBRARIES}) include (CheckCXXSourceCompiles) check_cxx_source_compiles("#include int main() { libusb_error_name(0); return 0; }" ERROR_NAME_COMPILE) if (NOT ERROR_NAME_COMPILE) add_definitions("-DNO_ERROR_NAME") message(STATUS " - 1.0.8 or older") endif (NOT ERROR_NAME_COMPILE) else (LIBUSB_1_FOUND) if (USB-1_FIND_REQUIRED) message(FATAL_ERROR "Could not find libusb-1.0. Please install libusb-1.0 along with the development package.") endif (USB-1_FIND_REQUIRED) endif (LIBUSB_1_FOUND) # show the LIBUSB_1_INCLUDE_DIRS and LIBUSB_1_LIBRARIES variables only in the advanced view mark_as_advanced(LIBUSB_1_INCLUDE_DIRS LIBUSB_1_LIBRARIES) endif (LIBUSB_1_LIBRARIES AND LIBUSB_1_INCLUDE_DIRS) libindi-0.9.7/cmake_modules/FindFTDI.cmake0000644000175000017500000000240212241463551017263 0ustar jasemjasem# - Try to find FTDI # Once done this will define # # FTDI_FOUND - system has FTDI # FTDI_INCLUDE_DIR - the FTDI include directory # FTDI_LIBRARIES - Link these to use FTDI # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) # in cache already set(FTDI_FOUND TRUE) message(STATUS "Found libftdi: ${FTDI_LIBRARIES}") else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) find_path(FTDI_INCLUDE_DIR ftdi.h ${_obIncDir} ${GNUWIN32_DIR}/include ) find_library(FTDI_LIBRARIES NAMES ftdi PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) if(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) set(FTDI_FOUND TRUE) else (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) set(FTDI_FOUND FALSE) endif(FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) if (FTDI_FOUND) if (NOT FTDI_FIND_QUIETLY) message(STATUS "Found FTDI: ${FTDI_LIBRARIES}") endif (NOT FTDI_FIND_QUIETLY) else (FTDI_FOUND) if (FTDI_FIND_REQUIRED) message(FATAL_ERROR "FTDI not found. Please install libftdi-dev") endif (FTDI_FIND_REQUIRED) endif (FTDI_FOUND) mark_as_advanced(FTDI_INCLUDE_DIR FTDI_LIBRARIES) endif (FTDI_INCLUDE_DIR AND FTDI_LIBRARIES) libindi-0.9.7/cmake_modules/FindVorbis.cmake0000644000175000017500000000210412241463551020000 0ustar jasemjasem# - Find vorbis # Find the native vorbis includes and libraries # # VORBIS_INCLUDE_DIR - where to find vorbis.h, etc. # VORBIS_LIBRARIES - List of libraries when using vorbis(file). # VORBIS_FOUND - True if vorbis found. if(VORBIS_INCLUDE_DIR) # Already in cache, be silent set(VORBIS_FIND_QUIETLY TRUE) endif(VORBIS_INCLUDE_DIR) find_path(VORBIS_INCLUDE_DIR vorbis/vorbisfile.h) find_library(OGG_LIBRARY NAMES ogg) find_library(VORBIS_LIBRARY NAMES vorbis) find_library(VORBISFILE_LIBRARY NAMES vorbisfile) # Handle the QUIETLY and REQUIRED arguments and set VORBIS_FOUND to TRUE if # all listed variables are TRUE. include(FindPackageHandleStandardArgs) find_package_handle_standard_args(VORBIS DEFAULT_MSG VORBIS_INCLUDE_DIR OGG_LIBRARY VORBIS_LIBRARY VORBIS_LIBRARY) if(VORBIS_FOUND) set(VORBIS_LIBRARIES ${VORBISFILE_LIBRARY} ${VORBIS_LIBRARY} ${OGG_LIBRARY}) else(VORBIS_FOUND) set(VORBIS_LIBRARIES) endif(VORBIS_FOUND) mark_as_advanced(VORBIS_INCLUDE_DIR) mark_as_advanced(OGG_LIBRARY VORBIS_LIBRARY VORBISFILE_LIBRARY) libindi-0.9.7/cmake_modules/FindFISHCAMP.cmake0000644000175000017500000000246312241463551017736 0ustar jasemjasem# - Try to find FISHCAMP CCD # Once done this will define # # FISHCAMP_FOUND - system has FISHCAMP # FISHCAMP_LIBRARIES - Link these to use FISHCAMP # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (FISHCAMP_LIBRARIES) # in cache already set(FISHCAMP_FOUND TRUE) message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}") else (FISHCAMP_LIBRARIES) find_library(FISHCAMP_LIBRARIES NAMES fishcamp PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_LIBRARIES ${FISHCAMP_LIBRARIES}) if(FISHCAMP_LIBRARIES) set(FISHCAMP_FOUND TRUE) else (FISHCAMP_LIBRARIES) set(FISHCAMP_FOUND FALSE) endif(FISHCAMP_LIBRARIES) if (FISHCAMP_FOUND) if (NOT FISHCAMP_FIND_QUIETLY) message(STATUS "Found FISHCAMP: ${FISHCAMP_LIBRARIES}") endif (NOT FISHCAMP_FIND_QUIETLY) else (FISHCAMP_FOUND) if (FISHCAMP_FIND_REQUIRED) message(FATAL_ERROR "FISHCAMP not found. Please install FISHCAMP library. http://www.indilib.org") endif (FISHCAMP_FIND_REQUIRED) endif (FISHCAMP_FOUND) mark_as_advanced(FISHCAMP_LIBRARIES) endif (FISHCAMP_LIBRARIES) libindi-0.9.7/cmake_modules/FindMEADE.cmake0000644000175000017500000000247712241463551017364 0ustar jasemjasem# - Try to find Meade DSI Library. # Once done this will define # # MEADEDSI_FOUND - system has Meade DSI # MEADEDSI_LIBRARIES - Link these to use Meade DSI # Copyright (c) 2006, Jasem Mutlaq # Based on FindLibfacile by Carsten Niehaus, # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. if (MEADEDSI_LIBRARIES) # in cache already set(MEADEDSI_FOUND TRUE) message(STATUS "Found MEADEDSI: ${MEADEDSI_LIBRARIES}") else (MEADEDSI_LIBRARIES) find_library(MEADEDSI_LIBRARIES NAMES dsi PATHS ${_obLinkDir} ${GNUWIN32_DIR}/lib ) set(CMAKE_REQUIRED_LIBRARIES ${MEADEDSI_LIBRARIES}) if(MEADEDSI_LIBRARIES) set(MEADEDSI_FOUND TRUE) else (MEADEDSI_LIBRARIES) set(MEADEDSI_FOUND FALSE) endif(MEADEDSI_LIBRARIES) if (MEADEDSI_FOUND) if (NOT MEADEDSI_FIND_QUIETLY) message(STATUS "Found Meade DSI: ${MEADEDSI_LIBRARIES}") endif (NOT MEADEDSI_FIND_QUIETLY) else (MEADEDSI_FOUND) if (MEADEDSI_FIND_REQUIRED) message(FATAL_ERROR "Meade DSI not found. Please install Meade DSI library. http://linuxdsi.sourceforge.net") endif (MEADEDSI_FIND_REQUIRED) endif (MEADEDSI_FOUND) mark_as_advanced(MEADEDSI_LIBRARIES) endif (MEADEDSI_LIBRARIES) libindi-0.9.7/COPYING.LGPL0000644000175000017500000006364212241463551013727 0ustar jasemjasem GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libindi-0.9.7/drivers.xml0000644000175000017500000001607112241463551014331 0ustar jasemjasem indi_lx200basic 1.0 indi_lx200autostar 2.0 indi_lx200classic 2.0 indi_lx200gps 2.0 indi_lx200_16 2.0 indi_lx200autostar 2.0 indi_lx200autostar 2.0 indi_lx200autostar 2.0 indi_lx200autostar 2.0 indi_lx200ap 1.0 indi_celestron_gps 2.0 indi_celestron_gps 2.0 indi_lx200basic 1.0 indi_synscan 1.0 indi_synscan 0.1 indi_lx200basic 1.0 indi_lx200basic 1.0 indi_temma 0.1 indi_skycommander 0.1 indi_lx200basic 1.0 indi_intelliscope 0.2 indi_intelliscope 0.2 indi_synscan 1.0 indi_synscan 1.0 indi_synscan 1.0 indi_synscan 1.0 indi_magellan1 1.0 indi_ieq45_8406 0.1 indi_ieq45_8407 0.1 indi_simulator_telescope 1.0 indi_simulator_focus 1.0 indi_robo_focus 1.0 indi_tcfs_focus 0.1 indi_tcfs3_focus 0.1 indi_simulator_ccd 1.0 indi_trutech_wheel 0.1 indi_simulator_wheel 1.0 indi_v4l_generic 1.0 indi_v4l_philips 1.0 indi_meade_lpi 0.1 indi_sbig_stv 0.1 indi_gpusb 0.1 indi_joystick 0.1 libindi-0.9.7/base64.h0000644000175000017500000000326612241463551013370 0ustar jasemjasem#if 0 INDI Copyright (C) 2003 Elwood C. Downey 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 #ifndef BASE64_H #define BASE64_H #ifdef __cplusplus extern "C" { #endif /** * \defgroup base64 Base 64 Functions: Convert from and to base64 */ /*@{*/ /** \brief Convert bytes array to base64. \param out output buffer in base64. The buffer size must be at least (4 * inlen / 3 + 4) bytes long. \param in input binary buffer \param inlen number of bytes to convert \return 0 on success, -1 on failure. */ extern int to64frombits(unsigned char *out, const unsigned char *in, int inlen); /** \brief Convert base64 to bytes array. \param out output buffer in bytes. The buffer size must be at least (3 * size_of_in_buffer / 4) bytes long. \param in input base64 buffer \return 0 on success, -1 on failure. */ extern int from64tobits(char *out, const char *in); /*@}*/ #ifdef __cplusplus } #endif #endif libindi-0.9.7/base64.c0000644000175000017500000001611512241463551013360 0ustar jasemjasem#if 0 INDI Copyright (C) 2003 Elwood C. Downey 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 Adapted from code written by Eric S. Raymond #endif /* Pair of functions to convert to/from base64. * Also can be used to build a standalone utility and a loopback test. * see http://www.faqs.org/rfcs/rfc3548.html */ /** \file base64.c \brief Pair of functions to convert to/from base64. */ #include #include "base64.h" static const char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define BAD (-1) static const char base64val[] = { BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD,BAD, BAD,BAD,BAD, 62, BAD,BAD,BAD, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,BAD,BAD, BAD,BAD,BAD,BAD, BAD, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,BAD, BAD,BAD,BAD,BAD, BAD, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,BAD, BAD,BAD,BAD,BAD }; #define DECODE64(c) (isascii(c) ? base64val[c] : BAD) /* convert inlen raw bytes at in to base64 string (NUL-terminated) at out. * out size should be at least 4*inlen/3 + 4. * return length of out (sans trailing NUL). */ int to64frombits(unsigned char *out, const unsigned char *in, int inlen) { unsigned char *out0 = out; for (; inlen >= 3; inlen -= 3) { *out++ = base64digits[in[0] >> 2]; *out++ = base64digits[((in[0] << 4) & 0x30) | (in[1] >> 4)]; *out++ = base64digits[((in[1] << 2) & 0x3c) | (in[2] >> 6)]; *out++ = base64digits[in[2] & 0x3f]; in += 3; } if (inlen > 0) { unsigned char fragment; *out++ = base64digits[in[0] >> 2]; fragment = (in[0] << 4) & 0x30; if (inlen > 1) fragment |= in[1] >> 4; *out++ = base64digits[fragment]; *out++ = (inlen < 2) ? '=' : base64digits[(in[1] << 2) & 0x3c]; *out++ = '='; } *out = '\0'; return (out-out0); } /* convert base64 at in to raw bytes out, returning count or <0 on error. * base64 may contain any embedded whitespace. * out should be at least 3/4 the length of in. */ int from64tobits(char *out, const char *in) { int len = 0; register unsigned char digit1, digit2, digit3, digit4; do { do {digit1 = *in++;} while (isspace(digit1)); if (DECODE64(digit1) == BAD) return(-1); do {digit2 = *in++;} while (isspace(digit2)); if (DECODE64(digit2) == BAD) return(-2); do {digit3 = *in++;} while (isspace(digit3)); if (digit3 != '=' && DECODE64(digit3) == BAD) return(-3); do {digit4 = *in++;} while (isspace(digit4)); if (digit4 != '=' && DECODE64(digit4) == BAD) return(-4); *out++ = (DECODE64(digit1) << 2) | (DECODE64(digit2) >> 4); ++len; if (digit3 != '=') { *out++ = ((DECODE64(digit2) << 4) & 0xf0) | (DECODE64(digit3) >> 2); ++len; if (digit4 != '=') { *out++ = ((DECODE64(digit3) << 6) & 0xc0) | DECODE64(digit4); ++len; } } while (isspace(*in)) in++; } while (*in && digit4 != '='); return (len); } #ifdef BASE64_PROGRAM /* standalone program that converts to/from base64. * cc -o base64 -DBASE64_PROGRAM base64.c */ #include #include #include static void usage (char *me) { fprintf (stderr, "Purpose: convert stdin to/from base64 on stdout\n"); fprintf (stderr, "Usage: %s {-t,-f}\n", me); exit (1); } int main (int ac, char *av[]) { int to64 = 1; /* decide whether to or from base64 */ if (ac == 2 && strcmp (av[1], "-f") == 0) to64 = 0; else if (ac != 1 && (ac != 2 || strcmp (av[1], "-t"))) usage (av[0]); if (to64) { unsigned char *rawin, *b64; int i, n, nrawin, nb64; /* read raw on stdin until EOF */ rawin = malloc(4096); nrawin = 0; while ((n = fread (rawin+nrawin, 1, 4096, stdin)) > 0) rawin = realloc (rawin, (nrawin+=n)+4096); /* convert to base64 */ b64 = malloc (4*nrawin/3+4); nb64 = to64frombits(b64, rawin, nrawin); /* pretty print */ for (i = 0; i < nb64; i += 72) printf ("%.*s\n", 72, b64+i); } else { unsigned char *raw, *b64; int n, nraw, nb64; /* read base64 on stdin until EOF */ b64 = malloc(4096); nb64 = 0; while ((n = fread (b64+nb64, 1, 4096, stdin)) > 0) b64 = realloc (b64, (nb64+=n)+4096); b64[nb64] = '\0'; /* convert to raw */ raw = malloc (3*nb64/4); nraw = from64tobits(raw, b64); if (nraw < 0) { fprintf (stderr, "base64 conversion error: %d\n", nraw); return (1); } /* write */ fwrite (raw, 1, nraw, stdout); } return (0); } #endif #ifdef LOOPBACK_TEST /* standalone test that reads binary on stdin, converts to base64 and back, * then compares. exit 0 if compares the same else 1 */ #include #include #include int main (int ac, char *av[]) { unsigned char *rawin, *b64, *rawback; int n, nrawin, nrawback, nb64; /* read raw on stdin until EOF */ rawin = malloc(4096); nrawin = 0; while ((n = fread (rawin+nrawin, 1, 4096, stdin)) > 0) rawin = realloc (rawin, (nrawin+=n)+4096); /* convert to base64 */ b64 = malloc (4*nrawin*3 + 4); nb64 = to64frombits(b64, rawin, nrawin); /* convert back to raw */ rawback = malloc (3*nb64/4); nrawback = from64tobits(rawback, b64); if (nrawback < 0) { fprintf (stderr, "base64 error: %d\n", nrawback); return(1); } if (nrawback != nrawin) { fprintf (stderr, "base64 back length %d != %d\n", nrawback, nrawin); return(1); } /* compare */ if (memcmp (rawback, rawin, nrawin)) { fprintf (stderr, "compare error\n"); return (1); } /* success */ return (0); } #endif /* For RCS Only -- Do Not Edit */ static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile$ $Date: 2006-09-30 14:19:41 +0300 (Sat, 30 Sep 2006) $ $Revision: 590506 $ $Name: $"}; libindi-0.9.7/indidevapi.h0000644000175000017500000011076712241463551014425 0ustar jasemjasem#if 0 INDI Copyright (C) 2003-2006 Elwood C. Downey Modified by Jasem Mutlaq (2003-2006) 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 #ifndef INDI_DEVAPI_H #define INDI_DEVAPI_H /** \file indidevapi.h \brief Interface to the reference INDI C API device implementation on the Device Driver side. * \author Elwood C. Downey \author Jasem Mutlaq This file is divided into two main sections:\n
  1. Functions the INDI device driver framework defines which the Driver may call:
    • IDxxx functions to send messages to an INDI client.
    • IExxx functions to implement the event driven model.
    • IUxxx functions to perform handy utility functions.
  2. Functions the INDI device driver framework calls which the Driver must define:
    • ISxxx to respond to messages from a Client.

These functions are the interface to the INDI C-language Device Driver reference implementation library. Any driver that uses this interface is expected to #include "indidevapi.h" and to link with indidrivermain.o and eventloop.o. Indidevapi.h further includes indiapi.h. The former contains the prototypes for the functions documented here, although many functions take arguments defined in the latter.

These functions make it much easier to write a compliant INDI driver than starting from scratch, and also serve as a concrete example of the interactions an INDI driver, in any language, is expected to accommodate.

The reference driver framework and the optimizations made within the reference indiserver both assume and require that one driver program implements exactly one logical INDI device.

The functions in this framework fall into two broad categories. Some are functions that a driver must define because they are called by the reference framework; these functions begin with IS. The remaining functions are library utilities a driver may use to do important operations.

A major point to realize is that an INDI driver built with this framework does not contain the C main() function. As soon as a driver begins executing, it listens on stdin for INDI messages. Only when a valid and appropriate message is received will it then call the driver via one of the IS functions. The driver is then expected to respond promptly by calling one of the ID library functions. It may also use any of the IU utility functions as desired to make processing a message easier.

Rather separate from these IS, ID and IU functions are a collection of functions that utilize the notion of a callback. In a callback design, the driver registers a function with the framework to be called under certain circumstances. When said circumstances occur, the framework will call the callback function. The driver never calls these callbacks directly. These callback functions begin with IE. They can arrange for a callback function to be called under three kinds of circumstances: when a given file descriptor may be read without blocking (because either data is available or EOF has been encountered), when a given time interval has elapsed, or when the framework has nothing urgent to do. The callback functions for each circumstance must be written according to a well defined prototype since, after all, the framework must know how to call the callback correctlty.

*/ /******************************************************************************* * get the data structures */ #include "indiapi.h" #include "lilxml.h" /******************************************************************************* ******************************************************************************* * * Functions the INDI device driver framework defines which the Driver may call * ******************************************************************************* ******************************************************************************* */ #ifdef __cplusplus extern "C" { #endif /** * \defgroup d2cFunctions IDDef Functions: Functions drivers call to define their properties to clients.

Each of the following functions creates the appropriate XML formatted INDI message from its arguments and writes it to stdout. From there, is it typically read by indiserver which then sends it to the clients that have expressed interest in messages from the Device indicated in the message.

In addition to type-specific arguments, all end with a printf-style format string, and appropriate subsequent arguments, that form the \param msg attribute within the INDI message. If the format argument is NULL, no message attribute is included with the message. Note that a \e timestamp attribute is also always added automatically based on the clock on the computer on which this driver is running.

*/ /*@{*/ /** \brief Tell client to create a text vector property. \param t pointer to the vector text property to be defined. \param msg message in printf style to send to the client. May be NULL. */ extern void IDDefText (const ITextVectorProperty *t, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to create a number number property. \param n pointer to the vector number property to be defined. \param msg message in printf style to send to the client. May be NULL. */ extern void IDDefNumber (const INumberVectorProperty *n, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to create a switch vector property. \param s pointer to the vector switch property to be defined. \param msg message in printf style to send to the client. May be NULL. */ extern void IDDefSwitch (const ISwitchVectorProperty *s, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to create a light vector property. \param l pointer to the vector light property to be defined. \param msg message in printf style to send to the client. May be NULL. */ extern void IDDefLight (const ILightVectorProperty *l, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to create a BLOB vector property. \param b pointer to the vector BLOB property to be defined. \param msg message in printf style to send to the client. May be NULL. */ extern void IDDefBLOB (const IBLOBVectorProperty *b, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /*@}*/ /** * \defgroup d2cuFunctions IDSet Functions: Functions drivers call to tell clients of new values for existing properties. */ /*@{*/ /** \brief Tell client to update an existing text vector property. \param t pointer to the vector text property. \param msg message in printf style to send to the client. May be NULL. */ extern void IDSetText (const ITextVectorProperty *t, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to update an existing number vector property. \param n pointer to the vector number property. \param msg message in printf style to send to the client. May be NULL. */ extern void IDSetNumber (const INumberVectorProperty *n, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to update an existing switch vector property. \param s pointer to the vector switch property. \param msg message in printf style to send to the client. May be NULL. */ extern void IDSetSwitch (const ISwitchVectorProperty *s, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to update an existing light vector property. \param l pointer to the vector light property. \param msg message in printf style to send to the client. May be NULL. */ extern void IDSetLight (const ILightVectorProperty *l, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Tell client to update an existing BLOB vector property. \param b pointer to the vector BLOB property. \param msg message in printf style to send to the client. May be NULL. */ extern void IDSetBLOB (const IBLOBVectorProperty *b, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /*@}*/ /** * \defgroup d2duFunctions ID Functions: Functions to delete properties, and log messages locally or remotely. */ /*@{*/ /** \brief Function Drivers call to send log messages to Clients. If dev is specified the Client shall associate the message with that device; if dev is NULL the Client shall treat the message as generic from no specific Device. \param dev device name \param msg message in printf style to send to the client. */ extern void IDMessage (const char *dev, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 2, 3 ) ) ) #endif ; /** \brief Function Drivers call to inform Clients a Property is no longer available, or the entire device is gone if name is NULL. \param dev device name. If device name is NULL, the entire device will be deleted. \param name property name to be deleted. \param msg message in printf style to send to the client. */ extern void IDDelete (const char *dev, const char *name, const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 3, 4 ) ) ) #endif ; /** \brief Function Drivers call to log a message locally. The message is not sent to any Clients. \param msg message in printf style to send to the client. */ extern void IDLog (const char *msg, ...) #ifdef __GNUC__ __attribute__ ( ( format( printf, 1, 2 ) ) ) #endif ; /*@}*/ /** * \defgroup snoopFunctions ISnoop Functions: Functions drivers call to snoop on other drivers. */ /*@{*/ /** \typedef BLOBHandling \brief How drivers handle BLOBs incoming from snooping drivers */ typedef enum { B_NEVER=0, /*!< Never receive BLOBs */ B_ALSO, /*!< Receive BLOBs along with normal messages */ B_ONLY /*!< ONLY receive BLOBs from drivers, ignore all other traffic */ } BLOBHandling; /** \brief Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevice. \param snooped_device name of the device to snoop. \param snooped_property name of the snooped property in the device. */ extern void IDSnoopDevice (const char *snooped_device, const char *snooped_property); /** \brief Function a Driver calls to control whether they will receive BLOBs from snooped devices. \param snooped_device name of the device to snoop. \param bh How drivers handle BLOBs incoming from snooping drivers. */ extern void IDSnoopBLOBs (const char *snooped_device, BLOBHandling bh); /*@}*/ /** * \defgroup deventFunctions IE Functions: Functions drivers call to register with the INDI event utilities. Callbacks are called when a read on a file descriptor will not block. Timers are called once after a specified interval. Workprocs are called when there is nothing else to do. The "Add" functions return a unique id for use with their corresponding "Rm" removal function. An arbitrary pointer may be specified when a function is registered which will be stored and forwarded unchanged when the function is later invoked. */ /*@{*/ /* signature of a callback, timout caller and work procedure function */ /** \typedef IE_CBF \brief Signature of a callback. */ typedef void (IE_CBF) (int readfiledes, void *userpointer); /** \typedef IE_TCF \brief Signature of a timeout caller. */ typedef void (IE_TCF) (void *userpointer); /** \typedef IE_WPF \brief Signature of a work procedure function. */ typedef void (IE_WPF) (void *userpointer); /* functions to add and remove callbacks, timers and work procedures */ /** \brief Register a new callback, \e fp, to be called with \e userpointer as argument when \e readfiledes is ready. * * \param readfiledes file descriptor. * \param fp a pointer to the callback function. * \param userpointer a pointer to be passed to the callback function when called. * \return a unique callback id for use with IERmCallback(). */ extern int IEAddCallback (int readfiledes, IE_CBF *fp, void *userpointer); /** \brief Remove a callback function. * * \param callbackid the callback ID returned from IEAddCallback() */ extern void IERmCallback (int callbackid); /** \brief Register a new timer function, \e fp, to be called with \e ud as argument after \e ms. Add to list in order of decreasing time from epoch, ie, last entry runs soonest. The timer will only invoke the callback function \b once. You need to call addTimer again if you want to repeat the process. * * \param millisecs timer period in milliseconds. * \param fp a pointer to the callback function. * \param userpointer a pointer to be passed to the callback function when called. * \return a unique id for use with IERmTimer(). */ extern int IEAddTimer (int millisecs, IE_TCF *fp, void *userpointer); /** \brief Remove the timer with the given \e timerid, as returned from IEAddTimer. * * \param timerid the timer callback ID returned from IEAddTimer(). */ extern void IERmTimer (int timerid); /** \brief Add a new work procedure, fp, to be called with ud when nothing else to do. * * \param fp a pointer to the work procedure callback function. * \param userpointer a pointer to be passed to the callback function when called. * \return a unique id for use with IERmWorkProc(). */ extern int IEAddWorkProc (IE_WPF *fp, void *userpointer); /** \brief Remove a work procedure. * * \param workprocid The unique ID for the work procedure to be removed. */ extern void IERmWorkProc (int workprocid); /* wait in-line for a flag to set, presumably by another event function */ extern int IEDeferLoop (int maxms, int *flagp); extern int IEDeferLoop0 (int maxms, int *flagp); /*@}*/ /** * \defgroup dutilFunctions IU Functions: Functions drivers call to perform handy utility routines.

This section describes handy utility functions that are provided by the framework for tasks commonly required in the processing of client messages. It is not strictly necessary to use these functions, but it both prudent and efficient to do so.

These do not communicate with the Client in any way.

*/ /*@{*/ /** \brief Find an IText member in a vector text property. * * \param tvp a pointer to a text vector property. * \param name the name of the member to search for. * \return a pointer to an IText member on match, or NULL if nothing is found. */ extern IText *IUFindText (const ITextVectorProperty *tvp, const char *name); /** \brief Find an INumber member in a number text property. * * \param nvp a pointer to a number vector property. * \param name the name of the member to search for. * \return a pointer to an INumber member on match, or NULL if nothing is found. */ extern INumber *IUFindNumber(const INumberVectorProperty *nvp, const char *name); /** \brief Find an ISwitch member in a vector switch property. * * \param svp a pointer to a switch vector property. * \param name the name of the member to search for. * \return a pointer to an ISwitch member on match, or NULL if nothing is found. */ extern ISwitch *IUFindSwitch(const ISwitchVectorProperty *svp, const char *name); /** \brief Find an ILight member in a vector Light property. * * \param lvp a pointer to a Light vector property. * \param name the name of the member to search for. * \return a pointer to an ILight member on match, or NULL if nothing is found. */ extern ILight *IUFindLight(const ILightVectorProperty *lvp, const char *name); /** \brief Find an IBLOB member in a vector BLOB property. * * \param bvp a pointer to a BLOB vector property. * \param name the name of the member to search for. * \return a pointer to an IBLOB member on match, or NULL if nothing is found. */ extern IBLOB *IUFindBLOB(const IBLOBVectorProperty *bvp, const char *name); /** \brief Returns the first ON switch it finds in the vector switch property. * \note This is only valid for ISR_1OFMANY mode. That is, when only one switch out of many is allowed to be ON. Do not use this function if you can have multiple ON switches in the same vector property. * * \param sp a pointer to a switch vector property. * \return a pointer to the \e first ON ISwitch member if found. If all switches are off, NULL is returned. */ extern ISwitch *IUFindOnSwitch (const ISwitchVectorProperty *sp); /** \brief Returns the index of the string in a string array * * \param needle the string to match against each element in the hay * \param hay a pointer to a string array to search in * \param n the size of hay * \return index of needle if found in the hay. Otherwise -1 if not found. */ extern int IUFindIndex (const char *needle, char **hay, unsigned int n); /** \brief Returns the index of first ON switch it finds in the vector switch property. * \note This is only valid for ISR_1OFMANY mode. That is, when only one switch out of many is allowed to be ON. Do not use this function if you can have multiple ON switches in the same vector property. * * \param sp a pointer to a switch vector property. * \return index to the \e first ON ISwitch member if found. If all switches are off, -1 is returned. */ extern int IUFindOnSwitchIndex (const ISwitchVectorProperty *sp); /** \brief Reset all switches in a switch vector property to OFF. * * \param svp a pointer to a switch vector property. */ extern void IUResetSwitch(ISwitchVectorProperty *svp); /** \brief Update all switches in a switch vector property. * * \param svp a pointer to a switch vector property. * \param states the states of the new ISwitch members. * \param names the names of the ISwtich members to update. * \param n the number of ISwitch members to update. * \return 0 if update successful, -1 otherwise. */ extern int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n); /** \brief Update all numbers in a number vector property. * * \param nvp a pointer to a number vector property. * \param values the states of the new INumber members. * \param names the names of the INumber members to update. * \param n the number of INumber members to update. * \return 0 if update successful, -1 otherwise. Update will fail if values are out of scope, or in case of property name mismatch. */ extern int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n); /** \brief Update all text members in a text vector property. * * \param tvp a pointer to a text vector property. * \param texts a pointer to the text members * \param names the names of the IText members to update. * \param n the number of IText members to update. * \return 0 if update successful, -1 otherwise. Update will fail in case of property name mismatch. */ extern int IUUpdateText(ITextVectorProperty *tvp, char * texts[], char *names[], int n); /** \brief Update all BLOB members in a BLOB vector property. * * \param bvp a pointer to a BLOB vector property. * \param sizes sizes of the blobs. * \param blobsizes size of the blobs, raw without compression. * \param blobs a pointer to the BLOB members * \param names the names of the IBLOB members to update. * \param formats The blob format or extension. * \param n the number of IBLOB members to update. * \return 0 if update successful, -1 otherwise. Update will fail in case of property name mismatch. */ extern int IUUpdateBLOB(IBLOBVectorProperty *bvp, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n); /** \brief Function to save blob metadata in the corresponding blob. \param bp pointer to an IBLOB member. \param size size of the blob buffer encoded in base64 \param blobsize actual size of the buffer after base64 decoding. This is the actual byte count used in drivers. \param blob pointer to the blob buffer \param format format of the blob buffer \note Do not call this function directly, it is called internally by IUUpdateBLOB. */ extern int IUSaveBLOB(IBLOB *bp, int size, int blobsize, char *blob, char *format); /** \brief Function to update the min and max elements of a number in the client \param nvp pointer to an INumberVectorProperty. */ extern void IUUpdateMinMax(const INumberVectorProperty *nvp); /** \brief Function to reliably save new text in a IText. \param tp pointer to an IText member. \param newtext the new text to be saved */ extern void IUSaveText (IText *tp, const char *newtext); /** \brief Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL. \param sp pointer a switch property to fill \param name the switch name \param label the switch label \param s the switch state (ISS_ON or ISS_OFF) */ extern void IUFillSwitch(ISwitch *sp, const char *name, const char * label, ISState s); /** \brief Assign attributes for a light property. The light's auxiliary elements will be set to NULL. \param lp pointer a light property to fill \param name the light name \param label the light label \param s the light state (IDLE, WARNING, OK, ALERT) */ extern void IUFillLight(ILight *lp, const char *name, const char * label, IPState s); /** \brief Assign attributes for a number property. The number's auxiliary elements will be set to NULL. \param np pointer a number property to fill \param name the number name \param label the number label \param format the number format in printf style (e.g. "%02d") \param min the minimum possible value \param max the maximum possible value \param step the step used to climb from minimum value to maximum value \param value the number's current value */ extern void IUFillNumber(INumber *np, const char *name, const char * label, const char *format, double min, double max, double step, double value); /** \brief Assign attributes for a text property. The text's auxiliary elements will be set to NULL. \param tp pointer a text property to fill \param name the text name \param label the text label \param initialText the initial text */ extern void IUFillText(IText *tp, const char *name, const char * label, const char *initialText); /** \brief Assign attributes for a BLOB property. The BLOB's data and auxiliary elements will be set to NULL. \param bp pointer a BLOB property to fill \param name the BLOB name \param label the BLOB label \param format the BLOB format. */ extern void IUFillBLOB(IBLOB *bp, const char *name, const char * label, const char *format); /** \brief Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL. \param svp pointer a switch vector property to fill \param sp pointer to an array of switches \param nsp the dimension of sp \param dev the device name this vector property belongs to \param name the vector property name \param label the vector property label \param group the vector property group \param p the vector property permission \param r the switches behavior \param timeout vector property timeout in seconds \param s the vector property initial state. */ extern void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char * dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s); /** \brief Assign attributes for a light vector property. The vector's auxiliary elements will be set to NULL. \param lvp pointer a light vector property to fill \param lp pointer to an array of lights \param nlp the dimension of lp \param dev the device name this vector property belongs to \param name the vector property name \param label the vector property label \param group the vector property group \param s the vector property initial state. */ extern void IUFillLightVector(ILightVectorProperty *lvp, ILight *lp, int nlp, const char * dev, const char *name, const char *label, const char *group, IPState s); /** \brief Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL. \param nvp pointer a number vector property to fill \param np pointer to an array of numbers \param nnp the dimension of np \param dev the device name this vector property belongs to \param name the vector property name \param label the vector property label \param group the vector property group \param p the vector property permission \param timeout vector property timeout in seconds \param s the vector property initial state. */ extern void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s); /** \brief Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL. \param tvp pointer a text vector property to fill \param tp pointer to an array of texts \param ntp the dimension of tp \param dev the device name this vector property belongs to \param name the vector property name \param label the vector property label \param group the vector property group \param p the vector property permission \param timeout vector property timeout in seconds \param s the vector property initial state. */ extern void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s); /** \brief Assign attributes for a BLOB vector property. The vector's auxiliary elements will be set to NULL. \param bvp pointer a BLOB vector property to fill \param bp pointer to an array of BLOBs \param nbp the dimension of bp \param dev the device name this vector property belongs to \param name the vector property name \param label the vector property label \param group the vector property group \param p the vector property permission \param timeout vector property timeout in seconds \param s the vector property initial state. */ extern void IUFillBLOBVector(IBLOBVectorProperty *bvp, IBLOB *bp, int nbp, const char * dev, const char *name, const char *label, const char* group, IPerm p, double timeout, IPState s); /** \brief Update a snooped number vector property from the given XML root element. \param root XML root elememnt containing the snopped property content \param nvp a pointer to the number vector property to be updated. \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble. */ extern int IUSnoopNumber (XMLEle *root, INumberVectorProperty *nvp); /** \brief Update a snooped text vector property from the given XML root element. \param root XML root elememnt containing the snopped property content \param tvp a pointer to the text vector property to be updated. \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble. */ extern int IUSnoopText (XMLEle *root, ITextVectorProperty *tvp); /** \brief Update a snooped light vector property from the given XML root element. \param root XML root elememnt containing the snopped property content \param lvp a pointer to the light vector property to be updated. \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble. */ extern int IUSnoopLight (XMLEle *root, ILightVectorProperty *lvp); /** \brief Update a snooped switch vector property from the given XML root element. \param root XML root elememnt containing the snopped property content \param svp a pointer to the switch vector property to be updated. \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble. */ extern int IUSnoopSwitch (XMLEle *root, ISwitchVectorProperty *svp); /** \brief Update a snooped BLOB vector property from the given XML root element. \param root XML root elememnt containing the snopped property content \param bvp a pointer to the BLOB vector property to be updated. \return 0 if cracking the XML element and updating the property proceeded without errors, -1 if trouble. */ extern int IUSnoopBLOB (XMLEle *root, IBLOBVectorProperty *bvp); /*@}*/ /******************************************************************************* ******************************************************************************* * * Functions the INDI Device Driver framework calls which the Driver must * define. * ******************************************************************************* ******************************************************************************* */ /** * \defgroup dcuFunctions IS Functions: Functions all drivers must define. This section defines functions that must be defined in each driver. These functions are never called by the driver, but are called by the driver framework. These must always be defined even if they do nothing. */ /*@{*/ /** \brief Get Device Properties \param dev the name of the device. This function is called by the framework whenever the driver has received a getProperties message from an INDI client. The argument \param dev is either a string containing the name of the device specified within the message, or NULL if no device was specified. If the driver does not recognize the device, it should ignore the message and do nothing. If dev matches the device the driver is implementing, or dev is NULL, the driver must respond by sending one defXXX message to describe each property defined by this device, including its current (or initial) value. The recommended way to send these messages is to call the appropriate IDDef functions. */ extern void ISGetProperties (const char *dev); /** \brief Update the value of an existing text vector property. \param dev the name of the device. \param name the name of the text vector property to update. \param texts an array of text values. \param names parallel names to the array of text values. \param n the dimension of texts[]. \note You do not need to call this function, it is called by INDI when new text values arrive from the client. */ extern void ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n); /** \brief Update the value of an existing number vector property. \param dev the name of the device. \param name the name of the number vector property to update. \param doubles an array of number values. \param names parallel names to the array of number values. \param n the dimension of doubles[]. \note You do not need to call this function, it is called by INDI when new number values arrive from the client. */ extern void ISNewNumber (const char *dev, const char *name, double *doubles, char *names[], int n); /** \brief Update the value of an existing switch vector property. \param dev the name of the device. \param name the name of the switch vector property to update. \param states an array of switch states. \param names parallel names to the array of switch states. \param n the dimension of states[]. \note You do not need to call this function, it is called by INDI when new switch values arrive from the client. */ extern void ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n); /** \brief Update data of an existing blob vector property. \param dev the name of the device. \param name the name of the blob vector property to update. \param sizes an array of base64 blob sizes in bytes \e before decoding. \param blobsizes an array of the sizes of blobs \e after decoding from base64. \param blobs an array of decoded data. Each blob size is found in \e blobsizes array. \param formats Blob data format (e.g. fits.z). \param names names of blob members to update. \param n the number of blobs to update. \note You do not need to call this function, it is called by INDI when new blob values arrive from the client. e.g. BLOB element with name names[0] has data located in blobs[0] with size sizes[0] and format formats[0]. */ extern void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n); /** \brief Function defined by Drivers that is called when another Driver it is snooping (by having previously called IDSnoopDevice()) sent any INDI message. \param root The argument contains the full message exactly as it was sent by the driver. \e Hint: use the IUSnoopXXX utility functions to help crack the message if it was one of setXXX or defXXX. */ extern void ISSnoopDevice (XMLEle *root); /*@}*/ /* Handy readability macro to avoid unused variables warnings */ #define INDI_UNUSED(x) (void) x /** \brief Extract dev and name attributes from an XML element. \param root The XML element to be parsed. \param dev pointer to an allocated buffer to save the extracted element device name attribute. The buffer size must be at least MAXINDIDEVICE bytes. \param name pointer to an allocated buffer to save the extracted elemented name attribute. The buffer size must be at least MAXINDINAME bytes. \param msg pointer to an allocated char buffer to store error messages. The minimum buffer size is MAXRBUF. \return 0 if successful, -1 if error is encountered and msg is set. */ extern int crackDN (XMLEle *root, char **dev, char **name, char msg[]); /** \brief Extract property state (Idle, OK, Busy, Alert) from the supplied string. \param str A string representation of the state. \param ip Pointer to IPState structure to store the extracted property state. \return 0 if successful, -1 if error is encountered. */ extern int crackIPState (const char *str, IPState *ip); /** \brief Extract switch state (On or Off) from the supplied string. \param str A string representation of the switch state. \param ip Pointer to ISState structure to store the extracted switch state. \return 0 if successful, -1 if error is encountered. */ extern int crackISState (const char *str, ISState *ip); /** \brief Extract property permission state (RW, RO, WO) from the supplied string. \param str A string representation of the permission state. \param ip Pointer to IPerm structure to store the extracted permission state. \return 0 if successful, -1 if error is encountered. */ extern int crackIPerm (const char *str, IPerm *ip); /** \brief Extract switch rule (OneOfMany, OnlyOne..etc) from the supplied string. \param str A string representation of the switch rule. \param ip Pointer to ISRule structure to store the extracted switch rule. \return 0 if successful, -1 if error is encountered. */ extern int crackISRule (const char *str, ISRule *ip); /** \return Returns a string representation of the supplied property state. */ extern const char *pstateStr(IPState s); /** \return Returns a string representation of the supplied switch status. */ extern const char *sstateStr(ISState s); /** \return Returns a string representation of the supplied switch rule. */ extern const char *ruleStr(ISRule r); /** \return Returns a string representation of the supplied permission value. */ extern const char *permStr(IPerm p); extern void xmlv1(void); #ifdef __cplusplus } #endif #endif