Instrument Neutral Distributed Interface INDI 2.2.5
esatto.cpp
Go to the documentation of this file.
1/*
2 Esatto Focuser
3 Copyright (C) 2022 Jasem Mutlaq
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19*/
20
21#include "esatto.h"
22
23#include <cmath>
24#include <cstring>
25#include <memory>
26#include <algorithm>
27
29
30static std::unique_ptr<Esatto> sesto(new Esatto());
31
32static const char *ENVIRONMENT_TAB = "Environment";
33
35{
36 setVersion(1, 0);
37
38 // Can move in Absolute & Relative motions, can AbortFocuser motion.
40
41}
42
47{
48
50
51 FocusBacklashNP[0].setMin(0);
52 FocusBacklashNP[0].setMax(10000);
53 FocusBacklashNP[0].setStep(1);
54 FocusBacklashNP[0].setValue(0);
55
56 setConnectionParams();
57
58 // Firmware information
59 FirmwareTP[FIRMWARE_SN].fill("SERIALNUMBER", "Serial Number", "");
60 FirmwareTP[FIRMWARE_VERSION].fill("VERSION", "Version", "");
61 FirmwareTP.fill(getDeviceName(), "FOCUS_FIRMWARE", "Firmware", CONNECTION_TAB, IP_RO, 0, IPS_IDLE);
62
63 // Voltage Information
64 VoltageNP[VOLTAGE_12V].fill("VOLTAGE_12V", "12v", "%.2f", 0, 100, 0., 0.);
65 VoltageNP[VOLTAGE_USB].fill("VOLTAGE_USB", "USB", "%.2f", 0, 100, 0., 0.);
66 VoltageNP.fill(getDeviceName(), "VOLTAGE_IN", "Voltage in", ENVIRONMENT_TAB, IP_RO, 0, IPS_IDLE);
67
68 // Focuser temperature
69 TemperatureNP[TEMPERATURE_MOTOR].fill("TEMPERATURE", "Motor (c)", "%.2f", -50, 70., 0., 0.);
70 TemperatureNP[TEMPERATURE_EXTERNAL].fill("TEMPERATURE_ETX", "External (c)", "%.2f", -50, 70., 0., 0.);
71 TemperatureNP.fill(getDeviceName(), "FOCUS_TEMPERATURE", "Temperature", ENVIRONMENT_TAB, IP_RO, 0, IPS_IDLE);
72
73 // Speed Moves
74 FastMoveSP[FASTMOVE_IN].fill("FASTMOVE_IN", "Move In", ISS_OFF);
75 FastMoveSP[FASTMOVE_OUT].fill("FASTMOVE_OUT", "Move out", ISS_OFF);
76 FastMoveSP[FASTMOVE_STOP].fill("FASTMOVE_STOP", "Stop", ISS_OFF);
77 FastMoveSP.fill(getDeviceName(), "FAST_MOVE", "Calibration Move", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
78
79 // Override the default Max. Position to make it Read-Only
81
82 // Relative and absolute movement
83 FocusRelPosNP[0].setMin(0.);
84 FocusRelPosNP[0].setMax(50000.);
85 FocusRelPosNP[0].setValue(0);
86 FocusRelPosNP[0].setStep(1000);
87
88 FocusAbsPosNP[0].setMin(0.);
89 FocusAbsPosNP[0].setMax(200000.);
90 FocusAbsPosNP[0].setValue(0);
91 FocusAbsPosNP[0].setStep(10000);
92
93 FocusMaxPosNP[0].setValue(2097152);
94 PresetNP[0].setMax(FocusMaxPosNP[0].getValue());
95 PresetNP[1].setMax(FocusMaxPosNP[0].getValue());
96 PresetNP[2].setMax(FocusMaxPosNP[0].getValue());
97
99
101
102 return true;
103}
104
109{
110 if (isConnected())
111 getStartupValues();
112
114
115 if (isConnected())
116 {
117 defineProperty(FirmwareTP);
118
119 if (updateVoltageIn())
120 defineProperty(VoltageNP);
121
122 if (updateTemperature())
123 defineProperty(TemperatureNP);
124 }
125 else
126 {
127 if (TemperatureNP.getState() == IPS_OK)
128 deleteProperty(TemperatureNP);
129 deleteProperty(FirmwareTP);
130 deleteProperty(VoltageNP.getName());
131 }
132
133 return true;
134}
135
140{
141 if (Ack())
142 {
143 LOGF_INFO("%s is online. Getting focus parameters...", getDeviceName());
144
145 return true;
146 }
147
148 LOG_INFO("Error retrieving data from device, please ensure focuser is powered and the port is correct.");
149 return false;
150}
151
156{
157 return "Esatto";
158}
159
163bool Esatto::updateTemperature()
164{
165 double temperature = 0;
166
167 if (isSimulation())
168 temperature = 23.5;
169 else if ( m_Esatto->getMotorTemp(temperature) == false)
170 return false;
171
172 if (temperature > 90)
173 return false;
174
175 TemperatureNP[TEMPERATURE_MOTOR].setValue(temperature);
176 TemperatureNP.setState(IPS_OK);
177
178 // External temperature - Optional
179 if (m_Esatto->getExternalTemp(temperature))
180 {
181 if (temperature < 90)
182 TemperatureNP[TEMPERATURE_EXTERNAL].setValue(temperature);
183 else
184 TemperatureNP[TEMPERATURE_EXTERNAL].setValue(-273.15);
185 }
186
187 return true;
188}
189
193bool Esatto::updatePosition()
194{
195 uint32_t steps = 0;
196 if (isSimulation())
197 steps = static_cast<uint32_t>(FocusAbsPosNP[0].getValue());
198 else if (m_Esatto->getAbsolutePosition(steps) == false)
199 return false;
200
201 FocusAbsPosNP[0].setValue(steps);
202 return true;
203}
204
208bool Esatto::updateVoltageIn()
209{
210 double voltage;
211 if (m_Esatto->getVoltage12v(voltage))
212 VoltageNP[VOLTAGE_12V].setValue(voltage);
213
214 VoltageNP.setState((voltage >= 11.0) ? IPS_OK : IPS_ALERT);
215 if (m_Esatto->getVoltageUSB(voltage))
216 VoltageNP[VOLTAGE_USB].setValue(voltage);
217 return true;
218}
219
223bool Esatto::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
224{
225 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
226 {
227 // Fast motion
228 if (FastMoveSP.isNameMatch(name))
229 {
230 FastMoveSP.update(states, names, n);
231 auto current_switch = FastMoveSP.findOnSwitchIndex();
232
233 switch (current_switch)
234 {
235 case FASTMOVE_IN:
236 m_Esatto->fastMoveIn();
237 break;
238 case FASTMOVE_OUT:
239 m_Esatto->fastMoveOut();
240 break;
241 case FASTMOVE_STOP:
242 m_Esatto->stop();
243 break;
244 default:
245 break;
246 }
247
248 FastMoveSP.setState(IPS_BUSY);
249 FastMoveSP.apply();
250 return true;
251 }
252 }
253 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
254}
255
259IPState Esatto::MoveAbsFocuser(uint32_t targetTicks)
260{
261 if (m_Esatto->goAbsolutePosition(targetTicks) == false)
262 return IPS_ALERT;
263
264 return IPS_BUSY;
265}
266
271{
272 int reversed = (FocusReverseSP.findOnSwitchIndex() == INDI_ENABLED) ? -1 : 1;
273 int relativeTicks = ((dir == FOCUS_INWARD) ? -ticks : ticks) * reversed;
274 double newPosition = FocusAbsPosNP[0].getValue() + relativeTicks;
275
276 bool rc = MoveAbsFocuser(newPosition);
277
278 return (rc ? IPS_BUSY : IPS_ALERT);
279}
280
285{
286 if (isSimulation())
287 return true;
288
289 return m_Esatto->stop();
290}
291
296{
297 //if (!isConnected() || FocusAbsPosNP.getState() == IPS_BUSY || FocusRelPosNP.getState() == IPS_BUSY)
298 if (!isConnected())
299 {
301 return;
302 }
303
304 auto lastPos = FocusAbsPosNP[0].getValue();
305 bool rc = updatePosition();
306 if (rc && (std::abs(lastPos - FocusAbsPosNP[0].getValue()) > 0))
307 {
308 if (FocusAbsPosNP.getState() == IPS_BUSY && m_Esatto->isBusy() == false)
309 {
310 // To prevent reporting a bit too old position as the final one
311 updatePosition();
312
316 }
317
319 }
320
321 if (m_TemperatureCounter++ == TEMPERATURE_FREQUENCY)
322 {
323 rc = updateTemperature();
324
325 // Only update temperature if there is a change of 0.1 or more
326 if (rc && (std::abs(m_LastTemperature[TEMPERATURE_EXTERNAL] - TemperatureNP[TEMPERATURE_EXTERNAL].value) >=
327 MEASUREMENT_THRESHOLD ||
328 std::abs(m_LastTemperature[TEMPERATURE_MOTOR] - TemperatureNP[TEMPERATURE_MOTOR].value) >= MEASUREMENT_THRESHOLD ))
329 {
330 m_LastTemperature[TEMPERATURE_EXTERNAL] = TemperatureNP[TEMPERATURE_EXTERNAL].value;
331 m_LastTemperature[TEMPERATURE_MOTOR] = TemperatureNP[TEMPERATURE_MOTOR].value;
332 TemperatureNP.apply();
333 }
334
335 if (updateVoltageIn())
336 {
337 if (std::abs(m_LastVoltage[VOLTAGE_12V] - VoltageNP[VOLTAGE_12V].getValue()) >= MEASUREMENT_THRESHOLD ||
338 std::abs(m_LastVoltage[VOLTAGE_USB] - VoltageNP[VOLTAGE_USB].getValue()) >= MEASUREMENT_THRESHOLD)
339 {
340 m_LastVoltage[VOLTAGE_12V] = VoltageNP[VOLTAGE_12V].getValue();
341 m_LastVoltage[VOLTAGE_USB] = VoltageNP[VOLTAGE_USB].getValue();
342 VoltageNP.apply();
343 if (VoltageNP[VOLTAGE_12V].getValue() < 11.0)
344 LOG_WARN("Please check 12v DC power supply is connected.");
345 }
346 }
347 m_TemperatureCounter = 0; // Reset the counter
348 }
349
351}
352
356bool Esatto::getStartupValues()
357{
358 auto rc1 = updatePosition();
359 uint32_t steps {0};
360 auto rc2 = m_Esatto->getBacklash(steps);
361 if (rc2)
362 FocusBacklashNP[0].setValue(steps);
363
364 auto rc3 = updateMaxLimit();
365
366 return rc1 && rc2 && rc3;
367}
368
372bool Esatto::ReverseFocuser(bool enable)
373{
374 INDI_UNUSED(enable);
375 return false;
376}
377
381bool Esatto::Ack()
382{
383 std::string response;
384 m_Esatto.reset(new PrimalucaLabs::Esatto(getDeviceName(), PortFD));
385
386 if(m_Esatto->getSerialNumber(response))
387 LOGF_INFO("Serial number: %s", response.c_str());
388 else
389 return false;
390
391 FirmwareTP[FIRMWARE_SN].setText(response.c_str());
392
393 if (m_Esatto->getFirmwareVersion(response))
394 {
395 LOGF_INFO("Firmware version: %s", response.c_str());
396 IUSaveText(&FirmwareTP[FIRMWARE_VERSION], response.c_str());
397 }
398
399 return true;
400}
401
405void Esatto::setConnectionParams()
406{
409}
410
414bool Esatto::SetFocuserBacklash(int32_t steps)
415{
416 return m_Esatto->setBacklash(steps);
417}
418
422bool Esatto::updateMaxLimit()
423{
424 uint32_t maxLimit = 0;
425
426 if (m_Esatto->getMaxPosition(maxLimit) == false)
427 return false;
428
429 FocusMaxPosNP[0].setMax(maxLimit);
430 if (FocusMaxPosNP[0].getValue() > maxLimit)
431 FocusMaxPosNP[0].setValue(maxLimit);
432
433 FocusAbsPosNP[0].setMin(0);
434 FocusAbsPosNP[0].setMax(maxLimit);
435 FocusAbsPosNP[0].setValue(0);
436 FocusAbsPosNP[0].setStep((FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 50.0);
437
438 FocusRelPosNP[0].setMin(0.);
439 FocusRelPosNP[0].setMax(FocusAbsPosNP[0].getStep());
440 FocusRelPosNP[0].setValue(0);
441 FocusRelPosNP[0].setStep(FocusAbsPosNP[0].getStep());
442
443 PresetNP[0].setMax(maxLimit);
444 PresetNP[0].setStep((FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 50.0);
445 PresetNP[1].setMax(maxLimit);
446 PresetNP[1].setStep((FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 50.0);
447 PresetNP[2].setMax(maxLimit);
448 PresetNP[2].setStep((FocusAbsPosNP[0].getMax() - FocusAbsPosNP[0].getMin()) / 50.0);
449
450
452 return true;
453}
double temperature
void setWordSize(const uint8_t &value)
setWordSize Set word size to be used in the serial connection. Default 8
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
const char * getDefaultName() override
Definition esatto.cpp:155
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...
Definition esatto.cpp:223
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition esatto.cpp:284
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
Definition esatto.cpp:270
Esatto()
Definition esatto.cpp:34
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveFocuser the focuser to an absolute position.
Definition esatto.cpp:259
virtual bool SetFocuserBacklash(int32_t steps) override
SetFocuserBacklash Set the focuser backlash compensation value.
Definition esatto.cpp:414
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
Definition esatto.cpp:46
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
Definition esatto.cpp:139
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition esatto.cpp:295
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
Definition esatto.cpp:372
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
Definition esatto.cpp:108
bool isConnected() const
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
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)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
INDI::PropertyNumber FocusRelPosNP
INDI::PropertySwitch FocusReverseSP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusMaxPosNP
INDI::PropertyNumber FocusBacklashNP
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 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,...
Connection::Serial * serialConnection
INDI::PropertyNumber PresetNP
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
const char * getName() const
bool isNameMatch(const char *otherName) const
void setPermission(IPerm permission)
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)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
const char * CONNECTION_TAB
CONNECTION_TAB Where all device connection settings (serial, usb, ethernet) are defined and controlle...
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
@ ISS_OFF
Definition indiapi.h:149
@ 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_ATMOST1
Definition indiapi.h:172
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition indidevapi.c:44
#define INDI_UNUSED(x)
Definition indidevapi.h:132
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOG_WARN(txt)
Definition indilogger.h:73
#define LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName
#define ENVIRONMENT_TAB