Instrument Neutral Distributed Interface INDI  2.0.2
simple_receiver.cpp
Go to the documentation of this file.
1 /*
2  INDI Developers Manual
3  Tutorial #3
4 
5  "Simple Receiver Driver"
6 
7  We develop a simple Receiver driver.
8 
9  Refer to README, which contains instruction on how to build this driver, and use it
10  with an INDI-compatible client.
11 
12 */
13 
23 #include "simple_receiver.h"
24 
25 #include <memory>
26 
27 /* Macro shortcut to Receiver temperature value */
28 #define currentReceiverTemperature TemperatureN[0].value
29 
30 std::unique_ptr<SimpleReceiver> simpleReceiver(new SimpleReceiver());
31 
32 /**************************************************************************************
33 ** Client is asking us to establish connection to the device
34 ***************************************************************************************/
36 {
37  IDMessage(getDeviceName(), "Simple Receiver connected successfully!");
38 
39  // Let's set a timer that checks teleReceivers status every POLLMS milliseconds.
41 
42  return true;
43 }
44 
45 /**************************************************************************************
46 ** Client is asking us to terminate connection to the device
47 ***************************************************************************************/
49 {
50  IDMessage(getDeviceName(), "Simple Receiver disconnected successfully!");
51  return true;
52 }
53 
54 /**************************************************************************************
55 ** INDI is asking us for our default device name
56 ***************************************************************************************/
58 {
59  return "Simple Receiver";
60 }
61 
62 /**************************************************************************************
63 ** INDI is asking us to init our properties.
64 ***************************************************************************************/
66 {
67  // Must init parent properties first!
69 
70  // We set the Receiver capabilities
72  SetCapability(cap);
73 
74  // Add Debug, Simulator, and Configuration controls
76 
78 
79  return true;
80 }
81 
82 /********************************************************************************************
83 ** INDI is asking us to update the properties because there is a change in CONNECTION status
84 ** This fucntion is called whenever the device is connected or disconnected.
85 *********************************************************************************************/
87 {
88  // Call parent update properties first
90 
91  if (isConnected())
92  {
93  // Let's get parameters now from Receiver
94  setupParams();
95 
96  // Start the timer
98  }
99 
100  return true;
101 }
102 
103 /**************************************************************************************
104 ** Client is updating capture settings
105 ***************************************************************************************/
106 bool SimpleReceiver::paramsUpdated(float sr, float freq, float bps, float bw, float gain)
107 {
108  INDI_UNUSED(bps);
109  INDI_UNUSED(freq);
110  INDI_UNUSED(sr);
111  INDI_UNUSED(bw);
112  INDI_UNUSED(gain);
113  return true;
114 }
115 
116 /**************************************************************************************
117 ** Setting up Receiver parameters
118 ***************************************************************************************/
119 void SimpleReceiver::setupParams()
120 {
121  // Our Receiver is an 8 bit Receiver, 100MHz frequency 1MHz samplerate.
122  setFrequency(1000000.0);
123  setSampleRate(100000000.0);
124  setBPS(16);
125  setBandwidth(0.0);
126  setGain(25.0);
127 }
128 
129 /**************************************************************************************
130 ** Client is asking us to start an exposure
131 ***************************************************************************************/
132 bool SimpleReceiver::StartIntegration(double duration)
133 {
134  IntegrationRequest = duration;
135 
136  // Since we have only have one Receiver with one chip, we set the exposure duration of the primary Receiver
137  setIntegrationTime(duration);
138 
139  gettimeofday(&CapStart, nullptr);
140 
141  InIntegration = true;
142 
143  // We're done
144  return true;
145 }
146 
147 /**************************************************************************************
148 ** Client is asking us to abort an exposure
149 ***************************************************************************************/
151 {
152  InIntegration = false;
153  return true;
154 }
155 
156 /**************************************************************************************
157 ** Client is asking us to set a new temperature
158 ***************************************************************************************/
159 int SimpleReceiver::SetTemperature(double temperature)
160 {
161  TemperatureRequest = temperature;
162 
163  // 0 means it will take a while to change the temperature
164  return 0;
165 }
166 
167 /**************************************************************************************
168 ** How much longer until exposure is done?
169 ***************************************************************************************/
170 float SimpleReceiver::CalcTimeLeft()
171 {
172  double timesince;
173  double timeleft;
174  struct timeval now
175  {
176  0, 0
177  };
178 
179  gettimeofday(&now, nullptr);
180 
181  timesince = (double)(now.tv_sec * 1000.0 + now.tv_usec / 1000) -
182  (double)(CapStart.tv_sec * 1000.0 + CapStart.tv_usec / 1000);
183  timesince = timesince / 1000;
184 
185  timeleft = IntegrationRequest - timesince;
186  return timeleft;
187 }
188 
189 /**************************************************************************************
190 ** Main device loop. We check for exposure and temperature progress here
191 ***************************************************************************************/
193 {
194  long timeleft;
195 
196  if (!isConnected())
197  return; // No need to reset timer if we are not connected anymore
198 
199  if (InIntegration)
200  {
201  timeleft = CalcTimeLeft();
202 
203  // Less than a 0.1 second away from exposure completion
204  // This is an over simplified timing method, check ReceiverSimulator and simpleReceiver for better timing checks
205  if (timeleft < 0.1)
206  {
207  /* We're done exposing */
208  IDMessage(getDeviceName(), "Integration done, downloading image...");
209 
210  // Set exposure left to zero
212 
213  // We're no longer exposing...
214  InIntegration = false;
215 
216  /* grab and save image */
217  grabFrame();
218  }
219  else
220  // Just update time left in client
221  setIntegrationLeft(timeleft);
222  }
223 
224  // TemperatureNP is defined in INDI::Receiver
225  switch (TemperatureNP.s)
226  {
227  case IPS_IDLE:
228  case IPS_OK:
229  break;
230 
231  case IPS_BUSY:
232  /* If target temperature is higher, then increase current Receiver temperature */
233  if (currentReceiverTemperature < TemperatureRequest)
235  /* If target temperature is lower, then decrese current Receiver temperature */
236  else if (currentReceiverTemperature > TemperatureRequest)
238  /* If they're equal, stop updating */
239  else
240  {
242  IDSetNumber(&TemperatureNP, "Target temperature reached.");
243 
244  break;
245  }
246 
247  IDSetNumber(&TemperatureNP, nullptr);
248 
249  break;
250 
251  case IPS_ALERT:
252  break;
253  }
254 
256 }
257 
258 /**************************************************************************************
259 ** Create a random image and return it to client
260 ***************************************************************************************/
261 void SimpleReceiver::grabFrame()
262 {
263  // Set length of continuum
264  int len = getSampleRate() * getIntegrationTime() * getBPS() / 8;
265  setBufferSize(len);
266 
267  // Let's get a pointer to the frame buffer
268  uint8_t *continuum = getBuffer();
269 
270  // Fill buffer with random pattern
271  for (int i = 0; i < len; i++)
272  continuum[i] = rand() % 255;
273 
274  IDMessage(getDeviceName(), "Download complete.");
275 
276  // Let INDI::Receiver know we're done filling the image buffer
278 }
bool isConnected() const
Definition: basedevice.cpp:520
const char * getDeviceName() const
Definition: basedevice.cpp:821
void setDefaultPollingPeriod(uint32_t msec)
setDefaultPollingPeriod Change the default polling period to call TimerHit() function in the driver.
uint32_t getCurrentPollingPeriod() const
getCurrentPollingPeriod Return the current polling period.
void addAuxControls()
Add Debug, Simulation, and Configuration options to the driver.
int SetTimer(uint32_t ms)
Set a timer to call the function TimerHit after ms milliseconds.
void setGain(double gain)
setGain Set gain of Receiver device.
virtual bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
void setBandwidth(double bandwidth)
setBandwidth Set bandwidth of Receiver device.
virtual bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
void setFrequency(double freq)
setFrequency Set the frequency observed.
double getSampleRate()
getSampleRate Get requested sample rate for the sensor in Hz.
Definition: indireceiver.h:141
void setSampleRate(double sr)
setSampleRate Set depth of Receiver device.
void SetCapability(uint32_t cap)
SetCapability Set the Sensor capabilities. Al fields must be initialized.
void setBPS(int bps)
setBPP Set depth of Sensor device.
void setBufferSize(int nbuf, bool allocMem=true)
setBufferSize Set desired buffer size. The function will allocate memory accordingly....
void setIntegrationLeft(double duration)
setIntegrationLeft Update Integration time left. Inform the client of the new Integration time left v...
uint8_t * getBuffer()
getBuffer Get raw buffer of the stream of the Sensor device.
void setIntegrationTime(double duration)
setIntegrationTime Set desired Sensor frame Integration duration for next Integration....
INumberVectorProperty TemperatureNP
virtual bool IntegrationComplete()
Uploads target Device exposed buffer as FITS to the client. Dervied classes should class this functio...
int getBPS() const
getBPS Get Sensor depth (bits per sample).
double getIntegrationTime() const
getIntegrationTime Get requested Integration duration for the Sensor device in seconds.
void TimerHit() override
Callback function to be called once SetTimer duration elapses.
bool StartIntegration(double duration) override
Start integration from the Sensor device.
bool initProperties() override
Initilize properties initial state and value. The child class must implement this function.
bool Connect() override
Connect to the device. INDI::DefaultDevice implementation connects to appropriate connection interfac...
bool Disconnect() override
Disconnect from device.
const char * getDefaultName() override
int SetTemperature(double temperature) override
Set Sensor temperature.
bool paramsUpdated(float sr, float freq, float bps, float bw, float gain)
bool updateProperties() override
updateProperties is called whenever there is a change in the CONNECTION status of the driver....
bool AbortIntegration() override
Abort ongoing Integration.
@ IPS_BUSY
Definition: indiapi.h:163
@ IPS_ALERT
Definition: indiapi.h:164
@ IPS_IDLE
Definition: indiapi.h:161
@ IPS_OK
Definition: indiapi.h:162
#define INDI_UNUSED(x)
Definition: indidevapi.h:131
void IDSetNumber(const INumberVectorProperty *nvp, const char *fmt,...)
Definition: indidriver.c:1211
void IDMessage(const char *dev, const char *fmt,...)
Definition: indidriver.c:960
std::unique_ptr< SimpleReceiver > simpleReceiver(new SimpleReceiver())
#define currentReceiverTemperature