15 namespace ba = boost::asio;
16 namespace bs = boost::system;
17 namespace dummy = ba::placeholders;
53 PostMessage(
string(
"*IDN?\nvolt?\nmeas:volt?\nmeas:curr?\ncurr?\n"));
55 fTimeout.expires_from_now(boost::posix_time::seconds(fInterval));
64 if (error && error!=ba::error::basic_errors::operation_aborted)
67 str <<
"Status request timeout of " << URL() <<
": " << error.message() <<
" (" << error <<
")";
86 if (fTimeout.expires_at() > ba::deadline_timer::traits_type::now())
95 if (error && error!=ba::error::basic_errors::operation_aborted)
98 str <<
"Power cycle timeout of " << URL() <<
": " << error.message() <<
" (" << error <<
")";
117 if (fTimeout.expires_at() > ba::deadline_timer::traits_type::now())
126 ba::async_read_until(*
this, fBuffer,
"\n",
128 dummy::error, dummy::bytes_transferred, line+1));
135 if (bytes_received==0 || err)
137 if (err==ba::error::eof)
138 Warn(
"Connection closed by remote host (FTM).");
142 if (err && err!=ba::error::eof &&
143 err!=ba::error::basic_errors::not_connected &&
144 err!=ba::error::basic_errors::operation_aborted)
147 str <<
"Reading from " << URL() <<
": " << err.message() <<
" (" << err <<
")";
150 PostClose(err!=ba::error::basic_errors::operation_aborted);
157 Out() <<
kBold <<
"Received (" << bytes_received <<
", " << fBuffer.size() <<
" bytes):" << endl;
158 Out() <<
"-----\n" << string(ba::buffer_cast<const char*>(fBuffer.data()), bytes_received) <<
"-----\n";
161 istream is(&fBuffer);
164 getline(is, str,
'\n');
170 case 1: Out() <<
"ID: " << str << endl;
break;
179 catch (
const exception &e)
181 Error(
"String conversion failed for '"+str+
" ("+e.what()+
")");
198 fLastReceived =
Time();
211 fBuffer.prepare(1000);
220 fIsVerbose(true), fDebugRx(false), fTimeout(ioservice), fTimeoutPowerCycle(ioservice)
245 if (fLastCommand+boost::posix_time::seconds(59)>
Time())
247 Error(
"Last power command within the last 59 seconds... ignored.");
251 PostMessage(
"outp "+
string(on?
"on":
"off")+
"\n*IDN?\nvolt?\nmeas:volt?\nmeas:curr?\ncurr?\n");
252 fLastCommand =
Time();
255 fTimeoutPowerCycle.cancel();
262 if (!SetPower(
false))
265 fTimeoutPowerCycle.expires_from_now(boost::posix_time::seconds(seconds));
267 this, dummy::error));
275 if (fLastReceived+boost::posix_time::seconds(fInterval*2)<
Time())
314 fDim(
"AGILENT_CONTROL_"+fMode+
"/DATA",
"F:1;F:1;F:1;F:1",
315 "|U_nom[V]: Nominal output voltage" 316 "|U_mes[V]: Measured output voltage" 317 "|I_max[A]: Current limit" 318 "|I_mes[A]: Measured current")
326 template <
class T,
class S>
335 fAgilent.PostClose(
false);
343 return T::GetCurrentState();
349 fAgilent.PostClose(
false);
353 ba::io_service::poll();
359 fAgilent.PostClose(
true);
361 return T::GetCurrentState();
366 return fAgilent.GetState();
375 msg << name <<
" - Received event has " << has <<
" bytes, but expected " << size <<
".";
382 if (!CheckEventSize(evt.
GetSize(),
"SetVerbosity", 1))
383 return T::kSM_FatalError;
385 fAgilent.SetVerbose(evt.
GetBool());
387 return T::GetCurrentState();
392 if (!CheckEventSize(evt.
GetSize(),
"SetDebugRx", 1))
393 return T::kSM_FatalError;
395 fAgilent.SetDebugRx(evt.
GetBool());
397 return T::GetCurrentState();
402 if (!CheckEventSize(evt.
GetSize(),
"SetPower", 1))
403 return T::kSM_FatalError;
405 fAgilent.SetPower(evt.
GetBool());
407 return T::GetCurrentState();
412 if (!CheckEventSize(evt.
GetSize(),
"PowerCyle", 2))
413 return T::kSM_FatalError;
417 T::Warn(
"Power cycle delays of less than 60s not allowed.");
418 return T::GetCurrentState();
421 fAgilent.PowerCycle(evt.
GetShort());
423 return T::GetCurrentState();
429 StateMachineAsio<T>(out,
"AGILENT_CONTROL_"+S::fMode), fAgilent(*this, *this)
433 "Agilent not connected via ethernet.");
435 "Ethernet connection to Agilent established, but not data received yet.");
438 "The measured output voltage is lower than 0.1V");
440 "The measured output voltage is higher than 0.1V, but lower than the command voltage");
442 "The measured output voltage is higher than 0.1V and comparable to the command voltage");
444 "The measured output voltage is higher than the command voltage!");
447 T::AddEvent(
"SET_VERBOSE",
"B:1")
449 (
"set verbosity state" 450 "|verbosity[bool]:disable or enable verbosity for received data (yes/no)");
452 T::AddEvent(
"SET_DEBUG_RX",
"B:1")
455 "|debug[bool]:disable or enable verbosity for received raw data (yes/no)");
457 T::AddEvent(
"SET_POWER",
"B:1")
459 (
"Enable or disable power output" 460 "|output[bool]:set power output to 'on' or 'off'");
462 T::AddEvent(
"POWER_CYCLE",
"S:1")
464 (
"Power cycle the power output" 465 "|delay[short]:Defines the delay between switching off and on.");
471 (
"disconnect from ethernet");
475 (
"(Re)connect ethernet connection to Agilent, a new address can be given" 476 "|[host][string]:new ethernet address in the form <host:port>");
478 fAgilent.StartConnect();
483 fAgilent.SetEndpoint(url);
488 fAgilent.SetVerbose(!conf.
Get<
bool>(
"quiet"));
489 fAgilent.SetDebugRx(conf.
Get<
bool>(
"debug-rx"));
490 fAgilent.SetInterval(conf.
Get<uint16_t>(
"interval"));
492 SetEndpoint(conf.
Get<
string>(
"addr.", S::fMode));
495 for (
auto it=opts.begin(); it!=opts.end(); it++)
496 conf.
Get<
string>(*it);
506 template<
class T,
class S,
class R>
509 return Main::execute<T, StateMachineAgilent<S, R>>(conf);
514 po::options_description control(
"agilent_ctrl control options");
515 control.add_options()
516 (
"no-dim",
po_bool(),
"Disable dim services")
517 (
"mode,m", var<string>()->required(),
"Mode (e.g. 24V, 50V, 80V)")
518 (
"addr.*", var<string>(),
"Network address of Agilent specified by mode")
519 (
"debug-rx",
po_bool(
false),
"Enable raw debug output wehen receiving data")
520 (
"interval", var<uint16_t>(15),
"Interval in seconds in which the Agilent status is requested")
521 (
"quiet,q",
po_bool(
true),
"Disable printing contents of all received messages (except dynamic data) in clear text.")
524 po::positional_options_description p;
543 "The agilentctrl controls the FACT Agilent power supplies.\n\n" 545 "The default is that the program is started without user intercation. " 546 "All actions are supposed to arrive as DimCommands. Using the -c " 547 "option, a local shell can be initialized. With h or help a short " 548 "help message about the usuage can be brought to the screen.\n" 550 "Usage: agilentctrl [-c type] [OPTIONS] mode\n" 551 " or: agilentctrl [OPTIONS] mode\n";
557 Main::PrintHelp<StateMachineAgilent<StateMachine, ConnectionAgilent>>();
560 int main(
int argc,
const char* argv[])
575 if (!conf.
Has(
"console"))
577 if (conf.
Get<
bool>(
"no-dim"))
578 return RunShell<LocalStream, StateMachine, ConnectionAgilent>(conf);
580 return RunShell<LocalStream, StateMachineDim, ConnectionDimAgilent>(conf);
583 if (conf.
Get<
bool>(
"no-dim"))
585 if (conf.
Get<
int>(
"console")==0)
586 return RunShell<LocalShell, StateMachine, ConnectionAgilent>(conf);
588 return RunShell<LocalConsole, StateMachine, ConnectionAgilent>(conf);
592 if (conf.
Get<
int>(
"console")==0)
593 return RunShell<LocalShell, StateMachineDim, ConnectionDimAgilent>(conf);
595 return RunShell<LocalConsole, StateMachineDim, ConnectionDimAgilent>(conf);
void ConnectionEstablished()
void HandleStatusTimer(const bs::error_code &error)
A general base-class describing events issues in a state machine.
void SetupConfiguration(Configuration &conf)
ConnectionAgilent(ba::io_service &ioservice, MessageImp &imp)
The base implementation of a distributed messaging system.
Adds some functionality to boost::posix_time::ptime for our needs.
void SetPrintUsage(const std::function< void(void)> &func)
T Get(const std::string &var)
boost::asio::deadline_timer fTimeoutPowerCycle
int Reconnect(const EventImp &evt)
boost::asio::streambuf fBuffer
void SetInterval(uint16_t i)
void SetEndpoint(const string &url)
std::string GetString() const
void SetArgumentPositions(const po::positional_options_description &desc)
ConnectionDimAgilent(ba::io_service &ioservice, MessageImp &imp)
int EvalOptions(Configuration &conf)
virtual void UpdateDim(const Data &)
void HandlePowerCycle(const bs::error_code &error)
bool Has(const std::string &var)
bool CheckEventSize(size_t has, const char *name, size_t size)
void AddOptions(const po::options_description &opt, bool visible=true)
int PowerCycle(const EventImp &evt)
int SetPower(const EventImp &evt)
int SetVerbosity(const EventImp &evt)
void StartRead(int line=0)
boost::asio::deadline_timer fTimeout
Commandline parsing, resource file parsing and database access.
void UpdateDim(const Data &data)
void SetupConfiguration(Configuration &conf)
const std::map< std::string, std::string > & GetWildcardOptions() const
po::typed_value< bool > * po_bool(bool def=false)
int RunShell(Configuration &conf)
Maintains an ansynchronous TCP/IP client connection.
bool DoParse(int argc, const char **argv, const std::function< void()> &func=std::function< void()>())
int main(int argc, const char *argv[])
StateMachineAgilent(ostream &out=cout)
int SetDebugRx(const EventImp &evt)
void PowerCycle(uint16_t seconds)
void HandleReceivedData(const bs::error_code &err, size_t bytes_received, int line)
virtual size_t GetSize() const