API
 
Loading...
Searching...
No Matches
edtCamera.hpp
Go to the documentation of this file.
1/** \file edtCamera.hpp
2 * \brief EDT framegrabber interface
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup app_files
7 */
8
9#ifndef edtCamera_hpp
10#define edtCamera_hpp
11
12#ifndef MAGAOX_NOEDT
13
14#include <edtinc.h>
15
16#include "../../common/paths.hpp"
17
18#include "ioDevice.hpp"
19
20#include "stdCamera.hpp"
21
22namespace MagAOX
23{
24namespace app
25{
26namespace dev
27{
28
29
30
31
32/// MagAO-X EDT framegrabber interface
33/** Implements an interface to the EDT PDV SDK
34 *
35 * The derived class `derivedT` must be a MagAOXApp<true>, and must declare this class a friend like so:
36 * \code
37 * friend class dev::dssShutter<derivedT>;
38 * \endcode
39 *
40 * A static configuration variable must be defined in derivedT as
41 * \code
42 * static constexpr bool c_edtCamera_relativeConfigPath = true; //or: false
43 * \endcode
44 * which determines whether or not the EDT config path is relative to the MagAO-X config path (true) or absolute (false).
45 *
46 * In addition, `derivedT` should be `dev::frameGrabber` or equivalent, with an `m_reconfig` member, and calls
47 * to this class's `pdvStartAcquisition`, `pdvAcquire`, and `pdvReconfig` in the relevant `dev::frameGrabber`
48 * implementation functions.
49 *
50 * Calls to this class's `setupConfig`, `loadConfig`, `appStartup`, `appLogic`, `appShutdown`
51 * `onPowerOff`, and `whilePowerOff`, must be placed in the derived class's functions of the same name.
52 *
53 * \ingroup appdev
54 */
55template<class derivedT>
56class edtCamera : public ioDevice
57{
58
59public:
60
61
62protected:
63
64 /** \name Configurable Parameters
65 * @{
66 */
67 //Framegrabber:
68 int m_unit {0}; ///< EDT PDV board unit number
69 int m_channel {0}; ///< EDT PDV board channel number
70 int m_numBuffs {4}; ///< EDT PDV DMA buffer size, indicating number of images.
71
72 //cameraConfigMap derived().m_cameraModes; ///< Map holding the possible camera mode configurations
73
74 //std::string derived().m_startupMode; ///< The camera mode to load during first init after a power-on.
75
76 ///@}
77
78 PdvDev * m_pdv {nullptr}; ///< The EDT PDV device handle
79
80 u_char * m_image_p {nullptr}; ///< The image data grabbed
81
82 //std::string m_modeName; ///< The current mode name
83
84 //std::string derived().m_nextMode; ///< The mode to be set by the next reconfiguration
85
86 int m_raw_height {0}; ///< The height of the frame, according to the framegrabber
87 int m_raw_width {0}; ///< The width of the frame, according to the framegrabber
88 int m_raw_depth {0}; ///< The bit-depth of the frame, according to the framegrabber
89 std::string m_cameraType; ///< The camera type according to the framegrabber
90
91public:
92
93 ///C'tor, sets up stdCamera
95
96 ///Destructor, destroys the PdvDev structure
97 ~edtCamera() noexcept;
98
99 /// Send a serial command over cameralink and retrieve the response
100 int pdvSerialWriteRead( std::string & response, ///< [out] the response to the command from the device
101 const std::string & command ///< [in] the command to send to the device
102 );
103
104 /// Configure the EDT framegrabber
105 int pdvConfig( std::string & cfgname /**< [in] The configuration name for the mode to set */);
106
107 /// Setup the configuration system
108 /**
109 * This should be called in `derivedT::setupConfig` as
110 * \code
111 edtCamera<derivedT>::setupConfig(config);
112 \endcode
113 * with appropriate error checking.
114 */
115 void setupConfig(mx::app::appConfigurator & config /**< [out] the derived classes configurator*/);
116
117 /// load the configuration system results
118 /**
119 * This should be called in `derivedT::loadConfig` as
120 * \code
121 edtCamera<derivedT>::loadConfig(config);
122 \endcode
123 * with appropriate error checking.
124 */
125 void loadConfig(mx::app::appConfigurator & config /**< [in] the derived classes configurator*/);
126
127 /// Startup function
128 /**
129 * This should be called in `derivedT::appStartup` as
130 * \code
131 edtCamera<derivedT>::appStartup();
132 \endcode
133 * with appropriate error checking.
134 *
135 * \returns 0 on success
136 * \returns -1 on error, which is logged.
137 */
139
140 /// Application logic
141 /** Checks the edtCamera thread
142 *
143 * This should be called from the derived's appLogic() as in
144 * \code
145 edtCamera<derivedT>::appLogic();
146 \endcode
147 * with appropriate error checking.
148 *
149 * \returns 0 on success
150 * \returns -1 on error, which is logged.
151 */
152 int appLogic();
153
154 /// Actions on power off
155 /**
156 * This should be called from the derived's onPowerOff() as in
157 * \code
158 edtCamera<derivedT>::onPowerOff();
159 \endcode
160 * with appropriate error checking.
161 *
162 * \returns 0 on success
163 * \returns -1 on error, which is logged.
164 */
166
167 /// Actions while powered off
168 /**
169 * This should be called from the derived's whilePowerOff() as in
170 * \code
171 edtCamera<derivedT>::whilePowerOff();
172 \endcode
173 * with appropriate error checking.
174 *
175 * \returns 0 on success
176 * \returns -1 on error, which is logged.
177 */
179
180 /// Application the shutdown
181 /** Shuts down the edtCamera thread
182 *
183 * \code
184 edtCamera<derivedT>::appShutdown();
185 \endcode
186 * with appropriate error checking.
187 *
188 * \returns 0 on success
189 * \returns -1 on error, which is logged.
190 */
192
193
195
196 int pdvAcquire( timespec & currImageTimestamp );
197
199
200protected:
201
202
203 /** \name INDI
204 *
205 *@{
206 */
207protected:
208 //declare our properties
209
210public:
211
212 /// The static callback function to be registered for the channel properties.
213 /**
214 * \returns 0 on success.
215 * \returns -1 on error.
216 */
217 // static int st_newCallBack_mode( void * app, ///< [in] a pointer to this, will be static_cast-ed to derivedT.
218 // const pcf::IndiProperty &ipRecv ///< [in] the INDI property sent with the the new property request.
219 // );
220
221 /// The callback called by the static version, to actually process the new request.
222 /**
223 * \returns 0 on success.
224 * \returns -1 on error.
225 */
226 //int newCallBack_mode( const pcf::IndiProperty &ipRecv /**< [in] the INDI property sent with the the new property request.*/);
227
228 /// Update the INDI properties for this device controller
229 /** You should call this once per main loop.
230 * It is not called automatically.
231 *
232 * \returns 0 on success.
233 * \returns -1 on error.
234 */
236
237 ///@}
238
239private:
240 derivedT & derived()
241 {
242 return *static_cast<derivedT *>(this);
243 }
244};
245
246template<class derivedT>
250
251
252template<class derivedT>
254{
255 if(m_pdv) pdv_close(m_pdv);
256
257 return;
258}
259
260
261#define MAGAOX_PDV_SERBUFSIZE 512
262
263template<class derivedT>
264int edtCamera<derivedT>::pdvSerialWriteRead( std::string & response,
265 const std::string & command
266 )
267{
268 char buf[MAGAOX_PDV_SERBUFSIZE+1];
269
270 // Flush the channel first.
271 // This does not indicate errors, so no checks possible.
272 pdv_serial_read(m_pdv, buf, MAGAOX_PDV_SERBUFSIZE);
273
274 if( pdv_serial_command(m_pdv, command.c_str()) < 0)
275 {
276 derivedT::template log<software_error>({__FILE__, __LINE__, "PDV: error sending serial command"});
277 return -1;
278 }
279
280 int ret;
281
282 ret = pdv_serial_wait(m_pdv, m_readTimeout, 1);
283
284 if(ret == 0)
285 {
286 if(derived().powerState() != 1 || derived().powerStateTarget() != 1) return -1;
287
288 derivedT::template log<software_error>({__FILE__, __LINE__, "PDV: timeout, no serial response"});
289 return -1;
290 }
291
292 u_char lastbyte, waitc;
293
294 response.clear();
295
296 do
297 {
298 ret = pdv_serial_read(m_pdv, buf, MAGAOX_PDV_SERBUFSIZE);
299
300 if(ret > 0) response += buf;
301
302 //Check for last char, wait for more otherwise.
303 if (*buf) lastbyte = (u_char)buf[strnlen(buf, sizeof(buf))-1];
304
305 if (pdv_get_waitchar(m_pdv, &waitc) && (lastbyte == waitc))
306 break;
307 else ret = pdv_serial_wait(m_pdv, m_readTimeout/2, 1);
308 }
309 while(ret > 0);
310
311 if(ret == 0 && pdv_get_waitchar(m_pdv, &waitc))
312 {
313 derivedT::template log<software_error>({__FILE__, __LINE__, "PDV: timeout in serial response"});
314 return -1;
315 }
316
317 return 0;
318}
319
320template<class derivedT>
321int edtCamera<derivedT>::pdvConfig(std::string & modeName)
322{
323 Dependent *dd_p;
324 EdtDev *edt_p = NULL;
325 Edtinfo edtinfo;
326
327 //Preliminaries
328 if(m_pdv)
329 {
330 pdv_close(m_pdv);
331 m_pdv = nullptr;
332 }
333
334 derived().m_modeName = modeName;
335
336 if(modeName == "")
337 {
338 return derivedT::template log<text_log, -1>("Empty modeName passed to pdvConfig", logPrio::LOG_ERROR);
339 }
340
341 if(derived().m_cameraModes.count(modeName) != 1)
342 {
343 return derivedT::template log<text_log, -1>("No mode named " + modeName + " found.", logPrio::LOG_ERROR);
344 }
345
346 //Construct config file, adding relative path if configured that way
347 std::string configFile;
348
349 if(derivedT::c_edtCamera_relativeConfigPath)
350 {
351 configFile = derived().configDir() + "/";
352 }
353
354 configFile += derived().m_cameraModes[modeName].m_configFile;
355
356
357 derivedT::template log<text_log>("Loading EDT PDV config file: " + configFile);
358
359 if ((dd_p = pdv_alloc_dependent()) == NULL)
360 {
361 return derivedT::template log<software_error, -1>({__FILE__, __LINE__, "EDT PDV alloc_dependent FAILED"});
362 }
363
364 if (pdv_readcfg(configFile.c_str(), dd_p, &edtinfo) != 0)
365 {
366 free(dd_p);
367 return derivedT::template log<software_error, -1>({__FILE__, __LINE__, "EDT PDV readcfg FAILED"});
368
369 }
370
371 char edt_devname[128];
372 strncpy(edt_devname, EDT_INTERFACE, sizeof(edt_devname));
373
374 if ((edt_p = edt_open_channel(edt_devname, m_unit, m_channel)) == NULL)
375 {
376 char errstr[256];
377 edt_perror(errstr);
378 free(dd_p);
379 return derivedT::template log<software_error, -1>({__FILE__, __LINE__, std::string("EDT PDV edt_open_channel FAILED: ") + errstr});
380 }
381
382 char bitdir[1];
383 bitdir[0] = '\0';
384
385 int pdv_debug = 0;
386
387 if(derived().m_log.logLevel() > logPrio::LOG_INFO) pdv_debug = 2;
388
389 if (pdv_initcam(edt_p, dd_p, m_unit, &edtinfo, configFile.c_str(), bitdir, pdv_debug) != 0)
390 {
391 edt_close(edt_p);
392 free(dd_p);
393 return derivedT::template log<software_error, -1>({__FILE__, __LINE__, "initcam failed. Run with '--logLevel=DBG' to see complete debugging output."});
394 }
395
396 edt_close(edt_p);
397 free(dd_p);
398
399 //Now open the PDV device handle for talking to the camera via the EDT board.
400 if ((m_pdv = pdv_open_channel(edt_devname, m_unit, m_channel)) == NULL)
401 {
402 std::string errstr = std::string("pdv_open_channel(") + edt_devname + std::to_string(m_unit) + "_" + std::to_string(m_channel) + ")";
403
404 derivedT::template log<software_error>({__FILE__, __LINE__, errstr});
405 derivedT::template log<software_error>({__FILE__, __LINE__, errno});
406
407 return -1;
408 }
409
410 pdv_flush_fifo(m_pdv);
411
412 pdv_serial_read_enable(m_pdv); //This is undocumented, don't know if it's really needed.
413
414 m_raw_width = pdv_get_width(m_pdv);
415 m_raw_height = pdv_get_height(m_pdv);
416 m_raw_depth = pdv_get_depth(m_pdv);
417 m_cameraType = pdv_get_cameratype(m_pdv);
418
419 derivedT::template log<text_log>("Initialized framegrabber: " + m_cameraType);
420 derivedT::template log<text_log>("WxHxD: " + std::to_string(m_raw_width) + " X " + std::to_string(m_raw_height) + " X " + std::to_string(m_raw_depth));
421
422 /*
423 * allocate four buffers for optimal pdv ring buffer pipeline (reduce if
424 * memory is at a premium)
425 */
426 pdv_multibuf(m_pdv, m_numBuffs);
427 derivedT::template log<text_log>("allocated " + std::to_string(m_numBuffs) + " buffers");
428
429
430
431 return 0;
432
433}
434
435template<class derivedT>
436void edtCamera<derivedT>::setupConfig(mx::app::appConfigurator & config)
437{
438 config.add("framegrabber.pdv_unit", "", "framegrabber.pdv_unit", argType::Required, "framegrabber", "pdv_unit", false, "int", "The EDT PDV framegrabber unit number. Default is 0.");
439 config.add("framegrabber.pdv_channel", "", "framegrabber.pdv_channel", argType::Required, "framegrabber", "pdv_channel", false, "int", "The EDT PDV framegrabber channel number. Default is 0.");
440 config.add("framegrabber.numBuffs", "", "framegrabber.numBuffs", argType::Required, "framegrabber", "numBuffs", false, "int", "The EDT PDV framegrabber DMA buffer size [images]. Default is 4.");
441
443}
444
445template<class derivedT>
446void edtCamera<derivedT>::loadConfig(mx::app::appConfigurator & config)
447{
448 config(m_unit, "framegrabber.pdv_unit");
449 config(m_channel, "framegrabber.pdv_channel");
450 config(m_numBuffs, "framegrabber.numBuffs");
451
452 m_readTimeout = 1000;
453 m_writeTimeout = 1000;
455
456}
457
458
459template<class derivedT>
461{
462 if(pdvConfig(derived().m_startupMode) < 0)
463 {
464 derivedT::template log<software_error>({__FILE__, __LINE__});
465 return -1;
466 }
467
468 return 0;
469
470}
471
472template<class derivedT>
474{
475 return 0;
476
477}
478
479template<class derivedT>
481{
482 return 0;
483}
484
485template<class derivedT>
487{
488 return 0;
489}
490
491template<class derivedT>
493{
494 return 0;
495}
496
497template<class derivedT>
499{
500 pdv_start_images(m_pdv, m_numBuffs);
501
502 return 0;
503}
504
505template<class derivedT>
506int edtCamera<derivedT>::pdvAcquire( timespec & currImageTimestamp )
507{
508
509 uint dmaTimeStamp[2];
510 m_image_p = pdv_wait_last_image_timed(m_pdv, dmaTimeStamp);
511 //m_image_p = pdv_wait_image_timed(m_pdv, dmaTimeStamp);
512 pdv_start_image(m_pdv);
513
514 currImageTimestamp.tv_sec = dmaTimeStamp[0];
515 currImageTimestamp.tv_nsec = dmaTimeStamp[1];
516
517
518 return 0;
519}
520
521template<class derivedT>
523{
524
525 if(pdvConfig(derived().m_nextMode) < 0)
526 {
527 derivedT::template log<text_log>("error trying to re-configure with " + derived().m_nextMode, logPrio::LOG_ERROR);
528 sleep(1);
529 }
530 else
531 {
532 derived().m_nextMode = "";
533 }
534
535 return 0;
536}
537
538
539
540template<class derivedT>
542{
543 return 0;
544}
545
546
547} //namespace dev
548} //namespace app
549} //namespace MagAOX
550
551#endif //MAGAOX_NOEDT
552#endif //edtCamera_hpp
MagAO-X EDT framegrabber interface.
Definition edtCamera.hpp:57
int m_channel
EDT PDV board channel number.
Definition edtCamera.hpp:69
int m_raw_depth
The bit-depth of the frame, according to the framegrabber.
Definition edtCamera.hpp:88
int appLogic()
Application logic.
u_char * m_image_p
The image data grabbed.
Definition edtCamera.hpp:80
int m_raw_height
The height of the frame, according to the framegrabber.
Definition edtCamera.hpp:86
PdvDev * m_pdv
The EDT PDV device handle.
Definition edtCamera.hpp:78
int pdvConfig(std::string &cfgname)
Configure the EDT framegrabber.
int pdvAcquire(timespec &currImageTimestamp)
int pdvSerialWriteRead(std::string &response, const std::string &command)
Send a serial command over cameralink and retrieve the response.
int m_unit
EDT PDV board unit number.
Definition edtCamera.hpp:68
std::string m_cameraType
The camera type according to the framegrabber.
Definition edtCamera.hpp:89
~edtCamera() noexcept
Destructor, destroys the PdvDev structure.
edtCamera()
C'tor, sets up stdCamera.
int appStartup()
Startup function.
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int onPowerOff()
Actions on power off.
int updateINDI()
The static callback function to be registered for the channel properties.
int m_raw_width
The width of the frame, according to the framegrabber.
Definition edtCamera.hpp:87
int m_numBuffs
EDT PDV DMA buffer size, indicating number of images.
Definition edtCamera.hpp:70
int appShutdown()
Application the shutdown.
int whilePowerOff()
Actions while powered off.
#define MAGAOX_PDV_SERBUFSIZE
Configuration and control of an input and output device.
Definition dm.hpp:24
static constexpr logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
Standard camera interface.
An input/output capable device.
Definition ioDevice.hpp:27
int loadConfig(mx::app::appConfigurator &config)
Load the device section from an application configurator.
Definition ioDevice.cpp:28
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the device section.
Definition ioDevice.cpp:20
Software ERR log entry.
A simple text log, a string-type log.
Definition text_log.hpp:24