Instrument Neutral Distributed Interface INDI 2.2.5
telescope_script.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2016 CloudMakers, s. r. o.. All rights reserved.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7 .
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12 .
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18
19#include "telescope_script.h"
20
21#include <cstring>
22#include <memory>
23
24#include <unistd.h>
25#include <sys/wait.h>
26#include <errno.h>
27
28#define MAXARGS 20
29
46
47static std::unique_ptr<ScopeScript> scope_script(new ScopeScript());
48
53
55{
56 return (const char *)"Telescope Scripting Gateway";
57}
58
60{
62
63#if defined(__APPLE__)
64 IUFillText(&ScriptsT[0], "FOLDER", "Folder", "/usr/local/share/indi/scripts");
65#else
66 IUFillText(&ScriptsT[0], "FOLDER", "Folder", "/usr/share/indi/scripts");
67#endif
68 IUFillText(&ScriptsT[SCRIPT_CONNECT], "SCRIPT_CONNECT", "Connect script", "connect.py");
69 IUFillText(&ScriptsT[SCRIPT_DISCONNECT], "SCRIPT_DISCONNECT", "Disconnect script", "disconnect.py");
70 IUFillText(&ScriptsT[SCRIPT_STATUS], "SCRIPT_STATUS", "Get status script", "status.py");
71 IUFillText(&ScriptsT[SCRIPT_GOTO], "SCRIPT_GOTO", "Goto script", "goto.py");
72 IUFillText(&ScriptsT[SCRIPT_SYNC], "SCRIPT_SYNC", "Sync script", "sync.py");
73 IUFillText(&ScriptsT[SCRIPT_PARK], "SCRIPT_PARK", "Park script", "park.py");
74 IUFillText(&ScriptsT[SCRIPT_UNPARK], "SCRIPT_UNPARK", "Unpark script", "unpark.py");
75 IUFillText(&ScriptsT[SCRIPT_MOVE_NORTH], "SCRIPT_MOVE_NORTH", "Move north script", "move_north.py");
76 IUFillText(&ScriptsT[SCRIPT_MOVE_EAST], "SCRIPT_MOVE_EAST", "Move east script", "move_east.py");
77 IUFillText(&ScriptsT[SCRIPT_MOVE_SOUTH], "SCRIPT_MOVE_SOUTH", "Move south script", "move_south.py");
78 IUFillText(&ScriptsT[SCRIPT_MOVE_WEST], "SCRIPT_MOVE_WEST", "Move west script", "move_west.py");
79 IUFillText(&ScriptsT[SCRIPT_ABORT], "SCRIPT_ABORT", "Abort motion script", "abort.py");
80 IUFillTextVector(&ScriptsTP, ScriptsT, SCRIPT_COUNT, getDefaultName(), "SCRIPTS", "Scripts", OPTIONS_TAB, IP_RW, 60,
81 IPS_IDLE);
82
85 return true;
86}
87
89{
91 IUSaveConfigText(fp, &ScriptsTP);
92 return true;
93}
94
95void ScopeScript::ISGetProperties(const char *dev)
96{
98 defineProperty(&ScriptsTP);
99}
100
101bool ScopeScript::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
102{
103 if (strcmp(dev, getDeviceName()) == 0 && strcmp(name, ScriptsTP.name) == 0)
104 {
105 IUUpdateText(&ScriptsTP, texts, names, n);
106 IDSetText(&ScriptsTP, nullptr);
107 return true;
108 }
109 return Telescope::ISNewText(dev, name, texts, names, n);
110}
111
112bool ScopeScript::RunScript(int script, ...)
113{
114 char tmp[256];
115 snprintf(tmp, sizeof(tmp), "%s", ScriptsT[script].text);
116
117 char **args = (char **)malloc(MAXARGS * sizeof(char *));
118 int arg = 1;
119 char *p = tmp;
120 args[0] = p;
121 while (arg < MAXARGS)
122 {
123 char *pp = strstr(p, " ");
124 if (pp == nullptr)
125 break;
126 *pp++ = 0;
127 args[arg++] = pp;
128 p = pp;
129 }
130 va_list ap;
131 va_start(ap, script);
132 while (arg < MAXARGS)
133 {
134 char *pp = va_arg(ap, char *);
135 args[arg++] = pp;
136 if (pp == nullptr)
137 break;
138 }
139 va_end(ap);
140 char path[1024];
141 snprintf(path, sizeof(path), "%s/%s", ScriptsT[0].text, tmp);
142
143 if (access(path, F_OK | X_OK) != 0)
144 {
145 LOGF_ERROR("Cannot use script [%s], %s", path, strerror(errno));
146 return false;
147 }
148 if (isDebug())
149 {
150 char dbg[8 * 1024];
151 snprintf(dbg, sizeof(dbg), "execvp('%s'", path);
152 for (int i = 0; args[i]; i++)
153 {
154 strcat(dbg, ", '");
155 strcat(dbg, args[i]);
156 strcat(dbg, "'");
157 }
158 strcat(dbg, ", nullptr)");
159 LOG_DEBUG(dbg);
160 }
161
162 int pid = fork();
163 if (pid == -1)
164 {
165 LOG_ERROR("Fork failed");
166 return false;
167 }
168 else if (pid == 0)
169 {
170 execvp(path, args);
171 LOG_ERROR("Failed to execute script");
172 exit(1);
173 }
174 else
175 {
176 int status;
177 waitpid(pid, &status, 0);
178 LOGF_DEBUG("Script %s returned %d", ScriptsT[script].text, status);
179 return status == 0;
180 }
181}
182
184{
185 return true;
186}
187
189{
190 if (isConnected())
191 return true;
192
193 bool status = RunScript(SCRIPT_CONNECT, nullptr);
194 if (status)
195 {
196 LOG_INFO("Successfully connected");
199 }
200 else
201 {
202 LOG_ERROR("Failed to connect");
203 }
204 return status;
205}
206
208{
209 bool status = RunScript(SCRIPT_DISCONNECT, nullptr);
210 if (status)
211 {
212 LOG_INFO("Successfully disconnected");
213 }
214 else
215 {
216 LOG_WARN("Failed to disconnect");
217 }
218 return status;
219}
220
222{
223 if (!isConnected())
224 return false;
225 char tmpfile[] = "/tmp/indi_telescope_script_status_XXXXXX";
226 int fd = mkstemp(tmpfile);
227 if (fd == -1)
228 {
229 LOGF_ERROR("Temp file %s creation for status script failed, %s", tmpfile, strerror(errno));
230 unlink(tmpfile);
231 return false;
232 }
233 close(fd);
234 bool status = RunScript(SCRIPT_STATUS, tmpfile, nullptr);
235 if (status)
236 {
237 int parked = 0;
238 float ra = 0, dec = 0;
239 FILE *file = fopen(tmpfile, "r");
240
241 int rc = fscanf(file, "%d %f %f", &parked, &ra, &dec);
242 INDI_UNUSED(rc);
243 fclose(file);
244 unlink(tmpfile);
245 if (parked != 0)
246 {
247 if (!isParked())
248 {
249 SetParked(true);
250 LOG_INFO("Park successfully executed");
251 }
252 }
253 else
254 {
255 if (isParked())
256 {
257 SetParked(false);
258 LOG_INFO("Unpark successfully executed");
259 }
260 }
261 NewRaDec(ra, dec);
262 }
263 else
264 {
265 LOG_ERROR("Failed to read status");
266 }
267 return status;
268}
269
270bool ScopeScript::Goto(double ra, double dec)
271{
272 char _ra[16], _dec[16];
273 snprintf(_ra, 16, "%f", ra);
274 snprintf(_dec, 16, "%f", dec);
275 bool status = RunScript(SCRIPT_GOTO, _ra, _dec, nullptr);
276 if (status)
277 {
278 LOG_INFO("Goto successfully executed");
280 }
281 else
282 {
283 LOG_ERROR("Goto failed");
284 }
285 return status;
286}
287
288bool ScopeScript::Sync(double ra, double dec)
289{
290 char _ra[16], _dec[16];
291 snprintf(_ra, 16, "%f", ra);
292 snprintf(_dec, 16, "%f", dec);
293 bool status = RunScript(SCRIPT_SYNC, _ra, _dec, nullptr);
294 if (status)
295 {
296 LOG_INFO("Sync successfully executed");
297 }
298 else
299 {
300 LOG_ERROR("Failed to sync");
301 }
302 return status;
303}
304
306{
307 bool status = RunScript(SCRIPT_PARK, nullptr);
308 if (!status)
309 {
310 LOG_ERROR("Failed to park");
311 }
312 return status;
313}
314
316{
317 bool status = RunScript(SCRIPT_UNPARK, nullptr);
318 if (!status)
319 {
320 LOG_ERROR("Failed to unpark");
321 }
322 return status;
323}
324
326{
327 char _rate[] = { (char)('0' + SlewRateSP.findOnSwitchIndex()), 0 };
328 bool status = RunScript(command == MOTION_STOP ? SCRIPT_ABORT :
330 _rate, nullptr, nullptr);
331 return status;
332}
333
335{
336 char _rate[] = { (char)('0' + SlewRateSP.findOnSwitchIndex()), 0 };
337 bool status =
338 RunScript(command == MOTION_STOP ? SCRIPT_ABORT : dir == DIRECTION_WEST ? SCRIPT_MOVE_WEST : SCRIPT_MOVE_EAST,
339 _rate, nullptr, nullptr);
340 return status;
341}
342
344{
345 bool status = RunScript(SCRIPT_ABORT, nullptr);
346 if (status)
347 {
348 LOG_INFO("Successfully aborted");
349 }
350 else
351 {
352 LOG_ERROR("Failed to abort");
353 }
354 return status;
355}
bool isConnected() const
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
uint32_t getDriverInterface() const
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
TelescopeStatus TrackState
void SetTelescopeCapability(uint32_t cap, uint8_t slewRateCount)
SetTelescopeCapability sets the Telescope capabilities. All capabilities must be initialized.
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
bool isParked()
isParked is mount currently parked?
virtual void SetParked(bool isparked)
SetParked Change the mount parking status. The data park file (stored in ~/.indi/ParkData....
void NewRaDec(double ra, double dec)
The child class calls this function when it has updates.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool Goto(double, double) override
Move the scope to the supplied RA and DEC coordinates.
virtual bool ReadScopeStatus() override
Read telescope status.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool Sync(double ra, double dec) override
Set the telescope current RA and DEC coordinates to the supplied RA and DEC coordinates.
virtual const char * getDefaultName() override
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
virtual bool Handshake() override
perform handshake with device to check communication
virtual bool initProperties() override
Called to initialize basic properties required all the time.
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
virtual bool MoveNS(INDI_DIR_NS dir, TelescopeMotionCommand command) override
Start or Stop the telescope motion in the direction dir.
virtual bool Park() override
Park the telescope to its home position.
virtual bool UnPark() override
Unpark the telescope if already parked.
virtual bool Abort() override
Abort any telescope motion including tracking if possible.
virtual bool MoveWE(INDI_DIR_WE dir, TelescopeMotionCommand command) override
Move the telescope in the direction dir.
virtual bool Disconnect() override
Disconnect from device.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
#define MAXARGS
@ SCRIPT_DISCONNECT
@ SCRIPT_PARK
@ SCRIPT_STATUS
@ SCRIPT_CONNECT
@ SCRIPT_COUNT
@ SCRIPT_UNPARK
@ SCRIPT_ABORT
@ SCRIPT_GOTO
int errno
INDI::PropertySwitch SlewRateSP
double ra
double dec
@ IP_RW
Definition indiapi.h:184
@ IPS_IDLE
Definition indiapi.h:159
INDI_DIR_WE
@ DIRECTION_WEST
INDI_DIR_NS
@ DIRECTION_NORTH
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 indidevapi.c:509
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 indidevapi.c:416
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition indidevapi.c:28
#define INDI_UNUSED(x)
Definition indidevapi.h:132
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
#define LOG_DEBUG(txt)
Definition indilogger.h:75
#define LOG_WARN(txt)
Definition indilogger.h:73
#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 LOG_INFO(txt)
Definition indilogger.h:74
#define getDeviceName
int fd
char name[MAXINDINAME]
Definition indiapi.h:248
@ SCRIPT_DISCONNECT
@ SCRIPT_MOVE_EAST
@ SCRIPT_MOVE_WEST
@ SCRIPT_PARK
@ SCRIPT_STATUS
@ SCRIPT_CONNECT
@ SCRIPT_COUNT
@ SCRIPT_SYNC
@ SCRIPT_UNPARK
@ SCRIPT_ABORT
@ SCRIPT_MOVE_SOUTH
@ SCRIPT_GOTO
@ SCRIPT_MOVE_NORTH