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
|
/*
INDI Developers Manual
Tutorial #3
"Simple Receiver Driver"
We develop a simple Receiver driver.
Refer to README, which contains instruction on how to build this driver, and use it
with an INDI-compatible client.
*/
/** \file simpledetector.cpp
\brief Construct a basic INDI Receiver device that simulates exposure & temperature settings. It also generates a random pattern and uploads it as a FITS file.
\author Ilia Platone, clearly taken from SimpleCCD by Jasem Mutlaq
\example simpledetector.cpp
A simple Receiver device that can capture images and control temperature. It returns a FITS image to the client. To build drivers for complex Receivers, please
refer to the INDI Generic Receiver driver template in INDI SVN (under 3rdparty).
*/
#include "simple_receiver.h"
#include <memory>
/* Macro shortcut to Receiver temperature value */
#define currentReceiverTemperature TemperatureN[0].value
std::unique_ptr<SimpleReceiver> simpleReceiver(new SimpleReceiver());
/**************************************************************************************
** Client is asking us to establish connection to the device
***************************************************************************************/
bool SimpleReceiver::Connect()
{
IDMessage(getDeviceName(), "Simple Receiver connected successfully!");
// Let's set a timer that checks teleReceivers status every POLLMS milliseconds.
SetTimer(getCurrentPollingPeriod());
return true;
}
/**************************************************************************************
** Client is asking us to terminate connection to the device
***************************************************************************************/
bool SimpleReceiver::Disconnect()
{
IDMessage(getDeviceName(), "Simple Receiver disconnected successfully!");
return true;
}
/**************************************************************************************
** INDI is asking us for our default device name
***************************************************************************************/
const char *SimpleReceiver::getDefaultName()
{
return "Simple Receiver";
}
/**************************************************************************************
** INDI is asking us to init our properties.
***************************************************************************************/
bool SimpleReceiver::initProperties()
{
// Must init parent properties first!
INDI::Receiver::initProperties();
// We set the Receiver capabilities
uint32_t cap = SENSOR_CAN_ABORT | SENSOR_HAS_COOLER | SENSOR_HAS_SHUTTER;
SetCapability(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 SimpleReceiver::updateProperties()
{
// Call parent update properties first
INDI::Receiver::updateProperties();
if (isConnected())
{
// Let's get parameters now from Receiver
setupParams();
// Start the timer
SetTimer(getCurrentPollingPeriod());
}
return true;
}
/**************************************************************************************
** Client is updating capture settings
***************************************************************************************/
bool SimpleReceiver::paramsUpdated(float sr, float freq, float bps, float bw, float gain)
{
INDI_UNUSED(bps);
INDI_UNUSED(freq);
INDI_UNUSED(sr);
INDI_UNUSED(bw);
INDI_UNUSED(gain);
return true;
}
/**************************************************************************************
** Setting up Receiver parameters
***************************************************************************************/
void SimpleReceiver::setupParams()
{
// Our Receiver is an 8 bit Receiver, 100MHz frequency 1MHz samplerate.
setFrequency(1000000.0);
setSampleRate(100000000.0);
setBPS(16);
setBandwidth(0.0);
setGain(25.0);
}
/**************************************************************************************
** Client is asking us to start an exposure
***************************************************************************************/
bool SimpleReceiver::StartIntegration(double duration)
{
IntegrationRequest = duration;
// Since we have only have one Receiver with one chip, we set the exposure duration of the primary Receiver
setIntegrationTime(duration);
gettimeofday(&CapStart, nullptr);
InIntegration = true;
// We're done
return true;
}
/**************************************************************************************
** Client is asking us to abort an exposure
***************************************************************************************/
bool SimpleReceiver::AbortIntegration()
{
InIntegration = false;
return true;
}
/**************************************************************************************
** Client is asking us to set a new temperature
***************************************************************************************/
int SimpleReceiver::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 SimpleReceiver::CalcTimeLeft()
{
double timesince;
double timeleft;
struct timeval now
{
0, 0
};
gettimeofday(&now, nullptr);
timesince = (double)(now.tv_sec * 1000.0 + now.tv_usec / 1000) -
(double)(CapStart.tv_sec * 1000.0 + CapStart.tv_usec / 1000);
timesince = timesince / 1000;
timeleft = IntegrationRequest - timesince;
return timeleft;
}
/**************************************************************************************
** Main device loop. We check for exposure and temperature progress here
***************************************************************************************/
void SimpleReceiver::TimerHit()
{
long timeleft;
if (!isConnected())
return; // No need to reset timer if we are not connected anymore
if (InIntegration)
{
timeleft = CalcTimeLeft();
// Less than a 0.1 second away from exposure completion
// This is an over simplified timing method, check ReceiverSimulator and simpleReceiver for better timing checks
if (timeleft < 0.1)
{
/* We're done exposing */
IDMessage(getDeviceName(), "Integration done, downloading image...");
// Set exposure left to zero
setIntegrationLeft(0);
// We're no longer exposing...
InIntegration = false;
/* grab and save image */
grabFrame();
}
else
// Just update time left in client
setIntegrationLeft(timeleft);
}
// TemperatureNP is defined in INDI::Receiver
switch (TemperatureNP.s)
{
case IPS_IDLE:
case IPS_OK:
break;
case IPS_BUSY:
/* If target temperature is higher, then increase current Receiver temperature */
if (currentReceiverTemperature < TemperatureRequest)
currentReceiverTemperature++;
/* If target temperature is lower, then decrese current Receiver temperature */
else if (currentReceiverTemperature > TemperatureRequest)
currentReceiverTemperature--;
/* 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 SimpleReceiver::grabFrame()
{
// Set length of continuum
int len = getSampleRate() * getIntegrationTime() * getBPS() / 8;
setBufferSize(len);
// Let's get a pointer to the frame buffer
uint8_t *continuum = getBuffer();
// Fill buffer with random pattern
for (int i = 0; i < len; i++)
continuum[i] = rand() % 255;
IDMessage(getDeviceName(), "Download complete.");
// Let INDI::Receiver know we're done filling the image buffer
IntegrationComplete();
}
|