Instrument Neutral Distributed Interface INDI 2.2.5
pac_simulator.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 PAC Simulator (Polar Alignment Correction)
3
4 SPDX-FileCopyrightText: 2026 Joaquin Rodriguez
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*******************************************************************************/
7
8#include "pac_simulator.h"
10
11#include <memory>
12
13static std::unique_ptr<PACSimulator> simulator(new PACSimulator());
14
21
23{
25
27
28 // Adjust speed range for the simulator: 1 (slowest, 5 s) to 5 (fastest, 1 s)
29 SpeedNP[0].setMin(1);
30 SpeedNP[0].setMax(5);
31 SpeedNP[0].setStep(1);
32 SpeedNP[0].setValue(1);
33
35
36 CorrectionGainNP[0].fill("GAIN", "Gain (%)", "%.0f", 0, 100, 10, 100);
37 CorrectionGainNP.fill(getDeviceName(), "CORRECTION_GAIN", "Correction Gain", MAIN_CONTROL_TAB, IP_RW, 0, IPS_IDLE);
38 CorrectionGainNP.load();
39
41
42 return true;
43}
44
46{
48
49 if (isConnected())
50 defineProperty(CorrectionGainNP);
51 else
52 deleteProperty(CorrectionGainNP);
53
55
56 return true;
57}
58
59bool PACSimulator::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
60{
61 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
62 {
63 if (CorrectionGainNP.isNameMatch(name))
64 {
65 CorrectionGainNP.update(values, names, n);
66 CorrectionGainNP.setState(IPS_OK);
67 CorrectionGainNP.apply();
68 return true;
69 }
70
71 if (PACI::processNumber(dev, name, values, names, n))
72 return true;
73 }
74
75 return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
76}
77
78bool PACSimulator::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
79{
80 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
81 {
82 if (PACI::processSwitch(dev, name, states, names, n))
83 return true;
84 }
85
86 return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
87}
88
90{
92 CorrectionGainNP.save(fp);
94 return true;
95}
96
97// ---------------------------------------------------------------------------
98// Abort
99// ---------------------------------------------------------------------------
100
102{
103 LOG_INFO("Alignment correction motion aborted.");
104 m_MovingAxes = 0;
105 return true;
106}
107
108// ---------------------------------------------------------------------------
109// Speed and reverse
110// ---------------------------------------------------------------------------
111
112bool PACSimulator::SetPACSpeed(uint16_t speed)
113{
114 LOGF_INFO("Simulator speed set to %u (move duration will be %.0f s).",
115 speed, SpeedNP[0].getMax() + 1 - speed);
116 return true;
117}
118
119bool PACSimulator::ReverseAZ(bool enabled)
120{
121 LOGF_INFO("Azimuth direction reverse %s.", enabled ? "enabled" : "disabled");
122 return true;
123}
124
125bool PACSimulator::ReverseALT(bool enabled)
126{
127 LOGF_INFO("Altitude direction reverse %s.", enabled ? "enabled" : "disabled");
128 return true;
129}
130
131// ---------------------------------------------------------------------------
132// Single-axis movement
133// ---------------------------------------------------------------------------
134
136{
137 // Duration is inversely proportional to speed: speed 1 → max s, speed max → 1 s.
138 const double duration = SpeedNP[0].getMax() + 1 - SpeedNP[0].getValue();
139 const double gain = CorrectionGainNP[0].getValue() / 100.0;
140 const double effective = degrees * gain;
141 const char *direction = (effective >= 0) ? "East" : "West";
142
143 LOGF_INFO("Simulating azimuth move: %.4f deg %s (duration %.0f s, speed %.0f, gain %.0f%%).",
144 std::abs(effective), direction, duration, SpeedNP[0].getValue(), CorrectionGainNP[0].getValue());
145
146 m_MovingAxes++;
147
148 INDI::Timer::singleShot(static_cast<int>(duration * 1000), [this, effective]()
149 {
150 LOGF_INFO("Azimuth move complete: %.4f deg %s.", std::abs(effective), (effective >= 0) ? "East" : "West");
151
152 m_MovingAxes--;
153 if (m_MovingAxes <= 0)
154 {
155 m_MovingAxes = 0;
156 // Broadcast IPS_OK so snooping drivers (e.g. telescope simulator) can
157 // read the step values and apply the polar-alignment correction.
160 }
161 });
162
163 return IPS_BUSY;
164}
165
167{
168 // Duration is inversely proportional to speed: speed 1 → max s, speed max → 1 s.
169 const double duration = SpeedNP[0].getMax() + 1 - SpeedNP[0].getValue();
170 const double gain = CorrectionGainNP[0].getValue() / 100.0;
171 const double effective = degrees * gain;
172 const char *direction = (effective >= 0) ? "North" : "South";
173
174 LOGF_INFO("Simulating altitude move: %.4f deg %s (duration %.0f s, speed %.0f, gain %.0f%%).",
175 std::abs(effective), direction, duration, SpeedNP[0].getValue(), CorrectionGainNP[0].getValue());
176
177 m_MovingAxes++;
178
179 INDI::Timer::singleShot(static_cast<int>(duration * 1000), [this, effective]()
180 {
181 LOGF_INFO("Altitude move complete: %.4f deg %s.", std::abs(effective), (effective >= 0) ? "North" : "South");
182
183 m_MovingAxes--;
184 if (m_MovingAxes <= 0)
185 {
186 m_MovingAxes = 0;
189 }
190 });
191
192 return IPS_BUSY;
193}
bool isConnected() const
const char * getDeviceName() const
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
bool saveConfigItems(FILE *fp)
saveConfigItems Save PAC interface properties to config file. Call this from your driver's saveConfig...
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process PAC number properties.
INDI::PropertyNumber SpeedNP
void initProperties(const char *group)
initProperties Initialize PAC properties. Call this from your driver's initProperties().
void SetCapability(uint32_t cap)
SetCapability sets the PAC device capabilities. Call this in the driver constructor.
INDI::PropertyNumber ManualAdjustmentNP
bool processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process PAC switch properties.
bool updateProperties()
updateProperties Define or delete properties based on connection state. Call this from your driver's ...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool load()
load Attempt to load property values from configuration file.
void save(FILE *f) const
save Save property to configuration file.
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)
static void singleShot(int msec, const std::function< void()> &callback)
This static function calls a the given function after a given time interval.
Provides interface to implement automated polar alignment correction (PAC).
virtual bool ReverseAZ(bool enabled) override
ReverseAZ Reverse the direction of azimuth axis movement.
virtual bool ReverseALT(bool enabled) override
ReverseALT Reverse the direction of altitude axis movement.
virtual bool SetPACSpeed(uint16_t speed) override
SetPACSpeed Set the motor speed used for axis movements.
bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual IPState MoveALT(double degrees) override
MoveALT Move the altitude axis by the given number of degrees.
virtual IPState MoveAZ(double degrees) override
Move the azimuth axis by the given number of degrees.
virtual bool AbortMotion() override
AbortMotion Abort all axis motion immediately.
bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
ISState
Switch state.
Definition indiapi.h:148
@ IP_RW
Definition indiapi.h:184
IPState
Property state.
Definition indiapi.h:158
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOG_INFO(txt)
Definition indilogger.h:74