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 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
|
/*
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 <sys/time.h>
#include <memory>
#include "simpleccd.h"
const int POLLMS = 500; /* Polling interval 500 ms */
const int MAX_CCD_TEMP = 45; /* Max CCD temperature */
const int MIN_CCD_TEMP = -55; /* Min CCD temperature */
const float TEMP_THRESHOLD = .25; /* Differential temperature threshold (C)*/
/* Macro shortcut to CCD temperature value */
#define currentCCDTemperature TemperatureN[0].value
std::auto_ptr<SimpleCCD> simpleCCD(0);
void ISInit()
{
static int isInit =0;
if (isInit == 1)
return;
isInit = 1;
if(simpleCCD.get() == 0) simpleCCD.reset(new SimpleCCD());
}
void ISGetProperties(const char *dev)
{
ISInit();
simpleCCD->ISGetProperties(dev);
}
void ISNewSwitch(const char *dev, const char *name, ISState *states, char *names[], int num)
{
ISInit();
simpleCCD->ISNewSwitch(dev, name, states, names, num);
}
void ISNewText( const char *dev, const char *name, char *texts[], char *names[], int num)
{
ISInit();
simpleCCD->ISNewText(dev, name, texts, names, num);
}
void ISNewNumber(const char *dev, const char *name, double values[], char *names[], int num)
{
ISInit();
simpleCCD->ISNewNumber(dev, name, values, names, num);
}
void ISNewBLOB (const char *dev, const char *name, int sizes[], int blobsizes[], char *blobs[], char *formats[], char *names[], int n)
{
INDI_UNUSED(dev);
INDI_UNUSED(name);
INDI_UNUSED(sizes);
INDI_UNUSED(blobsizes);
INDI_UNUSED(blobs);
INDI_UNUSED(formats);
INDI_UNUSED(names);
INDI_UNUSED(n);
}
void ISSnoopDevice (XMLEle *root)
{
ISInit();
simpleCCD->ISSnoopDevice(root);
}
SimpleCCD::SimpleCCD()
{
InExposure = false;
}
/**************************************************************************************
** 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(POLLMS);
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
Capability cap;
cap.canAbort = true;
cap.canBin = true;
cap.canSubFrame = true;
cap.hasCooler = true;
cap.hasGuideHead = false;
cap.hasShutter = true;
cap.hasST4Port = false;
SetCapability(&cap);
// Add Debug, Simulator, and Configuration controls
addAuxControls();
return true;
}
/**************************************************************************************
** INDI is asking us to submit list of properties for the device
***************************************************************************************/
void SimpleCCD::ISGetProperties(const char *dev)
{
INDI::CCD::ISGetProperties(dev);
// If we are _already_ connected, let's define our temperature property to the client now
if (isConnected())
{
// Define our only property temperature
defineNumber(&TemperatureNP);
}
}
/********************************************************************************************
** 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(POLLMS);
}
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
int nbuf;
nbuf=PrimaryCCD.getXRes()*PrimaryCCD.getYRes() * PrimaryCCD.getBPP()/8;
nbuf+=512; // leave a little extra at the end
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);
gettimeofday(&ExpStart,NULL);
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;
// 1 means it will take a while to change the temperature
return 1;
}
/**************************************************************************************
** How much longer until exposure is done?
***************************************************************************************/
float SimpleCCD::CalcTimeLeft()
{
double timesince;
double timeleft;
struct timeval now;
gettimeofday(&now,NULL);
timesince=(double)(now.tv_sec * 1000.0 + now.tv_usec/1000) - (double)(ExpStart.tv_sec * 1000.0 + ExpStart.tv_usec/1000);
timesince=timesince/1000;
timeleft=ExposureRequest-timesince;
return timeleft;
}
/**************************************************************************************
** Main device loop. We check for exposure and temperature progress here
***************************************************************************************/
void SimpleCCD::TimerHit()
{
long timeleft;
if(isConnected() == false)
return; // No need to reset timer if we are not connected anymore
if (InExposure)
{
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, NULL);
break;
case IPS_ALERT:
break;
}
SetTimer(POLLMS);
return;
}
/**************************************************************************************
** Create a random image and return it to client
***************************************************************************************/
void SimpleCCD::grabImage()
{
// Let's get a pointer to the frame buffer
char * 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);
}
|