Exemplo n.º 1
0
class PVAServer(object):
    def __init__(self, provider_name, prefix):
        self.provider = StaticProvider(provider_name)
        self.prefix = prefix
        self.pvs = []

        self.fieldNames = SharedPV(initial=NTScalar('as').wrap(
            {'value': ['pid%02x' % i for i in range(31)]}),
                                   handler=DefaultPVHandler(self))

        # 'i' (integer) or 'f' (float)
        self.fieldTypes = SharedPV(initial=NTScalar('aB').wrap(
            {'value': [ord('i')] * 31}),
                                   handler=DefaultPVHandler(self))

        self.fieldMask = SharedPV(initial=NTScalar('I').wrap({'value':
                                                              0x8000}),
                                  handler=DefaultPVHandler(self))

        self.payload = SharedPV(initial=Value(Type([]), {}),
                                handler=DefaultPVHandler(self))

        self.provider.add(prefix + 'HPS:FIELDNAMES', self.fieldNames)
        self.provider.add(prefix + 'HPS:FIELDTYPES', self.fieldTypes)
        self.provider.add(prefix + 'HPS:FIELDMASK', self.fieldMask)
        self.provider.add(prefix + 'PAYLOAD', self.payload)
        self.update()

    def update(self):
        mask = self.fieldMask.current().get('value')
        names = self.fieldNames.current().get('value')
        types = self.fieldTypes.current().get('value')
        oid = self.payload.current().getID()
        nid = str(mask)

        if nid == oid:
            nid += 'a'
        ntypes = []
        nvalues = {}
        ntypes.append(('valid', 'i'))
        nvalues['valid'] = 0
        for i in range(31):
            if mask & 1:
                ntypes.append((names[i], chr(types[i])))
                nvalues[names[i]] = 0
            mask >>= 1

        pvname = self.prefix + 'PAYLOAD'
        self.provider.remove(pvname)
        self.payload = SharedPV(initial=Value(Type(ntypes, id=nid), nvalues),
                                handler=DefaultPVHandler(self))
        print('Payload struct ID %s' % self.payload.current().getID())
        self.provider.add(pvname, self.payload)

    def forever(self):
        Server.forever(providers=[self.provider])
Exemplo n.º 2
0
class PVCtrls(threading.Thread):
    def __init__(self, prefix, app):
        threading.Thread.__init__(self, daemon=True)
        self.prefix = prefix + ':'
        self.app = app

    def run(self):
        self.provider = StaticProvider(__name__)

        self.fieldNames = SharedPV(initial=NTScalar('as').wrap(
            {'value': ['pid%02x' % i for i in range(31)]}),
                                   handler=DefaultPVHandler(self))

        # 'i' (integer) or 'f' (float)
        self.fieldTypes = SharedPV(initial=NTScalar('aB').wrap(
            {'value': [ord('i')] * 31}),
                                   handler=DefaultPVHandler(self))

        self.fieldMask = SharedPV(initial=NTScalar('I').wrap({'value':
                                                              0x8000}),
                                  handler=DefaultPVHandler(self))

        self.payload = SharedPV(initial=Value(Type([]), {}),
                                handler=DefaultPVHandler(self))

        print('Hosting {:}HPS:FIELDMASK'.format(self.prefix))
        self.provider.add(self.prefix + 'HPS:FIELDNAMES', self.fieldNames)
        self.provider.add(self.prefix + 'HPS:FIELDTYPES', self.fieldTypes)
        self.provider.add(self.prefix + 'HPS:FIELDMASK', self.fieldMask)
        self.provider.add(self.prefix + 'PAYLOAD', self.payload)
        self.update()

        try:
            Server.forever(providers=[self.provider])
        except:
            print('Server exited')

    def update(self):
        self.app.Enable.set(0)

        mask = self.fieldMask.current().get('value')
        names = self.fieldNames.current().get('value')
        types = self.fieldTypes.current().get('value')
        oid = self.payload.current().getID()
        nid = str(mask)

        print('PVCtrls.update mask[{:x}] oid[{:}]'.format(mask, oid))

        if nid == oid:
            nid += 'a'
        ntypes = []
        nvalues = {}
        ntypes.append(('valid', 'i'))
        nvalues['valid'] = 0
        mmask = mask
        for i in range(31):
            if mmask & 1:
                ntypes.append((names[i], chr(types[i])))
                nvalues[names[i]] = 0
            mmask >>= 1

        pvname = self.prefix + 'PAYLOAD'
        self.provider.remove(pvname)
        self.payload = SharedPV(initial=Value(Type(ntypes, id=nid), nvalues),
                                handler=DefaultPVHandler(self))
        print('Payload struct ID %s' % self.payload.current().getID())
        self.provider.add(pvname, self.payload)

        if mask:
            self.app.channelMask.set(mask)
            self.app.Enable.set(1)
