Instrument Neutral Distributed Interface INDI  2.0.2
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 #ifdef __FreeBSD__
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
48 static 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,
96  ISR_1OFMANY, 0, IPS_IDLE);
97 
98  IUFillText(&ActiveDeviceT[ACTIVE_TELESCOPE], "ACTIVE_TELESCOPE", "Telescope", "Telescope Simulator");
99  IUFillTextVector(&ActiveDeviceTP, ActiveDeviceT, 1, getDeviceName(), "ACTIVE_DEVICES", "Active devices",
100  OPTIONS_TAB, IP_RW, 60, IPS_IDLE);
101 
102  addDebugControl();
103 
105 
106  return true;
107 }
108 
109 void SkySafari::ISGetProperties(const char *dev)
110 {
111  // First we let our parent populate
113 
114  defineProperty(&SettingsTP);
115  defineProperty(&ActiveDeviceTP);
116 
117  loadConfig(true);
118 }
119 
120 bool 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 
144 bool 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 
277 bool 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 
333 bool 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 
345 void 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 
664 void 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 
683 bool 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 
704 void 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?!!!
746 std::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
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
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()
Initilize properties initial state and value. The child class must implement this function.
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
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
Initilize 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...
Definition: skysafari.cpp:109
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.
Definition: skysafari.cpp:199
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.
Definition: skysafari.cpp:120
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: skysafari.cpp:191
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: skysafari.cpp:144
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.
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Update the value of an existing switch vector property.
void ISGetProperties(const char *dev)
Get Device Properties.
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:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
@ IP_RW
Definition: indiapi.h:186
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
@ ISR_1OFMANY
Definition: indiapi.h:173
@ AXIS_DE
Definition: indibasetypes.h:36
@ AXIS_RA
Definition: indibasetypes.h:35
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:205
void getSexComponents(double value, int *d, int *m, int *s)
Definition: indicom.c:254
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:291
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:137
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:158
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:198
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indidevapi.c:20
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:235
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:1308
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
Definition: indidriver.c:1231
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:1396
void IDSetText(const ITextVectorProperty *tvp, const char *fmt,...)
Definition: indidriver.c:1191
#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
std::vector< uint8_t > buffer
std::vector< std::string > split(const std::string &input, const std::string &regex)
__u8 cmd[4]
Definition: pwc-ioctl.h:2
char name[MAXINDINAME]
Definition: indiapi.h:371
char name[MAXINDINAME]
Definition: indiapi.h:250