Instrument Neutral Distributed Interface INDI  2.0.2
arduino_st4.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2018 Jasem Mutlaq. All rights reserved.
3 
4  Arduino ST4 Driver.
5 
6  For this project: https://github.com/kevinferrare/arduino-st4
7 
8  This program is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by the Free
10  Software Foundation; either version 2 of the License, or (at your option)
11  any later version.
12 
13  This program is distributed in the hope that it will be useful, but WITHOUT
14  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16  more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 
23  The full GNU General Public License is included in this distribution in the
24  file called LICENSE.
25 *******************************************************************************/
26 
27 #include "arduino_st4.h"
28 
29 #include "indicom.h"
31 
32 #include <cerrno>
33 #include <cstring>
34 #include <memory>
35 #include <termios.h>
36 #include <sys/ioctl.h>
37 
38 // We declare an auto pointer to ArduinoST4.
39 std::unique_ptr<ArduinoST4> arduinoST4(new ArduinoST4());
40 
41 #define FLAT_TIMEOUT 3
42 
44 {
45  setVersion(1, 0);
46 }
47 
49 {
51 
53 
55 
57 
58  serialConnection = new Connection::Serial(this);
59  serialConnection->registerHandshake([&]()
60  {
61  return Handshake();
62  });
64  // Arduino default port
65  serialConnection->setDefaultPort("/dev/ttyACM0");
66  registerConnection(serialConnection);
67 
68  return true;
69 }
70 
72 {
74 
75  if (isConnected())
76  {
79  }
80  else
81  {
84  }
85 
86  return true;
87 }
88 
90 {
91  return static_cast<const char *>("Arduino ST4");
92 }
93 
94 bool ArduinoST4::Handshake()
95 {
96  if (isSimulation())
97  {
98  LOGF_INFO("Connected successfully to simulated %s.", getDeviceName());
99  return true;
100  }
101 
102  PortFD = serialConnection->getPortFD();
103 
104  return true;
105 }
106 
108 {
109  sendCommand("DISCONNECT#");
110 
112 }
113 
114 bool ArduinoST4::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
115 {
116  if (!strcmp(name, GuideNSNP.name) || !strcmp(name, GuideWENP.name))
117  {
118  processGuiderProperties(name, values, names, n);
119  return true;
120  }
121 
122  return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
123 }
124 
126 {
127  LOGF_DEBUG("Guiding: N %.0f ms", ms);
128 
129  if (GuideNSTID)
130  {
131  IERmTimer(GuideNSTID);
132  GuideNSTID = 0;
133  }
134 
135  if (sendCommand("DEC+#") == false)
136  return IPS_ALERT;
137 
138  guideDirection = ARD_N;
139  GuideNSTID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperN, this);
140  return IPS_BUSY;
141 }
142 
144 {
145  LOGF_DEBUG("Guiding: S %.0f ms", ms);
146 
147  if (GuideNSTID)
148  {
149  IERmTimer(GuideNSTID);
150  GuideNSTID = 0;
151  }
152 
153  if (sendCommand("DEC-#") == false)
154  return IPS_ALERT;
155 
156  guideDirection = ARD_S;
157  GuideNSTID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperS, this);
158  return IPS_BUSY;
159 }
160 
162 {
163  LOGF_DEBUG("Guiding: E %.0f ms", ms);
164 
165  if (GuideWETID)
166  {
167  IERmTimer(GuideWETID);
168  GuideWETID = 0;
169  }
170 
171  if (sendCommand("RA+#") == false)
172  return IPS_ALERT;
173 
174  guideDirection = ARD_E;
175  GuideWETID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperE, this);
176  return IPS_BUSY;
177 }
178 
180 {
181  LOGF_DEBUG("Guiding: W %.0f ms", ms);
182 
183  if (GuideWETID)
184  {
185  IERmTimer(GuideWETID);
186  GuideWETID = 0;
187  }
188 
189  if (sendCommand("RA-#") == false)
190  return IPS_ALERT;
191 
192  guideDirection = ARD_W;
193  GuideWETID = IEAddTimer(static_cast<int>(ms), guideTimeoutHelperE, this);
194  return IPS_BUSY;
195 }
196 
197 //GUIDE The timer helper functions.
199 {
200  static_cast<ArduinoST4 *>(p)->guideTimeout(ARD_N);
201 }
203 {
204  static_cast<ArduinoST4 *>(p)->guideTimeout(ARD_S);
205 }
207 {
208  static_cast<ArduinoST4 *>(p)->guideTimeout(ARD_W);
209 }
211 {
212  static_cast<ArduinoST4 *>(p)->guideTimeout(ARD_E);
213 }
214 
216 {
217  if (direction == ARD_N || direction == ARD_S)
218  {
219  if (sendCommand("DEC0#"))
220  {
221  GuideNSNP.s = IPS_IDLE;
222  LOG_DEBUG("Guiding: DEC axis stopped.");
223  }
224  else
225  {
227  LOG_ERROR("Failed to stop DEC axis.");
228  }
229 
230  GuideNSTID = 0;
231  GuideNSNP.np[0].value = 0;
232  GuideNSNP.np[1].value = 0;
233  IDSetNumber(&GuideNSNP, nullptr);
234  }
235 
236  if (direction == ARD_W || direction == ARD_E)
237  {
238  if (sendCommand("RA0#"))
239  {
240  GuideWENP.s = IPS_IDLE;
241  LOG_DEBUG("Guiding: RA axis stopped.");
242  }
243  else
244  {
245  LOG_ERROR("Failed to stop RA axis.");
247  }
248 
249  GuideWENP.np[0].value = 0;
250  GuideWENP.np[1].value = 0;
251  GuideWETID = 0;
252  IDSetNumber(&GuideWENP, nullptr);
253  }
254 }
255 
256 bool ArduinoST4::sendCommand(const char *cmd)
257 {
258  int nbytes_read = 0, nbytes_written = 0, tty_rc = 0;
259  char res[8] = {0};
260  LOGF_DEBUG("CMD <%s>", cmd);
261 
262  if (!isSimulation())
263  {
264  tcflush(PortFD, TCIOFLUSH);
265  if ( (tty_rc = tty_write_string(PortFD, cmd, &nbytes_written)) != TTY_OK)
266  {
267  char errorMessage[MAXRBUF];
268  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
269  LOGF_ERROR("Serial write error: %s", errorMessage);
270  return false;
271  }
272  }
273 
274  if (isSimulation())
275  {
276  strncpy(res, "OK#", 8);
277  nbytes_read = 3;
278  }
279  else
280  {
281  if ( (tty_rc = tty_read_section(PortFD, res, '#', ARDUINO_TIMEOUT, &nbytes_read)) != TTY_OK)
282  {
283  char errorMessage[MAXRBUF];
284  tty_error_msg(tty_rc, errorMessage, MAXRBUF);
285  LOGF_ERROR("Serial read error: %s", errorMessage);
286  return false;
287  }
288  }
289 
290  res[nbytes_read - 1] = '\0';
291  LOGF_DEBUG("RES <%s>", res);
292 
293  return true;
294 }
std::unique_ptr< ArduinoST4 > arduinoST4(new ArduinoST4())
virtual IPState GuideWest(uint32_t ms) override
Guide west for ms milliseconds. West is defined as RA-.
const char * getDefaultName() override
Definition: arduino_st4.cpp:89
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: arduino_st4.cpp:71
static void guideTimeoutHelperE(void *p)
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: arduino_st4.cpp:48
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
static void guideTimeoutHelperS(void *p)
virtual IPState GuideSouth(uint32_t ms) override
Guide south for ms milliseconds. South is defined as DEC-.
void guideTimeout(ARDUINO_DIRECTION direction)
virtual bool Disconnect() override
Disconnect from device.
static void guideTimeoutHelperW(void *p)
static void guideTimeoutHelperN(void *p)
virtual IPState GuideEast(uint32_t ms) override
Guide east for ms milliseconds. East is defined as RA+.
virtual IPState GuideNorth(uint32_t ms) override
Guide north for ms milliseconds. North is defined as DEC+.
void registerHandshake(std::function< bool()> callback)
registerHandshake Register a handshake function to be called once the intial connection to the device...
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
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...
Provides interface to implement guider (ST4) port functionality.
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
virtual bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
virtual bool Disconnect()
Disconnect from device.
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
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)
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
bool isSimulation() const
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
INumberVectorProperty GuideNSNP
void initGuiderProperties(const char *deviceName, const char *groupName)
Initilize guider properties. It is recommended to call this function within initProperties() of your ...
INumberVectorProperty GuideWENP
void processGuiderProperties(const char *name, double values[], char *names[], int n)
Call this function whenever client updates GuideNSNP or GuideWSP properties in the primary device....
const char * MOTION_TAB
MOTION_TAB Where all the motion control properties of the device are located.
void IERmTimer(int timerid)
Remove the timer with the given timerid, as returned from IEAddTimer() or IEAddPeriodicTimer().
Definition: eventloop.c:602
int IEAddTimer(int millisecs, IE_TCF *fp, void *p)
Register a new single-shot timer function, fp, to be called with ud as argument after ms.
Definition: eventloop.c:582
IPState
Property state.
Definition: indiapi.h:160
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
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:566
int tty_write_string(int fd, const char *buf, int *nbytes_written)
Writes a null terminated string to fd.
Definition: indicom.c:474
void tty_error_msg(int err_code, char *err_msg, int err_msg_len)
Retrieve the tty error message.
Definition: indicom.c:1167
Implementations for common driver routines.
@ TTY_OK
Definition: indicom.h:150
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define LOG_DEBUG(txt)
Definition: indilogger.h:75
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define MAXRBUF
Definition: indiserver.cpp:102
Namespace to encapsulate INDI client, drivers, and mediator classes.
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:323