7 #ifndef tcsInterface_hpp
8 #define tcsInterface_hpp
12 #include "../../libMagAOX/libMagAOX.hpp"
13 #include "../../magaox_git_version.h"
16 #include "../../libMagAOX/app/dev/telemeter.hpp"
203 const std::string &statreq
213 const std::string & xmsstr
427 config.add(
"labMode",
"",
"labMode", argType::Required,
"",
"labMode",
false,
"bool",
"Flag to enable lab mode. Default is true.");
429 config.add(
"pyrNudger.C_00",
"",
"pyrNudger.C_00", argType::Required,
"pyrNudger",
"C_00",
false,
"float",
"Pyramid to AEG control matrix [0,0] of a 2x2 matrix");
430 config.add(
"pyrNudger.C_01",
"",
"pyrNudger.C_01", argType::Required,
"pyrNudger",
"C_01",
false,
"float",
"Pyramid to AEG control matrix [0,1] of a 2x2 matrix ");
431 config.add(
"pyrNudger.C_10",
"",
"pyrNudger.C_10", argType::Required,
"pyrNudger",
"C_10",
false,
"float",
"Pyramid to AEG control matrix [1,0] of a 2x2 matrix ");
432 config.add(
"pyrNudger.C_11",
"",
"pyrNudger.C_11", argType::Required,
"pyrNudger",
"C_11",
false,
"float",
"Pyramid to AEG control matrix [1,1] of a 2x2 matrix ");
434 config.add(
"pyrNudger.ang",
"",
"pyrNudger.ang", argType::Required,
"pyrNudger",
"ang",
false,
"float",
"");
435 config.add(
"pyrNudger.ang0",
"",
"pyrNudger.ang0", argType::Required,
"pyrNudger0",
"ang0",
false,
"float",
"");
436 config.add(
"pyrNudger.parity",
"",
"pyrNudger.parity", argType::Required,
"pyrNudger",
"parity",
false,
"float",
"");
438 config.add(
"pyrNudger.F_sign",
"",
"pyrNudger.F_sign", argType::Required,
"pyrNudger",
"F_sign",
false,
"int",
"Pyramid to AEG control matrix [1,1] of a 2x2 matrix ");
440 config.add(
"acqFromGuider.zdSign",
"",
"acqFromGuider.zdSign", argType::Required,
"acqFromGuider",
"zdSign",
false,
"int",
"Sign of the Zd to rotation angle, +1 or -1, -1 default");
441 config.add(
"acqFromGuider.az0",
"",
"acqFromGuider.az0", argType::Required,
"acqFromGuider",
"az0",
false,
"float",
"az component of acquisition vector a 0 zd.");
442 config.add(
"acqFromGuider.azoff",
"",
"acqFromGuider.azoff", argType::Required,
"acqFromGuider",
"azoff",
false,
"float",
"static offset to az component of acquisition vector");
443 config.add(
"acqFromGuider.el0",
"",
"acqFromGuider.el0", argType::Required,
"acqFromGuider",
"el0",
false,
"float",
"el component of acquisition vector a 0 zd.");
444 config.add(
"acqFromGuider.eloff",
"",
"acqFromGuider.eloff", argType::Required,
"acqFromGuider",
"eloff",
false,
"float",
"static offset to el component of acquisition vector");
445 config.add(
"acqFromGuider.focus",
"",
"acqFromGuider.focus", argType::Required,
"acqFromGuider",
"focus",
false,
"float",
"static offset for focus acquisition");
447 config.add(
"offload.TT_avgInt",
"",
"offload.TT_avgInt", argType::Required,
"offload",
"TT_avgInt",
false,
"float",
"Woofer to Telescope T/T offload averaging interval [sec] ");
448 config.add(
"offload.TT_gain",
"",
"offload.TT_gain", argType::Required,
"offload",
"TT_gain",
false,
"float",
"Woofer to Telescope T/T offload gain");
449 config.add(
"offload.TT_thresh",
"",
"offload.TT_thresh", argType::Required,
"offload",
"TT_thresh",
false,
"float",
"Woofer to Telescope T/T offload threshold");
451 config.add(
"offload.lab_TT_C_00",
"",
"offload.lab_TT_C_00", argType::Required,
"offload",
"lab_TT_C_00",
false,
"float",
"Woofer to TTM T/T offload control matrix [0,0] of a 2x2 matrix");
452 config.add(
"offload.lab_TT_C_01",
"",
"offload.lab_TT_C_01", argType::Required,
"offload",
"lab_TT_C_01",
false,
"float",
"Woofer to TTM T/T offload control matrix [0,1] of a 2x2 matrix ");
453 config.add(
"offload.lab_TT_C_10",
"",
"offload.lab_TT_C_10", argType::Required,
"offload",
"lab_TT_C_10",
false,
"float",
"Woofer to TTM T/T offload control matrix [1,0] of a 2x2 matrix ");
454 config.add(
"offload.lab_TT_C_11",
"",
"offload.lab_TT_C_11", argType::Required,
"offload",
"lab_TT_C_11",
false,
"float",
"Woofer to TTM T/T offload control matrix [1,1] of a 2x2 matrix ");
456 config.add(
"offload.TT_C_00",
"",
"offload.TT_C_00", argType::Required,
"offload",
"TT_C_00",
false,
"float",
"Woofer to Telescope T/T offload control matrix [0,0] of a 2x2 matrix");
457 config.add(
"offload.TT_C_01",
"",
"offload.TT_C_01", argType::Required,
"offload",
"TT_C_01",
false,
"float",
"Woofer to Telescope T/T offload control matrix [0,1] of a 2x2 matrix ");
458 config.add(
"offload.TT_C_10",
"",
"offload.TT_C_10", argType::Required,
"offload",
"TT_C_10",
false,
"float",
"Woofer to Telescope T/T offload control matrix [1,0] of a 2x2 matrix ");
459 config.add(
"offload.TT_C_11",
"",
"offload.TT_C_11", argType::Required,
"offload",
"TT_C_11",
false,
"float",
"Woofer to Telescope T/T offload control matrix [1,1] of a 2x2 matrix ");
462 config.add(
"offload.F_avgInt",
"",
"offload.F_avgInt", argType::Required,
"offload",
"F_avgInt",
false,
"float",
"Woofer to Telescope Focus offload averaging interval [sec] ");
463 config.add(
"offload.F_gain",
"",
"offload.F_gain", argType::Required,
"offload",
"F_gain",
false,
"float",
"Woofer to Telescope Focus offload gain");
464 config.add(
"offload.F_thresh",
"",
"offload.F_thresh", argType::Required,
"offload",
"F_thresh",
false,
"float",
"Woofer to Telescope Focus offload threshold");
466 config.add(
"offload.CFocus00",
"",
"offload.CFocus00", argType::Required,
"offload",
"CFocus00",
false,
"float",
"Woofer to Telescope Focus offload control scale factor.");
468 config.add(
"offload.CComa00",
"",
"offload.CComa00", argType::Required,
"offload",
"CComa00",
false,
"float",
"Woofer to Telescope Coma offload control matrix [0,0] of a 2x2 matrix");
469 config.add(
"offload.CComa01",
"",
"offload.CComa01", argType::Required,
"offload",
"CComa01",
false,
"float",
"Woofer to Telescope Coma offload control matrix [0,1] of a 2x2 matrix ");
470 config.add(
"offload.CComa10",
"",
"offload.CComa10", argType::Required,
"offload",
"CComa10",
false,
"float",
"Woofer to Telescope Coma offload control matrix [1,0] of a 2x2 matrix ");
471 config.add(
"offload.CComa11",
"",
"offload.CComa11", argType::Required,
"offload",
"CComa11",
false,
"float",
"Woofer to Telescope Coma offload control matrix [1,1] of a 2x2 matrix ");
473 config.add(
"device.address",
"",
"device.address", argType::Required,
"device",
"address",
false,
"string",
"The IP address or resolvable name of the TCS.");
474 config.add(
"device.port",
"",
"device.port", argType::Required,
"device",
"port",
false,
"int",
"The IP port for TCS communications. Should be the command port. Default is 5811.");
497 _config(
m_acqAz0,
"acqFromGuider.az0");
499 _config(
m_acqEl0,
"acqFromGuider.el0");
548 indi::addNumberElement<double>(
m_indiP_teltime,
"sidereal_time", 0, std::numeric_limits<double>::max(), 0,
"%0.6f");
553 indi::addNumberElement<double>(
m_indiP_telpos,
"epoch", 0, std::numeric_limits<double>::max(), 0,
"%0.6f");
555 indi::addNumberElement<double>(
m_indiP_telpos,
"ra", 0, 360, 0,
"%0.6f");
557 indi::addNumberElement<double>(
m_indiP_telpos,
"dec", -90, 90, 0,
"%0.6f");
559 indi::addNumberElement<double>(
m_indiP_telpos,
"el", 0, 90, 0,
"%0.6f");
561 indi::addNumberElement<double>(
m_indiP_telpos,
"ha", -180, 160, 0,
"%0.6f");
563 indi::addNumberElement<double>(
m_indiP_telpos,
"am", 0, 4, 0,
"%0.2f");
565 indi::addNumberElement<double>(
m_indiP_telpos,
"rotoff", 0, 360, 0,
"%0.6f");
574 indi::addNumberElement<int>(
m_indiP_teldata,
"tracking", 0, 1, 1,
"%d");
576 indi::addNumberElement<int>(
m_indiP_teldata,
"guiding", 0, 1, 1,
"%d");
578 indi::addNumberElement<int>(
m_indiP_teldata,
"slewing", 0, 1, 1,
"%d");
580 indi::addNumberElement<int>(
m_indiP_teldata,
"guider_moving", 0, 1, 1,
"%d");
582 indi::addNumberElement<double>(
m_indiP_teldata,
"az", 0, 360, 0,
"%0.6f");
584 indi::addNumberElement<double>(
m_indiP_teldata,
"zd", 0, 90, 0,
"%0.6f");
586 indi::addNumberElement<double>(
m_indiP_teldata,
"pa", 0, 360, 0,
"%0.6f");
588 indi::addNumberElement<double>(
m_indiP_teldata,
"dome_az", 0, 360, 0,
"%0.6f");
590 indi::addNumberElement<int>(
m_indiP_teldata,
"dome_stat", 0, 1, 1,
"%d");
603 indi::addNumberElement<double>(
m_indiP_catdata,
"ra", 0, 360, 0,
"%0.6f");
605 indi::addNumberElement<double>(
m_indiP_catdata,
"dec", -90, 90, 0,
"%0.6f");
607 indi::addNumberElement<double>(
m_indiP_catdata,
"epoch", 0, std::numeric_limits<double>::max(), 0,
"%0.6f");
609 indi::addNumberElement<double>(
m_indiP_catdata,
"rotoff", 0, 360, 0,
"%0.6f");
617 indi::addNumberElement<double>(
m_indiP_vaneend,
"secz", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
619 indi::addNumberElement<double>(
m_indiP_vaneend,
"encz", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
621 indi::addNumberElement<double>(
m_indiP_vaneend,
"secx", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
623 indi::addNumberElement<double>(
m_indiP_vaneend,
"encx", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
625 indi::addNumberElement<double>(
m_indiP_vaneend,
"secy", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
627 indi::addNumberElement<double>(
m_indiP_vaneend,
"ency", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
629 indi::addNumberElement<double>(
m_indiP_vaneend,
"sech", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
631 indi::addNumberElement<double>(
m_indiP_vaneend,
"ench", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
633 indi::addNumberElement<double>(
m_indiP_vaneend,
"secv", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
635 indi::addNumberElement<double>(
m_indiP_vaneend,
"encv", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.6f");
642 indi::addNumberElement<double>(
m_indiP_env,
"temp-out", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
644 indi::addNumberElement<double>(
m_indiP_env,
"pressure", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
646 indi::addNumberElement<double>(
m_indiP_env,
"humidity", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
648 indi::addNumberElement<double>(
m_indiP_env,
"wind", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
650 indi::addNumberElement<double>(
m_indiP_env,
"winddir", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
652 indi::addNumberElement<double>(
m_indiP_env,
"temp-truss", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
654 indi::addNumberElement<double>(
m_indiP_env,
"temp-cell", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
656 indi::addNumberElement<double>(
m_indiP_env,
"temp-seccell", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
658 indi::addNumberElement<double>(
m_indiP_env,
"temp-amb", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
660 indi::addNumberElement<double>(
m_indiP_env,
"dewpoint", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
666 indi::addNumberElement<unsigned>(
m_indiP_seeing,
"dimm_time", std::numeric_limits<unsigned>::lowest(), std::numeric_limits<unsigned>::max(), 0,
"%d");
668 indi::addNumberElement<double>(
m_indiP_seeing,
"dimm_el", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
670 indi::addNumberElement<double>(
m_indiP_seeing,
"dimm_fwhm", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
672 indi::addNumberElement<double>(
m_indiP_seeing,
"dimm_fwhm_corr", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
674 indi::addNumberElement<unsigned>(
m_indiP_seeing,
"mag1_time", std::numeric_limits<unsigned>::lowest(), std::numeric_limits<unsigned>::max(), 0,
"%d");
676 indi::addNumberElement<double>(
m_indiP_seeing,
"mag1_el", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
678 indi::addNumberElement<double>(
m_indiP_seeing,
"mag1_fwhm", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
680 indi::addNumberElement<double>(
m_indiP_seeing,
"mag1_fwhm_corr", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
682 indi::addNumberElement<unsigned>(
m_indiP_seeing,
"mag2_time", std::numeric_limits<unsigned>::lowest(), std::numeric_limits<unsigned>::max(), 0,
"%d");
684 indi::addNumberElement<double>(
m_indiP_seeing,
"mag2_el", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
686 indi::addNumberElement<double>(
m_indiP_seeing,
"mag2_fwhm", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
688 indi::addNumberElement<double>(
m_indiP_seeing,
"mag2_fwhm_corr", std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max(), 0,
"%0.2f");
693 signal(SIGPIPE, SIG_IGN);
714 log<software_error>({__FILE__,__LINE__});
721 log<software_error>({__FILE__,__LINE__});
728 log<software_error>({__FILE__,__LINE__});
737 log<software_error>({__FILE__,__LINE__});
746 log<software_error>({__FILE__,__LINE__});
755 log<software_error>({__FILE__,__LINE__});
762 log<software_error>({__FILE__,__LINE__});
769 log<software_error>({__FILE__,__LINE__});
778 log<software_error>({__FILE__,__LINE__});
787 log<software_error>({__FILE__,__LINE__});
796 log<software_error>({__FILE__,__LINE__});
810 log<software_error>({__FILE__, __LINE__});
846 static int lastrv = 0;
847 static int lasterrno = 0;
858 std::stringstream logs;
860 log<text_log>(logs.str());
876 if( errno != lasterrno )
878 log<software_error>( {__FILE__,__LINE__, errno});
887 std::string response;
960 const std::string &statreq
966 std::string statreq_nl;
968 #ifdef LOG_TCS_STATUS
969 log<text_log>(
"Sending status request: " + statreq);
972 std::lock_guard<std::mutex> guard(
m_tcsMutex);
974 statreq_nl = statreq;
989 log<text_log>(
"No response received to status request: " + statreq,
logPrio::LOG_ERROR);
994 char * nl = strchr(answer,
'\n');
995 if(nl) answer[nl-answer] =
'\0';
997 #ifdef LOG_TCS_STATUS
998 log<text_log>(std::string(
"Received response: ") + answer);
1013 std::string command_nl;
1015 #ifdef LOG_TCS_STATUS
1016 log<text_log>(
"Sending command: " + command);
1019 std::lock_guard<std::mutex> guard(
m_tcsMutex);
1021 command_nl = command;
1039 char * nl = strchr(answer,
'\n');
1040 if(nl) answer[nl-answer] =
'\0';
1042 #ifdef LOG_TCS_STATUS
1043 log<text_log>(std::string(
"Received response: ") + answer);
1046 return atoi(answer);
1053 std::vector<std::string> vres;
1061 pos1 = tdat.find_first_not_of(
" " , 0);
1063 if(pos1 == -1) pos1 = 0;
1065 pos2 = tdat.find_first_of(
" ", pos1);
1069 tok = tdat.substr(pos1, pos2-pos1);
1071 vres.push_back(tok);
1076 pos2 = tdat.find_first_not_of(
" ", pos1);
1081 pos2 = tdat.find_first_of(
" ", pos1);
1087 pos2 = tdat.length();
1089 tok = tdat.substr(pos1, pos2-pos1);
1091 pos2 = tok.find_first_of(
" \n\r", 0);
1093 if(pos2 >= 0) tok.erase(pos2, tok.length()-pos2);
1095 vres.push_back(tok);
1105 const std::string & xmsstr
1113 en = xmsstr.find(
':', st);
1116 if(en == std::string::npos)
1118 log<software_error>({__FILE__, __LINE__,
"error parsing x:m:s"});
1123 if(en - st < 2 || en < st)
1125 log<software_error>({__FILE__, __LINE__,
"error parsing x:m:s"});
1132 xstr = xmsstr.substr(st, en-st);
1134 catch(
const std::exception & e)
1136 log<software_error>({__FILE__, __LINE__, e.what()});
1142 x = std::stod(xstr);
1144 catch(
const std::exception & e)
1146 log<software_error>({__FILE__, __LINE__, e.what()});
1151 if(std::signbit(x)) sgn = -1;
1152 if(xmsstr[0] ==
'-') sgn = -1;
1156 en = xmsstr.find(
':', st);
1159 if(en == std::string::npos)
1161 log<software_error>({__FILE__, __LINE__,
"error parsing x:m:s"});
1166 if(en - st < 2 || en < st)
1168 log<software_error>({__FILE__, __LINE__,
"error parsing x:m:s"});
1175 mstr = xmsstr.substr(st, en-st);
1177 catch(
const std::exception & e)
1179 log<software_error>({__FILE__, __LINE__, e.what()});
1185 m = sgn*std::stod(mstr);
1187 catch(
const std::exception & e)
1189 log<software_error>({__FILE__, __LINE__, e.what()});
1195 if(st >= xmsstr.length() - 1)
1197 log<software_error>({__FILE__, __LINE__,
"error parsing x:m:s"});
1204 sstr = xmsstr.substr(st, xmsstr.length()-st);
1206 catch(
const std::exception & e)
1208 log<software_error>({__FILE__, __LINE__, e.what()});
1214 s = sgn*std::stod(sstr);
1216 catch(
const std::exception & e)
1218 log<software_error>({__FILE__, __LINE__, e.what()});
1230 std::vector<std::string> pdat;
1245 log<text_log>(
"Error getting telescope time (datetime): TCS returned -1",
logPrio::LOG_WARNING);
1249 if(pdat.size() != 3)
1252 log<text_log>(
"Error getting telescope position (datetime): TCS response wrong size, returned " + std::to_string(pdat.size()) +
" values",
logPrio::LOG_WARNING);
1262 m_telST = (h + m/60. + s/3600.);
1272 std::vector<std::string> pdat;
1287 log<text_log>(
"Error getting telescope position (telpos): TCS returned -1",
logPrio::LOG_WARNING);
1291 if(pdat.size() != 6)
1294 log<text_log>(
"Error getting telescope position (telpos): TCS response wrong size, returned " + std::to_string(pdat.size()) +
" values",
logPrio::LOG_WARNING);
1304 m_telRA = (h + m/60. + s/3600.)*15.;
1326 m_telHA = h + m/60. + s/3600.;
1328 m_telAM = strtod(pdat[4].c_str(),0);
1344 std::vector<std::string> tdat;
1358 log<text_log>(
"Error getting telescope data (teldata): TCS returned -1",
logPrio::LOG_WARNING);
1362 if(tdat.size() != 10)
1365 log<text_log>(
"[TCS] Error getting telescope data (teldata): TCS response wrong size, returned " + std::to_string(tdat.size()) +
" values",
logPrio::LOG_WARNING);
1373 char bit[2] = {0,0};
1375 bit[0] = tdat[1].c_str()[0];
1377 bit[0] = tdat[1].c_str()[1];
1381 bit[0] = tdat[2].c_str()[0];
1383 bit[0] = tdat[2].c_str()[1];
1388 m_telAz = strtod(tdat[4].c_str(),0);
1390 m_telEl = strtod(tdat[5].c_str(),0);
1392 m_telZd = strtod(tdat[6].c_str(),0);
1394 m_telPA = strtod(tdat[7].c_str(),0);
1413 std::vector<std::string> cdat;
1432 if(cdat.size() != 6)
1435 log<text_log>(
"Catalog data (catdata): TCS response wrong size, returned " + std::to_string(cdat.size()) +
" values",
logPrio::LOG_WARNING);
1457 m_catRA = (h + m/60. + s/3600.)*15.;
1467 m_catEp = strtod(cdat[2].c_str(),0);
1469 m_catRo = strtod(cdat[3].c_str(),0);
1482 std::vector<std::string> vedat;
1487 log<text_log>(
"Error getting telescope secondary positions (vedata)",
logPrio::LOG_ERROR);
1493 if(vedat[0] ==
"-1")
1496 log<text_log>(
"Error getting telescope secondary positions (vedata): TCS returned -1",
logPrio::LOG_WARNING);
1500 if(vedat.size() != 10)
1503 log<text_log>(
"Error getting telescope secondary positions (vedata): TCS response wrong size, returned " + std::to_string(vedat.size()) +
" values",
logPrio::LOG_WARNING);
1531 std::vector<std::string> edat;
1536 log<text_log>(
"Error getting telescope environment data (telenv)",
logPrio::LOG_ERROR);
1545 log<text_log>(
"Error getting telescope environment data (telenv): TCS returned -1",
logPrio::LOG_WARNING);
1549 if(edat.size() != 10)
1552 log<text_log>(
"Error getting telescope environment data (telenv): TCS response wrong size, returned " + std::to_string(edat.size()) +
"values",
logPrio::LOG_WARNING);
1556 m_wxtemp = strtod(edat[0].c_str(), 0);
1557 m_wxpres = strtod(edat[1].c_str(), 0);
1559 m_wxwind = strtod(edat[3].c_str(), 0);
1560 m_wxwdir = strtod(edat[4].c_str(), 0);
1561 m_ttruss = strtod(edat[5].c_str(), 0);
1562 m_tcell = strtod(edat[6].c_str(), 0);
1578 static int last_query = 0;
1584 time_t sec_midnight;
1587 int rv = system(
"query_seeing > /dev/null");
1590 log<software_error>({__FILE__, __LINE__,
"Error from seeing query"});
1595 last_query = time(0);
1596 sec_midnight = last_query % 86400;
1599 std::string label, datestr, timestr, fwhmstr;
1603 fin.open(
"/tmp/dimm.tsv");
1607 log<software_error>({__FILE__, __LINE__,
"Error reading dimm seeing"});
1626 if(dt < 0) dt = 86400-dt;
1639 fin.open(
"/tmp/mag1.tsv");
1643 log<software_error>({__FILE__, __LINE__,
"Error reading mag1 seeing"});
1662 if(dt < 0) dt = 86400-dt;
1675 fin.open(
"/tmp/mag2.tsv");
1679 log<software_error>({__FILE__, __LINE__,
"Error reading mag2 seeing"});
1698 if(dt < 0) dt = 86400-dt;
1730 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1768 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1807 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1817 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1827 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1839 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1875 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1915 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1925 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1935 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1956 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1966 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
1976 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
2001 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
2011 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
2021 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
2055 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
2086 log<software_error>({__FILE__,__LINE__,
"INDI library exception"});
2144 static double lastEpoch = 0;
2145 static double lastRA = 0;
2146 static double lastDec = 0;
2147 static double lastEl = 0;
2148 static double lastHA = 0;
2149 static double lastAM = 0;
2150 static double lastRotOff = 0;
2177 static int lastROI = -999;
2178 static int lastTracking = -999;
2179 static int lastGuiding = -999;
2180 static int lastSlewing = -999;
2181 static int lastGuiderMoving = -999;
2182 static double lastAz = 0;
2183 static double lastZd = 0;
2184 static double lastPA = 0;
2185 static double lastDomeAz = 0;
2186 static int lastDomeStat = -999;
2188 if( force || lastROI !=
m_telROI ||
2219 static double lastSecZ = -999;
2220 static double lastEncZ = -999;
2221 static double lastSecX = -999;
2222 static double lastEncX = -999;
2223 static double lastSecY = -999;
2224 static double lastEncY = -999;
2225 static double lastSecH = -999;
2226 static double lastEncH = -999;
2227 static double lastSecV = -999;
2228 static double lastEncV = -999;
2261 static double lastWxtemp = -999;
2262 static double lastWxpres = -999;
2263 static double lastWxhumid = -999;
2264 static double lastWxwind = -999;
2265 static double lastWxwdir = -999;
2266 static double lastTtruss = -999;
2267 static double lastTcell = -999;
2268 static double lastTseccell = -999;
2269 static double lastTambient = -999;
2270 static double lastWxdewpoint = -999;
2273 if( force || lastWxtemp !=
m_wxtemp ||
2305 static std::string last_catObj;
2306 static std::string last_catRm;
2307 static double last_catRA = 0;
2308 static double last_catDec = 0;
2309 static double last_catEp = 0;
2310 static double last_catRo = 0;
2312 if(force ||
m_catObj != last_catObj ||
2335 static int last_dimm_time = 0;
2336 static double last_dimm_el = 0;
2337 static double last_dimm_fwhm = 0;
2340 static int last_mag1_time = 0;
2341 static double last_mag1_el = 0;
2342 static double last_mag1_fwhm = 0;
2343 static double last_mag1_fwhm_corr = 0;
2345 static int last_mag2_time = 0;
2346 static double last_mag2_el = 0;
2347 static double last_mag2_fwhm = 0;
2348 static double last_mag2_fwhm_corr = 0;
2364 telem<telem_telsee>({
m_dimm_time,
m_dimm_el,
m_dimm_fwhm, -1,
m_mag1_time,
m_mag1_el,
m_mag1_fwhm,
m_mag1_fwhm_corr,
m_mag2_time,
m_mag2_el,
m_mag2_fwhm,
m_mag2_fwhm_corr});
2390 if(x != 0 || y != 0)
2402 snprintf(ttstr,
sizeof(ttstr) ,
"aeg %f %f", dx, dy);
2408 log<software_error>({__FILE__,__LINE__, std::string(
"error sending command: ") + ttstr});
2421 log<software_error>({__FILE__,__LINE__, std::string(
"error sending command: ") + ttstr});
2439 snprintf(ttstr,
sizeof(ttstr) ,
"aeg %f %f", az, el);
2445 log<software_error>({__FILE__,__LINE__, std::string(
"error sending command: ") + ttstr});
2455 log<software_error>({__FILE__,__LINE__, std::string(
"error sending command: ") + ttstr});
2472 static int last_loopState = -1;
2482 int sincelast_TT = 0;
2485 int sincelast_F = 0;
2604 log<text_log>(
"[OFFL] TT dumping: " + std::to_string(tt_0) +
" " + std::to_string(tt_1));
2617 if(tt_0 ==0 && tt_1 == 0)
2623 log<text_log>(
"[OFFL] TT offloading: " + std::to_string(tt_0) +
" " + std::to_string(tt_1));
2642 pcf::IndiProperty ip(pcf::IndiProperty::Number);
2643 ip.setDevice(
"modwfs");
2644 ip.setName(
"offset12");
2645 ip.add(pcf::IndiElement(
"dC1"));
2646 ip.add(pcf::IndiElement(
"dC2"));
2660 snprintf(ttstr,
sizeof(ttstr) ,
"aeg %f %f", tt_0, tt_1);
2662 log<text_log>(std::string(
"[OFFL] sending: ") + ttstr);
2671 log<text_log>(
"[OFFL] Focus dumping: " + std::to_string(F_0));
2687 log<text_log>(
"[OFFL] Focus sending: " + std::to_string(F_0));
2692 log<text_log>(
"Focus offload above threshold but Focus offloading disabled",
logPrio::LOG_WARNING);
2704 snprintf(fstr,
sizeof(fstr),
"zimr %f", F_0);
2706 log<text_log>(std::string(
"[OFFL] sending: ") + fstr);
2721 x =
ipRecv[
"y"].get<
float>();
2726 y =
ipRecv[
"x"].get<
float>();
2731 z =
ipRecv[
"z"].get<
float>();
2734 return sendPyrNudge(x, y, z);
2743 if(!
ipRecv.find(
"request"))
2748 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
2750 return acquireFromGuider();
2760 if(!
ipRecv.find(
"toggle"))
return 0;
2762 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On)
2780 if(m_loopState != 2)
return 0;
2782 size_t nextReq = m_lastRequest + 1;
2784 if(nextReq >= m_offloadRequests[0].size()) nextReq = 0;
2787 float tt0 =
ipRecv[
"00"].get<
float>();
2788 float tt1 =
ipRecv[
"01"].get<
float>();
2792 m_offloadRequests[0][nextReq] = m_lab_offlTT_C_00 * tt0 + m_lab_offlTT_C_01 * tt1;
2793 m_offloadRequests[1][nextReq] = m_lab_offlTT_C_10 * tt0 + m_lab_offlTT_C_11 * tt1;
2797 m_offloadRequests[0][nextReq] = m_offlTT_C_00 * tt0 + m_offlTT_C_01 * tt1;
2798 m_offloadRequests[1][nextReq] = m_offlTT_C_10 * tt0 + m_offlTT_C_11 * tt1;
2802 float f0 =
ipRecv[
"02"].get<
float>();
2804 m_offloadRequests[2][nextReq] = m_offlCFocus_00 * f0;
2808 float c0 =
ipRecv[
"03"].get<
float>();
2809 float c1 =
ipRecv[
"04"].get<
float>();
2811 m_offloadRequests[3][nextReq] = m_offlCComa_00 * c0 + m_offlCComa_01 * c1;
2812 m_offloadRequests[4][nextReq] = m_offlCComa_10 * c0 + m_offlCComa_11 * c1;
2815 m_lastRequest = nextReq;
2817 if(m_nRequests > m_offloadRequests[0].size()) ++m_firstRequest;
2818 if(m_firstRequest >= m_offloadRequests[0].size()) m_firstRequest = 0;
2826 if(
ipRecv.getName() != m_indiP_offlTTenable.getName())
2828 log<software_error>({__FILE__,__LINE__,
"wrong INDI property received."});
2832 if(!
ipRecv.find(
"toggle"))
return 0;
2834 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On && m_offlTT_enabled ==
false)
2838 m_offlTT_enabled =
true;
2840 else if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::Off && m_offlTT_enabled ==
true)
2844 m_offlTT_enabled =
false;
2855 if(!
ipRecv.find(
"request"))
return 0;
2857 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
2861 m_offlTT_dump =
true;
2874 if( indiTargetUpdate( m_indiP_offlTTavgInt, target,
ipRecv,
true) < 0)
2876 log<software_error>({__FILE__,__LINE__});
2880 m_offlTT_avgInt = target;
2891 if( indiTargetUpdate( m_indiP_offlTTgain, target,
ipRecv,
true) < 0)
2893 log<software_error>({__FILE__,__LINE__});
2897 m_offlTT_gain = target;
2908 if( indiTargetUpdate( m_indiP_offlTTthresh, target,
ipRecv,
true) < 0)
2910 log<software_error>({__FILE__,__LINE__});
2914 m_offlTT_thresh = target;
2924 if(!
ipRecv.find(
"toggle"))
return 0;
2926 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On && m_offlF_enabled ==
false)
2930 m_offlF_enabled =
true;
2932 else if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::Off && m_offlF_enabled ==
true)
2936 m_offlF_enabled =
false;
2947 if(!
ipRecv.find(
"request"))
return 0;
2949 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
2953 m_offlF_dump =
true;
2966 if( indiTargetUpdate( m_indiP_offlFavgInt, target,
ipRecv,
true) < 0)
2968 log<software_error>({__FILE__,__LINE__});
2972 m_offlF_avgInt = target;
2983 if( indiTargetUpdate( m_indiP_offlFgain, target,
ipRecv,
true) < 0)
2985 log<software_error>({__FILE__,__LINE__});
2989 m_offlF_gain = target;
3002 if( indiTargetUpdate( m_indiP_offlFthresh, target,
ipRecv,
true) < 0)
3004 log<software_error>({__FILE__,__LINE__});
3008 m_offlF_thresh = target;
The base-class for MagAO-X 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.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFgain)
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlTTgain)
double m_dimm_el
DIMM elevation at time of seeing measurement.
pcf::IndiProperty m_indiP_offlTTdump
double m_wxdewpoint
Dew point from weather station.
int recordTelem(const telem_telpos *)
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_mag1_fwhm
MAG1 raw FWHM.
double m_telDomeAz
dome azimuth
int m_telGuiding
guider moving state
int sendMagTelCommand(const std::string &command, int timeout)
int recordTelCat(bool force=false)
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFavgInt)
double m_catRA
Catalog right ascension [degrees].
pcf::IndiProperty m_indiP_teltime
double m_mag1_el
MAG1 elevation at time of seeing measurement.
double m_dimm_fwhm_corr
DIMM elevation corrected FWHM.
int m_telGuiderMoving
guider moving state
pcf::IndiProperty m_indiP_env
INDI Property for environment.
int sendTToffload(float TT_0, float TT_1)
pcf::IndiProperty m_indiP_pyrNudge
Property used to request a pyramid nudge.
int recordTelPos(bool force=false)
int recordTelEnv(bool force=false)
pcf::IndiProperty m_indiP_telpos
int recordTelData(bool force=false)
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.
double m_mag2_el
MAG2 elevation at time of seeing measurement.
std::thread m_offloadThread
The offloading thread.
double m_telZd
zenith distance
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
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 INDI 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.
tcsInterface()
Default c'tor.
int sendFoffload(float F_0)
pcf::IndiProperty m_indiP_offlTTenable
double m_ttruss
Telescope truss temperature, Celsius.
int doTToffload(float TT_0, float TT_1)
pcf::IndiProperty m_indiP_catalog
INDI Property for the catalog text information.
double m_wxhumid
Outside humidity, percent.
virtual int appStartup()
Startup function.
int recordTelVane(bool force=false)
virtual int appShutdown()
Shutdown the app.
int recordTelSee(bool force=false)
int doFoffload(float F_0)
int m_telDomeStat
dome status
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
int m_telSlewing
slewing state
int m_telROI
The rotator of interest.
int m_telTracking
tracking state
double m_catRo
Catalog rotator offset.
INDI_NEWCALLBACK_DECL(tcsInterface, m_indiP_offlFenable)
double m_wxtemp
Outside temperature, Celsius.
pcf::IndiProperty m_indiP_offlTTavgInt
double m_dimm_fwhm
DIMM raw FWHM.
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_mag2_fwhm
MAG2 raw FWHM.
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
int sendPyrNudge(float x, float y, float z)
INDI_SETCALLBACK_DECL(tcsInterface, m_indiP_loopState)
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
@ 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.
std::string ttyErrorString(int ec)
Get a text explanation of a TTY_E_ error code.
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.
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &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
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
INDI_SETCALLBACK_DEFN(MagAOXApp< _useINDI >, m_indiP_powerChannel)(const pcf
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
#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 which saves telemetry.
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 checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
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)