Instrument Neutral Distributed Interface INDI  2.0.2
dspinterface.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2017 Jasem Mutlaq. All rights reserved.
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 *******************************************************************************/
18 
19 #include "dspinterface.h"
20 
21 #include "defaultdevice.h"
22 #include "indiccd.h"
23 #include "indisensorinterface.h"
24 #include "indilogger.h"
25 #include "locale_compat.h"
26 #include "indicom.h"
27 #include "libastro.h"
28 #include "indiutility.h"
29 
30 #include <fitsio.h>
31 
32 #include <libnova/julian_day.h>
33 #include <libnova/ln_types.h>
34 #include <libnova/precession.h>
35 
36 #include <regex>
37 
38 #include <dirent.h>
39 #include <cerrno>
40 #include <locale.h>
41 #include <cstdio>
42 #include <cstdlib>
43 #include <cstring>
44 #include <zlib.h>
45 #include <sys/stat.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 
49 static std::string regex_replace_compat(const std::string &input, const std::string &pattern, const std::string &replace)
50 {
51  std::stringstream s;
52  std::regex_replace(std::ostreambuf_iterator<char>(s), input.begin(), input.end(), std::regex(pattern), replace);
53  return s.str();
54 }
55 
56 namespace DSP
57 {
58 const char *DSP_TAB = "Signal Processing";
59 
60 Interface::Interface(INDI::DefaultDevice *dev, Type type, const char *name, const char *label) : m_Device(dev),
61  m_Name(name), m_Label(label), m_Type(type)
62 {
63  char activatestrname[MAXINDINAME];
64  char activatestrlabel[MAXINDILABEL];
65  sprintf(activatestrname, "DSP_ACTIVATE_%s", m_Name);
66  sprintf(activatestrlabel, "%s", m_Label);
67  IUFillSwitch(&ActivateS[0], "DSP_ACTIVATE_ON", "On", ISState::ISS_OFF);
68  IUFillSwitch(&ActivateS[1], "DSP_ACTIVATE_OFF", "Off", ISState::ISS_ON);
69  IUFillSwitchVector(&ActivateSP, ActivateS, 2, getDeviceName(), activatestrname, activatestrlabel, DSP_TAB, IP_RW,
70  ISR_1OFMANY, 60, IPS_IDLE);
71 
74  BufferSizes = nullptr;
75  BufferSizesQty = 0;
77  //Create the dsp stream
81  buffer = malloc(1);
82 }
83 
85 {
86  if(buffer != nullptr)
87  free(buffer);
88  if(stream != nullptr)
89  {
92  }
93 }
94 
96 {
97  return m_Device->getDeviceName();
98 }
99 
100 void Interface::ISGetProperties(const char *dev)
101 {
102  INDI_UNUSED(dev);
103  if (m_Device->isConnected())
104  {
106  }
107  else
108  {
110  PluginActive = false;
111  Deactivated();
112  }
113 }
114 
116 {
117  if (m_Device->isConnected())
118  {
120  }
121  else
122  {
124  PluginActive = false;
125  Deactivated();
126  }
127  return true;
128 }
129 
130 bool Interface::ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
131 {
132  if(!strcmp(dev, getDeviceName()) && !strcmp(name, ActivateSP.name))
133  {
134  IUUpdateSwitch(&ActivateSP, states, names, n);
135  if(ActivateSP.sp[0].s == ISS_ON)
136  {
137  PluginActive = true;
138  Activated();
139  }
140  else
141  {
142  PluginActive = false;
143  Deactivated();
144  }
145  IDSetSwitch(&ActivateSP, nullptr);
146  }
147  return false;
148 }
149 
150 bool Interface::ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
151 {
152  INDI_UNUSED(dev);
153  INDI_UNUSED(name);
154  INDI_UNUSED(values);
155  INDI_UNUSED(names);
156  INDI_UNUSED(n);
157  return false;
158 }
159 
160 bool Interface::ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
161 {
162  INDI_UNUSED(dev);
163  INDI_UNUSED(name);
164  INDI_UNUSED(texts);
165  INDI_UNUSED(names);
166  INDI_UNUSED(n);
167  return false;
168 }
169 
170 bool Interface::ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[],
171  char *names[], int n)
172 {
173  INDI_UNUSED(dev);
174  INDI_UNUSED(name);
175  INDI_UNUSED(sizes);
176  INDI_UNUSED(blobsizes);
177  INDI_UNUSED(blobs);
178  INDI_UNUSED(formats);
179  INDI_UNUSED(names);
180  INDI_UNUSED(n);
181  return false;
182 }
183 
184 uint8_t* Interface::Callback(uint8_t* buf, uint32_t ndims, int* dims, int bits_per_sample)
185 {
186  INDI_UNUSED(buf);
187  INDI_UNUSED(ndims);
188  INDI_UNUSED(dims);
189  INDI_UNUSED(bits_per_sample);
190  DEBUG(INDI::Logger::DBG_WARNING, "Interface::Callback - Should never get here");
191  return nullptr;
192 }
193 
194 bool Interface::processBLOB(uint8_t* buffer, uint32_t ndims, int* dims, int bits_per_sample)
195 {
196  bool success = false;
197  if(PluginActive)
198  {
199  bool sendCapture = (m_Device->getSwitch("UPLOAD_MODE")[0].getState() == ISS_ON
200  || m_Device->getSwitch("UPLOAD_MODE")[2].getState() == ISS_ON);
201  bool saveCapture = (m_Device->getSwitch("UPLOAD_MODE")[1].getState() == ISS_ON
202  || m_Device->getSwitch("UPLOAD_MODE")[2].getState() == ISS_ON);
203 
204  if (sendCapture || saveCapture)
205  {
206  if (buffer)
207  {
208  setSizes(ndims, dims);
209  setBPS(bits_per_sample);
210  LOGF_INFO("%s processing done.", m_Label);
211 
212  long len = 1;
213  uint32_t i;
214  for (len = 1, i = 0; i < BufferSizesQty; len *= BufferSizes[i++]);
215  len *= getBPS() / 8;
216 
217  if (!strcmp(captureExtention, "fits"))
218  {
219  success = sendFITS(buffer, sendCapture, saveCapture);
220  }
221  else
222  {
223  success = uploadFile(buffer, len, sendCapture, saveCapture, captureExtention);
224  }
225  }
226  }
227  }
228  return success;
229 }
230 
232 {
234 }
235 
237 {
239 }
240 
242 {
243  INDI_UNUSED(fp);
244  return true;
245 }
246 
247 void Interface::addFITSKeywords(fitsfile *fptr)
248 {
249  int status = 0;
250  char exp_start[32];
251 
252  char *orig = setlocale(LC_NUMERIC, "C");
253 
254  char fitsString[MAXINDIDEVICE];
255 
256  // Telescope
257  strncpy(fitsString, m_Device->getText("ACTIVE_DEVICES")[0].getText(), MAXINDIDEVICE);
258  fits_update_key_s(fptr, TSTRING, "TELESCOP", fitsString, "Telescope name", &status);
259 
260  // Observer
261  strncpy(fitsString, m_Device->getText("FITS_HEADER")[0].getText(), MAXINDIDEVICE);
262  fits_update_key_s(fptr, TSTRING, "OBSERVER", fitsString, "Observer name", &status);
263 
264  // Object
265  strncpy(fitsString, m_Device->getText("FITS_HEADER")[1].getText(), MAXINDIDEVICE);
266  fits_update_key_s(fptr, TSTRING, "OBJECT", fitsString, "Object name", &status);
267 
268  auto nv = m_Device->getNumber("GEOGRAPHIC_COORDS");
269  if(!nv)
270  {
271  double Lat = nv[0].getValue();
272  double Lon = nv[1].getValue();
273  double El = nv[2].getValue();
274 
275  char lat_str[MAXINDIFORMAT];
276  char lon_str[MAXINDIFORMAT];
277  char el_str[MAXINDIFORMAT];
278  fs_sexa(lat_str, Lat, 2, 360000);
279  fs_sexa(lon_str, Lon, 2, 360000);
280  snprintf(el_str, MAXINDIFORMAT, "%lf", El);
281  fits_update_key_s(fptr, TSTRING, "LATITUDE", lat_str, "Location Latitude", &status);
282  fits_update_key_s(fptr, TSTRING, "LONGITUDE", lon_str, "Location Longitude", &status);
283  fits_update_key_s(fptr, TSTRING, "ELEVATION", el_str, "Location Elevation", &status);
284  }
285 
286  nv = m_Device->getNumber("EQUATORIAL_EOD_COORDS");
287  if(nv)
288  {
289  double RA = nv[0].getValue();
290  double Dec = nv[1].getValue();
291 
292  INDI::IEquatorialCoordinates epochPos { 0, 0 }, J2000Pos { 0, 0 };
293  epochPos.rightascension = RA;
294  epochPos.declination = Dec;
295 
296  // Convert from JNow to J2000
297  //TODO use exp_start instead of julian from system
298  INDI::ObservedToJ2000(&epochPos, ln_get_julian_from_sys(), &J2000Pos);
299 
300  double raJ2000 = J2000Pos.rightascension;
301  double decJ2000 = J2000Pos.declination;
302  char ra_str[32], de_str[32];
303 
304  fs_sexa(ra_str, raJ2000, 2, 360000);
305  fs_sexa(de_str, decJ2000, 2, 360000);
306 
307  char *raPtr = ra_str, *dePtr = de_str;
308  while (*raPtr != '\0')
309  {
310  if (*raPtr == ':')
311  *raPtr = ' ';
312  raPtr++;
313  }
314  while (*dePtr != '\0')
315  {
316  if (*dePtr == ':')
317  *dePtr = ' ';
318  dePtr++;
319  }
320 
321  fits_update_key_s(fptr, TSTRING, "OBJCTRA", ra_str, "Object RA", &status);
322  fits_update_key_s(fptr, TSTRING, "OBJCTDEC", de_str, "Object DEC", &status);
323 
324  int epoch = 2000;
325 
326  //fits_update_key_s(fptr, TINT, "EPOCH", &epoch, "Epoch", &status);
327  fits_update_key_s(fptr, TINT, "EQUINOX", &epoch, "Equinox", &status);
328  }
329 
330  fits_update_key_s(fptr, TSTRING, "DATE-OBS", exp_start, "UTC start date of observation", &status);
331  fits_write_comment(fptr, "Generated by INDI", &status);
332 
333  setlocale(LC_NUMERIC, orig);
334 }
335 
336 void Interface::fits_update_key_s(fitsfile *fptr, int type, std::string name, void *p, std::string explanation,
337  int *status)
338 {
339  // this function is for removing warnings about deprecated string conversion to char* (from arg 5)
340  fits_update_key(fptr, type, name.c_str(), p, const_cast<char *>(explanation.c_str()), status);
341 }
342 
344 {
345  dsp_stream_p loaded_stream = nullptr;
346  char filename[MAXINDINAME];
347  sprintf(filename, "INDI_DSP_INTERFACE_XXXXXX");
348  int fd = mkstemp(filename);
349  if(fd > 0)
350  {
351  int written = write(fd, buffer, len);
352  if(written != len)
353  return nullptr;
354  close(fd);
355  int channels = 0;
356  dsp_stream_p *stream_arr = dsp_file_read_fits(filename, &channels, false);
357  if (channels > 0)
358  {
359  loaded_stream = stream_arr[channels];
360  for (int c = 0; c < channels; c++)
361  {
362  dsp_stream_free_buffer(stream_arr[c]);
363  dsp_stream_free(stream_arr[c]);
364  }
365  free(stream_arr);
366  }
367  unlink(filename);
368  }
369  return loaded_stream;
370 }
371 
372 bool Interface::sendFITS(uint8_t *buf, bool sendCapture, bool saveCapture)
373 {
374  int img_type = USHORT_IMG;
375  int byte_type = TUSHORT;
376  std::string bit_depth = "16 bits per sample";
377  switch (getBPS())
378  {
379  case 8:
380  byte_type = TBYTE;
381  img_type = BYTE_IMG;
382  bit_depth = "8 bits per sample";
383  break;
384 
385  case 16:
386  byte_type = TUSHORT;
387  img_type = USHORT_IMG;
388  bit_depth = "16 bits per pixel";
389  break;
390 
391  case 32:
392  byte_type = TUINT;
393  img_type = ULONG_IMG;
394  bit_depth = "32 bits per sample";
395  break;
396 
397  case 64:
398  byte_type = TLONG;
399  img_type = ULONG_IMG;
400  bit_depth = "64 bits double per sample";
401  break;
402 
403  case -32:
404  byte_type = TFLOAT;
405  img_type = FLOAT_IMG;
406  bit_depth = "32 bits double per sample";
407  break;
408 
409  case -64:
410  byte_type = TDOUBLE;
411  img_type = DOUBLE_IMG;
412  bit_depth = "64 bits double per sample";
413  break;
414 
415  default:
416  DEBUGF(INDI::Logger::DBG_ERROR, "Unsupported bits per sample value %d", getBPS());
417  return false;
418  }
419 
420  fitsfile *fptr = nullptr;
421  void *memptr;
422  size_t memsize;
423  int status = 0;
424  int naxis = static_cast<int>(BufferSizesQty);
425  long *naxes = static_cast<long*>(malloc(sizeof(long) * BufferSizesQty));
426  long nelements = 1;
427 
428  for (uint32_t i = 0; i < BufferSizesQty; nelements *= static_cast<long>(BufferSizes[i++]))
429  naxes[i] = BufferSizes[i];
430  char error_status[MAXINDINAME];
431 
432  // Now we have to send fits format data to the client
433  memsize = 5760;
434  memptr = malloc(memsize);
435  if (!memptr)
436  {
437  LOGF_ERROR("Error: failed to allocate memory: %lu", memsize);
438  return false;
439  }
440 
441  fits_create_memfile(&fptr, &memptr, &memsize, 2880, realloc, &status);
442 
443  if (status)
444  {
445  fits_report_error(stderr, status); /* print out any error messages */
446  fits_get_errstatus(status, error_status);
447  fits_close_file(fptr, &status);
448  free(memptr);
449  LOGF_ERROR("FITS Error: %s", error_status);
450  return false;
451  }
452 
453  fits_create_img(fptr, img_type, naxis, naxes, &status);
454 
455  if (status)
456  {
457  fits_report_error(stderr, status); /* print out any error messages */
458  fits_get_errstatus(status, error_status);
459  fits_close_file(fptr, &status);
460  free(memptr);
461  LOGF_ERROR("FITS Error: %s", error_status);
462  return false;
463  }
464 
465  addFITSKeywords(fptr);
466 
467  fits_write_img(fptr, byte_type, 1, nelements, buf, &status);
468 
469  if (status)
470  {
471  fits_report_error(stderr, status); /* print out any error messages */
472  fits_get_errstatus(status, error_status);
473  fits_close_file(fptr, &status);
474  free(memptr);
475  LOGF_ERROR("FITS Error: %s", error_status);
476  return false;
477  }
478  fits_close_file(fptr, &status);
479 
480  uploadFile(memptr, memsize, sendCapture, saveCapture, captureExtention);
481 
482  free(memptr);
483  return true;
484 }
485 
486 bool Interface::uploadFile(const void *fitsData, size_t totalBytes, bool sendCapture, bool saveCapture, const char* format)
487 {
488 
489  DEBUGF(INDI::Logger::DBG_DEBUG, "Uploading file. Ext: %s, Size: %d, sendCapture? %s, saveCapture? %s",
490  format, totalBytes, sendCapture ? "Yes" : "No", saveCapture ? "Yes" : "No");
491 
492  FitsB.blob = const_cast<void*>(fitsData);
493  FitsB.bloblen = static_cast<int>(totalBytes);
494  FitsB.size = totalBytes;
495  FitsBP.s = IPS_BUSY;
496 
497  snprintf(FitsB.format, MAXINDIBLOBFMT, ".%s", captureExtention);
498 
499  if (saveCapture)
500  {
501 
502  FILE *fp = nullptr;
503 
504  std::string prefix = m_Device->getText("UPLOAD_SETTINGS")[1].getText();
505 
506  int maxIndex = getFileIndex(m_Device->getText("UPLOAD_SETTINGS")[0].getText(), prefix.c_str(),
507  format);
508 
509  if (maxIndex < 0)
510  {
511  DEBUGF(INDI::Logger::DBG_ERROR, "Error iterating directory %s. %s", m_Device->getText("UPLOAD_SETTINGS")[0].getText(),
512  strerror(errno));
513  return false;
514  }
515 
516  if (maxIndex > 0)
517  {
518  char ts[32];
519  struct tm *tp;
520  time_t t;
521  time(&t);
522  tp = localtime(&t);
523  strftime(ts, sizeof(ts), "%Y-%m-%dT%H-%M-%S", tp);
524  std::string filets(ts);
525  prefix = std::regex_replace(prefix, std::regex("ISO8601"), filets);
526 
527  char indexString[8];
528  snprintf(indexString, 8, "%03d", maxIndex);
529  std::string prefixIndex = indexString;
530  //prefix.replace(prefix.find("XXX"), std::string::npos, prefixIndex);
531  prefix = std::regex_replace(prefix, std::regex("XXX"), prefixIndex);
532  }
533 
534  char processedFileName[MAXINDINAME];
535 
536  snprintf(processedFileName, MAXINDINAME, "%s/%s_%s.%s", m_Device->getText("UPLOAD_SETTINGS")[0].getText(), prefix.c_str(),
537  m_Name, format);
538 
539  fp = fopen(processedFileName, "w");
540  if (fp == nullptr)
541  {
542  DEBUGF(INDI::Logger::DBG_ERROR, "Unable to save image file (%s). %s", processedFileName, strerror(errno));
543  return false;
544  }
545 
546  int n = 0;
547  for (int nr = 0; nr < static_cast<int>(FitsB.bloblen); nr += n)
548  n = fwrite((static_cast<char *>(FitsB.blob) + nr), 1, FitsB.bloblen - nr, fp);
549 
550  fclose(fp);
551  LOGF_INFO("File saved in %s.", processedFileName);
552  }
553 
554  if (sendCapture)
555  {
556 
557  auto start = std::chrono::high_resolution_clock::now();
558  IDSetBLOB(&FitsBP, nullptr);
559  auto end = std::chrono::high_resolution_clock::now();
560  std::chrono::duration<double> diff = end - start;
561  LOGF_DEBUG("BLOB transfer took %g seconds", diff.count());
562  }
563 
564  FitsBP.s = IPS_OK;
565 
566  DEBUG(INDI::Logger::DBG_DEBUG, "Upload complete");
567 
568  return true;
569 }
570 
571 int Interface::getFileIndex(const char *dir, const char *prefix, const char *ext)
572 {
573  INDI_UNUSED(ext);
574 
575  DIR *dpdf = nullptr;
576  struct dirent *epdf = nullptr;
577  std::vector<std::string> files = std::vector<std::string>();
578 
579  std::string prefixIndex = prefix;
580  prefixIndex = regex_replace_compat(prefixIndex, "_ISO8601", "");
581  prefixIndex = regex_replace_compat(prefixIndex, "_XXX", "");
582 
583  // Create directory if does not exist
584  struct stat st;
585 
586  if (stat(dir, &st) == -1)
587  {
588  LOGF_DEBUG("Creating directory %s...", dir);
589  if (INDI::mkpath(dir, 0755) == -1)
590  LOGF_ERROR("Error creating directory %s (%s)", dir, strerror(errno));
591  }
592 
593  dpdf = opendir(dir);
594  if (dpdf != nullptr)
595  {
596  while ((epdf = readdir(dpdf)))
597  {
598  if (strstr(epdf->d_name, prefixIndex.c_str()))
599  files.push_back(epdf->d_name);
600  }
601  closedir(dpdf);
602  }
603  else
604  return -1;
605 
606  int maxIndex = 0;
607 
608  for (unsigned long i = 0; i < static_cast<unsigned long>(files.size()); i++)
609  {
610  int index = -1;
611 
612  std::string file = files.at(i);
613  std::size_t start = file.find_last_of("_");
614  std::size_t end = file.find_last_of(".");
615  if (start != std::string::npos)
616  {
617  index = atoi(file.substr(start + 1, end).c_str());
618  if (index > maxIndex)
619  maxIndex = index;
620  }
621  }
622 
623  return (maxIndex + 1);
624 }
625 
626 bool Interface::setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
627 {
628  stream->sizes = (int*)realloc(stream->sizes, sizeof(int));
629  stream->dims = 0;
630  stream->len = 1;
634  for(uint32_t dim = 0; dim < dims; dim++)
635  dsp_stream_add_dim(stream, sizes[dim]);
637  switch (bits_per_sample)
638  {
639  case 8:
640  dsp_buffer_copy((static_cast<uint8_t *>(buf)), stream->buf, stream->len);
641  break;
642  case 16:
643  dsp_buffer_copy((static_cast<uint16_t *>(buf)), stream->buf, stream->len);
644  break;
645  case 32:
646  dsp_buffer_copy((static_cast<uint32_t *>(buf)), stream->buf, stream->len);
647  break;
648  case 64:
649  dsp_buffer_copy((static_cast<unsigned long *>(buf)), stream->buf, stream->len);
650  break;
651  case -32:
652  dsp_buffer_copy((static_cast<float *>(buf)), stream->buf, stream->len);
653  break;
654  case -64:
655  dsp_buffer_copy((static_cast<double *>(buf)), stream->buf, stream->len);
656  break;
657  default:
660  return false;
661  }
662  return true;
663 }
664 
665 bool Interface::setMagnitude(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
666 {
667  if(stream == nullptr) return false;
668  if(dims != (uint32_t)stream->dims) return false;
669  for(uint32_t d = 0; d < dims; d++)
670  if(sizes[d] != stream->sizes[d]) return false;
675  switch (bits_per_sample)
676  {
677  case 8:
678  dsp_buffer_copy((static_cast<uint8_t *>(buf)), stream->magnitude->buf, stream->len);
679  break;
680  case 16:
681  dsp_buffer_copy((static_cast<uint16_t *>(buf)), stream->magnitude->buf, stream->len);
682  break;
683  case 32:
684  dsp_buffer_copy((static_cast<uint32_t *>(buf)), stream->magnitude->buf, stream->len);
685  break;
686  case 64:
687  dsp_buffer_copy((static_cast<unsigned long *>(buf)), stream->magnitude->buf, stream->len);
688  break;
689  case -32:
690  dsp_buffer_copy((static_cast<float *>(buf)), stream->magnitude->buf, stream->len);
691  break;
692  case -64:
693  dsp_buffer_copy((static_cast<double *>(buf)), stream->magnitude->buf, stream->len);
694  break;
695  default:
698  return false;
699  }
700  return true;
701 }
702 
703 bool Interface::setPhase(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
704 {
705  if(stream == nullptr) return false;
706  if(dims != (uint32_t)stream->dims) return false;
707  for(uint32_t d = 0; d < dims; d++)
708  if(sizes[d] != stream->sizes[d]) return false;
713  switch (bits_per_sample)
714  {
715  case 8:
716  dsp_buffer_copy((static_cast<uint8_t *>(buf)), stream->magnitude->buf, stream->len);
717  break;
718  case 16:
719  dsp_buffer_copy((static_cast<uint16_t *>(buf)), stream->magnitude->buf, stream->len);
720  break;
721  case 32:
722  dsp_buffer_copy((static_cast<uint32_t *>(buf)), stream->magnitude->buf, stream->len);
723  break;
724  case 64:
725  dsp_buffer_copy((static_cast<unsigned long *>(buf)), stream->magnitude->buf, stream->len);
726  break;
727  case -32:
728  dsp_buffer_copy((static_cast<float *>(buf)), stream->magnitude->buf, stream->len);
729  break;
730  case -64:
731  dsp_buffer_copy((static_cast<double *>(buf)), stream->magnitude->buf, stream->len);
732  break;
733  default:
736  return false;
737  }
738  return true;
739 }
740 
741 bool Interface::setReal(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
742 {
743  if(stream == nullptr) return false;
744  if(dims != (uint32_t)stream->dims) return false;
745  for(uint32_t d = 0; d < dims; d++)
746  if(sizes[d] != stream->sizes[d]) return false;
747  if(stream->dft.buf == nullptr)
748  stream->dft.buf = (double*)malloc(sizeof(double) * stream->len * 2);
749  else
750  stream->dft.buf = (double*)realloc(stream->dft.buf, sizeof(double) * stream->len * 2);
751  switch (bits_per_sample)
752  {
753  case 8:
754  dsp_buffer_copy_stepping((static_cast<uint8_t *>(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2);
755  break;
756  case 16:
757  dsp_buffer_copy_stepping((static_cast<uint16_t *>(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2);
758  break;
759  case 32:
760  dsp_buffer_copy_stepping((static_cast<uint32_t *>(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2);
761  break;
762  case 64:
763  dsp_buffer_copy_stepping((static_cast<unsigned long *>(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2);
764  break;
765  case -32:
766  dsp_buffer_copy_stepping((static_cast<float *>(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2);
767  break;
768  case -64:
769  dsp_buffer_copy_stepping((static_cast<double *>(buf)), stream->dft.buf, stream->len, stream->len * 2, 1, 2);
770  break;
771  default:
772  return false;
773  }
774  return true;
775 }
776 
777 bool Interface::setImaginary(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
778 {
779  if(stream == nullptr) return false;
780  if(dims != (uint32_t)stream->dims) return false;
781  for(uint32_t d = 0; d < dims; d++)
782  if(sizes[d] != stream->sizes[d]) return false;
783  if(stream->dft.buf == nullptr)
784  stream->dft.buf = (double*)malloc(sizeof(double) * stream->len * 2);
785  else
786  stream->dft.buf = (double*)realloc(stream->dft.buf, sizeof(double) * stream->len * 2);
787  switch (bits_per_sample)
788  {
789  case 8:
790  dsp_buffer_copy_stepping((static_cast<uint8_t *>(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2);
791  break;
792  case 16:
793  dsp_buffer_copy_stepping((static_cast<uint16_t *>(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1,
794  2);
795  break;
796  case 32:
797  dsp_buffer_copy_stepping((static_cast<uint32_t *>(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1,
798  2);
799  break;
800  case 64:
801  dsp_buffer_copy_stepping((static_cast<unsigned long *>(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2,
802  1, 2);
803  break;
804  case -32:
805  dsp_buffer_copy_stepping((static_cast<float *>(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2);
806  break;
807  case -64:
808  dsp_buffer_copy_stepping((static_cast<double *>(buf)), ((double*)&stream->dft.buf[1]), stream->len, stream->len * 2, 1, 2);
809  break;
810  default:
811  return false;
812  }
813  return true;
814 }
815 
817 {
818  buffer = realloc(buffer, stream->len * getBPS() / 8);
819  switch (getBPS())
820  {
821  case 8:
822  dsp_buffer_copy(stream->buf, (static_cast<uint8_t *>(buffer)), stream->len);
823  break;
824  case 16:
825  dsp_buffer_copy(stream->buf, (static_cast<uint16_t *>(buffer)), stream->len);
826  break;
827  case 32:
828  dsp_buffer_copy(stream->buf, (static_cast<uint32_t *>(buffer)), stream->len);
829  break;
830  case 64:
831  dsp_buffer_copy(stream->buf, (static_cast<unsigned long *>(buffer)), stream->len);
832  break;
833  case -32:
834  dsp_buffer_copy(stream->buf, (static_cast<float *>(buffer)), stream->len);
835  break;
836  case -64:
837  dsp_buffer_copy(stream->buf, (static_cast<double *>(buffer)), stream->len);
838  break;
839  default:
840  free (buffer);
841  break;
842  }
843  return static_cast<uint8_t *>(buffer);
844 }
845 
847 {
848  buffer = malloc(stream->len * getBPS() / 8);
849  switch (getBPS())
850  {
851  case 8:
852  dsp_buffer_copy(stream->magnitude->buf, (static_cast<uint8_t *>(buffer)), stream->len);
853  break;
854  case 16:
855  dsp_buffer_copy(stream->magnitude->buf, (static_cast<uint16_t *>(buffer)), stream->len);
856  break;
857  case 32:
858  dsp_buffer_copy(stream->magnitude->buf, (static_cast<uint32_t *>(buffer)), stream->len);
859  break;
860  case 64:
861  dsp_buffer_copy(stream->magnitude->buf, (static_cast<unsigned long *>(buffer)), stream->len);
862  break;
863  case -32:
864  dsp_buffer_copy(stream->magnitude->buf, (static_cast<float *>(buffer)), stream->len);
865  break;
866  case -64:
867  dsp_buffer_copy(stream->magnitude->buf, (static_cast<double *>(buffer)), stream->len);
868  break;
869  default:
870  free (buffer);
871  break;
872  }
873  return static_cast<uint8_t *>(buffer);
874 }
875 
876 uint8_t* Interface::getBuffer(dsp_stream_p in, uint32_t *dims, int **sizes)
877 {
878  void *buffer = malloc(in->len * getBPS() / 8);
879  switch (getBPS())
880  {
881  case 8:
882  dsp_buffer_copy(in->buf, (static_cast<uint8_t *>(buffer)), in->len);
883  break;
884  case 16:
885  dsp_buffer_copy(in->buf, (static_cast<uint16_t *>(buffer)), in->len);
886  break;
887  case 32:
888  dsp_buffer_copy(in->buf, (static_cast<uint32_t *>(buffer)), in->len);
889  break;
890  case 64:
891  dsp_buffer_copy(in->buf, (static_cast<unsigned long *>(buffer)), in->len);
892  break;
893  case -32:
894  dsp_buffer_copy(in->buf, (static_cast<float *>(buffer)), in->len);
895  break;
896  case -64:
897  dsp_buffer_copy(in->buf, (static_cast<double *>(buffer)), in->len);
898  break;
899  default:
900  free (buffer);
901  break;
902  }
903  *dims = in->dims;
904  *sizes = (int*)malloc(sizeof(int) * in->dims);
905  for(int d = 0; d < in->dims; d++)
906  *sizes[d] = in->sizes[d];
907  return static_cast<uint8_t *>(buffer);
908 }
909 
911 {
912  snprintf(captureExtention, MAXINDIBLOBFMT, "%s", ext);
913 }
914 }
bool setImaginary(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
Interface(INDI::DefaultDevice *dev, Type type=DSP_NONE, const char *name="DSP_PLUGIN", const char *label="DSP Plugin")
const char * getDeviceName()
virtual bool ISNewText(const char *dev, const char *name, char *texts[], char *names[], int n)
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n)
uint8_t * getStream()
virtual void ISGetProperties(const char *dev)
virtual void Activated()
Activated Called after activation from client application.
ISwitchVectorProperty ActivateSP
Definition: dspinterface.h:183
virtual ~Interface()
void setCaptureFileExtension(const char *ext)
setIntegrationFileExtension Set the returned file extension.
uint8_t * getMagnitude()
virtual bool ISNewBLOB(const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
int getBPS()
getBPS Get the returned file bit depth/sample size.
Definition: dspinterface.h:137
virtual bool updateProperties()
virtual bool saveConfigItems(FILE *fp)
virtual bool processBLOB(uint8_t *buf, uint32_t ndims, int *dims, int bits_per_sample)
processBLOB Propagate to Callback and generate BLOBs for parent device.
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n)
bool setReal(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
void setSizes(uint32_t num, int *sizes)
setSizes Set the returned file dimensions and corresponding sizes.
Definition: dspinterface.h:107
dsp_stream_p stream
Definition: dspinterface.h:213
IBLOBVectorProperty FitsBP
Definition: dspinterface.h:180
ISwitch ActivateS[2]
Definition: dspinterface.h:184
const char * m_Label
Definition: dspinterface.h:200
bool setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
INDI::DefaultDevice * m_Device
Definition: dspinterface.h:198
const char * m_Name
Definition: dspinterface.h:199
dsp_stream_p loadFITS(char *buf, int len)
loadFITS Converts FITS data into a dsp_stream structure pointer.
void setBPS(int bps)
setBPS Set the returned file bit depth/sample size.
Definition: dspinterface.h:128
bool setMagnitude(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
virtual uint8_t * Callback(uint8_t *buf, uint32_t ndims, int *dims, int bits_per_sample)
Callback Called by processBLOB.
uint8_t * getBuffer(dsp_stream_p in, uint32_t *dims, int **sizes)
bool setPhase(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
virtual void Deactivated()
Deactivated Called after deactivation from client application.
bool isConnected() const
Definition: basedevice.cpp:520
INDI::PropertyNumber getNumber(const char *name) const
Definition: basedevice.cpp:89
const char * getDeviceName() const
Definition: basedevice.cpp:821
INDI::PropertySwitch getSwitch(const char *name) const
Definition: basedevice.cpp:99
INDI::PropertyText getText(const char *name) const
Definition: basedevice.cpp:94
Class to provide extended functionality for devices in addition to the functionality provided by INDI...
virtual bool deleteProperty(const char *propertyName)
Delete a property and unregister it. It will also be deleted from all clients.
void defineProperty(INumberVectorProperty *property)
IPState getState() const
INDI::PropertyViewText * getText() const
int errno
struct dsp_stream_t * phase
Fourier transform phase.
Definition: dsp.h:413
int * sizes
Sizes of each dimension.
Definition: dsp.h:373
dsp_complex dft
Fourier transform.
Definition: dsp.h:377
double * buf
Linear double array containing complex numbers.
Definition: dsp.h:310
struct dsp_stream_t * magnitude
Fourier transform magnitude.
Definition: dsp.h:411
int dims
Number of dimensions of the buffers.
Definition: dsp.h:371
dsp_t * buf
buffer
Definition: dsp.h:375
int len
The buffers length.
Definition: dsp.h:369
#define dsp_buffer_copy(in, out, len)
Fill the output buffer with the values of the elements of the input stream by casting them to the out...
Definition: dsp.h:1038
#define dsp_buffer_copy_stepping(in, out, inlen, outlen, instep, outstep)
Fill the output buffer with the values of the elements of the input stream by casting them to the out...
Definition: dsp.h:1059
#define dsp_buffer_set(buf, len, _val)
Fill the buffer with the passed value.
Definition: dsp.h:815
DLL_EXPORT void dsp_stream_free(dsp_stream_p stream)
Free the DSP stream passed as argument.
Definition: stream.c:163
DLL_EXPORT dsp_stream_p dsp_stream_copy(dsp_stream_p stream)
Create a copy of the DSP stream passed as argument.
Definition: stream.c:192
DLL_EXPORT dsp_stream_p dsp_stream_new(void)
Allocate a new DSP stream type.
Definition: stream.c:124
DLL_EXPORT void dsp_stream_add_dim(dsp_stream_p stream, int len)
Add a dimension with length len to a DSP stream.
Definition: stream.c:227
DLL_EXPORT void dsp_stream_alloc_buffer(dsp_stream_p stream, int len)
Allocate a buffer with length len on the stream passed as argument.
Definition: stream.c:78
DLL_EXPORT void dsp_stream_free_buffer(dsp_stream_p stream)
Free the buffer of the DSP Stream passed as argument.
Definition: stream.c:112
DLL_EXPORT dsp_stream_p * dsp_file_read_fits(const char *filename, int *channels, int stretch)
Read a FITS file and fill a dsp_stream_p with its content.
Definition: file.c:27
ISState
Switch state.
Definition: indiapi.h:150
@ ISS_OFF
Definition: indiapi.h:151
@ ISS_ON
Definition: indiapi.h:152
#define MAXINDIBLOBFMT
Definition: indiapi.h:196
#define MAXINDIDEVICE
Definition: indiapi.h:193
#define MAXINDIFORMAT
Definition: indiapi.h:195
@ IP_RW
Definition: indiapi.h:186
@ IP_RO
Definition: indiapi.h:184
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
#define MAXINDILABEL
Definition: indiapi.h:192
@ ISR_1OFMANY
Definition: indiapi.h:173
#define MAXINDINAME
Definition: indiapi.h:191
int fs_sexa(char *out, double a, int w, int fracbase)
Converts a sexagesimal number to a string. sprint the variable a in sexagesimal format into out[].
Definition: indicom.c:141
Implementations for common driver routines.
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 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
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: indidevapi.c:310
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: indidevapi.c:216
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
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
void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
Definition: indidriver.c:1287
#define LOGF_INFO(fmt,...)
Definition: indilogger.h:82
#define DEBUG(priority, msg)
Macro to print log messages. Example of usage of the Logger: DEBUG(DBG_DEBUG, "hello " << "world");.
Definition: indilogger.h:56
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
#define LOGF_ERROR(fmt,...)
Definition: indilogger.h:80
#define DEBUGF(priority, msg,...)
Definition: indilogger.h:57
int fd
Definition: intelliscope.c:43
std::vector< uint8_t > buffer
The DSP Namespace adds signal processing to INDI drivers. Primarily written for sensors and detectors...
Definition: convolution.cpp:40
const char * DSP_TAB
void ObservedToJ2000(IEquatorialCoordinates *observed, double jd, IEquatorialCoordinates *J2000pos)
ObservedToJ2000 converts an observed position to a J2000 catalogue position removes aberration,...
Definition: libastro.cpp:50
int mkpath(std::string s, mode_t mode)
Definition: indiutility.cpp:51
__le16 type
Definition: pwc-ioctl.h:0
Holds the connection type.
char name[MAXINDINAME]
Definition: indiapi.h:475
char name[MAXINDINAME]
Definition: indiapi.h:371
Contains a set of informations and data relative to a buffer and how to use it.
Definition: dsp.h:363