def __init__(self): # create logger self.logger = logging.getLogger('frame_receiver_client') self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter( '%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) # Create the appropriate IPC channels self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.ctrl_channel.connect('tcp://127.0.0.1:5000') self._run = True
def __init__(self): prog_name = os.path.basename(sys.argv[0]) # Parse command line arguments self.args = self._parse_arguments(prog_name) # create logger self.logger = logging.getLogger(prog_name) self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter( '%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) # Create the appropriate IPC channels self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.ctrl_channel.connect(self.args.ctrl_endpoint) self._run = True
def __init__(self, run_status_signal, num_frames, app_main, live_view_signal): ''' This is executed on the first run of each GUI session - this object is retained throughout the lifecycle of the session. ''' try: self.run_status_signal = run_status_signal self.num_frames = num_frames self.app_main = app_main self.live_view_signal = live_view_signal self.hdf_file_location = None print("Launching Frame Receiver and Frame Processor") # Getting location of FR & FP and paths of their config files fr_fp_location = self.app_main.getCachedParam("frameReceiverProcessorLocation") frame_receiver_config_path = self.app_main.getCachedParam("frameReceiverConfigFile") frame_processor_config_path = self.app_main.getCachedParam("frameProcessorConfigFile") # Using Subprocess to launch the frame receiver and frame processor self.frame_receiver = Popen(["./frameReceiver", "--logconfig", frame_receiver_config_path], cwd=fr_fp_location) self.frame_processor = Popen(["./frameProcessor", "--logconfig", frame_processor_config_path], cwd=fr_fp_location) # Create the appropriate IPC channels for receiver and proccessor print("Connecting to Frame Receiver's IPC Control Channel") self.fr_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fr_ctrl_channel.connect(self.app_main.getCachedParam('odinFrCtrlChannel')) print("Connecting to Frame Proccessor's IPC Control Channel") self.fp_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fp_ctrl_channel.connect(self.app_main.getCachedParam('odinFpCtrlChannel')) except Exception as e: print("LdpFemOdinDataReceiver got exception during initialisation: %s" % e)
def __init__(self, args=None, prog_name=None, logger=None): if prog_name is None: prog_name = os.path.basename(sys.argv[0]) # Parse command line arguments self.args = self._parse_arguments(prog_name, args) # Create logger if not specified if logger is None: self.logger = logging.getLogger(prog_name) self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter('%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) else: self.logger = logger # Create the appropriate IPC channels self.fr_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fr_ctrl_channel.connect(self.args.fr_ctrl_endpoint) self.fp_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fp_ctrl_channel.connect(self.args.fp_ctrl_endpoint) self.channels = [('receiver', self.fr_ctrl_channel), ('processor', self.fp_ctrl_channel)] # Create empty receiver and processor configuration parameter dicts self.fr_config = {} self.fp_config = {} self.fp_plugins = [] # Set default number of frames, file path and name self.frames = 1 self.file_path = '/tmp' self.file_name = 'test.hdf5' # Internal IpcMessage ID counter self._msg_id = 0
def __init__(self, ip_address, port): self.logger = logging.getLogger(self.__class__.__name__) self._ip_address = ip_address self._port = port self.ctrl_endpoint = self.ENDPOINT_TEMPLATE.format(IP=ip_address, PORT=port) self.logger.debug("Connecting to client at %s", self.ctrl_endpoint) self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.ctrl_channel.connect(self.ctrl_endpoint) self.message_id = 0 self._lock = RLock()
def afterEditing(self): self.parentApp.ctrl_endpoint = self.ctrl.value self.parentApp.ready_endpoint = self.ready.value self.parentApp.release_endpoint = self.release.value self.parentApp.shared_buffer = self.buffer.value self.parentApp._ctrl_channel = IpcChannel( IpcChannel.CHANNEL_TYPE_DEALER) self.parentApp._ctrl_channel.connect(self.ctrl.value) self.parentApp.setNextForm("MAIN_MENU")
def __init__(self): # Initialise the logging module with log messages directed to stdout #logging.basicConfig(format='%(asctime)s %(levelname)s FrameProcessor - %(message)s', level=logging.DEBUG) #ch = logging.StreamHandler(sys.stdout) #logging.addHandler(ch) # create logger self.logger = logging.getLogger('frame_processor') self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter( '%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) # Instantiate a configuration container object, which will be populated # with sensible default values self.config = FrameProcessorConfig( "FrameProcessor", "FrameProcessor - test harness to simulate operation of FrameProcessor application" ) # Create the appropriate IPC channels self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_REQ) self.ready_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_SUB) self.release_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_PUB) # Zero frames recevied counter self.frames_received = 0 # Create the thread to handle frame processing self.frame_processor = threading.Thread(target=self.process_frames) self.frame_processor.daemon = True self._run = True
class FrameReceiverClient(object): def __init__(self): # create logger self.logger = logging.getLogger('frame_receiver_client') self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter( '%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) # Create the appropriate IPC channels self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.ctrl_channel.connect('tcp://127.0.0.1:5000') self._run = True def run(self): self.logger.info("Frame receiver client starting up") self.logger.debug("Control IPC channel has identity {}".format( self.ctrl_channel.identity)) msg = IpcMessage('cmd', 'configure') msg.set_param('test', {'list': True}) self.ctrl_channel.send(msg.encode()) pollevts = self.ctrl_channel.poll(1000) if pollevts == IpcChannel.POLLIN: reply = IpcMessage(from_str=self.ctrl_channel.recv()) self.logger.info("Got response: {}".format(reply))
class FrameReceiverClient(object): def __init__(self): prog_name = os.path.basename(sys.argv[0]) # Parse command line arguments self.args = self._parse_arguments(prog_name) # create logger self.logger = logging.getLogger(prog_name) self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter( '%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) # Create the appropriate IPC channels self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.ctrl_channel.connect(self.args.ctrl_endpoint) self._run = True def _parse_arguments(self, prog_name=sys.argv[0]): parser = argparse.ArgumentParser( prog=prog_name, description='ODIN Frame Receiver Client') parser.add_argument( '--ctrl', type=str, default='tcp://127.0.0.1:5000', dest='ctrl_endpoint', help='Specify the IPC control channel endpoint URL') parser.add_argument( '--config', type=argparse.FileType('r'), dest='config_file', nargs='?', default=None, const=sys.stdin, help='Specify JSON configuration file to send as configure command' ) parser.add_argument( '--status', action='store_true', help='Request a status report from the frame receiver') parser.add_argument('--shutdown', action='store_true', help='Instruct the frame receiver to shut down') args = parser.parse_args() return args def run(self): self.logger.info("Frame receiver client starting up") self.logger.debug("Control IPC channel has identity {}".format( self.ctrl_channel.identity)) if self.args.config_file is not None: self.do_config_cmd(self.args.config_file) if self.args.status: self.do_status_cmd() if self.args.shutdown: self.do_shutdown_cmd() def do_config_cmd(self, config_file): try: config_params = json.load(config_file) config_msg = IpcMessage('cmd', 'configure') for param, value in config_params.items(): config_msg.set_param(param, value) self.logger.info( "Sending configure command to frame receiver with specified parameters" ) self.ctrl_channel.send(config_msg.encode()) self.await_response() except JSONDecodeError as e: self.logger.error( "Failed to parse configuration file: {}".format(e)) def do_status_cmd(self): status_msg = IpcMessage('cmd', 'status') self.logger.info("Sending status request to frame receiver") self.ctrl_channel.send(status_msg.encode()) self.await_response() def do_shutdown_cmd(self): shutdown_msg = IpcMessage('cmd', 'shutdown') self.logger.info("Sending shutdown command to frame receiver") self.ctrl_channel.send(shutdown_msg.encode()) self.await_response() def await_response(self, timeout_ms=1000): pollevts = self.ctrl_channel.poll(1000) if pollevts == IpcChannel.POLLIN: reply = IpcMessage(from_str=self.ctrl_channel.recv()) self.logger.info("Got response: {}".format(reply))
class OdinDataClient(object): MESSAGE_ID_MAX = 2**32 def __init__(self, args=None, prog_name=None, logger=None): if prog_name is None: prog_name = os.path.basename(sys.argv[0]) # Parse command line arguments self.args = self._parse_arguments(prog_name, args) # Create logger if not specified if logger is None: self.logger = logging.getLogger(prog_name) self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter('%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) else: self.logger = logger # Create the appropriate IPC channels self.fr_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fr_ctrl_channel.connect(self.args.fr_ctrl_endpoint) self.fp_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fp_ctrl_channel.connect(self.args.fp_ctrl_endpoint) self.channels = [('receiver', self.fr_ctrl_channel), ('processor', self.fp_ctrl_channel)] # Create empty receiver and processor configuration parameter dicts self.fr_config = {} self.fp_config = {} self.fp_plugins = [] # Set default number of frames, file path and name self.frames = 1 self.file_path = '/tmp' self.file_name = 'test.hdf5' # Internal IpcMessage ID counter self._msg_id = 0 def _next_msg_id(self): self._msg_id = (self._msg_id + 1) % self.MESSAGE_ID_MAX return self._msg_id def run(self): self.logger.info("Odin data client starting up") self.logger.debug("Frame receiver control IPC channel has identity {}".format(self.fr_ctrl_channel.identity)) self.logger.debug("Frame processor control IPC channel has identity {}".format(self.fp_ctrl_channel.identity)) if self.args.config_file is not None: self.load_config(self.args.config_file) if self.args.frames: self.set_num_frames(self.args.frames) if self.args.bitdepth: self.set_bitdepth(self.args.bitdepth) if self.args.file_path: self.set_file_path(self.args.file_path) if self.args.file_name: self.set_file_name(self.args.file_name) if self.args.config: self.do_config_cmd() if self.args.start: self.set_file_writing(True) elif self.args.stop: self.set_file_writing(False) if self.args.status: self.do_status_cmd() if self.args.getconfig: self.do_request_config_cmd() if self.args.shutdown: self.do_shutdown_cmd() def load_config(self, config_file): self.logger.debug("Parsing default configuration from file {}".format(config_file.name)) try: config_params = json.load(config_file) if 'receiver_default_config' in config_params: self.fr_config = config_params['receiver_default_config'] if 'processor_default_config' in config_params: self.fp_config = config_params['processor_default_config'] if 'processor_plugins' in config_params: self.fp_plugins = config_params['processor_plugins'] except JSONDecodeError as e: self.logger.error("Failed to parse configuration file: {}".format(e)) def _ensure_config_section(self, config, section): if section not in config: config[section] = {} self.logger.debug("Created {} section in config params".format(section)) def set_num_frames(self, frames): self.frames = frames self._ensure_config_section(self.fp_config, 'hdf') self.fp_config['hdf']['frames'] = frames def set_file_path(self, file_path): self.file_path = file_path self._ensure_config_section(self.fp_config, 'hdf') self._ensure_config_section(self.fp_config['hdf'], 'file') self.fp_config['hdf']['file']['path'] = file_path def set_file_name(self, file_name): self.file_name = file_name self._ensure_config_section(self.fp_config, 'hdf') self._ensure_config_section(self.fp_config['hdf'], 'file') self.fp_config['hdf']['file']['name'] = file_name def set_bitdepth(self, bitdepth): bitdepth_str = '{:d}-bit'.format(bitdepth) self._ensure_config_section(self.fr_config, 'decoder_config') self.fr_config['decoder_config']['bitdepth'] = bitdepth_str self._ensure_config_section(self.fp_config, 'excalibur') self.fp_config['excalibur']['bitdepth'] = bitdepth_str rdtype_map = { 1: 0, 6: 0, 12: 1, 24: 2, } rdtype = rdtype_map[bitdepth] self._ensure_config_section(self.fp_config, 'hdf') self._ensure_config_section(self.fp_config['hdf'], 'dataset') self._ensure_config_section(self.fp_config['hdf']['dataset'], 'data') self.fp_config['hdf']['dataset']['data']['datatype'] = rdtype #print(self.fp_config) def do_config_cmd(self): self.logger.info("Sending configuration command to frame receiver") self.send_config_cmd(self.fr_ctrl_channel, self.fr_config) if 'fr_setup' in self.fp_config: self.logger.info("Sending receiver plugin configuration command to frame processor") params = {'fr_setup' : self.fp_config['fr_setup']} self.send_config_cmd(self.fp_ctrl_channel, params) if len(self.fp_plugins): self.logger.info( "Sending {} plugin chain configuration commands to frame processor".format( len(self.fp_plugins))) for plugin in self.fp_plugins: self.send_config_cmd(self.fp_ctrl_channel, plugin) self.logger.info("Sending plugin parameter configuration command to frame processor") self.send_config_cmd(self.fp_ctrl_channel, self.fp_config) def send_config_cmd(self, channel, params): config_msg = IpcMessage('cmd', 'configure', id=self._next_msg_id()) config_msg.attrs['params'] = params channel.send(config_msg.encode()) self.await_response(channel) def set_file_writing(self, enable): self.set_file_name(self.file_name) self.set_file_path(self.file_path) self.set_num_frames(self.frames) self.fp_config['hdf']['frames'] = self.frames self.fp_config['hdf']['write'] = enable # write_config = {} # if enable: # write_config['file'] = { # "path": self.file_path, # "name": self.file_name, # } # write_config["frames"] = self.frames # write_config["write"] = enable config_msg = IpcMessage('cmd', 'configure', id=self._next_msg_id()) #config_msg.set_param('hdf', write_config) config_msg.attrs['params'] = {'hdf': self.fp_config['hdf']} print(config_msg) self.logger.info('Sending file writing {} command to frame processor'.format( 'enable' if enable else 'disable')) self.fp_ctrl_channel.send(config_msg.encode()) self.await_response(self.fp_ctrl_channel) def do_status_cmd(self): for (name, channel) in self.channels: self.logger.info("Sending status request to frame {}".format(name)) reply = self.send_status_cmd(channel) if reply is not None: self.logger.info("Got response: {}".format(reply)) def send_status_cmd(self, channel): status_msg = IpcMessage('cmd', 'status', id=self._next_msg_id()) channel.send(status_msg.encode()) reply = self.await_response(channel) return reply def do_request_config_cmd(self): request_msg = IpcMessage('cmd', 'request_configuration', id=self._next_msg_id()) for (name, channel) in self.channels: self.logger.info("Sending configuration request for frame {}".format(name)) channel.send(request_msg.encode()) reply = self.await_response(channel) if reply is not None: self.logger.info("Got response: {}".format(reply)) def await_response(self, channel, timeout_ms=1000): reply = None pollevts = channel.poll(1000) if pollevts == IpcChannel.POLLIN: reply = IpcMessage(from_str=channel.recv()) return reply def _parse_arguments(self, prog_name=sys.argv[0], args=None): parser = argparse.ArgumentParser(prog=prog_name, description='ODIN data client') parser.add_argument('--frctrl', type=str, default='tcp://127.0.0.1:5000', dest='fr_ctrl_endpoint', help='Specify the frame recevier IPC control channel endpoint URL') parser.add_argument('--fpctrl', type=str, default='tcp://127.0.0.1:5004', dest='fp_ctrl_endpoint', help='Specify the frame processor IPC control channel endpoint URL') parser.add_argument('--default', type=argparse.FileType('r'), dest='config_file', nargs='?', default=None, const=sys.stdin, help='Specify JSON configuration file to parse for default config') parser.add_argument('--config', action='store_true', help='Send a configuration command to the processes') parser.add_argument('--frames', type=int, dest='frames', help='Override the number of frames in configuration') parser.add_argument('--bitdepth', type=int, dest='bitdepth', choices=[1, 6, 12, 24], help='Override the bit depth param in configuration') file_writing = parser.add_mutually_exclusive_group() file_writing.add_argument('--start', action='store_true', help='Start frame processor file writing') file_writing.add_argument('--stop', action='store_true', help='Stop frame processor file writing') parser.add_argument('--path', type=str, dest='file_path', help='Set file writing path') parser.add_argument('--file', type=str, dest='file_name', help='Set file writing name') parser.add_argument('--status', action='store_true', help='Request a status report from the processes') parser.add_argument('--getconfig', action='store_true', help='Get the current configuration of the processes') parser.add_argument('--shutdown', action='store_true', help='Instruct the processes to shut down') args = parser.parse_args(args) return args
class FrameProcessor(object): def __init__(self): # Initialise the logging module with log messages directed to stdout #logging.basicConfig(format='%(asctime)s %(levelname)s FrameProcessor - %(message)s', level=logging.DEBUG) #ch = logging.StreamHandler(sys.stdout) #logging.addHandler(ch) # create logger self.logger = logging.getLogger('frame_processor') self.logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler(sys.stdout) ch.setLevel(logging.DEBUG) # create formatter formatter = logging.Formatter( '%(asctime)s %(levelname)s %(name)s - %(message)s') # add formatter to ch ch.setFormatter(formatter) # add ch to logger self.logger.addHandler(ch) # Instantiate a configuration container object, which will be populated # with sensible default values self.config = FrameProcessorConfig( "FrameProcessor", "FrameProcessor - test harness to simulate operation of FrameProcessor application" ) # Create the appropriate IPC channels self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_REQ) self.ready_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_SUB) self.release_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_PUB) # Zero frames recevied counter self.frames_received = 0 # Create the thread to handle frame processing self.frame_processor = threading.Thread(target=self.process_frames) self.frame_processor.daemon = True self._run = True def map_shared_buffer(self): success = False # Check if the current configuration object has a shared buffer name defined, otherwise request one from the # upstream frameReceiver if self.config.sharedbuf is None: if not self.request_shared_buffer_config(): return success # Map the shared buffer manager try: self.shared_buffer_manager = SharedBufferManager( self.config.sharedbuf, boost_mmap_mode=self.config.boost_mmap_mode) success = True except SharedBufferManagerException as e: self.logger.error("Failed to create shared buffer manager: %s" % str(e)) return success def request_shared_buffer_config(self): success = False max_request_retries = 10 max_reply_retries = 10 request_retries = 0 config_request = IpcMessage(msg_type='cmd', msg_val='request_buffer_config') while success is False and request_retries < max_request_retries: self.logger.debug( "Sending buffer config request {}".format(request_retries + 1)) self.release_channel.send(config_request.encode()) reply_retries = 0 while success is False and reply_retries < max_reply_retries: if self.ready_channel.poll(100): config_msg = self.ready_channel.recv() config_decoded = IpcMessage(from_str=config_msg) self.logger.debug( 'Got buffer configuration response with shared buffer name: {}' .format( config_decoded.get_param('shared_buffer_name'))) self.config.sharedbuf = config_decoded.get_param( 'shared_buffer_name') success = True else: reply_retries += 1 request_retries += 1 # temp hack if not success: self.logger.error("Failed to obtain shared buffer configuration") return success def run(self): self.logger.info("Frame processor starting up") # Connect the IPC channels self.ctrl_channel.connect(self.config.ctrl_endpoint) self.ready_channel.connect(self.config.ready_endpoint) self.release_channel.connect(self.config.release_endpoint) # Ready channel subscribes to all topics self.ready_channel.subscribe(b'') # Map the shared buffer manager - quit if this fails if not self.map_shared_buffer(): self._run = False return self.logger.info( "Mapped shared buffer manager ID %d with %d buffers of size %d" % (self.shared_buffer_manager.get_manager_id(), self.shared_buffer_manager.get_num_buffers(), self.shared_buffer_manager.get_buffer_size())) if self.config.sensortype == 'percivalemulator': self.frame_decoder = PercivalEmulatorFrameDecoder( self.shared_buffer_manager) self.logger.debug( 'Loaded frame decoder for PERCIVAL emulator sensor type') elif self.config.sensortype == 'excalibur': self.frame_decoder = ExcaliburFrameDecoder( self.shared_buffer_manager) self.logger.debug('Loaded frame decoder for EXCALIBUR sensor type') else: self.frame_decoder = None self.logger.error("Unrecognised sensor type specified: %s" % self.config.sensortype) return # Launch the frame processing thread self.frame_processor.start() try: while self._run: if self.config.frames and self.frames_received >= self.config.frames: self.logger.info( "Specified number of frames (%d) received, terminating" % self.config.frames) self._run = False else: msg = IpcMessage(msg_type='cmd', msg_val='status') #self.logger.debug("Sending status command message") self.ctrl_channel.send(msg.encode()) reply = self.ctrl_channel.recv() reply_decoded = IpcMessage(from_str=reply) #self.logger.debug("Got reply, msg_type = " + reply_decoded.get_msg_type() + " val = " + reply_decoded.get_msg_val()) time.sleep(1) except KeyboardInterrupt: self.logger.info("Got interrupt, terminating") self._run = False self.frame_processor.join() self.logger.info("Frame processor shutting down") def process_frames(self): self.frame_header = Struct('<LLQQL') while self._run: if (self.ready_channel.poll(100)): ready_msg = self.ready_channel.recv() ready_decoded = IpcMessage(from_str=ready_msg) if ready_decoded.get_msg_type( ) == 'notify' and ready_decoded.get_msg_val() == 'frame_ready': frame_number = ready_decoded.get_param('frame') buffer_id = ready_decoded.get_param('buffer_id') self.logger.debug( "Got frame ready notification for frame %d buffer ID %d" % (frame_number, buffer_id)) if not self.config.bypass_mode: self.handle_frame(frame_number, buffer_id) release_msg = IpcMessage(msg_type='notify', msg_val='frame_release') release_msg.set_param('frame', frame_number) release_msg.set_param('buffer_id', buffer_id) self.release_channel.send(release_msg.encode()) self.frames_received += 1 elif ready_decoded.get_msg_type( ) == 'notify' and ready_decoded.get_msg_val( ) == 'buffer_config': shared_buffer_name = ready_decoded.get_param( 'shared_buffer_name') self.logger.debug( 'Got shared buffer config notification with name %s' % (shared_buffer_name)) else: self.logger.error( "Got unexpected message on ready notification channel: %s" % (ready_decoded)) self.logger.info("Frame processing thread interrupted, terminating") def handle_frame(self, frame_number, buffer_id): self.frame_decoder.decode_header(buffer_id) self.logger.debug( 'Frame {:d} in buffer {:d} decoded header values:\n{:s}'.format( frame_number, buffer_id, self.frame_decoder.header_state_str())) if self.config.packet_state: self.logger.debug("Packet state : \n" + self.frame_decoder.packet_state_str()) self.frame_decoder.decode_data(buffer_id) self.logger.debug("Frame start: " + ' '.join( "0x{:04x}".format(val) for val in self.frame_decoder.data.pixels[:16])) self.logger.debug("Frame end : " + ' '.join( "0x{:04x}".format(val) for val in self.frame_decoder.data.pixels[-16:]))
class LpdFemOdinDataReceiver(): ''' This object is used when the data is coming from ODIN (as opposed to internally). This object is recycled throughout the lifecycle of the GUI session ''' MESSAGE_ID_MAX = 2**32 _msg_id = 0 def __init__(self, run_status_signal, num_frames, app_main, live_view_signal): ''' This is executed on the first run of each GUI session - this object is retained throughout the lifecycle of the session. ''' try: self.run_status_signal = run_status_signal self.num_frames = num_frames self.app_main = app_main self.live_view_signal = live_view_signal self.hdf_file_location = None print("Launching Frame Receiver and Frame Processor") # Getting location of FR & FP and paths of their config files fr_fp_location = self.app_main.getCachedParam("frameReceiverProcessorLocation") frame_receiver_config_path = self.app_main.getCachedParam("frameReceiverConfigFile") frame_processor_config_path = self.app_main.getCachedParam("frameProcessorConfigFile") # Using Subprocess to launch the frame receiver and frame processor self.frame_receiver = Popen(["./frameReceiver", "--logconfig", frame_receiver_config_path], cwd=fr_fp_location) self.frame_processor = Popen(["./frameProcessor", "--logconfig", frame_processor_config_path], cwd=fr_fp_location) # Create the appropriate IPC channels for receiver and proccessor print("Connecting to Frame Receiver's IPC Control Channel") self.fr_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fr_ctrl_channel.connect(self.app_main.getCachedParam('odinFrCtrlChannel')) print("Connecting to Frame Proccessor's IPC Control Channel") self.fp_ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.fp_ctrl_channel.connect(self.app_main.getCachedParam('odinFpCtrlChannel')) except Exception as e: print("LdpFemOdinDataReceiver got exception during initialisation: %s" % e) def configure(self, num_frames, num_images): ''' Executed at the start of every run to do a number of things including creating and starting the data monitor & live view threads ''' try: self.num_frames = num_frames # Load Odin Data config print("Loading ODIN Data config from {}".format(self.app_main.getCachedParam('odinDataConfigFile'))) with open(self.app_main.getCachedParam('odinDataConfigFile')) as configFile: self.odin_data_config = json.load(configFile) self.config_receiver = self.odin_data_config['receiver_default_config'] self.config_processor = self.odin_data_config['processor_default_config'] self.config_processor_plugins = self.odin_data_config['processor_plugins'] # Set number of expected frames based on the master dataset (dataset containing the # data, as defined in odin_data_lpd_config.json) self.config_processor['hdf']['frames'] = (self.num_frames * num_images) # Set path and filename of output file print("Setting Path & Filename of Output File") file_path = self.app_main.getCachedParam('dataFilePath') self.config_processor['hdf']['file']['path'] = file_path # Set file name based on current run number run_number = self.app_main.getCachedParam('runNumber') file_name = "lpdData-{:05d}.hdf5".format(run_number) self.config_processor['hdf']['file']['name'] = file_name # Set offset and divisor in config to be used in process plugin self.config_processor['lpd']['divisor'] = self.app_main.getCachedParam('liveViewDivisor') self.config_processor['lpd']['offset'] = self.app_main.getCachedParam('liveViewOffset') print("Setting debug level for frame receiver and frame processor") debug_level = self.app_main.getCachedParam('odinDataDebugLevel') self.config_receiver['debug_level'] = debug_level self.config_processor['debug_level'] = debug_level # Send Frame Receiver config print("Sending Frame Receiver Config") self.send_config_msg(self.fr_ctrl_channel, self.config_receiver) # Send Frame Receiver info to Frame Processor print("Sending Receiver connection info to Frame Processor") params = {'fr_setup': self.config_processor['fr_setup']} self.send_config_msg(self.fp_ctrl_channel, params) # Sending Processor plugin configs if len(self.config_processor_plugins): print("Sending Processor plugin chain config to Frame Processor") for plugin in self.config_processor_plugins: self.send_config_msg(self.fp_ctrl_channel, plugin) # Send Frame Processor config print("Sending Frame Processor Config") self.send_config_msg(self.fp_ctrl_channel, self.config_processor) print("Waiting for Receiver/Processor handshake to complete") # Around 8 seconds before timeout timeout_attempts = 40 request_number = 0 # Checking status of FR/FP handshake while True: reply = self.send_status_cmd(self.fp_ctrl_channel) if reply is not None: try: shared_memory_buffer_status = reply.attrs['params']['shared_memory']['configured'] if shared_memory_buffer_status is True: print("Shared memory is now configured in FP") break except KeyError as e: print("LdpFemOdinDataReceiver got KeyError accessing shared buffer ", "status parameter: %s" % e) request_number += 1 if(request_number > timeout_attempts): raise Exception("Handshake between frame receiver and frame processor has ", "timed out") break time.sleep(0.2) print("Resetting statistics in LPD Process Plugin") self.reset_stats_cmd(self.fp_ctrl_channel) # Create data monitor object and thread then move object into thread print("Creating Data Monitor Thread") self.data_monitor = OdinDataMonitor(self) self.data_monitor_thread = QtCore.QThread() self.data_monitor.moveToThread(self.data_monitor_thread) # Connect monitor loop start signal to monitor loop function print("Starting Data Monitor Thread") self.data_monitor_thread.started.connect(self.data_monitor.monitorLoop) self.data_monitor_thread.start() if self.app_main.getCachedParam("liveViewEnable"): # Create live view receiver object and thread, then move object into thread print("Creating Live View Receiver Thread") self.live_view_receiver = LiveViewReceiver(self, self.live_view_signal, num_images) self.live_view_receiver_thread = QtCore.QThread() self.live_view_receiver.moveToThread(self.live_view_receiver_thread) # Start the thread and connect start signal to receive_data() print("Starting Live View Receiver Thread") self.live_view_receiver_thread.started.connect(self.live_view_receiver.receive_data) self.live_view_receiver_thread.start() except Exception as e: print("LdpFemOdinDataReceiver got exception during configuration: %s" % e) def awaitCompletion(self): print("Waiting for frame processing to complete") while (self.data_monitor.running) and (self.app_main.abort_run == False): time.sleep(0.1) if self.app_main.abort_run: print("Run aborted by user") self.data_monitor.abort_run() else: print("Frame processor handled all frames, terminating data monitor thread") # Set file writing and data now the run has finished self.set_file_writing(False) if self.app_main.getCachedParam("liveViewEnable"): # Subscriber in receive_data() will no longer look for data off the socket self.live_view_receiver.set_data_polling(False) # Get path of hdf file for the current run file_path = self.config_processor['hdf']['file']['path'] file_name = self.config_processor['hdf']['file']['name'] # Remove hardcoded file ending when feature disabled self.hdf_file_location = file_path + "/" + file_name + "_000001.h5" # Open hdf file for metadata to be written to it try: self.hdf_file = h5py.File(self.hdf_file_location, 'r+') except IOError as e: print("Failed to open HDF file with error: %s" % e) raise(e) # Create metadata group and add datasets to it metadata_group = self.hdf_file.create_group('metadata') self.metadata_handler = MetadataWriter(self.app_main.cached_params) self.metadata_handler.write_metadata(metadata_group) # Close hdf file self.hdf_file.close() self.data_monitor_thread.quit() self.data_monitor_thread.wait() def await_response(self, channel, timeout_ms=1000): ''' Polls the passed channel for any data to be received, used in various functions below ''' reply = None pollevts = channel.poll(timeout_ms) if pollevts == IpcChannel.POLLIN: reply = IpcMessage(from_str=channel.recv()) return reply def _next_msg_id(self): ''' Increments message ID for the IPC messages ''' self._msg_id = (self._msg_id + 1) % self.MESSAGE_ID_MAX return self._msg_id def send_config_msg(self, channel, config): ''' Sends a configuration command to the channel that's passed ''' config_msg = IpcMessage('cmd', 'configure', id=self._next_msg_id()) config_msg.attrs['params'] = config channel.send(config_msg.encode()) reply = self.await_response(channel) def send_status_cmd(self, channel): ''' Sends a status command to the channel that's passed ''' status_msg = IpcMessage('cmd', 'status', id=self._next_msg_id()) channel.send(status_msg.encode()) reply = self.await_response(channel) return reply def reset_stats_cmd(self, channel): ''' Used to reset statistics in LPD Process Plugin ''' reset = IpcMessage('cmd', 'reset_statistics', id=self._next_msg_id()) channel.send(reset.encode()) reply = self.await_response(channel) return reply def do_shutdown_cmd(self, channel): ''' Sends a shutdown command to the channel that's passed ''' shutdown_msg = IpcMessage('cmd', 'shutdown', id=self._next_msg_id()) channel.send(shutdown_msg.encode()) self.await_response(channel) def shutdown_frame_receiver_processor(self): ''' Used when GUI is closed to stop FR & FP processes ''' print("Shutting down frame receiver and frame processor") self.do_shutdown_cmd(self.fr_ctrl_channel) self.do_shutdown_cmd(self.fp_ctrl_channel) def set_file_writing(self, enable): ''' Enables or disables file writing (typically once a run has finished) ''' self.config_processor['hdf']['frames'] = self.num_frames self.config_processor['hdf']['write'] = enable config_msg = IpcMessage('cmd', 'configure', id=self._next_msg_id()) config_msg.attrs['params'] = {'hdf': self.config_processor['hdf']} print('Sending file writing {} command to frame processor'.format( 'enable' if enable else 'disable')) self.fp_ctrl_channel.send(config_msg.encode()) self.await_response(self.fp_ctrl_channel) def last_data_file(self): '''Returns the location (path) of the last data file written. ''' return self.hdf_file_location
class IpcClient(object): ENDPOINT_TEMPLATE = "tcp://{IP}:{PORT}" MESSAGE_ID_MAX = 2**32 def __init__(self, ip_address, port): self.logger = logging.getLogger(self.__class__.__name__) self._ip_address = ip_address self._port = port self.ctrl_endpoint = self.ENDPOINT_TEMPLATE.format(IP=ip_address, PORT=port) self.logger.debug("Connecting to client at %s", self.ctrl_endpoint) self.ctrl_channel = IpcChannel(IpcChannel.CHANNEL_TYPE_DEALER) self.ctrl_channel.connect(self.ctrl_endpoint) self.message_id = 0 self._lock = RLock() def _send_message(self, msg, timeout): msg.set_msg_id(self.message_id) self.message_id = (self.message_id + 1) % self.MESSAGE_ID_MAX self.logger.debug("Sending control message:\n%s", msg.encode()) with self._lock: self.ctrl_channel.send(msg.encode()) expected_id = msg.get_msg_id() id = None while not id == expected_id: pollevts = self.ctrl_channel.poll(timeout) if pollevts == zmq.POLLIN: reply = IpcMessage(from_str=self.ctrl_channel.recv()) id = reply.get_msg_id() if not id == expected_id: self.logger.warn("Dropping reply message with id [" + str(id) + "] as was expecting [" + str(expected_id) + "]") continue if reply.is_valid() and reply.get_msg_type( ) == IpcMessage.ACK: self.logger.debug("Request successful: %s", reply) return True, reply.attrs else: self.logger.debug("Request unsuccessful") return False, reply.attrs else: self.logger.warning("Received no response") return False, None @staticmethod def _raise_reply_error(msg, reply): if reply is not None: raise IpcMessageException("Request\n%s\nunsuccessful." " Got invalid response: %s" % (msg, reply)) else: raise IpcMessageException("Request\n%s\nunsuccessful." " Got no response." % msg) def send_request(self, value, timeout=1000): msg = IpcMessage("cmd", value) success, reply = self._send_message(msg, timeout) if success: return reply else: self._raise_reply_error(msg, reply) def send_configuration(self, content, target=None, valid_error=None, timeout=1000): msg = IpcMessage("cmd", "configure") if target is not None: msg.set_param(target, content) else: for parameter, value in content.items(): msg.set_param(parameter, value) success, reply = self._send_message(msg, timeout) if not success and None not in [reply, valid_error]: if reply["params"]["error"] != valid_error: self._raise_reply_error(msg, reply) else: self.logger.debug("Got valid error for request %s: %s", msg, reply) return success, reply def _read_message(self, timeout): pollevts = self.ctrl_channel.poll(timeout) if pollevts == zmq.POLLIN: reply = IpcMessage(from_str=self.ctrl_channel.recv()) return reply