Instrument Neutral Distributed Interface INDI 2.2.5
test_ccd_simulator.cpp
Go to the documentation of this file.
1#include "indilogger.h"
2
3#include <gtest/gtest.h>
4
5#include "ccd_simulator.h"
6
7#include <cmath>
8
9char _me[] = "MockCCDSimDriver";
10char *me = _me;
12{
13 public:
19
21 {
22 auto p = getNumber("SIMULATOR_SETTINGS");
23 ASSERT_TRUE(p.isValid());
24 ASSERT_NE(p.findWidgetByName("SIM_XRES"), nullptr);
25 ASSERT_NE(p.findWidgetByName("SIM_YRES"), nullptr);
26 ASSERT_NE(p.findWidgetByName("SIM_XSIZE"), nullptr);
27 ASSERT_NE(p.findWidgetByName("SIM_YSIZE"), nullptr);
28 ASSERT_NE(p.findWidgetByName("SIM_MAXVAL"), nullptr);
29 ASSERT_NE(p.findWidgetByName("SIM_SATURATION"), nullptr);
30 ASSERT_NE(p.findWidgetByName("SIM_LIMITINGMAG"), nullptr);
31 ASSERT_NE(p.findWidgetByName("SIM_NOISE"), nullptr);
32 ASSERT_NE(p.findWidgetByName("SIM_SKYGLOW"), nullptr);
33 ASSERT_NE(p.findWidgetByName("SIM_OAGOFFSET"), nullptr);
34 ASSERT_NE(p.findWidgetByName("SIM_POLAR"), nullptr);
35 ASSERT_NE(p.findWidgetByName("SIM_POLARDRIFT"), nullptr);
36 }
37
39 {
40 EXPECT_TRUE(isnan(currentRA)) << "Field 'currentRA' is undefined when initializing CCDSim.";
41 EXPECT_TRUE(isnan(currentDE)) << "Field 'currentDEC' is undefined when initializing CCDSim.";
42
43 EXPECT_EQ(GuideRate, 7 /* arcsec/s */);
44
45 EXPECT_EQ(guideNSOffset, 0);
46 EXPECT_EQ(guideWEOffset, 0);
47
48 double const arcsec = 1.0 / 3600.0;
49
50 EXPECT_EQ(GuideNorth(1000.0), IPS_OK);
51 EXPECT_NEAR(guideNSOffset, +7 * arcsec, 1 * arcsec);
52 EXPECT_EQ(GuideSouth(1000.0), IPS_OK);
53 EXPECT_NEAR(guideNSOffset, +0 * arcsec, 1 * arcsec);
54 EXPECT_EQ(GuideSouth(1000.0), IPS_OK);
55 EXPECT_NEAR(guideNSOffset, -7 * arcsec, 1 * arcsec);
56 EXPECT_EQ(GuideNorth(1000.0), IPS_OK);
57 EXPECT_NEAR(guideNSOffset, +0 * arcsec, 1 * arcsec);
58
59 currentDE = 0;
60
61 EXPECT_EQ(GuideWest(1000.0), IPS_OK);
62 EXPECT_NEAR(guideWEOffset, +7 * arcsec, 15 * arcsec);
63 EXPECT_EQ(GuideEast(1000.0), IPS_OK);
64 EXPECT_NEAR(guideWEOffset, +0 * arcsec, 15 * arcsec);
65 EXPECT_EQ(GuideEast(1000.0), IPS_OK);
66 EXPECT_NEAR(guideWEOffset, -7 * arcsec, 15 * arcsec);
67 EXPECT_EQ(GuideWest(1000.0), IPS_OK);
68 EXPECT_NEAR(guideWEOffset, +0 * arcsec, 15 * arcsec);
69 }
70};
71
72// ---------------------------------------------------------------------------
73// SkyRenderer tests -- exercise the renderer standalone, no INDI driver.
74// ---------------------------------------------------------------------------
75class SkyRendererTest : public ::testing::Test
76{
77 protected:
80
81 void setupChip(int xres, int yres, float pixelSize = 4.6f)
82 {
83 chip.setResolution(xres, yres);
84 chip.setPixelSize(pixelSize, pixelSize);
85 chip.setFrame(0, 0, xres, yres);
86 chip.setBPP(16);
87 chip.setFrameBufferSize(xres * yres * 2);
89 }
90
91 uint16_t *fb()
92 {
93 return reinterpret_cast<uint16_t *>(chip.getFrameBuffer());
94 }
95
96 long sumFrame(int xres, int yres)
97 {
98 uint16_t *buf = fb();
99 long s = 0;
100 for (int i = 0; i < xres * yres; i++)
101 s += buf[i];
102 return s;
103 }
104
105 uint16_t peakPixel(int xres, int yres)
106 {
107 uint16_t *buf = fb();
108 uint16_t peak = 0;
109 for (int i = 0; i < xres * yres; i++)
110 if (buf[i] > peak) peak = buf[i];
111 return peak;
112 }
113};
114
115// --- flux behavior (tested through drawImageStar) ---
116
117TEST_F(SkyRendererTest, saturation_mag_produces_high_adu)
118{
119 int const xres = 33;
120 int const yres = 33;
121 int const maxval = 65000;
122
123 RenderConfig cfg;
124 cfg.maxVal = maxval;
125 cfg.saturationMag = 5.0f;
126 cfg.limitingMag = 20.0f;
127 cfg.seeing = 2.0f;
128 renderer.setConfig(cfg);
129 renderer.setImageScale(1.0f, 1.0f);
130 setupChip(xres, yres);
131
132 renderer.drawImageStar(&chip, cfg.saturationMag, xres / 2, yres / 2, 1.0f);
133
134 EXPECT_GT(peakPixel(xres, yres), static_cast<uint16_t>(maxval / 4))
135 << "a star at saturation magnitude for 1s should produce high ADU";
136}
137
138TEST_F(SkyRendererTest, limiting_mag_produces_minimal_adu)
139{
140 int const xres = 33;
141 int const yres = 33;
142
143 RenderConfig cfg;
144 cfg.maxVal = 65000;
145 cfg.saturationMag = 0.0f;
146 cfg.limitingMag = 20.0f;
147 cfg.seeing = 2.0f;
148 renderer.setConfig(cfg);
149 renderer.setImageScale(1.0f, 1.0f);
150 setupChip(xres, yres);
151
152 renderer.drawImageStar(&chip, cfg.limitingMag, xres / 2, yres / 2, 1.0f);
153
154 EXPECT_LE(peakPixel(xres, yres), 2u)
155 << "a star at limiting magnitude for 1s should produce ~1 ADU";
156}
157
158TEST_F(SkyRendererTest, degenerate_mag_range_does_not_crash)
159{
160 int const xres = 33;
161 int const yres = 33;
162
163 RenderConfig cfg;
164 cfg.maxVal = 65000;
165 cfg.saturationMag = 10.0f;
166 cfg.limitingMag = 10.0f;
167 cfg.seeing = 2.0f;
168 renderer.setConfig(cfg);
169 renderer.setImageScale(1.0f, 1.0f);
170 setupChip(xres, yres);
171
172 renderer.drawImageStar(&chip, 10.0f, xres / 2, yres / 2, 1.0f);
173 // Must not crash or produce NaN; some output is acceptable
174}
175
176TEST_F(SkyRendererTest, brighter_star_produces_more_flux)
177{
178 int const xres = 33;
179 int const yres = 33;
180 int const cx = xres / 2;
181 int const cy = yres / 2;
182
183 RenderConfig cfg;
184 cfg.maxVal = 65000;
185 cfg.saturationMag = 0.0f;
186 cfg.limitingMag = 20.0f;
187 cfg.seeing = 2.0f;
188 renderer.setConfig(cfg);
189 renderer.setImageScale(1.0f, 1.0f);
190
191 setupChip(xres, yres);
192 renderer.drawImageStar(&chip, 8.0f, cx, cy, 1.0f);
193 long const sum_bright = sumFrame(xres, yres);
194
195 setupChip(xres, yres);
196 renderer.drawImageStar(&chip, 12.0f, cx, cy, 1.0f);
197 long const sum_dim = sumFrame(xres, yres);
198
199 ASSERT_GT(sum_bright, 0L);
200 ASSERT_GT(sum_dim, 0L);
201 EXPECT_GT(sum_bright, sum_dim);
202}
203
204// --- pixel clamping (tested through drawImageStar) ---
205
206TEST_F(SkyRendererTest, pixel_values_clamped_at_max_val)
207{
208 int const xres = 33;
209 int const yres = 33;
210 int const maxval = 1000;
211
212 RenderConfig cfg;
213 cfg.maxVal = maxval;
214 cfg.saturationMag = 0.0f;
215 cfg.limitingMag = 20.0f;
216 cfg.seeing = 2.0f;
217 renderer.setConfig(cfg);
218 renderer.setImageScale(1.0f, 1.0f);
219 setupChip(xres, yres);
220
221 renderer.drawImageStar(&chip, 0.0f, xres / 2, yres / 2, 1000.0f);
222
223 uint16_t *buf = fb();
224 for (int i = 0; i < xres * yres; i++)
225 EXPECT_LE(buf[i], static_cast<uint16_t>(maxval))
226 << "no pixel may exceed maxVal";
227}
228
229// --- drawImageStar: behavioral properties ---
230
231TEST_F(SkyRendererTest, star_center_is_brightest)
232{
233 int const xres = 33;
234 int const yres = 33;
235
236 RenderConfig cfg;
237 cfg.maxVal = 65000;
238 cfg.saturationMag = 0.0f;
239 cfg.limitingMag = 20.0f;
240 cfg.seeing = 2.0f;
241 renderer.setConfig(cfg);
242 renderer.setImageScale(1.0f, 1.0f);
243 setupChip(xres, yres);
244
245 int const cx = xres / 2;
246 int const cy = yres / 2;
247 renderer.drawImageStar(&chip, 5.0f, cx, cy, 1.0f);
248
249 uint16_t *buf = fb();
250 uint16_t const peak = buf[cy * xres + cx];
251 EXPECT_GT(peak, 0u);
252 EXPECT_GT(peak, buf[cy * xres + cx + 1]);
253 EXPECT_GT(peak, buf[cy * xres + cx - 1]);
254 EXPECT_GT(peak, buf[(cy + 1) * xres + cx]);
255 EXPECT_GT(peak, buf[(cy - 1) * xres + cx]);
256}
257
258TEST_F(SkyRendererTest, star_profile_symmetric)
259{
260 int const xres = 33;
261 int const yres = 33;
262
263 RenderConfig cfg;
264 cfg.maxVal = 65000;
265 cfg.saturationMag = 0.0f;
266 cfg.limitingMag = 20.0f;
267 cfg.seeing = 2.0f;
268 renderer.setConfig(cfg);
269 renderer.setImageScale(1.0f, 1.0f);
270 setupChip(xres, yres);
271
272 int const cx = xres / 2;
273 int const cy = yres / 2;
274 renderer.drawImageStar(&chip, 5.0f, cx, cy, 1.0f);
275
276 uint16_t *buf = fb();
277 for (int d = 1; d <= 3; d++)
278 {
279 EXPECT_EQ(buf[cy * xres + cx + d], buf[cy * xres + cx - d])
280 << "horizontal symmetry at d=" << d;
281 EXPECT_EQ(buf[(cy + d) * xres + cx], buf[(cy - d) * xres + cx])
282 << "vertical symmetry at d=" << d;
283 }
284}
285
286TEST_F(SkyRendererTest, star_profile_monotonic_falloff)
287{
288 int const xres = 33;
289 int const yres = 33;
290
291 RenderConfig cfg;
292 cfg.maxVal = 65000;
293 cfg.saturationMag = 0.0f;
294 cfg.limitingMag = 20.0f;
295 cfg.seeing = 2.0f;
296 renderer.setConfig(cfg);
297 renderer.setImageScale(1.0f, 1.0f);
298 setupChip(xres, yres);
299
300 int const cx = xres / 2;
301 int const cy = yres / 2;
302 renderer.drawImageStar(&chip, 5.0f, cx, cy, 1.0f);
303
304 uint16_t *buf = fb();
305 for (int d = 0; d < 5; d++)
306 {
307 uint16_t const inner = buf[cy * xres + cx + d];
308 uint16_t const outer = buf[cy * xres + cx + d + 1];
309 EXPECT_GE(inner, outer)
310 << "profile must not increase at d=" << d << " -> " << d + 1;
311 }
312}
313
314TEST_F(SkyRendererTest, star_zero_beyond_render_box)
315{
316 int const xres = 65;
317 int const yres = 65;
318
319 RenderConfig cfg;
320 cfg.maxVal = 65000;
321 cfg.saturationMag = 0.0f;
322 cfg.limitingMag = 20.0f;
323 cfg.seeing = 1.0f;
324 renderer.setConfig(cfg);
325 renderer.setImageScale(1.0f, 1.0f);
326 setupChip(xres, yres);
327
328 int const cx = xres / 2;
329 int const cy = yres / 2;
330 renderer.drawImageStar(&chip, 10.0f, cx, cy, 1.0f);
331
332 uint16_t *buf = fb();
333 int const beyond = static_cast<int>(3.0f * cfg.seeing / 1.0f) + 2;
334 for (int d = beyond; d < cx; d++)
335 {
336 EXPECT_EQ(buf[cy * xres + cx + d], 0u)
337 << "pixel at d=" << d << " is beyond the render box";
338 }
339}
340
341// Regression guard for indilib/indi#2465: the PSF must be centred on the true
342// (sub-pixel) star position, not snapped to the truncated integer pixel. If the
343// fractional part of the coordinate is discarded, a sub-pixel shift produces no
344// change in the rendered centroid, which quantised guide-sim drift to a lattice
345// and broke calibration.
346TEST_F(SkyRendererTest, star_centroid_tracks_subpixel_shift)
347{
348 int const xres = 201;
349 int const yres = 201;
350
351 RenderConfig cfg;
352 cfg.maxVal = 65000;
353 cfg.saturationMag = 0.0f;
354 cfg.limitingMag = 20.0f;
355 cfg.seeing = 3.0f;
356 renderer.setConfig(cfg);
357 renderer.setImageScale(1.0f, 1.0f);
358
359 // Flux-weighted X centroid of the whole frame.
360 auto centroidX = [this](int nx, int ny) -> double
361 {
362 uint16_t *buf = fb();
363 double sumWeighted = 0.0;
364 double sumFlux = 0.0;
365 for (int y = 0; y < ny; y++)
366 for (int x = 0; x < nx; x++)
367 {
368 double const v = buf[y * nx + x];
369 sumWeighted += v * x;
370 sumFlux += v;
371 }
372 return sumFlux > 0 ? sumWeighted / sumFlux : -1.0;
373 };
374
375 // Integer y keeps the comparison on the X axis only.
376 float const y = 100.0f;
377
378 setupChip(xres, yres);
379 renderer.drawImageStar(&chip, 6.0f, 100.3f, y, 1.0f);
380 double const cxLow = centroidX(xres, yres);
381
382 setupChip(xres, yres);
383 renderer.drawImageStar(&chip, 6.0f, 100.7f, y, 1.0f);
384 double const cxHigh = centroidX(xres, yres);
385
386 ASSERT_GT(cxLow, 0.0);
387 ASSERT_GT(cxHigh, 0.0);
388
389 // Each centroid should sit near its true sub-pixel position...
390 EXPECT_NEAR(cxLow, 100.3, 0.15);
391 EXPECT_NEAR(cxHigh, 100.7, 0.15);
392 // ...and, crucially, the 0.4 px shift must be reflected in the render.
393 // The pre-fix code snapped both to pixel 100, giving a zero difference.
394 EXPECT_GT(cxHigh - cxLow, 0.2);
395}
396
397TEST_F(SkyRendererTest, star_flux_scales_with_exposure)
398{
399 int const xres = 33;
400 int const yres = 33;
401
402 RenderConfig cfg;
403 cfg.maxVal = 65000;
404 cfg.saturationMag = 0.0f;
405 cfg.limitingMag = 20.0f;
406 cfg.seeing = 2.0f;
407 renderer.setConfig(cfg);
408 renderer.setImageScale(1.0f, 1.0f);
409
410 int const cx = xres / 2;
411 int const cy = yres / 2;
412
413 setupChip(xres, yres);
414 renderer.drawImageStar(&chip, 10.0f, cx, cy, 1.0f);
415 long const sum1s = sumFrame(xres, yres);
416
417 setupChip(xres, yres);
418 renderer.drawImageStar(&chip, 10.0f, cx, cy, 4.0f);
419 long const sum4s = sumFrame(xres, yres);
420
421 ASSERT_GT(sum1s, 0L);
422 EXPECT_NEAR(static_cast<double>(sum4s) / sum1s, 4.0, 0.5)
423 << "total flux must scale linearly with exposure time";
424}
425
426TEST_F(SkyRendererTest, star_off_chip_draws_nothing)
427{
428 int const xres = 33;
429 int const yres = 33;
430
431 RenderConfig cfg;
432 cfg.maxVal = 65000;
433 cfg.saturationMag = 0.0f;
434 cfg.limitingMag = 20.0f;
435 cfg.seeing = 2.0f;
436 renderer.setConfig(cfg);
437 renderer.setImageScale(1.0f, 1.0f);
438 setupChip(xres, yres);
439
440 renderer.drawImageStar(&chip, 5.0f, -10.0f, -10.0f, 1.0f);
441 renderer.drawImageStar(&chip, 5.0f, xres + 10.0f, yres + 10.0f, 1.0f);
442 EXPECT_EQ(sumFrame(xres, yres), 0);
443}
444
445// --- renderFrame ---
446
447TEST_F(SkyRendererTest, render_frame_image_scale)
448{
449 int const xres = 100;
450 int const yres = 100;
451 float const pixelSizeUM = 5.0f;
452 double const focalLengthMM = 1000.0;
453
454 RenderConfig cfg;
455 cfg.maxVal = 65000;
456 cfg.skyGlow = 99.0f;
457 renderer.setConfig(cfg);
458 setupChip(xres, yres, pixelSizeUM);
459
460 renderer.renderFrame(&chip, 0.0, 0.0, focalLengthMM, 0.0, 1.0f, false);
461
462 float const expectedScale = static_cast<float>((pixelSizeUM / focalLengthMM) * 206.3);
463 EXPECT_NEAR(renderer.imageScaleX(), expectedScale, 0.001f);
464 EXPECT_NEAR(renderer.imageScaleY(), expectedScale, 0.001f);
465}
466
467TEST_F(SkyRendererTest, render_frame_no_stars_produces_sky_glow)
468{
469 int const xres = 33;
470 int const yres = 33;
471
472 RenderConfig cfg;
473 cfg.maxVal = 65000;
474 cfg.skyGlow = 15.0f;
475 cfg.saturationMag = 0.0f;
476 cfg.limitingMag = 20.0f;
477 renderer.setConfig(cfg);
478 setupChip(xres, yres);
479
480 int drawn = renderer.renderFrame(&chip, 0.0, 0.0, 500.0, 0.0, 10.0f, false);
481 EXPECT_EQ(drawn, 0) << "renderStars=false must draw zero stars";
482 EXPECT_GT(sumFrame(xres, yres), 0L) << "sky glow must still be rendered";
483}
484
485TEST_F(SkyRendererTest, render_frame_sky_glow_vignetting)
486{
487 int const xres = 65;
488 int const yres = 65;
489
490 RenderConfig cfg;
491 cfg.maxVal = 65000;
492 cfg.skyGlow = 15.0f;
493 cfg.saturationMag = 0.0f;
494 cfg.limitingMag = 20.0f;
495 renderer.setConfig(cfg);
496 setupChip(xres, yres);
497
498 renderer.renderFrame(&chip, 0.0, 0.0, 500.0, 0.0, 10.0f, false);
499
500 uint16_t *buf = fb();
501 uint16_t const center_val = buf[(yres / 2) * xres + xres / 2];
502 uint16_t const corner_val = buf[0];
503
504 EXPECT_GT(center_val, 0u);
505 EXPECT_GT(center_val, corner_val)
506 << "vignetting must make center brighter than corners";
507}
508
509TEST_F(SkyRendererTest, render_frame_clears_buffer)
510{
511 int const xres = 16;
512 int const yres = 16;
513
514 RenderConfig cfg;
515 cfg.maxVal = 65000;
516 cfg.skyGlow = 99.0f;
517 renderer.setConfig(cfg);
518 setupChip(xres, yres);
519
520 memset(chip.getFrameBuffer(), 0xFF, chip.getFrameBufferSize());
521
522 renderer.renderFrame(&chip, 0.0, 0.0, 500.0, 0.0, 0.001f, false);
523
524 uint16_t *buf = fb();
525 for (int i = 0; i < xres * yres; i++)
526 EXPECT_LT(buf[i], 10u) << "renderFrame must clear pre-existing data";
527}
528
529// --- applyReadoutNoise ---
530
531TEST_F(SkyRendererTest, readout_noise_adds_bias_and_noise)
532{
533 int const xres = 16;
534 int const yres = 16;
535 int const maxval = 65000;
536 int const bias = 1500;
537 int const maxNoise = 20;
538
539 RenderConfig cfg;
540 cfg.maxVal = maxval;
541 renderer.setConfig(cfg);
542 setupChip(xres, yres);
543
544 renderer.applyReadoutNoise(&chip, bias, maxNoise);
545
546 uint16_t *buf = fb();
547 for (int i = 0; i < xres * yres; i++)
548 {
549 EXPECT_GE(buf[i], static_cast<uint16_t>(bias));
550 EXPECT_LE(buf[i], static_cast<uint16_t>(bias + maxNoise));
551 }
552}
553
554TEST_F(SkyRendererTest, readout_noise_clamps_at_max_val)
555{
556 int const xres = 8;
557 int const yres = 8;
558 int const maxval = 100;
559
560 RenderConfig cfg;
561 cfg.maxVal = maxval;
562 renderer.setConfig(cfg);
563 setupChip(xres, yres);
564
565 // Bias alone exceeds maxVal
566 renderer.applyReadoutNoise(&chip, 200, 10);
567
568 uint16_t *buf = fb();
569 for (int i = 0; i < xres * yres; i++)
570 EXPECT_EQ(buf[i], static_cast<uint16_t>(maxval));
571}
572
573TEST_F(SkyRendererTest, readout_noise_skipped_when_zero)
574{
575 int const xres = 8;
576 int const yres = 8;
577
578 RenderConfig cfg;
579 cfg.maxVal = 65000;
580 renderer.setConfig(cfg);
581 setupChip(xres, yres);
582
583 renderer.applyReadoutNoise(&chip, 1500, 0);
584
585 EXPECT_EQ(sumFrame(xres, yres), 0)
586 << "maxNoise <= 0 must skip noise application entirely";
587}
588
589// --- benchmark (no assertions, informational only) ---
590
591TEST_F(SkyRendererTest, draw_star_benchmark)
592{
593 int const xres = 65;
594 int const yres = 65;
595
596 RenderConfig cfg;
597 cfg.maxVal = 65000;
598 cfg.saturationMag = 0.0f;
599 cfg.limitingMag = 30.0f;
600 cfg.seeing = 1.0f;
601 renderer.setConfig(cfg);
602 renderer.setImageScale(1.0f, 1.0f);
603 setupChip(xres, yres);
604
605 auto const before = std::chrono::steady_clock::now();
606 int const loops = 200000;
607 for (int i = 0; i < loops; i++)
608 {
609 float const m = (15.0f * rand()) / static_cast<float>(RAND_MAX);
610 float const x = static_cast<float>(xres * rand()) / static_cast<float>(RAND_MAX);
611 float const y = static_cast<float>(yres * rand()) / static_cast<float>(RAND_MAX);
612 float const e = (100.0f * rand()) / static_cast<float>(RAND_MAX);
613 renderer.drawImageStar(&chip, m, x, y, e);
614 }
615 auto const after = std::chrono::steady_clock::now();
616 auto const duration = std::chrono::duration_cast<std::chrono::nanoseconds>(after - before).count() / loops;
617 std::cout << "[ ] drawImageStar benchmark: " << duration << " ns/call" << std::endl;
618}
619
620// --- CCDSim driver-level tests ---
621
622TEST(CCDSimulatorDriverTest, test_properties)
623{
625}
626
627TEST(CCDSimulatorDriverTest, test_guide_api)
628{
630}
631
632int main(int argc, char **argv)
633{
636
637 ::testing::InitGoogleTest(&argc, argv);
638 return RUN_ALL_TESTS();
639}
The CCDSim class provides an advanced simulator for a CCD that includes a dedicated on-board guide ch...
bool initProperties() override
Initialize properties initial state and value. The child class must implement this function.
float guideWEOffset
virtual IPState GuideSouth(uint32_t) override
Guide southward for ms milliseconds.
float GuideRate
Guide rate is 7 arcseconds per second.
void ISGetProperties(const char *dev) override
define the driver's properties to the client. Usually, only a minimum set of properties are defined t...
float guideNSOffset
virtual IPState GuideEast(uint32_t) override
Guide easward for ms milliseconds.
virtual IPState GuideWest(uint32_t) override
Guide westward for ms milliseconds.
double currentDE
virtual IPState GuideNorth(uint32_t) override
Guide northward for ms milliseconds.
double currentRA
INDI::PropertyNumber getNumber(const char *name) const
The CCDChip class provides functionality of a CCD Chip within a CCD.
Definition indiccdchip.h:39
void setResolution(uint32_t x, uint32_t y)
setResolution set CCD Chip resolution
void setFrame(uint32_t subx, uint32_t suby, uint32_t subw, uint32_t subh)
setFrame Set desired frame resolutoin for an exposure.
void setPixelSize(double x, double y)
setPixelSize Set CCD Chip pixel size
uint8_t * getFrameBuffer()
getFrameBuffer Get raw frame buffer of the CCD chip.
void setFrameBufferSize(uint32_t nbuf, bool allocMem=true)
setFrameBufferSize Set desired frame buffer size. The function will allocate memory accordingly....
int getFrameBufferSize() const
getFrameBufferSize Get allocated frame buffer size to hold the CCD image frame.
void setBPP(uint8_t bpp)
setBPP Set depth of CCD chip.
uint16_t peakPixel(int xres, int yres)
long sumFrame(int xres, int yres)
void setupChip(int xres, int yres, float pixelSize=4.6f)
int main()
@ IPS_OK
Definition indiapi.h:160
static const loggerConf file_off
Definition indilogger.h:219
void configure(const std::string &outputFile, const loggerConf configuration, const int fileVerbosityLevel, const int screenVerbosityLevel)
Method to configure the logger. Called by the DEBUG_CONF() macro. To make implementation easier,...
static Logger & getInstance()
Method to get a reference to the object (i.e., Singleton) It is a static method.
float limitingMag
Definition sky_renderer.h:9
float saturationMag
TEST_F(SkyRendererTest, saturation_mag_produces_high_adu)
TEST(CCDSimulatorDriverTest, test_properties)
char _me[]
char * me