alibava-gui can also work as a SOAP server. This means that we can send a number (very limited) of commands to the alibava-gui process to start or stop a run and, also, to retrieve some information about the status of the acquisition. The SOAP server and client libraries are implemented using the gSOAP toolkit for Web Services1
The SOAP commands are summarized below:
: void getStatus(in int request, out Status status);
Returns the status of the acquisition in a structure of type Status, described in Example 10. The request parameter can be ignored and one can send any value, usually 0.
: void startRun(in DAQParam daqParam, out base64binary data);
Starts a run with the parameters specified in a structure of type DAQParam described in Example 11. It returns a data block which contains various histograms.
: void stopRun(in int value, out int response);
Stops the current run. The value parameter has no meaning and any value is accepted. The output parameter, response, with return 0 if the operation was succesful and an error code otherwise.
: void setDataFile(in string fileName, out int response);
Sets the name of the data file and forces alibava-gui to log data into that file. The output parameter, response, with return 0 if the operation was succesful and an error code otherwise.
class Status { public: string status; time time; int nexpected; int ntrigger; double rate; string run_type; double value; }
class DAQParam { public: int runType; int numEvents; int sampleSize; int nbin; double xmin; double xmax; }
The data sent by the startRun consists of 2 histograms. The first contains the spectrum and the second the mean value of the signal seen by each channel. The format of the data is described in Table 5. See
Size and type | Description |
---|---|
int32 | number of histograms |
For each histogram | |
int32 | number of bins |
double | xmin |
double | xmax |
nbin * double | data chunk with nbin doubles |
The SOAP server also provides a web service where you can monitor the current status of your run. The interface is really simple. The addres you have to give to the browser is
http://address_of_your_computer:nnnn
where nnn is the port you have given to the SOAP server (10000 by default). You may need to enable that port in order to do that from another computer. Figure 22 shows an exmple of what the server will provide. It will, essentially, be the histograms that are shown at the main window of the alibava-gui application.
The test folder in the distribution contains some examples that may help understanding the procedure to communicate with alibava-gui via SOAP. The examples are written in two languages, python and C++.
In the case of python, we recomend to have SOAPpy installed in the system. It can be downloaded from http://sourceforge.net/projects/pywebsvcs/files/SOAP.py. It is also in most of the Linux distributions so the best is to use the one provided by your particular distribution if you are using Linux. The example below uses this python package. There are two parts. One that hides all the complexity of the SOAP data types intrinsic to Albava and the other the one that contains your actual commands.
The first one is shown in Example 12 and the second in Example 13.
#!/usr/bin/env python """ Basic methods to communicate via SOAP with the Alibava gui. It defines the special types: DAQParam and Status It also defines a couple of conveniece classes. Ones is Hist, that helps to access the data in form of histograms and Alibava.that encapsulates the SOAP commands """ import base64 import struct import cStringIO from SOAPpy import SOAPProxy from SOAPpy import WSDL import SOAPpy import traceback #SOAPpy.Config.debug = 1 ALIBAVA_NS="http://alibavasystems.com/alibava/" # modify SOAPBuilder # This is needed for SOAPpy versions before 0.12, # otherwise, the class daqParam can handle it def dump_DAQParam(self, obj, tag, typed = 1, ns_map = {}): """ This is a helper function for SOAPpy that will construct the request for a ParameterValue. """ if SOAPpy.Config.debug: print "In dump_DAQParam. tag=", tag tag = tag or "daqParam" tag = SOAPpy.wstools.XMLname.toXMLname(tag) # convert from SOAP 1.2 XML name encoding id = self.checkref(obj, tag, ns_map) if id == None: return try: a = obj._marshalAttrs(ns_map, self) except: a = '' try: ns = ns_map[ALIBAVA_NS] tnm = 'xsi:type="%s:DAQParam"' % (ns) except KeyError: tnm = '' self.out.append('<%s %s>\n' % (tag, tnm)) self.out.append('<runType xsi:type="xsd:int">%d</runType>\n' % obj.runType) self.out.append('<numEvents xsi:type="xsd:int">%d</numEvents>\n' % obj.numEvents) self.out.append('<sampleSize xsi:type="xsd:int">%d</sampleSize>\n' %obj.sampleSize) self.out.append('<nbin xsi:type="xsd:int">%d</nbin>' % obj.nbin) self.out.append('<xmin xsi:type="xsd:double">%f</xmin>' % obj.xmin) self.out.append('<xmax xsi:type="xsd:double">%f</xmax>' % obj.xmax) self.out.append('</%s>\n' % tag) def funcToMethod(func,clas,method_name=None): """ Helper function to add dynamically methods to a class """ import new method = new.instancemethod(func,None,clas) if not method_name: method_name=func.__name__ clas.__dict__[method_name]=method funcToMethod(dump_DAQParam, SOAPpy.SOAPBuilder, "dump_daqParam") (PEDESTAL, RADIOACTIVE, LASER, LASERSCAN, CALIBRATION) = range(0,5) class daqParam(dict): def __init__(self, run_type, num_events, sample_size, nbin=1024, xmin=-512.0, xmax=512.0): self['runType'] = int(run_type) self['numEvents'] = int(num_events) self['sampleSize'] = int(sample_size) self['nbin'] = int(nbin) self['xmin'] = float(xmin) self['xmax'] = float(xmax) def __getattr__(self, name): if name in self: return self[name] else: raise AttributeError, name class Status(object): """ The status of a DAQObject. """ attr_list = {'status': lambda x:x, 'time': lambda x:x, 'nexpected': int, 'ntrigger': int, 'rate': float, 'run_type': lambda x:x, 'value': float} def __init__(self, response): for attr, cast in Status.attr_list.items(): print attr, getattr(response, attr) setattr(self, attr, cast(getattr(response, attr))) def __str__(self): rate = self.rate; rate_units=" Hz"; thr_units = " Mb/s"; if rate>1.e6: rate /=1.e6 rate_units="MHz" elif rate>1000.0: rate /=1000. rate_units = "kHz" out = "Evts %7d time %s rate %8.1f %s value %f" % \ (self.ntrigger, self.time, rate, rate_units, self.value) return out class Hst(object): """ This is a histogram """ def __init__(self, nx, xmin, xmax, buff=None): self.nx = nx self.xmin = xmin self.xmax = xmax if buff: self.buff = buff else: buff = [ 0.0 for i in range(0, nx) ] def __str__(self): ss = "Nbin: %d xmin %f xmax %f\n" % (self.nx, self.xmin, self.xmax) i=0 for val in self.buff: ss += "%d - %f\n" %(i, val) i += 1 return ss def decode_data(data): """ This method decodes the data received from alibava-gui and returns a list of histograms. """ val = cStringIO.StringIO(base64.decodestring(data)) fmt ='i' sz = struct.calcsize(fmt) v = struct.unpack(fmt, val.read(sz)) nhst = v[0] hst_list = [] for i in range(0, nhst): fmt = 'i' sz = struct.calcsize(fmt) nbin = struct.unpack(fmt, val.read(sz))[0] fmt = 'd' sz = struct.calcsize(fmt) xmin = struct.unpack(fmt, val.read(sz))[0] fmt = 'd' sz = struct.calcsize(fmt) xmax = struct.unpack(fmt, val.read(sz))[0] fmt = "%dd" % nbin sz = struct.calcsize(fmt) hst = struct.unpack(fmt, val.read(sz)) hst_list.append( Hst(nbin, xmin, xmax, hst) ) return hst_list class soapClient(object): """ Proxy to talk to Alibava It encapsulates the SOAP client """ def __init__(self, host, port): self.server = SOAPpy.SOAPProxy("http://%s:%d/alibava" %(host, port), namespace=ALIBAVA_NS, noroot=1) def getStatus(self): return Status( self.server.getStatus() ) def stopRun(self): self.server.stopRun(0) def startPedestalRun(self, nevt, nbin=512, xmin=-512, xmax=-512, nsample=100): R = self.server.startRun(daqParam=daqParam(PEDESTAL, nevt, nsample, nbin, xmin, xmax)); return decode_data(R) def startSourceRun(self, nevt, nbin=512, xmin=-512, xmax=-512, nsample=100): R = self.server.startRun(daqParam=daqParam(RADIOACTIVE, nevt, nsample, nbin, xmin, xmax)); return decode_data(R) def startLaserRun(self, nevt, nbin=512, xmin=-512, xmax=-512, nsample=100): R = self.server.startRun(daqParam=daqParam(LASER, nevt, nsample, nbin, xmin, xmax)); return decode_data(R) def setDataFile(self, fnam): self.server.setDataFile(dataFile=fnam)
#!/usr/bin/env python """ Example of a soap client for alibava """ import sys from alibavaSOAP import soapClient, Status def main(host="localhost", port=10000): server = soapClient(host, port) S = server.getStatus() print S R = server.stopRun() R = server.startPedestalRun(1000) R = server.startLaserRun(1000, nbin=32, xmin=-512, xmax=512) for hst in R: print hst server.setDataFile( "alibava_data.dat" ) R= server.startSourceRun(1000, nbin=32) for hst in R: print hst if __name__ == "__main__": try: host = sys.argv[1] except IndexError: host = "localhost" try: port = int(sys.argv[2]) except IndexError: port = 10000 main(host, port)
The alibava package provides libraries for communicating with alibava-gui. The test folder of the distribution contains an example, which also shown in Example 14. Look at the given Makefile to see which are the requered includes and libraries. The example shown here also uses the Histogram class whose implementation can also be found in the test folder of the distribution.
#include <iostream> #include <iomanip> #include <sstream> #include <vector> #include <algorithm> #include <soapalibavaSOAPProxy.h> #include "Histogram.h" std::ostream &operator<<(std::ostream &os, const ns1__Status &st) { double rate = st.rate; std::string rate_units = " Hz"; std::string thr_units; if (rate > 1.e6) { rate /= 1.e6; rate_units = "MHz"; } else if (rate > 1000.) { rate /= 1000.; rate_units = "kHz"; } os << "Evts " << std::setiosflags(std::ios::fixed | std::ios::right) << std::setw(7) << st.ntrigger << " time " << std::setw(6) << std::setprecision(1) << st.time << " rate " << std::setw(8) << std::setprecision(1) << rate << rate_units << " eff " << std::setw(5) << "[" << st.status << "]" << std::flush; return os; } class soapClient { public: typedef std::vector<Histogram *> HstList; private: alibavaSOAPProxy *server; HstList histograms; void reset_histograms(); public: soapClient(); ~soapClient(); void connect(const char *uri); int getStatus(ns1__Status &status); int setDataFile(const char *ofile); int stopRun(); int startRun(ns1__RunType type, int nevt, int nbin, int xmin, int xmax, int nsample); int startPedestalRun(int nevt, int nbin= 512, int xmin=-512, int xmax= 512, int nsample=100); int startSourceRun(int nevt, int nbin= 512, int xmin=-512, int xmax=512, int nsample=100); int startLaserRun(int nevt, int nbin=512, int xmin=-512, int xmax=512, int nsample=100); Histogram *get_histogram(int ix) { return histograms[ix]; } }; soapClient::soapClient() : server(0) { } void soapClient::connect(const char *uri) { if (server) delete server; server = new alibavaSOAPProxy(uri); } soapClient::~soapClient() { if (server) delete server; reset_histograms(); } struct HstEraser : public std::unary_function<Histogram *, void> { HstEraser() {} void operator() (Histogram *hst) { delete hst; } }; void soapClient::reset_histograms() { std::for_each(histograms.begin(), histograms.end(), HstEraser() ); histograms.clear(); } int soapClient::setDataFile(const char *ofile) { if (!server) return 1; ns1__setDataFileResponse response; return server->setDataFile(ofile, response); } int soapClient::getStatus(ns1__Status &status) { if (!server) return 1; ns1__getStatusResponse response; server->getStatus(0, response); ns1__Status *ss = response.status; status.status = ss->status; status.nexpected = ss->nexpected; status.ntrigger = ss->ntrigger; status.rate = ss->rate; status.time = ss->time; status.value = ss->value; return 0; } int soapClient::stopRun() { if (!server) return 1; ns1__stopRunResponse response; return server->stopRun(0, response); } int soapClient::startRun(ns1__RunType type, int nevt, int nbin, int xmin, int xmax, int nsample) { ns1__startRunResponse response; ns1__DAQParam param; param.nbin = nbin; param.xmin = xmin; param.xmax = xmax; param.numEvents = nevt; param.sampleSize = nsample; param.runType = type; server->startRun(¶m, response); std::istringstream is( std::string( (const char *)response.startRunResponse.__ptr, (size_t)response.startRunResponse.__size ) ); int ihst, nhst; const char *titles[] = { "Spectrum", "Channel Profile", 0 }; is.read((char *)&nhst, sizeof(int)); for(ihst=0; ihst<nhst;ihst++) { Histogram *hst = new Histogram(titles[ihst % 2], titles[ihst % 2], 1, 0., 1.); hst->import_from_soap(is); histograms.push_back(hst); } return 0; } int soapClient::startPedestalRun(int nevt, int nbin, int xmin, int xmax, int nsample) { if (!server) return 1; return startRun(ns1__RunType__Pedestal, nevt, nbin, xmin, xmax, nsample); } int soapClient::startSourceRun(int nevt, int nbin, int xmin, int xmax, int nsample) { if (!server) return 1; return startRun(ns1__RunType__RadioactiveSource, nevt, nbin, xmin, xmax, nsample); } int soapClient::startLaserRun(int nevt, int nbin, int xmin, int xmax, int nsample) { if (!server) return 1; return startRun(ns1__RunType__Laser, nevt, nbin, xmin, xmax, nsample); } int main(int argc, char **argv) { const char *uri = "http://localhost:10000"; soapClient client; ns1__Status status; if (argv[1]) uri = argv[1]; client.connect(uri); client.getStatus(status); std::cout << "Status:" << std::endl; std::cout << status << std::endl; client.startPedestalRun(5000); client.startLaserRun(5000); client.getStatus(status); std::cout << "Status:" << std::endl; std::cout << status << std::endl; client.setDataFile("/tmp/data_file.dat"); client.startSourceRun(10000); client.getStatus(status); std::cout << "Status:" << std::endl; std::cout << status << std::endl; client.get_histogram(0)->Print(std::cout); return 0; }
Robert A. van Engelen and Kyle Gallivan, The gSOAP Toolkit for Web Services and Peer-To-Peer Computing Networks, in the proceedings of the 2nd IEEE International Symposium on Cluster Computing and the Grid (CCGrid2002), pages 128-135, May 21-24, 2002, Berlin, Germany.