7 #ifndef timeSeriesSimulator_hpp
8 #define timeSeriesSimulator_hpp
14 #include "../../libMagAOX/libMagAOX.hpp"
15 #include "../../magaox_git_version.h"
50 const double PI = 3.141592653589793238463;
80 std::vector<pcf::IndiProperty *>
gizmos;
139 double lerp(
double x0,
double y0,
double x1,
double y1,
double xnew);
154 static_cast<void>(_config);
167 pcf::IndiProperty::Switch,
168 pcf::IndiProperty::ReadWrite,
169 pcf::IndiProperty::Idle,
170 pcf::IndiProperty::OneOfMany,
172 function.add(pcf::IndiElement(
"sin"));
173 function[
"sin"].setSwitchState(pcf::IndiElement::SwitchStateType::Off);
174 function.add(pcf::IndiElement(
"cos"));
175 function[
"cos"].setSwitchState(pcf::IndiElement::SwitchStateType::Off);
176 function.add(pcf::IndiElement(
"square"));
177 function[
"square"].setSwitchState(pcf::IndiElement::SwitchStateType::On);
178 function.add(pcf::IndiElement(
"constant"));
179 function[
"constant"].setSwitchState(pcf::IndiElement::SwitchStateType::Off);
182 simsensor.add(pcf::IndiElement(
"value"));
184 simsensor.setState(pcf::IndiProperty::Ok);
189 duty_cycle.add(pcf::IndiElement(
"amplitude"));
194 std::cerr <<
"configuring gizmo #" << i << std::endl;
195 gizmos.push_back(
new pcf::IndiProperty(pcf::IndiProperty::Number));
196 pcf::IndiProperty *prop =
gizmos.back();
198 std::stringstream propName;
199 propName <<
"gizmo_" << std::setfill(
'0') << std::setw(4) << i;
200 prop->setName(propName.str());
201 std::cerr <<
"gizmo prop name is " << propName.str() << std::endl;
202 prop->setPerm(pcf::IndiProperty::ReadWrite);
203 prop->setState(pcf::IndiProperty::Idle);
204 for (
int j = 0; j < 2; j++)
206 std::cerr <<
"configuring gizmo element #" << j << std::endl;
207 auto elemName = j == 0 ?
"current" :
"target";
208 indi::addNumberElement<float>(*prop, elemName, 0, 100, 1,
"%f", std::to_string(i));
209 std::cerr <<
"added " << elemName <<
" to prop" << std::endl;
212 std::cerr <<
"added to gizmos" << std::endl;
235 double currentPos = (*gizmoPtr)[
"current"].get<
double>();
239 std::string ipName = gizmoPtr->getName();
261 std::string ipName =
ipRecv.getName();
262 std::cerr <<
"setProperty cb for gizmos" << std::endl;
263 auto it = gizmos.begin();
264 while (
it != gizmos.end())
266 pcf::IndiProperty *gizmoPtr = *
it;
267 pcf::IndiProperty theGizmo = *gizmoPtr;
268 if (ipName == theGizmo.getName())
270 std::cerr <<
"Adjusting prop " << ipName << std::endl;
271 if (
ipRecv.find(
"target"))
273 double currentPos = theGizmo[
"current"].get<
double>();
276 msg <<
"Setting '" << theGizmo.getName() <<
"' to " <<
targetPos <<
" currently " << currentPos;
277 log<software_notice>({__FILE__, __LINE__,
msg.str()});
280 theGizmo.setState(pcf::IndiProperty::Busy);
281 m_indiDriver->sendSetProperty(theGizmo);
290 (
const pcf::IndiProperty &
ipRecv)
296 duty_cycle[
"period"] =
ipRecv[
"period"].get<
double>();
297 period =
ipRecv[
"period"].get<
double>();
298 std::stringstream
msg;
299 msg <<
"Setting 'period' to " << period;
300 log<software_notice>({__FILE__, __LINE__,
msg.str()});
304 duty_cycle[
"amplitude"] =
ipRecv[
"amplitude"].get<
double>();
305 amplitude =
ipRecv[
"amplitude"].get<
double>();
306 std::stringstream
msg;
307 msg <<
"Setting 'amplitude' to " << amplitude;
308 log<software_notice>({__FILE__, __LINE__,
msg.str()});
311 duty_cycle.setState(pcf::IndiProperty::Ok);
312 m_indiDriver->sendSetProperty(duty_cycle);
318 (
const pcf::IndiProperty &
ipRecv)
320 std::string currentFunctionName;
323 case SimFunction::sin:
324 currentFunctionName =
"sin";
326 case SimFunction::cos:
327 currentFunctionName =
"sin";
329 case SimFunction::square:
330 currentFunctionName =
"square";
332 case SimFunction::constant:
333 currentFunctionName =
"constant";
340 for (
auto fname : SimFunctionNames)
348 if (
ipRecv[fname].getSwitchState() == pcf::IndiElement::SwitchStateType::On)
350 std::cerr <<
"Got fname " << fname << std::endl;
351 currentFunctionName = fname;
355 if (currentFunctionName ==
"sin")
357 myFunction = SimFunction::sin;
358 log<software_notice>({__FILE__, __LINE__,
"Switching sine 'On'"});
360 else if (currentFunctionName ==
"cos")
362 myFunction = SimFunction::cos;
363 log<software_notice>({__FILE__, __LINE__,
"Switching cosine 'On'"});
365 else if (currentFunctionName ==
"square")
367 myFunction = SimFunction::square;
368 log<software_notice>({__FILE__, __LINE__,
"Switching square wave 'On'"});
370 else if (currentFunctionName ==
"constant")
372 myFunction = SimFunction::constant;
373 log<software_notice>({__FILE__, __LINE__,
"Switching constant 'On'"});
375 for (
auto fname : SimFunctionNames)
377 if (fname == currentFunctionName)
379 function[fname] = pcf::IndiElement::SwitchStateType::On;
383 function[fname] = pcf::IndiElement::SwitchStateType::Off;
387 function.setState(pcf::IndiProperty::Ok);
388 m_indiDriver->sendSetProperty(
function);
398 double elapsedSeconds = mx::sys::get_curr_time() -
startTimeSec;
424 return y0 + (xnew - x0) * ((y1 - y0) / (x1 - x0));
432 pcf::IndiProperty *gizmoProp =
it->second->property;
434 double elapsedSeconds = mx::sys::get_curr_time() - theMotionRequest->
requestTime;
448 currentPos = theMotionRequest->
targetPos;
450 gizmoProp->setState(pcf::IndiProperty::Ok);
451 std::cerr << gizmoProp->getName() <<
" moved to " << currentPos << std::endl;
453 (*gizmoProp)[
"current"] = currentPos;
454 (*gizmoProp)[
"target"] = theMotionRequest->
targetPos;
The base-class for MagAO-X applications.
std::string m_configName
The name of the configuration file (minus .conf).
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.
unsigned long m_loopPause
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
pcf::IndiProperty * property
INDI_NEWCALLBACK_DECL(timeSeriesSimulator, gizmos)
static const uintmax_t nanos_in_milli
pcf::IndiProperty gizmo_presets
INDI_NEWCALLBACK_DECL(timeSeriesSimulator, duty_cycle)
void requestGizmoTarget(pcf::IndiProperty *gizmoPtr, double targetPos)
INDI_NEWCALLBACK_DECL(timeSeriesSimulator, gizmo_zero)
double lerp(double x0, double y0, double x1, double y1, double xnew)
virtual int appShutdown()
Shutdown the app.
INDI_NEWCALLBACK_DECL(timeSeriesSimulator, gizmo_presets)
pcf::IndiProperty duty_cycle
pcf::IndiProperty gizmo_zero
~timeSeriesSimulator() noexcept
D'tor, declared and defined for noexcept.
std::vector< std::string > SimFunctionNames
timeSeriesSimulator()
Default c'tor.
pcf::IndiProperty simsensor
virtual int appStartup()
Startup function.
std::vector< pcf::IndiProperty * > gizmos
virtual int appLogic()
Implementation of the FSM for timeSeriesSimulator.
virtual void loadConfig()
INDI_NEWCALLBACK_DECL(timeSeriesSimulator, function)
std::unordered_map< std::string, MotionRequest * > gizmosInMotion
virtual void setupConfig()
#define REG_INDI_NEWPROP_NOCB(prop, propName, type)
Register a NEW INDI property with the class, with no callback.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
#define REG_INDI_NEWPROP(prop, propName, type)
Register a NEW INDI property with the class, using the standard callback name.
@ READY
The device is ready for operation, but is not operating.
INDI_VALIDATE_CALLBACK_PROPS(function, ipRecv)
const pcf::IndiProperty & ipRecv
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf