API
 
Loading...
Searching...
No Matches
cacaoInterface.hpp
Go to the documentation of this file.
1/** \file cacaoInterface.hpp
2 * \brief The MagAO-X CACAO Interface header file
3 *
4 * \ingroup cacaoInterface_files
5 */
6
7#ifndef cacaoInterface_hpp
8#define cacaoInterface_hpp
9
10#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
11#include "../../magaox_git_version.h"
12
13/** \defgroup cacaoInterface
14 * \brief The CACAO Interface to provide loop status
15 *
16 * <a href="../handbook/apps/cacaoInterface.html">Application Documentation</a>
17 *
18 * \ingroup apps
19 *
20 */
21
22/** \defgroup cacaoInterface_files
23 * \ingroup cacaoInterface
24 */
25
26namespace MagAOX
27{
28namespace app
29{
30
31/// The MagAO-X CACAO Interface
32/**
33 * \ingroup cacaoInterface
34 */
35class cacaoInterface : public MagAOXApp<true>, public dev::telemeter<cacaoInterface>
36{
37
38 //Give the test harness access.
39 friend class cacaoInterface_test;
40
42
43 friend class dev::telemeter<cacaoInterface>;
44
45protected:
46
47 /** \name Configurable Parameters
48 *@{
49 */
50 std::string m_loopNumber; ///< The loop number, X in aolX. We keep it a string because that's how it gets used.
51
52 ///@}
53
54 std::string m_aoCalDir;
55 std::string m_aoCalArchiveTime;
56 std::string m_aoCalLoadTime;
57
58 std::string m_loopName; ///< the loop name
59
60
61 std::string m_fpsName;
62 std::string m_fpsFifo;
63
64
65 int m_loopState {0}; ///< The loop state. 0 = off, 1 = paused (on, 0 gain), 2 = on
66
67 bool m_loopProcesses {false}; ///< Status of the loop processes.
68 bool m_loopProcesses_stat {false}; ///< What the cacao status file says the state of loop processes is.
69
70 float m_gain {0.0}; ///< The current loop gain.
71 float m_gain_target {0.0}; ///< The target loop gain.
72
73 float m_multCoeff {0.0}; ///< The current multiplicative coefficient (1-leak)
74 float m_multCoeff_target {0.0}; ///< The target multiplicative coefficient (1-leak)
75
76 std::vector<int> m_modeBlockStart;
77 std::vector<int> m_modeBlockN;
78
79 std::vector<float> m_modeBlockGains;
80 std::vector<float> m_modeBlockMCs;
81 std::vector<float> m_modeBlockLims;
82
83 std::mutex m_modeBlockMutex;
84
85
86 float m_maxLim {0.0}; ///< The current max limit
87 float m_maxLim_target {0.0}; ///< The target max limit
88
89public:
90 /// Default c'tor.
92
93 /// D'tor, declared and defined for noexcept.
96
97 virtual void setupConfig();
98
99 /// Implementation of loadConfig logic, separated for testing.
100 /** This is called by loadConfig().
101 */
102 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
103
104 virtual void loadConfig();
105
106 /// Startup function
107 /**
108 *
109 */
110 virtual int appStartup();
111
112 /// Implementation of the FSM for cacaoInterface.
113 /**
114 * \returns 0 on no critical error
115 * \returns -1 on an error requiring shutdown
116 */
117 virtual int appLogic();
118
119 /// Shutdown the app.
120 /**
121 *
122 */
123 virtual int appShutdown();
124
125
126 /** \name CACAO Interface Functions
127 * @{
128 */
129
130 int setFPSVal( const std::string & fps,
131 const std::string & param,
132 const std::string & val
133 );
134
135
136 template<typename T>
137 int setFPSVal( const std::string & fps,
138 const std::string & param,
139 const T & val
140 );
141
142 std::string getFPSValStr(const std::string & fps,
143 const std::string & param );
144
145 std::string getFPSValNum(const std::string & fps,
146 const std::string & param );
147
148 /// Get the calibration details
149 /** This is done each loop
150 *
151 * \returns 0 on success
152 * \returns -1 on an error
153 */
154 int getAOCalib();
155
157
158 /// Check if the loop processes are running
159 /** sets m_loopProcesses to true or false depending on what it finds out.
160 *
161 * \returns 0 on success
162 * \returns -1 on an error
163 */
164 int checkLoopProcesses();
165
166 /// Set loop gain to the value of m_gain_target;
167 /**
168 *
169 * \returns 0 on success
170 * \returns -1 on an error
171 */
172 int setGain();
173
174 /// Set loop multiplication coefficient to the value of m_multCoeff_target;
175 /**
176 *
177 * \returns 0 on success
178 * \returns -1 on an error
179 */
180 int setMultCoeff();
181
182 /// Set loop max lim to the value of m_maxLim_target;
183 /**
184 *
185 * \returns 0 on success
186 * \returns -1 on an error
187 */
188 int setMaxLim();
189
190 /// Turn the loop on
191 /**
192 * \returns 0 on success
193 * \returns -1 on an error
194 */
195 int loopOn();
196
197 /// Turn the loop off
198 /**
199 * \returns 0 on success
200 * \returns -1 on an error
201 */
202 int loopOff();
203
204 /// Zero the loop control channel
205 /**
206 * \returns 0 on success
207 * \returns -1 on an error
208 */
209 int loopZero();
210
211 /// @}
212
213 /** \name File Monitoring Thread
214 * Handling of offloads from the average woofer shape
215 * @{
216 */
217 int m_fmThreadPrio {0}; ///< Priority of the filemonitoring thread.
218
219 std::thread m_fmThread; ///< The file monitoring thread.
220
221 bool m_fmThreadInit {true}; ///< Initialization flag for the file monitoring thread.
222
223 pid_t m_fmThreadID {0}; ///< File monitor thread PID.
224
225 pcf::IndiProperty m_fmThreadProp; ///< The property to hold the f.m. thread details.
226
227 /// File monitoring thread starter function
228 static void fmThreadStart( cacaoInterface * c /**< [in] pointer to this */);
229
230
231 /// File monitoring thread function
232 /** Runs until m_shutdown is true.
233 */
234 void fmThreadExec();
235
236
237 ///@}
238
239 pcf::IndiProperty m_indiP_loop;
240 pcf::IndiProperty m_indiP_loopProcesses;
241
242 pcf::IndiProperty m_indiP_loopState;
243 pcf::IndiProperty m_indiP_loopZero;
244 pcf::IndiProperty m_indiP_loopGain;
245 pcf::IndiProperty m_indiP_multCoeff;
246 pcf::IndiProperty m_indiP_maxLim;
247
253
254 /** \name Telemeter Interface
255 *
256 * @{
257 */
258 int checkRecordTimes();
259
260 int recordTelem( const telem_loopgain * );
261
262 int recordLoopGain( bool force = false );
263
264 ///@}
265
266
267};
268
269cacaoInterface::cacaoInterface() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
270{
271
272 return;
273}
274
276{
277 config.add("loop.number", "", "loop.number", argType::Required, "loop", "number", false, "string", "the loop number");
278
280}
281
282int cacaoInterface::loadConfigImpl( mx::app::appConfigurator & _config )
283{
284 _config(m_loopNumber, "loop.number");
285
287 {
288 log<text_log>("Error during telemeter config", logPrio::LOG_CRITICAL);
289 m_shutdown = true;
290 }
291
292 return 0;
293}
294
296{
297 loadConfigImpl(config);
298}
299
301{
302
303 if(m_loopNumber == "")
304 {
305 return log<software_critical, -1>({__FILE__, __LINE__, "loop number not set"});
306 }
307
308 createROIndiText( m_indiP_loop, "loop", "name", "Loop Description", "Loop Controls", "Name");
309 indi::addTextElement(m_indiP_loop, "number", "Number");
310 m_indiP_loop["number"] = m_loopNumber;
311 m_indiP_loop["name"] = m_loopName;
313
314 createStandardIndiToggleSw( m_indiP_loopProcesses, "loop_processes", "Loop Processes", "Loop Controls");
316
317 createStandardIndiToggleSw( m_indiP_loopState, "loop_state", "Loop State", "Loop Controls");
319
320 createStandardIndiRequestSw( m_indiP_loopZero, "loop_zero", "Loop Zero", "Loop Controls");
322
323 createStandardIndiNumber<float>( m_indiP_loopGain, "loop_gain", 0.0, 10.0, 0.01, "%0.3f", "Loop Gain", "Loop Controls");
325
326 createStandardIndiNumber<float>( m_indiP_multCoeff, "loop_multcoeff", 0.0, 1.0, 0.001, "%0.3f", "Mult. Coefficient", "Loop Controls");
328
329 createStandardIndiNumber<float>( m_indiP_maxLim, "loop_max_limit", 0.0, 10.0, 0.001, "%0.3f", "Max. Limit", "Loop Controls");
331
333 {
335 return -1;
336 }
337
338 if(telemeterT::appStartup() < 0)
339 {
340 return log<software_error,-1>({__FILE__,__LINE__});
341 }
342
343 return 0;
344}
345
347{
348 //do a join check to see if other threads have exited.
349 if(pthread_tryjoin_np(m_fmThread.native_handle(),0) == 0)
350 {
351 log<software_critical>({__FILE__, __LINE__, "cacao file monitoring thread has exited"});
352
353 return -1;
354 }
355
356 //These could change if a new calibration is loaded
357 if(getAOCalib() < 0 )
358 {
360 if(!stateLogged()) log<text_log>("Could not get AO calib", logPrio::LOG_ERROR);
361 return 0;
362 }
363
366
367 if(telemeterT::appLogic() < 0)
368 {
370 return 0;
371 }
372
373 std::unique_lock<std::mutex> lock(m_indiMutex);
374
375 updateIfChanged(m_indiP_loop, std::vector<std::string>({"name", "number"}), std::vector<std::string>({m_loopName, m_loopNumber}));
376
378 {
379 updateSwitchIfChanged(m_indiP_loopProcesses, "toggle", pcf::IndiElement::On, INDI_OK);
380 }
381 else
382 {
383 updateSwitchIfChanged(m_indiP_loopProcesses, "toggle", pcf::IndiElement::Off, INDI_IDLE);
384 }
385
386 if(m_loopState == 0)
387 {
388 updateSwitchIfChanged(m_indiP_loopState, "toggle", pcf::IndiElement::Off, INDI_IDLE);
389 }
390 else if(m_loopState == 1)
391 {
392 updateSwitchIfChanged(m_indiP_loopState, "toggle", pcf::IndiElement::On, INDI_IDLE);
393 }
394 else if(m_loopState == 2)
395 {
396 updateSwitchIfChanged(m_indiP_loopState, "toggle", pcf::IndiElement::On, INDI_OK);
397 }
398
401
405
406 return 0;
407}
408
410{
411
412 if(m_fmThread.joinable())
413 {
414 try
415 {
416 m_fmThread.join(); //this will throw if it was already joined
417 }
418 catch(...)
419 {
420 }
421 }
422
424
425 return 0;
426}
427
428int cacaoInterface::setFPSVal( const std::string & fps,
429 const std::string & param,
430 const std::string & val
431 )
432{
433 std::string comout = "setval " + fps + "-" + m_loopNumber + "." + param + " " + val + "\n";
434
435 int wfd = open( m_fpsFifo.c_str(), O_WRONLY);
436 if(wfd < 0)
437 {
438 log<software_error>({__FILE__, __LINE__, errno, "error opening " + m_fpsFifo});
439 return -1;
440 }
441
442 int w = write(wfd, comout.c_str(), comout.size());
443
444 if(w != (int) comout.size())
445 {
446 log<software_error>({__FILE__, __LINE__, errno, "error on write to " + m_fpsFifo});
447 return -1;
448 }
449
450 close(wfd);
451
452 return 0;
453}
454
455
456template<typename T>
457int cacaoInterface::setFPSVal( const std::string & fps,
458 const std::string & param,
459 const T & val
460 )
461{
462 return setFPSVal( fps, param, std::to_string(val));
463}
464
465std::string cacaoInterface::getFPSValStr( const std::string & fps,
466 const std::string & param
467 )
468{
469 std::string outfile = "/dev/shm/" + m_loopName + "_out_" + fps + "-" + m_loopNumber + "." + param;
470
471 std::string comout = "fwrval " + fps + "-" + m_loopNumber + "." + param + " " + outfile + "\n";
472
473 int wfd = open( m_fpsFifo.c_str(), O_WRONLY);
474 if(wfd < 0)
475 {
476 log<software_error>({__FILE__, __LINE__, errno, "error opening " + m_fpsFifo});
477 return "";
478 }
479
480 int w = write(wfd, comout.c_str(), comout.size());
481
482 if(w != (int) comout.size())
483 {
484 log<software_error>({__FILE__, __LINE__, errno, "error on write to " + m_fpsFifo});
485 return "";
486 }
487
488 close(wfd);
489
490 char inbuff [4096];
491
492 int rfd = -1;
493 int nr =0;
494 while(rfd < 0 && nr < 20)
495 {
496 rfd = open(outfile.c_str(), O_RDONLY);
497 ++nr;
498 mx::sys::milliSleep(10);
499 }
500
501 int r = read(rfd, inbuff, sizeof(inbuff));
502
503 if(r < 0)
504 {
505 log<software_error>({__FILE__, __LINE__, errno, "error on read from " + m_fpsFifo});
506 return "";
507 }
508
509 close(rfd);
510
511 remove(outfile.c_str());
512
513 inbuff[r] = '\0';
514
515 std::string instr = inbuff;
516
517 size_t ned = instr.find_last_not_of(" \t\r\n");
518
519 if(ned == std::string::npos || ned == 0)
520 {
521 log<software_error>({__FILE__, __LINE__, "got empty result from " + m_fpsFifo});
522 return "";
523 }
524
525 size_t nst = instr.rfind(' ', ned);
526
527 if(nst == 0 || nst == std::string::npos || ned <= nst)
528 {
529 log<software_error>({__FILE__, __LINE__, "bad format in result from " + m_fpsFifo});
530 return "";
531 }
532
533 return instr.substr(nst+1);
534}
535
536std::string cacaoInterface::getFPSValNum( const std::string & fps,
537 const std::string & param
538 )
539{
540 std::string outfile = "/dev/shm/" + m_loopName + "_out_" + fps + "-" + m_loopNumber + "." + param;
541
542 std::string comout = "fwrval " + fps + "-" + m_loopNumber + "." + param + " " + outfile + "\n";
543
544 int wfd = open( m_fpsFifo.c_str(), O_WRONLY);
545 if(wfd < 0)
546 {
547 log<software_error>({__FILE__, __LINE__, errno, "error opening " + m_fpsFifo});
548 return "";
549 }
550
551 int w = write(wfd, comout.c_str(), comout.size());
552
553 if(w != (int) comout.size())
554 {
555 log<software_error>({__FILE__, __LINE__, errno, "error on write to " + m_fpsFifo});
556 return "";
557 }
558 close(wfd);
559
560 char inbuff [4096];
561
562 int rfd = -1;
563 int nr =0;
564 while(rfd < 0 && nr < 20)
565 {
566 rfd = open(outfile.c_str(), O_RDONLY);
567 ++nr;
568 mx::sys::milliSleep(10);
569 }
570
571 int r = read(rfd, inbuff, sizeof(inbuff));
572
573 close(rfd);
574
575 if(r < 0)
576 {
577 log<software_error>({__FILE__, __LINE__, errno, "error on read from " + m_fpsFifo});
578 return "";
579 }
580
581 remove(outfile.c_str());
582
583 inbuff[r] = '\0';
584
585 std::string instr = inbuff;
586
587 size_t ned = instr.find_last_not_of(" \t\r\n");
588
589 if(ned == std::string::npos || ned == 0)
590 {
591 log<software_error>({__FILE__, __LINE__, "got empty result from " + m_fpsFifo});
592 return "";
593 }
594
595 size_t nst = instr.rfind(' ', ned);
596
597 if(nst == 0 || nst == std::string::npos || ned <= nst)
598 {
599 log<software_error>({__FILE__, __LINE__, "bad format in result from " + m_fpsFifo});
600 return "";
601 }
602
603 return instr.substr(nst);
604}
605
606inline
608{
609 std::string calsrc = "/milk/shm/aol" + m_loopNumber + "_calib_source.txt";
610
611 std::ifstream fin;
612
613 //First read in the milk/shm directory name, which could be to a symlinked directory
614 fin.open(calsrc);
615 if(!fin)
616 {
617 return 0;
618 }
619 fin >> calsrc;
620 fin.close();
621
622 //Now read in the actual directory
623 calsrc += "/calib_dir.txt";
624 fin.open(calsrc);
625 if(!fin)
626 {
627 return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + calsrc});
628 }
629 std::string aoCalDir;
630
631 fin >> aoCalDir;
632
633 fin.close();
634
635 bool newcal = false;
636 if(aoCalDir != m_aoCalDir)
637 {
639 newcal = true;
640 }
641
642 std::string nameFile = m_aoCalDir + "/LOOPNAME";
643 fin.open(nameFile);
644 if(!fin)
645 {
646 return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + nameFile});
647 }
648 fin >> m_loopName;
649 fin.close();
650
651 m_fpsFifo = "/milk/shm/" + m_loopName + "_fpsCTRL.fifo";
652
653 calsrc = "/milk/shm/aol" + m_loopNumber + "_calib_loaded.txt";
654 fin.open(calsrc);
655 if(!fin)
656 {
657 return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + calsrc});
658 }
659 std::string aoCalLoadTime;
661
663 {
664 newcal = true;
666 }
667
668 if(newcal)
669 {
670 log<text_log>("new calibration " + m_aoCalDir + " loaded at: " + m_aoCalLoadTime, logPrio::LOG_INFO);
671 }
672
673 fin.close();
674
675 calsrc = m_aoCalDir + "/calib_archived.txt";
676
677 fin.open(calsrc);
678 if(!fin)
679 {
680 return log<software_error, -1>({__FILE__, __LINE__, errno, "cacaoInterface::getAOCalib failed to open: " + calsrc});
681 }
682
683 while(!fin.eof())
684 {
686 }
687 fin.close();
688
689
690 return 0;
691}
692
694{
695 ///\todo look for actual evidence of processes, such as interrogating ps.
696
698
699 return 0;
700}
701
703{
704 recordLoopGain(true);
705 return setFPSVal("mfilt", "loopgain", m_gain_target);
706}
707
709{
710 recordLoopGain(true);
711 return setFPSVal("mfilt", "loopmult", m_multCoeff_target);
712}
713
715{
716 recordLoopGain(true);
717 return setFPSVal("mfilt", "looplimit", m_maxLim_target);
718}
719
721{
722 recordLoopGain(true);
723 if( setFPSVal("mfilt", "loopON", std::string("ON")) != 0)
724 {
725 return log<software_error,-1>({__FILE__, __LINE__, "error setting FPS val"});
726 }
727
729
730 return 0;
731
732}
733
735{
736 recordLoopGain(true);
737 if( setFPSVal("mfilt", "loopON", std::string("OFF")) != 0)
738 {
739 return log<software_error,-1>({__FILE__, __LINE__, "error setting FPS val"});
740 }
741
742 if(m_gain == 0)
743 {
745 }
746 else
747 {
749 }
750
751 return 0;
752
753}
754
756{
757 if( setFPSVal("mfilt", "loopZERO", std::string("ON")) != 0)
758 {
759 return log<software_error,-1>({__FILE__, __LINE__, "error setting FPS val"});
760 }
761
762 log<text_log>("loop zeroed", logPrio::LOG_NOTICE);
763
764 return 0;
765
766}
767
769{
770 c->fmThreadExec();
771}
772
773
775{
777
778 while( m_fmThreadInit == true && shutdown() == 0)
779 {
780 sleep(1);
781 }
782
783 while(shutdown() == 0)
784 {
785 if(m_fpsFifo == "")
786 {
787 sleep(1);
788 continue;
789 }
790
791 std::string ans = getFPSValStr("mfilt", "loopON");
792
793 if(ans[1] == 'F')
794 {
795 m_loopState = 0;
796 }
797 else m_loopState = 2; //closed
798
799 ans = getFPSValNum("mfilt", "loopgain");
800
801 try
802 {
803 m_gain = std::stof(ans);
804 }
805 catch(const std::exception& e)
806 {
807 m_gain = 0;
808 }
809
810 ans = getFPSValNum("mfilt", "loopmult");
811 try
812 {
813 m_multCoeff = std::stof(ans);
814 }
815 catch(...)
816 {
817 m_multCoeff = 0;
818 }
819 ans = getFPSValNum("mfilt", "looplimit");
820 try
821 {
822 m_maxLim = std::stof(ans);
823 }
824 catch(...)
825 {
826 m_maxLim = 0;
827 }
828
830
831 mx::sys::milliSleep(250);
832
833 }
834
835 return;
836}
837
838INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_loopState )(const pcf::IndiProperty &ipRecv)
839{
840 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_loopState, ipRecv);
841
842 if(!ipRecv.find("toggle")) return 0;
843
844 std::unique_lock<std::mutex> lock(m_indiMutex);
845
846 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
847 {
848 return loopOn();
849 }
850 else if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
851 {
852 return loopOff();
853 }
854
855 log<software_error>({__FILE__,__LINE__, "switch state fall through."});
856 return -1;
857}
858
859INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_loopGain )(const pcf::IndiProperty &ipRecv)
860{
861 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_loopGain, ipRecv);
862
863 float current = -1;
864 float target = -1;
865
866 if(ipRecv.find("current"))
867 {
868 current = ipRecv["current"].get<double>();
869 }
870
871 if(ipRecv.find("target"))
872 {
873 target = ipRecv["target"].get<double>();
874 }
875
876 if(target == -1) target = current;
877
878 if(target == -1)
879 {
880 return 0;
881 }
882
883 std::lock_guard<std::mutex> guard(m_indiMutex);
884
885 m_gain_target = target;
886
887 updateIfChanged(m_indiP_loopGain, "target", m_gain_target);
888
889 return setGain();
890}
891
892INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_loopZero )(const pcf::IndiProperty &ipRecv)
893{
894 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_loopZero, ipRecv);
895
896 if(!ipRecv.find("request")) return 0;
897
898 std::unique_lock<std::mutex> lock(m_indiMutex);
899
900 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
901 {
902 return loopZero();
903 }
904
905 return 0;
906}
907
908INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_multCoeff )(const pcf::IndiProperty &ipRecv)
909{
910 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_multCoeff, ipRecv);
911
912 float current = -1;
913 float target = -1;
914
915 if(ipRecv.find("current"))
916 {
917 current = ipRecv["current"].get<double>();
918 }
919
920 if(ipRecv.find("target"))
921 {
922 target = ipRecv["target"].get<double>();
923 }
924
925 if(target == -1) target = current;
926
927 if(target == -1)
928 {
929 return 0;
930 }
931
932 std::lock_guard<std::mutex> guard(m_indiMutex);
933
934 m_multCoeff_target = target;
935 updateIfChanged(m_indiP_multCoeff, "target", target);
936
937 return setMultCoeff();
938}
939
940INDI_NEWCALLBACK_DEFN(cacaoInterface, m_indiP_maxLim )(const pcf::IndiProperty &ipRecv)
941{
942 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_maxLim, ipRecv);
943
944 float current = -1;
945 float target = -1;
946
947 if(ipRecv.find("current"))
948 {
949 current = ipRecv["current"].get<double>();
950 }
951
952 if(ipRecv.find("target"))
953 {
954 target = ipRecv["target"].get<double>();
955 }
956
957 if(target == -1) target = current;
958
959 if(target == -1)
960 {
961 return 0;
962 }
963
964 std::lock_guard<std::mutex> guard(m_indiMutex);
965 m_maxLim_target = target;
966 updateIfChanged(m_indiP_maxLim, "target", target);
967
968 return setMaxLim();
969}
970
971inline
976
977inline
979{
980 return recordLoopGain(true);
981}
982
983inline
985{
986 static uint8_t state {0};
987 static float gain {-1000};
988 static float multcoef {0};
989 static float limit {0};
990
991 if(state != m_loopState || gain != m_gain || multcoef != m_multCoeff || limit != m_maxLim || force)
992 {
994 gain = m_gain;
995 multcoef = m_multCoeff;
996 limit = m_maxLim;
997
999 }
1000
1001 return 0;
1002}
1003
1004} //namespace app
1005} //namespace MagAOX
1006
1007#endif //cacaoInterface_hpp
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
int createStandardIndiRequestSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single request element.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
int shutdown()
Get the value of the shutdown flag.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
int stateLogged()
Updates and returns the value of m_stateLogged. Will be 0 on first call after a state change,...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
int createROIndiText(pcf::IndiProperty &prop, const std::string &propName, const std::string &elName, const std::string &propLabel="", const std::string &propGroup="", const std::string &elLabel="")
Create a standard ReadOnly INDI Text property, with at least one element.
std::mutex m_indiMutex
Mutex for locking INDI communications.
int threadStart(std::thread &thrd, bool &thrdInit, pid_t &tpid, pcf::IndiProperty &thProp, int thrdPrio, const std::string &cpuset, const std::string &thrdName, thisPtr *thrdThis, Function &&thrdStart)
Start a thread, using this class's privileges to set priority, etc.
The MagAO-X CACAO Interface.
int setMultCoeff()
Set loop multiplication coefficient to the value of m_multCoeff_target;.
pcf::IndiProperty m_indiP_loopZero
int m_loopState
The loop state. 0 = off, 1 = paused (on, 0 gain), 2 = on.
int checkLoopProcesses()
Check if the loop processes are running.
INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_maxLim)
bool m_fmThreadInit
Initialization flag for the file monitoring thread.
virtual int appLogic()
Implementation of the FSM for cacaoInterface.
std::string getFPSValNum(const std::string &fps, const std::string &param)
void fmThreadExec()
File monitoring thread function.
float m_gain_target
The target loop gain.
static void fmThreadStart(cacaoInterface *c)
File monitoring thread starter function.
INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_loopZero)
int loopOn()
Turn the loop on.
int setFPSVal(const std::string &fps, const std::string &param, const std::string &val)
std::vector< float > m_modeBlockLims
pcf::IndiProperty m_indiP_loopState
bool m_loopProcesses
Status of the loop processes.
float m_maxLim
The current max limit.
INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_multCoeff)
pcf::IndiProperty m_fmThreadProp
The property to hold the f.m. thread details.
std::vector< float > m_modeBlockGains
int m_fmThreadPrio
Priority of the filemonitoring thread.
std::vector< float > m_modeBlockMCs
int setGain()
Set loop gain to the value of m_gain_target;.
float m_gain
The current loop gain.
std::string m_loopName
the loop name
~cacaoInterface() noexcept
D'tor, declared and defined for noexcept.
std::string getFPSValStr(const std::string &fps, const std::string &param)
int recordLoopGain(bool force=false)
std::vector< int > m_modeBlockStart
std::thread m_fmThread
The file monitoring thread.
virtual int appStartup()
Startup function.
int getAOCalib()
Get the calibration details.
int setMaxLim()
Set loop max lim to the value of m_maxLim_target;.
virtual int appShutdown()
Shutdown the app.
float m_maxLim_target
The target max limit.
float m_multCoeff
The current multiplicative coefficient (1-leak)
dev::telemeter< cacaoInterface > telemeterT
int recordTelem(const telem_loopgain *)
INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_loopState)
std::string m_loopNumber
The loop number, X in aolX. We keep it a string because that's how it gets used.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
pid_t m_fmThreadID
File monitor thread PID.
std::vector< int > m_modeBlockN
int loopOff()
Turn the loop off.
pcf::IndiProperty m_indiP_loopProcesses
pcf::IndiProperty m_indiP_multCoeff
float m_multCoeff_target
The target multiplicative coefficient (1-leak)
pcf::IndiProperty m_indiP_loopGain
int loopZero()
Zero the loop control channel.
bool m_loopProcesses_stat
What the cacao status file says the state of loop processes is.
INDI_NEWCALLBACK_DECL(cacaoInterface, m_indiP_loopGain)
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
@ OPERATING
The device is operating, other than homing.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:28
#define INDI_OK
Definition indiUtils.hpp:29
int addTextElement(pcf::IndiProperty &prop, const std::string &name, const std::string &label="")
Add a standard INDI Text element.
Definition indiUtils.hpp:40
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
A device base class which saves telemetry.
Definition telemeter.hpp:69
int appShutdown()
Perform telemeter application shutdown.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int appLogic()
Perform telemeter application logic.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int appStartup()
Starts the telemetry log thread.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
Software CRITICAL log entry.
Software ERR log entry.
Log entry recording the build-time git state.