AAO DRAMA/DRAMA2 C++ Interface
monitor2.cpp
/* M O N I T O R 2
* Module name:
MONITOR2
* Function:
A simple DRAMA program demonstrating parameter monitors.
* Description:
Finds the program TESTTASK and monitors parameters within it.
This example uses a monitor based on the drama::thread::MonitorByType
class, which provides for methods to be invoked when events on
parameters of given types are received.
* Language:
C++
* Copyright (c) Australian Astronomical Observatory, 2014.
Not to be used for commercial purposes without permission.
No warranty of any form unless subject to a specific agreement.
* Support: Tony Farrell, AAO
* History:
08-May-2014 - TJF - Original version
* @(#) $Id: ACMM:Drama2/examples/monitor2.cpp,v 1.45+ 22-Feb-2016 14:09:53+11 tjf $
*/
static const char *rcsId="@(#) $Id: ACMM:Drama2/examples/monitor2.cpp,v 1.45+ 22-Feb-2016 14:09:53+11 tjf $";
static void *use_rcsId = (0 ? (void *)(&use_rcsId) : (void *) &rcsId);
#include "drama.hh"
#include "drama/path.hh"
#include <iostream>
/*
* Create a class used to implement our monitors. In particular, methods
* we declare here will be invoked when parameter values change. This
* implementation is a sub-class of MonitorByType.
*/
class MyMonitor : public drama::thread::MonitorByType {
// Use the MonitorByType constructors.
using drama::thread::MonitorByType::MonitorByType;
/*
* Each of these override methods in MonitorByType.
* Mark them as "override" to ensure we have the signature correct.
*/
// Invoked when a signed integer parameter is changed.
void ParamChanged(const std::string &name, long value) override;
// Invoked when a string parameter is changed, also for any of
// int/unsigned int/real which we have not overriden, so in this case,
// real/unsigned int cases as well.
void ParamChanged(const std::string &name, const std::string & value) override;
// Invoked when some complex parameter (array of items or structured item)
// is changed.
void ParamChanged(const std::string &name, const drama::sds::IdPtr &value) override;
};
/*
* MyMonitor method implementations.
*
* Invoked when an integer parameter being monitored changed.
*/
void MyMonitor::ParamChanged(const std::string &name, long value)
{
std::cerr << "*** MyMonitor:ParamChanged (int) \""
<< name
<< "\" to \""
<< value
<< "\""
<< std::endl;
}
/*
* Invoked when a string parameter being monitored changed.
* Also invoked for any of int/unsigned/real which we don't explicitly
* support.
*/
void MyMonitor::ParamChanged(
const std::string &name,
const std::string & value)
{
std::cerr << "*** MyMonitor:ParamChanged (string) \""
<< name
<< "\" to \""
<< value
<< "\""
<< std::endl;
}
/*
* Invoked when a complex parameter changes.
*/
void MyMonitor::ParamChanged(
const std::string &name,
const drama::sds::IdPtr &value)
{
std::cerr << "*** MyMonitor:ParamChanged (complex) \""
<< name
<< "\""
<< std::endl;
value->List(std::cerr);
}
/*
* This function is invoked in a thread, to initiate and run the monitor.
*/
void MonitorThread(drama::Task *task)
{
try
{
/*
* We are not part of a DRAMA action, so we need a UFACE handler to
* deal with the messages.
*/
drama::thread::TUface ufaceHandler(task->TaskPtr());
/*
* Set up access to the testtask program.
*/
drama::Path testtask(task->TaskPtr(), "TESTTASK@mynode", "", "./testtask");
/*
* Get path to TESTTASK (loading if required and possible).
*/
testtask.GetPath(&ufaceHandler);
/*
* Create a monitor object, specifying a list of parameters in
* the TESTTASK task to be monitored.
*/
MyMonitor myMonitor(task->TaskPtr(), { "PARAM1" , "PARAM2", "PARAM3",
"PARAM4" , "STRUCT_PARAM" });
try
{
ufaceHandler.MessageUser("About to run monitor");
myMonitor.Run(&testtask, &ufaceHandler);
}
catch (drama::Exception &e)
{
/*
* If the above threw a DRAMA Run loop exit error, then
* this task was shutdown whilst we were running the monitor.
* In this case, we are not that worried and allow the thread
* to close down without error messages. But for any other
* reason, we re-throw the exception.
*/
if (e.dramaStatus() != DRAMA2__RUN_LOOP_EXIT)
throw e;
}
}
catch (...)
{
/*
* Ensure the DRAMA loop exits and re-throw the exception. The
* exception will be reported by the main program.
*/
throw;
}
/*
* If the thread completes (through it should not unless an exception occurs)
* signal DRAMA to exit.
*/
}
class Monitor : public drama::Task {
private:
std::future<void> _ufaceThreadFuture;
public:
Monitor() : drama::Task("MONITOR2") {
/*
* Our only action is the EXIT action.
*/
/*
* By constructing one of these, we block all signals whilst
* the thread is being created, to avoid race conditions. The
* thread will block signals itself once it starts running. The
* destructor restores the signal mask.
*/
drama::thread::SignalBlocker threadSignalBlocker;
/*
* Start the thread which will do the monitors. This returns a future
* we can use to wait for the thread to exit.
*/
_ufaceThreadFuture = std::async(std::launch::async, MonitorThread, this);
}
/*
* This method will wait for a thread to exit and will throw if the
* monitor thread threw an exception.
*/
void WaitThreadExit(unsigned seconds) {
if (_ufaceThreadFuture.wait_for(std::chrono::seconds(seconds)) !=
std::future_status::ready)
{
DramaTHROW(DRAMA2__THREAD_TIMEOUT,
"UFACE Thread did not complete");
}
_ufaceThreadFuture.get(); // Will throw if thread did.
}
~Monitor() {
}
};
int main()
{
try
{
/*
* Make this program a DRAMA task named MONITOR.
*/
Monitor task;
/*
* Process DRAMA messages.
*/
task.RunDrama();
/*
* Wait for the threads to exit (3 seconds only, timeout causes exception).
*/
task.WaitThreadExit(3);
}
/*
* Deal with any exceptions.
*/
catch (drama::Exception &e)
{
e.Print();
exit (e.statusAsSysExitCode());
}
catch (std::exception &e)
{
std::cerr << "std::exception thrown by task.RunDrama"
<< e.what()
<< std::endl;
exit(1);
}
return 0;
}

Click here for the DRAMA home page and here for the AAO home page.

For more information, contact tjf@aao.gov.au 

Generated on Mon Feb 22 2016 15:57:52 for AAO DRAMA/DRAMA2 C++ Interface by doxygen 1.8.10