Instrument Neutral Distributed Interface INDI  1.9.5
indisensorinterface.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2010, 2017 Ilia Platone, Jasem Mutlaq. All rights reserved.
3 
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 *******************************************************************************/
19 
20 #include "defaultdevice.h"
21 #include "indisensorinterface.h"
24 
25 #include "indicom.h"
26 #include "libastro.h"
27 #include "stream/streammanager.h"
28 #include "locale_compat.h"
29 #include "indiutility.h"
30 
31 #include <fitsio.h>
32 
33 #include <libnova/julian_day.h>
34 #include <libnova/ln_types.h>
35 #include <libnova/precession.h>
36 
37 #include <regex>
38 
39 #include <dirent.h>
40 #include <cerrno>
41 #include <locale.h>
42 #include <cstdlib>
43 #include <zlib.h>
44 #include <sys/stat.h>
45 
46 namespace INDI
47 {
48 
50 {
51  //ctor
52  capability = 0;
53 
54  InIntegration = false;
55 
56  AutoLoop = false;
57  SendIntegration = false;
58  ShowMarker = false;
59 
60  IntegrationTime = 0.0;
61 
62  RA = -1000;
63  Dec = -1000;
64  MPSAS = -1000;
65  Latitude = -1000;
66  Longitude = -1000;
67  Elevation = -1000;
69 
70  Buffer = static_cast<uint8_t *>(malloc(sizeof(uint8_t))); // Seed for realloc
71  BufferSize = 0;
72  NAxis = 2;
73 
74  BPS = 8;
75 
76  strncpy(integrationExtention, "raw", MAXINDIBLOBFMT);
77 }
78 
80 {
81  free(Buffer);
82  BufferSize = 0;
83  Buffer = nullptr;
84 }
85 
86 
88 {
89  //IDLog("Sensor UpdateProperties isConnected returns %d %d\n",isConnected(),Connected);
90  if (isConnected())
91  {
93 
94  if (CanAbort())
96 
98 
99  if (HasCooler())
101 
103 
105 
107 
108  if (UploadSettingsT[UPLOAD_DIR].text == nullptr)
109  IUSaveText(&UploadSettingsT[UPLOAD_DIR], getenv("HOME"));
111  }
112  else
113  {
115  if (CanAbort())
118 
120 
121  if (HasCooler())
123 
125 
128  }
129 
130  if (HasStreaming())
131  Streamer->updateProperties();
132 
133  if (HasDSP())
134  DSP->updateProperties();
135  return true;
136 }
137 
138 void SensorInterface::processProperties(const char *dev)
139 {
141 
143  loadConfig(true, "ACTIVE_DEVICES");
144 
145  if (HasStreaming())
146  Streamer->ISGetProperties(dev);
147 
148  if (HasDSP())
149  DSP->ISGetProperties(dev);
150 }
151 
153 {
154  if (!IUSnoopNumber(root, &EqNP))
155  {
156  RA = EqNP.np[0].value;
157  Dec = EqNP.np[1].value;
158  //IDLog("Snooped RA %4.2f Dec %4.2f\n", RA, Dec);
159  }
160  if (!IUSnoopNumber(root, &LocationNP))
161  {
162  Latitude = LocationNP.np[0].value;
163  Longitude = LocationNP.np[1].value;
164  Elevation = LocationNP.np[2].value;
165  //IDLog("Snooped Latitude %4.2f Longitude %4.2f Elevation %4.2f\n", RA, Dec, Elevation);
166  }
167  if (!IUSnoopNumber(root, &ScopeParametersNP))
168  {
171  //IDLog("Snooped primaryAperture %4.2f primaryFocalLength %4.2f\n", primaryAperture, primaryFocalLength);
172  }
173 
175 }
176 
177 bool SensorInterface::processText(const char *dev, const char *name, char *texts[], char *names[], int n)
178 {
179  // first check if it's for our device
180  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
181  {
182  // This is for our device
183  // Now lets see if it's something we process here
184  if (!strcmp(name, ActiveDeviceTP.name))
185  {
187  IUUpdateText(&ActiveDeviceTP, texts, names, n);
188  IDSetText(&ActiveDeviceTP, nullptr);
189 
190  // Update the property name!
191  strncpy(EqNP.device, ActiveDeviceT[0].text, MAXINDIDEVICE);
192  strncpy(LocationNP.device, ActiveDeviceT[0].text, MAXINDIDEVICE);
194 
195  IDSnoopDevice(ActiveDeviceT[0].text, "EQUATORIAL_EOD_COORD");
196  IDSnoopDevice(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
197  IDSnoopDevice(ActiveDeviceT[0].text, "TELESCOPE_INFO");
198  IDSnoopDevice(ActiveDeviceT[1].text, "GEOGRAPHIC_COORD");
199 
200  // Tell children active devices was updated.
202 
203  // We processed this one, so, tell the world we did it
204  return true;
205  }
206 
207  if (!strcmp(name, FITSHeaderTP.name))
208  {
209  IUUpdateText(&FITSHeaderTP, texts, names, n);
211  IDSetText(&FITSHeaderTP, nullptr);
212  return true;
213  }
214 
215  if (!strcmp(name, UploadSettingsTP.name))
216  {
217  IUUpdateText(&UploadSettingsTP, texts, names, n);
219  IDSetText(&UploadSettingsTP, nullptr);
220  return true;
221  }
222  }
223 
224  if (HasStreaming())
225  Streamer->ISNewText(dev, name, texts, names, n);
226 
227  if (HasDSP())
228  DSP->ISNewText(dev, name, texts, names, n);
229 
230  return INDI::DefaultDevice::ISNewText(dev, name, texts, names, n);
231 }
232 
233 bool SensorInterface::processNumber(const char *dev, const char *name, double values[], char *names[], int n)
234 {
235  // first check if it's for our device
236  //IDLog("SensorInterface::processNumber %s\n",name);
237  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
238  {
239  if (!strcmp(name, "SENSOR_INTEGRATION"))
240  {
241  if ((values[0] < FramedIntegrationN[0].min || values[0] > FramedIntegrationN[0].max))
242  {
243  DEBUGF(Logger::DBG_ERROR, "Requested integration value (%g) seconds out of bounds [%g,%g].",
244  values[0], FramedIntegrationN[0].min, FramedIntegrationN[0].max);
246  IDSetNumber(&FramedIntegrationNP, nullptr);
247  return false;
248  }
249 
250  FramedIntegrationN[0].value = IntegrationTime = values[0];
251 
253  {
254  if (CanAbort() && AbortIntegration() == false)
255  DEBUG(Logger::DBG_WARNING, "Warning: Aborting integration failed.");
256  }
257 
260  else
262  IDSetNumber(&FramedIntegrationNP, nullptr);
263  return true;
264  }
265 
266  // Sensor TEMPERATURE:
267  if (!strcmp(name, TemperatureNP.name))
268  {
269  if (values[0] < TemperatureN[0].min || values[0] > TemperatureN[0].max)
270  {
272  DEBUGF(Logger::DBG_ERROR, "Error: Bad temperature value! Range is [%.1f, %.1f] [C].",
274  IDSetNumber(&TemperatureNP, nullptr);
275  return false;
276  }
277 
278  int rc = SetTemperature(values[0]);
279 
280  if (rc == 0)
282  else if (rc == 1)
284  else
286 
287  IDSetNumber(&TemperatureNP, nullptr);
288  return true;
289  }
290  }
291 
292  if (HasStreaming())
293  Streamer->ISNewNumber(dev, name, values, names, n);
294 
295  if (HasDSP())
296  DSP->ISNewNumber(dev, name, values, names, n);
297 
298  return INDI::DefaultDevice::ISNewNumber(dev, name, values, names, n);
299 }
300 
301 bool SensorInterface::processSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
302 {
303  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
304  {
305  if (!strcmp(name, UploadSP.name))
306  {
307  int prevMode = IUFindOnSwitchIndex(&UploadSP);
308  IUUpdateSwitch(&UploadSP, states, names, n);
309  UploadSP.s = IPS_OK;
310  IDSetSwitch(&UploadSP, nullptr);
311 
312  if (UploadS[0].s == ISS_ON)
313  {
314  DEBUG(Logger::DBG_SESSION, "Upload settings set to client only.");
315  if (prevMode != 0)
317  }
318  else if (UploadS[1].s == ISS_ON)
319  {
320  DEBUG(Logger::DBG_SESSION, "Upload settings set to local only.");
322  }
323  else
324  {
325  DEBUG(Logger::DBG_SESSION, "Upload settings set to client and local.");
327  }
328  return true;
329  }
330 
331  if (!strcmp(name, TelescopeTypeSP.name))
332  {
333  IUUpdateSwitch(&TelescopeTypeSP, states, names, n);
335  IDSetSwitch(&TelescopeTypeSP, nullptr);
336  return true;
337  }
338 
339  // Primary Device Abort Expsoure
340  if (strcmp(name, AbortIntegrationSP.name) == 0)
341  {
343 
344  if (AbortIntegration())
345  {
348  FramedIntegrationN[0].value = 0;
349  }
350  else
351  {
354  }
355 
356  IDSetSwitch(&AbortIntegrationSP, nullptr);
357  IDSetNumber(&FramedIntegrationNP, nullptr);
358 
359  return true;
360  }
361  }
362 
363  if (HasStreaming())
364  Streamer->ISNewSwitch(dev, name, states, names, n);
365 
366  if (HasDSP())
367  DSP->ISNewSwitch(dev, name, states, names, n);
368 
369  return INDI::DefaultDevice::ISNewSwitch(dev, name, states, names, n);
370 }
371 
372 bool SensorInterface::processBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[],
373  char *formats[], char *names[], int n)
374 {
375  if (HasDSP())
376  DSP->ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
377 
378  return INDI::DefaultDevice::ISNewBLOB(dev, name, sizes, blobsizes, blobs, formats, names, n);
379 }
380 
382 {
383  INDI::DefaultDevice::initProperties(); // let the base class flesh in what it wants
384 
385  // Sensor Temperature
386  IUFillNumber(&TemperatureN[0], "SENSOR_TEMPERATURE_VALUE", "Temperature (C)", "%5.2f", -50.0, 50.0, 0., 0.);
387  IUFillNumberVector(&TemperatureNP, TemperatureN, 1, getDeviceName(), "SENSOR_TEMPERATURE", "Temperature",
389 
390  /**********************************************/
391  /**************** Primary Device ****************/
392  /**********************************************/
393 
394  // Sensor Integration
395  IUFillNumber(&FramedIntegrationN[0], "SENSOR_INTEGRATION_VALUE", "Time (s)", "%5.2f", 0.01, 3600, 1.0, 1.0);
397  "Integration", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE);
398 
399  // Sensor Abort
400  if(CanAbort())
401  {
402  IUFillSwitch(&AbortIntegrationS[0], "ABORT", "Abort", ISS_OFF);
403  IUFillSwitchVector(&AbortIntegrationSP, AbortIntegrationS, 1, getDeviceName(), "SENSOR_ABORT_INTEGRATION",
404  "Integration Abort", MAIN_CONTROL_TAB, IP_RW, ISR_ATMOST1, 60, IPS_IDLE);
405  }
406 
407 
408  /**********************************************/
409  /************** Upload Settings ***************/
410  /**********************************************/
411  // Upload Data
412  IUFillBLOB(&FitsB, "DATA", "Sensor Data Blob", "");
413 
414  IUFillBLOBVector(&FitsBP, &FitsB, 1, getDeviceName(), "SENSOR", "Integration Data", MAIN_CONTROL_TAB,
415  IP_RO, 60, IPS_IDLE);
416 
417  // Upload Mode
418  IUFillSwitch(&UploadS[0], "UPLOAD_CLIENT", "Client", ISS_ON);
419  IUFillSwitch(&UploadS[1], "UPLOAD_LOCAL", "Local", ISS_OFF);
420  IUFillSwitch(&UploadS[2], "UPLOAD_BOTH", "Both", ISS_OFF);
421  IUFillSwitchVector(&UploadSP, UploadS, 3, getDeviceName(), "UPLOAD_MODE", "Upload", OPTIONS_TAB, IP_RW, ISR_1OFMANY,
422  0, IPS_IDLE);
423 
424  // Upload Settings
425  IUFillText(&UploadSettingsT[UPLOAD_DIR], "UPLOAD_DIR", "Dir", "");
426  IUFillText(&UploadSettingsT[UPLOAD_PREFIX], "UPLOAD_PREFIX", "Prefix", "INTEGRATION_XXX");
427  IUFillTextVector(&UploadSettingsTP, UploadSettingsT, 2, getDeviceName(), "UPLOAD_SETTINGS", "Upload Settings",
428  OPTIONS_TAB, IP_RW, 60, IPS_IDLE);
429 
430  // Upload File Path
431  IUFillText(&FileNameT[0], "FILE_PATH", "Path", "");
432  IUFillTextVector(&FileNameTP, FileNameT, 1, getDeviceName(), "SENSOR_FILE_PATH", "Filename", OPTIONS_TAB, IP_RO, 60,
433  IPS_IDLE);
434 
435  /**********************************************/
436  /****************** FITS Header****************/
437  /**********************************************/
438 
439  IUFillText(&FITSHeaderT[FITS_OBSERVER], "FITS_OBSERVER", "Observer", "Unknown");
440  IUFillText(&FITSHeaderT[FITS_OBJECT], "FITS_OBJECT", "Object", "Unknown");
441  IUFillTextVector(&FITSHeaderTP, FITSHeaderT, 2, getDeviceName(), "FITS_HEADER", "FITS Header", INFO_TAB, IP_RW, 60,
442  IPS_IDLE);
443 
444  /**********************************************/
445  /**************** Snooping ********************/
446  /**********************************************/
447 
448  // Snooped Devices
449  IUFillText(&ActiveDeviceT[0], "ACTIVE_TELESCOPE", "Telescope", "Telescope Simulator");
450  IUFillText(&ActiveDeviceT[1], "ACTIVE_GPS", "GPS", "GPS Simulator");
451  IUFillTextVector(&ActiveDeviceTP, ActiveDeviceT, 2, getDeviceName(), "ACTIVE_DEVICES", "Snoop devices", OPTIONS_TAB,
452  IP_RW, 60, IPS_IDLE);
453 
454  // Snoop properties of interest
455  IUFillNumber(&EqN[0], "RA", "RA (hh:mm:ss)", "%010.6m", 0, 24, 0, 0);
456  IUFillNumber(&EqN[1], "DEC", "DEC (dd:mm:ss)", "%010.6m", -90, 90, 0, 0);
457  IUFillNumberVector(&EqNP, EqN, 2, getDeviceName(), "EQUATORIAL_EOD_COORD", "Eq. Coordinates", MAIN_CONTROL_TAB,
458  IP_RW, 60, IPS_IDLE);
459 
460  IUFillNumber(&LocationN[0], "LAT", "Latitude (dd:mm:ss)", "%010.6m", -90, 90, 0, 0.0);
461  IUFillNumber(&LocationN[1], "LONG", "Longitude (dd:mm:ss)", "%010.6m", 0, 360, 0, 0.0);
462  IUFillNumber(&LocationN[2], "ELEV", "Elevation (m)", "%g", -200, 10000, 0, 0);
463  IUFillNumberVector(&LocationNP, LocationN, 3, getDeviceName(), "GEOGRAPHIC_COORD", "Location", MAIN_CONTROL_TAB,
464  IP_RO, 60, IPS_IDLE);
465 
466  IUFillNumber(&ScopeParametersN[0], "TELESCOPE_APERTURE", "Aperture (mm)", "%g", 10, 5000, 0, 0.0);
467  IUFillNumber(&ScopeParametersN[1], "TELESCOPE_FOCAL_LENGTH", "Focal Length (mm)", "%g", 10, 10000, 0, 0.0);
468  IUFillNumber(&ScopeParametersN[2], "GUIDER_APERTURE", "Guider Aperture (mm)", "%g", 10, 5000, 0, 0.0);
469  IUFillNumber(&ScopeParametersN[3], "GUIDER_FOCAL_LENGTH", "Guider Focal Length (mm)", "%g", 10, 10000, 0, 0.0);
470  IUFillNumberVector(&ScopeParametersNP, ScopeParametersN, 4, getDeviceName(), "TELESCOPE_INFO", "Scope Properties",
471  OPTIONS_TAB, IP_RW, 60, IPS_OK);
472 
473  IDSnoopDevice(ActiveDeviceT[0].text, "EQUATORIAL_EOD_COORD");
474  IDSnoopDevice(ActiveDeviceT[0].text, "GEOGRAPHIC_COORD");
475  IDSnoopDevice(ActiveDeviceT[0].text, "TELESCOPE_INFO");
476  IDSnoopDevice(ActiveDeviceT[1].text, "GEOGRAPHIC_COORD");
477 
478  if (sensorConnection & CONNECTION_SERIAL)
479  {
482  {
483  return callHandshake();
484  });
486  }
487 
488  if (sensorConnection & CONNECTION_TCP)
489  {
490  tcpConnection = new Connection::TCP(this);
492  {
493  return callHandshake();
494  });
495 
497  }
498 
499  return true;
500 }
501 
502 void SensorInterface::SetCapability(uint32_t cap)
503 {
504  capability = cap;
505 
507 
508  HasStreaming();
509  HasDSP();
510 }
511 
512 void SensorInterface::setMinMaxStep(const char *property, const char *element, double min, double max, double step,
513  bool sendToClient)
514 {
515  INumberVectorProperty *vp = nullptr;
516 
517  if (!strcmp(property, FramedIntegrationNP.name))
518  {
520 
521  INumber *np = IUFindNumber(vp, element);
522  if (np)
523  {
524  np->min = min;
525  np->max = max;
526  np->step = step;
527 
528  if (sendToClient)
530  }
531  }
532 }
533 
534 void SensorInterface::setBufferSize(int nbuf, bool allocMem)
535 {
536  if (nbuf == BufferSize)
537  return;
538 
539  BufferSize = nbuf;
540 
541  // Reset size
542  if (HasStreaming())
543  Streamer->setSize(BufferSize * 8 / getBPS());
544 
545  // DSP
546  if (HasDSP())
547  DSP->setSizes(1, new int[1] { BufferSize * 8 / getBPS() });
548 
549  if (allocMem == false)
550  return;
551 
552  Buffer = static_cast<uint8_t *>(realloc(Buffer, nbuf * sizeof(uint8_t)));
553 }
554 
555 bool SensorInterface::StartIntegration(double duration)
556 {
557  INDI_UNUSED(duration);
558  DEBUGF(Logger::DBG_WARNING, "SensorInterface::StartIntegration %4.2f - Should never get here", duration);
559  return false;
560 }
561 
562 void SensorInterface::setIntegrationLeft(double duration)
563 {
564  FramedIntegrationN[0].value = duration;
565 
566  IDSetNumber(&FramedIntegrationNP, nullptr);
567 }
568 
569 void SensorInterface::setIntegrationTime(double duration)
570 {
571  integrationTime = duration;
572  // JM 2020-04-28: FIXME
573  // This does not compile on MacOS, so commenting now.
574  // IP 2020-04-29: trying with some adaptation
575  startIntegrationTime = time_ns();
576 }
577 
579 {
580  static char ts[32];
581 
582  char iso8601[32];
583  struct tm *tp;
584  time_t t = (time_t)startIntegrationTime;
585 
586  tp = gmtime(&t);
587  strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%S", tp);
588  return (ts);
589 }
590 
592 {
594  IDSetNumber(&FramedIntegrationNP, nullptr);
595 }
596 
597 int SensorInterface::getNAxis() const
598 {
599  return NAxis;
600 }
601 
602 void SensorInterface::setNAxis(int value)
603 {
604  NAxis = value;
605 }
606 
608 {
609  strncpy(integrationExtention, ext, MAXINDIBLOBFMT);
610 }
611 
612 
614 {
615  DEBUG(Logger::DBG_WARNING, "SensorInterface::AbortIntegration - Should never get here");
616  return false;
617 }
618 
619 void SensorInterface::addFITSKeywords(fitsfile *fptr, uint8_t* buf, int len)
620 {
621 #ifndef WITH_MINMAX
622  INDI_UNUSED(buf);
623  INDI_UNUSED(len);
624 #endif
625  int status = 0;
626  char dev_name[32];
627  char exp_start[32];
628  char timestamp[32];
629  double integrationTime;
630 
631  char *orig = setlocale(LC_NUMERIC, "C");
632 
633  char fitsString[MAXINDIDEVICE];
634 
635  // SENSOR
636  strncpy(fitsString, getDeviceName(), MAXINDIDEVICE);
637  fits_update_key_s(fptr, TSTRING, "INSTRUME", fitsString, "Sensor Name", &status);
638 
639  // Telescope
640  strncpy(fitsString, ActiveDeviceT[0].text, MAXINDIDEVICE);
641  fits_update_key_s(fptr, TSTRING, "TELESCOP", fitsString, "Telescope name", &status);
642 
643  // Observer
644  strncpy(fitsString, FITSHeaderT[FITS_OBSERVER].text, MAXINDIDEVICE);
645  fits_update_key_s(fptr, TSTRING, "OBSERVER", fitsString, "Observer name", &status);
646 
647  // Object
648  strncpy(fitsString, FITSHeaderT[FITS_OBJECT].text, MAXINDIDEVICE);
649  fits_update_key_s(fptr, TSTRING, "OBJECT", fitsString, "Object name", &status);
650 
651  integrationTime = getIntegrationTime();
652 
653  strncpy(dev_name, getDeviceName(), 32);
654  strncpy(exp_start, getIntegrationStartTime(), 32);
655  snprintf(timestamp, 32, "%lf", startIntegrationTime);
656 
657  fits_update_key_s(fptr, TDOUBLE, "EXPTIME", &(integrationTime), "Total Integration Time (s)", &status);
658 
659  if (HasCooler())
660  fits_update_key_s(fptr, TDOUBLE, "SENSOR-TEMP", &(TemperatureN[0].value), "PrimarySensorInterface Temperature (Celsius)",
661  &status);
662 
663 #ifdef WITH_MINMAX
664  if (getNAxis() == 2)
665  {
666  double min_val, max_val;
667  getMinMax(&min_val, &max_val, buf, len, getBPS());
668 
669  fits_update_key_s(fptr, TDOUBLE, "DATAMIN", &min_val, "Minimum value", &status);
670  fits_update_key_s(fptr, TDOUBLE, "DATAMAX", &max_val, "Maximum value", &status);
671  }
672 #endif
673 
674  if (primaryFocalLength != -1)
675  fits_update_key_s(fptr, TDOUBLE, "FOCALLEN", &primaryFocalLength, "Focal Length (mm)", &status);
676 
677  if (MPSAS != -1000)
678  {
679  fits_update_key_s(fptr, TDOUBLE, "MPSAS", &MPSAS, "Sky Quality (mag per arcsec^2)", &status);
680  }
681 
682  if (Latitude != -1000 && Longitude != -1000 && Elevation != -1000)
683  {
684  char lat_str[MAXINDIFORMAT];
685  char lon_str[MAXINDIFORMAT];
686  char el_str[MAXINDIFORMAT];
687  fs_sexa(lat_str, Latitude, 2, 360000);
688  fs_sexa(lat_str, Longitude, 2, 360000);
689  snprintf(el_str, MAXINDIFORMAT, "%lf", Elevation);
690  fits_update_key_s(fptr, TSTRING, "SITELAT", lat_str, "Location Latitude", &status);
691  fits_update_key_s(fptr, TSTRING, "SITELONG", lon_str, "Location Longitude", &status);
692  fits_update_key_s(fptr, TSTRING, "SITEELEV", el_str, "Location Elevation", &status);
693  }
694  if (RA != -1000 && Dec != -1000)
695  {
696  INDI::IEquatorialCoordinates epochPos { 0, 0 }, J2000Pos { 0, 0 };
697  epochPos.rightascension = RA;
698  epochPos.declination = Dec;
699 
700  // Convert from JNow to J2000
701  //TODO use exp_start instead of julian from system
702  INDI::ObservedToJ2000(&epochPos, ln_get_julian_from_sys(), &J2000Pos);
703 
704  double raJ2000 = J2000Pos.rightascension;
705  double decJ2000 = J2000Pos.declination;
706  char ra_str[32], de_str[32];
707 
708  fs_sexa(ra_str, raJ2000, 2, 360000);
709  fs_sexa(de_str, decJ2000, 2, 360000);
710 
711  char *raPtr = ra_str, *dePtr = de_str;
712  while (*raPtr != '\0')
713  {
714  if (*raPtr == ':')
715  *raPtr = ' ';
716  raPtr++;
717  }
718  while (*dePtr != '\0')
719  {
720  if (*dePtr == ':')
721  *dePtr = ' ';
722  dePtr++;
723  }
724 
725  fits_update_key_s(fptr, TSTRING, "OBJCTRA", ra_str, "Object RA", &status);
726  fits_update_key_s(fptr, TSTRING, "OBJCTDEC", de_str, "Object DEC", &status);
727 
728  int epoch = 2000;
729 
730  //fits_update_key_s(fptr, TINT, "EPOCH", &epoch, "Epoch", &status);
731  fits_update_key_s(fptr, TINT, "EQUINOX", &epoch, "Equinox", &status);
732  }
733 
734  fits_update_key_s(fptr, TSTRING, "EPOCH", timestamp, "Unix Epoch of start of integration", &status);
735 
736  fits_update_key_s(fptr, TSTRING, "DATE-OBS", exp_start, "UTC start date of observation", &status);
737 
738  fits_write_comment(fptr, "Generated by INDI", &status);
739 
740  setlocale(LC_NUMERIC, orig);
741 }
742 
743 void SensorInterface::fits_update_key_s(fitsfile *fptr, int type, std::string name, void *p, std::string explanation,
744  int *status)
745 {
746  // this function is for removing warnings about deprecated string conversion to char* (from arg 5)
747  fits_update_key(fptr, type, name.c_str(), p, const_cast<char *>(explanation.c_str()), status);
748 }
749 
750 void* SensorInterface::sendFITS(uint8_t *buf, int len)
751 {
752  bool sendIntegration = (UploadS[0].s == ISS_ON || UploadS[2].s == ISS_ON);
753  bool saveIntegration = (UploadS[1].s == ISS_ON || UploadS[2].s == ISS_ON);
754  fitsfile *fptr = nullptr;
755  void *memptr;
756  size_t memsize;
757  int img_type = 0;
758  int byte_type = 0;
759  int status = 0;
760  long naxis = 2;
761  long naxes[2] = {0};
762  int nelements = 0;
763  std::string bit_depth;
764  char error_status[MAXRBUF];
765  switch (getBPS())
766  {
767  case 8:
768  byte_type = TBYTE;
769  img_type = BYTE_IMG;
770  bit_depth = "8 bits per sample";
771  break;
772 
773  case 16:
774  byte_type = TUSHORT;
775  img_type = USHORT_IMG;
776  bit_depth = "16 bits per sample";
777  break;
778 
779  case 32:
780  byte_type = TLONG;
781  img_type = LONG_IMG;
782  bit_depth = "32 bits per sample";
783  break;
784 
785  case 64:
786  byte_type = TLONGLONG;
787  img_type = LONGLONG_IMG;
788  bit_depth = "64 bits double per sample";
789  break;
790 
791  case -32:
792  byte_type = TFLOAT;
793  img_type = FLOAT_IMG;
794  bit_depth = "32 bits double per sample";
795  break;
796 
797  case -64:
798  byte_type = TDOUBLE;
799  img_type = DOUBLE_IMG;
800  bit_depth = "64 bits double per sample";
801  break;
802 
803  default:
804  DEBUGF(Logger::DBG_ERROR, "Unsupported bits per sample value %d", getBPS());
805  return nullptr;
806  }
807  naxes[0] = len;
808  naxes[0] = naxes[0] < 1 ? 1 : naxes[0];
809  naxes[1] = 1;
810  nelements = naxes[0];
811 
812  /*DEBUGF(Logger::DBG_DEBUG, "Exposure complete. Image Depth: %s. Width: %d Height: %d nelements: %d", bit_depth.c_str(), naxes[0],
813  naxes[1], nelements);*/
814 
815  // Now we have to send fits format data to the client
816  memsize = 5760;
817  memptr = malloc(memsize);
818  if (!memptr)
819  {
820  DEBUGF(Logger::DBG_ERROR, "Error: failed to allocate memory: %lu", static_cast<unsigned long>(memsize));
821  }
822 
823  fits_create_memfile(&fptr, &memptr, &memsize, 2880, realloc, &status);
824 
825  if (status)
826  {
827  fits_report_error(stderr, status); /* print out any error messages */
828  fits_get_errstatus(status, error_status);
829  DEBUGF(Logger::DBG_ERROR, "FITS Error: %s", error_status);
830  if(memptr != nullptr)
831  free(memptr);
832  return nullptr;
833  }
834 
835  fits_create_img(fptr, img_type, naxis, naxes, &status);
836 
837  if (status)
838  {
839  fits_report_error(stderr, status); /* print out any error messages */
840  fits_get_errstatus(status, error_status);
841  DEBUGF(Logger::DBG_ERROR, "FITS Error: %s", error_status);
842  if(memptr != nullptr)
843  free(memptr);
844  return nullptr;
845  }
846 
847  addFITSKeywords(fptr, buf, len);
848 
849  fits_write_img(fptr, byte_type, 1, nelements, buf, &status);
850 
851  if (status)
852  {
853  fits_report_error(stderr, status); /* print out any error messages */
854  fits_get_errstatus(status, error_status);
855  DEBUGF(Logger::DBG_ERROR, "FITS Error: %s", error_status);
856  if(memptr != nullptr)
857  free(memptr);
858  return nullptr;
859  }
860 
861  fits_close_file(fptr, &status);
862 
863  uploadFile(memptr, memsize, sendIntegration, saveIntegration);
864 
865  return memptr;
866 }
867 
869 {
870  // Reset POLLMS to default value
872 
873  if(HasDSP())
874  {
875  uint8_t* buf = (uint8_t*)malloc(getBufferSize());
876  memcpy(buf, getBuffer(), getBufferSize());
877  DSP->processBLOB(buf, 1, new int[1] { getBufferSize() * 8 / getBPS() }, getBPS());
878  free(buf);
879  }
880  // Run async
881  std::thread(&SensorInterface::IntegrationCompletePrivate, this).detach();
882 
883  return true;
884 }
885 
886 bool SensorInterface::IntegrationCompletePrivate()
887 {
888  bool sendIntegration = (UploadS[0].s == ISS_ON || UploadS[2].s == ISS_ON);
889  bool saveIntegration = (UploadS[1].s == ISS_ON || UploadS[2].s == ISS_ON);
890  bool autoLoop = false;
891 
892  if (sendIntegration || saveIntegration)
893  {
894  void* blob = nullptr;
895  if (!strcmp(getIntegrationFileExtension(), "fits"))
896  {
897  blob = sendFITS(getBuffer(), getBufferSize() * 8 / abs(getBPS()));
898  }
899  else
900  {
901  uploadFile(getBuffer(), getBufferSize(), sendIntegration,
902  saveIntegration);
903  }
904 
905  if (sendIntegration)
906  IDSetBLOB(&FitsBP, nullptr);
907  if(blob != nullptr)
908  free(blob);
909 
910  DEBUG(Logger::DBG_DEBUG, "Upload complete");
911  }
912 
914  IDSetNumber(&FramedIntegrationNP, nullptr);
915 
916  if (autoLoop)
917  {
920 
923  else
924  {
925  DEBUG(Logger::DBG_DEBUG, "Autoloop: Sensor Integration Error!");
927  }
928 
929  IDSetNumber(&FramedIntegrationNP, nullptr);
930  }
931 
932  return true;
933 }
934 
935 bool SensorInterface::uploadFile(const void *fitsData, size_t totalBytes, bool sendIntegration,
936  bool saveIntegration)
937 {
938 
939  DEBUGF(Logger::DBG_DEBUG, "Uploading file. Ext: %s, Size: %d, sendIntegration? %s, saveIntegration? %s",
940  getIntegrationFileExtension(), totalBytes, sendIntegration ? "Yes" : "No", saveIntegration ? "Yes" : "No");
941 
942  FitsB.blob = const_cast<void *>(fitsData);
943  FitsB.bloblen = totalBytes;
944  snprintf(FitsB.format, MAXINDIBLOBFMT, ".%s", getIntegrationFileExtension());
945  if (saveIntegration)
946  {
947 
948  FILE *fp = nullptr;
949  char integrationFileName[MAXRBUF];
950 
951  std::string prefix = UploadSettingsT[UPLOAD_PREFIX].text;
952  int maxIndex = getFileIndex(UploadSettingsT[UPLOAD_DIR].text, UploadSettingsT[UPLOAD_PREFIX].text,
953  FitsB.format);
954 
955  if (maxIndex < 0)
956  {
957  DEBUGF(Logger::DBG_ERROR, "Error iterating directory %s. %s", UploadSettingsT[0].text,
958  strerror(errno));
959  return false;
960  }
961 
962  if (maxIndex > 0)
963  {
964  char ts[32];
965  struct tm *tp;
966  time_t t;
967  time(&t);
968  tp = localtime(&t);
969  strftime(ts, sizeof(ts), "%Y-%m-%dT%H-%M-%S", tp);
970  std::string filets(ts);
971  prefix = std::regex_replace(prefix, std::regex("ISO8601"), filets);
972 
973  char indexString[8];
974  snprintf(indexString, 8, "%03d", maxIndex);
975  std::string prefixIndex = indexString;
976  //prefix.replace(prefix.find("XXX"), std::string::npos, prefixIndex);
977  prefix = std::regex_replace(prefix, std::regex("XXX"), prefixIndex);
978  }
979 
980  snprintf(integrationFileName, MAXRBUF, "%s/%s%s", UploadSettingsT[0].text, prefix.c_str(), FitsB.format);
981 
982  fp = fopen(integrationFileName, "w");
983  if (fp == nullptr)
984  {
985  DEBUGF(Logger::DBG_ERROR, "Unable to save image file (%s). %s", integrationFileName, strerror(errno));
986  return false;
987  }
988 
989  int n = 0;
990  for (int nr = 0; nr < static_cast<int>(FitsB.bloblen); nr += n)
991  n = fwrite((static_cast<char *>(FitsB.blob) + nr), 1, FitsB.bloblen - nr, fp);
992 
993  fclose(fp);
994 
995  // Save image file path
996  IUSaveText(&FileNameT[0], integrationFileName);
997 
998  DEBUGF(Logger::DBG_SESSION, "Image saved to %s", integrationFileName);
999  FileNameTP.s = IPS_OK;
1000  IDSetText(&FileNameTP, nullptr);
1001  }
1002 
1003  FitsB.size = totalBytes;
1004  FitsBP.s = IPS_OK;
1005 
1006  DEBUG(Logger::DBG_DEBUG, "Upload complete");
1007 
1008  return true;
1009 }
1010 
1012 {
1013  LOG_ERROR("Streaming is not supported.");
1014  return false;
1015 }
1016 
1018 {
1019  LOG_ERROR("Streaming is not supported.");
1020  return false;
1021 }
1022 
1023 int SensorInterface::SetTemperature(double temperature)
1024 {
1025  INDI_UNUSED(temperature);
1026  DEBUGF(Logger::DBG_WARNING, "SensorInterface::SetTemperature %4.2f - Should never get here", temperature);
1027  return -1;
1029 
1030 bool SensorInterface::saveConfigItems(FILE *fp)
1031 {
1033 
1038 
1039  if (HasStreaming())
1040  Streamer->saveConfigItems(fp);
1041 
1042  if (HasDSP())
1043  DSP->saveConfigItems(fp);
1044 
1045  return true;
1046 }
1048 void SensorInterface::getMinMax(double *min, double *max, uint8_t *buf, int len, int bpp)
1049 {
1050  int ind = 0, i, j;
1051  int integrationHeight = 1;
1052  int integrationWidth = len;
1053  double lmin = 0, lmax = 0;
1054 
1055  switch (bpp)
1056  {
1057  case 8:
1058  {
1059  uint8_t *integrationBuffer = static_cast<uint8_t *>(buf);
1060  lmin = lmax = integrationBuffer[0];
1061 
1062  for (i = 0; i < integrationHeight; i++)
1063  for (j = 0; j < integrationWidth; j++)
1064  {
1065  ind = (i * integrationWidth) + j;
1066  if (integrationBuffer[ind] < lmin)
1067  lmin = integrationBuffer[ind];
1068  else if (integrationBuffer[ind] > lmax)
1069  lmax = integrationBuffer[ind];
1070  }
1071  }
1072  break;
1073 
1074  case 16:
1075  {
1076  uint16_t *integrationBuffer = reinterpret_cast<uint16_t *>(buf);
1077  lmin = lmax = integrationBuffer[0];
1078 
1079  for (i = 0; i < integrationHeight; i++)
1080  for (j = 0; j < integrationWidth; j++)
1081  {
1082  ind = (i * integrationWidth) + j;
1083  if (integrationBuffer[ind] < lmin)
1084  lmin = integrationBuffer[ind];
1085  else if (integrationBuffer[ind] > lmax)
1086  lmax = integrationBuffer[ind];
1087  }
1088  }
1089  break;
1090 
1091  case 32:
1092  {
1093  uint32_t *integrationBuffer = reinterpret_cast<uint32_t *>(buf);
1094  lmin = lmax = integrationBuffer[0];
1095 
1096  for (i = 0; i < integrationHeight; i++)
1097  for (j = 0; j < integrationWidth; j++)
1098  {
1099  ind = (i * integrationWidth) + j;
1100  if (integrationBuffer[ind] < lmin)
1101  lmin = integrationBuffer[ind];
1102  else if (integrationBuffer[ind] > lmax)
1103  lmax = integrationBuffer[ind];
1104  }
1105  }
1106  break;
1107 
1108  case 64:
1109  {
1110  unsigned long *integrationBuffer = reinterpret_cast<unsigned long *>(buf);
1111  lmin = lmax = integrationBuffer[0];
1112 
1113  for (i = 0; i < integrationHeight; i++)
1114  for (j = 0; j < integrationWidth; j++)
1115  {
1116  ind = (i * integrationWidth) + j;
1117  if (integrationBuffer[ind] < lmin)
1118  lmin = integrationBuffer[ind];
1119  else if (integrationBuffer[ind] > lmax)
1120  lmax = integrationBuffer[ind];
1121  }
1122  }
1123  break;
1124 
1125  case -32:
1126  {
1127  double *integrationBuffer = reinterpret_cast<double *>(buf);
1128  lmin = lmax = integrationBuffer[0];
1129 
1130  for (i = 0; i < integrationHeight; i++)
1131  for (j = 0; j < integrationWidth; j++)
1132  {
1133  ind = (i * integrationWidth) + j;
1134  if (integrationBuffer[ind] < lmin)
1135  lmin = integrationBuffer[ind];
1136  else if (integrationBuffer[ind] > lmax)
1137  lmax = integrationBuffer[ind];
1138  }
1139  }
1140  break;
1141 
1142  case -64:
1143  {
1144  double *integrationBuffer = reinterpret_cast<double *>(buf);
1145  lmin = lmax = integrationBuffer[0];
1146 
1147  for (i = 0; i < integrationHeight; i++)
1148  for (j = 0; j < integrationWidth; j++)
1149  {
1150  ind = (i * integrationWidth) + j;
1151  if (integrationBuffer[ind] < lmin)
1152  lmin = integrationBuffer[ind];
1153  else if (integrationBuffer[ind] > lmax)
1154  lmax = integrationBuffer[ind];
1155  }
1156  }
1157  break;
1158  }
1159  *min = lmin;
1160  *max = lmax;
1161 }
1162 
1163 std::string regex_replace_compat2(const std::string &input, const std::string &pattern, const std::string &replace)
1164 {
1165  std::stringstream s;
1166  std::regex_replace(std::ostreambuf_iterator<char>(s), input.begin(), input.end(), std::regex(pattern), replace);
1167  return s.str();
1168 }
1169 
1170 int SensorInterface::getFileIndex(const char *dir, const char *prefix, const char *ext)
1171 {
1172  INDI_UNUSED(ext);
1173 
1174  DIR *dpdf = nullptr;
1175  struct dirent *epdf = nullptr;
1176  std::vector<std::string> files = std::vector<std::string>();
1177 
1178  std::string prefixIndex = prefix;
1179  prefixIndex = regex_replace_compat2(prefixIndex, "_ISO8601", "");
1180  prefixIndex = regex_replace_compat2(prefixIndex, "_XXX", "");
1181 
1182  // Create directory if does not exist
1183  struct stat st;
1184 
1185  if (stat(dir, &st) == -1)
1186  {
1187  LOGF_DEBUG("Creating directory %s...", dir);
1188  if (INDI::mkpath(dir, 0755) == -1)
1189  LOGF_ERROR("Error creating directory %s (%s)", dir, strerror(errno));
1190  }
1191 
1192  dpdf = opendir(dir);
1193  if (dpdf != nullptr)
1194  {
1195  while ((epdf = readdir(dpdf)))
1196  {
1197  if (strstr(epdf->d_name, prefixIndex.c_str()))
1198  files.push_back(epdf->d_name);
1199  }
1200  closedir(dpdf);
1201  }
1202  else
1203  return -1;
1204 
1205  int maxIndex = 0;
1206 
1207  for (int i = 0; i < static_cast<int>(files.size()); i++)
1208  {
1209  int index = -1;
1210 
1211  std::string file = files.at(i);
1212  std::size_t start = file.find_last_of("_");
1213  std::size_t end = file.find_last_of(".");
1214  if (start != std::string::npos)
1215  {
1216  index = atoi(file.substr(start + 1, end).c_str());
1217  if (index > maxIndex)
1218  maxIndex = index;
1219  }
1220  }
1221 
1222  return (maxIndex + 1);
1223 }
1224 
1225 void SensorInterface::setBPS(int bps)
1226 {
1227  BPS = bps;
1228 
1229  // Reset size
1230  if (HasStreaming())
1231  Streamer->setSize(getBufferSize() * 8 / BPS);
1232 
1233  // DSP
1234  if (HasDSP())
1235  DSP->setSizes(1, new int[1] { getBufferSize() * 8 / BPS });
1236 }
1237 
1238 
1240 {
1241  return false;
1243 
1244 bool SensorInterface::callHandshake()
1245 {
1246  if (sensorConnection > 0)
1247  {
1250  else if (getActiveConnection() == tcpConnection)
1252  }
1253 
1254  return Handshake();
1255 }
1257 void SensorInterface::setSensorConnection(const uint8_t &value)
1258 {
1260 
1261  if (value == 0 || (mask & value) == 0)
1262  {
1263  DEBUGF(Logger::DBG_ERROR, "Invalid connection mode %d", value);
1264  return;
1265  }
1266 
1267  sensorConnection = value;
1268 }
1269 }
INDI::SensorInterface::HasDSP
bool HasDSP()
Definition: indisensorinterface.h:367
INDI::SensorInterface::saveConfigItems
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save configuration items in XML file.
Definition: indisensorinterface.cpp:1047
MAXINDIDEVICE
#define MAXINDIDEVICE
Definition: indiapi.h:192
INDI::SensorInterface::getBuffer
uint8_t * getBuffer()
getBuffer Get raw buffer of the stream of the Sensor device.
Definition: indisensorinterface.h:146
INDI::SensorInterface::updateProperties
bool updateProperties()
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indisensorinterface.cpp:104
INDI::SensorInterface::TemperatureN
INumber TemperatureN[1]
Definition: indisensorinterface.h:502
INDI::SensorInterface::SensorInterface
SensorInterface()
Definition: indisensorinterface.cpp:66
IP_RO
@ IP_RO
Definition: indiapi.h:183
indiutility.h
INDI::SensorInterface::TemperatureNP
INumberVectorProperty TemperatureNP
Definition: indisensorinterface.h:503
INDI::SensorInterface::IntegrationComplete
virtual bool IntegrationComplete()
Uploads target Device exposed buffer as FITS to the client. Dervied classes should class this functio...
Definition: indisensorinterface.cpp:885
Connection::TCP::getPortFD
int getPortFD() const
Definition: connectiontcp.h:120
INDI::SensorInterface::getIntegrationTime
double getIntegrationTime() const
getIntegrationTime Get requested Integration duration for the Sensor device in seconds.
Definition: indisensorinterface.h:131
INDI::SensorInterface::FileNameT
IText FileNameT[1]
Definition: indisensorinterface.h:432
INDI::SensorInterface::SendIntegration
bool SendIntegration
Definition: indisensorinterface.h:488
IUUpdateMinMax
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1850
INDI::SensorInterface::CanAbort
bool CanAbort() const
Definition: indisensorinterface.h:359
INDI::SensorInterface::CONNECTION_TCP
@ CONNECTION_TCP
Definition: indisensorinterface.h:96
_IBLOBVectorProperty::s
IPState s
Definition: indiapi.h:484
INDI::SensorInterface::AutoLoop
bool AutoLoop
Definition: indisensorinterface.h:487
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
min
double min(void)
INDI::SensorInterface::StartStreaming
virtual bool StartStreaming()
StartStreaming Start live video streaming.
Definition: indisensorinterface.cpp:1028
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
indicom.h
Implementations for common driver routines.
connectiontcp.h
locale_compat.h
INDI::Logger::DBG_WARNING
@ DBG_WARNING
Definition: indilogger.h:193
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
INDI::SensorInterface::PortFD
int PortFD
For Serial & TCP connections.
Definition: indisensorinterface.h:517
IDSnoopDevice
void IDSnoopDevice(const char *snooped_device, const char *snooped_property)
Function a Driver calls to snoop on another Device. Snooped messages will then arrive via ISSnoopDevi...
Definition: indidriver.c:137
INumber
One number descriptor.
Connection::Serial
The Serial class manages connection with serial devices including Bluetooth. Serial communication is ...
Definition: connectionserial.h:56
INDI::SensorInterface::serialConnection
Connection::Serial * serialConnection
Definition: indisensorinterface.h:513
INDI::SensorInterface::setSensorConnection
void setSensorConnection(const uint8_t &value)
setSensorConnection Set Sensor connection mode. Child class should call this in the constructor befor...
Definition: indisensorinterface.cpp:1274
INDI::SensorInterface::IntegrationTime
double IntegrationTime
Definition: indisensorinterface.h:491
Connection::TCP
The TCP class manages connection with devices over the network via TCP/IP. Upon successfull connectio...
Definition: connectiontcp.h:55
IUFillNumber
void IUFillNumber(INumber *np, const char *name, const char *label, const char *format, double min, double max, double step, double value)
Assign attributes for a number property. The number's auxiliary elements will be set to NULL.
Definition: indidriver.c:348
INDI::DefaultDevice::defineProperty
void defineProperty(INumberVectorProperty *property)
Definition: defaultdevice.cpp:997
OPTIONS_TAB
const char * OPTIONS_TAB
OPTIONS_TAB Where all the driver's options are located. Those may include auxiliary controls,...
Definition: defaultdevice.cpp:39
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
INDI::SensorInterface::ScopeParametersNP
INumberVectorProperty ScopeParametersNP
Definition: indisensorinterface.h:483
INDI::Logger::DBG_ERROR
@ DBG_ERROR
Definition: indilogger.h:192
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
timestamp
const char * timestamp()
Create an ISO 8601 formatted time stamp. The format is YYYY-MM-DDTHH:MM:SS.
Definition: indicom.c:340
uploadFile
void uploadFile(const char *filename)
Definition: stv.c:1710
INDI_UNUSED
#define INDI_UNUSED(x)
Definition: indidevapi.h:799
INDI::SensorInterface::processBLOB
bool processBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Definition: indisensorinterface.cpp:389
MAXINDIBLOBFMT
#define MAXINDIBLOBFMT
Definition: indiapi.h:195
INDI::SensorInterface::FitsBP
IBLOBVectorProperty FitsBP
Definition: indisensorinterface.h:427
time_ns
double time_ns()
Get a unix timestamp with nanosecond precision.
Definition: indicom.c:322
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
INDI::SensorInterface::AbortIntegration
virtual bool AbortIntegration()
Abort ongoing Integration.
Definition: indisensorinterface.cpp:630
IDSetBLOB
void void void void void void void void void IDSetBLOB(const IBLOBVectorProperty *b, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing BLOB vector property.
INDI::Logger::DBG_SESSION
@ DBG_SESSION
Definition: indilogger.h:194
INDI::SensorInterface::tcpConnection
Connection::TCP * tcpConnection
Definition: indisensorinterface.h:514
INDI::SensorInterface::FileNameTP
ITextVectorProperty FileNameTP
Definition: indisensorinterface.h:433
INDI::SensorInterface::processText
bool processText(const char *dev, const char *name, char *texts[], char *names[], int n)
Definition: indisensorinterface.cpp:194
INFO_TAB
const char * INFO_TAB
INFO_TAB Where all the properties for general information are located.
Definition: defaultdevice.cpp:45
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
INDI::SensorInterface::setIntegrationFileExtension
void setIntegrationFileExtension(const char *ext)
setIntegrationExtension Set integration exntension
Definition: indisensorinterface.cpp:624
INDI::SensorInterface::processSwitch
bool processSwitch(const char *dev, const char *name, ISState states[], char *names[], int n)
Definition: indisensorinterface.cpp:318
INDI::SensorInterface::RA
double RA
Definition: indisensorinterface.h:477
INDI::SensorInterface::primaryAperture
double primaryAperture
Definition: indisensorinterface.h:485
IUUpdateText
int IUUpdateText(ITextVectorProperty *tvp, char *texts[], char *names[], int n)
Update all text members in a text vector property.
Definition: indidriver.c:259
INDI::SensorInterface::setIntegrationFailed
void setIntegrationFailed()
setIntegrationFailed Alert the client that the Integration failed.
Definition: indisensorinterface.cpp:608
MAXRBUF
#define MAXRBUF
Definition: indidriver.c:52
INDI::SensorInterface::SetTemperature
virtual int SetTemperature(double temperature)
Set Sensor temperature.
Definition: indisensorinterface.cpp:1040
DEBUG
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
INDI::DefaultDevice::initProperties
virtual bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
Definition: defaultdevice.cpp:917
max
double max(void)
IUResetSwitch
void IUResetSwitch(ISwitchVectorProperty *svp)
Reset all switches in a switch vector property to OFF.
Definition: indicom.c:1442
INDI::ObservedToJ2000
void ObservedToJ2000(IEquatorialCoordinates *observed, double jd, IEquatorialCoordinates *J2000pos)
ObservedToJ2000 converts an observed position to a J2000 catalogue position removes aberration,...
Definition: libastro.cpp:50
INDI::Logger::DBG_DEBUG
@ DBG_DEBUG
Definition: indilogger.h:195
INDI::SensorInterface::getIntegrationFileExtension
char * getIntegrationFileExtension()
Definition: indisensorinterface.h:242
INDI::SensorInterface::UploadSP
ISwitchVectorProperty UploadSP
Definition: indisensorinterface.h:444
INDI::SensorInterface::Streamer
std::unique_ptr< StreamManager > Streamer
Definition: indisensorinterface.h:508
INDI::SensorInterface::UPLOAD_DIR
@ UPLOAD_DIR
Definition: indisensorinterface.h:450
INDI::SensorInterface::FITSHeaderT
IText FITSHeaderT[2]
Definition: indisensorinterface.h:458
INDI::mkpath
int mkpath(std::string s, mode_t mode)
Create a path directory - this function uses 'mkdir'.
Definition: indiutility.cpp:29
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
INDI::DefaultDevice::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root)
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: defaultdevice.cpp:633
INDI::SensorInterface::setIntegrationTime
void setIntegrationTime(double duration)
setIntegrationTime Set desired Sensor frame Integration duration for next Integration....
Definition: indisensorinterface.cpp:586
INDI::SensorInterface::setNAxis
void setNAxis(int value)
setNAxis Set FITS number of axis
Definition: indisensorinterface.cpp:619
type
__le16 type
Definition: pwc-ioctl.h:2
INDI::SensorInterface::capability
uint32_t capability
Definition: indisensorinterface.h:418
INDI::SensorInterface::FITS_OBJECT
@ FITS_OBJECT
Definition: indisensorinterface.h:463
INDI::IEquatorialCoordinates::rightascension
double rightascension
Definition: libastro.h:50
INDI::SensorInterface::UPLOAD_PREFIX
@ UPLOAD_PREFIX
Definition: indisensorinterface.h:451
_INumberVectorProperty
Number vector property descriptor.
Definition: indiapi.h:317
INDI::SensorInterface::getNAxis
int getNAxis() const
Definition: indisensorinterface.cpp:614
INDI::SensorInterface::CONNECTION_SERIAL
@ CONNECTION_SERIAL
Definition: indisensorinterface.h:95
IUSaveConfigText
void IUSaveConfigText(FILE *fp, const ITextVectorProperty *tvp)
Add a text vector property value to the configuration file.
Definition: indicom.c:1460
streammanager.h
INDI::DefaultDevice::getDriverInterface
virtual uint16_t getDriverInterface() override
Definition: defaultdevice.cpp:896
INDI::SensorInterface::~SensorInterface
~SensorInterface()
Definition: indisensorinterface.cpp:96
INDI::DefaultDevice::getPollingPeriod
uint32_t getPollingPeriod() const
getPollingPeriod Return the polling period.
Definition: defaultdevice.cpp:1251
INDI::DefaultDevice::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
Process the client newNumber command.
Definition: defaultdevice.cpp:593
INDI::SensorInterface::setMinMaxStep
void setMinMaxStep(const char *property, const char *element, double min, double max, double step, bool sendToClient=true)
setMinMaxStep for a number property element
Definition: indisensorinterface.cpp:529
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
IUFillNumberVector
void IUFillNumberVector(INumberVectorProperty *nvp, INumber *np, int nnp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a number vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:455
INDI::SensorInterface::initProperties
bool initProperties()
Initilize properties initial state and value. The child class must implement this function.
Definition: indisensorinterface.cpp:398
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
connectionserial.h
INDI::SensorInterface::StartIntegration
virtual bool StartIntegration(double duration)
Start integration from the Sensor device.
Definition: indisensorinterface.cpp:572
_INumberVectorProperty::np
INumber * np
Definition: indiapi.h:334
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
INDI::SensorInterface::FITS_OBSERVER
@ FITS_OBSERVER
Definition: indisensorinterface.h:462
INDI::SensorInterface::ScopeParametersN
INumber ScopeParametersN[4]
Definition: indisensorinterface.h:484
INDI::SensorInterface::StopStreaming
virtual bool StopStreaming()
StopStreaming Stop live video streaming.
Definition: indisensorinterface.cpp:1034
INDI::SensorInterface::Latitude
double Latitude
Definition: indisensorinterface.h:481
INDI::SensorInterface::activeDevicesUpdated
virtual void activeDevicesUpdated()
activeDevicesUpdated Inform children that ActiveDevices property was updated so they can snoop on the...
Definition: indisensorinterface.h:500
INDI::SensorInterface::getBPS
int getBPS() const
getBPS Get Sensor depth (bits per sample).
Definition: indisensorinterface.h:168
INDI::SensorInterface::FramedIntegrationN
INumber FramedIntegrationN[1]
Definition: indisensorinterface.h:421
INDI::DefaultDevice::registerConnection
void registerConnection(Connection::Interface *newConnection)
registerConnection Add new connection plugin to the existing connection pool. The connection type sha...
Definition: defaultdevice.cpp:1107
xml_ele_
Definition: lilxml.c:105
INDI::SensorInterface::CONNECTION_NONE
@ CONNECTION_NONE
Definition: indisensorinterface.h:94
ISR_ATMOST1
@ ISR_ATMOST1
Definition: indiapi.h:173
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
INDI::SensorInterface::fits_update_key_s
void fits_update_key_s(fitsfile *fptr, int type, std::string name, void *p, std::string explanation, int *status)
Definition: indisensorinterface.cpp:760
INDI::DefaultDevice::loadConfig
virtual bool loadConfig(bool silent=false, const char *property=nullptr)
Load the last saved configuration file.
Definition: defaultdevice.cpp:147
INDI::SensorInterface::AbortIntegrationS
ISwitch AbortIntegrationS[1]
Definition: indisensorinterface.h:424
defaultdevice.h
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::SensorInterface::FramedIntegrationNP
INumberVectorProperty FramedIntegrationNP
Definition: indisensorinterface.h:420
end
JsonIterator end(JsonValue)
Definition: gason.h:108
_ITextVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:249
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
IUFindNumber
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1372
MAXINDIFORMAT
#define MAXINDIFORMAT
Definition: indiapi.h:194
INDI::SensorInterface::processNumber
bool processNumber(const char *dev, const char *name, double values[], char *names[], int n)
Definition: indisensorinterface.cpp:250
INDI::SensorInterface::InIntegration
bool InIntegration
Definition: indisensorinterface.h:473
IUFillBLOB
void IUFillBLOB(IBLOB *bp, const char *name, const char *label, const char *format)
Assign attributes for a BLOB property. The BLOB's data and auxiliary elements will be set to NULL.
Definition: indidriver.c:390
INDI::SensorInterface::Dec
double Dec
Definition: indisensorinterface.h:477
INDI::SensorInterface::FITSHeaderTP
ITextVectorProperty FITSHeaderTP
Definition: indisensorinterface.h:459
DSP
The DSP Namespace adds signal processing to INDI drivers. Primarily written for sensors and detectors...
Definition: convolution.cpp:39
INDI::SensorInterface::primaryFocalLength
double primaryFocalLength
Definition: indisensorinterface.h:485
LOG_ERROR
#define LOG_ERROR(txt)
Shorter logging macros. In order to use these macros, the function (or method) "getDeviceName()" must...
Definition: indilogger.h:72
INDI::SensorInterface::ActiveDeviceT
IText ActiveDeviceT[4]
Definition: indisensorinterface.h:430
INDI::SensorInterface::Handshake
virtual bool Handshake()
perform handshake with device to check communication
Definition: indisensorinterface.cpp:1256
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1449
INDI::SensorInterface::getBufferSize
int getBufferSize() const
getContinuumBufferSize Get allocated continuum buffer size to hold the Sensor integrationd stream.
Definition: indisensorinterface.h:113
INDI::SensorInterface::HasCooler
bool HasCooler() const
Definition: indisensorinterface.h:351
INDI::SensorInterface::getIntegrationStartTime
const char * getIntegrationStartTime()
getIntegrationStartTime
Definition: indisensorinterface.cpp:595
INDI::DefaultDevice::ISGetProperties
virtual void ISGetProperties(const char *dev)
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: defaultdevice.cpp:750
name
const char * name
Definition: indiserver.c:116
indisensorinterface.h
INDI::SensorInterface::addFITSKeywords
virtual void addFITSKeywords(fitsfile *fptr, uint8_t *buf, int len)
Add FITS keywords to a fits file.
Definition: indisensorinterface.cpp:636
INDI::SensorInterface::TelescopeTypeSP
ISwitchVectorProperty TelescopeTypeSP
Definition: indisensorinterface.h:455
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::SensorInterface::Longitude
double Longitude
Definition: indisensorinterface.h:481
_ITextVectorProperty::s
IPState s
Definition: indiapi.h:259
INDI::SensorInterface::processProperties
void processProperties(const char *dev)
Definition: indisensorinterface.cpp:155
_INumberVectorProperty::device
char device[MAXINDIDEVICE]
Definition: indiapi.h:320
INDI::SensorInterface::HasStreaming
bool HasStreaming()
Definition: indisensorinterface.h:383
INDI
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: AlignmentSubsystemForClients.cpp:11
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
INDI::DefaultDevice::ISNewBLOB
virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
Process the client newBLOB command.
Definition: defaultdevice.cpp:623
INDI::SensorInterface::EqNP
INumberVectorProperty EqNP
Definition: indisensorinterface.h:475
_IBLOBVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:474
INDI::SensorInterface::ActiveDeviceTP
ITextVectorProperty ActiveDeviceTP
Definition: indisensorinterface.h:429
DEBUGF
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
fs_sexa
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string.
Definition: indicom.c:137
INDI::DefaultDevice::saveConfigItems
virtual bool saveConfigItems(FILE *fp)
saveConfigItems Save specific properties in the provide config file handler. Child class usually over...
Definition: defaultdevice.cpp:175
INDI::SensorInterface::ShowMarker
bool ShowMarker
Definition: indisensorinterface.h:489
IP_RW
@ IP_RW
Definition: indiapi.h:185
INDI::SensorInterface::setIntegrationLeft
void setIntegrationLeft(double duration)
setIntegrationLeft Update Integration time left. Inform the client of the new Integration time left v...
Definition: indisensorinterface.cpp:579
INDI::DefaultDevice::setCurrentPollingPeriod
void setCurrentPollingPeriod(uint32_t msec)
setCurrentPollingPeriod Change the current polling period to call TimerHit() function in the driver.
Definition: defaultdevice.cpp:1133
INDI::SensorInterface::processSnoopDevice
bool processSnoopDevice(XMLEle *root)
Definition: indisensorinterface.cpp:169
INDI::SensorInterface::UploadSettingsTP
ITextVectorProperty UploadSettingsTP
Definition: indisensorinterface.h:447
INDI::SensorInterface::UploadS
ISwitch UploadS[3]
Definition: indisensorinterface.h:443
INDI::SensorInterface::MPSAS
double MPSAS
Definition: indisensorinterface.h:494
INDI::SensorInterface::FitsB
IBLOB FitsB
Definition: indisensorinterface.h:426
ISState
ISState
Switch state.
Definition: indiapi.h:148
Connection::Serial::getPortFD
int getPortFD() const
Definition: connectionserial.h:136
INDI::DefaultDevice::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
Process the client newSwitch command.
Definition: defaultdevice.cpp:409
INDI::SensorInterface::SetCapability
void SetCapability(uint32_t cap)
SetCapability Set the Sensor capabilities. Al fields must be initilized.
Definition: indisensorinterface.cpp:519
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1424
INDI::IEquatorialCoordinates
Definition: libastro.h:48
INDI::SensorInterface::EqN
INumber EqN[2]
Definition: indisensorinterface.h:476
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1465
INDI::SensorInterface::UploadSettingsT
IText UploadSettingsT[2]
Definition: indisensorinterface.h:446
IUFillBLOBVector
void IUFillBLOBVector(IBLOBVectorProperty *bvp, IBLOB *bp, int nbp, const char *dev, const char *name, const char *label, const char *group, IPerm p, double timeout, IPState s)
Assign attributes for a BLOB vector property. The vector's auxiliary elements will be set to NULL.
Definition: indidriver.c:499
INDI::SensorInterface::setBPS
void setBPS(int bps)
setBPP Set depth of Sensor device.
Definition: indisensorinterface.cpp:1242
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
INDI::DefaultDevice::ISNewText
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
Process the client newSwitch command.
Definition: defaultdevice.cpp:614
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.
errno
int errno
INDI::regex_replace_compat2
std::string regex_replace_compat2(const std::string &input, const std::string &pattern, const std::string &replace)
Definition: indisensorinterface.cpp:1180
INDI::DefaultDevice::setDriverInterface
void setDriverInterface(uint16_t value)
setInterface Set driver interface. By default the driver interface is set to GENERAL_DEVICE....
Definition: defaultdevice.cpp:902
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::SensorInterface::LocationN
INumber LocationN[3]
Definition: indisensorinterface.h:480
libastro.h
INDI::SensorInterface::setBufferSize
void setBufferSize(int nbuf, bool allocMem=true)
setBufferSize Set desired buffer size. The function will allocate memory accordingly....
Definition: indisensorinterface.cpp:551
INDI::DefaultDevice::getActiveConnection
Connection::Interface * getActiveConnection()
Definition: defaultdevice.cpp:1245
IUSnoopNumber
int IUSnoopNumber(XMLEle *root, INumberVectorProperty *nvp)
Update a snooped number vector property from the given XML root element.
Definition: indidriver.c:531
INDI::SensorInterface::LocationNP
INumberVectorProperty LocationNP
Definition: indisensorinterface.h:479
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
INDI::SensorInterface::Elevation
double Elevation
Definition: indisensorinterface.h:481
ISS_ON
@ ISS_ON
Definition: indiapi.h:151
INDI::SensorInterface::AbortIntegrationSP
ISwitchVectorProperty AbortIntegrationSP
Definition: indisensorinterface.h:423