3 #ifndef ttmModulator_hpp
4 #define ttmModulator_hpp
7 #include "../../libMagAOX/libMagAOX.hpp"
8 #include "../../magaox_git_version.h"
11 #define MODSTATE_UNKNOWN (-1)
12 #define MODSTATE_OFF (0)
13 #define MODSTATE_REST (1)
14 #define MODSTATE_MIDSET (2)
15 #define MODSTATE_SET (3)
16 #define MODSTATE_MODULATING (4)
93 std::vector<double>
m_calFreqs = { 100, 250, 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, 2500, 2750, 3000};
94 std::vector<double>
m_calC1Amps = {0.310, 0.317, 0.327, 0.327, 0.333, 0.333, 0.343, 0.350, 0.373, 0.39, 0.405, 0.425, 0.435};
95 std::vector<double>
m_calC2Amps = {0.313, 0.317, 0.327, 0.340, 0.357, 0.363, 0.380, 0.407, 0.426667, 0.45, 0.475, 0.490, 0.510};
96 std::vector<double>
m_calC2Phse = { 74, 74, 74, 74, 74, 71, 71, 68, 68, 68, 68, 68, 68};
162 int modTTM(
double newRad,
231 config.add(
"limits.maxfreq",
"",
"limits.maxfreq", argType::Required,
"limits",
"maxfreq",
false,
"real",
"The maximum frequency [Hz] which can be set through this program.");
232 config.add(
"limits.maxamp",
"",
"limits.maxamp", argType::Required,
"limits",
"maxamp",
false,
"real",
"The maximum amplitude [lam/D] which can be set throught this program.");
234 config.add(
"cal.voltsperld1",
"",
"cal.voltsperld1", argType::Required,
"cal",
"voltsperld1",
false,
"real",
"The voltage per lam/D for channel 1.");
235 config.add(
"cal.voltsperld2",
"",
"cal.voltsperld2", argType::Required,
"cal",
"voltsperld2",
false,
"real",
"The voltage per lam/D for channel 2.");
236 config.add(
"cal.phase",
"",
"cal.phase", argType::Required,
"cal",
"phase",
false,
"real",
"The axis phase offset, which is applied to channel 2.");
238 config.add(
"cal.setv1",
"",
"cal.setv1", argType::Required,
"cal",
"setv1",
false,
"real",
"The set position voltage of chaannel 1.");
239 config.add(
"cal.setv2",
"",
"cal.setv2", argType::Required,
"cal",
"setv2",
false,
"real",
"The set position voltage of chaannel 2.");
241 config.add(
"cal.setDvolts",
"",
"cal.setDvolts", argType::Required,
"cal",
"setDvolts",
false,
"real",
"The setting ramp step size [Volts]");
243 config.add(
"cal.modDfreq",
"",
"cal.modDfreq", argType::Required,
"cal",
"modDfreq",
false,
"real",
"The modulation ramp frequency step size [Hz]");
244 config.add(
"cal.modDvolts",
"",
"cal.modDvolts", argType::Required,
"cal",
"modDvolts",
false,
"real",
"The modulation ramp voltage step size [Volts]");
246 config.add(
"cal.rotAngle",
"",
"cal.rotAngle", argType::Required,
"cal",
"rotAngle",
false,
"real",
"The offset rotation matrix angle in degrees.");
247 config.add(
"cal.rotParity",
"",
"cal.rotParity", argType::Required,
"cal",
"rotParity",
false,
"real",
"The offset rotation matrix parity, +1 or -1.");
330 log<software_critical>({__FILE__,__LINE__});
385 if(newRad <= 0.1 || newFreq <= 1)
500 std::this_thread::sleep_for( std::chrono::duration<unsigned long, std::nano>(nsec));
506 unsigned long timeout = 5000000000,
507 unsigned long pauseWait = 1000000
510 if(var == tgtVal)
return 0;
512 struct timespec ts0, ts1;
513 clock_gettime(CLOCK_REALTIME, &ts0);
517 while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
519 if(var == tgtVal)
return 0;
523 clock_gettime(CLOCK_REALTIME, &ts1);
526 if(var == tgtVal)
return 0;
528 std::cerr <<
"Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) <<
"\n";
538 unsigned long timeout = 5000000000,
539 unsigned long pauseWait = 1000000
542 if(fabs(tgtVal - var) <= tol)
return 0;
544 struct timespec ts0, ts1;
545 clock_gettime(CLOCK_REALTIME, &ts0);
548 while( (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) < timeout)
550 if(fabs(tgtVal - var) <= tol)
return 0;
554 clock_gettime(CLOCK_REALTIME, &ts1);
557 if(fabs(tgtVal - var) <= tol)
return 0;
559 std::cerr <<
"Timeout: " << (ts1.tv_sec - ts0.tv_sec)*1e9 + (ts1.tv_nsec - ts0.tv_nsec) <<
"\n";
589 if(
waitValue(
m_C1freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
590 if(
waitValue(
m_C2freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
591 if(
waitValue(
m_C1volts, 0.002, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
592 if(
waitValue(
m_C2volts, 0.002, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
593 if(
waitValue(
m_C1phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
594 if(
waitValue(
m_C2phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
595 if(
waitValue(
m_C1ofst, 0.001, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
596 if(
waitValue(
m_C2ofst, 0.001, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
597 if(
waitValue(
m_C1outp, 0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
598 if(
waitValue(
m_C2outp, 0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
634 if(
waitValue(
m_C1freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
635 if(
waitValue(
m_C2freq, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
636 if(
waitValue(
m_C1volts, 0.002, 1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
637 if(
waitValue(
m_C2volts, 0.002,1e-6) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
638 if(
waitValue(
m_C1phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
639 if(
waitValue(
m_C2phse, 0.0) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
667 if(
waitValue(
m_C1outp, 1) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
668 if(
waitValue(
m_C2outp, 1) < 0)
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
677 log<text_log>(
"Ramping with " + std::to_string(N) +
" steps. [" + std::to_string(N1) +
" " + std::to_string(N2) +
"]",
logPrio::LOG_DEBUG);
679 for(
size_t i=1; i< N ; ++i)
683 if(nv < 0 || nv > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
687 if(
waitValue(
m_C1ofst, nv, 1e-10) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
693 if(
waitValue(
m_C2ofst, nv, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
698 for(
size_t j=N; j< N1;++j)
702 if(nv < 0 || nv > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
706 if(
waitValue(
m_C1ofst, nv, 1e-6) < 0 )
return log<software_error, -1>({__FILE__,__LINE__,
"fxngen timeout"});
711 for(
size_t j=N; j< N2;++j)
715 if(nv < 0 || nv > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
719 if(
waitValue(
m_C2ofst, nv, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
726 if( m_setVoltage_1 < 0 || m_setVoltage_1 > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
736 if( m_setVoltage_2 < 0 || m_setVoltage_2 > 10)
return log<
software_error,-1>({__FILE__, __LINE__,
"Bad voltage calculated. Refusing."});
762 if(newRad < 0 || newFreq < 0)
return 0;
774 if(
calcState() < 0)
return log<software_error, -1>({__FILE__,__LINE__});
781 if(
setTTM() < 0 )
return log<software_error, -1>({__FILE__, __LINE__});
783 if(
calcState() < 0 )
return log<software_error, -1>({__FILE__,__LINE__});
791 log<text_log>(
"Requested frequency " + std::to_string(newFreq) +
" Hz exceeds limit (" + std::to_string(
m_maxFreq) +
" Hz). Limiting.",
logPrio::LOG_WARNING);
796 double voltageC1, voltageC2;
802 double terpC1Amp = 0;
803 double terpC2Amp = 0;
804 double terpC2Phse = 0;
836 log<text_log>(
"Requested ch-1 voltge " + std::to_string(voltageC1) +
" V exceeds limit (" + std::to_string(
m_maxVolt) +
" V). Limiting.",
logPrio::LOG_WARNING);
842 log<text_log>(
"Requested ch-2 voltge " + std::to_string(voltageC2) +
" V exceeds limit (" + std::to_string(
m_maxVolt) +
" V). Limiting.",
logPrio::LOG_WARNING);
857 if(
waitValue(
m_C2phse, terpC2Phse, 1e-4) < 0 )
return log<software_error, -1>({__FILE__,__LINE__,
"fxngen timeout"});
860 double nextFreq = 100.0;
861 if(nextFreq > newFreq) nextFreq = newFreq;
868 if(
waitValue(
m_C1freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
869 if(
waitValue(
m_C2freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
872 double nextVolts1 = 0.1;
873 if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
875 double nextVolts2 = 0.1;
876 if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
884 if(
waitValue(
m_C1volts, nextVolts1, 1e-6) < 0 ) log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
885 if(
waitValue(
m_C2volts, nextVolts2, 1e-6) < 0 ) log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
891 if(nextFreq > newFreq) nextFreq = newFreq;
894 while( fabs(currFreq - newFreq) > 1e-4)
900 if(
waitValue(
m_C1freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
901 if(
waitValue(
m_C2freq, nextFreq, 1e-6) < 0 )
return log<software_error,-1>({__FILE__,__LINE__,
"fxngen timeout"});
907 if(nextFreq > newFreq) nextFreq = newFreq;
915 if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
918 if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
920 while( fabs(currVolts1 - voltageC1) > 1e-4 || fabs(currVolts2 - voltageC2) > 1e-4)
939 if(nextVolts1 > voltageC1) nextVolts1 = voltageC1;
943 if(nextVolts2 > voltageC2) nextVolts2 = voltageC2;
950 else return log<
software_error,-1>({__FILE__,__LINE__,
"TTM not set but should be by now."});
977 double rdx = dx * cs - dy * ss;
993 if( indiTargetUpdate( m_indiP_modState, target,
ipRecv,
false) < 0)
998 m_modStateRequested = target;
1023 if( indiTargetUpdate( m_indiP_modFrequency, target,
ipRecv,
false) < 0)
1030 m_modFreqRequested = target;
1037 nf = ipRecv["target"].get<double>();
1038 if(nf > 0) m_modFreqRequested = nf;
1042 //do nothing, just means no requested in command.
1055 if( indiTargetUpdate( m_indiP_modRadius, target,
ipRecv,
false) < 0)
1062 m_modRadRequested = target;
1070 nr = ipRecv["target"].get<double>();
1071 if(nr > 0) m_modRadRequested = nr;
1075 //do nothing, just means no requested in command.
1090 dx =
ipRecv[
"dC1"].get<
double>();
1097 dy =
ipRecv[
"dC2"].get<
double>();
1103 return offset12(dx, dy);
1114 dx =
ipRecv[
"x"].get<
double>();
1121 dy =
ipRecv[
"y"].get<
double>();
1127 return offsetXY(dx, dy);
1140 std::string outp =
ipRecv[
"value"].getValue();
1146 else if (outp ==
"On")
1159 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1173 double nv =
ipRecv[
"current"].get<
double>();
1181 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1194 m_indiP_C1volts =
ipRecv;
1195 double nv =
ipRecv[
"current"].get<
double>();
1202 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1216 double nv =
ipRecv[
"value"].get<
double>();
1224 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1239 double nv =
ipRecv[
"value"].get<
double>();
1247 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1261 std::string outp =
ipRecv[
"value"].getValue();
1267 else if (outp ==
"On")
1280 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1294 double nv =
ipRecv[
"current"].get<
double>();
1302 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1315 m_indiP_C2volts =
ipRecv;
1316 double nv =
ipRecv[
"current"].get<
double>();
1323 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1338 double nv =
ipRecv[
"value"].get<
double>();
1346 log<software_error>({__FILE__, __LINE__,
"exception from libcommon"});
1360 double nv =
ipRecv[
"value"].get<
double>();
1368 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)
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.
@ NOTHOMED
The device has not been homed.
@ 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.
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
void nanoSleep(unsigned long nsec)
const pcf::IndiProperty & ipRecv
int waitValue(const T &var, const T &tgtVal, unsigned long timeout=5000000000, unsigned long pauseWait=1000000)
INDI_SETCALLBACK_DEFN(adcTracker, m_indiP_teldata)(const pcf
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
std::unique_lock< std::mutex > lock(m_indiMutex)
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.
#define MODSTATE_MODULATING