Instrument Neutral Distributed Interface INDI  2.0.2
focus_simulator.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2012 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 "focus_simulator.h"
20 
21 #include <cmath>
22 #include <memory>
23 #include <cstring>
24 #include <unistd.h>
25 
26 // We declare an auto pointer to focusSim.
27 static std::unique_ptr<FocusSim> focusSim(new FocusSim());
28 
29 /************************************************************************************
30  *
31 ************************************************************************************/
33 {
35 }
36 
37 /************************************************************************************
38  *
39 ************************************************************************************/
41 {
42  SetTimer(1000);
43  return true;
44 }
45 
46 /************************************************************************************
47  *
48 ************************************************************************************/
50 {
51  return true;
52 }
53 
54 /************************************************************************************
55  *
56 ************************************************************************************/
58 {
59  return "Focuser Simulator";
60 }
61 
62 /************************************************************************************
63  *
64 ************************************************************************************/
65 void FocusSim::ISGetProperties(const char *dev)
66 {
67  if (dev != nullptr && strcmp(dev, getDeviceName()) != 0)
68  return;
69 
71 
72  defineProperty(&ModeSP);
73  loadConfig(true, "Mode");
74 }
75 
76 /************************************************************************************
77  *
78 ************************************************************************************/
80 {
82 
83  IUFillNumber(&SeeingN[0], "SIM_SEEING", "arcseconds", "%4.2f", 0, 60, 0, 3.5);
84  IUFillNumberVector(&SeeingNP, SeeingN, 1, getDeviceName(), "SEEING_SETTINGS", "Seeing", MAIN_CONTROL_TAB, IP_RW, 60,
85  IPS_IDLE);
86 
87  IUFillNumber(&FWHMN[0], "SIM_FWHM", "arcseconds", "%4.2f", 0, 60, 0, 7.5);
88  IUFillNumberVector(&FWHMNP, FWHMN, 1, getDeviceName(), "FWHM", "FWHM", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
89 
90  IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50., 70., 0., 0.);
91  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
93 
94  DelayNP[0].fill("DELAY_VALUE", "Value (uS)", "%.f", 0, 60000, 100, 100);
95  DelayNP.fill(getDeviceName(), "DELAY", "Delay", OPTIONS_TAB, IP_RW, 60, IPS_IDLE);
96 
97  IUFillSwitch(&ModeS[MODE_ALL], "All", "All", ISS_ON);
98  IUFillSwitch(&ModeS[MODE_ABSOLUTE], "Absolute", "Absolute", ISS_OFF);
99  IUFillSwitch(&ModeS[MODE_RELATIVE], "Relative", "Relative", ISS_OFF);
100  IUFillSwitch(&ModeS[MODE_TIMER], "Timer", "Timer", ISS_OFF);
101  IUFillSwitchVector(&ModeSP, ModeS, MODE_COUNT, getDeviceName(), "Mode", "Mode", MAIN_CONTROL_TAB, IP_RW,
102  ISR_1OFMANY, 60, IPS_IDLE);
103 
104  initTicks = sqrt(FWHMN[0].value - SeeingN[0].value) / 0.75;
105 
106  FocusSpeedN[0].min = 1;
107  FocusSpeedN[0].max = 5;
108  FocusSpeedN[0].step = 1;
109  FocusSpeedN[0].value = 1;
110 
111  FocusAbsPosN[0].value = FocusAbsPosN[0].max / 2;
112 
113  internalTicks = FocusAbsPosN[0].value;
114 
115  return true;
116 }
117 
118 /************************************************************************************
119  *
120 ************************************************************************************/
122 {
124 
125  if (isConnected())
126  {
127  defineProperty(&SeeingNP);
128  defineProperty(&FWHMNP);
129  defineProperty(&TemperatureNP);
130  defineProperty(DelayNP);
131  }
132  else
133  {
134  deleteProperty(SeeingNP.name);
135  deleteProperty(FWHMNP.name);
136  deleteProperty(TemperatureNP.name);
137  deleteProperty(DelayNP);
138  }
139 
140  return true;
141 }
142 
143 /************************************************************************************
144  *
145 ************************************************************************************/
146 bool FocusSim::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
147 {
148  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
149  {
150  // Modes
151  if (strcmp(ModeSP.name, name) == 0)
152  {
153  IUUpdateSwitch(&ModeSP, states, names, n);
154  uint32_t cap = 0;
155  int index = IUFindOnSwitchIndex(&ModeSP);
156 
157  switch (index)
158  {
159  case MODE_ALL:
161  break;
162 
163  case MODE_ABSOLUTE:
164  cap = FOCUSER_CAN_ABS_MOVE;
165  break;
166 
167  case MODE_RELATIVE:
168  cap = FOCUSER_CAN_REL_MOVE;
169  break;
170 
171  case MODE_TIMER:
173  break;
174 
175  default:
176  ModeSP.s = IPS_ALERT;
177  IDSetSwitch(&ModeSP, "Unknown mode index %d", index);
178  return true;
179  }
180 
181  FI::SetCapability(cap);
182  ModeSP.s = IPS_OK;
183  IDSetSwitch(&ModeSP, nullptr);
184  return true;
185  }
186  }
187 
188  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
189 }
190 
191 /************************************************************************************
192  *
193 ************************************************************************************/
194 bool FocusSim::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
195 {
196  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
197  {
198  if (strcmp(name, "SEEING_SETTINGS") == 0)
199  {
200  SeeingNP.s = IPS_OK;
201  IUUpdateNumber(&SeeingNP, values, names, n);
202 
203  IDSetNumber(&SeeingNP, nullptr);
204  return true;
205  }
206 
207  if (strcmp(name, "FOCUS_TEMPERATURE") == 0)
208  {
209  TemperatureNP.s = IPS_OK;
210  IUUpdateNumber(&TemperatureNP, values, names, n);
211 
212  IDSetNumber(&TemperatureNP, nullptr);
213  return true;
214  }
215 
216  // Delay
217  if (DelayNP.isNameMatch(name))
218  {
219  DelayNP.update(values, names, n);
220  DelayNP.setState(IPS_OK);
221  DelayNP.apply();
222  saveConfig(true, DelayNP.getName());
223  return true;
224  }
225  }
226 
227  // Let INDI::Focuser handle any other number properties
228  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
229 }
230 
231 /************************************************************************************
232  *
233 ************************************************************************************/
234 IPState FocusSim::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
235 {
236  double mid = (FocusAbsPosN[0].max - FocusAbsPosN[0].min) / 2;
237  int mode = IUFindOnSwitchIndex(&ModeSP);
238  double targetTicks = ((dir == FOCUS_INWARD) ? -1 : 1) * (speed * duration);
239 
240  internalTicks += targetTicks;
241 
242  if (mode == MODE_ALL)
243  {
244  if (internalTicks < FocusAbsPosN[0].min || internalTicks > FocusAbsPosN[0].max)
245  {
246  internalTicks -= targetTicks;
247  LOG_ERROR("Cannot move focuser in this direction any further.");
248  return IPS_ALERT;
249  }
250  }
251 
252  // simulate delay in motion as the focuser moves to the new position
253  usleep(duration * 1000);
254 
255  double ticks = initTicks + (internalTicks - mid) / 5000.0;
256 
257  FWHMN[0].value = 0.5625 * ticks * ticks + SeeingN[0].value;
258 
259  LOGF_DEBUG("TIMER Current internal ticks: %g FWHM ticks: %g FWHM: %g", internalTicks, ticks,
260  FWHMN[0].value);
261 
262  if (mode == MODE_ALL)
263  {
264  FocusAbsPosN[0].value = internalTicks;
265  IDSetNumber(&FocusAbsPosNP, nullptr);
266  }
267 
268  if (FWHMN[0].value < SeeingN[0].value)
269  FWHMN[0].value = SeeingN[0].value;
270 
271  IDSetNumber(&FWHMNP, nullptr);
272 
273  return IPS_OK;
274 }
275 
276 /************************************************************************************
277  *
278 ************************************************************************************/
279 IPState FocusSim::MoveAbsFocuser(uint32_t targetTicks)
280 {
281  double mid = (FocusAbsPosN[0].max - FocusAbsPosN[0].min) / 2;
282 
283  internalTicks = targetTicks;
284 
285  // Limit to +/- 10 from initTicks
286  double ticks = initTicks + (targetTicks - mid) / 5000.0;
287 
288  // simulate delay in motion as the focuser moves to the new position
289  usleep(std::abs((targetTicks - FocusAbsPosN[0].value) * DelayNP[0].getValue()));
290 
291  FocusAbsPosN[0].value = targetTicks;
292 
293  FWHMN[0].value = 0.5625 * ticks * ticks + SeeingN[0].value;
294 
295  LOGF_DEBUG("ABS Current internal ticks: %g FWHM ticks: %g FWHM: %g", internalTicks, ticks,
296  FWHMN[0].value);
297 
298  if (FWHMN[0].value < SeeingN[0].value)
299  FWHMN[0].value = SeeingN[0].value;
300 
301  IDSetNumber(&FWHMNP, nullptr);
302 
303  return IPS_OK;
304 }
305 
306 /************************************************************************************
307  *
308 ************************************************************************************/
310 {
311  uint32_t targetTicks = FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1));
313  IDSetNumber(&FocusAbsPosNP, nullptr);
314  return MoveAbsFocuser(targetTicks);
315 }
316 
317 /************************************************************************************
318  *
319 ************************************************************************************/
321 {
322  INDI_UNUSED(speed);
323  return true;
324 }
325 
326 /************************************************************************************
327  *
328 ************************************************************************************/
329 bool FocusSim::SetFocuserBacklash(int32_t steps)
330 {
331  INDI_UNUSED(steps);
332  return true;
333 }
334 
335 /************************************************************************************
336  *
337 ************************************************************************************/
339 {
340  INDI_UNUSED(enabled);
341  return true;
342 }
343 
344 /************************************************************************************
345  *
346 ************************************************************************************/
348 {
350 
351  DelayNP.save(fp);
352 
353  return true;
354 }
The FocusSim class provides a simple Focuser simulator that can simulator the following devices:
bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
bool Disconnect() override
Disconnect from device.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
const char * getDefaultName() override
virtual IPState MoveFocuser(FocusDirection dir, int speed, uint16_t duration) override
MoveFocuser the focuser in a particular direction with a specific speed for a finite duration.
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
virtual bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool saveConfig(bool silent=false, const char *property=nullptr)
Save the current properties in a configuration file.
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INumberVectorProperty FocusAbsPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Saves the Device Port and Focuser Presets in the configuration file
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: indifocuser.cpp:95
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:42
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
const char * getName() const
bool isNameMatch(const char *otherName) const
bool update(const double values[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
double max(void)
double min(void)
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
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: indidevapi.c:272
int IUFindOnSwitchIndex(const ISwitchVectorProperty *svp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indidevapi.c:128
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: indidevapi.c:158
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: indidevapi.c:180
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: indidevapi.c:235
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:1362
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
char name[MAXINDINAME]
Definition: indiapi.h:323
char name[MAXINDINAME]
Definition: indiapi.h:371