3 #ifndef ttmModulator_hpp
4 #define ttmModulator_hpp
7 #include "../../libMagAOX/libMagAOX.hpp"
8 #include "../../magaox_git_version.h"
80 std::vector<double>
m_calFreqs = { 100, 250, 500, 750, 1000, 1250, 1500, 1750, 2000};
81 std::vector<double>
m_calC1Amps = {0.22, 0.28, 0.43, 0.61, 0.82, 1.06, 1.35, 1.70, 2.045};
82 std::vector<double>
m_calC2Amps = {0.23, 0.23, 0.56, 0.85, 1.16, 1.58, 1.96, 2.60, 3.63};
83 std::vector<double>
m_calC2Phse = { 79, 82, 82, 82, 82, 82, 84, 88, 93};
149 int modTTM(
double newRad,
218 config.add(
"limits.maxfreq",
"",
"limits.maxfreq", argType::Required,
"limits",
"maxfreq",
false,
"real",
"The maximum frequency [Hz] which can be set through this program.");
219 config.add(
"limits.maxamp",
"",
"limits.maxamp", argType::Required,
"limits",
"maxamp",
false,
"real",
"The maximum amplitude [lam/D] which can be set throught this program.");
221 config.add(
"cal.voltsperld1",
"",
"cal.voltsperld1", argType::Required,
"cal",
"voltsperld1",
false,
"real",
"The voltage per lam/D for channel 1.");
222 config.add(
"cal.voltsperld2",
"",
"cal.voltsperld2", argType::Required,
"cal",
"voltsperld2",
false,
"real",
"The voltage per lam/D for channel 2.");
223 config.add(
"cal.phase",
"",
"cal.phase", argType::Required,
"cal",
"phase",
false,
"real",
"The axis phase offset, which is applied to channel 2.");
225 config.add(
"cal.setv1",
"",
"cal.setv1", argType::Required,
"cal",
"setv1",
false,
"real",
"The set position voltage of chaannel 1.");
226 config.add(
"cal.setv2",
"",
"cal.setv2", argType::Required,
"cal",
"setv2",
false,
"real",
"The set position voltage of chaannel 2.");
228 config.add(
"cal.setDvolts",
"",
"cal.setDvolts", argType::Required,
"cal",
"setDvolts",
false,
"real",
"The setting ramp step size [Volts]");
230 config.add(
"cal.modDfreq",
"",
"cal.modDfreq", argType::Required,
"cal",
"modDfreq",
false,
"real",
"The modulation ramp frequency step size [Hz]");
231 config.add(
"cal.modDvolts",
"",
"cal.modDvolts", argType::Required,
"cal",
"modDvolts",
false,
"real",
"The modulation ramp voltage step size [Volts]");
233 config.add(
"cal.rotAngle",
"",
"cal.rotAngle", argType::Required,
"cal",
"rotAngle",
false,
"real",
"The offset rotation matrix angle in degrees.");
234 config.add(
"cal.rotParity",
"",
"cal.rotParity", argType::Required,
"cal",
"rotParity",
false,
"real",
"The offset rotation matrix parity, +1 or -1.");
321 log<software_critical>({__FILE__,__LINE__});
369 if(newState == 3)
setTTM();
372 if(newRad <= 0.1 || newFreq <= 1)
482 std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>(nsec));
488 unsigned long timeout = 5000000000,
489 unsigned long pauseWait = 1000000
492 if(var == tgtVal)
return 0;
494 struct timespec ts0, ts1;
495 clock_gettime(CLOCK_REALTIME, &ts0);
499 while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
501 if(var == tgtVal)
return 0;
505 clock_gettime(CLOCK_REALTIME, &ts1);
508 if(var == tgtVal)
return 0;
510 std::cerr <<
"Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) <<
"\n";
520 unsigned long timeout = 5000000000,
521 unsigned long pauseWait = 1000000
524 if(fabs(tgtVal - var) <= tol)
return 0;
526 struct timespec ts0, ts1;
527 clock_gettime(CLOCK_REALTIME, &ts0);
530 while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
532 if(fabs(tgtVal - var) <= tol)
return 0;
536 clock_gettime(CLOCK_REALTIME, &ts1);
539 if(fabs(tgtVal - var) <= tol)
return 0;
541 std::cerr <<
"Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) <<
"\n";
571 if(
waitValue(
m_C1freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
572 if(
waitValue(
m_C2freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
573 if(
waitValue(
m_C1volts, 0.002, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
574 if(
waitValue(
m_C2volts, 0.002, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
575 if(
waitValue(
m_C1phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
576 if(
waitValue(
m_C2phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
577 if(
waitValue(
m_C1ofst, 0.001, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
578 if(
waitValue(
m_C2ofst, 0.001, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
579 if(
waitValue(
m_C1outp, 0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
580 if(
waitValue(
m_C2outp, 0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
616 if(
waitValue(
m_C1freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
617 if(
waitValue(
m_C2freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
618 if(
waitValue(
m_C1volts, 0.002, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
619 if(
waitValue(
m_C2volts, 0.002,1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
620 if(
waitValue(
m_C1phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
621 if(
waitValue(
m_C2phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
649 if(
waitValue(
m_C1outp, 1) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
650 if(
waitValue(
m_C2outp, 1) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
659 log<text_log>(
"Ramping with " + std::to_string(N) +
" steps. [" + std::to_string(N1) +
" " + std::to_string(N2) +
"]",
logPrio::LOG_DEBUG);
661 for(
size_t i=1; i< N ; ++i)
665 if(nv < 0 || nv > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
669 if(
waitValue(
m_C1ofst, nv, 1e-10) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
675 if(
waitValue(
m_C2ofst, nv, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
680 for(
size_t j=N; j< N1;++j)
684 if(nv < 0 || nv > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
688 if(
waitValue(
m_C1ofst, nv, 1e-6) < 0 )
return log<software_error, -1>({__FILE__,__LINE__,
"fxngen timeout"});
693 for(
size_t j=N; j< N2;++j)
697 if(nv < 0 || nv > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
701 if(
waitValue(
m_C2ofst, nv, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
708 if( m_setVoltage_1 < 0 || m_setVoltage_1 > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
718 if( m_setVoltage_2 < 0 || m_setVoltage_2 > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
744 if(newRad < 0 || newFreq < 0)
return 0;
756 if(
calcState() < 0)
return log<software_error, -1>({__FILE__,__LINE__});
763 if(
setTTM() < 0 )
return log<software_error, -1>({__FILE__, __LINE__});
765 if(
calcState() < 0 )
return log<software_error, -1>({__FILE__,__LINE__});
773 log<text_log>(
"Requested frequency " + std::to_string(newFreq) +
" Hz exceeds limit (" + std::to_string(
m_maxFreq) +
" Hz). Limiting.",
logPrio::LOG_WARNING);
778 double voltageC1, voltageC2;
784 double terpC1Amp = 0;
785 double terpC2Amp = 0;
786 double terpC2Phse = 0;
818 log<text_log>(
"Requested ch-1 voltge " + std::to_string(voltageC1) +
" V exceeds limit (" + std::to_string(
m_maxVolt) +
" V). Limiting.",
logPrio::LOG_WARNING);
824 log<text_log>(
"Requested ch-2 voltge " + std::to_string(voltageC2) +
" V exceeds limit (" + std::to_string(
m_maxVolt) +
" V). Limiting.",
logPrio::LOG_WARNING);
839 if(
waitValue(
m_C2phse, terpC2Phse, 1e-4) < 0 )
return log<software_error, -1>({__FILE__,__LINE__,
"fxngen timeout"});
842 double nextFreq = 100.0;
843 if(nextFreq > newFreq) nextFreq = newFreq;
850 if(
waitValue(
m_C1freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
851 if(
waitValue(
m_C2freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
854 double nextVolts1 = 0.1;
855 if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
857 double nextVolts2 = 0.1;
858 if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
866 if(
waitValue(
m_C1volts, nextVolts1, 1e-6) < 0 ) log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
867 if(
waitValue(
m_C2volts, nextVolts2, 1e-6) < 0 ) log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
873 if(nextFreq > newFreq) nextFreq = newFreq;
876 while( fabs(currFreq - newFreq) > 1e-4)
882 if(
waitValue(
m_C1freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
883 if(
waitValue(
m_C2freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
889 if(nextFreq > newFreq) nextFreq = newFreq;
897 if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
900 if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
902 while( fabs(currVolts1 - voltageC1) > 1e-4 || fabs(currVolts2 - voltageC2) > 1e-4)
921 if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
925 if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
932 else return log<
software_error,-1>({__FILE__,__LINE__,
"TTM not set but should be by now."});
959 double rdx = dx * cs - dy * ss;
975 if( indiTargetUpdate( m_indiP_modState, target,
ipRecv,
false) < 0)
980 m_modStateRequested = target;
1005 if( indiTargetUpdate( m_indiP_modFrequency, target,
ipRecv,
false) < 0)
1012 m_modFreqRequested = target;
1019 nf = ipRecv["target"].get<double>();
1020 if(nf > 0) m_modFreqRequested = nf;
1024 //do nothing, just means no requested in command.
1037 if( indiTargetUpdate( m_indiP_modRadius, target,
ipRecv,
false) < 0)
1044 m_modRadRequested = target;
1052 nr = ipRecv["target"].get<double>();
1053 if(nr > 0) m_modRadRequested = nr;
1057 //do nothing, just means no requested in command.
1072 dx =
ipRecv[
"dC1"].get<
double>();
1079 dy =
ipRecv[
"dC2"].get<
double>();
1085 return offset12(dx, dy);
1096 dx =
ipRecv[
"x"].get<
double>();
1103 dy =
ipRecv[
"y"].get<
double>();
1109 return offsetXY(dx, dy);
1122 std::string outp =
ipRecv[
"value"].getValue();
1128 else if (outp ==
"On")
1141 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1155 double nv =
ipRecv[
"current"].get<
double>();
1163 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1176 m_indiP_C1volts =
ipRecv;
1177 double nv =
ipRecv[
"current"].get<
double>();
1184 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1198 double nv =
ipRecv[
"value"].get<
double>();
1206 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1221 double nv =
ipRecv[
"value"].get<
double>();
1229 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1243 std::string outp =
ipRecv[
"value"].getValue();
1249 else if (outp ==
"On")
1262 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1276 double nv =
ipRecv[
"current"].get<
double>();
1284 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1297 m_indiP_C2volts =
ipRecv;
1298 double nv =
ipRecv[
"current"].get<
double>();
1305 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1320 double nv =
ipRecv[
"value"].get<
double>();
1328 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1342 double nv =
ipRecv[
"value"].get<
double>();
1350 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
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.
stateCodes::stateCodeT state()
Get the current state code.
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.
std::mutex m_indiMutex
Mutex for locking INDI communications.
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)
bool m_powerMgtEnabled
Flag controls whether power mgt is used. Set this in the constructor of a derived app....
double m_C1volts
Voltage p2p of fxn gen channel 1.
virtual int appStartup()
Startup functions.
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2volts)
pcf::IndiProperty m_indiP_C1phse
pcf::IndiProperty m_indiP_C2ofst
std::vector< double > m_calC2Amps
int m_C1outp
Output state of fxn gen channel 1.
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2ofst)
double m_setDVolts
The setting ramp step size [volts].
double m_maxFreq
The maximum modulation frequency settable by this program.
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1volts)
pcf::IndiProperty m_indiP_C1ofst
int m_modState
-1 = unknown, 0 = off, 1 = rest, 2 = midset, 3 = set, 4 = modulating
int modTTM(double newRad, double newFreq)
Begin modulating or modify current modulation parameters.
virtual int appLogic()
Implementation of the FSM for the TTM Modulator.
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1phse)
double m_modRadRequested
The requested modulation radius, in lam/D.
pcf::IndiProperty m_indiP_offset
int restTTM()
Rest the TTM.
pcf::IndiProperty m_indiP_C2outp
double m_C1phse
Phase of fxn gen channel 1.
double m_C2freq
Frequency of fxn gen channel 2.
double m_modFreq
The current modulation frequency, in Hz.
double m_C2volts
Voltage p2p of fxn gen channel 2.
pcf::IndiProperty m_indiP_C2volts
pcf::IndiProperty m_indiP_C2phse
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1freq)
pcf::IndiProperty m_indiP_offset12
double m_maxVolt
The maximum modulation voltage settable by this program.
pcf::IndiProperty m_indiP_modState
int m_C2outp
Output state of fxn gen channel 2.
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1ofst)
double m_modRad
The current modulation radius, in lam/D.
INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modRadius)
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C1outp)
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2freq)
pcf::IndiProperty m_indiP_C2freq
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2phse)
virtual void loadConfig()
load the configuration system results (called by MagAOXApp::setup())
pcf::IndiProperty m_indiP_modFrequency
ttmModulator()
Default c'tor.
double m_setVoltage_1
the set position voltage of Ch. 1.
double m_C1freq
Frequency of fxn gen channel 1.
pcf::IndiProperty m_indiP_C1outp
int calcState()
Calculate the state of the modulator from the fxn gen params.
double m_C1ofst
DC offset of fxn gen channel 1.
int m_modStateRequested
The requested TTM state.
INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modFrequency)
virtual int appShutdown()
Do any needed shutdown tasks. Currently nothing in this app.
double m_modDVolts
The modulation ramp voltage step size [Volts].
pcf::IndiProperty m_indiP_C1freq
double m_C2ofst
DC offset of fxn gen channel 2.
int offsetXY(double dx, double dy)
~ttmModulator() noexcept
D'tor, declared and defined for noexcept.
double m_setVoltage_2
the set position voltage of Ch. 2.
pcf::IndiProperty m_indiP_C1volts
int offset12(double d1, double d2)
std::vector< double > m_calC2Phse
std::vector< double > m_calFreqs
INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_modState)
pcf::IndiProperty m_indiP_modRadius
INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_offset)
double m_C2phse
Phase of fxn gen channel 2.
pcf::IndiProperty m_indiP_FGState
INDI_SETCALLBACK_DECL(ttmModulator, m_indiP_C2outp)
std::vector< double > m_calC1Amps
double m_modDFreq
The modulation ramp frequency step size [Hz].
INDI_NEWCALLBACK_DECL(ttmModulator, m_indiP_offset12)
virtual void setupConfig()
Setup the configuration system (called by MagAOXApp::setup())
double m_modFreqRequested
The requested modulation frequency, in Hz.
#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.
@ OPERATING
The device is operating, other than homing.
@ POWEROFF
The device power is off.
@ CONFIGURING
The application is configuring the device.
@ ERROR
The application has encountered an error, from which it is recovering (with or without intervention)
@ READY
The device is ready for operation, but is not operating.
@ POWERON
The device power is on.
const pcf::IndiProperty & ipRecv
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
void nanoSleep(unsigned long nsec)
int waitValue(const T &var, const T &tgtVal, unsigned long timeout=5000000000, unsigned long pauseWait=1000000)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
INDI_SETCALLBACK_DEFN(MagAOXApp< _useINDI >, m_indiP_powerChannel)(const pcf
constexpr static logPrioT LOG_DEBUG
Used for debugging.
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
constexpr static logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
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.