7#ifndef tcsInterface_hpp
8#define tcsInterface_hpp
14#include "../../libMagAOX/libMagAOX.hpp"
15#include "../../magaox_git_version.h"
17#include "../../libMagAOX/app/dev/telemeter.hpp"
182 mx::app::appConfigurator &
_config );
478 config.add(
"labMode",
486 "Flag to enable lab mode. Default is true." );
488 config.add(
"pyrNudger.C_00",
496 "Pyramid to AEG control matrix [0,0] of a 2x2 matrix" );
497 config.add(
"pyrNudger.C_01",
505 "Pyramid to AEG control matrix [0,1] of a 2x2 matrix " );
506 config.add(
"pyrNudger.C_10",
514 "Pyramid to AEG control matrix [1,0] of a 2x2 matrix " );
515 config.add(
"pyrNudger.C_11",
523 "Pyramid to AEG control matrix [1,1] of a 2x2 matrix " );
525 config.add(
"pyrNudger.ang",
"",
"pyrNudger.ang", argType::Required,
"pyrNudger",
"ang",
false,
"float",
"" );
526 config.add(
"pyrNudger.ang0",
"",
"pyrNudger.ang0", argType::Required,
"pyrNudger0",
"ang0",
false,
"float",
"" );
528 "pyrNudger.parity",
"",
"pyrNudger.parity", argType::Required,
"pyrNudger",
"parity",
false,
"float",
"" );
530 config.add(
"pyrNudger.F_sign",
538 "Pyramid to AEG control matrix [1,1] of a 2x2 matrix " );
540 config.add(
"acqFromGuider.zdSign",
542 "acqFromGuider.zdSign",
548 "Sign of the Zd to rotation angle, +1 or -1, -1 default" );
549 config.add(
"acqFromGuider.az0",
557 "az component of acquisition vector a 0 zd." );
558 config.add(
"acqFromGuider.azoff",
560 "acqFromGuider.azoff",
566 "static offset to az component of acquisition vector" );
567 config.add(
"acqFromGuider.el0",
575 "el component of acquisition vector a 0 zd." );
576 config.add(
"acqFromGuider.eloff",
578 "acqFromGuider.eloff",
584 "static offset to el component of acquisition vector" );
585 config.add(
"acqFromGuider.focus",
587 "acqFromGuider.focus",
593 "static offset for focus acquisition" );
595 config.add(
"offload.TT_avgInt",
603 "Woofer to Telescope T/T offload averaging interval [sec] " );
604 config.add(
"offload.TT_gain",
612 "Woofer to Telescope T/T offload gain" );
613 config.add(
"offload.TT_thresh",
621 "Woofer to Telescope T/T offload threshold" );
623 config.add(
"offload.lab_TT_C_00",
625 "offload.lab_TT_C_00",
631 "Woofer to TTM T/T offload control matrix [0,0] of a 2x2 matrix" );
632 config.add(
"offload.lab_TT_C_01",
634 "offload.lab_TT_C_01",
640 "Woofer to TTM T/T offload control matrix [0,1] of a 2x2 matrix " );
641 config.add(
"offload.lab_TT_C_10",
643 "offload.lab_TT_C_10",
649 "Woofer to TTM T/T offload control matrix [1,0] of a 2x2 matrix " );
650 config.add(
"offload.lab_TT_C_11",
652 "offload.lab_TT_C_11",
658 "Woofer to TTM T/T offload control matrix [1,1] of a 2x2 matrix " );
660 config.add(
"offload.TT_C_00",
668 "Woofer to Telescope T/T offload control matrix [0,0] of a 2x2 matrix" );
669 config.add(
"offload.TT_C_01",
677 "Woofer to Telescope T/T offload control matrix [0,1] of a 2x2 matrix " );
678 config.add(
"offload.TT_C_10",
686 "Woofer to Telescope T/T offload control matrix [1,0] of a 2x2 matrix " );
687 config.add(
"offload.TT_C_11",
695 "Woofer to Telescope T/T offload control matrix [1,1] of a 2x2 matrix " );
697 config.add(
"offload.F_avgInt",
705 "Woofer to Telescope Focus offload averaging interval [sec] " );
706 config.add(
"offload.F_gain",
714 "Woofer to Telescope Focus offload gain" );
715 config.add(
"offload.F_thresh",
723 "Woofer to Telescope Focus offload threshold" );
725 config.add(
"offload.CFocus00",
733 "Woofer to Telescope Focus offload control scale factor." );
735 config.add(
"offload.CComa00",
743 "Woofer to Telescope Coma offload control matrix [0,0] of a 2x2 matrix" );
744 config.add(
"offload.CComa01",
752 "Woofer to Telescope Coma offload control matrix [0,1] of a 2x2 matrix " );
753 config.add(
"offload.CComa10",
761 "Woofer to Telescope Coma offload control matrix [1,0] of a 2x2 matrix " );
762 config.add(
"offload.CComa11",
770 "Woofer to Telescope Coma offload control matrix [1,1] of a 2x2 matrix " );
772 config.add(
"device.address",
780 "The IP address or resolvable name of the TCS." );
781 config.add(
"device.port",
789 "The IP port for TCS communications. Should be the command port. Default is 5811." );
892 indi::addNumberElement<double>(
893 m_indiP_teltime,
"sidereal_time", 0, std::numeric_limits<double>::max(), 0,
"%0.6f" );
898 indi::addNumberElement<double>(
m_indiP_telpos,
"epoch", 0, std::numeric_limits<double>::max(), 0,
"%0.6f" );
900 indi::addNumberElement<double>(
m_indiP_telpos,
"ra", 0, 360, 0,
"%0.6f" );
902 indi::addNumberElement<double>(
m_indiP_telpos,
"dec", -90, 90, 0,
"%0.6f" );
904 indi::addNumberElement<double>(
m_indiP_telpos,
"el", 0, 90, 0,
"%0.6f" );
906 indi::addNumberElement<double>(
m_indiP_telpos,
"ha", -180, 160, 0,
"%0.6f" );
908 indi::addNumberElement<double>(
m_indiP_telpos,
"am", 0, 4, 0,
"%0.2f" );
910 indi::addNumberElement<double>(
m_indiP_telpos,
"rotoff", 0, 360, 0,
"%0.6f" );
918 indi::addNumberElement<int>(
m_indiP_teldata,
"tracking", 0, 1, 1,
"%d" );
920 indi::addNumberElement<int>(
m_indiP_teldata,
"guiding", 0, 1, 1,
"%d" );
922 indi::addNumberElement<int>(
m_indiP_teldata,
"slewing", 0, 1, 1,
"%d" );
924 indi::addNumberElement<int>(
m_indiP_teldata,
"guider_moving", 0, 1, 1,
"%d" );
926 indi::addNumberElement<double>(
m_indiP_teldata,
"az", 0, 360, 0,
"%0.6f" );
928 indi::addNumberElement<double>(
m_indiP_teldata,
"zd", 0, 90, 0,
"%0.6f" );
930 indi::addNumberElement<double>(
m_indiP_teldata,
"pa", 0, 360, 0,
"%0.6f" );
932 indi::addNumberElement<double>(
m_indiP_teldata,
"dome_az", 0, 360, 0,
"%0.6f" );
934 indi::addNumberElement<int>(
m_indiP_teldata,
"dome_stat", 0, 1, 1,
"%d" );
946 indi::addNumberElement<double>(
m_indiP_catdata,
"ra", 0, 360, 0,
"%0.6f" );
948 indi::addNumberElement<double>(
m_indiP_catdata,
"dec", -90, 90, 0,
"%0.6f" );
950 indi::addNumberElement<double>(
m_indiP_catdata,
"epoch", 0, std::numeric_limits<double>::max(), 0,
"%0.6f" );
952 indi::addNumberElement<double>(
m_indiP_catdata,
"rotoff", 0, 360, 0,
"%0.6f" );
960 std::numeric_limits<double>::lowest(),
961 std::numeric_limits<double>::max(),
967 std::numeric_limits<double>::lowest(),
968 std::numeric_limits<double>::max(),
974 std::numeric_limits<double>::lowest(),
975 std::numeric_limits<double>::max(),
981 std::numeric_limits<double>::lowest(),
982 std::numeric_limits<double>::max(),
988 std::numeric_limits<double>::lowest(),
989 std::numeric_limits<double>::max(),
995 std::numeric_limits<double>::lowest(),
996 std::numeric_limits<double>::max(),
1002 std::numeric_limits<double>::lowest(),
1003 std::numeric_limits<double>::max(),
1009 std::numeric_limits<double>::lowest(),
1010 std::numeric_limits<double>::max(),
1016 std::numeric_limits<double>::lowest(),
1017 std::numeric_limits<double>::max(),
1023 std::numeric_limits<double>::lowest(),
1024 std::numeric_limits<double>::max(),
1034 std::numeric_limits<double>::lowest(),
1035 std::numeric_limits<double>::max(),
1041 std::numeric_limits<double>::lowest(),
1042 std::numeric_limits<double>::max(),
1048 std::numeric_limits<double>::lowest(),
1049 std::numeric_limits<double>::max(),
1053 indi::addNumberElement<double>(
1054 m_indiP_env,
"wind", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f" );
1056 indi::addNumberElement<double>(
1057 m_indiP_env,
"winddir", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f" );
1061 std::numeric_limits<double>::lowest(),
1062 std::numeric_limits<double>::max(),
1068 std::numeric_limits<double>::lowest(),
1069 std::numeric_limits<double>::max(),
1075 std::numeric_limits<double>::lowest(),
1076 std::numeric_limits<double>::max(),
1082 std::numeric_limits<double>::lowest(),
1083 std::numeric_limits<double>::max(),
1089 std::numeric_limits<double>::lowest(),
1090 std::numeric_limits<double>::max(),
1100 std::numeric_limits<unsigned>::lowest(),
1101 std::numeric_limits<unsigned>::max(),
1107 std::numeric_limits<double>::lowest(),
1108 std::numeric_limits<double>::max(),
1114 std::numeric_limits<unsigned>::lowest(),
1115 std::numeric_limits<unsigned>::max(),
1121 std::numeric_limits<double>::lowest(),
1122 std::numeric_limits<double>::max(),
1128 std::numeric_limits<unsigned>::lowest(),
1129 std::numeric_limits<unsigned>::max(),
1135 std::numeric_limits<double>::lowest(),
1136 std::numeric_limits<double>::max(),
1313 std::stringstream
logs;
1346 std::string response;
1420#ifdef LOG_TCS_STATUS
1450#ifdef LOG_TCS_STATUS
1465#ifdef LOG_TCS_STATUS
1493#ifdef LOG_TCS_STATUS
1503 std::vector<std::string>
vres;
1510 pos1 =
tdat.find_first_not_of(
" ", 0 );
1515 pos2 =
tdat.find_first_of(
" ", pos1 );
1519 tok =
tdat.substr( pos1, pos2 - pos1 );
1526 pos2 =
tdat.find_first_not_of(
" ", pos1 );
1531 pos2 =
tdat.find_first_of(
" ", pos1 );
1537 pos2 =
tdat.length();
1539 tok =
tdat.substr( pos1, pos2 - pos1 );
1541 pos2 =
tok.find_first_of(
" \n\r", 0 );
1544 tok.erase( pos2,
tok.length() - pos2 );
1562 if(
en == std::string::npos )
1580 catch(
const std::exception &
e )
1588 x = std::stod(
xstr );
1590 catch(
const std::exception &
e )
1597 if( std::signbit( x ) )
1607 if(
en == std::string::npos )
1625 catch(
const std::exception &
e )
1635 catch(
const std::exception &
e )
1654 catch(
const std::exception &
e )
1664 catch(
const std::exception &
e )
1677 std::vector<std::string>
pdat;
1689 if(
pdat[0] ==
"-1" )
1696 if(
pdat.size() != 3 )
1699 log<text_log>(
"Error getting telescope time (datetime): TCS response wrong size, returned " +
1700 std::to_string(
pdat.size() ) +
" values",
1720 std::vector<std::string>
pdat;
1732 if(
pdat[0] ==
"-1" )
1739 if(
pdat.size() != 6 )
1742 log<text_log>(
"Error getting telescope position (telpos): TCS response wrong size, returned " +
1743 std::to_string(
pdat.size() ) +
" values",
1754 m_telRA = ( h +
m / 60. +
s / 3600. ) * 15.;
1793 std::vector<std::string>
tdat;
1804 if(
tdat[0] ==
"-1" )
1811 if(
tdat.size() != 10 )
1814 log<text_log>(
"[TCS] Error getting telescope data (teldata): TCS response wrong size, returned " +
1815 std::to_string(
tdat.size() ) +
" values",
1823 char bit[2] = { 0, 0 };
1862 std::vector<std::string>
cdat;
1874 if(
cdat[0] ==
"-1" )
1881 if(
cdat.size() != 6 )
1885 if(
cdat.size() == 7 )
1887 if(
cdat[6] ==
"Pointing" )
1896 log<text_log>(
"Catalog data (catdata): TCS response wrong size, returned " +
1897 std::to_string(
cdat.size() ) +
" values",
1900 for(
size_t n = 0;
n <
cdat.size(); ++
n )
1902 std::cerr <<
n <<
" " <<
cdat[
n] <<
"\n";
1926 m_catRA = ( h +
m / 60. +
s / 3600. ) * 15.;
1950 std::vector<std::string>
vedat;
1961 if(
vedat[0] ==
"-1" )
1968 if(
vedat.size() != 10 )
1971 log<text_log>(
"Error getting telescope secondary positions (vedata): TCS response wrong size, returned " +
1972 std::to_string(
vedat.size() ) +
" values",
1999 std::vector<std::string>
edat;
2010 if(
edat[0] ==
"-1" )
2017 if(
edat.size() != 10 )
2020 log<text_log>(
"Error getting telescope environment data (telenv): TCS response wrong size, returned " +
2021 std::to_string(
edat.size() ) +
"values",
2071 int rv =
system(
"query_seeing > /dev/null" );
2096 fin.open(
"/tmp/xsup_query_seeing.txt" );
2296 std::vector<std::string>( {
"epoch",
"ra",
"dec",
"el",
"ha",
"am",
"rotoff" } ),
2376 std::vector<std::string>( {
"object",
"rotmode" } ),
2412 std::vector<std::string>( {
"ra",
"dec",
"epoch",
"rotoff" } ),
2725 static double lastRA = 0;
2727 static double lastEl = 0;
2728 static double lastHA = 0;
2729 static double lastAM = 0;
2756 static double lastAz = 0;
2757 static double lastZd = 0;
2758 static double lastPA = 0;
2951 static float lastAvgInt = std::numeric_limits<float>::quiet_NaN();
2952 static float lastGain = std::numeric_limits<float>::quiet_NaN();
2953 static float lastThresh = std::numeric_limits<float>::quiet_NaN();
2984 static float lastAvgInt = std::numeric_limits<float>::quiet_NaN();
2985 static float lastGain = std::numeric_limits<float>::quiet_NaN();
2986 static float lastThresh = std::numeric_limits<float>::quiet_NaN();
3024 if( x != 0 || y != 0 )
3323 pcf::IndiProperty
ip( pcf::IndiProperty::Number );
3324 ip.setDevice(
"modwfs" );
3325 ip.setName(
"offset12" );
3326 ip.add( pcf::IndiElement(
"dC1" ) );
3327 ip.add( pcf::IndiElement(
"dC2" ) );
3413 if( !
ipRecv.find(
"toggle" ) )
3415 return log<
software_error, -1>( { __FILE__, __LINE__,
"no toggle element" } );
3420 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
3429 bool changed =
false;
3432 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3433 if( m_labMode != labMode )
3435 m_labMode = labMode;
3448 updateSwitchIfChanged( m_indiP_labMode,
"toggle", pcf::IndiElement::On,
INDI_OK );
3453 updateSwitchIfChanged( m_indiP_labMode,
"toggle", pcf::IndiElement::Off,
INDI_OK );
3456 recordTcsiLabMode();
3471 x =
ipRecv[
"y"].get<
float>();
3476 y =
ipRecv[
"x"].get<
float>();
3481 z =
ipRecv[
"z"].get<
float>();
3484 return sendPyrNudge( x, y, z );
3491 if( !
ipRecv.find(
"request" ) )
3496 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
3498 return acquireFromGuider();
3508 if( !
ipRecv.find(
"toggle" ) )
3511 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
3513 m_loopState.store( 2 );
3517 m_loopState.store( 0 );
3527 if( m_loopState.load() != 2 )
3531 float tt0 =
ipRecv[
"00"].get<
float>();
3532 float tt1 =
ipRecv[
"01"].get<
float>();
3550 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3551 labMode = m_labMode;
3552 labOfflTTC00 = m_lab_offlTT_C_00;
3553 labOfflTTC01 = m_lab_offlTT_C_01;
3554 labOfflTTC10 = m_lab_offlTT_C_10;
3555 labOfflTTC11 = m_lab_offlTT_C_11;
3556 offlTTC00 = m_offlTT_C_00;
3557 offlTTC01 = m_offlTT_C_01;
3558 offlTTC10 = m_offlTT_C_10;
3559 offlTTC11 = m_offlTT_C_11;
3560 offlCFocus00 = m_offlCFocus_00;
3561 offlCComa00 = m_offlCComa_00;
3562 offlCComa01 = m_offlCComa_01;
3563 offlCComa10 = m_offlCComa_10;
3564 offlCComa11 = m_offlCComa_11;
3568 std::lock_guard<std::mutex>
lock( m_offloadMutex );
3570 size_t nextReq = m_lastRequest + 1;
3572 if( nextReq >= m_offloadRequests[0].size() )
3577 m_offloadRequests[0][nextReq] = labOfflTTC00 * tt0 + labOfflTTC01 * tt1;
3578 m_offloadRequests[1][nextReq] = labOfflTTC10 * tt0 + labOfflTTC11 * tt1;
3582 m_offloadRequests[0][nextReq] = offlTTC00 * tt0 + offlTTC01 * tt1;
3583 m_offloadRequests[1][nextReq] = offlTTC10 * tt0 + offlTTC11 * tt1;
3587 float f0 =
ipRecv[
"02"].get<
float>();
3589 m_offloadRequests[2][nextReq] = offlCFocus00 * f0;
3592 float c0 =
ipRecv[
"03"].get<
float>();
3593 float c1 =
ipRecv[
"04"].get<
float>();
3595 m_offloadRequests[3][nextReq] = offlCComa00 * c0 + offlCComa01 * c1;
3596 m_offloadRequests[4][nextReq] = offlCComa10 * c0 + offlCComa11 * c1;
3599 m_lastRequest = nextReq;
3601 if( m_nRequests > m_offloadRequests[0].size() )
3603 if( m_firstRequest >= m_offloadRequests[0].size() )
3613 if(
ipRecv.getName() != m_indiP_offlTTenable.getName() )
3615 log<software_error>( { __FILE__, __LINE__,
"wrong INDI property received." } );
3619 if( !
ipRecv.find(
"toggle" ) )
3622 bool changed =
false;
3624 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
3627 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3628 if( m_offlTT_enabled ==
false )
3630 m_offlTT_enabled =
true;
3636 updateSwitchIfChanged( m_indiP_offlTTenable,
"toggle", pcf::IndiElement::On,
INDI_OK );
3637 recordTcsiTipTilt();
3640 else if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::Off )
3643 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3644 if( m_offlTT_enabled ==
true )
3646 m_offlTT_enabled =
false;
3652 updateSwitchIfChanged( m_indiP_offlTTenable,
"toggle", pcf::IndiElement::Off,
INDI_IDLE );
3653 recordTcsiTipTilt();
3664 if( !
ipRecv.find(
"request" ) )
3667 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
3669 updateSwitchIfChanged( m_indiP_offlTTdump,
"request", pcf::IndiElement::On,
INDI_OK );
3672 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3673 m_offlTT_dump =
true;
3686 if( indiTargetUpdate( m_indiP_offlTTavgInt,
target,
ipRecv,
true ) < 0 )
3688 log<software_error>( { __FILE__, __LINE__ } );
3693 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3694 m_offlTT_avgInt =
target;
3696 recordTcsiTipTilt();
3707 if( indiTargetUpdate( m_indiP_offlTTgain,
target,
ipRecv,
true ) < 0 )
3709 log<software_error>( { __FILE__, __LINE__ } );
3714 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3717 recordTcsiTipTilt();
3728 if( indiTargetUpdate( m_indiP_offlTTthresh,
target,
ipRecv,
true ) < 0 )
3730 log<software_error>( { __FILE__, __LINE__ } );
3735 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3736 m_offlTT_thresh =
target;
3738 recordTcsiTipTilt();
3747 if( !
ipRecv.find(
"toggle" ) )
3750 bool changed =
false;
3752 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
3755 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3756 if( m_offlF_enabled ==
false )
3758 m_offlF_enabled =
true;
3764 updateSwitchIfChanged( m_indiP_offlFenable,
"toggle", pcf::IndiElement::On,
INDI_OK );
3768 else if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::Off )
3771 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3772 if( m_offlF_enabled ==
true )
3774 m_offlF_enabled =
false;
3780 updateSwitchIfChanged( m_indiP_offlFenable,
"toggle", pcf::IndiElement::Off,
INDI_IDLE );
3792 if( !
ipRecv.find(
"request" ) )
3795 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
3797 updateSwitchIfChanged( m_indiP_offlFdump,
"request", pcf::IndiElement::On,
INDI_OK );
3800 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3801 m_offlF_dump =
true;
3814 if( indiTargetUpdate( m_indiP_offlFavgInt,
target,
ipRecv,
true ) < 0 )
3816 log<software_error>( { __FILE__, __LINE__ } );
3821 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3835 if( indiTargetUpdate( m_indiP_offlFgain,
target,
ipRecv,
true ) < 0 )
3837 log<software_error>( { __FILE__, __LINE__ } );
3842 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
3856 std::cerr <<
"Got offl thresh\n";
3858 if( indiTargetUpdate( m_indiP_offlFthresh,
target,
ipRecv,
true ) < 0 )
3860 log<software_error>( { __FILE__, __LINE__ } );
3865 std::lock_guard<std::mutex>
lock( m_offloadCtrlMutex );
The base-class for XWCTk applications.
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 createStandardIndiNumber(pcf::IndiProperty &prop, const std::string &name, const T &min, const T &max, const T &step, const std::string &format, const std::string &label="", const std::string &group="")
Create a standard R/W INDI Number property with target and current elements.
int shutdown()
Get the value of the shutdown flag.
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
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 createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
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.
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.
int sendNewProperty(const pcf::IndiProperty &ipSend, const std::string &el, const T &newVal)
Send a newProperty command to another device (using the INDI Client interface)
The MagAO-X Clay Telescope TCS Interface.
float m_offlTT_avgInt
The number of recent requests included in each tip/tilt offload average.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFgain)
int checkRecordTimes()
Check whether any telemetry records are due.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlTTgain)
double m_dimm_el
DIMM elevation at time of seeing measurement.
size_t m_lastRequest
Index of the newest valid request in the offload ring.
pcf::IndiProperty m_indiP_offlTTdump
size_t m_last_nRequests
Request count last processed by the offload thread.
double m_wxdewpoint
Dew point from weather station.
int recordTelem(const telem_telpos *)
Record telescope-position telemetry on a forced telemeter update.
virtual int appLogic()
Implementation of the FSM for tcsInterface.
pcf::IndiProperty m_indiP_offlFgain
pcf::IndiProperty m_indiP_acqFromGuider
Property used to request a pyramid nudge.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlTTthresh)
~tcsInterface() noexcept
D'tor, declared and defined for noexcept.
pcf::IndiProperty m_indiP_seeing
INDI Property for seeing.
double m_telDomeAz
dome azimuth
int recordTcsiTipTilt(bool force=false)
Record tip/tilt offload-control telemetry when values change.
int m_telGuiding
guider moving state
int recordTcsiFocus(bool force=false)
Record focus offload-control telemetry when values change.
float m_offlF_avgInt
The number of recent requests included in each focus offload average.
int sendMagTelCommand(const std::string &command, int timeout)
int recordTelCat(bool force=false)
Record catalog telemetry when values change.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFavgInt)
double m_catRA
Catalog right ascension [degrees].
pcf::IndiProperty m_indiP_teltime
double m_dimm_fwhm_corr
DIMM elevation corrected FWHM.
pcf::IndiProperty m_indiP_labMode
int m_telGuiderMoving
guider moving state
pcf::IndiProperty m_indiP_env
INDI Property for environment.
int sendTToffload(float TT_0, float TT_1)
Send a tip/tilt offload command to the selected target.
pcf::IndiProperty m_indiP_pyrNudge
Property used to request a pyramid nudge.
int recordTcsiLabMode(bool force=false)
Record lab-mode telemetry when values change.
int recordTelPos(bool force=false)
Record telescope-position telemetry when values change.
int recordTelEnv(bool force=false)
Record telescope-environment telemetry when values change.
pcf::IndiProperty m_indiP_telpos
int recordTelData(bool force=false)
Record telescope-status telemetry when values change.
double m_telPA
parallactic angle
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlTTenable)
double m_wxpres
Outside pressue, millibars.
std::string m_catObj
Catalog object name.
int m_mag2_time
Seconds since midnight of MAG2 measurement.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFthresh)
pcf::IndiProperty m_indiP_offloadCoeffs
Property used to report the latest woofer modal coefficients for offloading.
pcf::IndiProperty m_offloadThreadProp
Offload thread INDI property.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_pyrNudge)
pcf::IndiProperty m_indiP_offlTTgain
pcf::IndiProperty m_indiP_catdata
INDI Property for the catalog data.
bool m_offloadThreadInit
Initialization flag for the offload thread.
int m_mag1_time
Seconds since midnight of MAG1 measurement.
std::thread m_offloadThread
The offloading thread.
double m_telZd
zenith distance
float m_offlF_gain
The operator-set gain applied to focus offload requests.
friend class tcsInterface_test
void offloadThreadExec()
Offload thread function.
int getMagTelStatus(std::string &response, const std::string &statreq)
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFdump)
virtual void loadConfig()
double m_catDec
Catalog declination [degrees].
double m_wxwind
outside wind intensity, mph
pcf::IndiProperty m_indiP_teldata
float m_offlF_thresh
The deadband threshold applied to focus offload requests.
bool m_offlTT_enabled
Tracks whether tip/tilt offloading is currently enabled.
int parse_xms(double &x, double &m, double &s, const std::string &xmsstr)
int m_devicePort
The IP port for TCS communications. Should be the command port. Default is 5811.
std::mutex m_tcsMutex
Mutex for locking TCS communications.
double m_mag2_fwhm_corr
MAG2 elevation corrected FWHM.
double m_tcell
Primary mirror cell temperature, Celsius.
double m_mag1_fwhm_corr
MAG1 elevation corrected FWHM.
virtual void setupConfig()
std::string m_deviceAddr
The IP address or resolvable name of the TCS.
pid_t m_offloadThreadID
Offload thread pid.
pcf::IndiProperty m_indiP_vaneend
INDI Property for the vane end positions.
std::string m_catRm
Catalog rotator mode.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_acqFromGuider)
pcf::IndiProperty m_indiP_offlFenable
INDI_SETCALLBACK_DECL(tcsInterface, m_indiP_offloadCoeffs)
int m_dimm_time
Seconds since midnight of DIMM measurement.
pcf::IndiProperty m_indiP_offlFdump
double m_catEp
Catalog epoch.
double m_tambient
Dome air temperature, Celsius.
size_t m_nRequests
Number of valid requests currently stored in the offload ring.
int getSeeing()
Query, parse, and record seeing measurements.
tcsInterface()
Default c'tor.
int sendFoffload(float F_0)
Send a focus offload command to the telescope.
int badSeeing()
Record bad seeing measurements on errors in getSeeing().
bool m_labMode
Tracks whether the app is operating in lab mode rather than on-sky mode.
pcf::IndiProperty m_indiP_offlTTenable
double m_ttruss
Telescope truss temperature, Celsius.
int doTToffload(float TT_0, float TT_1)
Apply tip/tilt offload controls to an averaged request vector.
pcf::IndiProperty m_indiP_catalog
INDI Property for the catalog text information.
double m_wxhumid
Outside humidity, percent.
virtual int appStartup()
Startup function.
bool m_offlF_enabled
Tracks whether focus offloading is currently enabled.
int recordTelVane(bool force=false)
Record vane-position telemetry when values change.
virtual int appShutdown()
Shutdown the app.
int recordTelSee(bool force=false)
Record seeing telemetry when values change.
int doFoffload(float F_0)
Apply focus offload controls to an averaged request value.
float m_offlTT_gain
The operator-set gain applied to tip/tilt offload requests.
int m_telDomeStat
dome status
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
int m_telSlewing
slewing state
std::mutex m_offloadMutex
Protects the offload request ring and its queue-state indices across producer and consumer threads.
int m_telROI
The rotator of interest.
int m_telTracking
tracking state
size_t m_firstRequest
Index of the oldest valid request in the offload ring.
float m_offlTT_thresh
The deadband threshold applied to tip/tilt offload requests.
double m_catRo
Catalog rotator offset.
std::mutex m_offloadCtrlMutex
Protects shared offload control parameters accessed by callbacks and the offload thread.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFenable)
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_labMode)
double m_wxtemp
Outside temperature, Celsius.
pcf::IndiProperty m_indiP_offlTTavgInt
static void offloadThreadStart(tcsInterface *t)
Offload thread starter function.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlTTdump)
pcf::IndiProperty m_indiP_loopState
Property used to report the loop state.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlTTavgInt)
double m_wxwdir
outside wind direction, degrees
double m_tseccell
Secondary mirror cell temperature, Celsius.
pcf::IndiProperty m_indiP_offlFavgInt
std::vector< std::string > parse_teldata(std::string &tdat)
pcf::IndiProperty m_indiP_offlFthresh
pcf::IndiProperty m_indiP_offlTTthresh
std::vector< std::vector< float > > m_offloadRequests
Ring buffer of modal offload requests indexed by mode and request slot.
int sendPyrNudge(float x, float y, float z)
INDI_SETCALLBACK_DECL(tcsInterface, m_indiP_loopState)
std::atomic< int > m_loopState
Tracks the current loop state shared between the INDI callback and the offload thread.
m_regCounter resize(m_numModes)
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define CREATE_REG_INDI_NEW_TOGGLESWITCH(prop, name)
Create and register a NEW INDI property as a standard toggle switch, using the standard callback name...
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
const pcf::IndiProperty & ipRecv
std::unique_lock< std::mutex > lock(m_indiMutex)
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
static constexpr logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
#define NETSERIAL_E_NOERROR
An input/output capable device.
int loadConfig(mx::app::appConfigurator &config)
Load the device section from an application configurator.
int appStartup()
Perform application startup steps specific to an ioDevice.
int setupConfig(mx::app::appConfigurator &config)
Setup an application configurator for the device section.
unsigned m_readTimeout
The read timeout [msec].
A device base class which saves telemetry.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
Focus offload-control telemetry.
tcsInterface lab-mode telemetry.
Tip/tilt offload-control telemetry.
Log entry recording the build-time git state.
Log entry recording the build-time git state.
Log entry recording the build-time git state.
Log entry recording the build-time git state.
Log entry recording the build-time git state.
Log entry recording the build-time git state.
Manage a connectio to a serial device over a network.
int serialOut(const char *buf, int len)
int serialInString(char *buf, int len, int timeout, char terminator)
int serialInit(const char *address, int port)