Instrument Neutral Distributed Interface INDI  1.9.5
indiccdchip.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2019 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 #include "indiccdchip.h"
19 #include "indidevapi.h"
20 #include "locale_compat.h"
21 
22 #include <cstring>
23 #include <ctime>
24 
25 namespace INDI
26 {
27 
29 {
30  strncpy(ImageExtention, "fits", MAXINDIBLOBFMT);
31 }
32 
34 {
35  delete [] RawFrame;
36  delete[] BinFrame;
37 }
38 
39 void CCDChip::setFrameType(CCD_FRAME type)
40 {
41  FrameType = type;
42 }
43 
44 void CCDChip::setResolution(uint32_t x, uint32_t y)
45 {
46  XRes = x;
47  YRes = y;
48 
49  ImagePixelSizeN[0].value = x;
50  ImagePixelSizeN[1].value = y;
51 
52  IDSetNumber(&ImagePixelSizeNP, nullptr);
53 
54  ImageFrameN[FRAME_X].min = 0;
55  ImageFrameN[FRAME_X].max = x - 1;
56  ImageFrameN[FRAME_Y].min = 0;
57  ImageFrameN[FRAME_Y].max = y - 1;
58 
59  ImageFrameN[FRAME_W].min = 1;
60  ImageFrameN[FRAME_W].max = x;
61  ImageFrameN[FRAME_H].min = 1;
62  ImageFrameN[FRAME_H].max = y;
63  IUUpdateMinMax(&ImageFrameNP);
64 }
65 
66 void CCDChip::setFrame(uint32_t subx, uint32_t suby, uint32_t subw, uint32_t subh)
67 {
68  SubX = subx;
69  SubY = suby;
70  SubW = subw;
71  SubH = subh;
72 
73  ImageFrameN[FRAME_X].value = SubX;
74  ImageFrameN[FRAME_Y].value = SubY;
75  ImageFrameN[FRAME_W].value = SubW;
76  ImageFrameN[FRAME_H].value = SubH;
77 
78  IDSetNumber(&ImageFrameNP, nullptr);
79 }
80 
81 void CCDChip::setBin(uint8_t hor, uint8_t ver)
82 {
83  BinX = hor;
84  BinY = ver;
85 
86  ImageBinN[BIN_W].value = BinX;
87  ImageBinN[BIN_H].value = BinY;
88 
89  IDSetNumber(&ImageBinNP, nullptr);
90 }
91 
92 void CCDChip::setMinMaxStep(const char *property, const char *element, double min, double max, double step,
93  bool sendToClient)
94 {
95  INumberVectorProperty *nvp = nullptr;
96 
97  if (!strcmp(property, ImageExposureNP.name))
98  nvp = &ImageExposureNP;
99  else if (!strcmp(property, ImageFrameNP.name))
100  nvp = &ImageFrameNP;
101  else if (!strcmp(property, ImageBinNP.name))
102  nvp = &ImageBinNP;
103  else if (!strcmp(property, ImagePixelSizeNP.name))
104  nvp = &ImagePixelSizeNP;
105  // else if (!strcmp(property, RapidGuideDataNP.name))
106  // nvp = &RapidGuideDataNP;
107  else
108  return;
109 
110  INumber *np = IUFindNumber(nvp, element);
111  if (np)
112  {
113  np->min = min;
114  np->max = max;
115  np->step = step;
116 
117  if (sendToClient)
118  IUUpdateMinMax(nvp);
119  }
120 }
121 
122 void CCDChip::setPixelSize(double x, double y)
123 {
124  PixelSizeX = x;
125  PixelSizeY = y;
126 
127  ImagePixelSizeN[2].value = x;
128  ImagePixelSizeN[3].value = x;
129  ImagePixelSizeN[4].value = y;
130 
131  IDSetNumber(&ImagePixelSizeNP, nullptr);
132 }
133 
134 void CCDChip::setBPP(uint8_t bbp)
135 {
136  BitsPerPixel = bbp;
137 
138  ImagePixelSizeN[5].value = BitsPerPixel;
139 
140  IDSetNumber(&ImagePixelSizeNP, nullptr);
141 }
142 
143 void CCDChip::setFrameBufferSize(uint32_t nbuf, bool allocMem)
144 {
145  if (nbuf == RawFrameSize)
146  return;
147 
148  RawFrameSize = nbuf;
149 
150  if (allocMem == false)
151  return;
152 
153  delete [] RawFrame;
154  RawFrame = new uint8_t[nbuf];
155 
156  if (BinFrame)
157  {
158  delete [] BinFrame;
159  BinFrame = new uint8_t[nbuf];
160  }
161 }
162 
163 void CCDChip::setExposureLeft(double duration)
164 {
165  ImageExposureNP.s = IPS_BUSY;
166  ImageExposureN[0].value = duration;
167  IDSetNumber(&ImageExposureNP, nullptr);
168 }
169 
171 {
172  ImageExposureNP.s = IPS_OK;
173  ImageExposureN[0].value = 0;
174  IDSetNumber(&ImageExposureNP, nullptr);
175 }
176 
177 void CCDChip::setExposureDuration(double duration)
178 {
179  ExposureDuration = duration;
180  gettimeofday(&StartExposureTime, nullptr);
181 }
182 
183 const char *CCDChip::getFrameTypeName(CCD_FRAME fType)
184 {
185  return FrameTypeS[fType].name;
186 }
187 
188 const char *CCDChip::getExposureStartTime()
189 {
190  static char ts[32];
191 
192  char iso8601[32] = {0};
193  struct tm *tp = nullptr;
194 
195  // Get exposure startup timestamp
196  time_t t = static_cast<time_t>(StartExposureTime.tv_sec);
197 
198  // Get UTC timestamp
199  tp = gmtime(&t);
200 
201  // Format it in ISO8601 format
202  strftime(iso8601, sizeof(iso8601), "%Y-%m-%dT%H:%M:%S", tp);
203 
204  // Add millisecond
205  snprintf(ts, 32, "%s.%03d", iso8601, static_cast<int>(StartExposureTime.tv_usec / 1000.0));
206 
207  return (ts);
208 }
209 
210 //void CCDChip::setInterlaced(bool intr)
211 //{
212 // Interlaced = intr;
213 //}
214 
216 {
217  ImageExposureNP.s = IPS_ALERT;
218  IDSetNumber(&ImageExposureNP, nullptr);
219 }
220 
221 int CCDChip::getNAxis() const
222 {
223  return NAxis;
224 }
225 
226 void CCDChip::setNAxis(int value)
227 {
228  NAxis = value;
229 }
230 
231 void CCDChip::setImageExtension(const char *ext)
232 {
233  strncpy(ImageExtention, ext, MAXINDIBLOBFMT);
234 }
235 
236 void CCDChip::binFrame()
237 {
238  if (BinX == 1)
239  return;
240 
241  // Jasem: Keep full frame shadow in memory to enhance performance and just swap frame pointers after operation is complete
242  if (BinFrame == nullptr)
243  BinFrame = new uint8_t[RawFrameSize];
244 
245  memset(BinFrame, 0, RawFrameSize);
246 
247  switch (getBPP())
248  {
249  case 8:
250  {
251  uint8_t *bin_buf = BinFrame;
252  // Try to average pixels since in 8bit they get saturated pretty quickly
253  double factor = (BinX * BinX) / 2;
254  double accumulator = 0;
255 
256  for (uint32_t i = 0; i < SubH; i += BinX)
257  for (uint32_t j = 0; j < SubW; j += BinX)
258  {
259  accumulator = 0;
260  for (int k = 0; k < BinX; k++)
261  {
262  for (int l = 0; l < BinX; l++)
263  {
264  accumulator += *(RawFrame + j + (i + k) * SubW + l);
265  }
266  }
267 
268  accumulator /= factor;
269  if (accumulator > UINT8_MAX)
270  *bin_buf = UINT8_MAX;
271  else
272  *bin_buf += static_cast<uint8_t>(accumulator);
273  bin_buf++;
274  }
275  }
276  break;
277 
278  case 16:
279  {
280  uint16_t *bin_buf = reinterpret_cast<uint16_t *>(BinFrame);
281  uint16_t *RawFrame16 = reinterpret_cast<uint16_t *>(RawFrame);
282  uint16_t val;
283 
284  for (uint32_t i = 0; i < SubH; i += BinX)
285  for (uint32_t j = 0; j < SubW; j += BinX)
286  {
287  for (int k = 0; k < BinX; k++)
288  {
289  for (int l = 0; l < BinX; l++)
290  {
291  val = *(RawFrame16 + j + (i + k) * SubW + l);
292  if (val + *bin_buf > UINT16_MAX)
293  *bin_buf = UINT16_MAX;
294  else
295  *bin_buf += val;
296  }
297  }
298  bin_buf++;
299  }
300  }
301  break;
302 
303  default:
304  return;
305  }
306 
307  // Swap frame pointers
308  uint8_t *rawFramePointer = RawFrame;
309  RawFrame = BinFrame;
310  // We just memset it next time we use it
311  BinFrame = rawFramePointer;
312 }
313 
314 
315 // Thx8411:
316 // Binning Bayer frames
317 // Each raw frame pixel is mapped and summed onto the binned frame
318 // The right place of each pixel in the 2x2 Bayer matrix is found by :
319 // (((i/BinX) & 0xFFFFFFFE) + (i & 0x00000001))
320 // and
321 // ((j/BinX) & 0xFFFFFFFE) + (j & 0x00000001)
322 //
324 {
325  if (BinX == 1)
326  return;
327 
328  // Jasem: Keep full frame shadow in memory to enhance performance and just swap frame pointers after operation is complete
329  if (BinFrame == nullptr)
330  BinFrame = new uint8_t[RawFrameSize];
331 
332  memset(BinFrame, 0, RawFrameSize);
333 
334  switch (getBPP())
335  {
336  // 8 bpp frame
337  case 8:
338  {
339  uint32_t BinFrameOffset;
340  uint32_t val;
341  uint32_t BinW=SubW/BinX;
342  uint8_t BinFactor=BinX*BinY;
343  uint32_t RawOffset=0;
344  uint32_t BinOffsetH;
345 
346  // for each raw frame row
347  for (uint32_t i = 0; i < SubH; i++)
348  {
349  // find the binned frame row
350  BinOffsetH=(((i/BinY) & 0xFFFFFFFE) + (i & 0x00000001)) * BinW;
351  // for each raw column
352  for (uint32_t j = 0; j < SubW; j++)
353  {
354  // find the proper position in the binned frame
355  BinFrameOffset=BinOffsetH + ((j/BinX) & 0xFFFFFFFE) + (j & 0x00000001);
356  // get the existing value in the binned frame
357  val=BinFrame[BinFrameOffset];
358  // add the new value, averaged and caped
359  val+=RawFrame[RawOffset]/BinFactor;
360  if(val>UINT8_MAX)
361  val=UINT8_MAX;
362  // write back into the binned frame
363  BinFrame[BinFrameOffset]=(uint8_t)val;
364  // next binned frame pixel
365  RawOffset++;
366  }
367  }
368  }
369  break;
370 
371  // 16 bpp frame
372  case 16:
373  {
374  // works the same as the 8 bits version, without averaging but
375  // mapped onto 16 bits pixel
376  uint16_t *RawFrame16 = reinterpret_cast<uint16_t *>(RawFrame);
377  uint16_t *BinFrame16 = reinterpret_cast<uint16_t *>(BinFrame);
378 
379  uint32_t BinFrameOffset;
380  uint32_t val;
381  uint32_t BinW=SubW/BinX;
382  uint32_t RawOffset=0;
383  uint32_t BinOffsetH;
384 
385  for (uint32_t i = 0; i < SubH; i++)
386  {
387  BinOffsetH=(((i/BinY) & 0xFFFFFFFE) + (i & 0x00000001)) * BinW;
388  for (uint32_t j = 0; j < SubW; j++)
389  {
390  BinFrameOffset=BinOffsetH + ((j/BinX) & 0xFFFFFFFE) + (j & 0x00000001);
391  val=BinFrame16[BinFrameOffset];
392  val+=RawFrame16[RawOffset];
393  if(val>UINT16_MAX)
394  val=UINT16_MAX;
395  BinFrame16[BinFrameOffset]=(uint16_t)val;
396  RawOffset++;
397  }
398  }
399 
400  }
401  break;
402 
403  default:
404  return;
405  }
406 
407  // Swap frame pointers
408  uint8_t *rawFramePointer = RawFrame;
409  RawFrame = BinFrame;
410  // We just memset it next time we use it
411  BinFrame = rawFramePointer;
412 }
413 
414 }
INDI::CCDChip::setFrameBufferSize
void setFrameBufferSize(uint32_t nbuf, bool allocMem=true)
setFrameBufferSize Set desired frame buffer size. The function will allocate memory accordingly....
Definition: indiccdchip.cpp:159
INDI::CCDChip::getFrameTypeName
const char * getFrameTypeName(CCD_FRAME fType)
getFrameTypeName returns CCD Frame type name
Definition: indiccdchip.cpp:199
INDI::CCDChip::setBin
void setBin(uint8_t hor, uint8_t ver)
setBin Set CCD Chip binnig
Definition: indiccdchip.cpp:97
indiccdchip.h
IUUpdateMinMax
void IUUpdateMinMax(const INumberVectorProperty *nvp)
Function to update the min and max elements of a number in the client.
Definition: indidriver.c:1850
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
min
double min(void)
locale_compat.h
INDI::CCDChip::setFrameType
void setFrameType(CCD_FRAME type)
setFrameType Set desired frame type for next exposure.
Definition: indiccdchip.cpp:55
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
INumber
One number descriptor.
MAXINDIBLOBFMT
#define MAXINDIBLOBFMT
Definition: indiapi.h:195
INDI::CCDChip::FRAME_X
@ FRAME_X
Definition: indiccdchip.h:71
INDI::CCDChip::setExposureDuration
void setExposureDuration(double duration)
setExposureDuration Set desired CCD frame exposure duration for next exposure. You must call this fun...
Definition: indiccdchip.cpp:193
INDI::CCDChip::setExposureLeft
void setExposureLeft(double duration)
setExposureLeft Update exposure time left. Inform the client of the new exposure time left value.
Definition: indiccdchip.cpp:179
max
double max(void)
INDI::CCDChip::setBPP
void setBPP(uint8_t bpp)
setBPP Set depth of CCD chip.
Definition: indiccdchip.cpp:150
INDI::CCDChip::setExposureComplete
void setExposureComplete()
setExposureComplete Mark exposure as complete by setting ImageExposure property to IPS_OK
Definition: indiccdchip.cpp:186
INDI::CCDChip::setExposureFailed
void setExposureFailed()
setExposureFailed Alert the client that the exposure failed.
Definition: indiccdchip.cpp:231
INDI::CCDChip::BIN_H
@ BIN_H
Definition: indiccdchip.h:72
type
__le16 type
Definition: pwc-ioctl.h:2
_INumberVectorProperty
Number vector property descriptor.
Definition: indiapi.h:317
indidevapi.h
Interface to the reference INDI C API device implementation on the Device Driver side.
INDI::CCDChip::FRAME_W
@ FRAME_W
Definition: indiccdchip.h:71
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
INDI::CCDChip::CCDChip
CCDChip()
Definition: indiccdchip.cpp:44
INDI::CCDChip::getExposureStartTime
const char * getExposureStartTime()
getExposureStartTime
Definition: indiccdchip.cpp:204
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
INDI::CCDChip::getBPP
int getBPP() const
getBPP Get CCD Chip depth (bits per pixel).
Definition: indiccdchip.h:177
INDI::CCDChip::setImageExtension
void setImageExtension(const char *ext)
setImageExtension Set image exntension
Definition: indiccdchip.cpp:247
INDI::CCDChip::binBayerFrame
void binBayerFrame()
binBayerFrame Perform software binning on a 2x2 Bayer matrix CCD frame. Only use this function if har...
Definition: indiccdchip.cpp:339
IUFindNumber
INumber * IUFindNumber(const INumberVectorProperty *nvp, const char *name)
Find an INumber member in a number text property.
Definition: indicom.c:1372
INDI::CCDChip::setFrame
void setFrame(uint32_t subx, uint32_t suby, uint32_t subw, uint32_t subh)
setFrame Set desired frame resolutoin for an exposure.
Definition: indiccdchip.cpp:82
INDI::CCDChip::FRAME_Y
@ FRAME_Y
Definition: indiccdchip.h:71
INDI::CCDChip::setPixelSize
void setPixelSize(double x, double y)
setPixelSize Set CCD Chip pixel size
Definition: indiccdchip.cpp:138
INDI::CCDChip::getNAxis
int getNAxis() const
Definition: indiccdchip.cpp:237
INDI::CCDChip::setNAxis
void setNAxis(int value)
setNAxis Set FITS number of axis
Definition: indiccdchip.cpp:242
INDI
Namespace to encapsulate INDI client, drivers, and mediator classes.
Definition: AlignmentSubsystemForClients.cpp:11
INDI::CCDChip::~CCDChip
~CCDChip()
Definition: indiccdchip.cpp:49
INDI::CCDChip::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: indiccdchip.cpp:108
INDI::CCDChip::binFrame
void binFrame()
binFrame Perform software binning on the CCD frame. Only use this function if hardware binning is not...
Definition: indiccdchip.cpp:252
INDI::CCDChip::BIN_W
@ BIN_W
Definition: indiccdchip.h:72
IDSetNumber
void void void IDSetNumber(const INumberVectorProperty *n, const char *msg,...) ATTRIBUTE_FORMAT_PRINTF(2
Tell client to update an existing number vector property.
INDI::CCDChip::FRAME_H
@ FRAME_H
Definition: indiccdchip.h:71
INDI::CCDChip::setResolution
void setResolution(uint32_t x, uint32_t y)
setResolution set CCD Chip resolution
Definition: indiccdchip.cpp:60