Instrument Neutral Distributed Interface INDI 2.2.5
deepskydad_fr1.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2020 Jasem Mutlaq. All rights reserved.
3
4 Deep Sky Dad Field Rotator 1
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2 of the License, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 The full GNU General Public License is included in this distribution in the
22 file called LICENSE.
23*******************************************************************************/
24
25#include "deepskydad_fr1.h"
26#include "indicom.h"
28
29#include <cerrno>
30#include <cstring>
31#include <memory>
32#include <termios.h>
33#include <unistd.h>
34#include <inttypes.h>
35#include <sys/ioctl.h>
36#include <cmath>
37
38#define DSD_CMD 40
39#define DSD_RES 40
40#define DSD_TIMEOUT 3
41
42// We declare an auto pointer to DeepSkyDadFR1.
43static std::unique_ptr<DeepSkyDadFR1> dsdFR1(new DeepSkyDadFR1());
44
49
51{
53
57
59
60 // Speed mode
61 SpeedModeSP[Slow].fill("SLOW", "Slow", ISS_OFF);
62 SpeedModeSP[Fast].fill( "FAST", "Fast", ISS_OFF);
63 SpeedModeSP.fill(getDeviceName(), "Speed mode", "Speed mode", MAIN_CONTROL_TAB, IP_RW,
65
66 // Step mode
67 StepSizeSP[One].fill("1", "1", ISS_OFF);
68 StepSizeSP[Two].fill("2", "1/2", ISS_OFF);
69 StepSizeSP[Four].fill( "4", "1/4", ISS_OFF);
70 StepSizeSP[Eight].fill( "8", "1/8", ISS_OFF);
71 StepSizeSP.fill(getDeviceName(), "Step mode", "Step mode", MAIN_CONTROL_TAB, IP_RW,
73
74 // Firmware version
75 FirmwareTP[0].fill("Version", "Version", nullptr);
76 FirmwareTP.fill(getDeviceName(), "Firmware", "Firmware", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
77
78 serialConnection->setDefaultPort("/dev/ttyACM0");
80 {
81 return Handshake();
82 });
84 return true;
85}
86
88{
90
91 if (isConnected())
92 {
93 defineProperty(SpeedModeSP);
94 defineProperty(StepSizeSP);
95 defineProperty(FirmwareTP);
96 }
97 else
98 {
99 deleteProperty(SpeedModeSP);
100 deleteProperty(StepSizeSP);
101 deleteProperty(FirmwareTP);
102 }
103
104 return true;
105}
106
108{
109 return "Deep Sky Dad FR1";
110}
111
112bool DeepSkyDadFR1::Handshake()
113{
115 return getInitialStatusData();
116}
117
118bool DeepSkyDadFR1::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
119{
120 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
121 {
122 if (SpeedModeSP.isNameMatch(name))
123 {
124 int current_mode = SpeedModeSP.findOnSwitchIndex();
125
126 SpeedModeSP.update(states, names, n);
127
128 int target_mode = SpeedModeSP.findOnSwitchIndex();
129
130 if (current_mode == target_mode)
131 {
132 SpeedModeSP.setState(IPS_OK);
133 SpeedModeSP.apply();
134 return true;
135 }
136
137 char cmd[DSD_RES] = {0};
138 char response[DSD_RES] = {0};
139
140 snprintf(cmd, DSD_RES, "[SSPD%d]", target_mode);
141 bool rc = sendCommand(cmd, response);
142 if (!rc)
143 {
144 SpeedModeSP.reset();
145 SpeedModeSP[current_mode].setState(ISS_ON);
146 SpeedModeSP.setState(IPS_ALERT);
147 SpeedModeSP.apply();
148 return false;
149 }
150
151 SpeedModeSP.setState(IPS_OK);
152 SpeedModeSP.apply();
153 return true;
154 }
155 else if (StepSizeSP.isNameMatch(name))
156 {
157 int current_mode = StepSizeSP.findOnSwitchIndex();
158
159 StepSizeSP.update(states, names, n);
160
161 int target_mode = StepSizeSP.findOnSwitchIndex();
162
163 if (current_mode == target_mode)
164 {
165 StepSizeSP.setState(IPS_OK);
166 StepSizeSP.apply();
167 return true;
168 }
169
170 char cmd[DSD_RES] = {0};
171 char response[DSD_RES] = {0};
172
173 snprintf(cmd, DSD_RES, "[SSTP%d]", target_mode);
174 bool rc = sendCommand(cmd, response);
175 if (!rc)
176 {
177 StepSizeSP.reset();
178 StepSizeSP[current_mode].setState(ISS_ON);
179 StepSizeSP.setState(IPS_ALERT);
180 StepSizeSP.apply();
181 return false;
182 }
183
184 StepSizeSP.setState(IPS_OK);
185 StepSizeSP.apply();
186 return true;
187 }
188 }
189
190 return Rotator::ISNewSwitch(dev, name, states, names, n);
191}
192
194{
195 char response[DSD_RES];
196 char cmd[DSD_CMD];
197 int angleInt = (int)(angle * 100);
198 snprintf(cmd, DSD_CMD, "[STRG%d]", angleInt);
199 if (!sendCommand(cmd, response) || !sendCommand("[SMOV]", response))
200 return IPS_ALERT;
201
202 if (strcmp(response, "(OK)") == 0)
203 {
204 return IPS_BUSY;
205 }
206 else
207 return IPS_ALERT;
208}
209
211{
212 char response[DSD_RES];
213 if (!sendCommand("[STOP]", response))
214 return false;
215
216 if (strcmp(response, "(OK)") == 0)
217 {
218 return true;
219 }
220 else
221 return false;
222}
223
225{
226 char response[DSD_RES];
227 char cmd[DSD_CMD];
228 snprintf(cmd, DSD_CMD, "[SREV%d]", enabled ? 1 : 0);
229 if (!sendCommand(cmd, response))
230 return false;
231
232 if (strcmp(response, "(OK)") == 0)
233 {
234 return true;
235 }
236 else
237 return false;
238}
239
241{
242 char response[DSD_RES];
243 char cmd[DSD_CMD];
244 int angleInt = (int)(angle * 100);
245 snprintf(cmd, DSD_CMD, "[SPOS%d]", angleInt);
246 if (!sendCommand(cmd, response))
247 return false;
248
249 if (strcmp(response, "(OK)") == 0)
250 {
251 return true;
252 }
253 else
254 return false;
255}
256
258{
259 if (!isConnected())
260 return;
261 getStatusData();
263}
264
265bool DeepSkyDadFR1::getStatusData()
266{
267 char response[DSD_RES];
268
269 int motorStatus;
270 int motorPosition;
271
272 if (!sendCommand("[GMOV]", response))
273 return false;
274 else
275 sscanf(response, "(%d)", &motorStatus);
276
277 if (!sendCommand("[GPOS]", response))
278 return false;
279 else
280 sscanf(response, "(%d)", &motorPosition);
281
282
283
284 const IPState motionState = motorStatus == 1 ? IPS_BUSY : IPS_OK;
285
286 double motorPositionDouble = (double)motorPosition / (double)100;
287 if (std::abs(motorPositionDouble - GotoRotatorNP[0].getValue()) > 0.01 || GotoRotatorNP.getState() != motionState)
288 {
289 GotoRotatorNP[0].setValue(motorPositionDouble);
290 GotoRotatorNP.setState(motionState);
292 }
293
294 return true;
295}
296
297bool DeepSkyDadFR1::getInitialStatusData()
298{
299 char response[DSD_RES] = {0};
300 if (!sendCommand("[GFRM]", response))
301 return false;
302
303 char versionString[6] = { 0 };
304 snprintf(versionString, 6, "%s", response + 31);
305 FirmwareTP[0].setText(response);
306 FirmwareTP.apply();
307
308 int motorReversed;
309
310 if (!sendCommand("[GREV]", response))
311 return false;
312 else
313 sscanf(response, "(%d)", &motorReversed);
314
315 const bool wasReversed = ReverseRotatorSP[INDI_ENABLED].getState() == ISS_ON;
316 if (motorReversed != wasReversed)
317 {
321 }
322
323 if (!sendCommand("[GSPD]", response))
324 return false;
325
326 if(strcmp(response, "(2)") == 0)
327 SpeedModeSP[Slow].setState(ISS_ON);
328 else if(strcmp(response, "(3)") == 0)
329 SpeedModeSP[Fast].setState(ISS_ON);
330
331 if (!sendCommand("[GSTP]", response))
332 return false;
333
334 if(strcmp(response, "(1)") == 0)
335 StepSizeSP[One].setState(ISS_ON);
336 else if(strcmp(response, "(2)") == 0)
337 StepSizeSP[Two].setState(ISS_ON);
338 else if(strcmp(response, "(4)") == 0)
339 StepSizeSP[Four].setState(ISS_ON);
340 else if(strcmp(response, "(8)") == 0)
341 StepSizeSP[Eight].setState(ISS_ON);
342
343 return true;
344}
345
349bool DeepSkyDadFR1::sendCommand(const char *cmd, char *res)
350{
351 int nbytes_written = 0, nbytes_read = 0, rc = -1;
352
353 tcflush(PortFD, TCIOFLUSH);
354
355 LOGF_DEBUG("CMD <%s>", cmd);
356
357 if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
358 {
359 char errstr[MAXRBUF] = {0};
360 tty_error_msg(rc, errstr, MAXRBUF);
361 LOGF_ERROR("Serial write error: %s.", errstr);
362 return false;
363 }
364
365 if (res == nullptr)
366 return true;
367
368 if ((rc = tty_nread_section(PortFD, res, DSD_RES, ')', DSD_TIMEOUT, &nbytes_read)) != TTY_OK)
369 {
370 char errstr[MAXRBUF] = {0};
371 tty_error_msg(rc, errstr, MAXRBUF);
372 LOGF_ERROR("Serial read error: %s.", errstr);
373 return false;
374 }
375
376 LOGF_DEBUG("RES <%s>", res);
377
378 tcflush(PortFD, TCIOFLUSH);
379
380 return true;
381}
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the initial connection to the devic...
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
void setDefaultPort(const char *port)
setDefaultPort Set default port. Call this function in initProperties() of your driver if you want to...
virtual bool AbortRotator() override
AbortRotator Abort all motion.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual bool updateProperties() override
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) override
Process the client newSwitch command.
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual IPState MoveRotator(double angle) override
MoveRotator Go to specific angle.
virtual bool ReverseRotator(bool enabled) override
ReverseRotator Reverse the direction of the rotator. CW is usually the normal direction,...
const char * getDefaultName() override
virtual bool SyncRotator(double angle) override
SyncRotator Set current angle as the supplied angle without moving the rotator.
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.
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.
void setState(IPState state)
void apply(const char *format,...) const ATTRIBUTE_FORMAT_PRINTF(2
bool isNameMatch(const char *otherName) const
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)
void SetCapability(uint32_t cap)
SetRotatorCapability sets the Rotator capabilities. All capabilities must be initialized.
INDI::PropertySwitch ReverseRotatorSP
INDI::PropertyNumber GotoRotatorNP
Connection::Serial * serialConnection
Definition indirotator.h:95
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
#define DSD_CMD
#define DSD_RES
#define DSD_TIMEOUT
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
@ 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
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_DEBUG(fmt,...)
Definition indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition indilogger.h:80
#define getDeviceName
uint8_t cmd[4]
Definition pwc-ioctl.h:2