Instrument Neutral Distributed Interface INDI  1.9.2
guide_simulator.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  Copyright(c) 2017 Jasem Mutlaq. All rights reserved.
3  Copyright(c) 2010 Gerry Rozema. All rights reserved.
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 "guide_simulator.h"
20 #include "indicom.h"
21 #include "stream/streammanager.h"
22 
23 #include "locale_compat.h"
24 
25 #include <libnova/julian_day.h>
26 #include <libastro.h>
27 
28 #include <cmath>
29 #include <unistd.h>
30 
31 static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
32 static pthread_mutex_t condMutex = PTHREAD_MUTEX_INITIALIZER;
33 
34 // We declare an auto pointer to GuideSim.
35 static std::unique_ptr<GuideSim> ccd(new GuideSim());
36 
38 {
39  currentRA = RA;
40  currentDE = Dec;
41 
42  streamPredicate = 0;
43  terminateThread = false;
44 
45  primaryFocalLength = 900; // focal length of the telescope in millimeters
46  guiderFocalLength = 300;
47 
48  time(&RunStart);
49 }
50 
51 bool GuideSim::SetupParms()
52 {
53  int nbuf;
54  SetCCDParams(SimulatorSettingsN[0].value, SimulatorSettingsN[1].value, 16, SimulatorSettingsN[2].value,
55  SimulatorSettingsN[3].value);
56 
57  if (HasCooler())
58  {
59  TemperatureN[0].value = 20;
60  IDSetNumber(&TemperatureNP, nullptr);
61  }
62 
63  // Kwiq
64  maxnoise = SimulatorSettingsN[8].value;
65  skyglow = SimulatorSettingsN[9].value;
66  maxval = SimulatorSettingsN[4].value;
67  bias = SimulatorSettingsN[5].value;
68  limitingmag = SimulatorSettingsN[7].value;
69  saturationmag = SimulatorSettingsN[6].value;
70  OAGoffset = SimulatorSettingsN[10].value; // An oag is offset this much from center of scope position (arcminutes);
71  polarError = SimulatorSettingsN[11].value;
72  polarDrift = SimulatorSettingsN[12].value;
73  rotationCW = SimulatorSettingsN[13].value;
74  // Kwiq++
75  king_gamma = SimulatorSettingsN[14].value * 0.0174532925;
76  king_theta = SimulatorSettingsN[15].value * 0.0174532925;
77  TimeFactor = SimulatorSettingsN[16].value;
78 
80  //nbuf += 512;
82 
83  Streamer->setPixelFormat(INDI_MONO, 16);
85 
86  return true;
87 }
88 
90 {
91  streamPredicate = 0;
92  terminateThread = false;
93  pthread_create(&primary_thread, nullptr, &streamVideoHelper, this);
95  return true;
96 }
97 
99 {
100  pthread_mutex_lock(&condMutex);
101  streamPredicate = 1;
102  terminateThread = true;
103  pthread_cond_signal(&cv);
104  pthread_mutex_unlock(&condMutex);
105 
106  return true;
107 }
108 
110 {
111  return "Guide Simulator";
112 }
113 
115 {
116  // Most hardware layers wont actually have indi properties defined
117  // but the simulators are a special case
119 
120  IUFillNumber(&SimulatorSettingsN[0], "SIM_XRES", "CCD X resolution", "%4.0f", 0, 8192, 0, 1280);
121  IUFillNumber(&SimulatorSettingsN[1], "SIM_YRES", "CCD Y resolution", "%4.0f", 0, 8192, 0, 1024);
122  IUFillNumber(&SimulatorSettingsN[2], "SIM_XSIZE", "CCD X Pixel Size", "%4.2f", 0, 60, 0, 5.2);
123  IUFillNumber(&SimulatorSettingsN[3], "SIM_YSIZE", "CCD Y Pixel Size", "%4.2f", 0, 60, 0, 5.2);
124  IUFillNumber(&SimulatorSettingsN[4], "SIM_MAXVAL", "CCD Maximum ADU", "%4.0f", 0, 65000, 0, 65000);
125  IUFillNumber(&SimulatorSettingsN[5], "SIM_BIAS", "CCD Bias", "%4.0f", 0, 6000, 0, 10);
126  IUFillNumber(&SimulatorSettingsN[6], "SIM_SATURATION", "Saturation Mag", "%4.1f", 0, 20, 0, 1.0);
127  IUFillNumber(&SimulatorSettingsN[7], "SIM_LIMITINGMAG", "Limiting Mag", "%4.1f", 0, 20, 0, 17.0);
128  IUFillNumber(&SimulatorSettingsN[8], "SIM_NOISE", "CCD Noise", "%4.0f", 0, 6000, 0, 10);
129  IUFillNumber(&SimulatorSettingsN[9], "SIM_SKYGLOW", "Sky Glow (magnitudes)", "%4.1f", 0, 6000, 0, 19.5);
130  IUFillNumber(&SimulatorSettingsN[10], "SIM_OAGOFFSET", "Oag Offset (arcminutes)", "%4.1f", 0, 6000, 0, 0);
131  IUFillNumber(&SimulatorSettingsN[11], "SIM_POLAR", "PAE (arcminutes)", "%4.1f", -600, 600, 0,
132  0); /* PAE = Polar Alignment Error */
133  IUFillNumber(&SimulatorSettingsN[12], "SIM_POLARDRIFT", "PAE Drift (minutes)", "%4.1f", 0, 6000, 0, 0);
134  IUFillNumber(&SimulatorSettingsN[13], "SIM_ROTATION", "Rotation CW (degrees)", "%4.1f", -360, 360, 0, 0);
135  IUFillNumber(&SimulatorSettingsN[14], "SIM_KING_GAMMA", "(CP,TCP), deg", "%4.1f", 0, 10, 0, 0);
136  IUFillNumber(&SimulatorSettingsN[15], "SIM_KING_THETA", "hour hangle, deg", "%4.1f", 0, 360, 0, 0);
137  IUFillNumber(&SimulatorSettingsN[16], "SIM_TIME_FACTOR", "Time Factor (x)", "%.2f", 0.01, 100, 0, 1);
138 
139  IUFillNumberVector(&SimulatorSettingsNP, SimulatorSettingsN, 17, getDeviceName(), "SIMULATOR_SETTINGS",
140  "Simulator Settings", "Simulator Config", IP_RW, 60, IPS_IDLE);
141 
142  // RGB Simulation
143  IUFillSwitch(&SimulateRgbS[0], "SIMULATE_YES", "Yes", ISS_OFF);
144  IUFillSwitch(&SimulateRgbS[1], "SIMULATE_NO", "No", ISS_ON);
145  IUFillSwitchVector(&SimulateRgbSP, SimulateRgbS, 2, getDeviceName(), "SIMULATE_RGB", "Simulate RGB",
146  "Simulator Config", IP_RW, ISR_1OFMANY, 60, IPS_IDLE);
147 
148  IUFillNumber(&FWHMN[0], "SIM_FWHM", "FWHM (arcseconds)", "%4.2f", 0, 60, 0, 7.5);
149  IUFillNumberVector(&FWHMNP, FWHMN, 1, ActiveDeviceT[ACTIVE_FOCUSER].text, "FWHM", "FWHM", OPTIONS_TAB, IP_RO, 60, IPS_IDLE);
150 
151  IUFillSwitch(&CoolerS[0], "COOLER_ON", "ON", ISS_OFF);
152  IUFillSwitch(&CoolerS[1], "COOLER_OFF", "OFF", ISS_ON);
153  IUFillSwitchVector(&CoolerSP, CoolerS, 2, getDeviceName(), "CCD_COOLER", "Cooler", MAIN_CONTROL_TAB, IP_WO,
154  ISR_1OFMANY, 0, IPS_IDLE);
155 
156  // CCD Gain
157  IUFillNumber(&GainN[0], "GAIN", "Gain", "%.f", 0, 100, 10, 50);
158  IUFillNumberVector(&GainNP, GainN, 1, getDeviceName(), "CCD_GAIN", "Gain", MAIN_CONTROL_TAB, IP_RW, 60, IPS_IDLE);
159 
160  IUFillNumber(&EqPEN[0], "RA_PE", "RA (hh:mm:ss)", "%010.6m", 0, 24, 0, 0);
161  IUFillNumber(&EqPEN[1], "DEC_PE", "DEC (dd:mm:ss)", "%010.6m", -90, 90, 0, 0);
162  IUFillNumberVector(&EqPENP, EqPEN, 2, getDeviceName(), "EQUATORIAL_PE", "EQ PE", "Simulator Config", IP_RW, 60,
163  IPS_IDLE);
164 
165 #ifdef USE_EQUATORIAL_PE
166  IDSnoopDevice(ActiveDeviceT[0].text, "EQUATORIAL_PE");
167 #else
168  IDSnoopDevice(ActiveDeviceT[ACTIVE_TELESCOPE].text, "EQUATORIAL_EOD_COORD");
169 #endif
170 
171 
173 
174  uint32_t cap = 0;
175 
176  cap |= CCD_CAN_ABORT;
177  cap |= CCD_CAN_BIN;
178  cap |= CCD_CAN_SUBFRAME;
179  cap |= CCD_HAS_SHUTTER;
180  cap |= CCD_HAS_ST4_PORT;
181  cap |= CCD_HAS_STREAMING;
182 
183 #ifdef HAVE_WEBSOCKET
184  cap |= CCD_HAS_WEB_SOCKET;
185 #endif
186 
187  SetCCDCapability(cap);
188 
189  // This should be called after the initial SetCCDCapability (above)
190  // as it modifies the capabilities.
191  setRGB(simulateRGB);
192 
193  addDebugControl();
194 
196 
197  // Make Guide Scope ON by default
200 
201  return true;
202 }
203 
204 void GuideSim::setRGB(bool onOff)
205 {
206  if (onOff)
207  {
209  IUSaveText(&BayerT[0], "0");
210  IUSaveText(&BayerT[1], "0");
211  IUSaveText(&BayerT[2], "RGGB");
212  }
213  else
214  {
216  }
217 }
218 
219 void GuideSim::ISGetProperties(const char * dev)
220 {
222 
223  defineProperty(&SimulatorSettingsNP);
224  defineProperty(&EqPENP);
225  defineProperty(&SimulateRgbSP);
226 }
227 
229 {
231 
232  if (isConnected())
233  {
234  if (HasCooler())
235  defineProperty(&CoolerSP);
236 
237  defineProperty(&GainNP);
238 
239  SetupParms();
240 
241  if (HasGuideHead())
242  {
243  SetGuiderParams(500, 290, 16, 9.8, 12.6);
245  }
246 
247  }
248  else
249  {
250  if (HasCooler())
251  deleteProperty(CoolerSP.name);
252 
253  deleteProperty(GainNP.name);
254  }
255 
256  return true;
257 }
258 
259 int GuideSim::SetTemperature(double temperature)
260 {
261  TemperatureRequest = temperature;
262  if (fabs(temperature - TemperatureN[0].value) < 0.1)
263  {
264  TemperatureN[0].value = temperature;
265  return 1;
266  }
267 
268  CoolerS[0].s = ISS_ON;
269  CoolerS[1].s = ISS_OFF;
270  CoolerSP.s = IPS_BUSY;
271  IDSetSwitch(&CoolerSP, nullptr);
272  return 0;
273 }
274 
275 bool GuideSim::StartExposure(float duration)
276 {
277  if (std::isnan(RA) && std::isnan(Dec))
278  {
279  LOG_ERROR("Telescope coordinates missing. Make sure telescope is connected and its name is set in CCD Options.");
280  return false;
281  }
282 
283  // for the simulator, we can just draw the frame now
284  // and it will get returned at the right time
285  // by the timer routines
286  AbortPrimaryFrame = false;
287  ExposureRequest = duration;
288 
290  gettimeofday(&ExpStart, nullptr);
291  // Leave the proper time showing for the draw routines
293  // Now compress the actual wait time
294  ExposureRequest = duration * TimeFactor;
295  InExposure = true;
296 
297  return true;
298 }
299 
301 {
302  GuideExposureRequest = n;
303  AbortGuideFrame = false;
306  gettimeofday(&GuideExpStart, nullptr);
307  InGuideExposure = true;
308  return true;
309 }
310 
312 {
313  if (!InExposure)
314  return true;
315 
316  AbortPrimaryFrame = true;
317 
318  return true;
319 }
320 
322 {
323  //IDLog("Enter AbortGuideExposure\n");
324  if (!InGuideExposure)
325  return true; // no need to abort if we aren't doing one
326  AbortGuideFrame = true;
327  return true;
328 }
329 
330 float GuideSim::CalcTimeLeft(timeval start, float req)
331 {
332  double timesince;
333  double timeleft;
334  struct timeval now
335  {
336  0, 0
337  };
338  gettimeofday(&now, nullptr);
339 
340  timesince =
341  (double)(now.tv_sec * 1000.0 + now.tv_usec / 1000) - (double)(start.tv_sec * 1000.0 + start.tv_usec / 1000);
342  timesince = timesince / 1000;
343  timeleft = req - timesince;
344  return timeleft;
345 }
346 
348 {
349  uint32_t nextTimer = getCurrentPollingPeriod();
350 
351  // No need to reset timer if we are not connected anymore
352  if (!isConnected())
353  return;
354 
355  if (InExposure)
356  {
357  if (AbortPrimaryFrame)
358  {
359  InExposure = false;
360  AbortPrimaryFrame = false;
361  }
362  else
363  {
364  float timeleft;
365  timeleft = CalcTimeLeft(ExpStart, ExposureRequest);
366 
367  //IDLog("CCD Exposure left: %g - Requset: %g\n", timeleft, ExposureRequest);
368  if (timeleft < 0)
369  timeleft = 0;
370 
371  PrimaryCCD.setExposureLeft(timeleft);
372 
373  if (timeleft < 1.0)
374  {
375  if (timeleft <= 0.001)
376  {
377  InExposure = false;
380  }
381  else
382  {
383  // set a shorter timer
384  nextTimer = timeleft * 1000;
385  }
386  }
387  }
388  }
389 
390  if (InGuideExposure)
391  {
392  float timeleft;
393  timeleft = CalcTimeLeft(GuideExpStart, GuideExposureRequest);
394 
395  //IDLog("GUIDE Exposure left: %g - Requset: %g\n", timeleft, GuideExposureRequest);
396 
397  if (timeleft < 0)
398  timeleft = 0;
399 
400  //ImageExposureN[0].value = timeleft;
401  //IDSetNumber(ImageExposureNP, nullptr);
402  GuideCCD.setExposureLeft(timeleft);
403 
404  if (timeleft < 1.0)
405  {
406  if (timeleft <= 0.001)
407  {
408  InGuideExposure = false;
409  if (!AbortGuideFrame)
410  {
411  GuideCCD.binFrame();
413  if (InGuideExposure)
414  {
415  // the call to complete triggered another exposure
416  timeleft = CalcTimeLeft(GuideExpStart, GuideExposureRequest);
417  if (timeleft < 1.0)
418  {
419  nextTimer = timeleft * 1000;
420  }
421  }
422  }
423  else
424  {
425  //IDLog("Not sending guide frame cuz of abort\n");
426  }
427  AbortGuideFrame = false;
428  }
429  else
430  {
431  nextTimer = timeleft * 1000; // set a shorter timer
432  }
433  }
434  }
435 
436  if (TemperatureNP.s == IPS_BUSY)
437  {
438  if (TemperatureRequest < TemperatureN[0].value)
439  TemperatureN[0].value = std::max(TemperatureRequest, TemperatureN[0].value - 0.5);
440  else
441  TemperatureN[0].value = std::min(TemperatureRequest, TemperatureN[0].value + 0.5);
442 
443 
444  IDSetNumber(&TemperatureNP, nullptr);
445 
446  // Above 20, cooler is off
447  if (TemperatureN[0].value >= 20)
448  {
449  CoolerS[0].s = ISS_OFF;
450  CoolerS[0].s = ISS_ON;
451  CoolerSP.s = IPS_IDLE;
452  IDSetSwitch(&CoolerSP, nullptr);
453  }
454  }
455 
456 
457  SetTimer(nextTimer);
458 }
459 
461 {
462  // CCD frame is 16 bit data
463  double exposure_time;
464  double targetFocalLength;
465 
466  uint16_t * ptr = reinterpret_cast<uint16_t *>(targetChip->getFrameBuffer());
467 
468  if (targetChip->getXRes() == 500)
469  exposure_time = GuideExposureRequest * 4;
470  else if (Streamer->isStreaming())
471  exposure_time = (ExposureRequest < 1) ? (ExposureRequest * 100) : ExposureRequest * 2;
472  else
473  exposure_time = ExposureRequest;
474 
475  if (GainN[0].value > 50)
476  exposure_time *= sqrt(GainN[0].value - 50);
477  else if (GainN[0].value < 50)
478  exposure_time /= sqrt(50 - GainN[0].value);
479 
481  targetFocalLength = primaryFocalLength;
482  else
483  targetFocalLength = guiderFocalLength;
484 
485  if (ShowStarField)
486  {
487  float PEOffset;
488  float PESpot;
489  float decDrift;
490  double rad; // telescope ra in degrees
491  double rar; // telescope ra in radians
492  double decr; // telescope dec in radians;
493  int nwidth = 0, nheight = 0;
494 
495  double timesince;
496  time_t now;
497  time(&now);
498 
499  // Lets figure out where we are on the pe curve
500  timesince = difftime(now, RunStart);
501  // This is our spot in the curve
502  PESpot = timesince / PEPeriod;
503  // Now convert to radians
504  PESpot = PESpot * 2.0 * 3.14159;
505 
506  PEOffset = PEMax * std::sin(PESpot);
507  //fprintf(stderr,"PEOffset = %4.2f arcseconds timesince %4.2f\n",PEOffset,timesince);
508  PEOffset = PEOffset / 3600; // convert to degrees
509  //PeOffset=PeOffset/15; // ra is in h:mm
510 
511  // Spin up a set of plate constants that will relate
512  // ra/dec of stars, to our fictitious ccd layout
513 
514  // to account for various rotations etc
515  // we should spin up some plate constants here
516  // then we can use these constants to rotate and offset
517  // the standard co-ordinates on each star for drawing
518  // a ccd frame;
519  double pa, pb, pc, pd, pe, pf;
520  // Pixels per radian
521  double pprx, ppry;
522  // Scale in arcsecs per pixel
523  double Scalex;
524  double Scaley;
525  // CCD width in pixels
526  double ccdW = targetChip->getXRes();
527 
528  // Pixels per radian
529  pprx = targetFocalLength / targetChip->getPixelSizeX() * 1000;
530  ppry = targetFocalLength / targetChip->getPixelSizeY() * 1000;
531 
532  // we do a simple scale for x and y locations
533  // based on the focal length and pixel size
534  // focal length in mm, pixels in microns
535  // JM: 2015-03-17: Using a simpler formula, Scalex and Scaley are in arcsecs/pixel
536  Scalex = (targetChip->getPixelSizeX() / targetFocalLength) * 206.3;
537  Scaley = (targetChip->getPixelSizeY() / targetFocalLength) * 206.3;
538 
539 #if 0
540  DEBUGF(
542  "pprx: %g pixels per radian ppry: %g pixels per radian ScaleX: %g arcsecs/pixel ScaleY: %g arcsecs/pixel",
543  pprx, ppry, Scalex, Scaley);
544 #endif
545 
546  double theta = rotationCW + 270;
547  if (theta > 360)
548  theta -= 360;
549  if (pierSide == 1)
550  theta -= 180; // rotate 180 if on East
551  else if (theta < -360)
552  theta += 360;
553 
554  // JM: 2015-03-17: Next we do a rotation assuming CW for angle theta
555  pa = pprx * cos(theta * M_PI / 180.0);
556  pb = ppry * sin(theta * M_PI / 180.0);
557 
558  pd = pprx * -sin(theta * M_PI / 180.0);
559  pe = ppry * cos(theta * M_PI / 180.0);
560 
561  nwidth = targetChip->getXRes();
562  pc = nwidth / 2;
563 
564  nheight = targetChip->getYRes();
565  pf = nheight / 2;
566 
567  ImageScalex = Scalex;
568  ImageScaley = Scaley;
569 
570 #ifdef USE_EQUATORIAL_PE
571  if (!usePE)
572  {
573 #endif
574  currentRA = RA;
575  currentDE = Dec;
576 
577  INDI::IEquatorialCoordinates epochPos { currentRA, currentDE }, J2000Pos { 0, 0 };
578  // Convert from JNow to J2000
579  INDI::ObservedToJ2000(&epochPos, ln_get_julian_from_sys(), &J2000Pos);
580  currentRA = J2000Pos.rightascension;
581  currentDE = J2000Pos.declination;
582  currentDE += guideNSOffset;
583  currentRA += guideWEOffset;
584 #ifdef USE_EQUATORIAL_PE
585  }
586 #endif
587 
588  // calc this now, we will use it a lot later
589  rad = currentRA * 15.0;
590  rar = rad * 0.0174532925;
591  // offsetting the dec by the guide head offset
592  float cameradec;
593  cameradec = currentDE + OAGoffset / 60;
594  decr = cameradec * 0.0174532925;
595 
596  decDrift = (polarDrift * polarError * cos(decr)) / 3.81;
597 
598  // Add declination drift, if any.
599  decr += decDrift / 3600.0 * 0.0174532925;
600 
601  //fprintf(stderr,"decPE %7.5f cameradec %7.5f CenterOffsetDec %4.4f\n",decPE,cameradec,decr);
602  // now lets calculate the radius we need to fetch
603  float radius;
604 
605  radius = sqrt((Scalex * Scalex * targetChip->getXRes() / 2.0 * targetChip->getXRes() / 2.0) +
606  (Scaley * Scaley * targetChip->getYRes() / 2.0 * targetChip->getYRes() / 2.0));
607  // we have radius in arcseconds now
608  radius = radius / 60; // convert to arcminutes
609 #if 0
610  LOGF_DEBUG("Lookup radius %4.2f", radius);
611 #endif
612 
613  // A saturationmag star saturates in one second
614  // and a limitingmag produces a one adu level in one second
615  // solve for zero point and system gain
616 
617  k = (saturationmag - limitingmag) / ((-2.5 * log(maxval)) - (-2.5 * log(1.0 / 2.0)));
618  z = saturationmag - k * (-2.5 * log(maxval));
619  //z=z+saturationmag;
620 
621  //IDLog("K=%4.2f Z=%4.2f\n",k,z);
622 
623  // Should probably do some math here to figure out the dimmest
624  // star we can see on this exposure
625  // and only fetch to that magnitude
626  // for now, just use the limiting mag number with some room to spare
627  float lookuplimit = limitingmag;
628 
629  if (radius > 60)
630  lookuplimit = 11;
631 
632  if (king_gamma > 0.)
633  {
634  // wildi, make sure there are always stars, e.g. in case where king_gamma is set to 1 degree.
635  // Otherwise the solver will fail.
636  radius = 60.;
637 
638  // wildi, transform to telescope coordinate system, differential form
639  // see E.S. King based on Chauvenet:
640  // https://ui.adsabs.harvard.edu/link_gateway/1902AnHar..41..153K/ADS_PDF
641  // Currently it is not possible to enable the logging in simulator devices (tested with ccd and telescope)
642  // Replace LOGF_DEBUG by IDLog
643  //IDLog("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", king_gamma); // without variable, macro expansion fails
644  char JnRAStr[64] = {0};
645  fs_sexa(JnRAStr, RA, 2, 360000);
646  char JnDecStr[64] = {0};
647  fs_sexa(JnDecStr, Dec, 2, 360000);
648  // IDLog("Longitude : %8.3f, Latitude : %8.3f\n", this->Longitude, this->Latitude);
649  // IDLog("King gamma : %8.3f, King theta : %8.3f\n", king_gamma / 0.0174532925, king_theta / 0.0174532925);
650  // IDLog("Jnow RA : %11s, dec: %11s\n", JnRAStr, JnDecStr );
651  // IDLog("Jnow RA : %8.3f, Dec : %8.3f\n", RA * 15., Dec);
652  // IDLog("J2000 Pos.ra: %8.3f, Pos.dec: %8.3f\n", J2000Pos.ra, J2000Pos.dec);
653  // Since the catalog is J2000, we are going back in time
654  // tra, tdec are at the center of the projection center for the simulated
655  // images
656  //double J2ra = J2000Pos.ra; // J2000Pos: 0,360, RA: 0,24
657  double J2dec = J2000Pos.declination;
658 
659  //double J2rar = J2ra * 0.0174532925;
660  double J2decr = J2dec * 0.0174532925;
661  double sid = get_local_sidereal_time(this->Longitude);
662  // HA is what is observed, that is Jnow
663  // ToDo check if mean or apparent
664  double JnHAr = get_local_hour_angle(sid, RA) * 15. * 0.0174532925;
665 
666  char sidStr[64] = {0};
667  fs_sexa(sidStr, sid, 2, 3600);
668  char JnHAStr[64] = {0};
669  fs_sexa(JnHAStr, JnHAr / 15. / 0.0174532925, 2, 360000);
670 
671  // IDLog("sid : %s\n", sidStr);
672  // IDLog("Jnow JnHA: %8.3f degree\n", JnHAr / 0.0174532925);
673  // IDLog(" JnHAStr: %11s hms\n", JnHAStr);
674  // king_theta is the HA of the great circle where the HA axis is in.
675  // RA is a right and HA a left handed coordinate system.
676  // apparent or J2000? apparent, since we live now :-)
677 
678  // Transform to the mount coordinate system
679  // remember it is the center of the simulated image
680  double J2_mnt_d_rar = king_gamma * sin(J2decr) * sin(JnHAr - king_theta) / cos(J2decr);
681  double J2_mnt_rar = rar - J2_mnt_d_rar
682  ; // rad = currentRA * 15.0; rar = rad * 0.0174532925; currentRA = J2000Pos.ra / 15.0;
683 
684  // Imagine the HA axis points to HA=0, dec=89deg, then in the mount's coordinate
685  // system a star at true dec = 88 is seen at 89 deg in the mount's system
686  // Or in other words: if one uses the setting circle, that is the mount system,
687  // and set it to 87 deg then the real location is at 88 deg.
688  double J2_mnt_d_decr = king_gamma * cos(JnHAr - king_theta);
689  double J2_mnt_decr = decr + J2_mnt_d_decr
690  ; // decr = cameradec * 0.0174532925; cameradec = currentDE + OAGoffset / 60; currentDE = J2000Pos.dec;
691  // IDLog("raw mod ra : %8.3f, dec: %8.3f (degree)\n", J2_mnt_rar / 0.0174532925, J2_mnt_decr / 0.0174532925 );
692  if (J2_mnt_decr > M_PI / 2.)
693  {
694  J2_mnt_decr = M_PI / 2. - (J2_mnt_decr - M_PI / 2.);
695  J2_mnt_rar -= M_PI;
696  }
697  J2_mnt_rar = fmod(J2_mnt_rar, 2. * M_PI) ;
698  // IDLog("mod sin : %8.3f, cos: %8.3f\n", sin(JnHAr - king_theta), cos(JnHAr - king_theta));
699  // IDLog("mod dra : %8.3f, ddec: %8.3f (degree)\n", J2_mnt_d_rar / 0.0174532925, J2_mnt_d_decr / 0.0174532925 );
700  // IDLog("mod ra : %8.3f, dec: %8.3f (degree)\n", J2_mnt_rar / 0.0174532925, J2_mnt_decr / 0.0174532925 );
701  //IDLog("mod ra : %11s, dec: %11s\n", );
702  char J2RAStr[64] = {0};
703  fs_sexa(J2RAStr, J2_mnt_rar / 15. / 0.0174532925, 2, 360000);
704  char J2DecStr[64] = {0};
705  fs_sexa(J2DecStr, J2_mnt_decr / 0.0174532925, 2, 360000);
706  // IDLog("mod ra : %s, dec: %s\n", J2RAStr, J2DecStr );
707  // IDLog("PEOffset : %10.5f setting it to ZERO\n", PEOffset);
708  PEOffset = 0.;
709  // feed the result to the original variables
710  rar = J2_mnt_rar ;
711  rad = rar / 0.0174532925;
712  decr = J2_mnt_decr;
713  cameradec = decr / 0.0174532925;
714  // IDLog("mod ra rad: %8.3f (degree)\n", rad);
715  }
716  // if this is a light frame, we need a star field drawn
717  INDI::CCDChip::CCD_FRAME ftype = targetChip->getFrameType();
718 
719  std::unique_lock<std::mutex> guard(ccdBufferLock);
720 
721  // Start by clearing the frame buffer
722  memset(targetChip->getFrameBuffer(), 0, targetChip->getFrameBufferSize());
723 
724  if (ftype == INDI::CCDChip::LIGHT_FRAME)
725  {
726  AutoCNumeric locale;
727  char gsccmd[250];
728  FILE * pp;
729  int drawn = 0;
730 
731  sprintf(gsccmd, "gsc -c %8.6f %+8.6f -r %4.1f -m 0 %4.2f -n 3000",
732  range360(rad + PEOffset),
733  rangeDec(cameradec),
734  radius,
735  lookuplimit);
736 
737  if (!Streamer->isStreaming() || (king_gamma > 0.))
738  LOGF_DEBUG("GSC Command: %s", gsccmd);
739 
740  pp = popen(gsccmd, "r");
741  if (pp != nullptr)
742  {
743  char line[256];
744  int stars = 0;
745  int lines = 0;
746 
747  while (fgets(line, 256, pp) != nullptr)
748  {
749  // ok, lets parse this line for specifcs we want
750  char id[20];
751  char plate[6];
752  char ob[6];
753  float mag;
754  float mage;
755  float ra;
756  float dec;
757  float pose;
758  int band;
759  float dist;
760  int dir;
761  int c;
762 
763  int rc = sscanf(line, "%10s %f %f %f %f %f %d %d %4s %2s %f %d", id, &ra, &dec, &pose, &mag, &mage,
764  &band, &c, plate, ob, &dist, &dir);
765  //fprintf(stderr,"Parsed %d items\n",rc);
766  if (rc == 12)
767  {
768  lines++;
769  //if(c==0) {
770  stars++;
771  //fprintf(stderr,"%s %8.4f %8.4f %5.2f %5.2f %d\n",id,ra,dec,mag,dist,dir);
772 
773  // Convert the ra/dec to standard co-ordinates
774  double sx; // standard co-ords
775  double sy; //
776  double srar; // star ra in radians
777  double sdecr; // star dec in radians;
778  double ccdx;
779  double ccdy;
780 
781  //fprintf(stderr,"line %s",line);
782  //fprintf(stderr,"parsed %6.5f %6.5f\n",ra,dec);
783 
784  srar = ra * 0.0174532925;
785  sdecr = dec * 0.0174532925;
786  // Handbook of astronomical image processing
787  // page 253
788  // equations 9.1 and 9.2
789  // convert ra/dec to standard co-ordinates
790 
791  sx = cos(sdecr) * sin(srar - rar) /
792  (cos(decr) * cos(sdecr) * cos(srar - rar) + sin(decr) * sin(sdecr));
793  sy = (sin(decr) * cos(sdecr) * cos(srar - rar) - cos(decr) * sin(sdecr)) /
794  (cos(decr) * cos(sdecr) * cos(srar - rar) + sin(decr) * sin(sdecr));
795 
796  // now convert to pixels
797  ccdx = pa * sx + pb * sy + pc;
798  ccdy = pd * sx + pe * sy + pf;
799 
800  // Invert horizontally
801  ccdx = ccdW - ccdx;
802 
803  rc = DrawImageStar(targetChip, mag, ccdx, ccdy, exposure_time);
804  drawn += rc;
805  if (rc == 1)
806  {
807  //LOGF_DEBUG("star %s scope %6.4f %6.4f star %6.4f %6.4f ccd %6.2f %6.2f",id,rad,decPE,ra,dec,ccdx,ccdy);
808  //LOGF_DEBUG("star %s ccd %6.2f %6.2f",id,ccdx,ccdy);
809  }
810  }
811  }
812  pclose(pp);
813  }
814  else
815  {
816  LOG_ERROR("Error looking up stars, is gsc installed with appropriate environment variables set ??");
817  }
818  if (drawn == 0)
819  {
820  LOG_ERROR("Got no stars, is gsc installed with appropriate environment variables set ??");
821  }
822  }
823  //fprintf(stderr,"Got %d stars from %d lines drew %d\n",stars,lines,drawn);
824 
825  // now we need to add background sky glow, with vignetting
826  // this is essentially the same math as drawing a dim star with
827  // fwhm equivalent to the full field of view
828 
829  if (ftype == INDI::CCDChip::LIGHT_FRAME || ftype == INDI::CCDChip::FLAT_FRAME)
830  {
831  float skyflux;
832  // calculate flux from our zero point and gain values
833  float glow = skyglow;
834 
835  if (ftype == INDI::CCDChip::FLAT_FRAME)
836  {
837  // Assume flats are done with a diffuser
838  // in broad daylight, so, the sky magnitude
839  // is much brighter than at night
840  glow = skyglow / 10;
841  }
842 
843  //fprintf(stderr,"Using glow %4.2f\n",glow);
844 
845  skyflux = pow(10, ((glow - z) * k / -2.5));
846  // ok, flux represents one second now
847  // scale up linearly for exposure time
848  skyflux = skyflux * exposure_time;
849  //IDLog("SkyFlux = %g ExposureRequest %g\n",skyflux,exposure_time);
850 
851  uint16_t * pt = reinterpret_cast<uint16_t *>(targetChip->getFrameBuffer());
852 
853  nheight = targetChip->getSubH();
854  nwidth = targetChip->getSubW();
855 
856  for (int y = 0; y < nheight; y++)
857  {
858  for (int x = 0; x < nwidth; x++)
859  {
860  float dc; // distance from center
861  float fp; // flux this pixel;
862  float sx, sy;
863  float vig;
864 
865  sx = nwidth / 2 - x;
866  sy = nheight / 2 - y;
867 
868  vig = nwidth;
869  vig = vig * ImageScalex;
870  // need to make this account for actual pixel size
871  dc = std::sqrt(sx * sx * ImageScalex * ImageScalex + sy * sy * ImageScaley * ImageScaley);
872  // now we have the distance from center, in arcseconds
873  // now lets plot a gaussian falloff to the edges
874  //
875  float fa;
876  fa = exp(-2.0 * 0.7 * (dc * dc) / vig / vig);
877 
878  // get the current value
879  fp = pt[0];
880 
881  // Add the sky glow
882  fp += skyflux;
883 
884  // now scale it for the vignetting
885  fp = fa * fp;
886 
887  // clamp to limits
888  if (fp > maxval)
889  fp = maxval;
890  if (fp > maxpix)
891  maxpix = fp;
892  if (fp < minpix)
893  minpix = fp;
894  // and put it back
895  pt[0] = fp;
896  pt++;
897  }
898  }
899  }
900 
901  // Now we add some bias and read noise
902  int subX = targetChip->getSubX();
903  int subY = targetChip->getSubY();
904  int subW = targetChip->getSubW() + subX;
905  int subH = targetChip->getSubH() + subY;
906 
907  if (maxnoise > 0)
908  {
909  for (int x = subX; x < subW; x++)
910  {
911  for (int y = subY; y < subH; y++)
912  {
913  int noise;
914 
915  noise = random();
916  noise = noise % maxnoise; //
917 
918  //IDLog("noise is %d\n", noise);
919  AddToPixel(targetChip, x, y, bias + noise);
920  }
921  }
922  }
923  }
924  else
925  {
926  testvalue++;
927  if (testvalue > 255)
928  testvalue = 0;
929  uint16_t val = testvalue;
930 
931  int nbuf = targetChip->getSubW() * targetChip->getSubH();
932 
933  for (int x = 0; x < nbuf; x++)
934  {
935  *ptr = val++;
936  ptr++;
937  }
938  }
939  return 0;
940 }
941 
942 int GuideSim::DrawImageStar(INDI::CCDChip * targetChip, float mag, float x, float y, float exposure_time)
943 {
944  //float d;
945  //float r;
946  int sx, sy;
947  int drew = 0;
948  //int boxsizex = 5;
949  int boxsizey = 5;
950  float flux;
951 
952  int subX = targetChip->getSubX();
953  int subY = targetChip->getSubY();
954  int subW = targetChip->getSubW() + subX;
955  int subH = targetChip->getSubH() + subY;
956 
957  if ((x < subX) || (x > subW || (y < subY) || (y > subH)))
958  {
959  // this star is not on the ccd frame anyways
960  return 0;
961  }
962 
963  // calculate flux from our zero point and gain values
964  flux = pow(10, ((mag - z) * k / -2.5));
965 
966  // ok, flux represents one second now
967  // scale up linearly for exposure time
968  flux = flux * exposure_time;
969 
970  float qx;
971  // we need a box size that gives a radius at least 3 times fwhm
972  qx = seeing / ImageScalex;
973  qx = qx * 3;
974  //boxsizex = (int)qx;
975  //boxsizex++;
976  qx = seeing / ImageScaley;
977  qx = qx * 3;
978  boxsizey = static_cast<int>(qx);
979  boxsizey++;
980 
981  //IDLog("BoxSize %d %d\n",boxsizex,boxsizey);
982 
983  for (sy = -boxsizey; sy <= boxsizey; sy++)
984  {
985  for (sx = -boxsizey; sx <= boxsizey; sx++)
986  {
987  int rc;
988  float dc; // distance from center
989  float fp; // flux this pixel;
990 
991  // need to make this account for actual pixel size
992  dc = std::sqrt(sx * sx * ImageScalex * ImageScalex + sy * sy * ImageScaley * ImageScaley);
993  // now we have the distance from center, in arcseconds
994  // This should be gaussian, but, for now we'll just go with
995  // a simple linear function
996  float fa = exp(-2.0 * 0.7 * (dc * dc) / seeing / seeing);
997 
998  fp = fa * flux;
999 
1000  if (fp < 0)
1001  fp = 0;
1002 
1003  rc = AddToPixel(targetChip, x + sx, y + sy, fp);
1004  if (rc != 0)
1005  drew = 1;
1006  }
1007  }
1008  return drew;
1009 }
1010 
1011 int GuideSim::AddToPixel(INDI::CCDChip * targetChip, int x, int y, int val)
1012 {
1013  int nwidth = targetChip->getSubW();
1014  int nheight = targetChip->getSubH();
1015 
1016  x -= targetChip->getSubX();
1017  y -= targetChip->getSubY();
1018 
1019  int drew = 0;
1020  if (x >= 0)
1021  {
1022  if (x < nwidth)
1023  {
1024  if (y >= 0)
1025  {
1026  if (y < nheight)
1027  {
1028  unsigned short * pt;
1029  int newval;
1030  drew++;
1031 
1032  pt = reinterpret_cast<uint16_t *>(targetChip->getFrameBuffer());
1033 
1034  pt += (y * nwidth);
1035  pt += x;
1036  newval = pt[0];
1037  newval += val;
1038  if (newval > maxval)
1039  newval = maxval;
1040  if (newval > maxpix)
1041  maxpix = newval;
1042  if (newval < minpix)
1043  minpix = newval;
1044  pt[0] = newval;
1045  }
1046  }
1047  }
1048  }
1049  return drew;
1050 }
1051 
1053 {
1054  guideNSOffset += v / 1000.0 * GuideRate / 3600;
1055  return IPS_OK;
1056 }
1057 
1059 {
1060  guideNSOffset += v / -1000.0 * GuideRate / 3600;
1061  return IPS_OK;
1062 }
1063 
1065 {
1066  float c = v / 1000.0 * GuideRate;
1067  c = c / 3600.0 / 15.0;
1068  c = c / (cos(currentDE * 0.0174532925));
1069 
1070  guideWEOffset += c;
1071 
1072  return IPS_OK;
1073 }
1074 
1076 {
1077  float c = v / -1000.0 * GuideRate;
1078  c = c / 3600.0 / 15.0;
1079  c = c / (cos(currentDE * 0.0174532925));
1080 
1081  guideWEOffset += c;
1082 
1083  return IPS_OK;
1084 }
1085 
1086 bool GuideSim::ISNewNumber(const char * dev, const char * name, double values[], char * names[], int n)
1087 {
1088  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
1089  {
1090 
1091  if (!strcmp(name, GainNP.name))
1092  {
1093  IUUpdateNumber(&GainNP, values, names, n);
1094  GainNP.s = IPS_OK;
1095  IDSetNumber(&GainNP, nullptr);
1096  return true;
1097  }
1098 
1099  if (strcmp(name, "SIMULATOR_SETTINGS") == 0)
1100  {
1101  IUUpdateNumber(&SimulatorSettingsNP, values, names, n);
1102  SimulatorSettingsNP.s = IPS_OK;
1103 
1104  // Reset our parameters now
1105  SetupParms();
1106  IDSetNumber(&SimulatorSettingsNP, nullptr);
1107 
1108  maxnoise = SimulatorSettingsN[8].value;
1109  skyglow = SimulatorSettingsN[9].value;
1110  maxval = SimulatorSettingsN[4].value;
1111  bias = SimulatorSettingsN[5].value;
1112  limitingmag = SimulatorSettingsN[7].value;
1113  saturationmag = SimulatorSettingsN[6].value;
1114  OAGoffset = SimulatorSettingsN[10].value;
1115  polarError = SimulatorSettingsN[11].value;
1116  polarDrift = SimulatorSettingsN[12].value;
1117  rotationCW = SimulatorSettingsN[13].value;
1118  // Kwiq++
1119  king_gamma = SimulatorSettingsN[14].value * 0.0174532925;
1120  king_theta = SimulatorSettingsN[15].value * 0.0174532925;
1121  TimeFactor = SimulatorSettingsN[16].value;
1122 
1123  return true;
1124  }
1125 
1126  // Record PE EQ to simulate different position in the sky than actual mount coordinate
1127  // This can be useful to simulate Periodic Error or cone error or any arbitrary error.
1128  if (!strcmp(name, EqPENP.name))
1129  {
1130  IUUpdateNumber(&EqPENP, values, names, n);
1131  EqPENP.s = IPS_OK;
1132 
1133  INDI::IEquatorialCoordinates epochPos { EqPEN[AXIS_RA].value, EqPEN[AXIS_DE].value }, J2000Pos { 0, 0 };
1134  INDI::ObservedToJ2000(&epochPos, ln_get_julian_from_sys(), &J2000Pos);
1135  currentRA = J2000Pos.rightascension;
1136  currentDE = J2000Pos.declination;
1137  usePE = true;
1138  IDSetNumber(&EqPENP, nullptr);
1139  return true;
1140  }
1141  }
1142 
1143  return INDI::CCD::ISNewNumber(dev, name, values, names, n);
1144 }
1145 
1146 bool GuideSim::ISNewSwitch(const char * dev, const char * name, ISState * states, char * names[], int n)
1147 {
1148  if (dev != nullptr && strcmp(dev, getDeviceName()) == 0)
1149  {
1150 
1151  if (!strcmp(name, SimulateRgbSP.name))
1152  {
1153  IUUpdateSwitch(&SimulateRgbSP, states, names, n);
1154  int index = IUFindOnSwitchIndex(&SimulateRgbSP);
1155  if (index == -1)
1156  {
1157  SimulateRgbSP.s = IPS_ALERT;
1158  LOG_INFO("Cannot determine whether RGB simulation should be switched on or off.");
1159  IDSetSwitch(&SimulateRgbSP, nullptr);
1160  return false;
1161  }
1162 
1163  simulateRGB = index == 0;
1164  setRGB(simulateRGB);
1165 
1166  SimulateRgbS[0].s = simulateRGB ? ISS_ON : ISS_OFF;
1167  SimulateRgbS[1].s = simulateRGB ? ISS_OFF : ISS_ON;
1168  SimulateRgbSP.s = IPS_OK;
1169  IDSetSwitch(&SimulateRgbSP, nullptr);
1170 
1171  return true;
1172  }
1173 
1174  if (strcmp(name, CoolerSP.name) == 0)
1175  {
1176  IUUpdateSwitch(&CoolerSP, states, names, n);
1177 
1178  if (CoolerS[0].s == ISS_ON)
1179  CoolerSP.s = IPS_BUSY;
1180  else
1181  {
1182  CoolerSP.s = IPS_IDLE;
1183  TemperatureRequest = 20;
1185  }
1186 
1187  IDSetSwitch(&CoolerSP, nullptr);
1188 
1189  return true;
1190  }
1191  }
1192 
1193  // Nobody has claimed this, so, ignore it
1194  return INDI::CCD::ISNewSwitch(dev, name, states, names, n);
1195 }
1196 
1198 {
1199 #ifdef USE_EQUATORIAL_PE
1200  IDSnoopDevice(ActiveDeviceT[0].text, "EQUATORIAL_PE");
1201 #else
1202  IDSnoopDevice(ActiveDeviceT[ACTIVE_TELESCOPE].text, "EQUATORIAL_EOD_COORD");
1203 #endif
1205 
1206  strncpy(FWHMNP.device, ActiveDeviceT[ACTIVE_FOCUSER].text, MAXINDIDEVICE);
1207 }
1208 
1210 {
1211  if (IUSnoopNumber(root, &FWHMNP) == 0)
1212  {
1213  seeing = FWHMNP.np[0].value;
1214  return true;
1215  }
1216 
1217  // We try to snoop EQPEC first, if not found, we snoop regular EQNP
1218 #ifdef USE_EQUATORIAL_PE
1219  const char * propName = findXMLAttValu(root, "name");
1220  if (!strcmp(propName, EqPENP.name))
1221  {
1222  XMLEle * ep = nullptr;
1223  int rc_ra = -1, rc_de = -1;
1224  double newra = 0, newdec = 0;
1225 
1226  for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
1227  {
1228  const char * elemName = findXMLAttValu(ep, "name");
1229 
1230  if (!strcmp(elemName, "RA_PE"))
1231  rc_ra = f_scansexa(pcdataXMLEle(ep), &newra);
1232  else if (!strcmp(elemName, "DEC_PE"))
1233  rc_de = f_scansexa(pcdataXMLEle(ep), &newdec);
1234  }
1235 
1236  if (rc_ra == 0 && rc_de == 0 && ((newra != raPE) || (newdec != decPE)))
1237  {
1238  INDI::IEquatorialCoordinates epochPos { 0, 0 }, J2000Pos { 0, 0 };
1239  epochPos.ra = newra * 15.0;
1240  epochPos.dec = newdec;
1241  ln_get_equ_prec2(&epochPos, ln_get_julian_from_sys(), JD2000, &J2000Pos);
1242  raPE = J2000Pos.ra / 15.0;
1243  decPE = J2000Pos.dec;
1244  usePE = true;
1245 
1246  EqPEN[AXIS_RA].value = newra;
1247  EqPEN[AXIS_DE].value = newdec;
1248  IDSetNumber(&EqPENP, nullptr);
1249 
1250  LOGF_DEBUG("raPE %g decPE %g Snooped raPE %g decPE %g", raPE, decPE, newra, newdec);
1251 
1252  return true;
1253  }
1254  }
1255 #endif
1256 
1257  return INDI::CCD::ISSnoopDevice(root);
1258 }
1259 
1261 {
1262  // Save CCD Config
1264 
1265 
1266  // Save CCD Simulator Config
1267  IUSaveConfigNumber(fp, &SimulatorSettingsNP);
1268 
1269  // Gain
1270  IUSaveConfigNumber(fp, &GainNP);
1271 
1272  // RGB
1273  IUSaveConfigSwitch(fp, &SimulateRgbSP);
1274 
1275  return true;
1276 }
1277 
1279 {
1280  ExposureRequest = 1.0 / Streamer->getTargetExposure();
1281  pthread_mutex_lock(&condMutex);
1282  streamPredicate = 1;
1283  pthread_mutex_unlock(&condMutex);
1284  pthread_cond_signal(&cv);
1285 
1286  return true;
1287 }
1288 
1290 {
1291  pthread_mutex_lock(&condMutex);
1292  streamPredicate = 0;
1293  pthread_mutex_unlock(&condMutex);
1294  pthread_cond_signal(&cv);
1295 
1296  return true;
1297 }
1298 
1299 bool GuideSim::UpdateCCDFrame(int x, int y, int w, int h)
1300 {
1301  long bin_width = w / PrimaryCCD.getBinX();
1302  long bin_height = h / PrimaryCCD.getBinY();
1303 
1304  bin_width = bin_width - (bin_width % 2);
1305  bin_height = bin_height - (bin_height % 2);
1306 
1307  Streamer->setSize(bin_width, bin_height);
1308 
1309  return INDI::CCD::UpdateCCDFrame(x, y, w, h);
1310 }
1311 
1312 bool GuideSim::UpdateCCDBin(int hor, int ver)
1313 {
1314  if (hor == 3 || ver == 3)
1315  {
1316  LOG_ERROR("3x3 binning is not supported.");
1317  return false;
1318  }
1319 
1320  long bin_width = PrimaryCCD.getSubW() / hor;
1321  long bin_height = PrimaryCCD.getSubH() / ver;
1322 
1323  bin_width = bin_width - (bin_width % 2);
1324  bin_height = bin_height - (bin_height % 2);
1325 
1326  Streamer->setSize(bin_width, bin_height);
1327 
1328  return INDI::CCD::UpdateCCDBin(hor, ver);
1329 }
1330 
1331 void * GuideSim::streamVideoHelper(void * context)
1332 {
1333  return static_cast<GuideSim *>(context)->streamVideo();
1334 }
1335 
1337 {
1338  auto start = std::chrono::high_resolution_clock::now();
1339  auto finish = std::chrono::high_resolution_clock::now();
1340 
1341  while (true)
1342  {
1343  pthread_mutex_lock(&condMutex);
1344 
1345  while (streamPredicate == 0)
1346  {
1347  pthread_cond_wait(&cv, &condMutex);
1348  ExposureRequest = Streamer->getTargetExposure();
1349  }
1350 
1351  if (terminateThread)
1352  break;
1353 
1354  // release condMutex
1355  pthread_mutex_unlock(&condMutex);
1356 
1357 
1358  // 16 bit
1360 
1361  PrimaryCCD.binFrame();
1362 
1363  finish = std::chrono::high_resolution_clock::now();
1364  std::chrono::duration<double> elapsed = finish - start;
1365 
1366  if (elapsed.count() < ExposureRequest)
1367  usleep(fabs(ExposureRequest - elapsed.count()) * 1e6);
1368 
1369  uint32_t size = PrimaryCCD.getFrameBufferSize() / (PrimaryCCD.getBinX() * PrimaryCCD.getBinY());
1370  Streamer->newFrame(PrimaryCCD.getFrameBuffer(), size);
1371 
1372  start = std::chrono::high_resolution_clock::now();
1373  }
1374 
1375  pthread_mutex_unlock(&condMutex);
1376  return nullptr;
1377 }
1378 
1379 void GuideSim::addFITSKeywords(fitsfile *fptr, INDI::CCDChip *targetChip)
1380 {
1381  INDI::CCD::addFITSKeywords(fptr, targetChip);
1382 
1383  int status = 0;
1384  fits_update_key_dbl(fptr, "Gain", GainN[0].value, 3, "Gain", &status);
1385 }
MAXINDIDEVICE
#define MAXINDIDEVICE
Definition: indiapi.h:192
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::CCD::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: indiccd.cpp:1307
IP_RO
@ IP_RO
Definition: indiapi.h:183
INDI::CCD::pierSide
int pierSide
Definition: indiccd.h:531
GuideSim::streamVideoHelper
static void * streamVideoHelper(void *context)
Definition: guide_simulator.cpp:1331
GuideSim::AddToPixel
int AddToPixel(INDI::CCDChip *targetChip, int, int, int)
Definition: guide_simulator.cpp:1011
GuideSim::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: guide_simulator.cpp:1086
INDI::CCD::CCD_HAS_BAYER
@ CCD_HAS_BAYER
Definition: indiccd.h:130
INDI::CCD::RA
double RA
Definition: indiccd.h:528
IP_WO
@ IP_WO
Definition: indiapi.h:184
GuideSim::addFITSKeywords
virtual void addFITSKeywords(fitsfile *fptr, INDI::CCDChip *targetChip) override
Add FITS keywords to a fits file.
Definition: guide_simulator.cpp:1379
INDI::CCDChip::getBinY
int getBinY() const
getBinY Get vertical binning of the CCD chip.
Definition: indiccdchip.h:150
IPState
IPState
Property state.
Definition: indiapi.h:158
GuideSim::DrawCcdFrame
int DrawCcdFrame(INDI::CCDChip *targetChip)
Definition: guide_simulator.cpp:460
IPS_OK
@ IPS_OK
Definition: indiapi.h:161
_INumberVectorProperty::s
IPState s
Definition: indiapi.h:332
min
double min(void)
GuideSim::AbortGuideExposure
bool AbortGuideExposure() override
Abort ongoing exposure.
Definition: guide_simulator.cpp:321
get_local_hour_angle
double get_local_hour_angle(double sideral_time, double ra)
get_local_hour_angle Returns local hour angle of an object
Definition: indicom.c:1522
INDI_MONO
@ INDI_MONO
Definition: indibasetypes.h:65
INDI::CCD::HasGuideHead
bool HasGuideHead()
Definition: indiccd.h:199
ISS_OFF
@ ISS_OFF
Definition: indiapi.h:150
pcdataXMLEle
char * pcdataXMLEle(XMLEle *ep)
Return the pcdata of an XML element.
Definition: lilxml.c:575
indicom.h
Implementations for common driver routines.
locale_compat.h
GuideSim::StartStreaming
virtual bool StartStreaming() override
StartStreaming Start live video streaming.
Definition: guide_simulator.cpp:1278
INDI::CCD::ExposureComplete
virtual bool ExposureComplete(CCDChip *targetChip)
Uploads target Chip exposed buffer as FITS to the client. Dervied classes should class this function ...
Definition: indiccd.cpp:2034
IPS_ALERT
@ IPS_ALERT
Definition: indiapi.h:163
INDI::CCD::CCD_HAS_ST4_PORT
@ CCD_HAS_ST4_PORT
Definition: indiccd.h:127
nextXMLEle
XMLEle * nextXMLEle(XMLEle *ep, int init)
Iterate an XML element for a list of nesetd XML elements.
Definition: lilxml.c:524
INDI::CCD::guiderFocalLength
double guiderFocalLength
Definition: indiccd.h:537
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
f_scansexa
int f_scansexa(const char *str0, double *dp)
convert sexagesimal string str AxBxC to double.
Definition: indicom.c:195
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
INDI::CCDChip::LIGHT_FRAME
@ LIGHT_FRAME
Definition: indiccdchip.h:70
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
GuideSim::GuideNorth
virtual IPState GuideNorth(uint32_t) override
Guide northward for ms milliseconds.
Definition: guide_simulator.cpp:1052
INDI::CCDChip::getPixelSizeY
float getPixelSizeY() const
getPixelSizeY Get vertical pixel size in microns.
Definition: indiccdchip.h:168
INDI::CCDChip::getSubH
int getSubH() const
getSubH Get the height of the frame
Definition: indiccdchip.h:132
INDI::CCDChip::getFrameType
CCD_FRAME getFrameType() const
isInterlaced
Definition: indiccdchip.h:259
GuideSim::Disconnect
bool Disconnect() override
Disconnect from device.
Definition: guide_simulator.cpp:98
INDI::CCD::SetCCDParams
virtual void SetCCDParams(int x, int y, int bpp, float xf, float yf)
Setup CCD paramters for primary CCD. Child classes call this function to update CCD parameters.
Definition: indiccd.cpp:2968
INDI::BaseDevice::getDeviceName
const char * getDeviceName() const
Definition: basedevice.cpp:799
guide_simulator.h
INDI::CCD::InGuideExposure
bool InGuideExposure
Definition: indiccd.h:539
INDI::CCD::TelescopeTypeS
ISwitch TelescopeTypeS[2]
Definition: indiccd.h:661
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:187
INDI::CCDChip::getFrameBuffer
uint8_t * getFrameBuffer()
getFrameBuffer Get raw frame buffer of the CCD chip.
Definition: indiccdchip.h:219
IUSaveConfigNumber
void IUSaveConfigNumber(FILE *fp, const INumberVectorProperty *nvp)
Add a number vector property value to the configuration file.
Definition: indicom.c:1434
INDI::CCD::PrimaryCCD
CCDChip PrimaryCCD
Definition: indiccd.h:583
INDI::CCDChip::getYRes
int getYRes() const
Get the vertical resolution in pixels of the CCD Chip.
Definition: indiccdchip.h:96
LOG_INFO
#define LOG_INFO(txt)
Definition: indilogger.h:74
GuideSim::GuideSouth
virtual IPState GuideSouth(uint32_t) override
Guide southward for ms milliseconds.
Definition: guide_simulator.cpp:1058
INDI::CCDChip::CCD_FRAME
CCD_FRAME
Definition: indiccdchip.h:70
INDI::CCD::addFITSKeywords
virtual void addFITSKeywords(fitsfile *fptr, CCDChip *targetChip)
Add FITS keywords to a fits file.
Definition: indiccd.cpp:1763
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
range360
double range360(double r)
range360 Limits an angle to be between 0-360 degrees.
Definition: indicom.c:1474
max
double max(void)
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::CCD::BayerT
IText BayerT[3]
Definition: indiccd.h:640
INDI::DefaultDevice::getCurrentPollingPeriod
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
Definition: defaultdevice.cpp:1139
GuideSim::initProperties
bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: guide_simulator.cpp:114
INDI::CCDChip
The CCDChip class provides functionality of a CCD Chip within a CCD.
Definition: indiccdchip.h:48
GuideSim::UpdateCCDBin
virtual bool UpdateCCDBin(int hor, int ver) override
CCD calls this function when CCD Binning needs to be updated in the hardware. Derived classes should ...
Definition: guide_simulator.cpp:1312
LOGF_DEBUG
#define LOGF_DEBUG(fmt,...)
Definition: indilogger.h:83
GuideSim::activeDevicesUpdated
virtual void activeDevicesUpdated() override
activeDevicesUpdated Inform children that ActiveDevices property was updated so they can snoop on the...
Definition: guide_simulator.cpp:1197
GuideSim::streamVideo
void * streamVideo()
Definition: guide_simulator.cpp:1336
INDI::DefaultDevice::SetTimer
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
Definition: defaultdevice.cpp:865
INDI::CCD::Dec
double Dec
Definition: indiccd.h:528
INDI::CCD::SetGuiderParams
virtual void SetGuiderParams(int x, int y, int bpp, float xf, float yf)
Setup CCD paramters for guide head CCD. Child classes call this function to update CCD parameters.
Definition: indiccd.cpp:2978
INDI::CCD::ACTIVE_TELESCOPE
@ ACTIVE_TELESCOPE
Definition: indiccd.h:613
INDI::CCD::CCD_HAS_STREAMING
@ CCD_HAS_STREAMING
Definition: indiccd.h:131
ra
double ra
Definition: ieqprolegacydriver.cpp:43
INDI::CCD::UpdateCCDBin
virtual bool UpdateCCDBin(int hor, int ver)
CCD calls this function when CCD Binning needs to be updated in the hardware. Derived classes should ...
Definition: indiccd.cpp:1727
streammanager.h
INDI::CCDChip::getSubX
int getSubX() const
getSubX Get the starting left coordinates (X) of the frame.
Definition: indiccdchip.h:105
INDI::CCD::initProperties
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
Definition: indiccd.cpp:133
GuideSim::DrawImageStar
int DrawImageStar(INDI::CCDChip *targetChip, float, float, float, float ExposureTime)
Definition: guide_simulator.cpp:942
GuideSim::updateProperties
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: guide_simulator.cpp:228
INDI::DefaultDevice::getDriverInterface
virtual uint16_t getDriverInterface() override
Definition: defaultdevice.cpp:896
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
IPS_BUSY
@ IPS_BUSY
Definition: indiapi.h:162
ISR_1OFMANY
@ ISR_1OFMANY
Definition: indiapi.h:172
_INumberVectorProperty::np
INumber * np
Definition: indiapi.h:334
IPS_IDLE
@ IPS_IDLE
Definition: indiapi.h:160
GuideSim::StartExposure
bool StartExposure(float duration) override
Start exposing primary CCD chip.
Definition: guide_simulator.cpp:275
INDI::CCD::ActiveDeviceT
IText ActiveDeviceT[5]
Definition: indiccd.h:610
INDI::CCD::TemperatureNP
INumberVectorProperty TemperatureNP
TemperatureNP Camera Temperature in Celcius.
Definition: indiccd.h:623
dec
double dec
Definition: ieqprolegacydriver.cpp:44
GuideSim::ISNewSwitch
virtual bool ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int n) override
Process the client newSwitch command.
Definition: guide_simulator.cpp:1146
xml_ele_
Definition: lilxml.c:105
INDI::CCD::InExposure
bool InExposure
Definition: indiccd.h:538
_INumberVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:322
INDI::CCD::updateProperties
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
Definition: indiccd.cpp:469
INDI::CCDChip::getBPP
int getBPP() const
getBPP Get CCD Chip depth (bits per pixel).
Definition: indiccdchip.h:177
GuideSim::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: guide_simulator.cpp:1209
INDI::CCDChip::getXRes
int getXRes() const
getXRes Get the horizontal resolution in pixels of the CCD Chip.
Definition: indiccdchip.h:87
IUUpdateSwitch
int IUUpdateSwitch(ISwitchVectorProperty *svp, ISState *states, char *names[], int n)
Update all switches in a switch vector property.
Definition: indidriver.c:171
INDI::CCDChip::getFrameBufferSize
int getFrameBufferSize() const
getFrameBufferSize Get allocated frame buffer size to hold the CCD image frame.
Definition: indiccdchip.h:186
INDI::BaseDevice::isConnected
bool isConnected() const
Definition: basedevice.cpp:518
INDI::CCDChip::FLAT_FRAME
@ FLAT_FRAME
Definition: indiccdchip.h:70
GuideSim::TimerHit
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
Definition: guide_simulator.cpp:347
INDI::CCDChip::getSubY
int getSubY() const
getSubY Get the starting top coordinates (Y) of the frame.
Definition: indiccdchip.h:114
get_local_sidereal_time
double get_local_sidereal_time(double longitude)
get_local_sidereal_time Returns local sideral time given longitude and system clock.
INDI::CCD::CCD_CAN_BIN
@ CCD_CAN_BIN
Definition: indiccd.h:123
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::CCD::CCD_CAN_SUBFRAME
@ CCD_CAN_SUBFRAME
Definition: indiccd.h:124
GuideSim::GuideEast
virtual IPState GuideEast(uint32_t) override
Guide easward for ms milliseconds.
Definition: guide_simulator.cpp:1064
INDI::CCD::TemperatureN
INumber TemperatureN[1]
Definition: indiccd.h:624
IUSaveText
void IUSaveText(IText *tp, const char *newtext)
Function to reliably save new text in a IText.
Definition: indicom.c:1428
INDI::CCD::ISGetProperties
virtual void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: indiccd.cpp:455
INDI::CCD::SetCCDCapability
void SetCCDCapability(uint32_t cap)
SetCCDCapability Set the CCD capabilities. Al fields must be initilized.
Definition: indiccd.cpp:119
_ISwitchVectorProperty::s
IPState s
Definition: indiapi.h:382
INDI::CCD::CCD_HAS_WEB_SOCKET
@ CCD_HAS_WEB_SOCKET
Definition: indiccd.h:132
INDI::CCD::ISSnoopDevice
virtual bool ISSnoopDevice(XMLEle *root) override
Process a snoop event from INDI server. This function is called when a snooped property is updated in...
Definition: indiccd.cpp:666
_INumberVectorProperty::device
char device[MAXINDIDEVICE]
Definition: indiapi.h:320
AXIS_RA
@ AXIS_RA
Definition: indibasetypes.h:33
GuideSim::UpdateCCDFrame
virtual bool UpdateCCDFrame(int x, int y, int w, int h) override
CCD calls this function when CCD Frame dimension needs to be updated in the hardware....
Definition: guide_simulator.cpp:1299
INDI::CCD::ACTIVE_FOCUSER
@ ACTIVE_FOCUSER
Definition: indiccd.h:615
INDI::CCD::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save configuration items in XML file.
Definition: indiccd.cpp:2988
rangeDec
double rangeDec(double decdegrees)
rangeDec Limits declination value to be in -90 to 90 range.
Definition: indicom.c:1484
IUUpdateNumber
int IUUpdateNumber(INumberVectorProperty *nvp, double values[], char *names[], int n)
Update all numbers in a number vector property.
Definition: indidriver.c:225
GuideSim::getDefaultName
const char * getDefaultName() override
Definition: guide_simulator.cpp:109
INDI::CCDChip::binFrame
void binFrame()
binFrame Perform softwre binning on the CCD frame. Only use this function if hardware binning is not ...
Definition: indiccdchip.cpp:246
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:131
GuideSim::GuideSim
GuideSim()
Definition: guide_simulator.cpp:37
INDI::CCD::CCD_HAS_SHUTTER
@ CCD_HAS_SHUTTER
Definition: indiccd.h:128
INDI::CCD::GuideCCD
CCDChip GuideCCD
Definition: indiccd.h:584
findXMLAttValu
const char * findXMLAttValu(XMLEle *ep, const char *name)
Find an XML element's attribute value.
Definition: lilxml.c:613
IP_RW
@ IP_RW
Definition: indiapi.h:185
INDI::CCD::ISNewNumber
virtual bool ISNewNumber(const char *dev, const char *name, double values[], char *names[], int n) override
Process the client newNumber command.
Definition: indiccd.cpp:921
GuideSim::ISGetProperties
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
Definition: guide_simulator.cpp:219
INDI::CCD::GetCCDCapability
uint32_t GetCCDCapability() const
GetCCDCapability returns the CCD capabilities.
Definition: indiccd.h:161
INDI::CCD::TELESCOPE_PRIMARY
@ TELESCOPE_PRIMARY
Definition: indiccd.h:665
GuideSim::AbortExposure
bool AbortExposure() override
Abort ongoing exposure.
Definition: guide_simulator.cpp:311
INDI::CCD::CCD_CAN_ABORT
@ CCD_CAN_ABORT
Definition: indiccd.h:125
ISState
ISState
Switch state.
Definition: indiapi.h:148
INDI::CCD::primaryFocalLength
double primaryFocalLength
Definition: indiccd.h:537
INDI::CCD::HasCooler
bool HasCooler()
Definition: indiccd.h:223
INDI::CCDChip::getBinX
int getBinX() const
getBinX Get horizontal binning of the CCD chip.
Definition: indiccdchip.h:141
IUFindOnSwitchIndex
int IUFindOnSwitchIndex(const ISwitchVectorProperty *sp)
Returns the index of first ON switch it finds in the vector switch property.
Definition: indicom.c:1403
GuideSim::Connect
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
Definition: guide_simulator.cpp:89
INDI::CCD::Longitude
double Longitude
Definition: indiccd.h:566
INDI::IEquatorialCoordinates
Definition: libastro.h:48
GuideSim::GuideWest
virtual IPState GuideWest(uint32_t) override
Guide westward for ms milliseconds.
Definition: guide_simulator.cpp:1075
GuideSim::saveConfigItems
virtual bool saveConfigItems(FILE *fp) override
saveConfigItems Save configuration items in XML file.
Definition: guide_simulator.cpp:1260
INDI::CCDChip::getPixelSizeX
float getPixelSizeX() const
getPixelSizeX Get horizontal pixel size in microns.
Definition: indiccdchip.h:159
INDI::DefaultDevice::addDebugControl
void addDebugControl()
Add Debug control to the driver.
Definition: defaultdevice.cpp:639
IUSaveConfigSwitch
void IUSaveConfigSwitch(FILE *fp, const ISwitchVectorProperty *svp)
Add a switch vector property value to the configuration file.
Definition: indicom.c:1444
GuideSim::StartGuideExposure
bool StartGuideExposure(float) override
Start exposing guide CCD chip.
Definition: guide_simulator.cpp:300
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::CCD::Streamer
std::unique_ptr< StreamManager > Streamer
Definition: indiccd.h:581
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.
GuideSim::StopStreaming
virtual bool StopStreaming() override
StopStreaming Stop live video streaming.
Definition: guide_simulator.cpp:1289
INDI::CCD::UpdateCCDFrame
virtual bool UpdateCCDFrame(int x, int y, int w, int h)
CCD calls this function when CCD Frame dimension needs to be updated in the hardware....
Definition: indiccd.cpp:1714
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
INDI::CCD::ccdBufferLock
std::mutex ccdBufferLock
Definition: indiccd.h:576
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
AXIS_DE
@ AXIS_DE
Definition: indibasetypes.h:34
GuideSim::SetTemperature
virtual int SetTemperature(double temperature) override
Set CCD temperature.
Definition: guide_simulator.cpp:259
INDI::CCDChip::getSubW
int getSubW() const
getSubW Get the width of the frame
Definition: indiccdchip.h:123
libastro.h
GuideSim
The GuideSim class provides an advanced simulator for a CCD that includes a dedicated on-board guide ...
Definition: guide_simulator.h:40
INDI::CCD::TELESCOPE_GUIDE
@ TELESCOPE_GUIDE
Definition: indiccd.h:666
IUSnoopNumber
int IUSnoopNumber(XMLEle *root, INumberVectorProperty *nvp)
Update a snooped number vector property from the given XML root element.
Definition: indidriver.c:531
_ISwitchVectorProperty::name
char name[MAXINDINAME]
Definition: indiapi.h:370
ISS_ON
@ ISS_ON
Definition: indiapi.h:151