Exemplo n.º 3
0
class PvaExportServer:
    def __init__(self, name, comm_addr, export_addr, aggregate=False):
        self.base = name
        self.ctx = zmq.Context()
        self.export = self.ctx.socket(zmq.SUB)
        self.export.setsockopt_string(zmq.SUBSCRIBE, "")
        self.export.connect(export_addr)
        self.comm = self.ctx.socket(zmq.REQ)
        self.comm.connect(comm_addr)
        self.queue = ThreadedWorkQueue(maxsize=20, workers=1)
        # pva server provider
        self.provider = StaticProvider(name)
        self.rpc_provider = NTURIDispatcher(self.queue,
                                            target=PvaExportRpcHandler(
                                                self.ctx, comm_addr),
                                            name="%s:cmd" % self.base,
                                            prefix="%s:cmd:" % self.base)
        self.server_thread = threading.Thread(target=self.server,
                                              name='pvaserv')
        self.server_thread.daemon = True
        self.aggregate = aggregate
        self.pvs = {}
        self.ignored = set()
        self.graph_pvbase = "ana"
        self.data_pvbase = "data"
        self.info_pvbase = "info"
        self.cmd_pvs = {'command'}
        self.payload_cmd_pvs = {'add', 'set', 'del'}

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()

    def close(self):
        self.ctx.destroy()

    @staticmethod
    def join_pv(*args):
        return ":".join(args)

    def graph_pvname(self, graph, name=None):
        if name is not None:
            return ":".join([self.graph_pvbase, graph, name])
        else:
            return ":".join([self.graph_pvbase, graph])

    def data_pvname(self, graph, name):
        return ":".join([self.graph_pvbase, graph, self.data_pvbase, name])

    def info_pvname(self, name):
        return ":".join([self.info_pvbase, name])

    def find_graph_pvnames(self, graph, names):
        return [
            name for name in names if name.startswith(self.graph_pvname(graph))
        ]

    def create_pv(self, name, nt, initial, func=None):
        if func is not None:
            pv = SharedPV(nt=nt,
                          initial=initial,
                          handler=PvaExportPutHandler(put=func))
        else:
            pv = SharedPV(nt=nt, initial=initial)
        self.provider.add('%s:%s' % (self.base, name), pv)
        self.pvs[name] = pv

    def create_bytes_pv(self, name, initial, func=None):
        self.create_pv(name, NTBytes(), initial, func=func)

    def valid(self, name, group=None):
        return not name.startswith('_')

    def get_pv_type(self, data):
        if isinstance(data, np.ndarray):
            return NTNDArray()
        elif isinstance(data, bool):
            return NTScalar('?')
        elif isinstance(data, int):
            return NTScalar('l')
        elif isinstance(data, float):
            return NTScalar('d')
        else:
            return NTObject()

    def update_graph(self, graph, data):
        # add the unaggregated version of the pvs
        for key, value in data.items():
            if key in NTGraph.flat_schema:
                name, nttype = NTGraph.flat_schema[key]
                pvname = self.graph_pvname(graph, name)
                if pvname not in self.pvs:
                    self.create_pv(pvname, nttype, value)
                else:
                    self.pvs[pvname].post(value)
        # add the aggregated graph pv if requested
        if self.aggregate:
            pvname = self.graph_pvname(graph)
            if pvname not in self.pvs:
                logger.debug("Creating pv for info on the graph")
                self.create_pv(pvname, NTGraph(), data)
            else:
                self.pvs[pvname].post(data)

    def update_store(self, graph, data):
        # add the unaggregated version of the pvs
        for key, value in data.items():
            if key in NTStore.flat_schema:
                name, nttype = NTStore.flat_schema[key]
                pvname = self.graph_pvname(graph, name)
                if pvname not in self.pvs:
                    self.create_pv(pvname, nttype, value)
                else:
                    self.pvs[pvname].post(value)
        # add the aggregated graph pv if requested
        if self.aggregate:
            pvname = self.graph_pvname(graph, 'store')
            if pvname not in self.pvs:
                logger.debug("Creating pv for info on the store")
                self.create_pv(pvname, NTStore(), data)
            else:
                self.pvs[pvname].post(data)

    def update_heartbeat(self, graph, heartbeat):
        pvname = self.graph_pvname(graph, 'heartbeat')
        if pvname not in self.pvs:
            self.create_pv(pvname, NTScalar('d'), heartbeat)
        else:
            self.pvs[pvname].post(heartbeat)

    def update_info(self, data):
        # add the unaggregated version of the pvs
        for key, value in data.items():
            pvname = self.info_pvname(key)
            if pvname not in self.pvs:
                self.create_pv(pvname, NTScalar('as'), value)
            else:
                self.pvs[pvname].post(value)

    def update_data(self, graph, name, data):
        pvname = self.data_pvname(graph, name)
        if pvname not in self.ignored:
            if pvname not in self.pvs:
                pv_type = self.get_pv_type(data)
                if pv_type is not None:
                    logger.debug("Creating new pv named %s for graph %s", name,
                                 graph)
                    self.create_pv(pvname, pv_type, data)
                else:
                    logger.warn(
                        "Cannot map type of '%s' from graph '%s' to PV: %s",
                        name, graph, type(data))
                    self.ignored.add(pvname)
            else:
                self.pvs[pvname].post(data)

    def update_destroy(self, graph):
        # close all the pvs associated with the purged graph
        for name in self.find_graph_pvnames(graph, self.pvs):
            logger.debug("Removing pv named %s for graph %s", name, graph)
            self.provider.remove('%s:%s' % (self.base, name))
            del self.pvs[name]
        # remove any ignored pvs associated with the purged graph
        for name in self.find_graph_pvnames(graph, self.ignored):
            self.ignored.remove(name)

    def server(self):
        server = Server(providers=[self.provider, self.rpc_provider])
        with server, self.queue:
            try:
                while True:
                    time.sleep(100)
            except KeyboardInterrupt:
                pass

    def run(self):
        # start the pva server thread
        self.server_thread.start()
        logger.info("Starting PVA data export server")
        while True:
            topic = self.export.recv_string()
            graph = self.export.recv_string()
            exports = self.export.recv_pyobj()
            if topic == 'data':
                for name, data in exports.items():
                    # ignore names starting with '_' - these are private
                    if self.valid(name):
                        self.update_data(graph, name, data)
            elif topic == 'graph':
                self.update_graph(graph, exports)
            elif topic == 'store':
                self.update_store(graph, exports)
            elif topic == 'heartbeat':
                self.update_heartbeat(graph, exports)
            elif topic == 'info':
                self.update_info(exports)
            elif topic == 'destroy':
                self.update_destroy(graph)
            else:
                logger.warn("No handler for topic: %s", topic)