Instrument Neutral Distributed Interface INDI  1.9.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 
37 #define DSD_CMD 40
38 #define DSD_RES 40
39 #define DSD_TIMEOUT 3
40 
41 // We declare an auto pointer to DeepSkyDadFR1.
42 static std::unique_ptr<DeepSkyDadFR1> dsdFR1(new DeepSkyDadFR1());
43 
45 {
46  setVersion(1, 0);
47 }
48 
50 {
52 
56 
58 
59  // Speed mode
60  IUFillSwitch(&SpeedModeS[Slow], "SLOW", "Slow", ISS_OFF);
61  IUFillSwitch(&SpeedModeS[Fast], "FAST", "Fast", ISS_OFF);
62  IUFillSwitchVector(&SpeedModeSP, SpeedModeS, 2, getDeviceName(), "Speed mode", "Speed mode", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
63 
64  // Step mode
65  IUFillSwitch(&StepSizeS[One], "1", "1", ISS_OFF);
66  IUFillSwitch(&StepSizeS[Two], "2", "1/2", ISS_OFF);
67  IUFillSwitch(&StepSizeS[Four], "4", "1/4", ISS_OFF);
68  IUFillSwitch(&StepSizeS[Eight], "8", "1/8", ISS_OFF);
69  IUFillSwitchVector(&StepSizeSP, StepSizeS, 4, getDeviceName(), "Step mode", "Step mode", MAIN_CONTROL_TAB, IP_RW, ISR_1OFMANY, 0, IPS_IDLE);
70 
71  // Firmware version
72  IUFillText(&FirmwareT[0], "Version", "Version", nullptr);
73  IUFillTextVector(&FirmwareTP, FirmwareT, 1, getDeviceName(), "Firmware", "Firmware", MAIN_CONTROL_TAB, IP_RO, 60, IPS_IDLE);
74 
75  serialConnection->setDefaultPort("/dev/ttyACM0");
76  serialConnection->registerHandshake([&]() { return Handshake(); });
78  return true;
79 }
80 
82 {
84 
85  if (isConnected())
86  {
87  defineProperty(&SpeedModeSP);
88  defineProperty(&StepSizeSP);
89  defineProperty(&FirmwareTP);
90  }
91  else
92  {
93  deleteProperty(SpeedModeSP.name);
94  deleteProperty(StepSizeSP.name);
95  deleteProperty(FirmwareTP.name);
96  }
97 
98  return true;
99 }
100 
102 {
103  return "Deep Sky Dad FR1";
104 }
105 
106 bool DeepSkyDadFR1::Handshake()
107 {
109  return getInitialStatusData();
110 }
111 
112 bool DeepSkyDadFR1::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
113 {
114  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
115  {
116  if (strcmp(SpeedModeSP.name, name) == 0)
117  {
118  int current_mode = IUFindOnSwitchIndex(&SpeedModeSP);
119 
120  IUUpdateSwitch(&SpeedModeSP, states, names, n);
121 
122  int target_mode = IUFindOnSwitchIndex(&SpeedModeSP);
123 
124  if (current_mode == target_mode)
125  {
126  SpeedModeSP.s = IPS_OK;
127  IDSetSwitch(&SpeedModeSP, nullptr);
128  return true;
129  }
130 
131  char cmd[DSD_RES] = {0};
132  char response[DSD_RES] = {0};
133 
134  snprintf(cmd, DSD_RES, "[SSPD%d]", target_mode);
135  bool rc = sendCommand(cmd, response);
136  if (!rc)
137  {
138  IUResetSwitch(&SpeedModeSP);
139  SpeedModeS[current_mode].s = ISS_ON;
140  SpeedModeSP.s = IPS_ALERT;
141  IDSetSwitch(&SpeedModeSP, nullptr);
142  return false;
143  }
144 
145  SpeedModeSP.s = IPS_OK;
146  IDSetSwitch(&SpeedModeSP, nullptr);
147  return true;
148  } else if (strcmp(StepSizeSP.name, name) == 0)
149  {
150  int current_mode = IUFindOnSwitchIndex(&StepSizeSP);
151 
152  IUUpdateSwitch(&StepSizeSP, states, names, n);
153 
154  int target_mode = IUFindOnSwitchIndex(&StepSizeSP);
155 
156  if (current_mode == target_mode)
157  {
158  StepSizeSP.s = IPS_OK;
159  IDSetSwitch(&StepSizeSP, nullptr);
160  return true;
161  }
162 
163  char cmd[DSD_RES] = {0};
164  char response[DSD_RES] = {0};
165 
166  snprintf(cmd, DSD_RES, "[SSTP%d]", target_mode);
167  bool rc = sendCommand(cmd, response);
168  if (!rc)
169  {
170  IUResetSwitch(&StepSizeSP);
171  StepSizeS[current_mode].s = ISS_ON;
172  StepSizeSP.s = IPS_ALERT;
173  IDSetSwitch(&StepSizeSP, nullptr);
174  return false;
175  }
176 
177  StepSizeSP.s = IPS_OK;
178  IDSetSwitch(&StepSizeSP, nullptr);
179  return true;
180  }
181  }
182 
183  return Rotator::ISNewSwitch(dev, name, states, names, n);
184 }
185 
187 {
188  char response[DSD_RES];
189  char cmd[DSD_CMD];
190  int angleInt = (int)(angle*100);
191  snprintf(cmd, DSD_CMD, "[STRG%d]", angleInt);
192  if (!sendCommand(cmd, response) || !sendCommand("[SMOV]", response))
193  return IPS_ALERT;
194 
195  if (strcmp(response, "(OK)") == 0)
196  {
197  return IPS_BUSY;
198  }
199  else
200  return IPS_ALERT;
201 }
202 
204 {
205  char response[DSD_RES];
206  if (!sendCommand("[STOP]", response))
207  return false;
208 
209  if (strcmp(response, "(OK)") == 0)
210  {
211  return true;
212  }
213  else
214  return false;
215 }
216 
218 {
219  char response[DSD_RES];
220  char cmd[DSD_CMD];
221  snprintf(cmd, DSD_CMD, "[SREV%d]", enabled ? 1 : 0);
222  if (!sendCommand(cmd, response))
223  return false;
224 
225  if (strcmp(response, "(OK)") == 0)
226  {
227  return true;
228  }
229  else
230  return false;
231 }
232 
233 bool DeepSkyDadFR1::SyncRotator(double angle)
234 {
235  char response[DSD_RES];
236  char cmd[DSD_CMD];
237  int angleInt = (int)(angle*100);
238  snprintf(cmd, DSD_CMD, "[SPOS%d]", angleInt);
239  if (!sendCommand(cmd, response))
240  return false;
241 
242  if (strcmp(response, "(OK)") == 0)
243  {
244  return true;
245  }
246  else
247  return false;
248 }
249 
251 {
252  if (!isConnected())
253  return;
254  getStatusData();
256 }
257 
258 bool DeepSkyDadFR1::getStatusData()
259 {
260  char response[DSD_RES];
261 
262  int motorStatus;
263  int motorPosition;
264 
265  if (!sendCommand("[GMOV]", response))
266  return false;
267  else
268  sscanf(response, "(%d)", &motorStatus);
269 
270  if (!sendCommand("[GPOS]", response))
271  return false;
272  else
273  sscanf(response, "(%d)", &motorPosition);
274 
275 
276 
277  const IPState motionState = motorStatus == 1 ? IPS_BUSY : IPS_OK;
278 
279  double motorPositionDouble = (double)motorPosition/(double)100;
280  if (std::abs(motorPositionDouble - GotoRotatorN[0].value) > 0.01 || GotoRotatorNP.s != motionState)
281  {
282  GotoRotatorN[0].value = motorPositionDouble;
283  GotoRotatorNP.s = motionState;
284  IDSetNumber(&GotoRotatorNP, nullptr);
285  }
286 
287  return true;
288 }
289 
290 bool DeepSkyDadFR1::getInitialStatusData()
291 {
292  char response[DSD_RES] = {0};
293  if (!sendCommand("[GFRM]", response))
294  return false;
295 
296  char versionString[6] = { 0 };
297  snprintf(versionString, 6, "%s", response + 31);
298  IUSaveText(&FirmwareT[0], response);
299  IDSetText(&FirmwareTP, nullptr);
300 
301  int motorReversed;
302 
303  if (!sendCommand("[GREV]", response))
304  return false;
305  else
306  sscanf(response, "(%d)", &motorReversed);
307 
308  const bool wasReversed = ReverseRotatorS[INDI_ENABLED].s == ISS_ON;
309  if (motorReversed != wasReversed)
310  {
311  ReverseRotatorS[INDI_ENABLED].s = motorReversed ? ISS_ON : ISS_OFF;
312  ReverseRotatorS[INDI_DISABLED].s = motorReversed ? ISS_OFF : ISS_ON;
313  IDSetSwitch(&ReverseRotatorSP, nullptr);
314  }
315 
316  if (!sendCommand("[GSPD]", response))
317  return false;
318 
319  if(strcmp(response, "(2)") == 0)
320  SpeedModeS[Slow].s = ISS_ON;
321  else if(strcmp(response, "(3)") == 0)
322  SpeedModeS[Fast].s = ISS_ON;
323 
324  if (!sendCommand("[GSTP]", response))
325  return false;
326 
327  if(strcmp(response, "(1)") == 0)
328  StepSizeS[One].s = ISS_ON;
329  else if(strcmp(response, "(2)") == 0)
330  StepSizeS[Two].s = ISS_ON;
331  else if(strcmp(response, "(4)") == 0)
332  StepSizeS[Four].s = ISS_ON;
333  else if(strcmp(response, "(8)") == 0)
334  StepSizeS[Eight].s = ISS_ON;
335 
336  return true;
337 }
338 
342 bool DeepSkyDadFR1::sendCommand(const char *cmd, char *res)
343 {
344  int nbytes_written = 0, nbytes_read = 0, rc = -1;
345 
346  tcflush(PortFD, TCIOFLUSH);
347 
348  LOGF_DEBUG("CMD <%s>", cmd);
349 
350  if ((rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
351  {
352  char errstr[MAXRBUF] = {0};
353  tty_error_msg(rc, errstr, MAXRBUF);
354  LOGF_ERROR("Serial write error: %s.", errstr);
355  return false;
356  }
357 
358  if (res == nullptr)
359  return true;
360 
361  if ((rc = tty_nread_section(PortFD, res, DSD_RES, ')', DSD_TIMEOUT, &nbytes_read)) != TTY_OK)
362  {
363  char errstr[MAXRBUF] = {0};
364  tty_error_msg(rc, errstr, MAXRBUF);
365  LOGF_ERROR("Serial read error: %s.", errstr);
366  return false;
367  }
368 
369  LOGF_DEBUG("RES <%s>", res);
370 
371  tcflush(PortFD, TCIOFLUSH);
372 
373  return true;
374 }
DeepSkyDadFR1::Fast
@ Fast
Definition: deepskydad_fr1.h:57
IP_RO
@ IP_RO
Definition: indiapi.h:183
cmd
__u8 cmd[4]
Definition: pwc-ioctl.h:4
INDI::DefaultDevice::addAuxControls
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
Definition: defaultdevice.cpp:665
INDI::Rotator::serialConnection
Connection::Serial * serialConnection
Definition: indirotator.h:95
DeepSkyDadFR1::TimerHit
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: deepskydad_fr1.cpp:250
IPState
IPState
Property state.
Definition: indiapi.h:158
tty_nread_section
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:657
LOGF_ERROR
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
DSD_CMD
#define DSD_CMD
Definition: deepskydad_fr1.cpp:37
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
IDSetText
void IDSetText(const ITextVectorProperty *t, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing text vector property.
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
DeepSkyDadFR1::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: deepskydad_fr1.cpp:49
INDI::Rotator::PortFD
int PortFD
Definition: indirotator.h:98
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
MAIN_CONTROL_TAB
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
Definition: defaultdevice.cpp:34
Connection::Serial::B_115200
@ B_115200
Definition: connectionserial.h:82
INDI::RotatorInterface::ROTATOR_CAN_ABORT
@ ROTATOR_CAN_ABORT
Definition: indirotatorinterface.h:55
IUFillTextVector
void IUFillTextVector(ITextVectorProperty *tvp, IText *tp, int ntp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a text vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:477
DeepSkyDadFR1::MoveRotator
virtual IPState MoveRotator(double angle) override
MoveRotator Go to specific angle.
Definition: deepskydad_fr1.cpp:186
DSD_TIMEOUT
#define DSD_TIMEOUT
Definition: deepskydad_fr1.cpp:39
INDI::DefaultDevice::setVersion
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
Definition: defaultdevice.cpp:1219
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
INDI::RotatorInterface::GotoRotatorN
INumber GotoRotatorN[1]
Definition: indirotatorinterface.h:197
IUFillText
void IUFillText(IText *tp, const char *name, const char *label, const char *initialText)
Assign attributes for a text property. The text's auxiliary elements will be set to NULL.
Definition: indidriver.c:369
DeepSkyDadFR1::AbortRotator
virtual bool AbortRotator() override
AbortRotator Abort all motion.
Definition: deepskydad_fr1.cpp:203
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
DeepSkyDadFR1
Definition: deepskydad_fr1.h:30
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1442
DeepSkyDadFR1::ReverseRotator
virtual bool ReverseRotator(bool enabled) override
ReverseRotator Reverse the direction of the rotator. CW is usually the normal direction,...
Definition: deepskydad_fr1.cpp:217
tty_error_msg
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1156
Connection::Serial::setDefaultPort
void setDefaultPort(const char *port)
setDefaultPort Set default port. Call this function in initProperties() of your driver if you want to...
Definition: connectionserial.cpp:372
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
INDI::Rotator::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indirotator.cpp:53
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
Connection::Serial::setDefaultBaudRate
void setDefaultBaudRate(BaudRate newRate)
setDefaultBaudRate Set default baud rate. The default baud rate is 9600 unless otherwise changed by t...
Definition: connectionserial.cpp:381
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
DeepSkyDadFR1::Slow
@ Slow
Definition: deepskydad_fr1.h:57
IUFillSwitchVector
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:412
INDI::BaseDevice::INDI_ENABLED
@ INDI_ENABLED
Definition: basedevice.h:64
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
DeepSkyDadFR1::Four
@ Four
Definition: deepskydad_fr1.h:58
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
DeepSkyDadFR1::Two
@ Two
Definition: deepskydad_fr1.h:58
connectionserial.h
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::RotatorInterface::ROTATOR_CAN_SYNC
@ ROTATOR_CAN_SYNC
Definition: indirotatorinterface.h:57
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
ISNewSwitch
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
Definition: defaultdevice.cpp:60
INDI::RotatorInterface::GotoRotatorNP
INumberVectorProperty GotoRotatorNP
Definition: indirotatorinterface.h:198
DeepSkyDadFR1::One
@ One
Definition: deepskydad_fr1.h:58
DeepSkyDadFR1::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: deepskydad_fr1.cpp:112
INDI::RotatorInterface::ROTATOR_CAN_REVERSE
@ ROTATOR_CAN_REVERSE
Definition: indirotatorinterface.h:58
INDI::Rotator::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indirotator.cpp:110
DeepSkyDadFR1::DeepSkyDadFR1
DeepSkyDadFR1()
Definition: deepskydad_fr1.cpp:44
INDI::RotatorInterface::SetCapability
void SetCapability(uint32_t cap)
SetRotatorCapability sets the Rotator capabilities. All capabilities must be initialized.
Definition: indirotatorinterface.h:74
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1449
name
const char * name
Definition: indiserver.c:116
DSD_RES
#define DSD_RES
Definition: deepskydad_fr1.cpp:38
INDI::RotatorInterface::ReverseRotatorSP
ISwitchVectorProperty ReverseRotatorSP
Definition: indirotatorinterface.h:210
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
Connection::Interface::registerHandshake
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
Definition: connectioninterface.cpp:108
deepskydad_fr1.h
IP_RW
@ IP_RW
Definition: indiapi.h:185
DeepSkyDadFR1::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: deepskydad_fr1.cpp:81
ISState
ISState
Switch state.
Definition: indiapi.h:148
Connection::Serial::getPortFD
int getPortFD() const
Definition: connectionserial.h:136
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1424
tty_write_string
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:465
TTY_OK
@ TTY_OK
Definition: indicom.h:94
INDI::RotatorInterface::ReverseRotatorS
ISwitch ReverseRotatorS[2]
Definition: indirotatorinterface.h:209
DeepSkyDadFR1::getDefaultName
const char * getDefaultName() override
Definition: deepskydad_fr1.cpp:101
INDI::DefaultDevice::deleteProperty
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
Definition: defaultdevice.cpp:965
IDSetNumber
void void void IDSetNumber(const INumberVectorProperty *n, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing number vector property.
IDSetSwitch
void void void void void IDSetSwitch(const ISwitchVectorProperty *s, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing switch vector property.
DeepSkyDadFR1::SyncRotator
virtual bool SyncRotator(double angle) override
SyncRotator Set current angle as the supplied angle without moving the rotator.
Definition: deepskydad_fr1.cpp:233
IUFillSwitch
void IUFillSwitch(ISwitch *sp, const char *name, const char *label, ISState s)
Assign attributes for a switch property. The switch's auxiliary elements will be set to NULL.
Definition: indidriver.c:320
INDI::BaseDevice::INDI_DISABLED
@ INDI_DISABLED
Definition: basedevice.h:65
DeepSkyDadFR1::Eight
@ Eight
Definition: deepskydad_fr1.h:58
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151