1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
/*
INDI Developers Manual
Tutorial #3
"Simple CCD Driver"
We develop a simple CCD driver.
Refer to README, which contains instruction on how to build this driver, and use it
with an INDI-compatible client.
*/
/** \file simpleccd.cpp
\brief Construct a basic INDI CCD device that simulates exposure & temperature settings. It also generates a random pattern and uploads it as a FITS file.
\author Jasem Mutlaq
\example simpleccd.cpp
A simple CCD device that can capture images and control temperature. It returns a FITS image to the client. To build drivers for complex CCDs, please
refer to the INDI Generic CCD driver template in INDI SVN (under 3rdparty).
*/
#include "simpleccd.h"
#include <memory>
/* Macro shortcut to CCD temperature value */
#define currentCCDTemperature TemperatureN[0].value
std::unique_ptr<SimpleCCD> simpleCCD(new SimpleCCD());
/**************************************************************************************
** Client is asking us to establish connection to the device
***************************************************************************************/
bool SimpleCCD::Connect()
{
IDMessage(getDeviceName(), "Simple CCD connected successfully!");
// Let's set a timer that checks teleCCDs status every POLLMS milliseconds.
SetTimer(getCurrentPollingPeriod());
return true;
}
/**************************************************************************************
** Client is asking us to terminate connection to the device
***************************************************************************************/
bool SimpleCCD::Disconnect()
{
IDMessage(getDeviceName(), "Simple CCD disconnected successfully!");
return true;
}
/**************************************************************************************
** INDI is asking us for our default device name
***************************************************************************************/
const char *SimpleCCD::getDefaultName()
{
return "Simple CCD";
}
/**************************************************************************************
** INDI is asking us to init our properties.
***************************************************************************************/
bool SimpleCCD::initProperties()
{
// Must init parent properties first!
INDI::CCD::initProperties();
// We set the CCD capabilities
uint32_t cap = CCD_CAN_ABORT | CCD_CAN_BIN | CCD_CAN_SUBFRAME | CCD_HAS_COOLER | CCD_HAS_SHUTTER;
SetCCDCapability(cap);
// Add Debug, Simulator, and Configuration controls
addAuxControls();
setDefaultPollingPeriod(500);
return true;
}
/********************************************************************************************
** INDI is asking us to update the properties because there is a change in CONNECTION status
** This fucntion is called whenever the device is connected or disconnected.
*********************************************************************************************/
bool SimpleCCD::updateProperties()
{
// Call parent update properties first
INDI::CCD::updateProperties();
if (isConnected())
{
// Let's get parameters now from CCD
setupParams();
// Start the timer
SetTimer(getCurrentPollingPeriod());
}
return true;
}
/**************************************************************************************
** Setting up CCD parameters
***************************************************************************************/
void SimpleCCD::setupParams()
{
// Our CCD is an 8 bit CCD, 1280x1024 resolution, with 5.4um square pixels.
SetCCDParams(1280, 1024, 8, 5.4, 5.4);
// Let's calculate how much memory we need for the primary CCD buffer
uint32_t nbuf = PrimaryCCD.getXRes() * PrimaryCCD.getYRes() * PrimaryCCD.getBPP() / 8;
PrimaryCCD.setFrameBufferSize(nbuf);
}
/**************************************************************************************
** Client is asking us to start an exposure
***************************************************************************************/
bool SimpleCCD::StartExposure(float duration)
{
ExposureRequest = duration;
// Since we have only have one CCD with one chip, we set the exposure duration of the primary CCD
PrimaryCCD.setExposureDuration(duration);
ExposureTimer.start();
InExposure = true;
// We're done
return true;
}
/**************************************************************************************
** Client is asking us to abort an exposure
***************************************************************************************/
bool SimpleCCD::AbortExposure()
{
InExposure = false;
return true;
}
/**************************************************************************************
** Client is asking us to set a new temperature
***************************************************************************************/
int SimpleCCD::SetTemperature(double temperature)
{
TemperatureRequest = temperature;
// 0 means it will take a while to change the temperature
return 0;
}
/**************************************************************************************
** How much longer until exposure is done?
***************************************************************************************/
float SimpleCCD::CalcTimeLeft()
{
return ExposureRequest - ExposureTimer.elapsed() / 1000.0;
}
/**************************************************************************************
** Main device loop. We check for exposure and temperature progress here
***************************************************************************************/
void SimpleCCD::TimerHit()
{
if (!isConnected())
return; // No need to reset timer if we are not connected anymore
if (InExposure)
{
double timeleft = CalcTimeLeft();
// Less than a 0.1 second away from exposure completion
// This is an over simplified timing method, check CCDSimulator and simpleCCD for better timing checks
if (timeleft < 0.1)
{
/* We're done exposing */
IDMessage(getDeviceName(), "Exposure done, downloading image...");
// Set exposure left to zero
PrimaryCCD.setExposureLeft(0);
// We're no longer exposing...
InExposure = false;
/* grab and save image */
grabImage();
}
else
// Just update time left in client
PrimaryCCD.setExposureLeft(timeleft);
}
// TemperatureNP is defined in INDI::CCD
switch (TemperatureNP.s)
{
case IPS_IDLE:
case IPS_OK:
break;
case IPS_BUSY:
/* If target temperature is higher, then increase current CCD temperature */
if (currentCCDTemperature < TemperatureRequest)
currentCCDTemperature++;
/* If target temperature is lower, then decrese current CCD temperature */
else if (currentCCDTemperature > TemperatureRequest)
currentCCDTemperature--;
/* If they're equal, stop updating */
else
{
TemperatureNP.s = IPS_OK;
IDSetNumber(&TemperatureNP, "Target temperature reached.");
break;
}
IDSetNumber(&TemperatureNP, nullptr);
break;
case IPS_ALERT:
break;
}
SetTimer(getCurrentPollingPeriod());
}
/**************************************************************************************
** Create a random image and return it to client
***************************************************************************************/
void SimpleCCD::grabImage()
{
// Let's get a pointer to the frame buffer
uint8_t *image = PrimaryCCD.getFrameBuffer();
// Get width and height
int width = PrimaryCCD.getSubW() / PrimaryCCD.getBinX() * PrimaryCCD.getBPP() / 8;
int height = PrimaryCCD.getSubH() / PrimaryCCD.getBinY();
// Fill buffer with random pattern
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
image[i * width + j] = rand() % 255;
IDMessage(getDeviceName(), "Download complete.");
// Let INDI::CCD know we're done filling the image buffer
ExposureComplete(&PrimaryCCD);
}
|