Line data Source code
1 : /** \file xt1121Ctrl.hpp
2 : * \brief The MagAO-X Acromag XT 1121digital I/O controller.
3 : *
4 : * \author Jared R. Males (jaredmales@gmail.com)
5 : *
6 : * \ingroup xt1121Ctrl_files
7 : */
8 :
9 : #ifndef xt1121Ctrl_hpp
10 : #define xt1121Ctrl_hpp
11 :
12 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
13 : #include "../../magaox_git_version.h"
14 :
15 : #include "xtChannels.hpp"
16 :
17 : namespace MagAOX
18 : {
19 : namespace app
20 : {
21 :
22 : /** \defgroup xt1121Ctrl Acromag xt1121Controller
23 : * \brief Control of an Acromag xt1121digital I/O module
24 : *
25 : * <a href="../handbook/operating/software/apps/xt1121Ctrl.html">Application Documentation</a>
26 : *
27 : * \ingroup apps
28 : *
29 : */
30 :
31 : /** \defgroup xt1121Ctrl_files Acromag xt1121Controller Files
32 : * \ingroup xt1121Ctrl
33 : */
34 :
35 : /** MagAO-X application to control an Acromag xt1121digital i/o module
36 : *
37 : * \ingroup xt1121Ctrl
38 : *
39 : */
40 : class xt1121Ctrl : public MagAOXApp<>, public xt1121Channels
41 : {
42 :
43 : protected:
44 : /** \name configurable parameters
45 : *@{
46 : */
47 :
48 : std::string m_address; ///< The I.P. address of the device
49 :
50 : uint16_t m_port{ 502 }; ///< The port to use. Default is 502 for modbus.
51 :
52 : ///@}
53 :
54 : std::mutex m_modbusMutex; ///< Protects m_mb lifetime and all modbus socket I/O.
55 :
56 : std::atomic<bool> m_callbacksEnabled{ true }; ///< Gates INDI callbacks during shutdown/teardown.
57 :
58 : modbus *m_mb{ nullptr }; ///< The modbus protocol communication object
59 :
60 : /// Close and delete the current modbus object under m_modbusMutex.
61 : void closeModbus();
62 :
63 : public:
64 : /// Default c'tor
65 : xt1121Ctrl();
66 :
67 : /// Destructor
68 : ~xt1121Ctrl() noexcept;
69 :
70 : /// Setup the configuration system (called by MagAOXApp::setup())
71 : virtual void setupConfig();
72 :
73 : /// load the configuration system results (called by MagAOXApp::setup())
74 : virtual void loadConfig();
75 :
76 : /// Startup functions
77 : /** Sets up the INDI vars.
78 : *
79 : */
80 : virtual int appStartup();
81 :
82 : /// Implementation of the FSM for the Siglent SDG
83 : virtual int appLogic();
84 :
85 : /// Implementation of the on-power-off FSM logic
86 : virtual int onPowerOff();
87 :
88 : /// Implementation of the while-powered-off FSM
89 : virtual int whilePowerOff();
90 :
91 : /// Do any needed shutdown tasks. Currently nothing in this app.
92 : virtual int appShutdown();
93 :
94 : /// Get the current state of the outlets.
95 : /**
96 : * \returns 0 on success
97 : * \returns -1 on error
98 : */
99 : int getState();
100 :
101 : // INDI:
102 : protected:
103 : // declare our properties
104 : pcf::IndiProperty m_indiP_ch00;
105 : pcf::IndiProperty m_indiP_ch01;
106 : pcf::IndiProperty m_indiP_ch02;
107 : pcf::IndiProperty m_indiP_ch03;
108 : pcf::IndiProperty m_indiP_ch04;
109 : pcf::IndiProperty m_indiP_ch05;
110 : pcf::IndiProperty m_indiP_ch06;
111 : pcf::IndiProperty m_indiP_ch07;
112 : pcf::IndiProperty m_indiP_ch08;
113 : pcf::IndiProperty m_indiP_ch09;
114 : pcf::IndiProperty m_indiP_ch10;
115 : pcf::IndiProperty m_indiP_ch11;
116 : pcf::IndiProperty m_indiP_ch12;
117 : pcf::IndiProperty m_indiP_ch13;
118 : pcf::IndiProperty m_indiP_ch14;
119 : pcf::IndiProperty m_indiP_ch15;
120 :
121 : public:
122 : /// Callback worker to actually set or clear a channel and send it to the device
123 : /** Contains the target/current logic, and calls the xtChannels::setRegisters
124 : * function, and then the modbus write_registers.
125 : *
126 : * \returns 0 on success
127 : * \returns -1 on error
128 : */
129 : int channelSetCallback( size_t chNo, ///< [in] The channel number to set
130 : pcf::IndiProperty &ipToSet, ///< [in] The corresponding local INDI property
131 : const pcf::IndiProperty &ipRecv ///< [in] The received INDI property
132 : );
133 :
134 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch00 );
135 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch01 );
136 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch02 );
137 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch03 );
138 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch04 );
139 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch05 );
140 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch06 );
141 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch07 );
142 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch08 );
143 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch09 );
144 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch10 );
145 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch11 );
146 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch12 );
147 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch13 );
148 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch14 );
149 0 : INDI_NEWCALLBACK_DECL( xt1121Ctrl, m_indiP_ch15 );
150 : };
151 :
152 3 : inline xt1121Ctrl::xt1121Ctrl() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
153 : {
154 1 : m_powerMgtEnabled = true;
155 1 : m_powerOnWait = 2; // set default.
156 1 : return;
157 0 : }
158 :
159 1 : inline xt1121Ctrl::~xt1121Ctrl() noexcept
160 : {
161 1 : m_callbacksEnabled = false;
162 1 : closeModbus();
163 :
164 1 : return;
165 1 : }
166 :
167 0 : inline void xt1121Ctrl::setupConfig()
168 : {
169 0 : config.add( "device.address",
170 : "",
171 : "device.address",
172 : argType::Required,
173 : "device",
174 : "address",
175 : true,
176 : "string",
177 : "The device I.P. address." );
178 :
179 0 : config.add( "device.port",
180 : "",
181 : "device.port",
182 : argType::Required,
183 : "device",
184 : "port",
185 : true,
186 : "int",
187 : "The device port. Default is 502." );
188 :
189 0 : config.add( "device.inputOnly",
190 : "",
191 : "device.inputOnly",
192 : argType::Required,
193 : "device",
194 : "inputOnly",
195 : false,
196 : "vector<int>",
197 : "List of channels which are input-only." );
198 0 : }
199 :
200 0 : inline void xt1121Ctrl::loadConfig()
201 : {
202 0 : config( m_address, "device.address" );
203 0 : config( m_port, "device.port" );
204 :
205 0 : std::vector<int> ino;
206 0 : config( ino, "device.inputOnly" );
207 :
208 0 : for( size_t i = 0; i < ino.size(); ++i )
209 : {
210 0 : if( setInputOnly( ino[i] ) != 0 )
211 : {
212 0 : log<text_log>( "Error setting channel " + std::to_string( i ) + " to input only.", logPrio::LOG_ERROR );
213 : }
214 : }
215 0 : }
216 :
217 0 : inline int xt1121Ctrl::appStartup()
218 : {
219 : // set up the INDI properties
220 0 : REG_INDI_NEWPROP( m_indiP_ch00, "ch00", pcf::IndiProperty::Number );
221 0 : m_indiP_ch00.add( pcf::IndiElement( "current" ) );
222 0 : m_indiP_ch00["current"].set( -1 );
223 0 : m_indiP_ch00.add( pcf::IndiElement( "target" ) );
224 :
225 0 : REG_INDI_NEWPROP( m_indiP_ch01, "ch01", pcf::IndiProperty::Number );
226 0 : m_indiP_ch01.add( pcf::IndiElement( "current" ) );
227 0 : m_indiP_ch01["current"].set( -1 );
228 0 : m_indiP_ch01.add( pcf::IndiElement( "target" ) );
229 :
230 0 : REG_INDI_NEWPROP( m_indiP_ch02, "ch02", pcf::IndiProperty::Number );
231 0 : m_indiP_ch02.add( pcf::IndiElement( "current" ) );
232 0 : m_indiP_ch02["current"].set( -1 );
233 0 : m_indiP_ch02.add( pcf::IndiElement( "target" ) );
234 :
235 0 : REG_INDI_NEWPROP( m_indiP_ch03, "ch03", pcf::IndiProperty::Number );
236 0 : m_indiP_ch03.add( pcf::IndiElement( "current" ) );
237 0 : m_indiP_ch03["current"].set( -1 );
238 0 : m_indiP_ch03.add( pcf::IndiElement( "target" ) );
239 :
240 0 : REG_INDI_NEWPROP( m_indiP_ch04, "ch04", pcf::IndiProperty::Number );
241 0 : m_indiP_ch04.add( pcf::IndiElement( "current" ) );
242 0 : m_indiP_ch04["current"].set( -1 );
243 0 : m_indiP_ch04.add( pcf::IndiElement( "target" ) );
244 :
245 0 : REG_INDI_NEWPROP( m_indiP_ch05, "ch05", pcf::IndiProperty::Number );
246 0 : m_indiP_ch05.add( pcf::IndiElement( "current" ) );
247 0 : m_indiP_ch05["current"].set( -1 );
248 0 : m_indiP_ch05.add( pcf::IndiElement( "target" ) );
249 :
250 0 : REG_INDI_NEWPROP( m_indiP_ch06, "ch06", pcf::IndiProperty::Number );
251 0 : m_indiP_ch06.add( pcf::IndiElement( "current" ) );
252 0 : m_indiP_ch06["current"].set( -1 );
253 0 : m_indiP_ch06.add( pcf::IndiElement( "target" ) );
254 :
255 0 : REG_INDI_NEWPROP( m_indiP_ch07, "ch07", pcf::IndiProperty::Number );
256 0 : m_indiP_ch07.add( pcf::IndiElement( "current" ) );
257 0 : m_indiP_ch07["current"].set( -1 );
258 0 : m_indiP_ch07.add( pcf::IndiElement( "target" ) );
259 :
260 0 : REG_INDI_NEWPROP( m_indiP_ch08, "ch08", pcf::IndiProperty::Number );
261 0 : m_indiP_ch08.add( pcf::IndiElement( "current" ) );
262 0 : m_indiP_ch08["current"].set( -1 );
263 0 : m_indiP_ch08.add( pcf::IndiElement( "target" ) );
264 :
265 0 : REG_INDI_NEWPROP( m_indiP_ch09, "ch09", pcf::IndiProperty::Number );
266 0 : m_indiP_ch09.add( pcf::IndiElement( "current" ) );
267 0 : m_indiP_ch09["current"].set( -1 );
268 0 : m_indiP_ch09.add( pcf::IndiElement( "target" ) );
269 :
270 0 : REG_INDI_NEWPROP( m_indiP_ch10, "ch10", pcf::IndiProperty::Number );
271 0 : m_indiP_ch10.add( pcf::IndiElement( "current" ) );
272 0 : m_indiP_ch10["current"].set( -1 );
273 0 : m_indiP_ch10.add( pcf::IndiElement( "target" ) );
274 :
275 0 : REG_INDI_NEWPROP( m_indiP_ch11, "ch11", pcf::IndiProperty::Number );
276 0 : m_indiP_ch11.add( pcf::IndiElement( "current" ) );
277 0 : m_indiP_ch11["current"].set( -1 );
278 0 : m_indiP_ch11.add( pcf::IndiElement( "target" ) );
279 :
280 0 : REG_INDI_NEWPROP( m_indiP_ch12, "ch12", pcf::IndiProperty::Number );
281 0 : m_indiP_ch12.add( pcf::IndiElement( "current" ) );
282 0 : m_indiP_ch12["current"].set( -1 );
283 0 : m_indiP_ch12.add( pcf::IndiElement( "target" ) );
284 :
285 0 : REG_INDI_NEWPROP( m_indiP_ch13, "ch13", pcf::IndiProperty::Number );
286 0 : m_indiP_ch13.add( pcf::IndiElement( "current" ) );
287 0 : m_indiP_ch13["current"].set( -1 );
288 0 : m_indiP_ch13.add( pcf::IndiElement( "target" ) );
289 :
290 0 : REG_INDI_NEWPROP( m_indiP_ch14, "ch14", pcf::IndiProperty::Number );
291 0 : m_indiP_ch14.add( pcf::IndiElement( "current" ) );
292 0 : m_indiP_ch14["current"].set( -1 );
293 0 : m_indiP_ch14.add( pcf::IndiElement( "target" ) );
294 :
295 0 : REG_INDI_NEWPROP( m_indiP_ch15, "ch15", pcf::IndiProperty::Number );
296 0 : m_indiP_ch15.add( pcf::IndiElement( "current" ) );
297 0 : m_indiP_ch15["current"].set( -1 );
298 0 : m_indiP_ch15.add( pcf::IndiElement( "target" ) );
299 :
300 0 : return 0;
301 : }
302 :
303 0 : inline int xt1121Ctrl::appLogic()
304 : {
305 0 : if( state() == stateCodes::POWERON )
306 : {
307 0 : if( !powerOnWaitElapsed() )
308 : {
309 0 : return 0;
310 : }
311 :
312 0 : state( stateCodes::NOTCONNECTED );
313 : }
314 :
315 0 : if( state() == stateCodes::NOTCONNECTED || state() == stateCodes::ERROR )
316 : {
317 : // Might have gotten here because of a power off.
318 0 : if( m_powerState == 0 )
319 : {
320 0 : return 0;
321 : }
322 :
323 0 : closeModbus();
324 :
325 0 : modbus *newMb = new( std::nothrow ) modbus( m_address, m_port );
326 :
327 0 : if( newMb == nullptr )
328 : {
329 0 : return log<software_critical, -1>( { __FILE__, __LINE__, "allocation failure" } );
330 : }
331 :
332 0 : newMb->modbus_set_slave_id( 1 );
333 :
334 0 : if( newMb->modbus_connect() == false )
335 : {
336 0 : if( !stateLogged() )
337 : {
338 0 : log<text_log>( "connect failed at " + m_address + ":" + std::to_string( m_port ) );
339 : }
340 0 : delete newMb;
341 0 : return 0;
342 : }
343 :
344 0 : if( !newMb->modbus_set_timeouts( 2, 0 ) )
345 : {
346 0 : log<text_log>( "failed setting modbus socket timeouts", logPrio::LOG_WARNING );
347 : }
348 :
349 : { // mutex scope
350 0 : std::lock_guard<std::mutex> lock( m_modbusMutex );
351 0 : m_mb = newMb;
352 0 : }
353 :
354 0 : state( stateCodes::CONNECTED );
355 0 : log<text_log>( "connected to " + m_address + ":" + std::to_string( m_port ) );
356 : }
357 :
358 0 : if( state() == stateCodes::CONNECTED )
359 : {
360 0 : if( getState() == 0 )
361 : {
362 0 : state( stateCodes::READY );
363 0 : return 0;
364 : }
365 : else
366 : {
367 0 : state( stateCodes::ERROR );
368 0 : return log<software_error, 0>( { __FILE__, __LINE__ } );
369 : }
370 : }
371 :
372 0 : if( state() == stateCodes::READY || state() == stateCodes::OPERATING )
373 : {
374 0 : if( getState() < 0 )
375 : {
376 0 : if( m_powerState == 0 )
377 : {
378 0 : return 0;
379 : }
380 :
381 0 : state( stateCodes::ERROR );
382 0 : return 0;
383 : }
384 :
385 0 : return 0;
386 : }
387 :
388 : // Fall through check?
389 :
390 0 : return 0;
391 : }
392 :
393 0 : inline int xt1121Ctrl::onPowerOff()
394 : {
395 0 : std::lock_guard<std::mutex> lock( m_indiMutex );
396 :
397 0 : updateIfChanged( m_indiP_ch00, "current", -1 );
398 0 : updateIfChanged( m_indiP_ch00, "target", -1 );
399 :
400 0 : updateIfChanged( m_indiP_ch01, "current", -1 );
401 0 : updateIfChanged( m_indiP_ch01, "target", -1 );
402 :
403 0 : updateIfChanged( m_indiP_ch02, "current", -1 );
404 0 : updateIfChanged( m_indiP_ch02, "target", -1 );
405 :
406 0 : updateIfChanged( m_indiP_ch03, "current", -1 );
407 0 : updateIfChanged( m_indiP_ch03, "target", -1 );
408 :
409 0 : updateIfChanged( m_indiP_ch04, "current", -1 );
410 0 : updateIfChanged( m_indiP_ch04, "target", -1 );
411 :
412 0 : updateIfChanged( m_indiP_ch05, "current", -1 );
413 0 : updateIfChanged( m_indiP_ch05, "target", -1 );
414 :
415 0 : updateIfChanged( m_indiP_ch06, "current", -1 );
416 0 : updateIfChanged( m_indiP_ch06, "target", -1 );
417 :
418 0 : updateIfChanged( m_indiP_ch07, "current", -1 );
419 0 : updateIfChanged( m_indiP_ch07, "target", -1 );
420 :
421 0 : updateIfChanged( m_indiP_ch08, "current", -1 );
422 0 : updateIfChanged( m_indiP_ch08, "target", -1 );
423 :
424 0 : updateIfChanged( m_indiP_ch09, "current", -1 );
425 0 : updateIfChanged( m_indiP_ch09, "target", -1 );
426 :
427 0 : updateIfChanged( m_indiP_ch10, "current", -1 );
428 0 : updateIfChanged( m_indiP_ch10, "target", -1 );
429 :
430 0 : updateIfChanged( m_indiP_ch11, "current", -1 );
431 0 : updateIfChanged( m_indiP_ch11, "target", -1 );
432 :
433 0 : updateIfChanged( m_indiP_ch12, "current", -1 );
434 0 : updateIfChanged( m_indiP_ch12, "target", -1 );
435 :
436 0 : updateIfChanged( m_indiP_ch13, "current", -1 );
437 0 : updateIfChanged( m_indiP_ch13, "target", -1 );
438 :
439 0 : updateIfChanged( m_indiP_ch14, "current", -1 );
440 0 : updateIfChanged( m_indiP_ch14, "target", -1 );
441 :
442 0 : updateIfChanged( m_indiP_ch15, "current", -1 );
443 0 : updateIfChanged( m_indiP_ch15, "target", -1 );
444 :
445 0 : return 0;
446 0 : }
447 :
448 0 : inline int xt1121Ctrl::whilePowerOff()
449 : {
450 0 : return 0;
451 : }
452 :
453 0 : inline int xt1121Ctrl::appShutdown()
454 : {
455 0 : m_callbacksEnabled = false;
456 0 : closeModbus();
457 0 : return 0;
458 : }
459 :
460 1 : inline void xt1121Ctrl::closeModbus()
461 : {
462 1 : std::lock_guard<std::mutex> lock( m_modbusMutex );
463 :
464 1 : if( !m_mb )
465 : {
466 1 : return;
467 : }
468 :
469 : try
470 : {
471 0 : m_mb->modbus_close();
472 : }
473 0 : catch( ... )
474 : {
475 0 : }
476 :
477 0 : delete m_mb;
478 0 : m_mb = nullptr;
479 1 : }
480 :
481 0 : inline int xt1121Ctrl::getState()
482 : {
483 0 : if( shutdown() != 0 )
484 : {
485 0 : return 0;
486 : }
487 :
488 : uint16_t input_regs[numRegisters];
489 :
490 : { // mutex scope
491 0 : std::lock_guard<std::mutex> lock( m_modbusMutex );
492 :
493 0 : if( m_mb == nullptr )
494 : {
495 0 : return -1;
496 : }
497 :
498 : try
499 : {
500 0 : m_mb->modbus_read_input_registers( 0, numRegisters, input_regs );
501 : }
502 0 : catch( std::exception &e )
503 : {
504 0 : if( m_powerState == 0 )
505 : {
506 0 : return 0; // due to power off
507 : }
508 :
509 0 : return log<software_error, -1>( { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
510 0 : }
511 0 : }
512 :
513 0 : std::lock_guard<std::mutex> lock( m_indiMutex );
514 0 : if( readRegisters( input_regs ) != 0 )
515 : {
516 0 : return log<software_error, -1>( { __FILE__, __LINE__ } );
517 : }
518 :
519 0 : updateIfChanged( m_indiP_ch00, "current", channel( 0 ) );
520 0 : updateIfChanged( m_indiP_ch01, "current", channel( 1 ) );
521 0 : updateIfChanged( m_indiP_ch02, "current", channel( 2 ) );
522 0 : updateIfChanged( m_indiP_ch03, "current", channel( 3 ) );
523 0 : updateIfChanged( m_indiP_ch04, "current", channel( 4 ) );
524 0 : updateIfChanged( m_indiP_ch05, "current", channel( 5 ) );
525 0 : updateIfChanged( m_indiP_ch06, "current", channel( 6 ) );
526 0 : updateIfChanged( m_indiP_ch07, "current", channel( 7 ) );
527 0 : updateIfChanged( m_indiP_ch08, "current", channel( 8 ) );
528 0 : updateIfChanged( m_indiP_ch09, "current", channel( 9 ) );
529 0 : updateIfChanged( m_indiP_ch10, "current", channel( 10 ) );
530 0 : updateIfChanged( m_indiP_ch11, "current", channel( 11 ) );
531 0 : updateIfChanged( m_indiP_ch12, "current", channel( 12 ) );
532 0 : updateIfChanged( m_indiP_ch13, "current", channel( 13 ) );
533 0 : updateIfChanged( m_indiP_ch14, "current", channel( 14 ) );
534 0 : updateIfChanged( m_indiP_ch15, "current", channel( 15 ) );
535 :
536 0 : return 0;
537 0 : }
538 :
539 0 : int xt1121Ctrl::channelSetCallback( size_t chNo, pcf::IndiProperty &ipToSet, const pcf::IndiProperty &ipRecv )
540 : {
541 0 : if( !m_callbacksEnabled || shutdown() != 0 )
542 : {
543 0 : return 0;
544 : }
545 :
546 0 : int current = -1, target = -1;
547 :
548 0 : if( ipRecv.find( "current" ) )
549 : {
550 0 : current = ipRecv["current"].get<unsigned>();
551 : }
552 :
553 0 : if( ipRecv.find( "target" ) )
554 : {
555 0 : target = ipRecv["target"].get<unsigned>();
556 : }
557 :
558 0 : if( target == -1 )
559 : {
560 0 : target = current;
561 : }
562 :
563 0 : if( target < 0 )
564 : {
565 0 : return 0;
566 : }
567 :
568 : uint16_t input_regs[numRegisters];
569 :
570 : { // mutex scope
571 0 : std::lock_guard<std::mutex> lock( m_indiMutex );
572 :
573 0 : if( target == 0 )
574 : {
575 0 : clearChannel( chNo );
576 : }
577 : else
578 : {
579 0 : setChannel( chNo );
580 : }
581 :
582 0 : target = channel( chNo ); // This checks for inputOnly
583 :
584 0 : updateIfChanged( ipToSet, "target", target );
585 :
586 0 : if( setRegisters( input_regs ) != 0 )
587 : {
588 0 : return log<software_error, -1>( { __FILE__, __LINE__ } );
589 : }
590 0 : }
591 :
592 : { // mutex scope
593 0 : std::lock_guard<std::mutex> lock( m_modbusMutex );
594 :
595 0 : if( m_mb == nullptr )
596 : {
597 0 : return 0;
598 : }
599 :
600 : try
601 : {
602 0 : m_mb->modbus_write_registers( 0, numRegisters, input_regs );
603 : }
604 0 : catch( std::exception &e )
605 : {
606 0 : if( m_powerState == 0 )
607 : {
608 0 : return 0; // due to power off
609 : }
610 :
611 0 : return log<software_error, -1>( { __FILE__, __LINE__, std::string( "Exception caught: " ) + e.what() } );
612 0 : }
613 0 : }
614 :
615 0 : log<text_log>( "Set channel " + std::to_string( chNo ) + " to " + std::to_string( target ) );
616 :
617 0 : return 0;
618 : }
619 :
620 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch00 )( const pcf::IndiProperty &ipRecv )
621 : {
622 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch00, ipRecv );
623 :
624 0 : return channelSetCallback( 0, m_indiP_ch00, ipRecv );
625 :
626 : return -1;
627 : }
628 :
629 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch01 )( const pcf::IndiProperty &ipRecv )
630 : {
631 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch01, ipRecv );
632 :
633 0 : return channelSetCallback( 1, m_indiP_ch01, ipRecv );
634 :
635 : return -1;
636 : }
637 :
638 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch02 )( const pcf::IndiProperty &ipRecv )
639 : {
640 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch02, ipRecv );
641 :
642 0 : return channelSetCallback( 2, m_indiP_ch02, ipRecv );
643 :
644 : return -1;
645 : }
646 :
647 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch03 )( const pcf::IndiProperty &ipRecv )
648 : {
649 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch03, ipRecv );
650 :
651 0 : return channelSetCallback( 3, m_indiP_ch03, ipRecv );
652 :
653 : return -1;
654 : }
655 :
656 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch04 )( const pcf::IndiProperty &ipRecv )
657 : {
658 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch04, ipRecv );
659 :
660 0 : return channelSetCallback( 4, m_indiP_ch04, ipRecv );
661 :
662 : return -1;
663 : }
664 :
665 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch05 )( const pcf::IndiProperty &ipRecv )
666 : {
667 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch05, ipRecv );
668 :
669 0 : return channelSetCallback( 5, m_indiP_ch05, ipRecv );
670 :
671 : return -1;
672 : }
673 :
674 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch06 )( const pcf::IndiProperty &ipRecv )
675 : {
676 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch06, ipRecv );
677 :
678 0 : return channelSetCallback( 6, m_indiP_ch06, ipRecv );
679 :
680 : return -1;
681 : }
682 :
683 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch07 )( const pcf::IndiProperty &ipRecv )
684 : {
685 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch07, ipRecv );
686 :
687 0 : return channelSetCallback( 7, m_indiP_ch07, ipRecv );
688 :
689 : return -1;
690 : }
691 :
692 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch08 )( const pcf::IndiProperty &ipRecv )
693 : {
694 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch08, ipRecv );
695 :
696 0 : return channelSetCallback( 8, m_indiP_ch08, ipRecv );
697 :
698 : return -1;
699 : }
700 :
701 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch09 )( const pcf::IndiProperty &ipRecv )
702 : {
703 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch09, ipRecv );
704 :
705 0 : return channelSetCallback( 9, m_indiP_ch09, ipRecv );
706 :
707 : return -1;
708 : }
709 :
710 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch10 )( const pcf::IndiProperty &ipRecv )
711 : {
712 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch10, ipRecv );
713 :
714 0 : return channelSetCallback( 10, m_indiP_ch10, ipRecv );
715 :
716 : return -1;
717 : }
718 :
719 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch11 )( const pcf::IndiProperty &ipRecv )
720 : {
721 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch11, ipRecv );
722 :
723 0 : return channelSetCallback( 11, m_indiP_ch11, ipRecv );
724 :
725 : return -1;
726 : }
727 :
728 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch12 )( const pcf::IndiProperty &ipRecv )
729 : {
730 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch12, ipRecv );
731 :
732 0 : return channelSetCallback( 12, m_indiP_ch12, ipRecv );
733 :
734 : return -1;
735 : }
736 :
737 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch13 )( const pcf::IndiProperty &ipRecv )
738 : {
739 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch13, ipRecv );
740 :
741 0 : return channelSetCallback( 13, m_indiP_ch13, ipRecv );
742 :
743 : return -1;
744 : }
745 :
746 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch14 )( const pcf::IndiProperty &ipRecv )
747 : {
748 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch14, ipRecv );
749 :
750 0 : return channelSetCallback( 14, m_indiP_ch14, ipRecv );
751 :
752 : return -1;
753 : }
754 :
755 0 : INDI_NEWCALLBACK_DEFN( xt1121Ctrl, m_indiP_ch15 )( const pcf::IndiProperty &ipRecv )
756 : {
757 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_ch15, ipRecv );
758 :
759 0 : return channelSetCallback( 15, m_indiP_ch15, ipRecv );
760 :
761 : return -1;
762 : }
763 :
764 : } // namespace app
765 : } // namespace MagAOX
766 : #endif
|