Instrument Neutral Distributed Interface INDI  1.9.5
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 // Focuser takes 100 microsecond to move for each step, completing 100,000 steps in 10 seconds
30 #define FOCUS_MOTION_DELAY 100
31 
32 /************************************************************************************
33  *
34 ************************************************************************************/
36 {
38 }
39 
40 /************************************************************************************
41  *
42 ************************************************************************************/
44 {
45  SetTimer(1000);
46  return true;
47 }
48 
49 /************************************************************************************
50  *
51 ************************************************************************************/
53 {
54  return true;
55 }
56 
57 /************************************************************************************
58  *
59 ************************************************************************************/
61 {
62  return "Focuser Simulator";
63 }
64 
65 /************************************************************************************
66  *
67 ************************************************************************************/
68 void FocusSim::ISGetProperties(const char *dev)
69 {
70  if (dev != nullptr && strcmp(dev, getDeviceName()) != 0)
71  return;
72 
74 
75  defineProperty(&ModeSP);
76  loadConfig(true, "Mode");
77 }
78 
79 /************************************************************************************
80  *
81 ************************************************************************************/
83 {
85 
86  IUFillNumber(&SeeingN[0], "SIM_SEEING", "arcseconds", "%4.2f", 0, 60, 0, 3.5);
87  IUFillNumberVector(&SeeingNP, SeeingN, 1, getDeviceName(), "SEEING_SETTINGS", "Seeing", MAIN_CONTROL_TAB, IP_RW, 60,
88  IPS_IDLE);
89 
90  IUFillNumber(&FWHMN[0], "SIM_FWHM", "arcseconds", "%4.2f", 0, 60, 0, 7.5);
91  IUFillNumberVector(&FWHMNP, FWHMN, 1, getDeviceName(), "FWHM", "FWHM", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
92 
93  IUFillNumber(&TemperatureN[0], "TEMPERATURE", "Celsius", "%6.2f", -50., 70., 0., 0.);
94  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
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  }
131  else
132  {
133  deleteProperty(SeeingNP.name);
134  deleteProperty(FWHMNP.name);
135  deleteProperty(TemperatureNP.name);
136  }
137 
138  return true;
139 }
140 
141 /************************************************************************************
142  *
143 ************************************************************************************/
144 bool FocusSim::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
145 {
146  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
147  {
148  // Modes
149  if (strcmp(ModeSP.name, name) == 0)
150  {
151  IUUpdateSwitch(&ModeSP, states, names, n);
152  uint32_t cap = 0;
153  int index = IUFindOnSwitchIndex(&ModeSP);
154 
155  switch (index)
156  {
157  case MODE_ALL:
159  break;
160 
161  case MODE_ABSOLUTE:
162  cap = FOCUSER_CAN_ABS_MOVE;
163  break;
164 
165  case MODE_RELATIVE:
166  cap = FOCUSER_CAN_REL_MOVE;
167  break;
168 
169  case MODE_TIMER:
171  break;
172 
173  default:
174  ModeSP.s = IPS_ALERT;
175  IDSetSwitch(&ModeSP, "Unknown mode index %d", index);
176  return true;
177  }
178 
179  FI::SetCapability(cap);
180  ModeSP.s = IPS_OK;
181  IDSetSwitch(&ModeSP, nullptr);
182  return true;
183  }
184  }
185 
186  return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
187 }
188 
189 /************************************************************************************
190  *
191 ************************************************************************************/
192 bool FocusSim::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
193 {
194  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
195  {
196  if (strcmp(name, "SEEING_SETTINGS") == 0)
197  {
198  SeeingNP.s = IPS_OK;
199  IUUpdateNumber(&SeeingNP, values, names, n);
200 
201  IDSetNumber(&SeeingNP, nullptr);
202  return true;
203  }
204 
205  if (strcmp(name, "FOCUS_TEMPERATURE") == 0)
206  {
207  TemperatureNP.s = IPS_OK;
208  IUUpdateNumber(&TemperatureNP, values, names, n);
209 
210  IDSetNumber(&TemperatureNP, nullptr);
211  return true;
212  }
213  }
214 
215  // Let INDI::Focuser handle any other number properties
216  return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
217 }
218 
219 /************************************************************************************
220  *
221 ************************************************************************************/
222 IPState FocusSim::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
223 {
224  double mid = (FocusAbsPosN[0].max - FocusAbsPosN[0].min) / 2;
225  int mode = IUFindOnSwitchIndex(&ModeSP);
226  double targetTicks = ((dir == FOCUS_INWARD) ? -1 : 1) * (speed * duration);
227 
228  internalTicks += targetTicks;
229 
230  if (mode == MODE_ALL)
231  {
232  if (internalTicks < FocusAbsPosN[0].min || internalTicks > FocusAbsPosN[0].max)
233  {
234  internalTicks -= targetTicks;
235  LOG_ERROR("Cannot move focuser in this direction any further.");
236  return IPS_ALERT;
237  }
238  }
239 
240  // simulate delay in motion as the focuser moves to the new position
241  usleep(duration * 1000);
242 
243  double ticks = initTicks + (internalTicks - mid) / 5000.0;
244 
245  FWHMN[0].value = 0.5625 * ticks * ticks + SeeingN[0].value;
246 
247  LOGF_DEBUG("TIMER Current internal ticks: %g FWHM ticks: %g FWHM: %g", internalTicks, ticks,
248  FWHMN[0].value);
249 
250  if (mode == MODE_ALL)
251  {
252  FocusAbsPosN[0].value = internalTicks;
253  IDSetNumber(&FocusAbsPosNP, nullptr);
254  }
255 
256  if (FWHMN[0].value < SeeingN[0].value)
257  FWHMN[0].value = SeeingN[0].value;
258 
259  IDSetNumber(&FWHMNP, nullptr);
260 
261  return IPS_OK;
262 }
263 
264 /************************************************************************************
265  *
266 ************************************************************************************/
267 IPState FocusSim::MoveAbsFocuser(uint32_t targetTicks)
268 {
269  double mid = (FocusAbsPosN[0].max - FocusAbsPosN[0].min) / 2;
270 
271  internalTicks = targetTicks;
272 
273  // Limit to +/- 10 from initTicks
274  double ticks = initTicks + (targetTicks - mid) / 5000.0;
275 
276  // simulate delay in motion as the focuser moves to the new position
277  usleep(std::abs((int)(targetTicks - FocusAbsPosN[0].value) * FOCUS_MOTION_DELAY));
278 
279  FocusAbsPosN[0].value = targetTicks;
280 
281  FWHMN[0].value = 0.5625 * ticks * ticks + SeeingN[0].value;
282 
283  LOGF_DEBUG("ABS Current internal ticks: %g FWHM ticks: %g FWHM: %g", internalTicks, ticks,
284  FWHMN[0].value);
285 
286  if (FWHMN[0].value < SeeingN[0].value)
287  FWHMN[0].value = SeeingN[0].value;
288 
289  IDSetNumber(&FWHMNP, nullptr);
290 
291  return IPS_OK;
292 }
293 
294 /************************************************************************************
295  *
296 ************************************************************************************/
298 {
299  uint32_t targetTicks = FocusAbsPosN[0].value + (ticks * (dir == FOCUS_INWARD ? -1 : 1));
301  IDSetNumber(&FocusAbsPosNP, nullptr);
302  return MoveAbsFocuser(targetTicks);
303 }
304 
305 /************************************************************************************
306  *
307 ************************************************************************************/
309 {
310  INDI_UNUSED(speed);
311  return true;
312 }
313 
314 /************************************************************************************
315  *
316 ************************************************************************************/
317 bool FocusSim::SetFocuserBacklash(int32_t steps)
318 {
319  INDI_UNUSED(steps);
320  return true;
321 }
322 
323 /************************************************************************************
324  *
325 ************************************************************************************/
327 {
328  INDI_UNUSED(enabled);
329  return true;
330 }
INDI::FocuserInterface::FOCUSER_CAN_ABS_MOVE
@ FOCUSER_CAN_ABS_MOVE
Definition: indifocuserinterface.h:74
IP_RO
@ IP_RO
Definition: indiapi.h:183
FOCUS_MOTION_DELAY
#define FOCUS_MOTION_DELAY
Definition: focus_simulator.cpp:30
INDI::FocuserInterface::FOCUSER_CAN_REL_MOVE
@ FOCUSER_CAN_REL_MOVE
Definition: indifocuserinterface.h:75
INDI::FocuserInterface::FocusAbsPosNP
INumberVectorProperty FocusAbsPosNP
Definition: indifocuserinterface.h:282
FocusSim
The FocusSim class provides a simple Focuser simulator that can simulator the following devices:
Definition: focus_simulator.h:34
IPState
IPState
Property state.
Definition: indiapi.h:158
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
min
double min(void)
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
INDI::Focuser::ISGetProperties
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:111
FocusSim::SetFocuserBacklash
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
Definition: focus_simulator.cpp:317
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
IUFillNumber
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:348
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
INDI::FocuserInterface::FOCUSER_HAS_VARIABLE_SPEED
@ FOCUSER_HAS_VARIABLE_SPEED
Definition: indifocuserinterface.h:79
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
focus_simulator.h
FocusSim::updateProperties
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: focus_simulator.cpp:121
max
double max(void)
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
FocusSim::MoveAbsFocuser
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition: focus_simulator.cpp:267
INDI::FocuserInterface::FOCUS_INWARD
@ FOCUS_INWARD
Definition: indifocuserinterface.h:68
IUFillSwitchVector
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:412
FocusSim::MoveRelFocuser
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition: focus_simulator.cpp:297
IUFillNumberVector
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:455
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
FocusSim::ISGetProperties
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: focus_simulator.cpp:68
FocusSim::Connect
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: focus_simulator.cpp:43
INDI::Focuser::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indifocuser.cpp:120
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
INDI::DefaultDevice::loadConfig
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
Definition: defaultdevice.cpp:147
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
FocusSim::getDefaultName
const char * getDefaultName() override
Definition: focus_simulator.cpp:60
FocusSim::FocusSim
FocusSim()
Definition: focus_simulator.cpp:35
LOG_ERROR
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
INDI::FocuserInterface::SetCapability
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
Definition: indifocuserinterface.h:95
name
const char * name
Definition: indiserver.c:116
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
FocusSim::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: focus_simulator.cpp:192
FocusSim::Disconnect
bool Disconnect() override
Disconnect from device.
Definition: focus_simulator.cpp:52
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
INDI::FocuserInterface::FocusDirection
FocusDirection
Definition: indifocuserinterface.h:66
IP_RW
@ IP_RW
Definition: indiapi.h:185
INDI::FocuserInterface::FOCUSER_HAS_BACKLASH
@ FOCUSER_HAS_BACKLASH
Definition: indifocuserinterface.h:80
FocusSim::MoveFocuser
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.
Definition: focus_simulator.cpp:222
ISState
ISState
Switch state.
Definition: indiapi.h:148
FocusSim::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: focus_simulator.cpp:144
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1424
INDI::Focuser::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indifocuser.cpp:58
INDI::DefaultDevice::deleteProperty
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
Definition: defaultdevice.cpp:965
INDI::Focuser::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indifocuser.cpp:168
FocusSim::SetFocuserSpeed
virtual bool SetFocuserSpeed(int speed) override
SetFocuserSpeed Set Focuser speed.
Definition: focus_simulator.cpp:308
INDI::FocuserInterface::FocusAbsPosN
INumber FocusAbsPosN[1]
Definition: indifocuserinterface.h:283
IDSetNumber
void void void IDSetNumber(const INumberVectorProperty *n, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing number vector property.
FocusSim::SetFocuserBacklashEnabled
virtual bool SetFocuserBacklashEnabled(bool enabled) override
SetFocuserBacklashEnabled Enables or disables the focuser backlash compensation.
Definition: focus_simulator.cpp:326
IDSetSwitch
void void void void void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing switch vector property.
IUFillSwitch
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:320
INDI::Focuser::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: indifocuser.cpp:145
FocusSim::initProperties
bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: focus_simulator.cpp:82
INDI::FocuserInterface::FocusSpeedN
INumber FocusSpeedN[1]
Definition: indifocuserinterface.h:269
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151