Instrument Neutral Distributed Interface INDI  1.1.0
indifocuser.cpp
1 /*******************************************************************************
2  Copyright(c) 2013 Jasem Mutlaq. All rights reserved.
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18 
19 #include "indifocuser.h"
20 
21 #include <string.h>
22 
23 INDI::Focuser::Focuser()
24 {
25  controller = new INDI::Controller(this);
26 
27  controller->setButtonCallback(buttonHelper);
28 }
29 
30 INDI::Focuser::~Focuser()
31 {
32 }
33 
35 {
36  DefaultDevice::initProperties(); // let the base class flesh in what it wants
37 
38  initFocuserProperties(getDeviceName(), MAIN_CONTROL_TAB);
39 
40  /* Port */
41  IUFillText(&PortT[0], "PORT", "Port", "/dev/ttyUSB0");
42  IUFillTextVector(&PortTP, PortT, 1, getDeviceName(), "DEVICE_PORT", "Ports", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE);
43 
44  // Presets
45  IUFillNumber(&PresetN[0], "Preset 1", "", "%6.2f", 0, 60000, 1000, 0);
46  IUFillNumber(&PresetN[1], "Preset 2", "", "%6.2f", 0, 60000, 1000, 0);
47  IUFillNumber(&PresetN[2], "Preset 3", "", "%6.2f", 0, 60000, 1000, 0);
48  IUFillNumberVector(&PresetNP, PresetN, 3, getDeviceName(), "Presets", "", "Presets", IP_RW, 0, IPS_IDLE);
49 
50  //Preset GOTO
51  IUFillSwitch(&PresetGotoS[0], "Preset 1", "", ISS_OFF);
52  IUFillSwitch(&PresetGotoS[1], "Preset 2", "", ISS_OFF);
53  IUFillSwitch(&PresetGotoS[2], "Preset 3", "", ISS_OFF);
54  IUFillSwitchVector(&PresetGotoSP, PresetGotoS, 3, getDeviceName(), "Goto", "", "Presets", IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
55 
56  addDebugControl();
57 
58  controller->mapController("Focus In", "Focus In", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_1");
59  controller->mapController("Focus Out", "Focus Out", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_2");
60  controller->mapController("Abort Focus", "Abort Focus", INDI::Controller::CONTROLLER_BUTTON, "BUTTON_3");
61 
62  controller->initProperties();
63 
64  setInterfaceDescriptor(FOCUSER_INTERFACE);
65 
66  return true;
67 }
68 
69 void INDI::Focuser::ISGetProperties (const char *dev)
70 {
71  // First we let our parent populate
73 
74  defineText(&PortTP);
75 
76  controller->ISGetProperties(dev);
77  return;
78 }
79 
81 {
82  if(isConnected())
83  {
84  // Now we add our focusser specific stuff
85  defineSwitch(&FocusMotionSP);
86 
87  if (capability.variableSpeed)
88  {
89  defineNumber(&FocusSpeedNP);
90  defineNumber(&FocusTimerNP);
91  }
92  if (capability.canRelMove)
93  defineNumber(&FocusRelPosNP);
94  if (capability.canAbsMove)
95  defineNumber(&FocusAbsPosNP);
96  if (capability.canAbort)
97  defineSwitch(&AbortSP);
98  if (capability.canAbsMove)
99  {
100  defineNumber(&PresetNP);
101  defineSwitch(&PresetGotoSP);
102  }
103  } else
104  {
105  deleteProperty(FocusMotionSP.name);
106  if (capability.variableSpeed)
107  {
108  deleteProperty(FocusSpeedNP.name);
109  deleteProperty(FocusTimerNP.name);
110  }
111  if (capability.canRelMove)
112  deleteProperty(FocusRelPosNP.name);
113  if (capability.canAbsMove)
114  deleteProperty(FocusAbsPosNP.name);
115  if (capability.canAbort)
116  deleteProperty(AbortSP.name);
117  if (capability.canAbsMove)
118  {
119  deleteProperty(PresetNP.name);
120  deleteProperty(PresetGotoSP.name);
121  }
122  }
123 
124  controller->updateProperties();
125  return true;
126 }
127 
128 
129 bool INDI::Focuser::ISNewNumber (const char *dev, const char *name, double values[], char *names[], int n)
130 {
131  // first check if it's for our device
132  if(strcmp(dev,getDeviceName())==0)
133  {
134  if (!strcmp(name, PresetNP.name))
135  {
136  IUUpdateNumber(&PresetNP, values, names, n);
137  PresetNP.s = IPS_OK;
138  IDSetNumber(&PresetNP, NULL);
139 
140  //saveConfig();
141 
142  return true;
143  }
144 
145  if (strstr(name, "FOCUS_"))
146  return processFocuserNumber(dev, name, values, names, n);
147 
148  }
149 
150  return DefaultDevice::ISNewNumber(dev,name,values,names,n);
151 }
152 
153 bool INDI::Focuser::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
154 {
155  if(strcmp(dev,getDeviceName())==0)
156  {
157  if (!strcmp(PresetGotoSP.name, name))
158  {
159  IUUpdateSwitch(&PresetGotoSP, states, names, n);
160  int index = IUFindOnSwitchIndex(&PresetGotoSP);
161 
162  if (PresetN[index].value < FocusAbsPosN[0].min)
163  {
164  PresetGotoSP.s = IPS_ALERT;
165  IDSetSwitch(&PresetGotoSP, NULL);
166  DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Focus minimum position is %g", FocusAbsPosN[0].min);
167  return false;
168  }
169  else if (PresetN[index].value > FocusAbsPosN[0].max)
170  {
171  PresetGotoSP.s = IPS_ALERT;
172  IDSetSwitch(&PresetGotoSP, NULL);
173  DEBUGFDEVICE(dev, INDI::Logger::DBG_ERROR, "Requested position out of bound. Focus maximum position is %g", FocusAbsPosN[0].max);
174  return false;
175  }
176 
177  int rc = MoveAbsFocuser(PresetN[index].value);
178  if (rc >= 0)
179  {
180  PresetGotoSP.s = IPS_OK;
181  DEBUGF(INDI::Logger::DBG_SESSION, "Moving to Preset %d with position %g.", index+1, PresetN[index].value);
182  IDSetSwitch(&PresetGotoSP, NULL);
183  return true;
184  }
185 
186  PresetGotoSP.s = IPS_ALERT;
187  IDSetSwitch(&PresetGotoSP, NULL);
188  return false;
189  }
190 
191  if (strstr(name, "FOCUS_"))
192  return processFocuserSwitch(dev, name, states, names, n);
193 
194  }
195 
196  controller->ISNewSwitch(dev, name, states, names, n);
197 
198  // Nobody has claimed this, so, ignore it
199  return DefaultDevice::ISNewSwitch(dev,name,states,names,n);
200 }
201 
202 bool INDI::Focuser::ISNewText (const char *dev, const char *name, char *texts[], char *names[], int n)
203 {
204  if(strcmp(dev,getDeviceName())==0)
205  {
206  if (!strcmp(name, PortTP.name))
207  {
208  IUUpdateText(&PortTP, texts, names, n);
209  PortTP.s = IPS_OK;
210  IDSetText(&PortTP, NULL);
211  return true;
212  }
213  }
214 
215  controller->ISNewText(dev, name, texts, names, n);
216 
217  return DefaultDevice::ISNewText(dev, name, texts, names, n);
218 }
219 
220 bool INDI::Focuser::ISSnoopDevice (XMLEle *root)
221 {
222  controller->ISSnoopDevice(root);
223 
225 }
226 
228 {
229  IUSaveConfigText(fp, &PortTP);
230  IUSaveConfigNumber(fp, &PresetNP);
231 
232  controller->saveConfigItems(fp);
233 
234  return true;
235 }
236 
237 void INDI::Focuser::buttonHelper(const char *button_n, ISState state, void *context)
238 {
239  static_cast<INDI::Focuser *>(context)->processButton(button_n, state);
240 }
241 
242 void INDI::Focuser::processButton(const char * button_n, ISState state)
243 {
244  //ignore OFF
245  if (state == ISS_OFF)
246  return;
247 
248  FocusTimerN[0].value = lastTimerValue;
249 
250  IPState rc= IPS_IDLE;
251 
252  // Abort
253  if (!strcmp(button_n, "Abort Focus"))
254  {
255  if (AbortFocuser())
256  {
257  AbortSP.s = IPS_OK;
258  DEBUG(INDI::Logger::DBG_SESSION, "Focuser aborted.");
259  if (capability.canAbsMove && FocusAbsPosNP.s != IPS_IDLE)
260  {
261  FocusAbsPosNP.s = IPS_IDLE;
262  IDSetNumber(&FocusAbsPosNP, NULL);
263  }
264  if (capability.canRelMove && FocusRelPosNP.s != IPS_IDLE)
265  {
266  FocusRelPosNP.s = IPS_IDLE;
267  IDSetNumber(&FocusRelPosNP, NULL);
268  }
269  }
270  else
271  {
272  AbortSP.s = IPS_ALERT;
273  DEBUG(INDI::Logger::DBG_ERROR, "Aborting focuser failed.");
274  }
275 
276  IDSetSwitch(&AbortSP, NULL);
277  }
278  // Focus In
279  else if (!strcmp(button_n, "Focus In"))
280  {
281  if (FocusMotionS[FOCUS_INWARD].s != ISS_ON)
282  {
283  FocusMotionS[FOCUS_INWARD].s = ISS_ON;
284  FocusMotionS[FOCUS_OUTWARD].s = ISS_OFF;
285  IDSetSwitch(&FocusMotionSP, NULL);
286  }
287 
288  if (capability.variableSpeed)
289  {
290  rc = MoveFocuser(FOCUS_INWARD, FocusSpeedN[0].value, FocusTimerN[0].value);
291  FocusTimerNP.s = rc;
292  IDSetNumber(&FocusTimerNP,NULL);
293  }
294  else if (capability.canRelMove)
295  {
296  rc=MoveRelFocuser(FOCUS_INWARD, FocusRelPosN[0].value);
297  if (rc == IPS_OK)
298  {
299  FocusRelPosNP.s=IPS_OK;
300  IDSetNumber(&FocusRelPosNP, "Focuser moved %d steps inward", (int) FocusRelPosN[0].value);
301  IDSetNumber(&FocusAbsPosNP, NULL);
302  }
303  else if (rc == IPS_BUSY)
304  {
305  FocusRelPosNP.s=IPS_BUSY;
306  IDSetNumber(&FocusAbsPosNP, "Focuser is moving %d steps inward...", (int) FocusRelPosN[0].value);
307  }
308  }
309  }
310  else if (!strcmp(button_n, "Focus Out"))
311  {
312  if (FocusMotionS[FOCUS_OUTWARD].s != ISS_ON)
313  {
314  FocusMotionS[FOCUS_INWARD].s = ISS_OFF;
315  FocusMotionS[FOCUS_OUTWARD].s = ISS_ON;
316  IDSetSwitch(&FocusMotionSP, NULL);
317  }
318 
319  if (capability.variableSpeed)
320  {
321  rc = MoveFocuser(FOCUS_OUTWARD, FocusSpeedN[0].value, FocusTimerN[0].value);
322  FocusTimerNP.s = rc;
323  IDSetNumber(&FocusTimerNP,NULL);
324  }
325  else if (capability.canRelMove)
326  {
327  rc=MoveRelFocuser(FOCUS_OUTWARD, FocusRelPosN[0].value);
328  if (rc == IPS_OK)
329  {
330  FocusRelPosNP.s=IPS_OK;
331  IDSetNumber(&FocusRelPosNP, "Focuser moved %d steps outward", (int) FocusRelPosN[0].value);
332  IDSetNumber(&FocusAbsPosNP, NULL);
333  }
334  else if (rc == IPS_BUSY)
335  {
336  FocusRelPosNP.s=IPS_BUSY;
337  IDSetNumber(&FocusAbsPosNP, "Focuser is moving %d steps outward...", (int) FocusRelPosN[0].value);
338  }
339  }
340  }
341 }
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indidriver.c:1347
void setButtonCallback(buttonFunc buttonCallback)
setButtonCallback Sets the callback function when a new button input is detected. ...
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver...
Definition: indifocuser.cpp:80
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file ...
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)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:503
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minumum set of properties are defined t...
void IDSetText(const ITextVectorProperty *t, const char *msg,...)
Tell client to update an existing text vector property.
Definition: indidriver.c:1700
void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...)
Tell client to update an existing switch vector property.
Definition: indidriver.c:1780
IPState
Property state.
Definition: indiapi.h:129
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:209
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:300
The Controller class provides functionality to access a controller (e.g. joystick) input and send it ...
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:263
Definition: indiapi.h:154
void IDSetNumber(const INumberVectorProperty *n, const char *msg,...)
Tell client to update an existing number vector property.
Definition: indidriver.c:1740
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL...
Definition: indidriver.c:419
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indidriver.c:1328
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minumum set of properties are defined t...
Definition: indifocuser.cpp:69
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL...
Definition: indidriver.c:367
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL...
Definition: indidriver.c:398
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1199
Class to provide general functionality of a focuser device.
Definition: indifocuser.h:37
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function...
ISState
Switch state.
Definition: indiapi.h:120
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)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:460
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)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL...
Definition: indidriver.c:526
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function...
Definition: indifocuser.cpp:34
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.