Instrument Neutral Distributed Interface INDI 2.2.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.
27static std::unique_ptr<FocusSim> focusSim(new FocusSim());
28
29/************************************************************************************
30 *
31************************************************************************************/
37
38/************************************************************************************
39 *
40************************************************************************************/
42{
43 SetTimer(1000);
44 return true;
45}
46
47/************************************************************************************
48 *
49************************************************************************************/
51{
52 return true;
53}
54
55/************************************************************************************
56 *
57************************************************************************************/
59{
60 return "Focuser Simulator";
61}
62
63/************************************************************************************
64 *
65************************************************************************************/
66void FocusSim::ISGetProperties(const char *dev)
67{
68 if (dev != nullptr && strcmp(dev, getDeviceName()) != 0)
69 return;
70
72
73 defineProperty(ModeSP);
74 loadConfig(true, "Mode");
75}
76
77/************************************************************************************
78 *
79************************************************************************************/
81{
83
84 SeeingNP[0].fill("SIM_SEEING", "arcseconds", "%4.2f", 0, 60, 0, 3.5);
85 SeeingNP.fill(getDeviceName(), "SEEING_SETTINGS", "Seeing", MAIN_CONTROL_TAB, IP_RW, 60,
86 IPS_IDLE);
87
88 FWHMNP[0].fill("SIM_FWHM", "arcseconds", "%4.2f", 0, 60, 0, 7.5);
89 FWHMNP.fill(getDeviceName(), "FWHM", "FWHM", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
90
91 TemperatureNP[0].fill("TEMPERATURE", "Celsius", "%6.2f", -50., 70., 0., 0.);
92 TemperatureNP.fill(getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
94
95 DelayNP[0].fill("DELAY_VALUE", "Value (uS)", "%.f", 0, 60000, 100, 100);
96 DelayNP.fill(getDeviceName(), "DELAY", "Delay", OPTIONS_TAB, IP_RW, 60, IPS_IDLE);
97
98 ModeSP[MODE_ALL].fill("All", "All", ISS_ON);
99 ModeSP[MODE_ABSOLUTE].fill("Absolute", "Absolute", ISS_OFF);
100 ModeSP[MODE_RELATIVE].fill("Relative", "Relative", ISS_OFF);
101 ModeSP[MODE_TIMER].fill("Timer", "Timer", ISS_OFF);
102 ModeSP.fill(getDeviceName(), "Mode", "Mode", MAIN_CONTROL_TAB, IP_RW,
103 ISR_1OFMANY, 60, IPS_IDLE);
104
105 initTicks = sqrt(FWHMNP[0].getValue() - SeeingNP[0].getValue()) / 0.75;
106
107 FocusSpeedNP[0].setMin(1);
108 FocusSpeedNP[0].setMax(5);
109 FocusSpeedNP[0].setStep(1);
110 FocusSpeedNP[0].setValue(1);
111
112 FocusAbsPosNP[0].setValue(FocusAbsPosNP[0].getMax() / 2);
113
114 internalTicks = FocusAbsPosNP[0].getValue();
115
116 return true;
117}
118
119/************************************************************************************
120 *
121************************************************************************************/
123{
125
126 if (isConnected())
127 {
128 defineProperty(SeeingNP);
129 defineProperty(FWHMNP);
130 defineProperty(TemperatureNP);
131 defineProperty(DelayNP);
132 }
133 else
134 {
135 deleteProperty(SeeingNP);
136 deleteProperty(FWHMNP);
137 deleteProperty(TemperatureNP);
138 deleteProperty(DelayNP);
139 }
140
141 return true;
142}
143
144/************************************************************************************
145 *
146************************************************************************************/
147bool FocusSim::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
148{
149 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
150 {
151 // Modes
152 if (ModeSP.isNameMatch(name))
153 {
154 ModeSP.update(states, names, n);
155 uint32_t cap = 0;
156 int index = ModeSP.findOnSwitchIndex();
157
158 switch (index)
159 {
160 case MODE_ALL:
162 break;
163
164 case MODE_ABSOLUTE:
166 break;
167
168 case MODE_RELATIVE:
170 break;
171
172 case MODE_TIMER:
174 break;
175
176 default:
177 ModeSP.setState(IPS_ALERT);
178 LOG_INFO("Unknown mode index");
179 ModeSP.apply();
180 return true;
181 }
182
184 ModeSP.setState(IPS_OK);
185 ModeSP.apply();
186 return true;
187 }
188 }
189
190 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
191}
192
193/************************************************************************************
194 *
195************************************************************************************/
196bool FocusSim::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
197{
198 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
199 {
200 if (strcmp(name, "SEEING_SETTINGS") == 0)
201 {
202 SeeingNP.setState(IPS_OK);
203 SeeingNP.update(values, names, n);
204
205 SeeingNP.apply();
206 return true;
207 }
208
209 if (strcmp(name, "FOCUS_TEMPERATURE") == 0)
210 {
211 TemperatureNP.setState(IPS_OK);
212 TemperatureNP.update(values, names, n);
213
214 TemperatureNP.apply();
215 return true;
216 }
217
218 // Delay
219 if (DelayNP.isNameMatch(name))
220 {
221 DelayNP.update(values, names, n);
222 DelayNP.setState(IPS_OK);
223 DelayNP.apply();
224 saveConfig(true, DelayNP.getName());
225 return true;
226 }
227 }
228
229 // Let INDI::Focuser handle any other number properties
230 return INDI::Focuser::ISNewNumber(dev, name, values, names, n);
231}
232
233/************************************************************************************
234 *
235************************************************************************************/
236IPState FocusSim::MoveFocuser(FocusDirection dir, int speed, uint16_t duration)
237{
238 double mid = (FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 2;
239 int mode = ModeSP.findOnSwitchIndex();
240 double targetTicks = ((dir == FOCUS_INWARD) ? -1 : 1) * (speed * duration);
241
242 internalTicks += targetTicks;
243
244 if (mode == MODE_ALL)
245 {
246 if (internalTicks < FocusAbsPosNP[0].getMin() || internalTicks > FocusAbsPosNP[0].getMax())
247 {
248 internalTicks -= targetTicks;
249 LOG_ERROR("Cannot move focuser in this direction any further.");
250 return IPS_ALERT;
251 }
252 }
253
254 // simulate delay in motion as the focuser moves to the new position
255 usleep(duration * 1000);
256
257 double ticks = initTicks + (internalTicks - mid) / 5000.0;
258
259 FWHMNP[0].setValue(0.5625 * ticks * ticks + SeeingNP[0].getValue());
260
261 LOGF_DEBUG("TIMER Current internal ticks: %g FWHM ticks: %g FWHM: %g", internalTicks, ticks,
262 FWHMNP[0].getValue());
263
264 if (mode == MODE_ALL)
265 {
266 FocusAbsPosNP[0].setValue(internalTicks);
268 }
269
270 if (FWHMNP[0].getValue() < SeeingNP[0].getValue())
271 FWHMNP[0].setValue(SeeingNP[0].getValue());
272
273 FWHMNP.apply();
274
275 return IPS_OK;
276}
277
278/************************************************************************************
279 *
280************************************************************************************/
282{
283 double mid = (FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 2;
284
285 internalTicks = targetTicks;
286
287 // Limit to +/- 10 from initTicks
288 double ticks = initTicks + (targetTicks - mid) / 5000.0;
289
290 // simulate delay in motion as the focuser moves to the new position
291 usleep(std::abs((targetTicks - FocusAbsPosNP[0].getValue()) * DelayNP[0].getValue()));
292
293 FocusAbsPosNP[0].setValue(targetTicks);
294
295 FWHMNP[0].setValue(0.5625 * ticks * ticks + SeeingNP[0].getValue());
296
297 LOGF_DEBUG("ABS Current internal ticks: %g FWHM ticks: %g FWHM: %g", internalTicks, ticks,
298 FWHMNP[0].getValue());
299
300 if (FWHMNP[0].getValue() < SeeingNP[0].getValue())
301 FWHMNP[0].setValue(SeeingNP[0].getValue());
302
303 FWHMNP.apply();
304
305 return IPS_OK;
306}
307
308/************************************************************************************
309 *
310************************************************************************************/
312{
313 uint32_t targetTicks = FocusAbsPosNP[0].getValue() + (ticks * (dir == FOCUS_INWARD ? -1 : 1));
316 return MoveAbsFocuser(targetTicks);
317}
318
319/************************************************************************************
320 *
321************************************************************************************/
323{
324 INDI_UNUSED(speed);
325 return true;
326}
327
328/************************************************************************************
329 *
330************************************************************************************/
331bool FocusSim::SyncFocuser(uint32_t ticks)
332{
333 INDI_UNUSED(ticks);
334 return true;
335}
336
337/************************************************************************************
338 *
339************************************************************************************/
341{
342 INDI_UNUSED(steps);
343 return true;
344}
345
346/************************************************************************************
347 *
348************************************************************************************/
350{
351 INDI_UNUSED(enabled);
352 return true;
353}
354
355/************************************************************************************
356 *
357************************************************************************************/
359{
361
362 DelayNP.save(fp);
363
364 return true;
365}
The FocusSim class provides a simple Focuser simulator that can simulator the following devices:
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set current position to ticks without moving the focuser.
bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
void ISGetProperties(const char *dev) override
Handles client requests for property definitions for this device or all devices. Delegates to the bas...
bool Disconnect() override
Disconnect from device.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
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
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
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
bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
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
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.
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusSpeedNP
INDI::PropertyNumber FocusAbsPosNP
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Processes incoming new switch states from the client for this device. Handles updates to FocuserInter...
virtual bool saveConfigItems(FILE *fp) override
virtual void ISGetProperties(const char *dev) override
Handles client requests for property definitions for this device or all devices. Delegates to the bas...
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Processes incoming new number values from the client for this device. Handles updates to FocuserInter...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void save(FILE *f) const
save Save property to configuration file.
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)
bool update(const ISState states[], const char *const names[], int n)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, 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,...
ISState
Switch state.
Definition indiapi.h:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
#define INDI_UNUSED(x)
Definition indidevapi.h:132
#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
#define LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName