16 #include <mx/improc/eigenImage.hpp>
17 #include <mx/ioutils/fits/fitsFile.hpp>
19 #include <boost/filesystem/operations.hpp>
21 #include "../../ImageStreamIO/ImageStruct.hpp"
30 template<
typename typeT>
39 return _DATATYPE_FLOAT;
45 return _DATATYPE_DOUBLE;
67 template<
class derivedT,
typename realT>
97 static constexpr uint8_t
m_dmDataType = ImageStreamTypeCode<realT>();
363 pcf::IndiProperty ipFreq(pcf::IndiProperty::Switch);
367 ipFreq.add(pcf::IndiElement(
"toggle"));
368 ipFreq[
"toggle"] = pcf::IndiElement::Off;
369 derived().sendNewProperty(ipFreq);
371 derivedT::template log<text_log>(
"DM saturation threshold exceeded. Loop opened.",
logPrio::LOG_WARNING);
417 const pcf::IndiProperty &
ipRecv
434 const pcf::IndiProperty &
ipRecv
451 const pcf::IndiProperty &
ipRecv
468 const pcf::IndiProperty &
ipRecv
484 const pcf::IndiProperty &
ipRecv
505 const pcf::IndiProperty &
ipRecv
522 const pcf::IndiProperty &
ipRecv
538 const pcf::IndiProperty &
ipRecv
564 return *
static_cast<derivedT *
>(
this);
568 template<
class derivedT,
typename realT>
571 config.add(
"dm.calibPath",
"",
"dm.calibPath", argType::Required,
"dm",
"calibPath",
false,
"string",
"The path to calibration files, relative to the MagAO-X calibration path.");
573 config.add(
"dm.flatPath",
"",
"dm.flatPath", argType::Required,
"dm",
"flatPath",
false,
"string",
"The path to flat files. Default is the calibration path.");
574 config.add(
"dm.flatDefault",
"",
"dm.flatDefault", argType::Required,
"dm",
"flatDefault",
false,
"string",
"The default flat file (path and extension are not required).");
576 config.add(
"dm.testPath",
"",
"dm.testPath", argType::Required,
"dm",
"testPath",
false,
"string",
"The path to test files. Default is the calibration path plus /tests.");
577 config.add(
"dm.testDefault",
"",
"dm.testDefault", argType::Required,
"dm",
"testDefault",
false,
"string",
"The default test file (path and extension are not required).");
582 config.add(
"dm.threadPrio",
"",
"dm.threadPrio", argType::Required,
"dm",
"threadPrio",
false,
"int",
"The real-time priority of the dm control thread.");
583 config.add(
"dm.cpuset",
"",
"dm.cpuset", argType::Required,
"dm",
"cpuset",
false,
"int",
"The cpuset for the dm control thread.");
585 config.add(
"dm.shmimName",
"",
"dm.shmimName", argType::Required,
"dm",
"shmimName",
false,
"string",
"The name of the ImageStreamIO shared memory image to monitor for DM comands. Will be used as /tmp/<shmimName>.im.shm.");
587 config.add(
"dm.shmimFlat",
"",
"dm.shmimFlat", argType::Required,
"dm",
"shmimFlat",
false,
"string",
"The name of the ImageStreamIO shared memory image to write the flat command to. Default is shmimName with 00 apended (i.e. dm00disp -> dm00disp00). ");
589 config.add(
"dm.shmimTest",
"",
"dm.shmimTest", argType::Required,
"dm",
"shmimTest",
false,
"string",
"The name of the ImageStreamIO shared memory image to write the test command to. Default is shmimName with 01 apended (i.e. dm00disp -> dm00disp01). ");
591 config.add(
"dm.shmimSat",
"",
"dm.shmimSat", argType::Required,
"dm",
"shmimSat",
false,
"string",
"The name of the ImageStreamIO shared memory image to write the saturation map to. Default is shmimName with SA apended (i.e. dm00disp -> dm00dispSA). This is created.");
593 config.add(
"dm.shmimSatPerc",
"",
"dm.shmimSatPerc", argType::Required,
"dm",
"shmimSatPerc",
false,
"string",
"The name of the ImageStreamIO shared memory image to write the saturation percentage map to. Default is shmimName with SP apended (i.e. dm00disp -> dm00dispSP). This is created.");
595 config.add(
"dm.satAvgInt",
"",
"dm.satAvgInt", argType::Required,
"dm",
"satAvgInt",
false,
"int",
"The interval in milliseconds over which saturation is accumulated before updating. Default is 100 ms.");
597 config.add(
"dm.width",
"",
"dm.width", argType::Required,
"dm",
"width",
false,
"string",
"The width of the DM in actuators.");
598 config.add(
"dm.height",
"",
"dm.height", argType::Required,
"dm",
"height",
false,
"string",
"The height of the DM in actuators.");
600 config.add(
"dm.percThreshold",
"",
"dm.percThreshold", argType::Required,
"dm",
"percThreshold",
false,
"float",
"Threshold on percentage of frames an actuator is saturated over an interval. Default is 0.98.");
601 config.add(
"dm.intervalSatThreshold",
"",
"dm.intervalSatThreshold", argType::Required,
"dm",
"intervalSatThreshold",
false,
"float",
"Threshold on percentage of actuators which exceed percThreshold in an interval. Default is 0.5.");
602 config.add(
"dm.intervalSatCountThreshold",
"",
"dm.intervalSatCountThreshold", argType::Required,
"dm",
"intervalSatCountThreshold",
false,
"float",
"Threshold one number of consecutive intervals the intervalSatThreshold is exceeded. Default is 10.");
604 config.add(
"dm.satTriggerDevice",
"",
"dm.satTriggerDevice", argType::Required,
"dm",
"satTriggerDevice",
false,
"vector<string>",
"Device(s) with a toggle switch to toggle on saturation trigger.");
605 config.add(
"dm.satTriggerProperty",
"",
"dm.satTriggerProperty", argType::Required,
"dm",
"satTriggerProperty",
false,
"vector<string>",
"Property with a toggle switch to toggle on saturation trigger, one per entry in satTriggerDevice.");
609 template<
class derivedT,
typename realT>
613 m_calibPath = derived().m_calibDir +
"/" + m_calibRelDir;
614 config( m_calibPath,
"dm.calibPath");
617 m_flatPath = m_calibPath +
"/flats";
618 config( m_flatPath,
"dm.flatPath");
620 config(m_flatDefault,
"dm.flatDefault");
621 if(m_flatDefault !=
"")
623 m_flatDefault = mx::ioutils::pathStem(m_flatDefault);
624 m_flatCurrent =
"default";
628 m_testPath = m_calibPath +
"/tests";
629 config(m_testPath,
"dm.testPath");
631 config(m_testDefault,
"dm.testDefault");
632 if(m_testDefault !=
"")
634 m_testDefault = mx::ioutils::pathStem(m_testDefault);
635 m_testCurrent =
"default";
640 config(derived().m_smThreadPrio,
"dm.threadPrio");
641 config(derived().m_smCpuset,
"dm.cpuset");
643 config(derived().m_shmimName,
"dm.shmimName");
645 if(derived().m_shmimName !=
"")
647 m_shmimFlat = derived().m_shmimName +
"00";
648 config(m_shmimFlat,
"dm.shmimFlat");
650 m_shmimTest = derived().m_shmimName +
"02";
651 config(m_shmimTest,
"dm.shmimTest");
654 m_shmimSat = derived().m_shmimName +
"ST";
655 config(m_shmimSat,
"dm.shmimSat");
657 m_shmimSatPerc = derived().m_shmimName +
"SP";
658 config(m_shmimSatPerc,
"dm.shmimSatPerc");
660 config(m_satAvgInt,
"dm.satAvgInt");
664 config.isSet(
"dm.shmimFlat");
665 config.isSet(
"dm.shmimTest");
666 config.isSet(
"dm.shmimSat");
667 config.isSet(
"dm.shmimSatPerc");
668 config.isSet(
"dm.satAvgInt");
671 config(m_dmWidth,
"dm.width");
672 config(m_dmHeight,
"dm.height");
674 config(m_percThreshold,
"dm.percThreshold");
675 config(m_intervalSatThreshold,
"dm.intervalSatThreshold");
676 config(m_intervalSatCountThreshold,
"dm.intervalSatCountThreshold");
677 config(m_satTriggerDevice,
"dm.satTriggerDevice");
678 config(m_satTriggerProperty,
"dm.satTriggerProperty");
682 template<
class derivedT,
typename realT>
685 if( m_dmDataType == 0)
687 derivedT::template log<software_error>({__FILE__,__LINE__,
"unsupported DM data type"});
696 m_indiP_flatShmim = pcf::IndiProperty(pcf::IndiProperty::Text);
697 m_indiP_flatShmim.setDevice(derived().configName());
698 m_indiP_flatShmim.setName(
"flat_shmim");
699 m_indiP_flatShmim.setPerm(pcf::IndiProperty::ReadOnly);
700 m_indiP_flatShmim.setState(pcf::IndiProperty::Idle);
701 m_indiP_flatShmim.add(pcf::IndiElement(
"channel"));
702 m_indiP_flatShmim[
"channel"] = m_shmimFlat;
704 if( derived().registerIndiPropertyReadOnly( m_indiP_flatShmim) < 0)
706 #ifndef DM_TEST_NOLOG
707 derivedT::template log<software_error>({__FILE__,__LINE__});
713 derived().createStandardIndiToggleSw( m_indiP_setFlat,
"flat_set");
714 if( derived().registerIndiPropertyNew( m_indiP_setFlat, st_newCallBack_setFlat) < 0)
716 #ifndef DM_TEST_NOLOG
717 derivedT::template log<software_error>({__FILE__,__LINE__});
727 m_indiP_testShmim = pcf::IndiProperty(pcf::IndiProperty::Text);
728 m_indiP_testShmim.setDevice(derived().configName());
729 m_indiP_testShmim.setName(
"test_shmim");
730 m_indiP_testShmim.setPerm(pcf::IndiProperty::ReadOnly);
731 m_indiP_testShmim.setState(pcf::IndiProperty::Idle);
732 m_indiP_testShmim.add(pcf::IndiElement(
"channel"));
733 m_indiP_testShmim[
"channel"] = m_shmimTest;
734 derived().createStandardIndiToggleSw( m_indiP_setTest,
"test_shmim");
735 if( derived().registerIndiPropertyReadOnly( m_indiP_testShmim) < 0)
737 #ifndef DM_TEST_NOLOG
738 derivedT::template log<software_error>({__FILE__,__LINE__});
744 derived().createStandardIndiToggleSw( m_indiP_setTest,
"test_set");
745 if( derived().registerIndiPropertyNew( m_indiP_setTest, st_newCallBack_setTest) < 0)
747 #ifndef DM_TEST_NOLOG
748 derivedT::template log<software_error>({__FILE__,__LINE__});
754 derived().createStandardIndiRequestSw( m_indiP_init,
"initDM");
755 if( derived().registerIndiPropertyNew( m_indiP_init, st_newCallBack_init) < 0)
757 #ifndef DM_TEST_NOLOG
758 derivedT::template log<software_error>({__FILE__,__LINE__});
764 derived().createStandardIndiRequestSw( m_indiP_zero,
"zeroDM");
765 if( derived().registerIndiPropertyNew( m_indiP_zero, st_newCallBack_zero) < 0)
767 #ifndef DM_TEST_NOLOG
768 derivedT::template log<software_error>({__FILE__,__LINE__});
774 derived().createStandardIndiRequestSw( m_indiP_release,
"releaseDM");
775 if( derived().registerIndiPropertyNew( m_indiP_release, st_newCallBack_release) < 0)
777 #ifndef DM_TEST_NOLOG
778 derivedT::template log<software_error>({__FILE__,__LINE__});
783 derived().createStandardIndiRequestSw( m_indiP_zeroAll,
"zeroAll");
784 if( derived().registerIndiPropertyNew( m_indiP_zeroAll, st_newCallBack_zeroAll) < 0)
786 #ifndef DM_TEST_NOLOG
787 derivedT::template log<software_error>({__FILE__,__LINE__});
792 if(m_flatDefault !=
"")
797 if(m_testDefault !=
"")
802 if(sem_init(&m_satSemaphore, 0,0) < 0)
return derivedT::template
log<software_critical, -1>({__FILE__, __LINE__, errno,0,
"Initializing sat semaphore"});
804 if(derived().threadStart( m_satThread, m_satThreadInit, m_satThreadID, m_satThreadProp, m_satThreadPrio,
"",
"saturation",
this, satThreadStart) < 0)
806 derivedT::template
log<software_error, -1>({__FILE__, __LINE__});
814 template<
class derivedT,
typename realT>
818 if(pthread_tryjoin_np(m_satThread.native_handle(),0) == 0)
820 derivedT::template log<software_error>({__FILE__, __LINE__,
"saturation thread has exited"});
828 if(m_intervalSatTrip)
831 m_intervalSatTrip =
false;
839 template<
class derivedT,
typename realT>
842 if(m_satThread.joinable())
844 pthread_kill(m_satThread.native_handle(), SIGUSR1);
857 template<
class derivedT,
typename realT>
864 template<
class derivedT,
typename realT>
873 template<
class derivedT,
typename realT>
876 std::vector<std::string> dmlist = mx::ioutils::getFileNames(
"/milk/shm/", derived().m_shmimName,
".im",
".shm");
878 if(dmlist.size() == 0)
880 derivedT::template log<software_error>({__FILE__, __LINE__,
"no dm channels found for " + derived().m_shmimName});
885 for(
size_t n =0; n < dmlist.size(); ++n)
888 snprintf(nstr,
sizeof(nstr),
"%02d.im.shm", (
int) n);
889 std::string tgt = derived().m_shmimName;
892 for(
size_t m=0; m < dmlist.size(); ++m)
894 if( dmlist[m].find(tgt) != std::string::npos)
896 if((
int) n > m_channels) m_channels = n;
904 derivedT::template log<text_log>({std::string(
"Found ") + std::to_string(m_channels) +
" channels for " + derived().m_shmimName});
909 template<
class derivedT,
typename realT>
912 static_cast<void>(sp);
916 if(derived().m_width != m_dmWidth)
918 derivedT::template log<software_critical>({__FILE__,__LINE__,
"shmim width does not match configured DM width"});
922 if(derived().m_height != m_dmHeight)
924 derivedT::template log<software_critical>({__FILE__,__LINE__,
"shmim height does not match configured DM height"});
928 if(derived().m_dataType != m_dmDataType)
930 derivedT::template log<software_critical>({__FILE__,__LINE__,
"shmim data type does not match configured DM data type"});
936 m_instSatMap.resize(m_dmWidth,m_dmHeight);
937 m_instSatMap.setZero();
939 m_accumSatMap.resize(m_dmWidth,m_dmHeight);
940 m_accumSatMap.setZero();
942 m_satPercMap.resize(m_dmWidth,m_dmHeight);
943 m_satPercMap.setZero();
945 if(findDMChannels() < 0)
947 derivedT::template log<software_critical>({__FILE__,__LINE__,
"error finding DM channels"});
955 template<
class derivedT,
typename realT>
960 static_cast<void>(sp);
962 int rv = derived().commandDM( curr_src );
966 derivedT::template log<software_critical>({__FILE__, __LINE__, errno, rv,
"Error from commandDM"});
970 if(sem_post(&m_satSemaphore) < 0)
972 derivedT::template log<software_critical>({__FILE__, __LINE__, errno, 0,
"Error posting to semaphore"});
979 template<
class derivedT,
typename realT>
983 if( (rv = derived().releaseDM()) < 0)
985 derivedT::template log<software_critical>({__FILE__, __LINE__, errno, rv,
"Error from releaseDM"});
989 if( (rv = zeroAll(
true)) < 0)
991 derivedT::template log<software_error>({__FILE__, __LINE__, errno, rv,
"Error from zeroAll"});
998 template<
class derivedT,
typename realT>
1001 std::vector<std::string> tfs = mx::ioutils::getFileNames(m_flatPath,
"",
"",
".fits");
1004 for(
size_t n=0; n < tfs.size(); ++n)
1006 if(mx::ioutils::pathStem(tfs[n]) ==
"default")
1008 tfs.erase(tfs.begin()+n);
1013 unsigned m_nFlatFiles = 5;
1016 if(tfs.size() >= m_nFlatFiles)
1018 std::vector<std::time_t> wtimes (tfs.size());
1020 for(
size_t n=0; n < wtimes.size(); ++n)
1022 wtimes[n] = boost::filesystem::last_write_time(tfs[n]);
1025 std::sort(wtimes.begin(), wtimes.end());
1027 std::time_t tn = wtimes[wtimes.size() - m_nFlatFiles];
1029 for(
size_t n=0; n < tfs.size(); ++n)
1031 std::time_t lmt = boost::filesystem::last_write_time(tfs[n]);
1034 tfs.erase(tfs.begin() + n);
1041 for(
auto it = m_flatCommands.begin();
it != m_flatCommands.end(); ++
it)
1046 bool changed =
false;
1047 for(
size_t n=0; n<tfs.size(); ++n)
1049 auto ir = m_flatCommands.insert(std::pair<std::string,std::string>(mx::ioutils::pathStem(tfs[n]), tfs[n]));
1050 if(ir.second ==
true) changed =
true;
1051 else ir.first->second = tfs[n];
1054 for(
auto it = m_flatCommands.begin();
it != m_flatCommands.end(); ++
it)
1056 if(
it->second ==
"")
1062 m_flatCommands.erase(itdel);
1069 if(derived().m_indiDriver)
1071 derived().m_indiDriver->sendDelProperty(m_indiP_flats);
1072 derived().m_indiNewCallBacks.erase(m_indiP_flats.createUniqueKey());
1075 m_indiP_flats = pcf::IndiProperty(pcf::IndiProperty::Switch);
1076 m_indiP_flats.setDevice(derived().configName());
1077 m_indiP_flats.setName(
"flat");
1078 m_indiP_flats.setPerm(pcf::IndiProperty::ReadWrite);
1079 m_indiP_flats.setState(pcf::IndiProperty::Idle);
1080 m_indiP_flats.setRule(pcf::IndiProperty::OneOfMany);
1083 for(
auto it = m_flatCommands.begin();
it != m_flatCommands.end(); ++
it)
1085 if(
it->first == m_flatCurrent || m_flatCurrent ==
"")
1087 m_indiP_flats.add(pcf::IndiElement(
it->first, pcf::IndiElement::On));
1088 m_flatCurrent =
it->first;
1092 m_indiP_flats.add(pcf::IndiElement(
it->first, pcf::IndiElement::Off));
1096 if(m_flatDefault !=
"")
1098 if(m_flatCurrent ==
"default")
1100 m_indiP_flats.add(pcf::IndiElement(
"default", pcf::IndiElement::On));
1104 m_indiP_flats.add(pcf::IndiElement(
"default", pcf::IndiElement::Off));
1109 if( derived().registerIndiPropertyNew( m_indiP_flats, st_newCallBack_flats) < 0)
1111 #ifndef DM_TEST_NOLOG
1112 derivedT::template log<software_error>({__FILE__,__LINE__});
1117 if(derived().m_indiDriver)
1119 derived().m_indiDriver->sendDefProperty(m_indiP_flats);
1126 template <
class derivedT,
typename realT>
1129 std::string target = intarget;
1131 std::string targetPath;
1133 if(target ==
"default")
1135 target = m_flatDefault;
1136 targetPath = m_flatPath +
"/" + m_flatDefault +
".fits";
1142 targetPath = m_flatCommands.at(target);
1146 derivedT::template log<text_log>(
"flat file " + target +
" not found",
logPrio::LOG_ERROR);
1151 m_flatLoaded =
false;
1153 mx::fits::fitsFile<realT> ff;
1154 if(ff.read(m_flatCommand, targetPath) < 0)
1156 derivedT::template log<text_log>(
"flat file " + targetPath +
" not found",
logPrio::LOG_ERROR);
1160 derivedT::template log<text_log>(
"loaded flat file " + targetPath);
1161 m_flatLoaded =
true;
1163 m_flatCurrent = intarget;
1165 if(m_indiP_flats.find(
"default"))
1167 if(m_flatCurrent ==
"default")
1169 m_indiP_flats[
"default"] = pcf::IndiElement::On;
1173 m_indiP_flats[
"default"] = pcf::IndiElement::Off;
1177 for(
auto i = m_flatCommands.begin(); i != m_flatCommands.end(); ++i)
1179 if(!m_indiP_flats.find(i->first))
1184 if(i->first == m_flatCurrent)
1186 m_indiP_flats[i->first] = pcf::IndiElement::On;
1190 m_indiP_flats[i->first] = pcf::IndiElement::Off;
1194 if(derived().m_indiDriver)
1196 derived().m_indiDriver->sendSetProperty(m_indiP_flats);
1207 template<
class derivedT,
typename realT>
1210 if(m_shmimFlat ==
"")
return 0;
1212 if( ImageStreamIO_openIm(&m_flatImageStream, m_shmimFlat.c_str()) != 0)
1214 derivedT::template log<text_log>(
"could not connect to flat channel " + m_shmimFlat,
logPrio::LOG_WARNING);
1218 if( m_flatImageStream.md[0].size[0] != m_dmWidth)
1220 ImageStreamIO_closeIm(&m_flatImageStream);
1221 derivedT::template log<text_log>(
"width mismatch between " + m_shmimFlat +
" and configured DM",
logPrio::LOG_ERROR);
1225 if( m_flatImageStream.md[0].size[1] != m_dmHeight)
1227 ImageStreamIO_closeIm(&m_flatImageStream);
1228 derivedT::template log<text_log>(
"height mismatch between " + m_shmimFlat +
" and configured DM",
logPrio::LOG_ERROR);
1234 bool flatSet = m_flatSet;
1237 if( loadFlat(m_flatCurrent) < 0 )
1239 derivedT::template log<text_log>(
"error loading flat " + m_flatCurrent,
logPrio::LOG_ERROR);
1241 m_flatSet = flatSet;
1246 ImageStreamIO_closeIm(&m_flatImageStream);
1251 if( m_flatCommand.rows() != m_dmWidth)
1253 ImageStreamIO_closeIm(&m_flatImageStream);
1254 derivedT::template log<text_log>(
"width mismatch between flat file and configured DM",
logPrio::LOG_ERROR);
1258 if( m_flatCommand.cols() != m_dmHeight)
1260 ImageStreamIO_closeIm(&m_flatImageStream);
1261 derivedT::template log<text_log>(
"height mismatch between flat file and configured DM",
logPrio::LOG_ERROR);
1265 m_flatImageStream.md->write=1;
1269 memcpy( m_flatImageStream.array.raw, m_flatCommand.data(), m_dmWidth*m_dmHeight*
sizeof(realT));
1272 clock_gettime(CLOCK_REALTIME, &m_flatImageStream.md->writetime);
1275 m_flatImageStream.md->atime = m_flatImageStream.md->writetime;
1277 m_flatImageStream.md->cnt0++;
1278 m_flatImageStream.md->write=0;
1279 ImageStreamIO_sempost(&m_flatImageStream,-1);
1284 ImageStreamIO_closeIm(&m_flatImageStream);
1288 derived().updateSwitchIfChanged(m_indiP_setFlat,
"toggle", pcf::IndiElement::On, pcf::IndiProperty::Busy);
1290 derivedT::template log<text_log>(
"flat set");
1296 template<
class derivedT,
typename realT>
1299 if(m_shmimFlat ==
"")
return 0;
1301 if( ImageStreamIO_openIm(&m_flatImageStream, m_shmimFlat.c_str()) != 0)
1303 derivedT::template log<text_log>(
"could not connect to flat channel " + m_shmimFlat,
logPrio::LOG_WARNING);
1307 if( m_flatImageStream.md[0].size[0] != m_dmWidth)
1309 ImageStreamIO_closeIm(&m_flatImageStream);
1310 derivedT::template log<text_log>(
"width mismatch between " + m_shmimFlat +
" and configured DM",
logPrio::LOG_ERROR);
1314 if( m_flatImageStream.md[0].size[1] != m_dmHeight)
1316 ImageStreamIO_closeIm(&m_flatImageStream);
1317 derivedT::template log<text_log>(
"height mismatch between " + m_shmimFlat +
" and configured DM",
logPrio::LOG_ERROR);
1321 m_flatImageStream.md->write=1;
1325 memset( m_flatImageStream.array.raw, 0, m_dmWidth*m_dmHeight*
sizeof(realT));
1328 clock_gettime(CLOCK_REALTIME, &m_flatImageStream.md->writetime);
1331 m_flatImageStream.md->atime = m_flatImageStream.md->writetime;
1333 m_flatImageStream.md->cnt0++;
1334 m_flatImageStream.md->write=0;
1335 ImageStreamIO_sempost(&m_flatImageStream,-1);
1340 ImageStreamIO_closeIm(&m_flatImageStream);
1342 derived().updateSwitchIfChanged(m_indiP_setFlat,
"toggle", pcf::IndiElement::Off, pcf::IndiProperty::Idle);
1344 derivedT::template log<text_log>(
"flat zeroed");
1349 template<
class derivedT,
typename realT>
1352 std::vector<std::string> tfs = mx::ioutils::getFileNames(m_testPath,
"",
"",
".fits");
1354 for(
auto it = m_testCommands.begin();
it != m_testCommands.end(); ++
it)
1359 bool changed =
false;
1360 for(
size_t n=0; n<tfs.size(); ++n)
1362 auto ir = m_testCommands.insert(std::pair<std::string,std::string>(mx::ioutils::pathStem(tfs[n]), tfs[n]));
1363 if(ir.second ==
true) changed =
true;
1364 else ir.first->second = tfs[n];
1367 for(
auto it = m_testCommands.begin();
it != m_testCommands.end(); ++
it)
1369 if(
it->second ==
"")
1375 m_testCommands.erase(itdel);
1382 if(derived().m_indiDriver)
1384 derived().m_indiDriver->sendDelProperty(m_indiP_tests);
1385 derived().m_indiNewCallBacks.erase(m_indiP_tests.createUniqueKey());
1388 m_indiP_tests = pcf::IndiProperty(pcf::IndiProperty::Switch);
1389 m_indiP_tests.setDevice(derived().configName());
1390 m_indiP_tests.setName(
"test");
1391 m_indiP_tests.setPerm(pcf::IndiProperty::ReadWrite);
1392 m_indiP_tests.setState(pcf::IndiProperty::Idle);
1393 m_indiP_tests.setRule(pcf::IndiProperty::OneOfMany);
1396 for(
auto it = m_testCommands.begin();
it != m_testCommands.end(); ++
it)
1398 if(
it->first == m_testCurrent || m_testCurrent ==
"")
1400 m_indiP_tests.add(pcf::IndiElement(
it->first, pcf::IndiElement::On));
1401 m_testCurrent =
it->first;
1405 m_indiP_tests.add(pcf::IndiElement(
it->first, pcf::IndiElement::Off));
1409 if(m_testDefault !=
"")
1411 if(m_testCurrent ==
"default")
1413 m_indiP_tests.add(pcf::IndiElement(
"default", pcf::IndiElement::On));
1417 m_indiP_tests.add(pcf::IndiElement(
"default", pcf::IndiElement::Off));
1422 if( derived().registerIndiPropertyNew( m_indiP_tests, st_newCallBack_tests) < 0)
1424 #ifndef DM_TEST_NOLOG
1425 derivedT::template log<software_error>({__FILE__,__LINE__});
1430 if(derived().m_indiDriver)
1432 derived().m_indiDriver->sendDefProperty(m_indiP_tests);
1439 template <
class derivedT,
typename realT>
1442 std::string target = intarget;
1444 if(target ==
"default")
1446 target = m_testDefault;
1449 std::string targetPath;
1453 targetPath = m_testCommands.at(target);
1457 derivedT::template log<text_log>(
"test file " + target +
" not found",
logPrio::LOG_ERROR);
1461 m_testLoaded =
false;
1463 mx::fits::fitsFile<realT> ff;
1464 if(ff.read(m_testCommand, targetPath) < 0)
1466 derivedT::template log<text_log>(
"test file " + targetPath +
" not found",
logPrio::LOG_ERROR);
1470 derivedT::template log<text_log>(
"loaded test file " + targetPath);
1471 m_testLoaded =
true;
1473 m_testCurrent = intarget;
1475 if(m_indiP_tests.find(
"default"))
1477 if(m_testCurrent ==
"default")
1479 m_indiP_tests[
"default"] = pcf::IndiElement::On;
1483 m_indiP_tests[
"default"] = pcf::IndiElement::Off;
1487 for(
auto i = m_testCommands.begin(); i != m_testCommands.end(); ++i)
1489 if(!m_indiP_tests.find(i->first))
1494 if(i->first == m_testCurrent)
1496 m_indiP_tests[i->first] = pcf::IndiElement::On;
1500 m_indiP_tests[i->first] = pcf::IndiElement::Off;
1504 if(derived().m_indiDriver) derived().m_indiDriver->sendSetProperty (m_indiP_tests);
1506 if(m_testSet) setTest();
1511 template<
class derivedT,
typename realT>
1515 if(m_shmimTest ==
"")
return 0;
1517 if( ImageStreamIO_openIm(&m_testImageStream, m_shmimTest.c_str()) != 0)
1519 derivedT::template log<text_log>(
"could not connect to test channel " + m_shmimTest,
logPrio::LOG_WARNING);
1523 if( m_testImageStream.md->size[0] != m_dmWidth)
1525 ImageStreamIO_closeIm(&m_testImageStream);
1526 derivedT::template log<text_log>(
"width mismatch between " + m_shmimTest +
" and configured DM",
logPrio::LOG_ERROR);
1530 if( m_testImageStream.md->size[1] != m_dmHeight)
1532 ImageStreamIO_closeIm(&m_testImageStream);
1533 derivedT::template log<text_log>(
"height mismatch between " + m_shmimTest +
" and configured DM",
logPrio::LOG_ERROR);
1539 bool testSet = m_testSet;
1542 if(loadTest(m_testCurrent)<0)
1544 derivedT::template log<text_log>(
"error loading test " + m_testCurrent,
logPrio::LOG_ERROR);
1546 m_testSet = testSet;
1551 ImageStreamIO_closeIm(&m_testImageStream);
1556 if( m_testCommand.rows() != m_dmWidth)
1558 ImageStreamIO_closeIm(&m_testImageStream);
1559 derivedT::template log<text_log>(
"width mismatch between test file and configured DM",
logPrio::LOG_ERROR);
1563 if( m_testCommand.cols() != m_dmHeight)
1565 ImageStreamIO_closeIm(&m_testImageStream);
1566 derivedT::template log<text_log>(
"height mismatch between test file and configured DM",
logPrio::LOG_ERROR);
1570 m_testImageStream.md->write=1;
1574 memcpy( m_testImageStream.array.raw, m_testCommand.data(), m_dmWidth*m_dmHeight*
sizeof(realT));
1577 clock_gettime(CLOCK_REALTIME, &m_testImageStream.md->writetime);
1580 m_testImageStream.md->atime = m_testImageStream.md->writetime;
1582 m_testImageStream.md->cnt0++;
1583 m_testImageStream.md->write=0;
1584 ImageStreamIO_sempost(&m_testImageStream,-1);
1589 ImageStreamIO_closeIm(&m_testImageStream);
1591 derived().updateSwitchIfChanged(m_indiP_setTest,
"toggle", pcf::IndiElement::On, pcf::IndiProperty::Busy);
1593 derivedT::template log<text_log>(
"test set");
1598 template<
class derivedT,
typename realT>
1601 if(m_shmimTest ==
"")
return 0;
1603 if( ImageStreamIO_openIm(&m_testImageStream, m_shmimTest.c_str()) != 0)
1605 derivedT::template log<text_log>(
"could not connect to test channel " + m_shmimTest,
logPrio::LOG_WARNING);
1609 if( m_testImageStream.md[0].size[0] != m_dmWidth)
1611 ImageStreamIO_closeIm(&m_testImageStream);
1612 derivedT::template log<text_log>(
"width mismatch between " + m_shmimTest +
" and configured DM",
logPrio::LOG_ERROR);
1616 if( m_testImageStream.md[0].size[1] != m_dmHeight)
1618 ImageStreamIO_closeIm(&m_testImageStream);
1619 derivedT::template log<text_log>(
"height mismatch between " + m_shmimTest +
" and configured DM",
logPrio::LOG_ERROR);
1623 m_testImageStream.md->write=1;
1627 memset( m_testImageStream.array.raw, 0, m_dmWidth*m_dmHeight*
sizeof(realT));
1630 clock_gettime(CLOCK_REALTIME, &m_testImageStream.md->writetime);
1633 m_testImageStream.md->atime = m_testImageStream.md->writetime;
1635 m_testImageStream.md->cnt0++;
1636 m_testImageStream.md->write=0;
1639 ImageStreamIO_sempost(&m_testImageStream,-1);
1643 ImageStreamIO_closeIm(&m_testImageStream);
1645 derived().updateSwitchIfChanged(m_indiP_setTest,
"toggle", pcf::IndiElement::Off, pcf::IndiProperty::Idle);
1647 derivedT::template log<text_log>(
"test zeroed");
1652 template<
class derivedT,
typename realT>
1655 if(derived().m_shmimName ==
"")
return 0;
1659 for(
int n=0; n < m_channels; ++n)
1662 snprintf(nstr,
sizeof(nstr),
"%02d", n);
1663 std::string shmimN = derived().m_shmimName + nstr;
1665 if( ImageStreamIO_openIm(&imageStream, shmimN.c_str()) != 0)
1667 derivedT::template log<text_log>(
"could not connect to channel " + shmimN,
logPrio::LOG_WARNING);
1671 if( imageStream.md->size[0] != m_dmWidth)
1673 ImageStreamIO_closeIm(&imageStream);
1674 derivedT::template log<text_log>(
"width mismatch between " + shmimN +
" and configured DM",
logPrio::LOG_ERROR);
1675 derived().updateSwitchIfChanged(m_indiP_zeroAll,
"request", pcf::IndiElement::Off,
INDI_IDLE);
1679 if( imageStream.md->size[1] != m_dmHeight)
1681 ImageStreamIO_closeIm(&imageStream);
1682 derivedT::template log<text_log>(
"height mismatch between " + shmimN +
" and configured DM",
logPrio::LOG_ERROR);
1683 derived().updateSwitchIfChanged(m_indiP_zeroAll,
"request", pcf::IndiElement::Off,
INDI_IDLE);
1687 imageStream.md->write=1;
1688 memset( imageStream.array.raw, 0, m_dmWidth*m_dmHeight*
sizeof(realT));
1690 clock_gettime(CLOCK_REALTIME, &imageStream.md->writetime);
1693 imageStream.md->atime = imageStream.md->writetime;
1695 imageStream.md->cnt0++;
1696 imageStream.md->write=0;
1699 if(n == m_channels-1 && !nosem) ImageStreamIO_sempost(&imageStream,-1);
1701 ImageStreamIO_closeIm(&imageStream);
1706 derived().updateSwitchIfChanged(m_indiP_zeroAll,
"request", pcf::IndiElement::Off,
INDI_IDLE);
1710 derived().updateSwitchIfChanged(m_indiP_setFlat,
"toggle", pcf::IndiElement::Off, pcf::IndiProperty::Idle);
1714 derived().updateSwitchIfChanged(m_indiP_setTest,
"toggle", pcf::IndiElement::Off, pcf::IndiProperty::Idle);
1717 if( (rv = clearSat()) < 0)
1719 derivedT::template log<software_error>({__FILE__, __LINE__, errno, rv,
"Error from clearSat"});
1726 template<
class derivedT,
typename realT>
1729 if(m_shmimSat ==
"")
return 0;
1733 std::vector<std::string> sats = {m_shmimSat, m_shmimSatPerc};
1735 for(
size_t n=0; n < sats.size(); ++n)
1737 std::string shmimN = sats[n];
1739 if( ImageStreamIO_openIm(&imageStream, shmimN.c_str()) != 0)
1741 derivedT::template log<text_log>(
"could not connect to sat map " + shmimN,
logPrio::LOG_WARNING);
1745 if( imageStream.md->size[0] != m_dmWidth)
1747 ImageStreamIO_closeIm(&imageStream);
1748 derivedT::template log<text_log>(
"width mismatch between " + shmimN +
" and configured DM",
logPrio::LOG_ERROR);
1749 derived().updateSwitchIfChanged(m_indiP_zeroAll,
"request", pcf::IndiElement::Off,
INDI_IDLE);
1753 if( imageStream.md->size[1] != m_dmHeight)
1755 ImageStreamIO_closeIm(&imageStream);
1756 derivedT::template log<text_log>(
"height mismatch between " + shmimN +
" and configured DM",
logPrio::LOG_ERROR);
1757 derived().updateSwitchIfChanged(m_indiP_zeroAll,
"request", pcf::IndiElement::Off,
INDI_IDLE);
1761 imageStream.md->write=1;
1762 memset( imageStream.array.raw, 0, m_dmWidth*m_dmHeight*
sizeof(realT));
1764 clock_gettime(CLOCK_REALTIME, &imageStream.md->writetime);
1767 imageStream.md->atime = imageStream.md->writetime;
1769 imageStream.md->cnt0++;
1770 imageStream.md->write=0;
1772 ImageStreamIO_closeIm(&imageStream);
1775 m_accumSatMap.setZero();
1776 m_instSatMap.setZero();
1782 template<
class derivedT,
typename realT>
1788 template<
class derivedT,
typename realT>
1792 m_satThreadID = syscall(SYS_gettid);
1795 while(m_satThreadInit ==
true && derived().shutdown() == 0)
1799 if(derived().shutdown())
return;
1801 uint32_t imsize[3] = {0,0,0};
1804 while((m_shmimSat ==
"" || m_accumSatMap.rows() == 0 || m_accumSatMap.cols() == 0) && !derived().shutdown())
1808 if(derived().shutdown())
return;
1810 imsize[0] = m_dmWidth;
1811 imsize[1] = m_dmHeight;
1814 ImageStreamIO_createIm_gpu(&m_satImageStream, m_shmimSat.c_str(), 3, imsize,
IMAGESTRUCT_UINT8, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL, 0);
1815 ImageStreamIO_createIm_gpu(&m_satPercImageStream, m_shmimSatPerc.c_str(), 3, imsize,
IMAGESTRUCT_FLOAT, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL, 0);
1819 m_satImageStream.md->cnt1 = 0;
1820 m_satPercImageStream.md->cnt1 = 0;
1823 mx::improc::eigenImage<uint8_t> satmap(m_dmWidth, m_dmHeight);
1826 double t_accumst = mx::sys::get_curr_time();
1829 while(!derived().shutdown())
1833 if(clock_gettime(CLOCK_REALTIME, &ts) < 0)
1835 derivedT::template log<software_critical>({__FILE__,__LINE__,errno,0,
"clock_gettime"});
1841 if(sem_timedwait(&m_satSemaphore, &ts) == 0)
1844 for(
int rr=0; rr < m_instSatMap.rows(); ++rr)
1846 for(
int cc=0; cc< m_instSatMap.cols(); ++cc)
1848 m_accumSatMap(rr,cc) += m_instSatMap(rr,cc);
1854 if(mx::sys::get_curr_time(ts) - t_accumst < m_satAvgInt/1000.0)
continue;
1861 for(
int rr=0; rr < m_instSatMap.rows(); ++rr)
1863 for(
int cc=0; cc< m_instSatMap.cols(); ++cc)
1865 m_satPercMap(rr,cc) = m_accumSatMap(rr,cc)/naccum;
1866 if(m_satPercMap(rr,cc) >= m_percThreshold) ++m_overSatAct;
1867 satmap(rr,cc) = (m_accumSatMap(rr,cc) > 0);
1873 if(m_overSatAct/(m_satPercMap.rows()*m_satPercMap.cols()*0.75) > m_intervalSatThreshold ) ++m_intervalSatExceeds;
1874 else m_intervalSatExceeds = 0;
1877 if(m_intervalSatExceeds >= m_intervalSatCountThreshold) m_intervalSatTrip =
true;
1879 m_satImageStream.md->write=1;
1880 m_satPercImageStream.md->write=1;
1882 memcpy( m_satImageStream.array.raw, satmap.data() , m_dmWidth*m_dmHeight*
sizeof(uint8_t));
1883 memcpy( m_satPercImageStream.array.raw, m_satPercMap.data() , m_dmWidth*m_dmHeight*
sizeof(
float));
1886 clock_gettime(CLOCK_REALTIME, &m_satImageStream.md->writetime);
1887 m_satPercImageStream.md->writetime = m_satImageStream.md->writetime;
1890 m_satImageStream.md->atime = m_satImageStream.md->writetime;
1891 m_satPercImageStream.md->atime = m_satPercImageStream.md->writetime;
1894 m_satImageStream.md->cnt1 = 0;
1895 m_satPercImageStream.md->cnt1 = 0;
1898 m_satImageStream.md->cnt0++;
1899 m_satPercImageStream.md->cnt0++;
1901 m_satImageStream.writetimearray[0] = m_satImageStream.md->writetime;
1902 m_satImageStream.atimearray[0] = m_satImageStream.md->atime;
1903 m_satImageStream.cntarray[0] = m_satImageStream.md->cnt0;
1905 m_satPercImageStream.writetimearray[0] = m_satPercImageStream.md->writetime;
1906 m_satPercImageStream.atimearray[0] = m_satPercImageStream.md->atime;
1907 m_satPercImageStream.cntarray[0] = m_satPercImageStream.md->cnt0;
1910 m_satImageStream.md->write=0;
1911 ImageStreamIO_sempost(&m_satImageStream,-1);
1913 m_satPercImageStream.md->write=0;
1914 ImageStreamIO_sempost(&m_satPercImageStream,-1);
1916 m_accumSatMap.setZero();
1918 t_accumst = mx::sys::get_curr_time(ts);
1923 if(errno == EINTR)
break;
1927 if(errno != ETIMEDOUT)
1929 derivedT::template log<software_error>({__FILE__, __LINE__,errno,
"sem_timedwait"});
1937 ImageStreamIO_destroyIm( &m_satImageStream );
1939 ImageStreamIO_destroyIm( &m_satPercImageStream );
1943 template<
class derivedT,
typename realT>
1946 if( !derived().m_indiDriver )
return 0;
1953 template<
class derivedT,
typename realT>
1955 const pcf::IndiProperty &
ipRecv
1958 return static_cast<derivedT *
>(app)->newCallBack_init(
ipRecv);
1961 template<
class derivedT,
typename realT>
1964 if(
ipRecv.createUniqueKey() != m_indiP_init.createUniqueKey())
1966 return derivedT::template
log<software_error,-1>({__FILE__, __LINE__,
"wrong INDI-P in callback"});
1969 if(!
ipRecv.find(
"request"))
return 0;
1971 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
1973 return derived().initDM();
1978 template<
class derivedT,
typename realT>
1980 const pcf::IndiProperty &
ipRecv
1983 return static_cast<derivedT *
>(app)->newCallBack_zero(
ipRecv);
1986 template<
class derivedT,
typename realT>
1989 if(
ipRecv.createUniqueKey() != m_indiP_zero.createUniqueKey())
1991 return derivedT::template
log<software_error,-1>({__FILE__, __LINE__,
"wrong INDI-P in callback"});
1994 if(!
ipRecv.find(
"request"))
return 0;
1996 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
1998 return derived().zeroDM();
2003 template<
class derivedT,
typename realT>
2005 const pcf::IndiProperty &
ipRecv
2008 return static_cast<derivedT *
>(app)->newCallBack_release(
ipRecv);
2011 template<
class derivedT,
typename realT>
2014 if(
ipRecv.createUniqueKey() != m_indiP_release.createUniqueKey())
2016 return derivedT::template
log<software_error,-1>({__FILE__, __LINE__,
"wrong INDI-P in callback"});
2019 if(!
ipRecv.find(
"request"))
return 0;
2021 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
2028 template<
class derivedT,
typename realT>
2030 const pcf::IndiProperty &
ipRecv
2033 return static_cast< derivedT *
>(app)->newCallBack_flats(
ipRecv);
2036 template<
class derivedT,
typename realT>
2039 if(
ipRecv.createUniqueKey() != m_indiP_flats.createUniqueKey())
2041 derivedT::template log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
2045 std::string newFlat;
2047 if(
ipRecv.find(
"default"))
2049 if(
ipRecv[
"default"].getSwitchState() == pcf::IndiElement::On)
2051 newFlat =
"default";
2056 for(
auto i=m_flatCommands.begin(); i != m_flatCommands.end(); ++i)
2058 if(!
ipRecv.find(i->first))
continue;
2060 if(
ipRecv[i->first].getSwitchState() == pcf::IndiElement::On)
2072 if(newFlat ==
"")
return 0;
2074 return loadFlat(newFlat);
2077 template<
class derivedT,
typename realT>
2079 const pcf::IndiProperty &
ipRecv
2082 return static_cast< derivedT *
>(app)->newCallBack_setFlat(
ipRecv);
2085 template<
class derivedT,
typename realT>
2088 if(
ipRecv.createUniqueKey() != m_indiP_setFlat.createUniqueKey())
2090 return derivedT::template
log<software_error,-1>({__FILE__, __LINE__,
"wrong INDI-P in callback"});
2093 if(!
ipRecv.find(
"toggle"))
return 0;
2095 if(
ipRecv[
"toggle"] == pcf::IndiElement::On)
2105 template<
class derivedT,
typename realT>
2107 const pcf::IndiProperty &
ipRecv
2110 return static_cast< derivedT *
>(app)->newCallBack_tests(
ipRecv);
2113 template<
class derivedT,
typename realT>
2116 if(
ipRecv.createUniqueKey() != m_indiP_tests.createUniqueKey())
2118 derivedT::template log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
2122 std::string newTest;
2124 if(
ipRecv.find(
"default"))
2126 if(
ipRecv[
"default"].getSwitchState() == pcf::IndiElement::On)
2128 newTest =
"default";
2133 for(
auto i=m_testCommands.begin(); i != m_testCommands.end(); ++i)
2135 if(!
ipRecv.find(i->first))
continue;
2137 if(
ipRecv[i->first].getSwitchState() == pcf::IndiElement::On)
2149 if(newTest ==
"")
return 0;
2151 return loadTest(newTest);
2154 template<
class derivedT,
typename realT>
2156 const pcf::IndiProperty &
ipRecv
2159 return static_cast< derivedT *
>(app)->newCallBack_setTest(
ipRecv);
2162 template<
class derivedT,
typename realT>
2165 if(
ipRecv.createUniqueKey() != m_indiP_setTest.createUniqueKey())
2167 return derivedT::template
log<software_error,-1>({__FILE__, __LINE__,
"wrong INDI-P in callback"});
2170 if(!
ipRecv.find(
"toggle"))
return 0;
2172 if(
ipRecv[
"toggle"] == pcf::IndiElement::On)
2183 template<
class derivedT,
typename realT>
2185 const pcf::IndiProperty &
ipRecv
2188 return static_cast< derivedT *
>(app)->newCallBack_zeroAll(
ipRecv);
2191 template<
class derivedT,
typename realT>
2194 if(
ipRecv.createUniqueKey() != m_indiP_zeroAll.createUniqueKey())
2196 return derivedT::template
log<software_error,-1>({__FILE__, __LINE__,
"wrong INDI-P in callback"});
2199 if(!
ipRecv.find(
"request"))
return 0;
2201 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On)
2205 std::lock_guard<std::mutex> guard(derived().m_indiMutex);
#define IMAGESTRUCT_FLOAT
#define IMAGESTRUCT_UINT8
std::string m_calibPath
The path to this DM's calibration files.
std::map< std::string, std::string > m_flatCommands
Map of flat file name to full path.
int newCallBack_tests(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the new request.
bool m_testSet
Flag indicating whether the test command has been set.
std::string m_flatPath
The path to this DM's flat files (usually the same as calibPath)
pcf::IndiProperty m_indiP_setFlat
INDI toggle switch to set the current flat.
static void satThreadStart(dm *d)
Thread starter, called by MagAOXApp::threadStart on thread construction. Calls satThreadExec.
pcf::IndiProperty m_indiP_init
uint32_t m_dmWidth
The width of the images in the stream.
pcf::IndiProperty m_indiP_flats
INDI Selection switch containing the flat files.
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int zeroFlat()
Zero the flat command on the DM.
static int st_newCallBack_init(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for initializing the DM.
int checkFlats()
Check the flats directory and update the list of flats if anything changes.
pcf::IndiProperty m_indiP_testShmim
Publish the shmim being used for the test command.
int checkTests()
Check the tests directory and update the list of tests if anything changes.
static int st_newCallBack_tests(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for selecting the test file.
std::string m_flatDefault
The file name of the this DM's default flat command. Path and extension will be ignored and can be om...
int setTest()
Send the current test command to the DM.
int clearSat()
Clear the saturation maps and zero the shared membory.
static int st_newCallBack_zero(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for initializing the DM.
int loadTest(const std::string &target)
Load a test file.
int loadFlat(const std::string &target)
Load a flat file.
int m_satThreadPrio
Priority of the saturation thread, should normally be > 0.
IMAGE m_satPercImageStream
The ImageStreamIO shared memory buffer for the sat percentage map.
std::string m_calibRelDir
The directory relative to the calibPath. Set this before calling dm<derivedT,realT>::loadConfig().
pcf::IndiProperty m_indiP_setTest
INDI toggle switch to set the current test pattern.
int findDMChannels()
Find the DM comb channels.
static constexpr uint8_t m_dmDataType
The ImageStreamIO type code.
pcf::IndiProperty m_indiP_tests
INDI Selection switch containing the test pattern files.
std::string m_shmimFlat
The name of the shmim stream to write the flat to.
int processImage(void *curr_src, const dev::shmimT &sp)
Called by shmimMonitor when a new DM command is available. This is just a pass-through to derivedT::c...
uint32_t m_dmHeight
The height of the images in the stream.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
int appShutdown()
DM shutdown.
std::string m_testPath
The path to this DM's test files (default is calibPath/tests;.
int newCallBack_zeroAll(const pcf::IndiProperty &ipRecv)
The callback for the zeroAll toggle switch, called by the static version.
bool m_flatSet
Flag indicating whether the flat command has been set.
pcf::IndiProperty m_satThreadProp
The property to hold the saturation thread details.
std::string m_shmimSatPerc
The name of the shmim stream to write the saturation percentage map to.
int newCallBack_setTest(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the new request.
static int st_newCallBack_flats(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for selecting the flat file.
std::string m_testCurrent
bool m_flatLoaded
Flag indicating whether a flat is loaded in memory.
bool m_testLoaded
Flag indicating whether a test command is loaded in memory.
mx::improc::eigenImage< float > m_satPercMap
Map of the percentage of time each actator was saturated during the avg. interval.
int setFlat(bool update=false)
Send the current flat command to the DM.
static int st_newCallBack_zeroAll(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for zeroing all channels.
int newCallBack_init(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the new request.
int zeroAll(bool nosem=false)
Zero all channels.
pid_t m_satThreadID
The ID of the saturation thread.
int zeroTest()
Zero the test command on the DM.
int m_satAvgInt
The time in milliseconds to accumulate saturation over.
int newCallBack_release(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the new request.
std::vector< std::string > m_satTriggerProperty
int updateINDI()
Update the INDI properties for this device controller.
int newCallBack_flats(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the new request.
sem_t m_satSemaphore
Semaphore used to tell the saturation thread to run.
pcf::IndiProperty m_indiP_flat
Property used to set and report the current flat.
IMAGE m_satImageStream
The ImageStreamIO shared memory buffer for the sat map.
int newCallBack_zero(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the new request.
bool m_satThreadInit
Synchronizer for thread startup, to allow priority setting to finish.
std::vector< std::string > m_satTriggerDevice
mx::improc::eigenImage< realT > m_flatCommand
Data storage for the flat command.
mx::improc::eigenImage< uint8_t > m_instSatMap
The instantaneous saturation map, 0/1, set by the commandDM() function of the derived class.
void satThreadExec()
Execute saturation processing.
static int st_newCallBack_release(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for initializing the DM.
pcf::IndiProperty m_indiP_flatShmim
Publish the shmim being used for the flat.
float m_intervalSatThreshold
int whilePowerOff()
DM Poweroff Updates.
static int st_newCallBack_setFlat(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for setting the flat.
static int st_newCallBack_setTest(void *app, const pcf::IndiProperty &ipRecv)
The static callback function to be registered for setting the test shape.
pcf::IndiProperty m_indiP_zeroAll
std::map< std::string, std::string > m_testCommands
Map of test file name to full path.
IMAGE m_testImageStream
The ImageStreamIO shared memory buffer for the test.
std::string m_testDefault
The file name of the this DM's default test command. Path and extension will be ignored and can be om...
int m_channels
The number of dmcomb channels found as part of allocation.
std::string m_shmimTest
The name of the shmim stream to write the test to.
int m_intervalSatCountThreshold
int appStartup()
Startup function.
int newCallBack_setFlat(const pcf::IndiProperty &ipRecv)
The callback called by the static version, to actually process the new request.
mx::improc::eigenImage< uint16_t > m_accumSatMap
The accumulated saturation map, which acccumulates for m_satAvgInt then is publised as a 0/1 image.
int onPowerOff()
DM Poweroff.
std::string m_shmimSat
The name of the shmim stream to write the saturation map to.
mx::improc::eigenImage< realT > m_testCommand
Data storage for the test command.
IMAGE m_flatImageStream
The ImageStreamIO shared memory buffer for the flat.
std::thread m_satThread
A separate thread for the actual saturation processing.
pcf::IndiProperty m_indiP_release
pcf::IndiProperty m_indiP_zero
int releaseDM()
Calls derived()->releaseDM() and then 0s all channels and the sat map.
int allocate(const dev::shmimT &sp)
Called after shmimMonitor connects to the dmXXdisp stream. Checks for proper size.
std::string m_flatCurrent
The name of the current flat command.
int appLogic()
DM application logic.
constexpr uint8_t ImageStreamTypeCode< float >()
constexpr uint8_t ImageStreamTypeCode()
constexpr uint8_t ImageStreamTypeCode< double >()
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
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.