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;
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();
199 propName <<
"gizmo_" << std::setfill(
'0') << std::setw(4) <<
i;
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>();
246 theReq->requestTime = mx::sys::get_curr_time();
254 theReq->requestTime = mx::sys::get_curr_time();
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()});
278 std::cerr <<
msg.str() << std::endl;
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);
432 pcf::IndiProperty *
gizmoProp =
it->second->property;
450 gizmoProp->setState(pcf::IndiProperty::Ok);
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...
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
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)
pcf::IndiProperty function
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 INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#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.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
const pcf::IndiProperty & ipRecv