parent
d82e77382d
commit
2349abd965
|
@ -0,0 +1,75 @@
|
||||||
|
LOCATION=authoring
|
||||||
|
#
|
||||||
|
# Add other locations and move target differences into the macros as needed
|
||||||
|
#
|
||||||
|
CC=g++
|
||||||
|
Cc=gcc
|
||||||
|
|
||||||
|
BOSTLIB=-L/usr/lib/boost
|
||||||
|
BOSINCL=-L/usr/include/boost
|
||||||
|
LOG4LIB=-L/usr/lib
|
||||||
|
|
||||||
|
SLIBS= -L/usr/lib $(BOSTLIB) $(LOG4LIB) -l boost_system -l boost_thread -l log4cpp
|
||||||
|
|
||||||
|
ifeq ($(LOCATION),authoring)
|
||||||
|
SINCL= -I include -I /usr/include/log4cpp $(BOSINCL)
|
||||||
|
CFLAGS= -DCURRENT_DEBUG=1000
|
||||||
|
endif
|
||||||
|
|
||||||
|
CLIBS= -L$(USRLIB)
|
||||||
|
|
||||||
|
CLFLAGS= -Wall -Wundef -Wpointer-arith -Wshadow \
|
||||||
|
-Wcast-align -Winline -Wmissing-declarations -Wredundant-decls \
|
||||||
|
-Wmissing-prototypes -Wnested-externs \
|
||||||
|
-Wstrict-prototypes -Waggregate-return -Wno-implicit
|
||||||
|
|
||||||
|
ACOBJS= build/cliever.o build/cdLogger.o build/clientDaemonConfig.o build/clientDaemon.o
|
||||||
|
|
||||||
|
# --- targets
|
||||||
|
#
|
||||||
|
|
||||||
|
ifeq ($(LOCATION),authoring)
|
||||||
|
all: cliever
|
||||||
|
endif
|
||||||
|
|
||||||
|
cliever: build/cliever
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(Cc) -c $(CLFLAGS) -o $<
|
||||||
|
|
||||||
|
build/cdLogger.o: client/cdLogger.cpp include/cdLogger.h
|
||||||
|
$(CC) $(CFLAGS) client/cdLogger.cpp -c -o build/cdLogger.o $(SINCL)
|
||||||
|
|
||||||
|
build/cliever.o: client/ausreg-cd.cpp include/*.h
|
||||||
|
$(CC) $(CFLAGS) client/ausreg-cd.cpp -c -o build/cliever.o $(SINCL)
|
||||||
|
|
||||||
|
build/clientDaemonConfig.o: client/clientDaemonConfig.cpp include/*.h
|
||||||
|
$(CC) $(CFLAGS) client/clientDaemonConfig.cpp -c -o build/clientDaemonConfig.o $(SINCL)
|
||||||
|
|
||||||
|
build/masterDaemon.o: client/clientDaemon.cpp include/*.h
|
||||||
|
$(CC) $(CFLAGS) client/clientDaemon.cpp -c -o build/clientDaemon.o $(SINCL)
|
||||||
|
|
||||||
|
build/ausreg-cd: $(ACOBJS)
|
||||||
|
$(CC) $(CFLAGS) -o build/ausreg-cd $(SINCL) $(LIBS) $(ACOBJS) $(SLIBS)
|
||||||
|
|
||||||
|
doxygen/index.html: etc/doxygen.config
|
||||||
|
doxygen etc/doxygen.config
|
||||||
|
|
||||||
|
# --- rebuild on copy to a new host
|
||||||
|
distclean:
|
||||||
|
clrbak
|
||||||
|
rm -rf build
|
||||||
|
rm -rf doxygen
|
||||||
|
mkdir doxygen
|
||||||
|
mkdir build
|
||||||
|
touch etc/doxygen.config
|
||||||
|
|
||||||
|
clean:
|
||||||
|
clrbak
|
||||||
|
find ./build -name "*.o" -print | perl -ne "print;chop;unlink"
|
||||||
|
find ./build -name "*.rpo" -print | perl -ne "print;chop;unlink"
|
||||||
|
rm build/drde-cliever
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*! \brief mdclient
|
||||||
|
* Master Daemon standalone client
|
||||||
|
*
|
||||||
|
* This MD sample client driver has the same functionality as the
|
||||||
|
* xmlrpc-c xmlrpc command line utility program but additionally
|
||||||
|
* runs a test suite using the test harness reused from the
|
||||||
|
* xmlrpc-c cpp test.
|
||||||
|
*
|
||||||
|
* Client interfaces are automatically generated when the server
|
||||||
|
* is compiled from the current server API so this program should
|
||||||
|
* be run to verify and currently the coding of test cases is
|
||||||
|
* entirely manual.
|
||||||
|
*
|
||||||
|
* \todo DLL packaging supplying the client functionality used here.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MDCLIENTMAIN
|
||||||
|
#include "mdclient.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
main(int argc, char **argv) {
|
||||||
|
|
||||||
|
char debug[10];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
cout << "mdclient compiled " __DATE__ " " __TIME__ " \n";
|
||||||
|
|
||||||
|
if (argc < 3 ) {
|
||||||
|
|
||||||
|
cerr << "Usage: apig-cli <deviceType> <serverURL> <thirdOption>\n\nwhere\n\n"
|
||||||
|
" <serverURL> = . defaults to '" MD_SERVER_URL "'\n"
|
||||||
|
" <device> = . defaults to '" DEFAULT_DEVICE "'\n"
|
||||||
|
" <thirdOption> = 'n' or 'N'\n\n"
|
||||||
|
|
||||||
|
"The master daemon must be running at the specified <serverURL>.\n"
|
||||||
|
"<thirdOption> = n causes non-repeatable testbucket(s) to be skipped.\n"
|
||||||
|
"Any other 3rd ooption causes a simple connectivity test and exit.\n"
|
||||||
|
"Otherwise performs the full MD core API test suite.\n\n";
|
||||||
|
|
||||||
|
// "If XMLRPC_TRACE_XML is defined will pause " <<
|
||||||
|
// PAUSE_SECS << " at selected points in the tests.\n\n";
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
phase = string("setup");
|
||||||
|
if (argc > 3) {
|
||||||
|
if (*argv[3] == 'n' || *argv[3] == 'N') repeatableOnly = true;
|
||||||
|
else doSanityCheck = true;
|
||||||
|
}
|
||||||
|
defaultDevice = (*argv[1] == '.') ? DEFAULT_DEVICE : argv[1];
|
||||||
|
serverURL = (*argv[2] == '.') ? MD_SERVER_URL : argv[2];
|
||||||
|
|
||||||
|
if (doSanityCheck) {
|
||||||
|
|
||||||
|
cout << "Doing sanity check with simple client: get a handle for " << defaultDevice << " from " << serverURL << "\n";
|
||||||
|
|
||||||
|
string const serverUrl(serverURL);
|
||||||
|
string const methodName("device.registeR");
|
||||||
|
|
||||||
|
xmlrpc_c::clientSimple monClient;
|
||||||
|
xmlrpc_c::value result;
|
||||||
|
|
||||||
|
monClient.call(serverUrl, methodName, "is", &result, 0, DEFAULT_DEVICE);
|
||||||
|
|
||||||
|
int const handle((xmlrpc_c::value_int(result)));
|
||||||
|
|
||||||
|
if ((mdServerHandle=handle) <= 0)
|
||||||
|
{cout << serverURL << " returned: " << handle << " instead of a valid handle.\n"
|
||||||
|
" Run terminates in error.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "Got " << defaultDevice << " handle: " << handle << "\n";
|
||||||
|
cout << "Sanity check completed OK.\n";
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
mdCoreAPITestSuite tests;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
xmlrpc_env_init(&env);
|
||||||
|
xmlrpc_client_setup_global_const(&env);
|
||||||
|
xmlrpc_client_init2(&env, 0, "mdclient", "1.0", NULL, 0);
|
||||||
|
|
||||||
|
tests.run(0);
|
||||||
|
|
||||||
|
} catch(exception const& e) {
|
||||||
|
cout << "During " << phase << " caught std exception: " << e.what() << "\n";
|
||||||
|
cout << "Terminating in error.\n" ;
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
catch(XmlRpcFault const& e) {
|
||||||
|
cout << "XmlRpcFault during " << phase << ": " << e.getFaultString() << "\n";
|
||||||
|
cout << "Terminating in error.\n" ;
|
||||||
|
rc = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << tests.tests << " Variation(s).\n"
|
||||||
|
<< tests.failures << " Failure(s).\n";
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,232 @@
|
||||||
|
#define CD_MAIN
|
||||||
|
#include "ausreg-cd.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
bool cdHasKb;
|
||||||
|
char cdOrKbValue;
|
||||||
|
const char *cdOrKb=&cdOrKbValue;
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the shell for the Unix Client Server (Cliever) daemon.
|
||||||
|
* There is a different shell for the Windows Service.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void runCommander();
|
||||||
|
void setSignals();
|
||||||
|
void signal_handler(int);
|
||||||
|
void usage();
|
||||||
|
|
||||||
|
using namespace boost::interprocess;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void aucClientServer() { // AKA "Cliever"
|
||||||
|
|
||||||
|
int i,lfp;
|
||||||
|
char str[10];
|
||||||
|
|
||||||
|
thisConfig->daemonProcess = fork();
|
||||||
|
if (thisConfig->daemonProcess < 0) {
|
||||||
|
puts("Can't initialize process!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (thisConfig->runCommander && getpid() == thisConfig->shellProcess)
|
||||||
|
{setSignals(); runCommander();}
|
||||||
|
setsid(); /* obtain a new process group */
|
||||||
|
i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standard I/O */
|
||||||
|
umask(027); /* set newly created file permissions */
|
||||||
|
chdir(RUNNING_DIR); /* change running directory */
|
||||||
|
lfp=open(CD_LOCK_FILE,O_RDWR|O_CREAT,0640);
|
||||||
|
if (lfp<0) {puts("Can't open lockfile!"); exit(1);}
|
||||||
|
if (lockf(lfp,F_TLOCK,0)<0)
|
||||||
|
{puts("Can't lock lockfile!"); exit(0);}
|
||||||
|
shared_memory_object shm(open_only, "auc-cd-global", read_write);
|
||||||
|
mapped_region aucCDglobal(shm, read_write);
|
||||||
|
gm = (auc_cd_global *)aucCDglobal.get_address();
|
||||||
|
if (strcmp(gm->id,"auc-cd")) // Same deal
|
||||||
|
{theseLogs.logN(0,"Daemon couldn't identify global memory. Bye."); exit(1);}
|
||||||
|
gm->daemon_pid = getpid();
|
||||||
|
sprintf(str,"%d",getpid());
|
||||||
|
theseLogs.logN(1,"auc-cd running (%s)",str);
|
||||||
|
strcat(str,"\n");
|
||||||
|
write(lfp,str,strlen(str)); /* record pid to lockfile */
|
||||||
|
setSignals();
|
||||||
|
|
||||||
|
theseLogs.init("auc-cd");
|
||||||
|
theseLogs.logN(0,CD_NAME " " CD_VERSION " compiled on " __DATE__ " @ " __TIME__);
|
||||||
|
theseLogs.logN(3,"Cliever processing(%d) begins for devices on port %s to MD at %s.",getpid(),thisConfig->telemetryPortStr.c_str(),thisConfig->mdAddress.c_str());
|
||||||
|
|
||||||
|
if (cdHasKb) {
|
||||||
|
thisConfig->clipsProcess = fork();
|
||||||
|
if (thisConfig->clipsProcess < 0) {
|
||||||
|
puts("Can't initialize CLIPS--!");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (getpid() != gm->daemon_pid) {
|
||||||
|
#if defined(MD_MAND)
|
||||||
|
theseLogs.logN(0,"Creating CLIPS Environment.");
|
||||||
|
DACLIPS::init();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
boost::thread cliever(runCliever);
|
||||||
|
boost::thread dataLayer(runDataLayer);
|
||||||
|
|
||||||
|
if (!dataLayer.joinable() || !cliever.joinable()) {
|
||||||
|
if (!dataLayer.joinable())
|
||||||
|
theseLogs.logN(0,"Failed to start data layer, auc-cd process will terminate.");
|
||||||
|
if (!cliever.joinable())
|
||||||
|
theseLogs.logN(0,"Failed to start client-server, auc-cd process will terminate.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
theseLogs.logN(0,"Cliever started OK.");
|
||||||
|
dataLayer.join();
|
||||||
|
theseLogs.logN(0,"auc-cd EOJ.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (std::exception &e)
|
||||||
|
{
|
||||||
|
theseLogs.logN(1,"Exception: %s",e.what());
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
theseLogs.logN(0,"General fault.");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(thisCliever->rc);
|
||||||
|
|
||||||
|
}
|
||||||
|
int main(int const argc, const char ** const argv)
|
||||||
|
{
|
||||||
|
const char *exeName,*banner = "\n" CD_NAME " " CD_VERSION " compiled on " __DATE__ " @ " __TIME__ " (%d)\n";
|
||||||
|
int mthParm, rc = OK;
|
||||||
|
|
||||||
|
thisCliever = NULL;
|
||||||
|
|
||||||
|
cdHasKb = strstr(argv[0],"clips") ? true : false;
|
||||||
|
cdOrKbValue = cdHasKb ? 'd' : 'D'; // d == kb enabled, D = !d
|
||||||
|
|
||||||
|
//RAII constructor/destructor
|
||||||
|
struct shm_remove
|
||||||
|
{
|
||||||
|
shm_remove() { shared_memory_object::remove("auc-cd-global"); }
|
||||||
|
~shm_remove() { shared_memory_object::remove("auc-cd-global"); }
|
||||||
|
} remover;
|
||||||
|
|
||||||
|
shared_memory_object shm(create_only, "auc-cd-global", read_write);
|
||||||
|
shm.truncate(CD_GLOBAL_SIZE);
|
||||||
|
mapped_region aucCDglobal(shm, read_write);
|
||||||
|
memset(aucCDglobal.get_address(), 0, aucCDglobal.get_size());
|
||||||
|
gm = (auc_cd_global *)aucCDglobal.get_address();
|
||||||
|
strcpy(gm->id,"auc-cd");
|
||||||
|
strcmp(gm->id,"auc-cd"); // Will segfault if there is a problem so catches are are futile.
|
||||||
|
// But the signal trap will catch the fault.
|
||||||
|
|
||||||
|
thisConfig = new clientDaemonConfig();
|
||||||
|
thisConfig->shellProcess = getpid();
|
||||||
|
strcpy(thisConfig->origCmd,argv[0]);
|
||||||
|
|
||||||
|
if (argc < 2 || argc > 7) usage();
|
||||||
|
|
||||||
|
thisConfig->telemetryPort = atoi(argv[1]);
|
||||||
|
if (thisConfig->telemetryPort < 1000 || thisConfig->telemetryPort > 65535)
|
||||||
|
{
|
||||||
|
std::cerr << "The <telemetry-udp-port> value is invalid.\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
thisConfig->telemetryPortStr = std::string(argv[1]);
|
||||||
|
for (mthParm=2;mthParm < argc;mthParm++) {
|
||||||
|
if (*argv[mthParm] == '*') {
|
||||||
|
thisConfig->runCommander = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!strncmp(argv[mthParm],"device=",7)) {
|
||||||
|
thisConfig->deviceName = std::string(argv[mthParm]+8);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!strncmp(argv[mthParm],"logs=",4)) {
|
||||||
|
strcpy(thisConfig->logPath,argv[mthParm]+5);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!strncmp(argv[mthParm],"mdIP=",4)) {
|
||||||
|
thisConfig->mdAddress = std::string(argv[mthParm]+5);
|
||||||
|
}
|
||||||
|
else usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thisConfig->runCommander) printf(banner,thisConfig->shellProcess);
|
||||||
|
aucClientServer();
|
||||||
|
while(!gm->graceful) sleep(2);
|
||||||
|
|
||||||
|
}
|
||||||
|
void runCommander() {
|
||||||
|
|
||||||
|
char msg[128];
|
||||||
|
int i;
|
||||||
|
mdCommander commander;
|
||||||
|
|
||||||
|
theseLogs.init("auc-cd-ui");
|
||||||
|
theseLogs.logN(0,"Interactive command processor started.");
|
||||||
|
commander.driver();
|
||||||
|
if (thisConfig->terminateRequest) {
|
||||||
|
theseLogs.logN(0,"Interactive shutdown requested.");
|
||||||
|
puts("auc-cd operator issued terminate command.");
|
||||||
|
kill(gm->daemon_pid,SIGTERM);
|
||||||
|
} else {
|
||||||
|
theseLogs.logN(0,"Interactive command processor ended.");
|
||||||
|
sprintf(msg,"Commander terminated, auc-cd continues (%d).",gm->daemon_pid);
|
||||||
|
puts(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
theseLogs.logN(1,"Closing out I/O for shell process (%d)",thisConfig->shellProcess);
|
||||||
|
for (i=getdtablesize();i>=0;--i) close(i); /* close all descriptors */
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
void setSignals() {
|
||||||
|
|
||||||
|
signal(SIGCHLD,SIG_IGN); /* ignore child */
|
||||||
|
signal(SIGTSTP,SIG_IGN); /* ignore tty signals */
|
||||||
|
signal(SIGTTOU,SIG_IGN); // both input
|
||||||
|
signal(SIGTTIN,SIG_IGN); // and output
|
||||||
|
signal(SIGSEGV,signal_handler);
|
||||||
|
signal(SIGUSR1,signal_handler); // commander log messages
|
||||||
|
signal(SIGHUP,signal_handler); /* catch hangup signal */
|
||||||
|
signal(SIGTERM,signal_handler); /* catch kill signal */
|
||||||
|
|
||||||
|
}
|
||||||
|
void signal_handler(int sig)
|
||||||
|
{
|
||||||
|
switch(sig) {
|
||||||
|
case SIGSEGV:
|
||||||
|
break;
|
||||||
|
case SIGUSR1:
|
||||||
|
break;
|
||||||
|
case SIGHUP:
|
||||||
|
theseLogs.logN(0,"hangup signal caught, currently auc-cd ignores this.");
|
||||||
|
break;
|
||||||
|
case SIGTERM:
|
||||||
|
theseLogs.logN(0,"terminate signal caught, auc-cd will shutdown.");
|
||||||
|
cdShutdown termEvent;
|
||||||
|
termEvent.send();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
void usage() {
|
||||||
|
|
||||||
|
std::cerr << "Usage: " << cdOrKb << " <udp-port> ['*'] [device=TEST] [mdIP=" MD_DEFAULT_IP "] [logs=\\tmp]\n\n where \n\n"
|
||||||
|
"\t <udp-port> is required, must be the first parameter, and must be 1000 or greater. \n"
|
||||||
|
"\t The other parameters are optional and non-positional and take the shown defaults. \n"
|
||||||
|
"\t '*', if present, indicates skip the command loop (string quotes may be required). \n";
|
||||||
|
exit(1);
|
||||||
|
}
|
|
@ -0,0 +1,182 @@
|
||||||
|
#include "auc-cd.h"
|
||||||
|
|
||||||
|
#include "log4cpp/Category.hh"
|
||||||
|
#include "log4cpp/Appender.hh"
|
||||||
|
#include "log4cpp/FileAppender.hh"
|
||||||
|
#include "log4cpp/Layout.hh"
|
||||||
|
#include "log4cpp/BasicLayout.hh"
|
||||||
|
#include "log4cpp/Priority.hh"
|
||||||
|
|
||||||
|
using namespace log4cpp;
|
||||||
|
|
||||||
|
Appender *app;
|
||||||
|
char cdLogWork[256];
|
||||||
|
Category &root = Category::getRoot(),
|
||||||
|
&cd_core = Category::getInstance(std::string("cd_core")),
|
||||||
|
&cd_dbug = Category::getInstance(std::string("cd_dbug")),
|
||||||
|
&cd_devl = Category::getInstance(std::string("cd_devl"));
|
||||||
|
PatternLayout *layout;
|
||||||
|
|
||||||
|
void cdLogger::init(const char *baseName) {
|
||||||
|
|
||||||
|
const char *defaultBasename = "auc-cd-99";
|
||||||
|
char mainLogFileName[128];
|
||||||
|
|
||||||
|
if (!strlen(baseName)) strcpy(mainLogFileName,defaultBasename);
|
||||||
|
else strcpy(mainLogFileName,baseName);
|
||||||
|
strcat(mainLogFileName,".log");
|
||||||
|
|
||||||
|
strcpy(cdLogWork,thisConfig->logPath);
|
||||||
|
strcat(cdLogWork,"/");
|
||||||
|
strcat(cdLogWork,mainLogFileName);
|
||||||
|
strcpy(thisConfig->logPath,cdLogWork);
|
||||||
|
logPath = cdLogWork;
|
||||||
|
|
||||||
|
app = new FileAppender("default", std::string(logPath));
|
||||||
|
layout = new PatternLayout();
|
||||||
|
layout->setConversionPattern("%d %p %c %x: %m%n");
|
||||||
|
app->setLayout(layout);
|
||||||
|
|
||||||
|
root.addAppender(app);
|
||||||
|
root.setPriority(Priority::ERROR);
|
||||||
|
|
||||||
|
cd_core.setPriority(Priority::INFO);
|
||||||
|
cd_core.setAdditivity(true);
|
||||||
|
|
||||||
|
cd_dbug.setPriority(Priority::DEBUG);
|
||||||
|
cd_dbug.setAdditivity(true);
|
||||||
|
|
||||||
|
cd_devl.setPriority(Priority::NOTSET);
|
||||||
|
cd_devl.setAdditivity(true);
|
||||||
|
|
||||||
|
}
|
||||||
|
void cdLogger::logN(int n, const char *format, ...) {
|
||||||
|
char buff[1024];
|
||||||
|
void *args[4];
|
||||||
|
int nthArg = 0;
|
||||||
|
va_list lm;
|
||||||
|
|
||||||
|
va_start(lm,format);
|
||||||
|
for (;nthArg<n;nthArg++) args[nthArg]=va_arg(lm,void *);
|
||||||
|
va_end(lm);
|
||||||
|
|
||||||
|
switch(n) {
|
||||||
|
case 0:
|
||||||
|
strcpy(buff,format);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sprintf(buff,format,args[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sprintf(buff,format,args[0],args[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3],args[4]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cd_core.info(buff);
|
||||||
|
}
|
||||||
|
void cdLogger::logNdebug(int n, const char *format, ...) {
|
||||||
|
char buff[1024];
|
||||||
|
void *args[5];
|
||||||
|
int nthArg = 0;
|
||||||
|
va_list lm;
|
||||||
|
|
||||||
|
va_start(lm,format);
|
||||||
|
for (;nthArg<n;nthArg++) args[nthArg]=va_arg(lm,void *);
|
||||||
|
va_end(lm);
|
||||||
|
|
||||||
|
switch(n) {
|
||||||
|
case 0:
|
||||||
|
strcpy(buff,format);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sprintf(buff,format,args[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sprintf(buff,format,args[0],args[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3],args[4]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cd_dbug.warn(buff);
|
||||||
|
}
|
||||||
|
void cdLogger::logNdebug(int m, int n, const char *format, ...) {
|
||||||
|
char buff[1024];
|
||||||
|
void *args[5];
|
||||||
|
int nthArg = 0;
|
||||||
|
va_list lm;
|
||||||
|
|
||||||
|
if (m < 0 || m > thisConfig->debugThreshold) return;
|
||||||
|
|
||||||
|
va_start(lm,format);
|
||||||
|
for (;nthArg<n;nthArg++) args[nthArg]=va_arg(lm,void *);
|
||||||
|
va_end(lm);
|
||||||
|
|
||||||
|
switch(n) {
|
||||||
|
case 0:
|
||||||
|
strcpy(buff,format);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sprintf(buff,format,args[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sprintf(buff,format,args[0],args[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3],args[4]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cd_dbug.warn(buff);
|
||||||
|
}
|
||||||
|
void cdLogger::logNdev(int n, const char *format, ...) {
|
||||||
|
char buff[1024];
|
||||||
|
void *args[5];
|
||||||
|
int nthArg = 0;
|
||||||
|
va_list lm;
|
||||||
|
|
||||||
|
va_start(lm,format);
|
||||||
|
for (;nthArg<n;nthArg++) args[nthArg]=va_arg(lm,void *);
|
||||||
|
va_end(lm);
|
||||||
|
|
||||||
|
switch(n) {
|
||||||
|
case 0:
|
||||||
|
strcpy(buff,format);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
sprintf(buff,format,args[0]);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sprintf(buff,format,args[0],args[1]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
sprintf(buff,format,args[0],args[1],args[2],args[3],args[4]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cd_devl.warn(buff);
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
#include "auc-cd.h"
|
||||||
|
#include "../server/Listener.cpp"
|
||||||
|
#include "../server/EventSender.cpp"
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using boost::asio::ip::udp;
|
||||||
|
|
||||||
|
void hbCallback(const boost::system::error_code&);
|
||||||
|
void stream();
|
||||||
|
void trCallback(const boost::system::error_code& error);
|
||||||
|
|
||||||
|
void mdCliever::processEvent( const cdIncoming &dgEvent )
|
||||||
|
{
|
||||||
|
assert(EventSender<cdIncoming>::isSending());
|
||||||
|
|
||||||
|
switch(dgEvent.dg.hdr.msgType) {
|
||||||
|
case MDDG_NEWBORN:
|
||||||
|
switch(dgEvent.dg.hdr.clientType) {
|
||||||
|
case MDDEV_MD:
|
||||||
|
if (dgEvent.dg.hdr.sinkHandle) {
|
||||||
|
myHandle = dgEvent.dg.hdr.sinkHandle;
|
||||||
|
theseLogs.logN(1,"Got handle (%d) from MD. End of natal sequence for this cliever.",myHandle);
|
||||||
|
}
|
||||||
|
else if (!myHandle)
|
||||||
|
theseLogs.logN(0,"MD rejected natal sequence. Please kill me and call tech. support.");
|
||||||
|
break;
|
||||||
|
case MACHINE:
|
||||||
|
break;
|
||||||
|
case MDDEV_INSTRUMENT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCliever::processEvent( const cdHeartbeat &thisPulse )
|
||||||
|
{
|
||||||
|
assert(EventSender<cdHeartbeat>::isSending());
|
||||||
|
|
||||||
|
myPulse.dg.hdr.msgSN = sentMsgCount[MDDG_HEARTBEAT][0]++;
|
||||||
|
myPulse.dg.hdr.sourceHandle = myHandle;
|
||||||
|
strcpy(myPulse.dg.payLoad,thisConfig->telemetryPortStr.c_str());
|
||||||
|
myPulse.dg.hdr.primeOffset = strlen(thisConfig->telemetryPortStr.c_str()) + 1;
|
||||||
|
strcpy((char *)(&myPulse.dg.payLoad[strlen(myPulse.dg.payLoad)+1]),"CLIEVER");
|
||||||
|
myPulse.dg.hdr.payloadSize = myPulse.dg.hdr.primeOffset + strlen("CLIEVER") + 1;
|
||||||
|
fg->send_to(myPulse.dg, myStdDevIdx );
|
||||||
|
theseLogs.logNdebug(MAX_DEBUG,1,"Heartbeat (%d)",sentMsgCount[MDDG_HEARTBEAT][0]);
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCliever::processEvent( const cdInteractiveCommand &cmdEvent )
|
||||||
|
{
|
||||||
|
assert(EventSender<cdInteractiveCommand>::isSending());
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCliever::processEvent( const cdShutdown &bye )
|
||||||
|
{
|
||||||
|
assert(EventSender<cdShutdown>::isSending());
|
||||||
|
shuttingDown = true;
|
||||||
|
theseLogs.logN(0,"Shutting down: draining work for immediate exit.");
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCliever::processEvent( const cdTelemetryFrame &thisFrame )
|
||||||
|
{
|
||||||
|
assert(EventSender<cdTelemetryFrame>::isSending());
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCliever::processEvent( const cdResponse &thisReply )
|
||||||
|
{
|
||||||
|
const void *queued = &thisReply;
|
||||||
|
|
||||||
|
assert(EventSender<cdResponse>::isSending());
|
||||||
|
queue(new mdWQitem( queued, MD_NEWBORN, 0 ));
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdDGChannel::handle_receive_from(const boost::system::error_code& error,
|
||||||
|
size_t bytes_recvd)
|
||||||
|
{
|
||||||
|
if (!error && bytes_recvd > 0)
|
||||||
|
{
|
||||||
|
cdIncoming incoming( *(thisCliever->bg) );
|
||||||
|
|
||||||
|
if (incoming.dg.hdr.clientType >= 0 && incoming.dg.hdr.clientType < N_MDDEV_TYPES)
|
||||||
|
{theseLogs.logNdebug(MAX_DEBUG,2,"msgtype %d received from a '%s'.",incoming.dg.hdr.msgType,clientTypes[incoming.dg.hdr.clientType]);
|
||||||
|
incoming.ip = p_endpoint_;
|
||||||
|
incoming.send();
|
||||||
|
|
||||||
|
} else
|
||||||
|
theseLogs.logNdebug(1,1,"msgtype %d received from unknown MD client type, ignored.",incoming.dg.hdr.msgType);
|
||||||
|
|
||||||
|
}
|
||||||
|
passive_.async_receive_from(
|
||||||
|
boost::asio::buffer(data_, MD_MAX_DATAGRAM), p_endpoint_,
|
||||||
|
boost::bind(&mdDGChannel::handle_receive_from, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCliever::dispatch(mdWQitem *next) {
|
||||||
|
|
||||||
|
switch(next->kind) {
|
||||||
|
case MD_NEWBORN:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
delete next;
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCDHeartbeat::nextBeat(const boost::system::error_code& error) { thisCliever->myPulse.send(); }
|
||||||
|
void mdCDHeartbeat::run() {
|
||||||
|
|
||||||
|
while (!thisCliever->shuttingDown)
|
||||||
|
{t0->async_wait(hbCallback);
|
||||||
|
if (thisCliever->myHandle)
|
||||||
|
sleep(60*MD_HEARTBEAT);
|
||||||
|
else
|
||||||
|
sleep(10*MD_HEARTBEAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
void hbCallback(const boost::system::error_code& error) { if (thisCliever->alive) thisCliever->pulse->nextBeat(error); }
|
||||||
|
void pulse() {
|
||||||
|
if ((thisCliever->connected=thisCliever->fg->connect_to( thisConfig->mdAddress, thisConfig->telemetryPortStr )))
|
||||||
|
theseLogs.logNdebug(NORMAL_DEBUG,2,"Cliever connection open on: MD @ %s port %s.", thisConfig->mdAddress.c_str(),thisConfig->telemetryPortStr.c_str());
|
||||||
|
else
|
||||||
|
theseLogs.logNdebug(NORMAL_DEBUG*2,2,"Cliever UDP socket open on: MD @ %s port %s failed.", thisConfig->mdAddress.c_str(),thisConfig->telemetryPortStr.c_str());
|
||||||
|
if (thisCliever->connected)
|
||||||
|
thisCliever->pulse->run();
|
||||||
|
}
|
||||||
|
void runCliever() {
|
||||||
|
|
||||||
|
try { cb[0] = new mdCB();
|
||||||
|
|
||||||
|
thisCliever = new mdCliever(thisConfig);
|
||||||
|
|
||||||
|
EventSender<cdHeartbeat>::add(*thisCliever);
|
||||||
|
assert(EventSender<cdHeartbeat>::getNumListeners() == 1);
|
||||||
|
EventSender<cdIncoming>::add(*thisCliever);
|
||||||
|
assert(EventSender<cdIncoming>::getNumListeners() == 1);
|
||||||
|
EventSender<cdShutdown>::add(*thisCliever);
|
||||||
|
assert(EventSender<cdShutdown>::getNumListeners() == 1);
|
||||||
|
EventSender<cdTelemetryFrame>::add(*thisCliever);
|
||||||
|
assert(EventSender<cdTelemetryFrame>::getNumListeners() == 1);
|
||||||
|
EventSender<cdInteractiveCommand>::add(*thisCliever);
|
||||||
|
assert(EventSender<cdInteractiveCommand>::getNumListeners() == 1);
|
||||||
|
|
||||||
|
thisCliever->fg = new mdDGChannel( io_fg, 0 );
|
||||||
|
|
||||||
|
} catch(...) {
|
||||||
|
theseLogs.logNdebug(-1,0,"Unknown error in Cliever initialization block.");
|
||||||
|
}
|
||||||
|
|
||||||
|
theseLogs.logNdebug(NORMAL_DEBUG*2,0,"Cliever instantiated, starting heartbeat and telemetry stream.");
|
||||||
|
|
||||||
|
thisCliever->alive = true;
|
||||||
|
io_fg.run();
|
||||||
|
theseLogs.logNdebug(0,0,"runCliever asio ended");
|
||||||
|
|
||||||
|
}
|
||||||
|
void runDataLayer() {
|
||||||
|
|
||||||
|
int assertCliever;
|
||||||
|
|
||||||
|
theseLogs.logN(1,"Spin to attach MD datalayer background on port %d ...",thisConfig->telemetryPort);
|
||||||
|
|
||||||
|
for(assertCliever=0;!thisCliever && assertCliever < MAX_DEBUG;assertCliever++);
|
||||||
|
for(assertCliever=0;!thisCliever->alive && assertCliever < MAX_DEBUG;assertCliever++);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
thisCliever->bg = new mdDGChannel(io_bg, thisConfig->telemetryPort );
|
||||||
|
theseLogs.logN(0,"... main bus background running.");
|
||||||
|
thisCliever->pulse = new mdCDHeartbeat();
|
||||||
|
thisCliever->pulse->init();
|
||||||
|
boost::thread myPulse(pulse);
|
||||||
|
assert(myPulse.joinable());
|
||||||
|
boost::thread telemetryStream(stream);
|
||||||
|
assert(telemetryStream.joinable());
|
||||||
|
io_bg.run();
|
||||||
|
myPulse.join();
|
||||||
|
telemetryStream.join();
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
theseLogs.logN(1,"Fatal error in data layer bg: %s .",e.what());
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
theseLogs.logN(0,"Unknown failure in datalayer bg.");
|
||||||
|
}
|
||||||
|
|
||||||
|
theseLogs.logNdebug(1,0,"asio background io service ended.");
|
||||||
|
|
||||||
|
}
|
||||||
|
void shutdown() {
|
||||||
|
|
||||||
|
cdShutdown bye = cdShutdown();
|
||||||
|
bye.send();
|
||||||
|
|
||||||
|
}
|
||||||
|
void stream() {
|
||||||
|
|
||||||
|
boost::asio::deadline_timer t1(io_bg, boost::posix_time::seconds(MD_REFRESH));
|
||||||
|
while (!thisCliever->shuttingDown)
|
||||||
|
{t1.async_wait(trCallback);
|
||||||
|
sleep(2*MD_REFRESH);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
void trCallback(const boost::system::error_code& error) {
|
||||||
|
|
||||||
|
cdTelemetryFrame thisFrame;
|
||||||
|
thisFrame.send();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
#include "auc-cd.h"
|
||||||
|
|
||||||
|
int clientDaemonConfig::loadMachineConfiguration() {
|
||||||
|
|
||||||
|
/*! \todo add processing for predefinition of local devices
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int rc=OK;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
#include "auc-cd.h"
|
||||||
|
|
||||||
|
int is_numeric(const char *p) { int i = strlen(p),j=0;
|
||||||
|
if (*p) {
|
||||||
|
char c;
|
||||||
|
while ((c=*p++)) { j++;
|
||||||
|
if (!isdigit(c)) {
|
||||||
|
if (j == i) return 2;
|
||||||
|
else return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void mdCommander::driver() {
|
||||||
|
|
||||||
|
bool rc;
|
||||||
|
char instrinsic[16],next,rawString[256],work[256];
|
||||||
|
const char *mdErrCode = "";
|
||||||
|
int i,commandLength;
|
||||||
|
|
||||||
|
greet();
|
||||||
|
while(acceptingInput) {
|
||||||
|
putchar('>');
|
||||||
|
next=0;
|
||||||
|
i=0;
|
||||||
|
memset(rawString,0,sizeof(rawString));
|
||||||
|
while(next != '\012') {
|
||||||
|
next = getchar();
|
||||||
|
rawString[i++] = next;
|
||||||
|
if (i > (sizeof(rawString) - 1)) {
|
||||||
|
puts("Max length exceeded!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!strlen(rawString)) continue;
|
||||||
|
if (rawString[0] == '?') {
|
||||||
|
help();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_numeric(rawString) == 2) {
|
||||||
|
rawString[strlen(rawString)] = 0;
|
||||||
|
mdStdDevIdx = atoi(rawString);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strlen(rawString) >= 4 && strlen(rawString) <= 6 )
|
||||||
|
{if (!strcmp(rawString,"log\n")) {
|
||||||
|
system("less /tmp/auc-cd.log");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(rawString,"rlog\n")) {
|
||||||
|
system(PULL_MD_LOG);
|
||||||
|
system("less auc-md.log");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(rawString,"clips\n")) {
|
||||||
|
#ifdef MD_MAND
|
||||||
|
|
||||||
|
#endif
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(rawString,"done\n")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(rawString,"mdapi\n")) {
|
||||||
|
system("mdclient ");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(rawString,"quit\n")) {
|
||||||
|
thisConfig->terminateRequest = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!strcmp(rawString,"mdapi\n")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strlen(rawString) < 3) {
|
||||||
|
puts("That SCPI command is too short!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rc = scpi(rawString);
|
||||||
|
if (!rc) puts("Command transmitted: OK.");
|
||||||
|
else printf("Command result: %s.",mdErrCode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCommander::greet() {
|
||||||
|
|
||||||
|
puts("auc-cd command processor");
|
||||||
|
puts("Enter ? for help or a cliever low level command");
|
||||||
|
acceptingInput = true;
|
||||||
|
SCPImode = true;
|
||||||
|
currentDevice = std::string("ALX");
|
||||||
|
|
||||||
|
}
|
||||||
|
void mdCommander::help() {
|
||||||
|
|
||||||
|
const char *banner = "\n" CD_NAME " " CD_VERSION " compiled on " __DATE__ " @ " __TIME__ " (%d)\n";
|
||||||
|
|
||||||
|
system("clear");
|
||||||
|
printf(banner,thisConfig->shellProcess);
|
||||||
|
printf("Target mdStdDevIdx: %d (0: Master Daemon(MD), 1: Cliever(CD))\n",mdStdDevIdx);
|
||||||
|
puts("LL (low level) Cliever commands: \n");
|
||||||
|
puts(" ? - display this screen");
|
||||||
|
puts(" <n> - make <n> (an integer) the target mdStdDevIdx");
|
||||||
|
puts(" done - terminate the command loop but not ausreg-cd");
|
||||||
|
puts(" log - display this cliever log");
|
||||||
|
puts(" rlog - pull and display the MD log");
|
||||||
|
puts(" mdapi - run mdclient here (xmlrpc-c must be installed)");
|
||||||
|
printf(" quit - terminate %s (if in md shell CTL-C if finished)\n\n",thisConfig->origCmd);
|
||||||
|
puts("Anything else is a EPP cmd for the selected EPP Server.");
|
||||||
|
puts("If the device responds it should show in the log if debug level high enough.\n");
|
||||||
|
if (*cdOrKb == 'd') {
|
||||||
|
puts("In the character mode UI:");
|
||||||
|
puts(" Enter (help) in the rules system for more help.");
|
||||||
|
puts(" Enter (exit) in the rules system to return here.\n");
|
||||||
|
}
|
||||||
|
puts("If in md shell, 'RST' and 'quit' resets the servers for this Cliever group");
|
||||||
|
puts("(i.e. if the mdStdDevIdx is 0;used to get a fresh epoch with MD");
|
||||||
|
puts(" and CD initialized and connected for device and data client testing).\n");
|
||||||
|
puts("NB: USE LL SCPI COMMANDS FOR DEVICE DEV ONLY -\n");
|
||||||
|
puts("Sending device commands at this level is potentially dangerous and is ");
|
||||||
|
puts("only for device development. Other users should issue commands using the");
|
||||||
|
puts("data client XMLRPC API, e.g. thru mdclient which uses the current best");
|
||||||
|
puts("proven rulebase (when MD is running as daclips-md).");
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mdCommander::scpi(char *cmd) {
|
||||||
|
|
||||||
|
char *command,work[256];
|
||||||
|
bool isDirect=false,rc=true;
|
||||||
|
|
||||||
|
if (!mdStdDevIdx && !strncmp(cmd,"RST",3)) {
|
||||||
|
|
||||||
|
mdDG mdg;
|
||||||
|
|
||||||
|
mdg.dg.hdr.sourceHandle = thisCliever->myHandle;
|
||||||
|
mdg.dg.hdr.payloadSize = 0;
|
||||||
|
mdg.dg.hdr.msgType = MDDG_CDRESET;
|
||||||
|
if (thisCliever->fg->send(mdg.dg)) rc = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include "xmlrpc-c/girerr.hpp"
|
||||||
|
using girerr::error;
|
||||||
|
using girerr::throwf;
|
||||||
|
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
testSuite::~testSuite() {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
testSuite::run(unsigned int const indentation) {
|
||||||
|
try {
|
||||||
|
cout << string(indentation*2, ' ')
|
||||||
|
<< "Running " << suiteName() << endl;
|
||||||
|
this->runtests(indentation);
|
||||||
|
} catch (error const& error) {
|
||||||
|
throwf("%s failed. %s", suiteName().c_str(), error.what());
|
||||||
|
} catch (...) { failures++;
|
||||||
|
throw(error(suiteName() + string(" failed. ") +
|
||||||
|
string("It threw an unexpected type of object")));
|
||||||
|
}
|
||||||
|
cout << string(indentation*2, ' ')
|
||||||
|
<< suiteName() << " tests passed." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// This is a good place to set a breakpoint.
|
||||||
|
void
|
||||||
|
logFailedTest(const char * const fileName,
|
||||||
|
unsigned int const lineNum,
|
||||||
|
const char * const statement) {
|
||||||
|
|
||||||
|
ostringstream msg;
|
||||||
|
|
||||||
|
msg << endl
|
||||||
|
<< fileName << ":" << lineNum
|
||||||
|
<< ": expected (" << statement << ")" << endl;
|
||||||
|
|
||||||
|
throw(error(msg.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
error
|
||||||
|
fileLineError(string const filename,
|
||||||
|
unsigned int const lineNumber,
|
||||||
|
string const description) {
|
||||||
|
|
||||||
|
ostringstream combined;
|
||||||
|
|
||||||
|
combined << filename << ":" << lineNumber << " " << description;
|
||||||
|
|
||||||
|
return error(combined.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
#ifndef MD_TELEMETRY
|
||||||
|
#define MD_TELEMETRY
|
||||||
|
#define MAX_FRAMESIZE 100 // Capacity if data elements of both kinds.
|
||||||
|
#define nameOffsetIdx (frame + (sizeof(unsigned short) * (1 + *nNames)))
|
||||||
|
|
||||||
|
class mdAPIFrame {
|
||||||
|
public:
|
||||||
|
|
||||||
|
char *frame,*frameData,*nameCursor;
|
||||||
|
int frameSize,i,nameOffset;
|
||||||
|
unsigned short *nameOffsets,*nNames;
|
||||||
|
std::string manifest[MAX_FRAMESIZE];
|
||||||
|
|
||||||
|
mdAPIFrame(const char *buffer,int size) : frameSize(size)
|
||||||
|
{frame = (char *)buffer;
|
||||||
|
frameData = frame + frameSize;
|
||||||
|
nNames = (unsigned short *)frame;
|
||||||
|
nameOffsets = ((unsigned short *)frame) + 1;
|
||||||
|
nameCursor = frame + ((MAX_FRAMESIZE + 1) * sizeof(unsigned short));
|
||||||
|
nameOffsets[0] = nameCursor - frame;
|
||||||
|
nameOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *nameIdx(int j) {return frame + ((MAX_FRAMESIZE+1) * sizeof(unsigned short)) + nameOffsets[j];}
|
||||||
|
|
||||||
|
void newOut() { memset(frame,0,frameSize); }
|
||||||
|
void newIn() { for (i=0;i< *nNames;i++) manifest[i] = std::string(nameIdx(i)); }
|
||||||
|
|
||||||
|
|
||||||
|
void pack(mdOperationalDataElement *ode, std::string &next) {
|
||||||
|
frameData -= ode->pack(frameData);
|
||||||
|
strcpy(nameCursor,next.c_str());
|
||||||
|
*((unsigned short *)nameOffsetIdx) = nameOffset;
|
||||||
|
nameOffset += (unsigned short)next.length() + 1;
|
||||||
|
*nNames++;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
#include <boost/statechart/event.hpp>
|
||||||
|
#include <boost/statechart/state_machine.hpp>
|
||||||
|
#include <boost/statechart/simple_state.hpp>
|
||||||
|
#include <boost/statechart/transition.hpp>
|
||||||
|
#include <boost/interprocess/shared_memory_object.hpp>
|
||||||
|
#include <boost/interprocess/mapped_region.hpp>
|
||||||
|
|
||||||
|
#include <msgpack.hpp>
|
||||||
|
|
||||||
|
#include <Category.hh>
|
||||||
|
#include <FileAppender.hh>
|
||||||
|
#include <PatternLayout.hh>
|
||||||
|
|
||||||
|
#include "Listener.h"
|
||||||
|
#include "EventSender.h"
|
||||||
|
#include "TimeStampedEvent.h"
|
||||||
|
#include "PolymorphEvent.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
|
#define CLIEVER
|
||||||
|
|
||||||
|
#include "mdcommon.h"
|
||||||
|
|
||||||
|
#ifdef MD_MAND
|
||||||
|
#include <clipsmm/clipsmm.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "cdEvents.h"
|
||||||
|
#include "mdCommander.h"
|
||||||
|
|
||||||
|
#include "mdBehavior.h"
|
||||||
|
#include "mdObservable.h"
|
||||||
|
#include "mdState.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define CD_EPOCH date()
|
||||||
|
#define CD_GLOBAL_SIZE 4096
|
||||||
|
#define CD_LOCK_FILE "auc-cd.lock"
|
||||||
|
#define CD_NAME DACLIPS_APP " Cliever"
|
||||||
|
#define CD_VERSION "1.1"
|
||||||
|
#define CD_REFRESH MD_HEARTBEAT // default milliseconds between telemetry frame updates
|
||||||
|
#define CD_MAX_DEVICE 4 // including ourselves
|
||||||
|
|
||||||
|
|
||||||
|
#include "clientDaemonConfig.h"
|
||||||
|
|
||||||
|
typedef std::map<std::string,mdObservable*> ObservablesOfInterest;
|
||||||
|
typedef std::map<std::string,mdOperationalDataElement*> ODEsOfInterest;
|
||||||
|
|
||||||
|
#include "cdLogger.h"
|
||||||
|
|
||||||
|
class cdDataLayer;
|
||||||
|
class mdCliever;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CD_MAIN
|
||||||
|
|
||||||
|
auc_cd_global *gm;
|
||||||
|
boost::asio::io_service io_bg,io_fg;
|
||||||
|
cdLogger theseLogs;
|
||||||
|
clientDaemonConfig *thisConfig;
|
||||||
|
mdCliever *thisCliever;
|
||||||
|
|
||||||
|
#ifdef MD_MAND
|
||||||
|
DACLIPS::Environment rules[2]; // 0: batch, 1: commander
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void runDataLayer();
|
||||||
|
extern void runCliever();
|
||||||
|
extern void shutdown();
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern auc_cd_global *gm;
|
||||||
|
extern boost::asio::io_service io_bg,io_fg;
|
||||||
|
extern const char *cdOrKb;
|
||||||
|
extern cdLogger theseLogs;
|
||||||
|
extern clientDaemonConfig *thisConfig;
|
||||||
|
extern mdCliever *thisCliever;
|
||||||
|
|
||||||
|
#ifdef MD_MAND
|
||||||
|
extern DACLIPS::Environment *rules[2];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "clientDaemon.h"
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
class cdHeartbeat: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
|
|
||||||
|
public:
|
||||||
|
mdDatagram dg;
|
||||||
|
mdReply dgr;
|
||||||
|
|
||||||
|
cdHeartbeat() {
|
||||||
|
|
||||||
|
memset((void *)&dg,0,sizeof(mdReply));
|
||||||
|
dg.hdr.clientType = MDDEV_CD;
|
||||||
|
dg.hdr.msgType = MDDG_HEARTBEAT;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
~cdHeartbeat() {};
|
||||||
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
|
||||||
|
};
|
||||||
|
class cdIncoming: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
|
|
||||||
|
public:
|
||||||
|
mdDatagram dg;
|
||||||
|
boost::asio::ip::udp::endpoint ip;
|
||||||
|
|
||||||
|
cdIncoming(mdDGChannel &c) {dg = *(c.inProcess);}
|
||||||
|
|
||||||
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
|
||||||
|
};
|
||||||
|
class cdResponse: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
|
public:
|
||||||
|
bool ackIsNak;
|
||||||
|
mdDatagram *incoming;
|
||||||
|
mdDatagram *reply;
|
||||||
|
boost::asio::ip::udp::endpoint ip;
|
||||||
|
|
||||||
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
|
||||||
|
};
|
||||||
|
class cdShutdown: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
};
|
||||||
|
class cdTelemetryFrame: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
};
|
||||||
|
class cdInteractiveCommand: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef CLIEVER_LOGGER
|
||||||
|
#define CLIEVER_LOGGER
|
||||||
|
|
||||||
|
#include "log4cpp/Category.hh"
|
||||||
|
#include "log4cpp/Appender.hh"
|
||||||
|
#include "log4cpp/FileAppender.hh"
|
||||||
|
#include "log4cpp/Layout.hh"
|
||||||
|
#include "log4cpp/BasicLayout.hh"
|
||||||
|
#include "log4cpp/Priority.hh"
|
||||||
|
|
||||||
|
using namespace log4cpp;
|
||||||
|
|
||||||
|
class cdLogger {
|
||||||
|
public:
|
||||||
|
char *logPath;
|
||||||
|
|
||||||
|
cdLogger() {};
|
||||||
|
|
||||||
|
void init(const char * = "");
|
||||||
|
void logN(int n, const char *format, ...);
|
||||||
|
void logNdebug(int n, const char *format, ...);
|
||||||
|
void logNdebug(int m, int n, const char *format, ...);
|
||||||
|
void logNdev(int n, const char *format, ...);
|
||||||
|
|
||||||
|
~cdLogger(){};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef CLIEVER_CORE
|
||||||
|
#define CLIEVER_CORE
|
||||||
|
|
||||||
|
|
||||||
|
using boost::asio::ip::udp;
|
||||||
|
/*! \brief mdClieverTransaction
|
||||||
|
* Abstract category encapsulating MD-CD interactions.
|
||||||
|
*/
|
||||||
|
class mdClieverTransaction : public mdProcess {void run() {};};
|
||||||
|
/*! \brief mdCDHearbeat
|
||||||
|
* Ensure vitality of the base MD-CD distributed process.
|
||||||
|
*/
|
||||||
|
void hbCallback(const boost::system::error_code& error);
|
||||||
|
class mdCDHeartbeat : public mdClieverTransaction {
|
||||||
|
|
||||||
|
boost::asio::deadline_timer *t0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
mdCDHeartbeat() {}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
t0 = new boost::asio::deadline_timer(io_bg, boost::posix_time::seconds(MD_HEARTBEAT));
|
||||||
|
}
|
||||||
|
void dispatch(mdWQitem*) {} // Heartbeats aren't dispatched.
|
||||||
|
void nextBeat(const boost::system::error_code& error);
|
||||||
|
void run();
|
||||||
|
|
||||||
|
};
|
||||||
|
/*! \brief cdClieverTransaction
|
||||||
|
* Encapsulates CD-mdHost interactions.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class cdClieverTransaction : public mdProcess {void run()=0;};
|
||||||
|
|
||||||
|
/*! \brief mdCliever
|
||||||
|
* Client-server middleware object.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class mdCliever: public mdProcess,
|
||||||
|
public Listener<cdHeartbeat>,
|
||||||
|
public Listener<cdTelemetryFrame>,
|
||||||
|
public Listener<cdIncoming>,
|
||||||
|
public Listener<cdInteractiveCommand>,
|
||||||
|
public Listener<cdResponse>,
|
||||||
|
public Listener<cdShutdown>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool alive,connected,shuttingDown,shutDown;
|
||||||
|
|
||||||
|
int instrumentHandle[MAX_INSTRUMENTS],
|
||||||
|
myHandle,machineHandle,
|
||||||
|
rc,
|
||||||
|
sentMsgCount[N_MDDG_TYPES][CD_MAX_DEVICE];
|
||||||
|
|
||||||
|
cdHeartbeat myPulse;
|
||||||
|
clientDaemonConfig *cfg;
|
||||||
|
mdCDHeartbeat *pulse;
|
||||||
|
mdDGChannel *bg,*fg;
|
||||||
|
|
||||||
|
|
||||||
|
mdCliever() { alive = connected = false;
|
||||||
|
rc = OK;
|
||||||
|
pulse = NULL;
|
||||||
|
shuttingDown = shutDown = false;
|
||||||
|
memset(sentMsgCount,0,sizeof(sentMsgCount));
|
||||||
|
memset(instrumentHandle,0,sizeof(instrumentHandle));
|
||||||
|
myHandle = machineHandle = 0;
|
||||||
|
}
|
||||||
|
mdCliever(clientDaemonConfig *cmdCfg)
|
||||||
|
{ this->cfg = cmdCfg; }
|
||||||
|
|
||||||
|
void dispatch(mdWQitem *);
|
||||||
|
void run() {}
|
||||||
|
|
||||||
|
virtual void processEvent(const cdHeartbeat &ev);
|
||||||
|
virtual void processEvent(const cdTelemetryFrame &ev);
|
||||||
|
virtual void processEvent(const cdInteractiveCommand &ev);
|
||||||
|
virtual void processEvent(const cdIncoming &ev);
|
||||||
|
virtual void processEvent(const cdResponse &ev);
|
||||||
|
virtual void processEvent(const cdShutdown &ev);
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef CLIEVER_CONFIG
|
||||||
|
#define CLIEVER_CONFIG
|
||||||
|
|
||||||
|
using namespace boost::gregorian;
|
||||||
|
using namespace boost::posix_time;
|
||||||
|
|
||||||
|
class mdDataSource {
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
std::string fullName;
|
||||||
|
int port;
|
||||||
|
int ip;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string,mdDataSource*> localSourcesByClaimedName;
|
||||||
|
|
||||||
|
class clientDaemonConfig {
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool runCommander;
|
||||||
|
bool terminateRequest;
|
||||||
|
char configPath[256],logPath[256],origCmd[32];
|
||||||
|
pid_t clipsProcess;
|
||||||
|
pid_t daemonProcess;
|
||||||
|
pid_t shellProcess;
|
||||||
|
std::string mdAddress;
|
||||||
|
std::string deviceName;
|
||||||
|
std::string telemetryPortStr;
|
||||||
|
int cluster,
|
||||||
|
debugThreshold,
|
||||||
|
instruments[MAX_INSTRUMENTS];
|
||||||
|
int telemetryPort; // talks to central server with this
|
||||||
|
date epoch(CD_EPOCH);
|
||||||
|
localSourcesByClaimedName localDevices;
|
||||||
|
|
||||||
|
clientDaemonConfig() { terminateRequest = false;
|
||||||
|
mdAddress = std::string(MD_DEFAULT_IP);
|
||||||
|
strcpy(configPath,"./");
|
||||||
|
deviceName = std::string("TEST");
|
||||||
|
debugThreshold = MAX_DEBUG;
|
||||||
|
strcpy(logPath,"/tmp");
|
||||||
|
runCommander = true;
|
||||||
|
memset(instruments,0,sizeof(instruments));
|
||||||
|
}
|
||||||
|
|
||||||
|
int loadMachineConfiguration();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct CD_GLOBAL {
|
||||||
|
char id[7];
|
||||||
|
pid_t daemon_pid;
|
||||||
|
bool cmdrShutdown;
|
||||||
|
bool graceful;
|
||||||
|
}
|
||||||
|
auc_cd_global;
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,23 @@
|
||||||
|
#ifndef MD_CHARGUI
|
||||||
|
#define MD_CHARGUI
|
||||||
|
|
||||||
|
class mdCommander {
|
||||||
|
|
||||||
|
bool acceptingInput;
|
||||||
|
bool SCPImode; // false implies CLIPS mode
|
||||||
|
int mdStdDevIdx;
|
||||||
|
std::string currentDevice;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
mdCommander() {mdStdDevIdx=0;}
|
||||||
|
~mdCommander() {}
|
||||||
|
|
||||||
|
void driver();
|
||||||
|
void greet();
|
||||||
|
void help();
|
||||||
|
bool scpi(char *command);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,104 @@
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <xmlrpc-c/base.hpp>
|
||||||
|
#include <xmlrpc-c/client_simple.hpp>
|
||||||
|
#define XMLRPC_C
|
||||||
|
#include "tools.h"
|
||||||
|
#include "mdClientBehavior.h"
|
||||||
|
#include "mdClientDevice.h"
|
||||||
|
#include "mdClientState.h"
|
||||||
|
|
||||||
|
#define MD_SERVER_URL "http://localhost:4243/RPC2"
|
||||||
|
#define DEFAULT_DEVICE "ALX"
|
||||||
|
#define EXPECTED_MACHINE_HANDLE 1
|
||||||
|
#define PAUSE_SECS 3
|
||||||
|
|
||||||
|
#ifdef MDCLIENTMAIN
|
||||||
|
|
||||||
|
bool doSanityCheck = false, repeatableOnly = false;
|
||||||
|
|
||||||
|
xmlrpc_env env;
|
||||||
|
xmlrpc_c::clientXmlTransport_libwww myTransport;
|
||||||
|
xmlrpc_c::client_xml myClient(&myTransport);
|
||||||
|
XmlRpcValue::int32 mdServerHandle = 0;
|
||||||
|
|
||||||
|
int pauseSecs=0;
|
||||||
|
const char *defaultDevice,*serverURL;
|
||||||
|
std::string phase;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
extern bool doSanityCheck, repeatableOnly;
|
||||||
|
|
||||||
|
extern xmlrpc_env env;
|
||||||
|
extern xmlrpc_c::clientXmlTransport_libwww myTransport;
|
||||||
|
extern xmlrpc_c::client_xml myClient;
|
||||||
|
extern XmlRpcValue::int32 mdServerHandle;
|
||||||
|
extern const char *defaultDevice,*serverURL;
|
||||||
|
extern int pauseSecs;
|
||||||
|
extern std::string phase;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class mdCoreAPITestSuite : public testSuite {
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
The object of this class tests the MD core API.
|
||||||
|
|
||||||
|
Some day, we would like to automate its generate
|
||||||
|
with that of the client objects it tests.
|
||||||
|
|
||||||
|
Unlike the "new" xmlrpc-c test style, we do count
|
||||||
|
successes and failures and attempt to execute the
|
||||||
|
entire suite.
|
||||||
|
-----------------------------------------------------------------------------*/
|
||||||
|
public:
|
||||||
|
|
||||||
|
mdClientState *testState;
|
||||||
|
mdClientDevice *thisClient;
|
||||||
|
mdClientBehavior *testBehavior;
|
||||||
|
|
||||||
|
virtual std::string suiteName() {
|
||||||
|
return "Phase I UAT Suite";
|
||||||
|
}
|
||||||
|
void bucket00(char const *title) {
|
||||||
|
|
||||||
|
std::cout << "\nTest Bucket: " << title << std::endl;
|
||||||
|
TEST(mdServerHandle = thisClient->registeR( 0, defaultDevice));
|
||||||
|
|
||||||
|
}
|
||||||
|
void bucket01(char const *title);
|
||||||
|
void bucket02(char const *title);
|
||||||
|
void bucket03(char const *title);
|
||||||
|
void bucket04(char const *title);
|
||||||
|
void bucket05(char const *title);
|
||||||
|
void bucket06(char const *title);
|
||||||
|
|
||||||
|
virtual void runtests(unsigned int const) {
|
||||||
|
|
||||||
|
char testContext[256];
|
||||||
|
mdClientState mdState(serverURL);
|
||||||
|
mdClientDevice mdClient(serverURL);
|
||||||
|
mdClientBehavior mdBehavior(serverURL);
|
||||||
|
|
||||||
|
testState = &mdState;
|
||||||
|
thisClient = &mdClient;
|
||||||
|
testBehavior = &mdBehavior;
|
||||||
|
|
||||||
|
tests = failures = 0;
|
||||||
|
|
||||||
|
sprintf(testContext,"Get handle for device: %s to test against: %s\n",defaultDevice,serverURL);
|
||||||
|
if (!mdServerHandle)
|
||||||
|
bucket00(testContext);
|
||||||
|
bucket01("Check predefined observables access.\n");
|
||||||
|
bucket02("Check for required SCPI subsystems for the selected device.\n");
|
||||||
|
if (!repeatableOnly)
|
||||||
|
bucket03("Check dynamic definition of remaining specified observables.\n");
|
||||||
|
bucket04("Check event/rule mechanism.\n");
|
||||||
|
bucket05("Check SCPI execution.\n");
|
||||||
|
bucket06("Check datagram layer operations.\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,537 @@
|
||||||
|
/**
|
||||||
|
* \mainpage AusReg Cliever
|
||||||
|
*
|
||||||
|
* <br><hr>
|
||||||
|
*
|
||||||
|
* \par About
|
||||||
|
* \par
|
||||||
|
* <a href="http://dnseppus.meansofproduction.biz/doc/ausregcliever">The Delivery Document Subsite</a>
|
||||||
|
*
|
||||||
|
* \htmlonly
|
||||||
|
* \endhtmlonly
|
||||||
|
*
|
||||||
|
* <br><hr>
|
||||||
|
*
|
||||||
|
* \par AusReg Cliever requirements
|
||||||
|
*
|
||||||
|
* This program suite was originally developed on Debian Wheezy 64 but
|
||||||
|
* should compile on any Unix where all of the requirements are present.
|
||||||
|
*
|
||||||
|
* <br><hr>
|
||||||
|
*
|
||||||
|
* \par Access source code
|
||||||
|
*
|
||||||
|
* Developers Repository
|
||||||
|
*
|
||||||
|
* - To pull from my git repo:
|
||||||
|
* - \verbatim git clone drde@git.meansofproduction.biz:/git/DRDE \endverbatim
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <br><hr>
|
||||||
|
*
|
||||||
|
* \par Top Level External Dependencies... and version currently used
|
||||||
|
* <br>
|
||||||
|
* \b boost: 1.49 <br>
|
||||||
|
* \b log4cpp: 1.0 <br>
|
||||||
|
* \b sigc++: 2.0 <br>
|
||||||
|
* <br>
|
||||||
|
* The above is a covering set of dependencies, everything else required for unix builds should be in the git repo or with AusReg EPP TK.
|
||||||
|
*
|
||||||
|
* <br><hr>
|
||||||
|
*
|
||||||
|
* accommon.h - Core Daemon Level definitions.
|
||||||
|
*
|
||||||
|
* \par Authors Support Site
|
||||||
|
*
|
||||||
|
* \htmlonly <a href=http://dnseppus.meansofproduction.biz>DNS EPP Upgrade Service</a> \endhtmlonly
|
||||||
|
*
|
||||||
|
* \par License
|
||||||
|
* See the licenses section of the Latex2HTML document
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MD_COMMON
|
||||||
|
#define MD_COMMON
|
||||||
|
|
||||||
|
#include<boost/asio/datagram_socket_service.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using boost::asio::ip::udp;
|
||||||
|
|
||||||
|
#define MAX_CLIENTS 1000
|
||||||
|
#define MAX_CLIEVER 10
|
||||||
|
#define MAX_DATACLIENTS 200
|
||||||
|
#define MAX_EPP_SERVERS 3 .
|
||||||
|
#define MAX_DEBUG 1000 // Set the config parm higher than this to inhibit logNdebug(m...) where m < this
|
||||||
|
#define MAX_HOST (((MAX_CLIEVER + 1) * MAX_EPP_SERVERS) + MAX_CLIENTS)
|
||||||
|
#ifndef MD_STAGE
|
||||||
|
#define CD_DEFAULT_IP "192.168.0.9"
|
||||||
|
#define MD_DEFAULT_IP "192.168.0.5"
|
||||||
|
#define PULL_MD_LOG "cp /somejuan/tmp/-md.log ."
|
||||||
|
#else
|
||||||
|
#define CD_DEFAULT_IP "184.168.64.86"
|
||||||
|
#define MD_DEFAULT_IP "178.79.142.228"
|
||||||
|
#define PULL_MD_LOG ("scp drde@" MD_DEFAULT_IP "/tmp/-md.log .")
|
||||||
|
#endif
|
||||||
|
#define MD_EPOCH date()
|
||||||
|
#define MD_HEARTBEAT 1 // Network peer heartbeat in seconds.
|
||||||
|
#define MD_MAX_DATAGRAM (32*1024) // half of the IPV4 max
|
||||||
|
#define AC_APP "Generic"
|
||||||
|
#define AC_COMPONENT "Master Daemon" // AC Component
|
||||||
|
#define AC_NAME AC_APP " " AC_COMPONENT
|
||||||
|
#define MD_VERSION " 1.1 " // DACLIPS Version
|
||||||
|
#define MD_REFRESH 10 // default milliseconds between APIG frame updates
|
||||||
|
#define MD_TYPE "EPPREGISTRAR"
|
||||||
|
#define NORMAL_DEBUG 10
|
||||||
|
#ifndef CURRENT_DEBUG
|
||||||
|
#define CURRENT_DEBUG NORMAL_DEBUG
|
||||||
|
#endif
|
||||||
|
#define NOT_OK -1
|
||||||
|
#define OK 0
|
||||||
|
#define RUNNING_DIR "/tmp"
|
||||||
|
|
||||||
|
#define theMachine thisConfig->machine[thisConfig->thisMachineContext]
|
||||||
|
|
||||||
|
enum md_mand {
|
||||||
|
MD_NAM, // Not a Mand.
|
||||||
|
MD_USER_MAND, // User defined mand type
|
||||||
|
MD_SCPI,
|
||||||
|
MD_RULE_ACTION,
|
||||||
|
MD_CLIEVER_CMD, // From CD command loop or other UI
|
||||||
|
MD_CLIENT_CMD, // From XMLRPC
|
||||||
|
MD_NMANDS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mdErrorCode { // In auc-md/kb index to masterDaemonConfig.err
|
||||||
|
MDERR_OK,
|
||||||
|
MDERR_MISSING,
|
||||||
|
MDERR_EXISTS,
|
||||||
|
MDERR_CONFLICT,
|
||||||
|
MDERR_NOTREADY,
|
||||||
|
MDERR_SYNTAX,
|
||||||
|
N_MDSTDERR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum md_dispatch_category {
|
||||||
|
MD_NEWBORN = 0, // inbound this isn't dispatched
|
||||||
|
CD_FRAME,
|
||||||
|
MD_FRAME,
|
||||||
|
CD_MDQUERY,
|
||||||
|
MD_SHUTDOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
enum md_host {
|
||||||
|
MDDEV_MD = 0,
|
||||||
|
MDDEV_CD,
|
||||||
|
MDDEV_PEER,
|
||||||
|
MACHINE,
|
||||||
|
N_MDDEV_TYPES
|
||||||
|
};
|
||||||
|
|
||||||
|
enum md_reserved {
|
||||||
|
MD_RESERVED_UNDEFINED = 0,
|
||||||
|
N_MD_RESERVED
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mdDGtype {
|
||||||
|
MDDG_HEARTBEAT = 0,
|
||||||
|
MDDG_DEVICEHB,
|
||||||
|
MDDG_NEWBORN,
|
||||||
|
MDDG_MDQUERY,
|
||||||
|
MDDG_REGSCPI,
|
||||||
|
MDDG_REGOBS,
|
||||||
|
MDDG_REGODE,
|
||||||
|
MDDG_TELEMETRY,
|
||||||
|
MDDG_CDRESET,
|
||||||
|
N_MDDG_TYPES
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct MD_DG_TYPE {
|
||||||
|
unsigned inBandOnly : 1;
|
||||||
|
unsigned requiresAck : 1;
|
||||||
|
unsigned isAckNak : 1;
|
||||||
|
unsigned value : 1; // i.e. boolean for ack/nak etc. where true = ack.
|
||||||
|
unsigned reserved : 4;
|
||||||
|
unsigned clieverGroup : 8; // masterDaemonConfig.thisMachineContext
|
||||||
|
unsigned reserved2 : 16;
|
||||||
|
}
|
||||||
|
mdDGflags;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct MD_DG_HEADER {
|
||||||
|
mdDGtype msgType;
|
||||||
|
mdDGflags dgType;
|
||||||
|
mdDGtype dgSubType;
|
||||||
|
int msgSN; // Ordinal in a dialog
|
||||||
|
md_device clientType;
|
||||||
|
int sourceHandle;
|
||||||
|
int sinkHandle;
|
||||||
|
int handle; // for example if query about a device other than source or sink.
|
||||||
|
mdErrorCode ec;
|
||||||
|
int payloadSize;
|
||||||
|
int primeOffset; // for example to the name associated with the data
|
||||||
|
}
|
||||||
|
mdDGHeader;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct MD_DATAGRAM {
|
||||||
|
mdDGHeader hdr;
|
||||||
|
char payLoad[MD_MAX_DATAGRAM - (sizeof(mdDGHeader))];
|
||||||
|
}
|
||||||
|
mdDatagram;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct MD_REPLY {
|
||||||
|
mdDGHeader hdr;
|
||||||
|
char payLoad[512 - sizeof(mdDGHeader)];
|
||||||
|
}
|
||||||
|
mdDGReply;
|
||||||
|
|
||||||
|
class mdReply {
|
||||||
|
public:
|
||||||
|
|
||||||
|
mdDGReply dg;
|
||||||
|
|
||||||
|
mdReply() {memset((void *)&dg,0,sizeof(mdDGReply));
|
||||||
|
dg.hdr.dgType.isAckNak = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (defined(MD_MAIN) || defined(CD_MAIN) )
|
||||||
|
const char *hostTypes[N_MDDEV_TYPES ] = { "Master Daemon", "Cliever", "Machine" };
|
||||||
|
#else
|
||||||
|
extern const char *clientTypes[N_MDDEV_TYPES];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* \brief mdProcess
|
||||||
|
* Abstract base class of various subprocesses
|
||||||
|
*
|
||||||
|
* AC is a distributed system with various subprocesses
|
||||||
|
* spanning the central server, the 'Cliever' middleware components and clients.
|
||||||
|
* Root class for these.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
class mdWQitem {
|
||||||
|
public:
|
||||||
|
md_dispatch_category kind;
|
||||||
|
const void *what;
|
||||||
|
int user; // User defined
|
||||||
|
mdWQitem (const void *work,md_dispatch_category priority,int x)
|
||||||
|
: what(work), kind(priority), user(x) {}
|
||||||
|
|
||||||
|
bool operator< (const mdWQitem & right) const {
|
||||||
|
return kind < right.kind;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::priority_queue < mdWQitem* > MDWQ;
|
||||||
|
|
||||||
|
class mdProcess {
|
||||||
|
public: MDWQ q;
|
||||||
|
mdProcess() {}
|
||||||
|
~mdProcess() {}
|
||||||
|
|
||||||
|
void queue(mdWQitem *w) {q.push(w);}
|
||||||
|
virtual void dispatch(mdWQitem *w)=0;
|
||||||
|
virtual void run() = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
#define MD_DEFAULT_DEVICE_PROTOCOL 0
|
||||||
|
#define MD_DEFAULT_RULE 0
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct {
|
||||||
|
unsigned open:1;
|
||||||
|
unsigned looped:1; // back channel established from passive connection.
|
||||||
|
unsigned reserved:30;
|
||||||
|
} mdCnctBool;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct MD_CONTROL_BLOCK
|
||||||
|
{int handle; // debug mark
|
||||||
|
mdCnctBool connection;
|
||||||
|
boost::asio::ip::udp::endpoint ep;
|
||||||
|
boost::asio::ip::udp::resolver::iterator it;
|
||||||
|
boost::asio::ip::udp::socket *udp;
|
||||||
|
MD_CONTROL_BLOCK() {
|
||||||
|
handle = 0;
|
||||||
|
memset((void *)&connection,0,sizeof(connection));
|
||||||
|
udp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mdCB;
|
||||||
|
|
||||||
|
typedef std::map<int,mdCB*> mdStdDevicePODMap; // MD Standard Device Map -
|
||||||
|
/*
|
||||||
|
*\brief stdDev: collection with MD at: 0, CDs in: 1 - MAX_CLIEVER,
|
||||||
|
* EPPSERVERS in: MAX_CLIEVER+2 - MAX_CLIEVER+2+MAX_EPPSERVER
|
||||||
|
*
|
||||||
|
* The mdStdDevIdx of a host is its index above.
|
||||||
|
* Within intervals clients are assigned compactly in the same order as thier handles are created and assigned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if (defined(MD_MAIN) || defined(CD_MAIN) || defined(TK_DLL_MAIN))
|
||||||
|
mdStdDevicePODMap cb;
|
||||||
|
int myStdDevIdx=MAX_CLIENTS+1; // global default to localhost
|
||||||
|
#else
|
||||||
|
extern mdStdDevicePODMap cb;
|
||||||
|
extern int myStdDevIdx;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class mdDGChannel
|
||||||
|
{public:
|
||||||
|
|
||||||
|
boost::asio::io_service& io_service_;
|
||||||
|
boost::asio::ip::udp::endpoint p_endpoint_;
|
||||||
|
boost::asio::ip::udp::endpoint a_endpoint_;
|
||||||
|
boost::asio::ip::udp::endpoint *ep_;
|
||||||
|
boost::asio::ip::udp::resolver *r;
|
||||||
|
boost::asio::ip::udp::resolver::query *q;
|
||||||
|
boost::asio::ip::udp::socket passive_;
|
||||||
|
boost::asio::ip::udp::socket *active_;
|
||||||
|
boost::asio::ip::udp::socket *s_;
|
||||||
|
|
||||||
|
char ack_[sizeof(mdDGReply)];
|
||||||
|
char data_[MD_MAX_DATAGRAM];
|
||||||
|
|
||||||
|
int mdStdDevIdx;
|
||||||
|
|
||||||
|
mdDatagram *inProcess;
|
||||||
|
mdReply *reply;
|
||||||
|
|
||||||
|
short port;
|
||||||
|
|
||||||
|
mdDGChannel(boost::asio::io_service& io_service,
|
||||||
|
short inport, int stdDevIdx=myStdDevIdx)
|
||||||
|
: io_service_(io_service), mdStdDevIdx(stdDevIdx),
|
||||||
|
passive_(io_service, udp::endpoint(udp::v4(), inport))
|
||||||
|
{
|
||||||
|
inProcess = (mdDatagram *)data_;
|
||||||
|
ep_ = &p_endpoint_;
|
||||||
|
port = inport;
|
||||||
|
reply = (mdReply *)ack_;
|
||||||
|
q = NULL;
|
||||||
|
r = NULL;
|
||||||
|
s_ = &passive_;
|
||||||
|
|
||||||
|
passive_.async_receive_from(
|
||||||
|
boost::asio::buffer(data_, MD_MAX_DATAGRAM), p_endpoint_,
|
||||||
|
boost::bind(&mdDGChannel::handle_receive_from, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
|
||||||
|
void async_send(mdDatagram &dg) {
|
||||||
|
|
||||||
|
size_t dgSize = sizeof(mdDGHeader) + dg.hdr.payloadSize;
|
||||||
|
|
||||||
|
*inProcess = dg;
|
||||||
|
//std::memcpy(this->data_,(char *)&dg,dgSize);
|
||||||
|
|
||||||
|
active_->async_send_to(
|
||||||
|
boost::asio::buffer(data_, dgSize), *ep_,
|
||||||
|
boost::bind(&mdDGChannel::handle_send_to, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connect_to (std::string &host, std::string &port, int stdDevIdx=-1) {
|
||||||
|
|
||||||
|
bool value = false;
|
||||||
|
int rport = atoi(port.c_str());
|
||||||
|
boost::system::error_code ec;
|
||||||
|
boost::asio::ip::udp::endpoint remote ( boost::asio::ip::address::from_string(host.c_str()), rport);
|
||||||
|
|
||||||
|
stdDevIdx = (stdDevIdx == -1) ? mdStdDevIdx : stdDevIdx;
|
||||||
|
map<int,mdCB *>::iterator iter = cb.find(stdDevIdx);
|
||||||
|
if( iter == cb.end() ) cb[stdDevIdx] = new mdCB();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!r) r = new udp::resolver(io_service_);
|
||||||
|
if ( q) delete q;
|
||||||
|
q = new udp::resolver::query(udp::v4(), host.c_str(), port.c_str());
|
||||||
|
cb[stdDevIdx]->it = r->resolve(*q);
|
||||||
|
if (!cb[mdStdDevIdx]->udp)
|
||||||
|
cb[mdStdDevIdx]->udp = new udp::socket(io_service_, udp::endpoint(udp::v4(), 0));
|
||||||
|
active_ = cb[mdStdDevIdx]->udp;
|
||||||
|
if (active_->is_open())
|
||||||
|
active_->connect(remote,ec);
|
||||||
|
|
||||||
|
if (!ec) value = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(...) {}
|
||||||
|
|
||||||
|
return (cb[stdDevIdx]->connection.open=value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connect_to (boost::asio::ip::udp::endpoint &ep,boost::system::error_code &ec,int &step,int stdDevIdx=-1)
|
||||||
|
{
|
||||||
|
|
||||||
|
bool value = false;
|
||||||
|
|
||||||
|
stdDevIdx = stdDevIdx == -1 ? mdStdDevIdx : stdDevIdx;
|
||||||
|
map<int,mdCB *>::iterator iter = cb.find(stdDevIdx);
|
||||||
|
if( iter == cb.end() ) cb[stdDevIdx] = new mdCB();
|
||||||
|
|
||||||
|
try { if (cb[stdDevIdx]->udp) {if (cb[stdDevIdx]->udp->is_open())
|
||||||
|
cb[stdDevIdx]->udp->close();
|
||||||
|
delete cb[stdDevIdx]->udp;}
|
||||||
|
|
||||||
|
cb[stdDevIdx]->ep = ep;
|
||||||
|
active_ = cb[stdDevIdx]->udp = new boost::asio::ip::udp::socket( io_service_ , udp::endpoint(udp::v4(), 0) );
|
||||||
|
ec.clear();
|
||||||
|
active_->connect( cb[stdDevIdx]->ep, ec );
|
||||||
|
if (active_->is_open()) { value = true; cb[stdDevIdx]->connection.open=1; }
|
||||||
|
else {
|
||||||
|
step++;
|
||||||
|
active_->open( udp::v4(), ec );
|
||||||
|
if (active_->is_open()) {value = true; cb[stdDevIdx]->connection.open=1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch(boost::system::system_error &be) {boost::system::system_error warning = be;}
|
||||||
|
catch(...) {}
|
||||||
|
|
||||||
|
return (value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd);
|
||||||
|
|
||||||
|
void handle_send_to(const boost::system::error_code& asioEC, size_t sentByes)
|
||||||
|
{
|
||||||
|
size_t dgSize = inProcess->hdr.dgType.requiresAck
|
||||||
|
? sizeof(mdReply) : sizeof(mdDatagram);
|
||||||
|
|
||||||
|
// std::string debugMsg = asioEC.message();
|
||||||
|
|
||||||
|
if (inProcess->hdr.dgType.requiresAck)
|
||||||
|
active_->async_receive_from(
|
||||||
|
boost::asio::buffer(ack_, dgSize), *ep_,
|
||||||
|
boost::bind(&mdDGChannel::handle_receive_from, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
else
|
||||||
|
active_->async_receive_from(
|
||||||
|
boost::asio::buffer(data_, dgSize), *ep_,
|
||||||
|
boost::bind(&mdDGChannel::handle_receive_from, this,
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool send(mdDatagram &dg) {
|
||||||
|
|
||||||
|
size_t dgSize = sizeof(mdDGHeader) + dg.hdr.payloadSize;
|
||||||
|
|
||||||
|
return (dgSize ==
|
||||||
|
active_->send(boost::asio::buffer((void *)&dg, dgSize)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool send_to(mdDatagram &dg, int mdStdDevIdx) {
|
||||||
|
|
||||||
|
size_t dgSize = sizeof(mdDGHeader) + dg.hdr.payloadSize;
|
||||||
|
|
||||||
|
return (dgSize ==
|
||||||
|
active_->send_to(boost::asio::buffer((void *)&dg, dgSize), *cb[mdStdDevIdx]->it));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t send(mdReply &dg, boost::system::error_code &ec) {
|
||||||
|
|
||||||
|
size_t dgSize = sizeof(mdDGReply);
|
||||||
|
boost::asio::socket_base::message_flags flags=0;
|
||||||
|
|
||||||
|
return (active_->send(boost::asio::buffer((void *)&dg, dgSize), flags, ec));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t send_back(mdReply &dg, boost::system::error_code &ec, int &step) {
|
||||||
|
|
||||||
|
size_t dgSize = sizeof(mdDGReply);
|
||||||
|
boost::asio::socket_base::message_flags flags=0;
|
||||||
|
step = 1;
|
||||||
|
|
||||||
|
a_endpoint_ = passive_.remote_endpoint(ec);
|
||||||
|
|
||||||
|
if (ec) return 0;
|
||||||
|
|
||||||
|
return (passive_.send_to(boost::asio::buffer((void *)&dg, dgSize), a_endpoint_, flags, ec));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool send_to(mdReply &dg,int mdStdDevIdx) {
|
||||||
|
|
||||||
|
size_t dgSize = sizeof(mdDGReply);
|
||||||
|
|
||||||
|
return (dgSize ==
|
||||||
|
active_->send_to(boost::asio::buffer((void *)&dg, dgSize), *cb[mdStdDevIdx]->it));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(_WIN32_WINNT) && !defined(DllExport) && defined(DV_DLL)
|
||||||
|
#pragma warning( disable: 4251 )
|
||||||
|
#define DllExport __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define DllExport
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef std::map<int,std::string> mdErrMsgMap;
|
||||||
|
|
||||||
|
class DllExport mdError {
|
||||||
|
|
||||||
|
int instance;
|
||||||
|
mdErrMsgMap text;
|
||||||
|
|
||||||
|
public:
|
||||||
|
mdError() { text[0] = std::string("OK");
|
||||||
|
instance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~mdError() {}
|
||||||
|
|
||||||
|
// The below populate the additional messages;
|
||||||
|
// Instances below 1000 are reserved for system errors, negative
|
||||||
|
// integers not used.
|
||||||
|
// Users derive from this class and implement additionalUsrMsgs.
|
||||||
|
|
||||||
|
void additionalUserMsg(int instCode,const char *msgText)
|
||||||
|
{if (instCode >= 1000) text[instCode] = std::string(msgText);}
|
||||||
|
void additionalSystemMsg(int instCode,const char *msgText)
|
||||||
|
{if (instCode < 1000 && instCode >0) text[instCode] = std::string(msgText);}
|
||||||
|
|
||||||
|
int get() {return instance;}
|
||||||
|
void get(mdError **parentPtr)
|
||||||
|
{*parentPtr = this;}
|
||||||
|
void set(int i) {instance = i;}
|
||||||
|
|
||||||
|
const char *what(char *buffer=NULL) {
|
||||||
|
if (text.find(get()) == text.end()) {
|
||||||
|
{if (!buffer) return NULL;
|
||||||
|
sprintf(buffer,"Unknown error code: %d",get());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
return text[get()].c_str();
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class mdDG {
|
||||||
|
public:
|
||||||
|
mdDatagram dg;
|
||||||
|
|
||||||
|
mdDG() {memset(&dg,0,sizeof(mdDatagram));}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,26 +1,37 @@
|
||||||
LOCATION=authoring
|
LOCATION=authoring
|
||||||
#
|
#
|
||||||
# Add other locations as needed.
|
# Add other locations and move target differences into the macros as needed
|
||||||
#
|
#
|
||||||
CC=g++
|
CC=g++
|
||||||
Cc=gcc
|
Cc=gcc
|
||||||
|
|
||||||
#ifeq ($(LOCATION),authoring)
|
|
||||||
BOSTLIB=-L/usr/lib/boost
|
BOSTLIB=-L/usr/lib/boost
|
||||||
BOSINCL=-L/usr/include/boost
|
BOSINCL=-L/usr/include/boost
|
||||||
ARTKLIB=
|
LOG4LIB=-L/usr/lib
|
||||||
ARTKINCL=
|
|
||||||
|
#ifeq ($(LOCATION),authoring)
|
||||||
|
ARTKLIB=-L/home/jdaugherty/clients/reg.de/git/AusRegEPPTk/build
|
||||||
|
ARTKINCL=I/home/jdaugherty/clients/reg.de/git/AusRegEPPTk/common
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SLIBS= -L/usr/lib $(BOSTLIB) $(LOG4LIB) -l boost_system -l boost_thread
|
#ifeq ($(LOCATION),testing)
|
||||||
|
ARTKLIB=-L/home/drdejdaugherty/clients/reg.de/git/AusRegEPPTk/build
|
||||||
|
ARTKINCL=I/home/jdaugherty/clients/reg.de/git/AusRegEPPTk/common
|
||||||
|
#endif
|
||||||
|
|
||||||
ARTKFLAGS=-shared -fPIC -Wl,-soname,libAusRegEPPTK.so
|
SLIBS= -L/usr/lib $(BOSTLIB) $(LOG4LIB) -l boost_system -l boost_thread -l log4cpp
|
||||||
|
|
||||||
ifeq ($(LOCATION),authoring)
|
ifeq ($(LOCATION),authoring)
|
||||||
SINCL= -I include -I /usr/include/log4cpp $(BOSINCL)
|
SINCL= -I include -I /usr/include/log4cpp $(BOSINCL)
|
||||||
CFLAGS= -DCURRENT_DEBUG=1000
|
CFLAGS= -DCURRENT_DEBUG=1000 -DPRODUCTION=0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LOCATION),production)
|
||||||
|
SINCL= -I include -I /usr/include/log4cpp $(BOSINCL)
|
||||||
|
CFLAGS= -DPRODUCTION=1
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
CLIBS= -L$(USRLIB)
|
CLIBS= -L$(USRLIB)
|
||||||
|
|
||||||
CLFLAGS= -Wall -Wundef -Wpointer-arith -Wshadow \
|
CLFLAGS= -Wall -Wundef -Wpointer-arith -Wshadow \
|
||||||
|
@ -28,6 +39,9 @@ CLFLAGS= -Wall -Wundef -Wpointer-arith -Wshadow \
|
||||||
-Wmissing-prototypes -Wnested-externs \
|
-Wmissing-prototypes -Wnested-externs \
|
||||||
-Wstrict-prototypes -Waggregate-return -Wno-implicit
|
-Wstrict-prototypes -Waggregate-return -Wno-implicit
|
||||||
|
|
||||||
|
ACOBJS= build/cliever.o build/mdLogger.o build/masterDaemonConfig.o build/masterDaemon.o \
|
||||||
|
build/mdHost.o
|
||||||
|
|
||||||
# --- targets
|
# --- targets
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -46,8 +60,17 @@ build/mdLogger.o: server/mdLogger.cpp include/mdLogger.h
|
||||||
build/cliever.o: server/cliever-md.cpp include/*.h
|
build/cliever.o: server/cliever-md.cpp include/*.h
|
||||||
$(CC) $(CFLAGS) server/cliever-md.cpp -c -o build/cliever.o $(SINCL)
|
$(CC) $(CFLAGS) server/cliever-md.cpp -c -o build/cliever.o $(SINCL)
|
||||||
|
|
||||||
build/drde-cliever: build/cliever.o build/mdLogger.o
|
build/masterDaemonConfig.o: server/masterDaemonConfig.cpp include/*.h
|
||||||
$(CC) $(CFLAGS) -o build/cliever $(SINCL) $(LIBS) build/mdLogger.o $(SLIBS)
|
$(CC) $(CFLAGS) server/masterDaemonConfig.cpp -c -o build/masterDaemonConfig.o $(SINCL)
|
||||||
|
|
||||||
|
build/mdHost.o: server/mdHost.cpp include/*.h
|
||||||
|
$(CC) $(CFLAGS) server/mdHost.cpp -c -o build/mdHost.o $(SINCL)
|
||||||
|
|
||||||
|
build/masterDaemon.o: server/masterDaemon.cpp include/*.h
|
||||||
|
$(CC) $(CFLAGS) server/masterDaemon.cpp -c -o build/masterDaemon.o $(SINCL)
|
||||||
|
|
||||||
|
build/drde-cliever: $(ACOBJS)
|
||||||
|
$(CC) $(CFLAGS) -o build/drde-cliever $(SINCL) $(LIBS) $(ACOBJS) $(SLIBS)
|
||||||
|
|
||||||
doxygen/index.html: etc/doxygen.config
|
doxygen/index.html: etc/doxygen.config
|
||||||
doxygen etc/doxygen.config
|
doxygen etc/doxygen.config
|
||||||
|
|
|
@ -1,63 +1,118 @@
|
||||||
|
#ifndef LISTENER_H
|
||||||
|
#define LISTENER_H
|
||||||
|
|
||||||
/**
|
/** \file
|
||||||
\class Listener
|
Class template definition file.
|
||||||
|
|
||||||
Derive your class from a Listener<EvType>, to give it the
|
\copyright
|
||||||
ability to hear (i.e. receive, listen to) events of type
|
Copyright (C) 2002, 2003 Oliver Schoenborn
|
||||||
EvType. EvType is a fundamental type (bool, int, float,
|
|
||||||
etc), a struct or a class of your choice. You must define
|
|
||||||
Listener<EvType>::processEvent() in your Listener<EvType>
|
|
||||||
subclass. You call listenForEvents() on your listener
|
|
||||||
instance (at least once) for it to be able to hear (i.e.
|
|
||||||
receive) any EvType event, and you call ignoreEvents() on
|
|
||||||
the instance so it will no longer receive events of type
|
|
||||||
EvType.
|
|
||||||
|
|
||||||
\note
|
|
||||||
- Do not assume that the Listeners will receive the generated event in
|
|
||||||
the same order as they registered.
|
|
||||||
- A class can listen to more than one type of event by inheriting
|
|
||||||
from more than one type of listener. Calling listenForEvents()
|
|
||||||
then is done by specifying which listenForEvents() to call, e.g.
|
|
||||||
\code
|
|
||||||
class YourListener:
|
|
||||||
public Listener<TicEvent>, public Listener<TacEvent>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
YourListener() {
|
|
||||||
Listener<TicEvent>::listenForEvents();
|
|
||||||
Listener<TacEvent>::listenForEvents();
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
virtual void processEvent(const TicEvent& event) {...}
|
|
||||||
virtual void processEvent(const TacEvent& event) {...}
|
|
||||||
};
|
|
||||||
\endcode
|
|
||||||
- If a subclass of your class must also process an event, remember
|
|
||||||
that because its processEvent is virtual, it will be the first
|
|
||||||
one called. Therefore it should call its base class method:
|
|
||||||
\code
|
|
||||||
struct TicEvent {...};
|
|
||||||
class YourListener: public Listener<TicEvent> {...};
|
|
||||||
class DerivedListener: public YourListener
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// ...
|
|
||||||
protected:
|
|
||||||
virtual void processEvent(const TicEvent& event)
|
|
||||||
{
|
|
||||||
// give parent class a chance to process event
|
|
||||||
YourListener::processEvent(event);
|
|
||||||
// do our stuff ...
|
|
||||||
}
|
|
||||||
};
|
|
||||||
\endcode
|
|
||||||
- ignoreThisEvent(): You can call it (from inside
|
|
||||||
processEvent()) to tell EventSender<EvType> that you will be ignoring
|
|
||||||
the event received. This can be a useful way to signify an error in
|
|
||||||
the data sent by the event generator. Just keep in mind that the
|
|
||||||
generator of the event may not actually check whether any listener
|
|
||||||
ignored the event (it may not care).
|
|
||||||
|
|
||||||
|
This software is provided 'as-is', without
|
||||||
|
any express or implied warranty. In no event
|
||||||
|
will the authors be held liable for any
|
||||||
|
damages arising from the use of this
|
||||||
|
software.
|
||||||
|
|
||||||
|
You can redistribute it and/or modify it
|
||||||
|
under the terms found in the LICENSE file that
|
||||||
|
is included in the library distribution.
|
||||||
|
\endcopyright
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
template <typename EvType>
|
||||||
|
class Listener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// By default, listener not registered
|
||||||
|
Listener(): _registered(false), _ignoringHeardEvent(false),
|
||||||
|
_processingEvent(false) {}
|
||||||
|
|
||||||
|
/// Automatically deregister ourselves
|
||||||
|
virtual ~Listener() { ignoreEvents(); }
|
||||||
|
|
||||||
|
void ignoreEvents();
|
||||||
|
void listenForEvents();
|
||||||
|
void ignoreThisEvent();
|
||||||
|
inline void processEventPublic(const EvType&);
|
||||||
|
|
||||||
|
/** Is this instance of listener registered?
|
||||||
|
If not, it will not receive events of type EvType,
|
||||||
|
processEvent() will not be called. To register
|
||||||
|
it, call listenForEvents().
|
||||||
|
\return true if *this is registered
|
||||||
|
*/
|
||||||
|
bool isRegistered() const {return _registered;}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Classes that inherit from Listener must override this
|
||||||
|
method. This is where you react to the \a event heard.
|
||||||
|
\param event the event heard.
|
||||||
|
*/
|
||||||
|
virtual void processEvent(const EvType& event) = 0;
|
||||||
|
|
||||||
|
private: // methods
|
||||||
|
inline void preProcessEvent();
|
||||||
|
inline void postProcessEvent();
|
||||||
|
|
||||||
|
private: // data
|
||||||
|
/** True if our listenForEvents() method has been called,
|
||||||
|
and false otherwise or if ignoreEvents() is called.
|
||||||
|
*/
|
||||||
|
bool _registered;
|
||||||
|
/// are we ignoring this event?
|
||||||
|
bool _ignoringHeardEvent;
|
||||||
|
/// are we ignoring this event?
|
||||||
|
bool _processingEvent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Pre-processing for the event.
|
||||||
|
template <typename EvType>
|
||||||
|
inline void
|
||||||
|
Listener<EvType>::preProcessEvent()
|
||||||
|
{
|
||||||
|
_ignoringHeardEvent = false;
|
||||||
|
_processingEvent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Undo any pre-processing, as required.
|
||||||
|
template <typename EvType>
|
||||||
|
inline void
|
||||||
|
Listener<EvType>::postProcessEvent()
|
||||||
|
{
|
||||||
|
_processingEvent = false;
|
||||||
|
// ignoringHeardEvent doesn't need touching
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Process this event. This public method can be called directly
|
||||||
|
with an event to simulate an event having been generated and heard by
|
||||||
|
this listener. It is also called by EventSender<EvType>::send(). This
|
||||||
|
public method is a "template pattern" method, in that it calls
|
||||||
|
several private methods but most importantly calls the protected,
|
||||||
|
virtual processEvent(). Since the latter is virtual it is the definition
|
||||||
|
in the most derived class of this Listener<EvType> that will get
|
||||||
|
called. The event is passed as const, so listeners can't
|
||||||
|
change the data carried by the event.
|
||||||
|
|
||||||
|
\param event event to process
|
||||||
|
*/
|
||||||
|
template <typename EvType>
|
||||||
|
inline void
|
||||||
|
Listener<EvType>::processEventPublic(const EvType& event)
|
||||||
|
{
|
||||||
|
preProcessEvent();
|
||||||
|
try {
|
||||||
|
processEvent(event);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
postProcessEvent();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
postProcessEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
//#ifdef __GNUG__
|
||||||
|
// because gcc doesn't handle separate template definition
|
||||||
|
//#include "Listener.cc"
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#endif // LISTENER_H
|
||||||
|
|
|
@ -29,24 +29,26 @@ namespace fsm = boost::statechart;
|
||||||
#include "mdcommon.h"
|
#include "mdcommon.h"
|
||||||
#include "mdevents.h"
|
#include "mdevents.h"
|
||||||
#include "mdLogger.h"
|
#include "mdLogger.h"
|
||||||
|
#include "mdBehavior.h"
|
||||||
|
#include "mdHost.h"
|
||||||
|
|
||||||
#define MD_HAUSHALT 1200000 // milliseconds between attention routine
|
#define MD_HAUSHALT 2000 // milliseconds between attention routine
|
||||||
#define MD_LOCK_FILE "cliever-md.lock"
|
#define MD_LOCK_FILE "cliever-md.lock"
|
||||||
|
|
||||||
#include "masterDaemonConfig.h"
|
#include "masterDaemonConfig.h"
|
||||||
|
|
||||||
#ifdef MD_MAIN
|
#ifdef MD_MAIN
|
||||||
|
|
||||||
mdDeviceFabrik *engineFactory;
|
mdHostFabrik *deviceFactory;
|
||||||
mdLogger *theseLogs;
|
mdLogger *theseLogs;
|
||||||
masterDaemonConfig *thisConfig;
|
masterDaemonConfig *thisConfig;
|
||||||
|
|
||||||
extern void runMasterDaemon();
|
extern void runMasterDaemon();
|
||||||
extern void runClientServiceLayer();
|
extern void runAPILayer();
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
extern mdDeviceFabrik *engineFactory;
|
extern mdHostFabrik *deviceFactory;
|
||||||
extern mdLogger *theseLogs;
|
extern mdLogger *theseLogs;
|
||||||
extern masterDaemonConfig *thisConfig;
|
extern masterDaemonConfig *thisConfig;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,239 @@
|
||||||
|
/*! \brief registerDevice
|
||||||
|
* core API.
|
||||||
|
*
|
||||||
|
* Singleton: All Devices must begin their interation with the MD
|
||||||
|
* with this and use the supplied handle sin subsequent
|
||||||
|
* API.
|
||||||
|
*/
|
||||||
|
class registerDevice : public xmlrpc_c::method {
|
||||||
|
private:
|
||||||
|
masterDaemonConfig *_cfg;
|
||||||
|
public:
|
||||||
|
registerDevice(masterDaemonConfig *cfg) {
|
||||||
|
_cfg = cfg;
|
||||||
|
_signature = "i:is";
|
||||||
|
_help = "Register a client with the auc-md. The first parameter is the client type "
|
||||||
|
"which should be the integer value of MDDEV_DATACLIENT (currently 4) "
|
||||||
|
"or other md_dev type value. The string, specifies a signature identifying "
|
||||||
|
"client. Normally the first call to the MD after connecting, the response "
|
||||||
|
"if positive definite is a handle to use in further interaction referring "
|
||||||
|
"to the registered client. This API is primarily intended for data integrators not "
|
||||||
|
"device integrators but device integrators can also use if for diagnostic "
|
||||||
|
"purposes. Execute this API with signature 'release' to remove a MD client "
|
||||||
|
"in which case the first parameter should be the handle for the client to drop. "
|
||||||
|
"Obviously this API can cause havoc with a production MD, so use with care.";
|
||||||
|
}
|
||||||
|
void
|
||||||
|
execute(xmlrpc_c::paramList const& paramList,
|
||||||
|
xmlrpc_c::value * const retvalP) {
|
||||||
|
|
||||||
|
int const handleOrType(paramList.getInt(0));
|
||||||
|
std::string stringField(paramList.getString(1));
|
||||||
|
|
||||||
|
paramList.verifyEnd(2);
|
||||||
|
|
||||||
|
if (stringField == "release")
|
||||||
|
*retvalP = xmlrpc_c::value_int(thisService->releaseDevice(handleOrType));
|
||||||
|
else
|
||||||
|
*retvalP = xmlrpc_c::value_int(thisService->getDeviceHandle(handleOrType,stringField));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
/*! \brief getter
|
||||||
|
* core API.
|
||||||
|
*
|
||||||
|
* Common getter.
|
||||||
|
*/
|
||||||
|
class getter : public xmlrpc_c::method, mdState {
|
||||||
|
public:
|
||||||
|
getter() {
|
||||||
|
_signature = "S:is";
|
||||||
|
_help = "Send handle, dataname, get structure answer. The the first "
|
||||||
|
"character of the dataname determines its type: ODEs "
|
||||||
|
"(Operational Data Elements) start with an underscore, otherwise "
|
||||||
|
"the dataname is that of an expermental Observable. The first "
|
||||||
|
"entry in the structure is always the state of the call which "
|
||||||
|
"will either the supplied dataname indicating success or error text. "
|
||||||
|
"The remainder of the structure is specific to the datatype.";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execute(xmlrpc_c::paramList const& paramList,
|
||||||
|
xmlrpc_c::value * const retvalP) {
|
||||||
|
|
||||||
|
int const deviceHandle(paramList.getInt(0));
|
||||||
|
std::string dataName(paramList.getString(1));
|
||||||
|
paramList.verifyEnd(2);
|
||||||
|
|
||||||
|
*retvalP = *mdState::get(deviceHandle,dataName);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
/*! \brief setter
|
||||||
|
* core API.
|
||||||
|
*
|
||||||
|
* Common setter.
|
||||||
|
*/
|
||||||
|
class setter : public xmlrpc_c::method, mdState {
|
||||||
|
public:
|
||||||
|
setter() {
|
||||||
|
|
||||||
|
_signature = "s:iS";
|
||||||
|
_help = "Process a gotten structure with changes. "
|
||||||
|
"Answers 'OK' or error text";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execute(xmlrpc_c::paramList const& paramList,
|
||||||
|
xmlrpc_c::value * const retvalP) {
|
||||||
|
|
||||||
|
int const deviceHandle(paramList.getInt(0));
|
||||||
|
xmlrpc_c::cstruct returnee(paramList.getStruct(1));
|
||||||
|
paramList.verifyEnd(2);
|
||||||
|
|
||||||
|
*retvalP = xmlrpc_c::value_string(mdState::set(deviceHandle,returnee));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/*! \brief create
|
||||||
|
* create a ndw data element.
|
||||||
|
*
|
||||||
|
* Dynamically create a MD data item.
|
||||||
|
*/
|
||||||
|
class create : public xmlrpc_c::method, mdState {
|
||||||
|
public:
|
||||||
|
create() {
|
||||||
|
|
||||||
|
_signature = "s:iss";
|
||||||
|
_help = "Given a device handle, focus type, and dataname create the element. "
|
||||||
|
"The type string uses the standard xmplrpc-c single character "
|
||||||
|
"type signatures and the name is an MD dataname whose first character "
|
||||||
|
"determines whether an Observable or and ODEe. Any text "
|
||||||
|
"following the type signature is preserved as a comment. "
|
||||||
|
"Answers 'OK' or error text";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execute(xmlrpc_c::paramList const& paramList,
|
||||||
|
xmlrpc_c::value * const retvalP) {
|
||||||
|
|
||||||
|
int const deviceHandle(paramList.getInt(0));
|
||||||
|
std::string typeSpec(paramList.getString(1));
|
||||||
|
std::string newName(paramList.getString(2));
|
||||||
|
paramList.verifyEnd(3);
|
||||||
|
|
||||||
|
*retvalP = xmlrpc_c::value_string(mdState::create(deviceHandle,typeSpec,newName));
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
/*! \brief cmdListFetch
|
||||||
|
* core API.
|
||||||
|
*
|
||||||
|
* Fetch currently defined SCPI for device.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
class cmdListFetch : public xmlrpc_c::method, mdCommand {
|
||||||
|
public:
|
||||||
|
cmdListFetch() {
|
||||||
|
|
||||||
|
_signature = "A:is";
|
||||||
|
_help = "Send handle, md_dev type, and the SCPI subsystem or subcommand. "
|
||||||
|
"Use empty string to get the full subsystem list. Reply will be "
|
||||||
|
"an array of the available command/subsystems. Only MD clients "
|
||||||
|
"of type MACHINE or MDDEV_INSTRUMENT can have SCPI commands defined "
|
||||||
|
"so it is an error to specify any other type of MD client";
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execute(xmlrpc_c::paramList const& paramList,
|
||||||
|
xmlrpc_c::value * const retvalP) {
|
||||||
|
|
||||||
|
int const deviceHandle(paramList.getInt(0));
|
||||||
|
int const deviceType(paramList.getInt(0));
|
||||||
|
std::string commandSetSpecified(paramList.getString(2));
|
||||||
|
paramList.verifyEnd(3);
|
||||||
|
|
||||||
|
if (deviceType != MACHINE && deviceType != MDDEV_INSTRUMENT)
|
||||||
|
*retvalP = xmlrpc_c::value_string(std::string("Invalid MD client type."));
|
||||||
|
else
|
||||||
|
{if (thisService->validateHandleForCmds(deviceHandle))
|
||||||
|
*retvalP = *thisService->fetchCommands(commandSetSpecified);
|
||||||
|
else *retvalP = xmlrpc_c::value_string(std::string("Error: Device not in state where this API can execute."));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/*! \brief cmd
|
||||||
|
* core API.
|
||||||
|
*
|
||||||
|
* Common commander.
|
||||||
|
*/
|
||||||
|
class cmd : public xmlrpc_c::method, mdCommand {
|
||||||
|
public:
|
||||||
|
cmd() {
|
||||||
|
|
||||||
|
_signature = "s:iS";
|
||||||
|
_help = "Given, a handle, device type, the full text of a SCPI "
|
||||||
|
"sends the command to the MD and if accepted to the device. "
|
||||||
|
"If the command is valid for the configured MD, MD answers OK "
|
||||||
|
"and sends it, otherwise answers error text. Whether "
|
||||||
|
"or not the OK indicates anything other than a valid command "
|
||||||
|
"depends on the configured behavior of the device.";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string head(std::string in) { return in; }
|
||||||
|
std::string tail(std::string in) { return in; }
|
||||||
|
void
|
||||||
|
execute(xmlrpc_c::paramList const& paramList,
|
||||||
|
xmlrpc_c::value * const retvalP) {
|
||||||
|
|
||||||
|
mdCommand *thisCommand;
|
||||||
|
mdCommand local;
|
||||||
|
|
||||||
|
int deviceHandle(paramList.getInt(0));
|
||||||
|
std::string commandText(paramList.getString(1));
|
||||||
|
paramList.verifyEnd(2);
|
||||||
|
std::string tails=tail(commandText);
|
||||||
|
|
||||||
|
// if (thisService->validateHandleForCmds(deviceHandle)) {
|
||||||
|
// if (thisCommand = thisDevice->commands[head(commandText)])
|
||||||
|
// *retvalP = xmlrpc_c::value_string(thisCommand->dO(thisDevice,&tails)) ;
|
||||||
|
// else {
|
||||||
|
// *retvalP = xmlrpc_c::value_string(std::string("Error: Can't construct SCPI Command '" + commandText + "'"));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// *retvalP = xmlrpc_c::value_string(std::string("Error: Unknown Device"));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! \brief getMDversion
|
||||||
|
* core API.
|
||||||
|
*
|
||||||
|
* Report the configuration of the MD. This API can be called at
|
||||||
|
* any time and does not require a device handle.
|
||||||
|
*/
|
||||||
|
class getMDversion : public xmlrpc_c::method {
|
||||||
|
public:
|
||||||
|
getMDversion() {
|
||||||
|
|
||||||
|
_signature = "i:s";
|
||||||
|
_help = "Accepts a device handle and returns the version identification "
|
||||||
|
"of the MD. ";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execute(xmlrpc_c::paramList const& paramList,
|
||||||
|
xmlrpc_c::value * const retvalP) {
|
||||||
|
|
||||||
|
int const addend(paramList.getInt(0));
|
||||||
|
|
||||||
|
paramList.verifyEnd(1);
|
||||||
|
*retvalP = xmlrpc_c::value_string("OpenAUC v 0.5");
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#ifndef MASTER_DAEMON
|
#ifndef MASTER_DAEMON
|
||||||
#define MASTER_DAEMON
|
#define MASTER_DAEMON
|
||||||
|
|
||||||
#include <msgpack.hpp>
|
|
||||||
|
|
||||||
/*! \brief masterDaemon
|
/*! \brief masterDaemon
|
||||||
* server core.
|
* server core.
|
||||||
*
|
*
|
||||||
* Contains the data layer and the XMLRPC API.
|
* Two Process Layers: one to n EPP Servers and one to n EPP Clients.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef MD_CORE
|
#ifdef MD_CORE
|
||||||
|
@ -29,8 +28,8 @@ class masterDaemon : public mdProcess,
|
||||||
public Listener<mdClientDeath>,
|
public Listener<mdClientDeath>,
|
||||||
public Listener<mdIncoming>,
|
public Listener<mdIncoming>,
|
||||||
public Listener<mdResponse>,
|
public Listener<mdResponse>,
|
||||||
public Listener<mdTelemetryFrame>,
|
public Listener<mdAPIFrame>,
|
||||||
public Listener<mdDeviceCommand> {
|
public Listener<mdHostCommand> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool shuttingDown;
|
bool shuttingDown;
|
||||||
|
@ -38,9 +37,10 @@ public:
|
||||||
boost::asio::io_service io_;
|
boost::asio::io_service io_;
|
||||||
|
|
||||||
int arCycles,
|
int arCycles,
|
||||||
dataClients[MAX_DATACLIENTS],
|
apiClients[MAX_CLIENTS],
|
||||||
instruments[MAX_INSTRUMENTS],
|
eppServers[MAX_PEER],
|
||||||
nClievers,
|
nClievers,
|
||||||
|
received,
|
||||||
sentCommands;
|
sentCommands;
|
||||||
|
|
||||||
masterDaemonConfig *cfg;
|
masterDaemonConfig *cfg;
|
||||||
|
@ -56,8 +56,8 @@ public:
|
||||||
cfg = cmdCfg;
|
cfg = cmdCfg;
|
||||||
nClievers = 0;
|
nClievers = 0;
|
||||||
shuttingDown = false;
|
shuttingDown = false;
|
||||||
memset(dataClients,0,sizeof(dataClients));
|
memset(apiClients,0,sizeof(apiClients));
|
||||||
memset(instruments,0,sizeof(instruments));
|
memset(eppServers,0,sizeof(eppServers));
|
||||||
}
|
}
|
||||||
|
|
||||||
int getDeviceHandle(int deviceMajor,std::string &deviceMinor) {};
|
int getDeviceHandle(int deviceMajor,std::string &deviceMinor) {};
|
||||||
|
@ -68,7 +68,8 @@ public:
|
||||||
void dispatch(mdWQitem*);
|
void dispatch(mdWQitem*);
|
||||||
void dispatch(const mdIncoming&);
|
void dispatch(const mdIncoming&);
|
||||||
void listen();
|
void listen();
|
||||||
xmlrpc_c::value* fetchCommands(std::string subSystem) {};
|
//rrj xmlrpc_c::value* fetchCommands(std::string subSystem) {};
|
||||||
|
void * fetchCommands(std::string subSystem) {};
|
||||||
|
|
||||||
virtual void processEvent(const mdAttention &ev);
|
virtual void processEvent(const mdAttention &ev);
|
||||||
virtual void processEvent(const mdCDPulse &ev);
|
virtual void processEvent(const mdCDPulse &ev);
|
||||||
|
@ -76,8 +77,8 @@ public:
|
||||||
virtual void processEvent(const mdClientDeath &ev);
|
virtual void processEvent(const mdClientDeath &ev);
|
||||||
virtual void processEvent(const mdIncoming &ev);
|
virtual void processEvent(const mdIncoming &ev);
|
||||||
virtual void processEvent(const mdResponse &ev);
|
virtual void processEvent(const mdResponse &ev);
|
||||||
virtual void processEvent(const mdTelemetryFrame &ev);
|
virtual void processEvent(const mdAPIFrame &ev);
|
||||||
virtual void processEvent(const mdDeviceCommand &ev);
|
virtual void processEvent(const mdHostCommand &ev);
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ public:
|
||||||
|
|
||||||
ClientsByHandle allClients;
|
ClientsByHandle allClients;
|
||||||
|
|
||||||
date epoch(MD_EPOCH);
|
// date epoch(MD_EPOCH);
|
||||||
int debugThreshold,nClients,nClievers,
|
int debugThreshold,nClients,nClievers,
|
||||||
servicePort,thisMachineContext,
|
servicePort,thisMachineContext,
|
||||||
clientPort;
|
clientPort;
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
#ifndef MD_BEHAVIOR
|
||||||
|
#define MD_BEHAVIOR
|
||||||
|
|
||||||
|
#include "Listener.h"
|
||||||
|
#include "EventSender.h"
|
||||||
|
#include "PolymorphEvent.h"
|
||||||
|
|
||||||
|
/*! \brief mdMand
|
||||||
|
* The former mdBehavior
|
||||||
|
*
|
||||||
|
* The overall object category and files are still using the original name.
|
||||||
|
* Wanted to make d0 pure virtual but too many problems with current gcc template instantiation
|
||||||
|
* ( http://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html )
|
||||||
|
*
|
||||||
|
* The CLIPS integration with the low level system in mostly restricted to this interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class mdMand;
|
||||||
|
|
||||||
|
typedef std::map<std::string,mdMand> MandLayer;
|
||||||
|
|
||||||
|
class mdMand {
|
||||||
|
public:
|
||||||
|
|
||||||
|
md_mand kind;
|
||||||
|
std::string fullname;
|
||||||
|
MandLayer subsystem; // children
|
||||||
|
MandLayer parent;
|
||||||
|
void *handler;
|
||||||
|
|
||||||
|
// Subtypes must implement these.
|
||||||
|
std::string *dO(std::string *text);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class mdMandSpace {
|
||||||
|
MandLayer catalog;
|
||||||
|
|
||||||
|
bool add(std::string name,md_mand typ)
|
||||||
|
{if (catalog.find(name) == catalog.end()) {
|
||||||
|
mdMand *newMand = new mdMand();
|
||||||
|
catalog[name] = *newMand;
|
||||||
|
newMand->fullname = name;
|
||||||
|
newMand->kind = typ;
|
||||||
|
newMand->handler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
mdMand *find(std::string fn);
|
||||||
|
mdMand *parseAndCreatePath(std::string fn);
|
||||||
|
bool setFullName(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool requiresResponse;
|
||||||
|
bool hasArguments;
|
||||||
|
unsigned short nArgs;
|
||||||
|
char sVal;
|
||||||
|
}
|
||||||
|
mdCmdPOD;
|
||||||
|
|
||||||
|
class mdCommand : mdMand {
|
||||||
|
public:
|
||||||
|
mdCmdPOD parms;
|
||||||
|
std::string signature;
|
||||||
|
|
||||||
|
mdCommand(md_mand typ=MD_USER_MAND,std::string name=std::string(""))
|
||||||
|
{mdMand::handler = NULL;
|
||||||
|
mdMand::fullname = name;
|
||||||
|
mdMand::kind = typ;
|
||||||
|
}
|
||||||
|
~mdCommand() {}
|
||||||
|
|
||||||
|
mdCommand *mand(int deviceHandle, std::string& text);
|
||||||
|
std::string dO(void *target,std::string *text);
|
||||||
|
void *getHandler() {return mdMand::handler;}
|
||||||
|
void setHandler(void *to) {mdMand::handler = to;}
|
||||||
|
|
||||||
|
};
|
||||||
|
class mdResponse; /*rrj
|
||||||
|
class mdSCPI : mdCommand {
|
||||||
|
public:
|
||||||
|
|
||||||
|
mdSCPI(std::string name) : mdCommand(MD_SCPI, name) {}
|
||||||
|
mdSCPI *setHandler(mdResponse *mdr);
|
||||||
|
std::string dO(void *target,std::string *text);
|
||||||
|
|
||||||
|
}; */
|
||||||
|
|
||||||
|
typedef std::map<std::string,mdCommand *> InstructionSet; // The EPP commands by cannonical name.
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
/*! \brief mdDevice
|
/*! \brief mdHost
|
||||||
* General abstraction of all MD clients
|
* General abstraction of all MD clients
|
||||||
*
|
*
|
||||||
* For historical reasons all clients are considered to be
|
* For historical reasons all clients are considered to be
|
||||||
|
@ -15,14 +15,13 @@ using namespace std;
|
||||||
using boost::asio::ip::udp;
|
using boost::asio::ip::udp;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class mdDevice {
|
class mdHost {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool isSingleton;
|
bool isSingleton;
|
||||||
int clieverGroup, // masterDaemonConfig.thisMachineContext
|
int clieverGroup, // masterDaemonConfig.thisMachineContext
|
||||||
handle,mdStdDevIdx;
|
handle,mdStdDevIdx;
|
||||||
md_device type;
|
md_device type;
|
||||||
mdState state;
|
|
||||||
|
|
||||||
udp::endpoint ip;
|
udp::endpoint ip;
|
||||||
|
|
||||||
|
@ -32,58 +31,52 @@ public:
|
||||||
// Some parameters initially here are now all uniformly ODEs
|
// Some parameters initially here are now all uniformly ODEs
|
||||||
// defined in the COOL scripts.
|
// defined in the COOL scripts.
|
||||||
|
|
||||||
~mdDevice() {}
|
~mdHost() {}
|
||||||
mdDevice(md_device t) : type(t) {clieverGroup = handle = mdStdDevIdx = -1;}
|
mdHost(md_device t) : type(t) {clieverGroup = handle = mdStdDevIdx = -1;}
|
||||||
|
|
||||||
void lxi_control(T* device,std::string scpiText);
|
|
||||||
T* registeR(md_device t);
|
T* registeR(md_device t);
|
||||||
|
|
||||||
xmlrpc_c::value* fetchCommands(std::string subSystem);
|
|
||||||
void registerCmd(const char *cmdName,const mdIncoming &mdI);
|
void registerCmd(const char *cmdName,const mdIncoming &mdI);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class mdClientServer;
|
class mdClientServer;
|
||||||
class mdClientServer : public mdDevice<mdClientServer> {
|
class mdClientServer : public mdHost<mdClientServer> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
mdClientServer() : mdDevice<mdClientServer>( MDDEV_CD ) {};
|
mdClientServer() : mdHost<mdClientServer>( MDDEV_CD ) {};
|
||||||
mdClientServer *validateClient(int handle, mdResponse &r);
|
mdClientServer *validateClient(int handle, mdResponse &r);
|
||||||
};
|
};
|
||||||
|
|
||||||
class mdMachine;
|
class mdMachine;
|
||||||
class mdMachine : public mdDevice<mdMachine> {
|
class mdMachine : public mdHost<mdMachine> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
mdMachine() : mdDevice<mdMachine>( MACHINE )
|
mdMachine() : mdHost<mdMachine>( MACHINE ) {}
|
||||||
{ cmds["RST"] = new mdCommand(MD_SCPI,std::string("RST")); }
|
|
||||||
mdMachine *validateClient(int handle, const mdClientBirth &c, mdResponse &r);
|
mdMachine *validateClient(int handle, const mdClientBirth &c, mdResponse &r);
|
||||||
void registerCmd(const char *cmdName,const mdIncoming &mdI);
|
void registerCmd(const char *cmdName,const mdIncoming &mdI);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class mdInstrument;
|
class mdInstrument;
|
||||||
class mdInstrument : public mdDevice<mdInstrument> {
|
class mdInstrument : public mdHost<mdInstrument> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
mdInstrument() : mdDevice<mdInstrument>( MDDEV_INSTRUMENT )
|
mdInstrument() : mdHost<mdInstrument>( MDDEV_PEER )
|
||||||
{ cmds["RST"] = new mdCommand(MD_SCPI,std::string("RST")); }
|
{
|
||||||
|
//rrj cmds["RST"] = new mdCommand(MD_SCPI,std::string("RST"));
|
||||||
|
cmds["RST"] = new mdCommand((md_mand)0,std::string("RST"));
|
||||||
|
}
|
||||||
mdInstrument *validateClient(int handle, const mdClientBirth &c, mdResponse &r);
|
mdInstrument *validateClient(int handle, const mdClientBirth &c, mdResponse &r);
|
||||||
void registerCmd(const char *cmdName,const mdIncoming &mdI);
|
void registerCmd(const char *cmdName,const mdIncoming &mdI);
|
||||||
};
|
};
|
||||||
|
|
||||||
class mdDataClient;
|
|
||||||
class mdDataClient : public mdDevice<mdDataClient> {
|
|
||||||
public:
|
|
||||||
|
|
||||||
mdDataClient() : mdDevice<mdDataClient>( MDDEV_DATACLIENT ) {};
|
|
||||||
mdDataClient *validateClient(int handle);
|
|
||||||
};
|
|
||||||
|
|
||||||
class masterDaemon;
|
class masterDaemon;
|
||||||
class mdDeviceFabrik : public mdDevice<masterDaemon>
|
class mdHostFabrik : public mdHost<masterDaemon>
|
||||||
{public:
|
{public:
|
||||||
|
|
||||||
mdDeviceFabrik() : mdDevice<masterDaemon>( MDDEV_MD ) {}
|
mdHostFabrik() : mdHost<masterDaemon>( MDDEV_MD ) {}
|
||||||
void newFromHeartbeat(const mdClientBirth &itsAWhat);
|
void newFromHeartbeat(const mdClientBirth &itsAWhat);
|
||||||
std::string newFromAPI(md_device type,std::string signature);
|
std::string newFromAPI(md_device type,std::string signature);
|
||||||
|
|
|
@ -35,10 +35,9 @@
|
||||||
* <br>
|
* <br>
|
||||||
* \b boost: 1.49 <br>
|
* \b boost: 1.49 <br>
|
||||||
* \b log4cpp: 1.0 <br>
|
* \b log4cpp: 1.0 <br>
|
||||||
* \b sigc++: 2.0 <br>
|
|
||||||
* \b AusRegTk: 1.3.2 <br>
|
* \b AusRegTk: 1.3.2 <br>
|
||||||
* <br>
|
* <br>
|
||||||
* See the Tk for it's dependencies, besides that and above everything should be in the git tree.
|
* See the Tk for its' dependencies, besides that and above everything should be in the git tree.
|
||||||
*
|
*
|
||||||
* <br><hr>
|
* <br><hr>
|
||||||
*
|
*
|
||||||
|
@ -61,12 +60,12 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using boost::asio::ip::udp;
|
using boost::asio::ip::udp;
|
||||||
|
|
||||||
#define MAX_CLIENTS 10
|
#define MAX_AC 1
|
||||||
#define MAX_CLIEVER 1
|
#define MAX_CLIENTS 1
|
||||||
#define MAX_SERVERS 3 // Per Cliever cluster.
|
#define MAX_CLIEVER 10
|
||||||
|
#define MAX_PEER 10
|
||||||
#define MAX_DEBUG 1000 // Set the config parm higher than this to inhibit logNdebug(m...) where m < this
|
#define MAX_DEBUG 1000 // Set the config parm higher than this to inhibit logNdebug(m...) where m < this
|
||||||
#define MAX_DEVICE (((MAX_CLIEVER + 1) * MAX_INSTRUMENTS) + MAX_DATACLIENTS)
|
#define MAX_DEVICE MAX_PEER + MAX_CLIEVER + MAX_CLIENTS + 1
|
||||||
|
|
||||||
#define MD_EPOCH date()
|
#define MD_EPOCH date()
|
||||||
#define MD_HEARTBEAT 1 // Network peer heartbeat in seconds.
|
#define MD_HEARTBEAT 1 // Network peer heartbeat in seconds.
|
||||||
#define MD_MAX_DATAGRAM (32*1024) // half of the IPV4 max
|
#define MD_MAX_DATAGRAM (32*1024) // half of the IPV4 max
|
||||||
|
@ -74,8 +73,8 @@ using boost::asio::ip::udp;
|
||||||
#define MD_COMPONENT "Master Daemon" // Cliever Component
|
#define MD_COMPONENT "Master Daemon" // Cliever Component
|
||||||
#define MD_NAME CLIEVER_APP " " MD_COMPONENT
|
#define MD_NAME CLIEVER_APP " " MD_COMPONENT
|
||||||
#define MD_VERSION " 1.0 " // Version
|
#define MD_VERSION " 1.0 " // Version
|
||||||
#define MD_REFRESH 10 // default milliseconds between telemetry frame updates
|
#define MD_REFRESH 10 // default milliseconds between API frame updates
|
||||||
#define MD_TYPE "AUSREGCLIEVER" // i.e. what a MACHINE is, Change per your Cliever derivation
|
#define MD_TYPE "EPPCLIENT"
|
||||||
#define NORMAL_DEBUG 10
|
#define NORMAL_DEBUG 10
|
||||||
#ifndef CURRENT_DEBUG
|
#ifndef CURRENT_DEBUG
|
||||||
#define CURRENT_DEBUG NORMAL_DEBUG
|
#define CURRENT_DEBUG NORMAL_DEBUG
|
||||||
|
@ -117,8 +116,9 @@ enum md_dispatch_category {
|
||||||
enum md_device {
|
enum md_device {
|
||||||
MDDEV_MD = 0,
|
MDDEV_MD = 0,
|
||||||
MDDEV_CD,
|
MDDEV_CD,
|
||||||
MACHINE,
|
|
||||||
MDDEV_DATACLIENT,
|
MDDEV_DATACLIENT,
|
||||||
|
MDDEV_PEER,
|
||||||
|
MACHINE,
|
||||||
N_MDDEV_TYPES
|
N_MDDEV_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -132,8 +132,11 @@ enum mdDGtype {
|
||||||
MDDG_DEVICEHB,
|
MDDG_DEVICEHB,
|
||||||
MDDG_NEWBORN,
|
MDDG_NEWBORN,
|
||||||
MDDG_MDQUERY,
|
MDDG_MDQUERY,
|
||||||
MDDG_MDDATA,
|
MDDG_REGSCPI,
|
||||||
MDDG_MDMAND,
|
MDDG_REGOBS,
|
||||||
|
MDDG_REGODE,
|
||||||
|
MDDG_TELEMETRY,
|
||||||
|
MDDG_CDRESET,
|
||||||
N_MDDG_TYPES
|
N_MDDG_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ class mdClientDeath: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
virtual void send() const { sendTypedEvent(*this); }
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
|
||||||
};
|
};
|
||||||
class mdDeviceCommand: public TimeStampedEvent<>, public PolymorphEvent {
|
class mdHostCommand: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void send() const { sendTypedEvent(*this); }
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
@ -72,11 +72,11 @@ public:
|
||||||
virtual void send() const { sendTypedEvent(*this); }
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
|
|
||||||
};
|
};
|
||||||
class mdTelemetryFrame: public TimeStampedEvent<>, public PolymorphEvent {
|
class mdAPIFrame: public TimeStampedEvent<>, public PolymorphEvent {
|
||||||
public:
|
public:
|
||||||
int mdStdDevIdx;
|
int mdStdDevIdx;
|
||||||
|
|
||||||
mdTelemetryFrame() {mdStdDevIdx = -1;}
|
mdAPIFrame() {mdStdDevIdx = -1;}
|
||||||
|
|
||||||
virtual void send() const { sendTypedEvent(*this); }
|
virtual void send() const { sendTypedEvent(*this); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
\endcopyright
|
\endcopyright
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Listener.h"
|
|
||||||
#include "EventSender.h"
|
|
||||||
|
|
||||||
/** Tell EventSender<EvType> that this listener is ignoring the event received.
|
/** Tell EventSender<EvType> that this listener is ignoring the event received.
|
||||||
This will increment a counter in EventSender<EvType>, such that a call to
|
This will increment a counter in EventSender<EvType>, such that a call to
|
||||||
|
|
|
@ -66,8 +66,8 @@ void md() {
|
||||||
theseLogs->logN(0,"AusReg Cliever <- MasterDaemon.");
|
theseLogs->logN(0,"AusReg Cliever <- MasterDaemon.");
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::thread foreground(runMasterDaemon);`
|
boost::thread foreground(runMasterDaemon);
|
||||||
boost::thread background(runClientLayer);
|
boost::thread background(runAPILayer);
|
||||||
|
|
||||||
if (!foreground.joinable()) {
|
if (!foreground.joinable()) {
|
||||||
theseLogs->logN(0,"Fatal Error: couldn't start master daemon!");
|
theseLogs->logN(0,"Fatal Error: couldn't start master daemon!");
|
||||||
|
@ -76,7 +76,7 @@ void md() {
|
||||||
|
|
||||||
if (background.joinable()) {
|
if (background.joinable()) {
|
||||||
theseLogs->logN(2,"%s %d","Accepting API Requests on Port",thisConfig->clientPort);
|
theseLogs->logN(2,"%s %d","Accepting API Requests on Port",thisConfig->clientPort);
|
||||||
myAusRegProcess.run();
|
// myAusRegTk.init();
|
||||||
background.join(); // normally unreachable
|
background.join(); // normally unreachable
|
||||||
} else
|
} else
|
||||||
theseLogs->logN(0,"Fatal Error: couldn't start client service layer!");
|
theseLogs->logN(0,"Fatal Error: couldn't start client service layer!");
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#define MD_CORE
|
#define MD_CORE
|
||||||
#include "auc-md.h"
|
#include "cliever-md.h"
|
||||||
#include "masterDaemon.h"
|
#include "masterDaemon.h"
|
||||||
#include "coreapi.h"
|
//#include "coreapi.h"
|
||||||
#include "../server/Listener.cpp"
|
#include "Listener.cpp"
|
||||||
#include "../server/EventSender2.cpp"
|
#include "EventSender2.cpp"
|
||||||
|
|
||||||
void attention();
|
void attention();
|
||||||
void arCallback(const boost::system::error_code& error);
|
void arCallback(const boost::system::error_code& error);
|
||||||
|
@ -82,8 +82,8 @@ void masterDaemon::dispatch(const mdIncoming &what) {
|
||||||
switch(what.dg.hdr.dgSubType) {
|
switch(what.dg.hdr.dgSubType) {
|
||||||
case MDDG_REGSCPI:
|
case MDDG_REGSCPI:
|
||||||
theseLogs->logNdebug(NORMAL_DEBUG,4,"Src SCPI: '%s' from type: %d ('%s'), handle %d.", name, what.dg.hdr.clientType,xStr,about);
|
theseLogs->logNdebug(NORMAL_DEBUG,4,"Src SCPI: '%s' from type: %d ('%s'), handle %d.", name, what.dg.hdr.clientType,xStr,about);
|
||||||
if (thisKind == MACHINE) theMachine->registerCmd(name,what);
|
//rrj if (thisKind == MACHINE) theMachine->registerCmd(name,what);
|
||||||
else thisConfig->instruments[about]->registerCmd(name,what);
|
//rrj else thisConfig->eppServers[about]->registerCmd(name,what);
|
||||||
break;
|
break;
|
||||||
case MDDG_REGODE:
|
case MDDG_REGODE:
|
||||||
theseLogs->logNdebug(NORMAL_DEBUG,4,"Src ODE: '%s' from type: %d ('%s'), handle %d.", name, what.dg.hdr.clientType,xStr,about);
|
theseLogs->logNdebug(NORMAL_DEBUG,4,"Src ODE: '%s' from type: %d ('%s'), handle %d.", name, what.dg.hdr.clientType,xStr,about);
|
||||||
|
@ -91,8 +91,8 @@ void masterDaemon::dispatch(const mdIncoming &what) {
|
||||||
case MDDG_REGOBS:
|
case MDDG_REGOBS:
|
||||||
theseLogs->logNdebug(NORMAL_DEBUG,4,"Src Obs: '%s' from type: %d ('%s'), handle %d.", name, what.dg.hdr.clientType,xStr,about);
|
theseLogs->logNdebug(NORMAL_DEBUG,4,"Src Obs: '%s' from type: %d ('%s'), handle %d.", name, what.dg.hdr.clientType,xStr,about);
|
||||||
regName:
|
regName:
|
||||||
if (thisKind == MACHINE) theMachine->state.registerData(name,what);
|
//rrj if (thisKind == MACHINE) theMachine->state.registerData(name,what);
|
||||||
else thisConfig->instruments[about]->state.registerData(name,what);
|
//rrj else thisConfig->instruments[about]->state.registerData(name,what);
|
||||||
break;
|
break;
|
||||||
}}
|
}}
|
||||||
break;
|
break;
|
||||||
|
@ -132,21 +132,6 @@ int masterDaemon::initBaseAPI(void) {
|
||||||
|
|
||||||
theseLogs->logN(0,"Create Generic Core API");
|
theseLogs->logN(0,"Create Generic Core API");
|
||||||
|
|
||||||
xmlrpc_c::methodPtr const registerDeviceP(new registerDevice(thisService->cfg));
|
|
||||||
xmlrpc_c::methodPtr const getMDversionP(new getMDversion);
|
|
||||||
xmlrpc_c::methodPtr const getP(new getter);
|
|
||||||
xmlrpc_c::methodPtr const setP(new setter);
|
|
||||||
xmlrpc_c::methodPtr const getCmdListP(new cmdListFetch);
|
|
||||||
xmlrpc_c::methodPtr const getCmdP(new cmd);
|
|
||||||
xmlrpc_c::methodPtr const createP(new create);
|
|
||||||
|
|
||||||
thisConfig->api_registry.addMethod("device.registeR", registerDeviceP );
|
|
||||||
thisConfig->api_registry.addMethod("state.getMDversion", getMDversionP );
|
|
||||||
thisConfig->api_registry.addMethod("state.create", createP);
|
|
||||||
thisConfig->api_registry.addMethod("state.get", getP );
|
|
||||||
thisConfig->api_registry.addMethod("state.set", setP );
|
|
||||||
thisConfig->api_registry.addMethod("behavior.getCommandList", getCmdListP );
|
|
||||||
thisConfig->api_registry.addMethod("behavior.command", getCmdP );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(...)
|
catch(...)
|
||||||
|
@ -165,14 +150,14 @@ void masterDaemon::listen() {
|
||||||
assert(EventSender<mdClientBirth>::getNumListeners() == 1);
|
assert(EventSender<mdClientBirth>::getNumListeners() == 1);
|
||||||
EventSender<mdClientDeath>::add(*this);
|
EventSender<mdClientDeath>::add(*this);
|
||||||
assert(EventSender<mdClientDeath>::getNumListeners() == 1);
|
assert(EventSender<mdClientDeath>::getNumListeners() == 1);
|
||||||
EventSender<mdDeviceCommand>::add(*this);
|
EventSender<mdHostCommand>::add(*this);
|
||||||
assert(EventSender<mdDeviceCommand>::getNumListeners() == 1);
|
assert(EventSender<mdHostCommand>::getNumListeners() == 1);
|
||||||
EventSender<mdIncoming>::add(*this);
|
EventSender<mdIncoming>::add(*this);
|
||||||
assert(EventSender<mdIncoming>::getNumListeners() == 1);
|
assert(EventSender<mdIncoming>::getNumListeners() == 1);
|
||||||
EventSender<mdResponse>::add(*this);
|
EventSender<mdResponse>::add(*this);
|
||||||
assert(EventSender<mdResponse>::getNumListeners() == 1);
|
assert(EventSender<mdResponse>::getNumListeners() == 1);
|
||||||
EventSender<mdTelemetryFrame>::add(*this);
|
EventSender<mdAPIFrame>::add(*this);
|
||||||
assert(EventSender<mdTelemetryFrame>::getNumListeners() == 1);
|
assert(EventSender<mdAPIFrame>::getNumListeners() == 1);
|
||||||
|
|
||||||
boost::thread mdAr(attention);
|
boost::thread mdAr(attention);
|
||||||
|
|
||||||
|
@ -200,9 +185,9 @@ void masterDaemon::processEvent( const mdClientDeath &thisWas )
|
||||||
{
|
{
|
||||||
assert(EventSender<mdClientDeath>::isSending());
|
assert(EventSender<mdClientDeath>::isSending());
|
||||||
}
|
}
|
||||||
void masterDaemon::processEvent( const mdDeviceCommand &thisCmd )
|
void masterDaemon::processEvent( const mdHostCommand &thisCmd )
|
||||||
{
|
{
|
||||||
assert(EventSender<mdDeviceCommand>::isSending());
|
assert(EventSender<mdHostCommand>::isSending());
|
||||||
}
|
}
|
||||||
void masterDaemon::processEvent( const mdIncoming &thisDatagram )
|
void masterDaemon::processEvent( const mdIncoming &thisDatagram )
|
||||||
{
|
{
|
||||||
|
@ -217,13 +202,13 @@ void masterDaemon::processEvent( const mdResponse &thisReply )
|
||||||
queue(new mdWQitem( queued, thisReply.dCat, 0 ));
|
queue(new mdWQitem( queued, thisReply.dCat, 0 ));
|
||||||
|
|
||||||
}
|
}
|
||||||
void masterDaemon::processEvent( const mdTelemetryFrame &thisFrame )
|
void masterDaemon::processEvent( const mdAPIFrame &thisFrame )
|
||||||
{
|
{
|
||||||
assert(EventSender<mdTelemetryFrame>::isSending());
|
assert(EventSender<mdAPIFrame>::isSending());
|
||||||
}
|
}
|
||||||
void masterDaemon::run() {
|
void masterDaemon::run() {
|
||||||
|
|
||||||
deviceFactory = new mdDeviceFabrik();
|
deviceFactory = new mdHostFabrik();
|
||||||
fg = new mdDGChannel( thisService->io_, 0 );
|
fg = new mdDGChannel( thisService->io_, 0 );
|
||||||
|
|
||||||
if (initBaseAPI()) return;
|
if (initBaseAPI()) return;
|
||||||
|
@ -301,15 +286,15 @@ void mdWQ() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
void runDataLayer() {
|
void runAPILayer() {
|
||||||
|
|
||||||
boost::asio::io_service io_;
|
boost::asio::io_service io_;
|
||||||
|
|
||||||
theseLogs->logN(1,"Background dgram service thread starting on port %d.",thisConfig->telemetryPort);
|
theseLogs->logN(1,"Background dgram service thread starting on port %d.",thisConfig->clientPort);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
thisService->bg = new mdDGChannel(io_, thisConfig->telemetryPort);
|
thisService->bg = new mdDGChannel(io_, thisConfig->clientPort);
|
||||||
io_.run();
|
io_.run();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -319,7 +304,7 @@ void runDataLayer() {
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
theseLogs->logN(0,"Unknown failure in background datalayer.");
|
theseLogs->logN(0,"Unknown failure in background service layer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
theseLogs->logNdebug(1,0,"mainbus background thread exited.");
|
theseLogs->logNdebug(1,0,"mainbus background thread exited.");
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
#include "cliever-md.h"
|
||||||
|
|
||||||
|
const char *mdStdErrs[] = { "No error detected.", "Required state/element missing.", "Already exists.",
|
||||||
|
"Conflict detected.", "Not ready.", "Syntax error." };
|
||||||
|
|
||||||
|
masterDaemonConfig::masterDaemonConfig() {
|
||||||
|
|
||||||
|
nClievers = 0;
|
||||||
|
configPath = "./";
|
||||||
|
logPath = "/tmp";
|
||||||
|
daemonized = true;
|
||||||
|
// used in the logNdebug by increasing power of 10.
|
||||||
|
debugThreshold = CURRENT_DEBUG;
|
||||||
|
halt = false;
|
||||||
|
shuttingDown = false;
|
||||||
|
shutdown = false;
|
||||||
|
thisMachineContext = -1; // in v 1.0. there's only 1 but the
|
||||||
|
// basis for more than one is pre-established.
|
||||||
|
err = mdStdErrs;
|
||||||
|
}
|
||||||
|
int masterDaemonConfig::loadMachineConfiguration(int deviceType) {
|
||||||
|
|
||||||
|
int rc=OK;
|
||||||
|
|
||||||
|
if (!deviceType) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* \todo Add configuration process for non-MD_TYPE devices */
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include "cliever-md.h"
|
||||||
|
#ifdef MD_MAND
|
||||||
|
#include <environment.h>
|
||||||
|
#endif
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
extern xmlrpc_c::registry aucMDregistry;
|
||||||
|
extern "C" int lxi_control(int,char **);
|
||||||
|
|
||||||
|
std::string mdCommand::dO(void *targeT,std::string *text) {
|
||||||
|
|
||||||
|
return std::string("OK");
|
||||||
|
|
||||||
|
}
|
||||||
|
mdSCPI *mdSCPI::setHandler(mdResponse *mdr) {
|
||||||
|
|
||||||
|
mdSCPI *value = this;
|
||||||
|
mdCmdPOD *flat = (mdCmdPOD *)(&mdr->reply.dg.payLoad[0]);
|
||||||
|
|
||||||
|
memcpy(flat,&this->parms,sizeof(mdCmdPOD));
|
||||||
|
strcpy(&flat->sVal,this->signature.c_str());
|
||||||
|
flat->nArgs = this->signature.length();
|
||||||
|
|
||||||
|
mdr->reply.dg.hdr.primeOffset = mdr->reply.dg.hdr.payloadSize = sizeof(mdCmdPOD) + flat->nArgs;
|
||||||
|
|
||||||
|
done: return value;
|
||||||
|
|
||||||
|
}
|
||||||
|
bool mdMandSpace::setFullName() {
|
||||||
|
|
||||||
|
bool value=true;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#include "cliever-md.h"
|
#include "cliever-md.h"
|
||||||
#include "masterDaemon.h"
|
#include "masterDaemon.h"
|
||||||
#include "../server/Listener.cpp"
|
#include "Listener.cpp"
|
||||||
#include "../server/EventSender2.cpp"
|
#include "EventSender2.cpp"
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
/*! \brief Client object implementatios
|
/*! \brief Client object implementatios
|
||||||
|
@ -28,12 +28,13 @@ int getHandle() {
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
}
|
}
|
||||||
template<class T> T* mdDevice<T>::registeR(md_device t) {
|
template<class T> T* mdHost<T>::registeR(md_device t) {
|
||||||
|
|
||||||
T *value=NULL;
|
T *value=NULL;
|
||||||
int h = getHandle();
|
int h = getHandle();
|
||||||
|
|
||||||
if (value=mdDevice<T>::validateClient(h)) {
|
//rrj if (value=mdHost<T>::validateClient(h)) {
|
||||||
|
if (0) {
|
||||||
theseLogs->logN(2,"Handle %d assigned to new client of type: %s",clientTypes[t]);
|
theseLogs->logN(2,"Handle %d assigned to new client of type: %s",clientTypes[t]);
|
||||||
} else {
|
} else {
|
||||||
theseLogs->logN(2,"Validation failed for client type: %s",clientTypes[t]);
|
theseLogs->logN(2,"Validation failed for client type: %s",clientTypes[t]);
|
||||||
|
@ -45,9 +46,9 @@ template<class T> T* mdDevice<T>::registeR(md_device t) {
|
||||||
thisConfig->allClients[h] = value; // validateClient has already added to group
|
thisConfig->allClients[h] = value; // validateClient has already added to group
|
||||||
return value ;
|
return value ;
|
||||||
|
|
||||||
}
|
}/*
|
||||||
template<class T>
|
template<class T>
|
||||||
void mdDevice<T>::lxi_control(T *device, std::string fullText) {
|
void mdHost<T>::lxi_control(T *device, std::string fullText) {
|
||||||
|
|
||||||
T *target = device;
|
T *target = device;
|
||||||
char *ip,*port,*command,*timeout,*argv[5];
|
char *ip,*port,*command,*timeout,*argv[5];
|
||||||
|
@ -69,7 +70,7 @@ template<class T>
|
||||||
free(timeout);
|
free(timeout);
|
||||||
free(command);
|
free(command);
|
||||||
|
|
||||||
}
|
}*/
|
||||||
mdClientServer* mdClientServer::validateClient(int handle, mdResponse &r) {
|
mdClientServer* mdClientServer::validateClient(int handle, mdResponse &r) {
|
||||||
|
|
||||||
bool isNew=true;
|
bool isNew=true;
|
||||||
|
@ -121,7 +122,7 @@ mdMachine* mdMachine::validateClient(int handle, const mdClientBirth &c, mdRespo
|
||||||
done:
|
done:
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
}
|
}/*
|
||||||
mdInstrument* mdInstrument::validateClient(int handle, const mdClientBirth &c, mdResponse &r) {
|
mdInstrument* mdInstrument::validateClient(int handle, const mdClientBirth &c, mdResponse &r) {
|
||||||
|
|
||||||
mdInstrument *value=NULL;
|
mdInstrument *value=NULL;
|
||||||
|
@ -146,11 +147,11 @@ mdDataClient* mdDataClient::validateClient(int handle) {
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
}
|
}*/
|
||||||
std::string mdDeviceFabrik::newFromAPI(md_device type,std::string thisSpecialOne) {
|
std::string mdHostFabrik::newFromAPI(md_device type,std::string thisSpecialOne) {
|
||||||
|
|
||||||
}
|
}
|
||||||
void mdDeviceFabrik::newFromHeartbeat(const mdClientBirth &thisOne) {
|
void mdHostFabrik::newFromHeartbeat(const mdClientBirth &thisOne) {
|
||||||
|
|
||||||
const char *kind,*outcome;
|
const char *kind,*outcome;
|
||||||
void *resultat;
|
void *resultat;
|
||||||
|
@ -176,8 +177,8 @@ void mdDeviceFabrik::newFromHeartbeat(const mdClientBirth &thisOne) {
|
||||||
case MDDEV_CD:
|
case MDDEV_CD:
|
||||||
thisKind = MDDEV_CD;
|
thisKind = MDDEV_CD;
|
||||||
kind = "cliever";
|
kind = "cliever";
|
||||||
newCliever = new mdClientServer();
|
newCliever = new mdClientServer(); if (0) {
|
||||||
if (resultat = newCliever = newCliever->validateClient( maybe, *result )) {
|
//rrj if (resultat = newCliever = newCliever->validateClient( maybe, *result )) {
|
||||||
newCliever->ip = thisOne.ip;
|
newCliever->ip = thisOne.ip;
|
||||||
mdStdDevIdx = newCliever->mdStdDevIdx;
|
mdStdDevIdx = newCliever->mdStdDevIdx;
|
||||||
}
|
}
|
||||||
|
@ -187,22 +188,24 @@ void mdDeviceFabrik::newFromHeartbeat(const mdClientBirth &thisOne) {
|
||||||
thisKind = MACHINE;
|
thisKind = MACHINE;
|
||||||
kind = "machine";
|
kind = "machine";
|
||||||
newMachine = new mdMachine();
|
newMachine = new mdMachine();
|
||||||
if (resultat = newMachine = newMachine->validateClient( maybe, thisOne, *result )) {
|
// if (resultat = newMachine = newMachine->validateClient( maybe, thisOne, *result )) {
|
||||||
|
if (0) {
|
||||||
theMachine = newMachine;
|
theMachine = newMachine;
|
||||||
newMachine->ip = thisOne.ip;
|
newMachine->ip = thisOne.ip;
|
||||||
mdStdDevIdx = MAX_CLIEVER + thisOne.dg.hdr.dgType.clieverGroup;
|
mdStdDevIdx = MAX_CLIEVER + thisOne.dg.hdr.dgType.clieverGroup;
|
||||||
}
|
}
|
||||||
else delete newMachine;
|
else delete newMachine;
|
||||||
break;
|
break;
|
||||||
case MDDEV_INSTRUMENT:
|
case MDDEV_PEER:
|
||||||
thisKind = MDDEV_INSTRUMENT;
|
thisKind = MDDEV_PEER;
|
||||||
kind = "instrument";
|
kind = "EPP Server";
|
||||||
newInstrument = new mdInstrument();
|
newInstrument = new mdInstrument();
|
||||||
if (!(resultat = newInstrument = newInstrument->validateClient( maybe, thisOne, *result )))
|
// if (!(resultat = newInstrument = newInstrument->validateClient( maybe, thisOne, *result )))
|
||||||
|
if (0)
|
||||||
delete newInstrument;
|
delete newInstrument;
|
||||||
else {newInstrument->ip = thisOne.ip;
|
else {newInstrument->ip = thisOne.ip;
|
||||||
for (i=0;i<MAX_INSTRUMENTS && thisService->instruments[i];i++);
|
for (i=0;i<MAX_PEER && thisService->eppServers[i];i++);
|
||||||
thisService->instruments[i] = maybe;
|
thisService->eppServers[i] = maybe;
|
||||||
mdStdDevIdx = 2+i;
|
mdStdDevIdx = 2+i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue