Instrument Neutral Distributed Interface INDI 2.2.5
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
49static 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
56namespace DSP
57{
58const char *DSP_TAB = "Signal Processing";
59
60Interface::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,
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
100void 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
130bool 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
150bool 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
160bool 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
170bool 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
184uint8_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
194bool 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
235
240
242{
243 INDI_UNUSED(fp);
244 return true;
245}
246
247void 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 snprintf(fitsString, MAXINDIDEVICE, "%s", m_Device->getText("ACTIVE_DEVICES")[0].getText());
258 fits_update_key_s(fptr, TSTRING, "TELESCOP", fitsString, "Telescope name", &status);
259
260 // Observer
261 snprintf(fitsString, MAXINDIDEVICE, "%s", m_Device->getText("FITS_HEADER")[0].getText());
262 fits_update_key_s(fptr, TSTRING, "OBSERVER", fitsString, "Observer name", &status);
263
264 // Object
265 snprintf(fitsString, MAXINDIDEVICE, "%s", m_Device->getText("FITS_HEADER")[1].getText());
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
336void 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
343dsp_stream_p Interface::loadFITS(char* buffer, int len)
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
372bool 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
486bool 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
571int 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
626bool 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
665bool 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
703bool 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
741bool 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
777bool 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
876uint8_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
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.
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.
dsp_stream_p stream
IBLOBVectorProperty FitsBP
ISwitch ActivateS[2]
const char * m_Label
bool setStream(void *buf, uint32_t dims, int *sizes, int bits_per_sample)
INDI::DefaultDevice * m_Device
const char * m_Name
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.
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
INDI::PropertyNumber getNumber(const char *name) const
const char * getDeviceName() const
INDI::PropertySwitch getSwitch(const char *name) const
INDI::PropertyText getText(const char *name) const
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)
INDI::PropertyViewText * getText() const
int errno
struct dsp_stream_t * phase
Fourier transform phase.
Definition dsp.h:429
int * sizes
Sizes of each dimension.
Definition dsp.h:389
dsp_complex dft
Fourier transform.
Definition dsp.h:393
double * buf
Linear double array containing complex numbers.
Definition dsp.h:326
struct dsp_stream_t * magnitude
Fourier transform magnitude.
Definition dsp.h:427
int dims
Number of dimensions of the buffers.
Definition dsp.h:387
dsp_t * buf
buffer
Definition dsp.h:391
int len
The buffers length.
Definition dsp.h:385
#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:1054
#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:1075
#define dsp_buffer_set(buf, len, _val)
Fill the buffer with the passed value.
Definition dsp.h:831
DLL_EXPORT void dsp_stream_free(dsp_stream_p stream)
Free the DSP stream passed as argument.
Definition stream.c:167
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:200
DLL_EXPORT dsp_stream_p dsp_stream_new(void)
Allocate a new DSP stream type.
Definition stream.c:128
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:235
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:148
@ ISS_OFF
Definition indiapi.h:149
@ ISS_ON
Definition indiapi.h:150
#define MAXINDIBLOBFMT
Definition indiapi.h:194
#define MAXINDIDEVICE
Definition indiapi.h:191
#define MAXINDIFORMAT
Definition indiapi.h:193
@ IP_RW
Definition indiapi.h:184
@ IP_RO
Definition indiapi.h:182
@ IPS_BUSY
Definition indiapi.h:161
@ IPS_IDLE
Definition indiapi.h:159
@ IPS_OK
Definition indiapi.h:160
#define MAXINDILABEL
Definition indiapi.h:190
@ ISR_1OFMANY
Definition indiapi.h:171
#define MAXINDINAME
Definition indiapi.h:189
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:130
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:376
void IUFillSwitchVector(ISwitchVectorProperty *svp, ISwitch *sp, int nsp, const char *dev, const char *name, const char *label, const char *group, IPerm p, ISRule r, double timeout, IPState s)
Assign attributes for a switch vector property. The vector's auxiliary elements will be set to NULL.
Definition indidevapi.c:453
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:528
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:434
#define INDI_UNUSED(x)
Definition indidevapi.h:132
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
void IDSetSwitch(const ISwitchVectorProperty *svp, const char *fmt,...)
void IDSetBLOB(const IBLOBVectorProperty *bvp, const char *fmt,...)
#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
The DSP Namespace adds signal processing to INDI drivers. Primarily written for sensors and detectors...
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:51
int mkpath(std::string s, mode_t mode)
uint16_t type
Definition pwc-ioctl.h:0
Holds the connection type.
char name[MAXINDINAME]
Definition indiapi.h:473
char name[MAXINDINAME]
Definition indiapi.h:369
ISState s
Definition indiapi.h:353
Contains a set of information and data relative to a buffer and how to use it.
Definition dsp.h:379