Instrument Neutral Distributed Interface INDI 2.2.5
skysafari.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 Copyright(c) 2017 Jasem Mutlaq. All rights reserved.
3
4 INDI SkySafar Middleware Driver.
5
6 The driver expects a heartbeat from the client every X minutes. If no heartbeat
7 is received, the driver executes the shutdown procedures.
8
9 This program is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 2 of the License, or (at your option)
12 any later version.
13
14 This program is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 more details.
18
19 You should have received a copy of the GNU Library General Public License
20 along with this library; see the file COPYING.LIB. If not, write to
21 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23
24 The full GNU General Public License is included in this distribution in the
25 file called LICENSE.
26*******************************************************************************/
27#include "skysafari.h"
28#include "skysafariclient.h"
29
30#include "indicom.h"
31
32#include <libnova/julian_day.h>
33
34#include <cerrno>
35#include <cstring>
36#include <cmath>
37#include <fcntl.h>
38#include <unistd.h>
39#include <arpa/inet.h>
40#include <sys/socket.h>
41
42#if defined(__FreeBSD__) || defined(__OpenBSD__)
43#include <netinet/in.h>
44#endif
45
46// We declare unique pointer to my lovely German Shephard Tommy (http://indilib.org/images/juli_tommy.jpg)
47// Rest in Peace Tommy 2013-2018
48static std::unique_ptr<SkySafari> tommyGoodBoy(new SkySafari());
49
51{
52 setVersion(0, 2);
54
55 skySafariClient.reset(new SkySafariClient());
56}
57
59{
60 return "SkySafari";
61}
62
64{
65 bool rc = startServer();
66 if (rc)
67 {
68 skySafariClient->setMount(ActiveDeviceT[ACTIVE_TELESCOPE].text);
69 skySafariClient->setServer(SettingsT[INDISERVER_HOST].text, std::stoi(SettingsT[INDISERVER_PORT].text));
70 skySafariClient->connectServer();
72 }
73
74 return rc;
75}
76
78{
79 return stopServer();
80}
81
83{
85
86 IUFillText(&SettingsT[INDISERVER_HOST], "INDISERVER_HOST", "indiserver host", "localhost");
87 IUFillText(&SettingsT[INDISERVER_PORT], "INDISERVER_PORT", "indiserver port", "7624");
88 IUFillText(&SettingsT[SKYSAFARI_PORT], "SKYSAFARI_PORT", "SkySafari port", "9624");
89 IUFillTextVector(&SettingsTP, SettingsT, 3, getDeviceName(), "SKYSAFARI_SETTINGS", "Settings", MAIN_CONTROL_TAB,
90 IP_RW, 60, IPS_IDLE);
91
92 IUFillSwitch(&ServerControlS[SERVER_ENABLE], "SERVER_ENABLE", "Enabled", ISS_OFF);
93 IUFillSwitch(&ServerControlS[SERVER_DISABLE], "SERVER_DISABLE", "Disabled", ISS_ON);
94 IUFillSwitchVector(&ServerControlSP, ServerControlS, 2, getDeviceName(), "SKYSAFARI_SERVER", "Server", MAIN_CONTROL_TAB,
95 IP_RW,
97
98 IUFillText(&ActiveDeviceT[ACTIVE_TELESCOPE], "ACTIVE_TELESCOPE", "Telescope", "Telescope Simulator");
99 IUFillTextVector(&ActiveDeviceTP, ActiveDeviceT, 1, getDeviceName(), "ACTIVE_DEVICES", "Active devices",
101
103
105
106 return true;
107}
108
109void SkySafari::ISGetProperties(const char *dev)
110{
111 // First we let our parent populate
112 DefaultDevice::ISGetProperties(dev);
113
114 defineProperty(&SettingsTP);
115 defineProperty(&ActiveDeviceTP);
116
117 loadConfig(true);
118}
119
120bool SkySafari::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
121{
122 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
123 {
124 if (!strcmp(SettingsTP.name, name))
125 {
126 IUUpdateText(&SettingsTP, texts, names, n);
127 SettingsTP.s = IPS_OK;
128 IDSetText(&SettingsTP, nullptr);
129 return true;
130 }
131
132 if (!strcmp(ActiveDeviceTP.name, name))
133 {
134 IUUpdateText(&ActiveDeviceTP, texts, names, n);
135 ActiveDeviceTP.s = IPS_OK;
136 IDSetText(&ActiveDeviceTP, nullptr);
137 return true;
138 }
139 }
140
141 return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
142}
143
144bool SkySafari::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
145{
146 if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
147 {
148 if (!strcmp(ServerControlSP.name, name))
149 {
150 bool rc = false;
151
152 if (!strcmp(IUFindOnSwitchName(states, names, n), ServerControlS[SERVER_ENABLE].name))
153 {
154 // If already working, do nothing
155 if (ServerControlS[SERVER_ENABLE].s == ISS_ON)
156 {
157 ServerControlSP.s = IPS_OK;
158 IDSetSwitch(&ServerControlSP, nullptr);
159 return true;
160 }
161
162 rc = startServer();
163 ServerControlSP.s = (rc ? IPS_OK : IPS_ALERT);
164 }
165 else
166 {
167 if (!strcmp(IUFindOnSwitchName(states, names, n), ServerControlS[SERVER_DISABLE].name))
168 {
169 // If already working, do nothing
170 if (ServerControlS[SERVER_DISABLE].s == ISS_ON)
171 {
172 ServerControlSP.s = IPS_IDLE;
173 IDSetSwitch(&ServerControlSP, nullptr);
174 return true;
175 }
176
177 rc = stopServer();
178 ServerControlSP.s = (rc ? IPS_IDLE : IPS_ALERT);
179 }
180 }
181
182 IUUpdateSwitch(&ServerControlSP, states, names, n);
183 IDSetSwitch(&ServerControlSP, nullptr);
184 return true;
185 }
186 }
187
188 return DefaultDevice::ISNewSwitch(dev, name, states, names, n);
189}
190
192{
193 IUSaveConfigText(fp, &SettingsTP);
194 IUSaveConfigText(fp, &ActiveDeviceTP);
195
196 return true;
197}
198
200{
201 if (!isConnected())
202 return;
203
204 if (clientFD == -1)
205 {
206 struct sockaddr_in cli_socket;
207 socklen_t cli_len;
208 int cli_fd = -1;
209
210 /* get a private connection to new client */
211 cli_len = sizeof(cli_socket);
212 cli_fd = accept(lsocket, (struct sockaddr *)&cli_socket, &cli_len);
213 if (cli_fd < 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
214 {
215 // Try again later
217 return;
218 }
219 else if (cli_fd < 0)
220 {
221 LOGF_ERROR("Failed to connect to SkySafari. %s", strerror(errno));
223 return;
224 }
225
226 clientFD = cli_fd;
227
228 int flags = 0;
229 // Get socket flags
230 if ((flags = fcntl(clientFD, F_GETFL, 0)) < 0)
231 {
232 LOGF_ERROR("Error connecting to SkySafari. F_GETFL: %s", strerror(errno));
233 }
234
235 // Set to Non-Blocking
236 if (fcntl(clientFD, F_SETFL, flags | O_NONBLOCK) < 0)
237 {
238 LOGF_ERROR("Error connecting to SkySafari. F_SETFL: %s", strerror(errno));
239 }
240
241 // Only show message first time SkySafari connects
242 if (isSkySafariConnected == false)
243 {
244 LOG_INFO("Connected to SkySafari.");
245 isSkySafariConnected = true;
246 }
247 }
248 else
249 {
250 // Read from SkySafari
251 char buffer[64] = { 0 };
252 int rc = read(clientFD, buffer, 64);
253 if (rc > 0)
254 {
255 std::vector<std::string> commands = split(buffer, '#');
256 for (std::string cmd : commands)
257 {
258 // Remove the :
259 cmd.erase(0, 1);
260 processCommand(cmd);
261 }
262 }
263 // EOF
264 else if (rc == 0)
265 {
266 //LOG_ERROR("SkySafari Disconnected? Reconnect again.");
267 close(clientFD);
268 clientFD = -1;
269 }
270
271 // Otherwise EAGAIN so we just try shortly
272 }
273
275}
276
277bool SkySafari::startServer()
278{
279 struct sockaddr_in serv_socket;
280 int sfd;
281 int flags = 0;
282 int reuse = 1;
283
284 /* make socket endpoint */
285 if ((sfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
286 {
287 LOGF_ERROR("Error starting server. socket: %s", strerror(errno));
288 return false;
289 }
290
291 // Get socket flags
292 if ((flags = fcntl(sfd, F_GETFL, 0)) < 0)
293 {
294 LOGF_ERROR("Error starting server. F_GETFL: %s", strerror(errno));
295 }
296
297 // Set to Non-Blocking
298 if (fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0)
299 {
300 LOGF_ERROR("Error starting server. F_SETFL: %s", strerror(errno));
301 }
302
303 /* bind to given port for any IP address */
304 memset(&serv_socket, 0, sizeof(serv_socket));
305 serv_socket.sin_family = AF_INET;
306 serv_socket.sin_addr.s_addr = htonl(INADDR_ANY);
307 serv_socket.sin_port = htons((unsigned short)atoi(SettingsT[SKYSAFARI_PORT].text));
308 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
309 {
310 LOGF_ERROR("Error starting server. setsockopt: %s", strerror(errno));
311 return false;
312 }
313
314 if (::bind(sfd, (struct sockaddr *)&serv_socket, sizeof(serv_socket)) < 0)
315 {
316 LOGF_ERROR("Error starting server. bind: %s", strerror(errno));
317 return false;
318 }
319
320 /* willing to accept connections with a backlog of 5 pending */
321 if (listen(sfd, 5) < 0)
322 {
323 LOGF_ERROR("Error starting server. listen: %s", strerror(errno));
324 return false;
325 }
326
327 lsocket = sfd;
328 LOG_INFO(
329 "SkySafari Server is running. Connect the App now to this machine using SkySafari LX200 driver.");
330 return true;
331}
332
333bool SkySafari::stopServer()
334{
335 if (clientFD > 0)
336 close(clientFD);
337 if (lsocket > 0)
338 close(lsocket);
339
340 clientFD = lsocket = -1;
341
342 return true;
343}
344
345void SkySafari::processCommand(std::string cmd)
346{
347 LOGF_DEBUG("CMD <%s>", cmd.c_str());
348
349 if (skySafariClient->isConnected() == false)
350 {
351 LOG_ERROR("Internal client is not connected! Please make sure the mount name is set in the Options tab. Disconnect and reconnect to try again.");
352 return;
353 }
354
355 // Set site Latitude
356 if (cmd.compare(0, 2, "St") == 0)
357 {
358 int dd = 0, mm = 0;
359 if (sscanf(cmd.c_str(), "St%d%*c%d", &dd, &mm) == 2)
360 {
361 haveLatitude = true;
362 siteLatitude = dd + mm / 60.0;
363 }
364
365 // Always respond with valid
366 sendSkySafari("1");
367
368 // Try sending geographic coords if all is available
369 sendGeographicCoords();
370 }
371 // Set site Longitude
372 else if (cmd.compare(0, 2, "Sg") == 0)
373 {
374 int ddd = 0, mm = 0;
375 if (sscanf(cmd.c_str(), "Sg%d%*c%d", &ddd, &mm) == 2)
376 {
377 haveLongitude = true;
378 siteLongitude = ddd + mm / 60.0;
379
380 // Convert to INDI format (0 to 360 Eastwards). Meade is 0 to 360 Westwards.
381 siteLongitude = 360 - siteLongitude;
382 }
383
384 // Always respond with valid
385 sendSkySafari("1");
386
387 // Try sending geographic coords if all is available
388 sendGeographicCoords();
389 }
390 // set the number of hours added to local time to yield UTC
391 else if (cmd.compare(0, 2, "SG") == 0)
392 {
393 int ofs;
394 if (sscanf(cmd.c_str(), "SG%d", &ofs) == 1)
395 {
396 ofs = -ofs;
397 LOGF_DEBUG("UTC Offset: %d", ofs);
398
399 timeUTCOffset = ofs;
400 haveUTCoffset = true;
401 }
402
403 // Always respond with valid
404 sendSkySafari("1");
405
406 // Try sending geographic coords if all is available
407 sendUTCtimedate();
408 }
409 // set the local time
410 else if (cmd.compare(0, 2, "SL") == 0)
411 {
412 int hh, mm, ss;
413 if (sscanf(cmd.c_str(), "SL%d:%d:%d", &hh, &mm, &ss) == 3)
414 {
415 LOGF_DEBUG("TIME : %02d:%02d:%02d", hh, mm, ss);
416
417 timeHour = hh;
418 timeMin = mm;
419 timeSec = ss;
420 haveUTCtime = true;
421 }
422
423 // Always respond with valid
424 sendSkySafari("1");
425
426 // Try sending geographic coords if all is available
427 sendUTCtimedate();
428 }
429 // set the local date
430 else if (cmd.compare(0, 2, "SC") == 0)
431 {
432 int yyyy, mm, dd;
433 if (sscanf(cmd.c_str(), "SC%d/%d/%d", &mm, &dd, &yyyy) == 3)
434 {
435 LOGF_DEBUG("DATE : %02d-%02d-%02d", yyyy, mm, dd);
436
437 timeYear = yyyy;
438 timeMonth = mm;
439 timeDay = dd;
440 haveUTCdate = true;
441 }
442
443 // Always respond with valid
444 sendSkySafari("1");
445
446 // Try sending geographic coords if all is available
447 sendUTCtimedate();
448 }
449 // Get RA
450 else if (cmd == "GR")
451 {
452 auto eqCoordsNP = skySafariClient->getEquatorialCoords();
453 if (eqCoordsNP == nullptr)
454 {
455 LOG_WARN("Unable to communicate with mount, is mount turned on and connected?");
456 return;
457 }
458
459 int hh, mm, ss;
460 char output[32] = { 0 };
461 getSexComponents(eqCoordsNP->at(AXIS_RA)->getValue(), &hh, &mm, &ss);
462 snprintf(output, 32, "%02d:%02d:%02d#", hh, mm, ss);
463 sendSkySafari(output);
464 }
465 // Get DE
466 else if (cmd == "GD")
467 {
468 auto eqCoordsNP = skySafariClient->getEquatorialCoords();
469 if (eqCoordsNP == nullptr)
470 {
471 LOG_WARN("Unable to communicate with mount, is mount turned on and connected?");
472 return;
473 }
474 int dd, mm, ss;
475 char output[32] = { 0 };
476 getSexComponents(eqCoordsNP->at(AXIS_DE)->getValue(), &dd, &mm, &ss);
477 snprintf(output, 32, "%c%02d:%02d:%02d#", (eqCoordsNP->at(AXIS_DE)->getValue() >= 0) ? '+' : '-',
478 std::abs(dd), mm, ss);
479 sendSkySafari(output);
480 }
481 // Set RA
482 else if (cmd.compare(0, 2, "Sr") == 0)
483 {
484 f_scansexa(cmd.c_str() + 2, &RA);
485 // Always respond with valid
486 sendSkySafari("1");
487 }
488 // Set DE
489 else if (cmd.compare(0, 2, "Sd") == 0)
490 {
491 f_scansexa(cmd.c_str() + 2, &DE);
492 // Always respond with valid
493 sendSkySafari("1");
494 }
495 // GOTO
496 else if (cmd == "MS")
497 {
498 auto gotoModeSP = skySafariClient->getGotoMode();
499 if (gotoModeSP == nullptr)
500 {
501 sendSkySafari("2<Not Supported>#");
502 return;
503 }
504
505 // Set mode first
506 auto trackSW = gotoModeSP->findWidgetByName("TRACK");
507 if (trackSW == nullptr)
508 {
509 sendSkySafari("2<Not Supported>#");
510 return;
511 }
512
513 gotoModeSP->reset();
514 trackSW->setState(ISS_ON);
515 skySafariClient->sendGotoMode();
516
517 auto eqCoordsNP = skySafariClient->getEquatorialCoords();
518 eqCoordsNP->at(AXIS_RA)->setValue(RA);
519 eqCoordsNP->at(AXIS_DE)->setValue(DE);
520 skySafariClient->sendEquatorialCoords();
521
522 sendSkySafari("0");
523 }
524 // Sync
525 else if (cmd == "CM")
526 {
527 auto gotoModeSP = skySafariClient->getGotoMode();
528 if (gotoModeSP == nullptr)
529 {
530 sendSkySafari("Not Supported#");
531 return;
532 }
533
534 // Set mode first
535 auto syncSW = gotoModeSP->findWidgetByName("SYNC");
536 if (syncSW == nullptr)
537 {
538 sendSkySafari("Not Supported#");
539 return;
540 }
541
542 gotoModeSP->reset();
543 syncSW->setState(ISS_ON);
544 skySafariClient->sendGotoMode();
545
546 auto eqCoordsNP = skySafariClient->getEquatorialCoords();
547 eqCoordsNP->at(AXIS_RA)->setValue(RA);
548 eqCoordsNP->at(AXIS_DE)->setValue(DE);
549 skySafariClient->sendEquatorialCoords();
550
551 sendSkySafari(" M31 EX GAL MAG 3.5 SZ178.0'#");
552 }
553 // Abort
554 else if (cmd == "Q")
555 {
556 skySafariClient->abort();
557 }
558 // RG
559 else if (cmd == "RG")
560 {
561 skySafariClient->setSlewRate(0);
562 }
563 // RC
564 else if (cmd == "RC")
565 {
566 skySafariClient->setSlewRate(1);
567 }
568 // RM
569 else if (cmd == "RM")
570 {
571 skySafariClient->setSlewRate(2);
572 }
573 // RS
574 else if (cmd == "RS")
575 {
576 skySafariClient->setSlewRate(3);
577 }
578 // Mn
579 else if (cmd == "Mn")
580 {
581 auto motionNSNP = skySafariClient->getMotionNS();
582 if (motionNSNP)
583 {
584 motionNSNP->reset();
585 motionNSNP->at(0)->setState(ISS_ON);
586 skySafariClient->setMotionNS();
587 }
588 }
589 // Qn
590 else if (cmd == "Qn")
591 {
592 auto motionNSNP = skySafariClient->getMotionNS();
593 if (motionNSNP)
594 {
595 motionNSNP->reset();
596 skySafariClient->setMotionNS();
597 }
598 }
599 // Ms
600 else if (cmd == "Ms")
601 {
602 auto motionNSNP = skySafariClient->getMotionNS();
603 if (motionNSNP)
604 {
605 motionNSNP->reset();
606 motionNSNP->at(1)->setState(ISS_ON);
607 skySafariClient->setMotionNS();
608 }
609 }
610 // Qs
611 else if (cmd == "Qs")
612 {
613 auto motionNSNP = skySafariClient->getMotionNS();
614 if (motionNSNP)
615 {
616 motionNSNP->reset();
617 skySafariClient->setMotionNS();
618 }
619 }
620 // Mw
621 else if (cmd == "Mw")
622 {
623 auto motionWENP = skySafariClient->getMotionWE();
624 if (motionWENP)
625 {
626 motionWENP->reset();
627 motionWENP->at(0)->setState(ISS_ON);
628 skySafariClient->setMotionWE();
629 }
630 }
631 // Qw
632 else if (cmd == "Qw")
633 {
634 auto motionWENP = skySafariClient->getMotionWE();
635 if (motionWENP)
636 {
637 motionWENP->reset();
638 skySafariClient->setMotionWE();
639 }
640 }
641 // Me
642 else if (cmd == "Me")
643 {
644 auto motionWENP = skySafariClient->getMotionWE();
645 if (motionWENP)
646 {
647 motionWENP->reset();
648 motionWENP->at(1)->setState(ISS_ON);
649 skySafariClient->setMotionWE();
650 }
651 }
652 // Qe
653 else if (cmd == "Qe")
654 {
655 auto motionWENP = skySafariClient->getMotionWE();
656 if (motionWENP)
657 {
658 motionWENP->reset();
659 skySafariClient->setMotionWE();
660 }
661 }
662}
663
664void SkySafari::sendGeographicCoords()
665{
666 auto geographicCoords = skySafariClient->getGeographiCoords();
667 if (geographicCoords && haveLatitude && haveLongitude)
668 {
669 auto latitude = geographicCoords->findWidgetByName("LAT");
670 auto longitude = geographicCoords->findWidgetByName("LONG");
671 if (latitude && longitude)
672 {
673 latitude->setValue(siteLatitude);
674 longitude->setValue(siteLongitude);
675 skySafariClient->sendGeographicCoords();
676
677 // Reset
678 haveLatitude = haveLongitude = false;
679 }
680 }
681}
682
683bool SkySafari::sendSkySafari(const char *message)
684{
685 LOGF_DEBUG("RES <%s>", message);
686
687 int bytesWritten = 0, totalBytes = strlen(message);
688
689 while (bytesWritten < totalBytes)
690 {
691 int bytesSent = write(clientFD, message, totalBytes - bytesWritten);
692 if (bytesSent >= 0)
693 bytesWritten += bytesSent;
694 else
695 {
696 LOGF_ERROR("Error writing to SkySafari. %s", strerror(errno));
697 return false;
698 }
699 }
700
701 return true;
702}
703
704void SkySafari::sendUTCtimedate()
705{
706 auto timeUTC = skySafariClient->getTimeUTC();
707 if (timeUTC && haveUTCoffset && haveUTCtime && haveUTCdate)
708 {
709 int yyyy = timeYear;
710 if (yyyy < 100)
711 yyyy += 2000;
712
713 // local to UTC
714 ln_zonedate zonedate;
715 ln_date utcdate;
716 zonedate.years = yyyy;
717 zonedate.months = timeMonth;
718 zonedate.days = timeDay;
719 zonedate.hours = timeHour;
720 zonedate.minutes = timeMin;
721 zonedate.seconds = timeSec;
722 zonedate.gmtoff = timeUTCOffset * 3600.0;
723
724 ln_zonedate_to_date(&zonedate, &utcdate);
725
726 char bufDT[32] = {0};
727 char bufOff[8] = {0};
728
729 snprintf(bufDT, 32, "%04d-%02d-%02dT%02d:%02d:%02d", utcdate.years, utcdate.months, utcdate.days, utcdate.hours,
730 utcdate.minutes, (int)(utcdate.seconds));
731 snprintf(bufOff, 8, "%4.2f", timeUTCOffset);
732
733 timeUTC->findWidgetByName("UTC")->setText(bufDT);
734 timeUTC->findWidgetByName("OFFSET")->setText(bufOff);
735
736 LOGF_DEBUG("send to timedate. %s, %s", bufDT, bufOff);
737
738 skySafariClient->setTimeUTC();
739
740 // Reset
741 haveUTCoffset = haveUTCtime = haveUTCdate = false;
742 }
743}
744
745// Had to get this from stackoverflow, why C++ STL lacks such basic functionality?!!!
746std::vector<std::string> SkySafari::split(const std::string &text, char sep)
747{
748 std::vector<std::string> tokens;
749 std::size_t start = 0, end = 0;
750 while ((end = text.find(sep, start)) != std::string::npos)
751 {
752 tokens.push_back(text.substr(start, end - start));
753 start = end + 1;
754 }
755 tokens.push_back(text.substr(start));
756 return tokens;
757}
bool isConnected() const
const char * getDeviceName() const
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
void setDriverInterface(uint32_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
void setVersion(uint16_t vMajor, uint16_t vMinor)
Set driver version information to be defined in DRIVER_INFO property as vMajor.vMinor.
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
void defineProperty(INumberVectorProperty *property)
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
virtual bool initProperties()
Initialize properties initial state and value. The child class must implement this function.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void addDebugControl()
Add Debug control to the driver.
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
virtual bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
Definition skysafari.cpp:82
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...
virtual bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition skysafari.cpp:63
virtual void TimerHit() override
Callback function to be called once SetTimer duration elapses.
virtual const char * getDefaultName() override
Definition skysafari.cpp:58
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n) override
Process the client newSwitch command.
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
virtual bool Disconnect() override
Disconnect from device.
Definition skysafari.cpp:77
const char * MAIN_CONTROL_TAB
MAIN_CONTROL_TAB Where all the primary controls for the device are located.
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
int errno
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
@ IPS_ALERT
Definition indiapi.h:162
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
@ ISR_1OFMANY
Definition indiapi.h:171
@ AXIS_DE
@ AXIS_RA
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double. x can be anything non-numeric. Any missing A,...
Definition indicom.c:194
void getSexComponents(double value, int *d, int *m, int *s)
Definition indicom.c:243
Implementations for common driver routines.
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 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 indidevapi.c:376
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
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 indidevapi.c:453
const char * IUFindOnSwitchName(ISState *states, char *names[], int n)
Returns the name of the first ON switch it finds in the supplied arguments.
Definition indidevapi.c:355
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
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_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
uint8_t cmd[4]
Definition pwc-ioctl.h:2
char name[MAXINDINAME]
Definition indiapi.h:369
char name[MAXINDINAME]
Definition indiapi.h:248