API
 
Loading...
Searching...
No Matches
cred2Utils.hpp
Go to the documentation of this file.
1/** \file cred2Utils.hpp
2 * \brief Utilities for the C-RED 2 camera controller.
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup cred2Ctrl_files
7 */
8
9#ifndef cred2Utils_hpp
10#define cred2Utils_hpp
11
12#include <algorithm>
13#include <cctype>
14#include <cmath>
15#include <cstdlib>
16#include <string>
17#include <vector>
18
19#include <mx/ioutils/stringUtils.hpp>
20
21namespace MagAOX
22{
23namespace app
24{
25
26/// Structure holding the temperature values reported by the C-RED 2.
27/**
28 * \ingroup cred2Ctrl
29 */
31{
32 float motherboard{ 0 }; ///< Motherboard temperature [C].
33 float frontend{ 0 }; ///< Front-end temperature [C].
34 float powerboard{ 0 }; ///< Power-board temperature [C].
35 float snake{ 0 }; ///< Detector temperature [C].
36 float setpoint{ 0 }; ///< Detector temperature setpoint [C].
37 float peltier{ 0 }; ///< External TEC temperature [C].
38 float heatsink{ 0 }; ///< Heatsink temperature [C].
39
40 /// Compare two cached temperature sets.
41 bool operator==( const cred2Temps &t /**< [in] the values to compare against */ ) const
42 {
43 return motherboard == t.motherboard && frontend == t.frontend && powerboard == t.powerboard &&
44 snake == t.snake && setpoint == t.setpoint && peltier == t.peltier && heatsink == t.heatsink;
45 }
46
47 /// Mark all temperature values invalid.
49 {
50 motherboard = -999;
51 frontend = -999;
52 powerboard = -999;
53 snake = -999;
54 setpoint = -999;
55 peltier = -999;
56 heatsink = -999;
57
58 return 0;
59 }
60};
61
62/// C-RED 2 ROI expressed as 0-based inclusive column and row limits.
63/**
64 * \ingroup cred2Ctrl
65 */
67{
68 int startColumn{ 0 }; ///< First included column.
69 int endColumn{ 0 }; ///< Last included column.
70 int startRow{ 0 }; ///< First included row.
71 int endRow{ 0 }; ///< Last included row.
72 bool fullFrame{ true }; ///< True when the ROI spans the full detector.
73};
74
75/// Strip an optional prompt and surrounding whitespace from a C-RED 2 CLI response.
76inline std::string cred2CleanResponse( const std::string &response /**< [in] raw CLI response */ )
77{
78 std::string clean = response;
79
80 size_t promptPos = clean.find( "fli-cli>" );
81 if( promptPos != std::string::npos )
82 {
83 clean.erase( promptPos );
84 }
85
86 size_t first = 0;
87 while( first < clean.size() && std::isspace( static_cast<unsigned char>( clean[first] ) ) )
88 {
89 ++first;
90 }
91
92 size_t last = clean.size();
93 while( last > first && std::isspace( static_cast<unsigned char>( clean[last - 1] ) ) )
94 {
95 --last;
96 }
97
98 return clean.substr( first, last - first );
99}
100
101/// Parse a raw numeric response into a float.
102inline int cred2ParseFloat( float &value, ///< [out] parsed floating-point value
103 const std::string &response /**< [in] raw or cleaned CLI response */
104)
105{
106 std::string clean = cred2CleanResponse( response );
107 if( clean.empty() )
108 {
109 return -1;
110 }
111
112 char *end = nullptr;
113 value = std::strtof( clean.c_str(), &end );
114
115 if( end == clean.c_str() )
116 {
117 return -1;
118 }
119
120 while( end != nullptr && *end != '\0' && std::isspace( static_cast<unsigned char>( *end ) ) )
121 {
122 ++end;
123 }
124
125 if( end != nullptr && *end != '\0' )
126 {
127 return -1;
128 }
129
130 return 0;
131}
132
133/// Parse a delimited list of raw numeric responses into a float vector.
134inline int cred2ParseFloatVector( std::vector<float> &values, ///< [out] parsed floating-point values
135 const std::string &response, /**< [in] raw or cleaned CLI response */
136 size_t expectedValues /**< [in] expected number of parsed values, or 0 */
137)
138{
139 std::string clean = cred2CleanResponse( response );
140 std::vector<std::string> tokens;
141
142 mx::ioutils::parseStringVector( tokens, clean, ":, \t\r\n" );
143
144 if( tokens.empty() )
145 {
146 return -1;
147 }
148
149 if( expectedValues > 0 && tokens.size() != expectedValues )
150 {
151 return -1;
152 }
153
154 values.clear();
155 values.reserve( tokens.size() );
156
157 for( const auto &token : tokens )
158 {
159 float value = 0;
160
161 if( cred2ParseFloat( value, token ) < 0 )
162 {
163 values.clear();
164 return -1;
165 }
166
167 values.push_back( value );
168 }
169
170 return 0;
171}
172
173/// Parse a raw on/off response into a boolean.
174inline int cred2ParseBool( bool &value, ///< [out] parsed boolean value
175 const std::string &response /**< [in] raw or cleaned CLI response */
176)
177{
178 std::string clean = cred2CleanResponse( response );
179 std::transform( clean.begin(),
180 clean.end(),
181 clean.begin(),
182 []( unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
183
184 if( clean == "on" || clean == "true" || clean == "1" )
185 {
186 value = true;
187 return 0;
188 }
189
190 if( clean == "off" || clean == "false" || clean == "0" )
191 {
192 value = false;
193 return 0;
194 }
195
196 return -1;
197}
198
199/// Parse a raw range response such as `0-639`.
200inline int cred2ParseRange( int &firstValue, ///< [out] first parsed range value
201 int &secondValue, ///< [out] second parsed range value
202 const std::string &response /**< [in] raw or cleaned CLI response */
203);
204
205/// Parse a raw cropping status response such as `on` or `on:192-447:128-383`.
206inline int cred2ParseCropState( bool &enabled, ///< [out] parsed cropping-enabled flag
207 int &startColumn, ///< [out] parsed first included column
208 int &endColumn, ///< [out] parsed last included column
209 int &startRow, ///< [out] parsed first included row
210 int &endRow, ///< [out] parsed last included row
211 const std::string &response /**< [in] raw or cleaned CLI response */
212)
213{
214 std::string clean = cred2CleanResponse( response );
215 std::vector<std::string> tokens;
216
217 mx::ioutils::parseStringVector( tokens, clean, ":" );
218
219 if( tokens.empty() )
220 {
221 return -1;
222 }
223
224 if( cred2ParseBool( enabled, tokens[0] ) < 0 )
225 {
226 return -1;
227 }
228
229 if( tokens.size() == 1 )
230 {
231 startColumn = 0;
232 endColumn = 0;
233 startRow = 0;
234 endRow = 0;
235 return 0;
236 }
237
238 if( tokens.size() != 3 )
239 {
240 return -1;
241 }
242
243 if( cred2ParseRange( startColumn, endColumn, tokens[1] ) < 0 || cred2ParseRange( startRow, endRow, tokens[2] ) < 0 )
244 {
245 return -1;
246 }
247
248 return 0;
249}
250
251/// Parse a raw range response such as `0-639`.
252inline int cred2ParseRange( int &firstValue, ///< [out] first parsed range value
253 int &secondValue, ///< [out] second parsed range value
254 const std::string &response /**< [in] raw or cleaned CLI response */
255)
256{
257 std::string clean = cred2CleanResponse( response );
258 std::vector<std::string> tokens;
259 mx::ioutils::parseStringVector( tokens, clean, "-, \t\r\n" );
260
261 if( tokens.size() != 2 )
262 {
263 return -1;
264 }
265
266 try
267 {
268 firstValue = mx::ioutils::stoT<int>( tokens[0] );
269 secondValue = mx::ioutils::stoT<int>( tokens[1] );
270 }
271 catch( ... )
272 {
273 return -1;
274 }
275
276 return 0;
277}
278
279/// Check whether a command response looks successful.
280inline bool cred2ResponseOK( const std::string &response /**< [in] raw or cleaned CLI response */ )
281{
282 std::string clean = cred2CleanResponse( response );
283 std::string lower = clean;
284 std::transform( lower.begin(),
285 lower.end(),
286 lower.begin(),
287 []( unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
288
289 if( lower.find( "error" ) != std::string::npos || lower.find( "fail" ) != std::string::npos )
290 {
291 return false;
292 }
293
294 return true;
295}
296
297/// Convert a MagAO-X ROI center/size description into C-RED 2 corners.
298inline int cred2RoiFromCenter( cred2Roi &roi, ///< [out] the corresponding C-RED 2 ROI
299 float centerX, /**< [in] ROI x center coordinate */
300 float centerY, /**< [in] ROI y center coordinate */
301 int width, /**< [in] ROI width in pixels */
302 int height, /**< [in] ROI height in pixels */
303 int fullWidth, /**< [in] detector full-frame width */
304 int fullHeight /**< [in] detector full-frame height */
305)
306{
307 if( width < 1 || height < 1 || fullWidth < 1 || fullHeight < 1 )
308 {
309 return -1;
310 }
311
312 roi.startColumn = static_cast<int>( std::lround( centerX - 0.5f * ( static_cast<float>( width ) - 1.0f ) ) );
313 roi.endColumn = roi.startColumn + width - 1;
314 roi.startRow = static_cast<int>( std::lround( centerY - 0.5f * ( static_cast<float>( height ) - 1.0f ) ) );
315 roi.endRow = roi.startRow + height - 1;
316
317 if( roi.startColumn < 0 || roi.startRow < 0 || roi.endColumn >= fullWidth || roi.endRow >= fullHeight )
318 {
319 return -1;
320 }
321
322 roi.fullFrame =
323 roi.startColumn == 0 && roi.endColumn == fullWidth - 1 && roi.startRow == 0 && roi.endRow == fullHeight - 1;
324
325 return 0;
326}
327
328/// Convert C-RED 2 ROI corners into a MagAO-X ROI center/size description.
329inline int cred2RoiToCenter( float &centerX, ///< [out] ROI x center coordinate
330 float &centerY, ///< [out] ROI y center coordinate
331 int &width, ///< [out] ROI width in pixels
332 int &height, ///< [out] ROI height in pixels
333 const cred2Roi &roi, /**< [in] the C-RED 2 ROI to convert */
334 int fullWidth, /**< [in] detector full-frame width */
335 int fullHeight /**< [in] detector full-frame height */
336)
337{
338 if( roi.startColumn < 0 || roi.startRow < 0 || roi.endColumn < roi.startColumn || roi.endRow < roi.startRow ||
339 roi.endColumn >= fullWidth || roi.endRow >= fullHeight )
340 {
341 return -1;
342 }
343
344 width = roi.endColumn - roi.startColumn + 1;
345 height = roi.endRow - roi.startRow + 1;
346
347 centerX = roi.startColumn + 0.5f * ( static_cast<float>( width ) - 1.0f );
348 centerY = roi.startRow + 0.5f * ( static_cast<float>( height ) - 1.0f );
349
350 return 0;
351}
352
353/// Format the column command payload for `set cropping columns`.
354inline std::string cred2ColumnsSpec( const cred2Roi &roi /**< [in] the ROI to format */ )
355{
356 return std::to_string( roi.startColumn ) + "-" + std::to_string( roi.endColumn );
357}
358
359/// Format the row command payload for `set cropping rows`.
360inline std::string cred2RowsSpec( const cred2Roi &roi /**< [in] the ROI to format */ )
361{
362 return std::to_string( roi.startRow ) + "-" + std::to_string( roi.endRow );
363}
364
365} // namespace app
366} // namespace MagAOX
367
368#endif // cred2Utils_hpp
bool fullFrame
True when the ROI spans the full detector.
int endRow
Last included row.
int startRow
First included row.
int endColumn
Last included column.
int startColumn
First included column.
C-RED 2 ROI expressed as 0-based inclusive column and row limits.
std::string cred2ColumnsSpec(const cred2Roi &roi)
Format the column command payload for set cropping columns.
std::string cred2CleanResponse(const std::string &response)
Strip an optional prompt and surrounding whitespace from a C-RED 2 CLI response.
int cred2ParseRange(int &firstValue, int &secondValue, const std::string &response)
Parse a raw range response such as 0-639.
int cred2RoiToCenter(float &centerX, float &centerY, int &width, int &height, const cred2Roi &roi, int fullWidth, int fullHeight)
Convert C-RED 2 ROI corners into a MagAO-X ROI center/size description.
int cred2ParseCropState(bool &enabled, int &startColumn, int &endColumn, int &startRow, int &endRow, const std::string &response)
Parse a raw cropping status response such as on or on:192-447:128-383.
int cred2RoiFromCenter(cred2Roi &roi, float centerX, float centerY, int width, int height, int fullWidth, int fullHeight)
Convert a MagAO-X ROI center/size description into C-RED 2 corners.
int cred2ParseFloatVector(std::vector< float > &values, const std::string &response, size_t expectedValues)
Parse a delimited list of raw numeric responses into a float vector.
bool cred2ResponseOK(const std::string &response)
Check whether a command response looks successful.
std::string cred2RowsSpec(const cred2Roi &roi)
Format the row command payload for set cropping rows.
int cred2ParseFloat(float &value, const std::string &response)
Parse a raw numeric response into a float.
int cred2ParseBool(bool &value, const std::string &response)
Parse a raw on/off response into a boolean.
Definition dm.hpp:19
Structure holding the temperature values reported by the C-RED 2.
float powerboard
Power-board temperature [C].
float setpoint
Detector temperature setpoint [C].
float peltier
External TEC temperature [C].
float motherboard
Motherboard temperature [C].
bool operator==(const cred2Temps &t) const
Compare two cached temperature sets.
int setInvalid()
Mark all temperature values invalid.
float snake
Detector temperature [C].
float frontend
Front-end temperature [C].
float heatsink
Heatsink temperature [C].