Instrument Neutral Distributed Interface INDI 2.2.5
ieaffocus.cpp
Go to the documentation of this file.
1/*
2 iOptron iEAF Focuser
3
4 Copyright (C) 2013 Paul de Backer ([email protected])
5 Copyright (C) 2024 Jasem Mutlaq
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21
22#include "ieaffocus.h"
23#include "indicom.h"
24
25#include <stdio.h>
26#include <termios.h>
27#include <string.h>
28#include <sys/time.h>
29#include <unistd.h>
30#include <math.h>
31#include <memory>
33
34#define iEAFFOCUS_TIMEOUT 4
35#define TEMPERATURE_THRESHOLD 0.1
36
37std::unique_ptr<iEAFFocus> ieafFocus(new iEAFFocus());
38
47
54
59{
61
64
65 TemperatureNP[0].fill("TEMPERATURE", "Celsius", "%2.2f", 0., 50., 0., 50.);
66 TemperatureNP.fill(getDeviceName(), "FOCUS_TEMPERATURE", "Temperature", MAIN_CONTROL_TAB, IP_RO, 0, IPS_IDLE);
67
68 SetZeroSP[0].fill("SETZERO", "Set Current Position to 0", ISS_OFF);
69 SetZeroSP.fill(getDeviceName(), "Zero Position", "Zero Position", OPTIONS_TAB, IP_RW, ISR_ATMOST1, 0, IPS_IDLE);
70
71 /* Relative and absolute movement */
72 FocusRelPosNP[0].setMin(0.);
73 FocusRelPosNP[0].setMax(5000.);
74 FocusRelPosNP[0].setValue(0.);
75 FocusRelPosNP[0].setStep(10.);
76
77 FocusAbsPosNP[0].setMin(0.);
78 FocusAbsPosNP[0].setMax(99999.);
79 FocusAbsPosNP[0].setValue(0.);
80 FocusAbsPosNP[0].setStep(10.);
81
82 return true;
83}
84
89{
91 if (isConnected())
92 {
93 defineProperty(TemperatureNP);
94 defineProperty(SetZeroSP);
95 GetFocusParams();
96 }
97 else
98 {
99 deleteProperty(TemperatureNP);
100 deleteProperty(SetZeroSP);
101 }
102
103 return true;
104
105}
106
111{
112 if (Ack())
113 {
114 DEBUG(INDI::Logger::DBG_SESSION, "iEAFFocus is online. Getting focus parameters...");
115 return true;
116 }
117 return false;
118}
119
124{
125 return "iEAFFocus";
126}
127
131bool iEAFFocus::Ack()
132{
133 int nbytes_written = 0, nbytes_read = 0, rc = -1;
134 char resp[16];
135 int ieafpos, ieafmodel, ieaflast;
136 sleep(2);
137 tcflush(PortFD, TCIOFLUSH);
138 if ( (rc = tty_write(PortFD, ":DeviceInfo#", 12, &nbytes_written)) != TTY_OK)
139 {
140 char errstr[MAXRBUF] = {0};
141 tty_error_msg(rc, errstr, MAXRBUF);
142 DEBUGF(INDI::Logger::DBG_ERROR, "Init send getdeviceinfo error: %s.", errstr);
143 return false;
144 }
145
146 if ( (rc = tty_read_section(PortFD, resp, '#', iEAFFOCUS_TIMEOUT * 2, &nbytes_read)) != TTY_OK)
147 {
148 char errstr[MAXRBUF] = {0};
149 tty_error_msg(rc, errstr, MAXRBUF);
150 DEBUGF(INDI::Logger::DBG_ERROR, "Init read deviceinfo error: %s.", errstr);
151 return false;
152 }
153 tcflush(PortFD, TCIOFLUSH);
154 resp[nbytes_read] = '\0';
155 sscanf(resp, "%6d%2d%4d", &ieafpos, &ieafmodel, &ieaflast);
156 //add iAFS Focuser
157 if ((ieafmodel == 2) || (ieafmodel == 3))
158 {
159 return true;
160 }
161 else
162 {
163 DEBUGF(INDI::Logger::DBG_ERROR, "Ack Response: %s", resp);
164 return false;
165 }
166
167 return true;
168}
169
173bool iEAFFocus::updateInfo()
174{
175 int nbytes_written = 0, nbytes_read = 0, rc = -1;
176 char errstr[MAXRBUF];
177 char resp[16] = {0};
178 char joedeviceinfo[16] = {0};
179 int ieafpos, ieafmove, ieaftemp, ieafdir;
180
181 tcflush(PortFD, TCIOFLUSH);
182 if ( (rc = tty_write(PortFD, ":FI#", 4, &nbytes_written)) != TTY_OK)
183 {
184 tty_error_msg(rc, errstr, MAXRBUF);
185 DEBUGF(INDI::Logger::DBG_ERROR, "updateInfo error: %s.", errstr);
186 }
187 if ( (rc = tty_read_section(PortFD, resp, '#', iEAFFOCUS_TIMEOUT, &nbytes_read)) != TTY_OK)
188 {
189 tty_error_msg(rc, errstr, MAXRBUF);
190 DEBUGF(INDI::Logger::DBG_ERROR, "updateInfo error: %s.", errstr);
191 return false;
192 }
193
194 tcflush(PortFD, TCIOFLUSH);
195
196 resp[nbytes_read] = '\0';
197
198 sscanf(resp, "%14s", joedeviceinfo);
199 rc = sscanf(resp, "%7d%1d%5d%1d", &ieafpos, &ieafmove, &ieaftemp, &ieafdir);
200
201 if (rc != 4)
202 {
203 LOGF_ERROR("Could not parse response %s", resp);
204 return false;
205 }
206
207 m_isMoving = ieafmove == 1;
208 auto temperature = ieaftemp / 100.0 - 273.15;
209 m_Reversed = (ieafdir == 0);
210 auto currentlyReversed = FocusReverseSP[INDI_ENABLED].getState() == ISS_ON;
211
212 // Only update if there is change
213 if (std::abs(temperature - TemperatureNP[0].getValue()) > TEMPERATURE_THRESHOLD)
214 {
215 TemperatureNP[0].setValue(temperature);
216 TemperatureNP.apply();
217 }
218
219 // Only update if there is change
220 if (m_Reversed != currentlyReversed)
221 {
226 }
227
228 // If absolute position is different, let's update
229 if (ieafpos != FocusAbsPosNP[0].getValue())
230 {
231 FocusAbsPosNP[0].setValue(ieafpos);
232 // Check if we are busy or not.
233 if ((m_isMoving == false && FocusAbsPosNP.getState() == IPS_BUSY) || (m_isMoving && FocusAbsPosNP.getState() != IPS_BUSY))
234 {
235 FocusAbsPosNP.setState(m_isMoving ? IPS_BUSY : IPS_OK);
236 FocusRelPosNP.setState(m_isMoving ? IPS_BUSY : IPS_OK);
238 }
240 }
241 // Update status if required
242 else if ((m_isMoving == false && FocusAbsPosNP.getState() == IPS_BUSY) || (m_isMoving
244 {
245 FocusAbsPosNP.setState(m_isMoving ? IPS_BUSY : IPS_OK);
246 FocusRelPosNP.setState(m_isMoving ? IPS_BUSY : IPS_OK);
249 }
250
251 return true;
252}
253
258{
259 INDI_UNUSED(ticks);
260 return false;
261}
262
266bool iEAFFocus::MoveMyFocuser(uint32_t position)
267{
268 int nbytes_written = 0, rc = -1;
269 char cmd[12] = {0};
270
271 snprintf(cmd, 12, ":FM%7u#", position);
272
273 // Set Position
274 tcflush(PortFD, TCIOFLUSH);
275 if ( (rc = tty_write(PortFD, cmd, strlen(cmd), &nbytes_written)) != TTY_OK)
276 {
277 char errstr[MAXRBUF];
278 tty_error_msg(rc, errstr, MAXRBUF);
279 LOGF_ERROR("setPosition error: %s.", errstr);
280 return false;
281 }
282 return true;
283}
284
289{
290 int nbytes_written = 0, rc = -1;
291
292 // If there is no change, return.
293 if (enabled == m_Reversed)
294 return true;
295
296 // Change Direction
297 tcflush(PortFD, TCIOFLUSH);
298 if ( (rc = tty_write(PortFD, ":FR#", 4, &nbytes_written)) != TTY_OK)
299 {
300 char errstr[MAXRBUF];
301 tty_error_msg(rc, errstr, MAXRBUF);
302 DEBUGF(INDI::Logger::DBG_ERROR, "change Direction error: %s.", errstr);
303 return false;
304 }
305 return true;
306}
307
311void iEAFFocus::setZero()
312{
313 int nbytes_written = 0, rc = -1;
314 // Set Zero
315 tcflush(PortFD, TCIOFLUSH);
316 if ( (rc = tty_write(PortFD, ":FZ#", 4, &nbytes_written)) != TTY_OK)
317 {
318 char errstr[MAXRBUF];
319 tty_error_msg(rc, errstr, MAXRBUF);
320 DEBUGF(INDI::Logger::DBG_ERROR, "set Zero error: %s.", errstr);
321 return;
322 }
323 return;
324}
325
329bool iEAFFocus::ISNewSwitch (const char *dev, const char *name, ISState *states, char *names[], int n)
330{
331 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
332 {
333 if (SetZeroSP.isNameMatch(name))
334 {
335 setZero();
336 SetZeroSP.setState(IPS_OK);
337 SetZeroSP.apply();
338 return true;
339 }
340 }
341
342 return INDI::Focuser::ISNewSwitch(dev, name, states, names, n);
343}
344
348void iEAFFocus::GetFocusParams ()
349{
350 updateInfo();
351}
352
357{
358 uint32_t targetPos = targetTicks;
359
360 bool rc = false;
361
362 rc = MoveMyFocuser(targetPos);
363
364 if (rc == false)
365 return IPS_ALERT;
366
368
369 return IPS_BUSY;
370}
371
376{
377 int relativeTicks = ((dir == FOCUS_INWARD) ? -ticks : ticks) * (m_Reversed ? -1 : 1);
378 uint32_t newPosition = FocusAbsPosNP[0].getValue() + relativeTicks;
379 newPosition = std::max(0u, std::min(static_cast<uint32_t>(FocusAbsPosNP[0].getMax()), newPosition));
380
381 auto rc = MoveMyFocuser(newPosition);
382
383 if (rc == false)
384 return IPS_ALERT;
385
386 FocusRelPosNP[0].setValue(ticks);
388
389 return IPS_BUSY;
390}
391
396{
397 if (!isConnected())
398 return;
399
400 updateInfo();
402}
403
408{
409 int nbytes_written;
410 tcflush(PortFD, TCIOFLUSH);
411 if (tty_write(PortFD, ":FQ#", 4, &nbytes_written) == TTY_OK)
412 {
417 return true;
418 }
419 else
420 return false;
421}
double temperature
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
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.
uint32_t getPollingPeriod() const
getPollingPeriod Return the polling period.
void defineProperty(INumberVectorProperty *property)
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 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
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isNameMatch(const char *otherName) const
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, ISRule rule, double timeout, IPState state)
virtual bool Handshake() override
Performs a device-specific handshake after a connection is established. This method should be overrid...
const char * getDefaultName() override
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
Definition ieaffocus.cpp:58
virtual bool ReverseFocuser(bool enabled) override
ReverseFocuser Reverse focuser motion direction.
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
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 SetFocuserMaxPosition(uint32_t ticks) override
SetFocuserMaxPosition Update focuser maximum position. It only updates the PresetNP property limits.
virtual IPState MoveAbsFocuser(uint32_t ticks) override
MoveFocuser the focuser to an absolute position.
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
Definition ieaffocus.cpp:88
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveFocuser the focuser to an relative position.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
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,...
#define TEMPERATURE_THRESHOLD
Definition dmfc.cpp:35
std::unique_ptr< iEAFFocus > ieafFocus(new iEAFFocus())
#define iEAFFOCUS_TIMEOUT
Definition ieaffocus.cpp:34
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_ATMOST1
Definition indiapi.h:172
int tty_read_section(int fd, char *buf, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:653
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
#define INDI_UNUSED(x)
Definition indidevapi.h:132
#define MAXRBUF
Definition indidriver.c:52
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition indilogger.h:56
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define DEBUGF(priority, msg,...)
Definition indilogger.h:57
#define getDeviceName
uint8_t cmd[4]
Definition pwc-ioctl.h:2