Instrument Neutral Distributed Interface INDI 2.2.5
aaf2.cpp
Go to the documentation of this file.
1/*
2 Arduino ASCOM Focuser 2 (AAF2) INDI Focuser
3
4 Copyright (C) 2019 Jasem Mutlaq ([email protected])
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20*/
21
22#include "aaf2.h"
23
24#include "indicom.h"
25
26#include <cmath>
27#include <cstring>
28#include <memory>
29
30#include <termios.h>
31#include <unistd.h>
32
33static std::unique_ptr<AAF2> aaf2(new AAF2());
34
42
44{
46
47 // Focuser temperature
48 TemperatureNP[0].fill("TEMPERATURE", "Celsius", "%6.2f", -50, 70., 0., 0.);
49 TemperatureNP.fill(getDeviceName(), "FOCUS_TEMPERATURE", "Temperature",
51
52 // Relative and absolute movement
53 FocusRelPosNP[0].setMin(0.);
54 FocusRelPosNP[0].setMax(50000.);
55 FocusRelPosNP[0].setValue(0);
56 FocusRelPosNP[0].setStep(1000);
57
58 FocusAbsPosNP[0].setMin(0.);
59 FocusAbsPosNP[0].setMax(100000.);
60 FocusAbsPosNP[0].setValue(0);
61 FocusAbsPosNP[0].setStep(1000);
62
64
65 return true;
66}
67
69{
71
72 if (isConnected())
73 {
74 defineProperty(TemperatureNP);
75
76 LOG_INFO("Focuser ready.");
77 }
78 else
79 {
80 deleteProperty(TemperatureNP);
81 }
82
83 return true;
84}
85
87{
88 if (Ack())
89 {
90 LOG_INFO("AAF2 is online.");
91
92 readVersion();
93
94 return true;
95 }
96
97 LOG_INFO("Error retrieving data from AAF2, please ensure AAF2 controller is powered and the port is correct.");
98 return false;
99}
100
102{
103 return "AAF2";
104}
105
106bool AAF2::Ack()
107{
108 int nbytes_written = 0, nbytes_read = 0, rc = -1;
109 char errstr[MAXRBUF];
110 char resp[5] = {0};
111
112 tcflush(PortFD, TCIOFLUSH);
113
114 int numChecks = 0;
115 bool success = false;
116 while (numChecks < 3 && !success)
117 {
118 numChecks++;
119 //wait 1 second between each test.
120 sleep(1);
121
122 bool transmissionSuccess = (rc = tty_write(PortFD, "#", 1, &nbytes_written)) == TTY_OK;
123 if(!transmissionSuccess)
124 {
125 tty_error_msg(rc, errstr, MAXRBUF);
126 LOGF_ERROR("Handshake Attempt %i, tty transmission error: %s.", numChecks, errstr);
127 }
128
129 bool responseSuccess = (rc = tty_read(PortFD, resp, 4, DRIVER_TIMEOUT, &nbytes_read)) == TTY_OK;
130 if(!responseSuccess)
131 {
132 tty_error_msg(rc, errstr, MAXRBUF);
133 LOGF_ERROR("Handshake Attempt %i, updatePosition response error: %s.", numChecks, errstr);
134 }
135
136 success = transmissionSuccess && responseSuccess;
137 }
138
139 if(!success)
140 {
141 LOG_INFO("Handshake failed after 3 attempts");
142 return false;
143 }
144
145 tcflush(PortFD, TCIOFLUSH);
146
147 return !strcmp(resp, "OK!#");
148}
149
150
151bool AAF2::readTemperature()
152{
153 char res[DRIVER_RES] = {0};
154
155 if (sendCommand("C#", res) == false)
156 return false;
157
158 int32_t temp = 0;
159 int rc = sscanf(res, "C%d:OK", &temp);
160 if (rc > 0)
161 // Hundredth of a degree
162 TemperatureNP[0].setValue(temp / 100.0);
163 else
164 {
165 LOGF_ERROR("Unknown error: focuser temperature value (%s)", res);
166 return false;
167 }
168
169 return true;
170}
171
172bool AAF2::readVersion()
173{
174 char res[DRIVER_RES] = {0};
175
176 if (sendCommand("V#", res) == false)
177 return false;
178
179 LOGF_INFO("Detected %s", res);
180
181 return true;
182}
183
184bool AAF2::readPosition()
185{
186 char res[DRIVER_RES] = {0};
187
188 if (sendCommand("P#", res) == false)
189 return false;
190
191 int32_t pos;
192 int rc = sscanf(res, "P%d:OK", &pos);
193
194 if (rc > 0)
195 FocusAbsPosNP[0].setValue(pos);
196 else
197 {
198 LOGF_ERROR("Unknown error: focuser position value (%s)", res);
199 return false;
200 }
201
202 return true;
203}
204
205bool AAF2::isMoving()
206{
207 char res[DRIVER_RES] = {0};
208
209 if (sendCommand("M#", res) == false)
210 return false;
211
212 if (strcmp(res, "M1:OK") == 0)
213 return true;
214 else if (strcmp(res, "M0:OK") == 0)
215 return false;
216
217 LOGF_ERROR("Unknown error: isMoving value (%s)", res);
218 return false;
219}
220
221
222bool AAF2::SyncFocuser(uint32_t ticks)
223{
224 char cmd[DRIVER_RES] = {0};
225 snprintf(cmd, DRIVER_RES, "I%d#", ticks);
226 return sendCommand(cmd);
227}
228
229IPState AAF2::MoveAbsFocuser(uint32_t targetTicks)
230{
231 char cmd[DRIVER_RES] = {0}, res[DRIVER_RES] = {0}, expected[DRIVER_RES] = {0};
232 snprintf(cmd, DRIVER_RES, "T%d#", targetTicks);
233 snprintf(expected, DRIVER_RES, "T%d:OK", targetTicks);
234 if (sendCommand(cmd, res) == false)
235 return IPS_ALERT;
236
237 targetPos = targetTicks;
238
239 if (!strcmp(res, expected))
240 return IPS_BUSY;
241 else
242 return IPS_ALERT;
243}
244
246{
247 int32_t newPosition = 0;
248
249 if (dir == FOCUS_INWARD)
250 newPosition = FocusAbsPosNP[0].getValue() - ticks;
251 else
252 newPosition = FocusAbsPosNP[0].getValue() + ticks;
253
254 // Clamp
255 newPosition = std::max(0, std::min(static_cast<int32_t>(FocusAbsPosNP[0].getMax()), newPosition));
256 if (MoveAbsFocuser(newPosition) != IPS_BUSY)
257 return IPS_ALERT;
258
259 FocusRelPosNP[0].setValue(ticks);
261
262 return IPS_BUSY;
263}
264
266{
267 if (!isConnected())
268 {
270 return;
271 }
272
273 bool rc = readPosition();
274 if (rc)
275 {
276 if (fabs(lastPos - FocusAbsPosNP[0].getValue()) > 5)
277 {
279 lastPos = FocusAbsPosNP[0].getValue();
280 }
281 }
282
283 rc = readTemperature();
284 if (rc)
285 {
286 if (fabs(lastTemperature - TemperatureNP[0].getValue()) >= 0.5)
287 {
288 TemperatureNP.apply();
289 lastTemperature = TemperatureNP[0].getValue();
290 }
291 }
292
294 {
295 if (!isMoving())
296 {
301 lastPos = FocusAbsPosNP[0].getValue();
302 LOG_INFO("Focuser reached requested position.");
303 }
304 }
305
307}
308
310{
311 return sendCommand("H#");
312}
313
314
315bool AAF2::sendCommand(const char * cmd, char * res)
316{
317 int nbytes_written = 0, nbytes_read = 0, rc = -1;
318
319 tcflush(PortFD, TCIOFLUSH);
320
321 LOGF_DEBUG("CMD <%s>", cmd);
322
323 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
324 {
325 char errstr[MAXRBUF] = {0};
326 tty_error_msg(rc, errstr, MAXRBUF);
327 LOGF_ERROR("Serial write error: %s.", errstr);
328 return false;
329 }
330
331 if (res == nullptr)
332 return true;
333
334 if ((rc = tty_nread_section(PortFD, res, DRIVER_RES, DRIVER_DEL, DRIVER_TIMEOUT, &nbytes_read)) != TTY_OK)
335 {
336 char errstr[MAXRBUF] = {0};
337 tty_error_msg(rc, errstr, MAXRBUF);
338 LOGF_ERROR("Serial read error: %s.", errstr);
339 return false;
340 }
341
342 // Remove the #
343 res[nbytes_read - 1] = 0;
344
345 LOGF_DEBUG("RES <%s>", res);
346
347 tcflush(PortFD, TCIOFLUSH);
348
349 return true;
350}
Definition aaf2.h:27
virtual bool AbortFocuser() override
AbortFocuser all focus motion.
Definition aaf2.cpp:309
virtual IPState MoveRelFocuser(FocusDirection dir, uint32_t ticks) override
MoveRelFocuser Move focuser for a relative amount of ticks in a specific direction.
Definition aaf2.cpp:245
virtual bool SyncFocuser(uint32_t ticks) override
SyncFocuser Set the supplied position as the current focuser position.
Definition aaf2.cpp:222
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition aaf2.cpp:265
AAF2()
Definition aaf2.cpp:35
virtual bool initProperties() override
Initializes the default properties for the focuser device. Sets up standard INDI properties,...
Definition aaf2.cpp:43
virtual bool updateProperties() override
Updates the state and definition of properties based on the current connection status....
Definition aaf2.cpp:68
virtual bool Handshake() override
Handshake Try to communicate with Focuser and see if there is a valid response.
Definition aaf2.cpp:86
virtual IPState MoveAbsFocuser(uint32_t targetTicks) override
MoveAbsFocuser Move to an absolute target position.
Definition aaf2.cpp:229
const char * getDefaultName() override
Definition aaf2.cpp:101
bool isConnected() const
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.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
INDI::PropertyNumber FocusRelPosNP
void SetCapability(uint32_t cap)
FI::SetCapability sets the focuser capabilities. All capabilities must be initialized.
INDI::PropertyNumber FocusAbsPosNP
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,...
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
void fill(const char *device, const char *name, const char *label, const char *group, IPerm permission, double timeout, IPState state)
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
@ 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
int tty_write(int fd, const char *buf, int nbytes, int *nbytes_written)
Writes a buffer to fd.
Definition indicom.c:418
int tty_read(int fd, char *buf, int nbytes, int timeout, int *nbytes_read)
read buffer from terminal
Definition indicom.c:548
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition indicom.c:473
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition indicom.c:1243
int tty_nread_section(int fd, char *buf, int nsize, char stop_char, int timeout, int *nbytes_read)
read buffer from terminal with a delimiter
Definition indicom.c:759
Implementations for common driver routines.
@ TTY_OK
Definition indicom.h:54
#define MAXRBUF
Definition indidriver.c:52
#define LOGF_INFO(fmt,...)
Definition indilogger.h:82
#define LOGF_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName
uint8_t cmd[4]
Definition pwc-ioctl.h:2