def offline_jianmo(self, shujulujing, moxinglujingqianzhui, timestamp=0, send=send): """Start building model for offline data Arguments: shujulujing {str} -- The offline data moxinglujingqianzhui {str} -- The prefix of model path, '.mat' will be added for real mpdel path Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 means success, 1 means fail """ send(real_time_reply.OK()) # The state should be 'Idle' if self.check_state('Idle', 'offline_jianmo', send=send) == 1: return 1 # Check {shujulujing} if not os.path.exists(shujulujing): onerror(runtime_error.FileError, shujulujing, send=send) return 1 # Try to mkdir and check of [moxinglujingqianzhui] try: mkdir(os.path.dirname(moxinglujingqianzhui)) except: onerror(runtime_error.FileError, moxinglujingqianzhui, send=send) return 1 # Workload moxinglujing = f'{moxinglujingqianzhui}.mat' # todo: Building a model self.latest_jianmo_send = send self.latest_shujulujing = shujulujing self.latest_moxinglujing = moxinglujing try: self.send_backend( dict(cmd='jianmo', moxinglujing=moxinglujing, shujulujing=shujulujing)) except: logger.info('Fail on sending jianmo request to backend.') # If not USE_BACKEND,**************************************** # use response_jianmo if not USE_BACKEND: self.response_jianmo(zhunquelv="1.0", timestamp=0, send=send) logger.debug('Building model.') logger.info('Building model.') return 0
def response_jianmo(self, zhunquelv, timestamp=0, send=send): moxinglujing = self.latest_moxinglujing shujulujing = self.latest_shujulujing self.latest_jianmo_send( dict(mode='Offline', cmd='zhunquelv', moxinglujing=moxinglujing, zhunquelv=zhunquelv, timestamp=time.time())) if not USE_BACKEND: print('-' * 80) print(moxinglujing) with open(moxinglujing, 'w') as f: f.writelines(['Fake model.']) logger.debug( f'Built model based on {shujulujing}, model has been saved in {moxinglujing}.' ) logger.info( f'Built model based on {shujulujing}, model has been saved in {moxinglujing}.' ) pass
def offline_jieshucaiji(self, timestamp=0, send=send): """Stop offline collection Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 means success, 1 means fail """ send(real_time_reply.OK()) # The state should be 'Offline' if self.check_state('Offline', 'offline_jieshucaiji', send=send) == 1: return 1 # workload self.state = 'Idle' # Stop backend try: self.send_backend(dict(cmd='jieshucaiji')) except: logger.info('Fail to stop offline recording in backend.') traceback.print_exc() if not USE_BACKEND: with open(self._shujulujing, 'w') as f: f.writelines(['Fake data.']) logger.debug('Stopped offline collection.') return 0
def starts(self): """ Start serving """ self.server.listen(1) t = threading.Thread(target=self.maintain_clients, name='TCP server') t.setDaemon(True) t.start() logger.info(f'TCP Server started.')
def query(self, chixushijian, zhenshibiaoqian, timestamp=0, send=send): """Answer for query package during ONLINE collection Arguments: chixushijian {float} -- Duration of the latest motion zhenshibiaoqian {str} -- True label of motion (image or actural motion) Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 for success, 1 for fail """ send(real_time_reply.OK()) # The state should be 'Online' if self.check_state('Online', 'query', send=send) == 1: return 1 # Workload # Save the [send] as [latest_query_send], # the query result will be send through it self.latest_query_send = send self.latest_zhenshibiaoqian = zhenshibiaoqian try: self.send_backend(dict(cmd='query')) except: logger.info(f'Fail to send query request to backend.') # If not USE_BACKEND,**************************************** # simulation response_query if not USE_BACKEND: # Use fix latency for message recognizeable time.sleep(0.1) self.response_query(zhenshibiaoqian, timestamp=0, send=send) # # Guess label, always return '2' for now # # todo: Estimate label from real data # logger.debug('Estimating label.') # gujibiaoqian = '2' # # Send back Query result # send(dict(mode='QueryReply', # gujibiaoqian=gujibiaoqian, # timestamp=time.time())) # # Send UI a motion order, # # if estimated and real label are both '2' # if all([gujibiaoqian == '2', # zhenshibiaoqian == '2']): # self.send_UI(dict(mode='Online', # cmd='kaishiyundong', # timestamp=time.time())) # logger.debug('Responded to query package') return 0
def maintain_clients(self): """ Maintain clients pool. """ while True: # Wait for new client c, a = self.new_client() # New client instance client = Client(client=c, address=a) # Add new client into client pool self.clientpool.append(client) logger.info(f'New client accepted {a}')
def state(self, s): """Safe switch STATE into [s] Arguments: s {str} -- The name of new state, one from ['Idle', 'Busy', 'Online', 'Offline'] """ assert (s in ['Idle', 'Busy', 'Online', 'Offline']) if not s == self._state: self._state = s logger.info(f'State switched to {s}.') logger.debug(f'State switched to {s}.')
def online_jieshucaiji(self, timestamp=0, send=send): """Stop online collection Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method. (default: {send}) Returns: {int} -- 0 for success, 1 for fail """ send(real_time_reply.OK()) # The state should be 'Online' if self.check_state('Online', 'online_jieshucaiji', send=send) == 1: return 1 # Workload # Stop backend try: self.send_backend(dict(cmd='jieshucaiji')) except: logger.info('Fail to stop offline recording in backend.') traceback.print_exc() if not USE_BACKEND: with open(self._shujulujing, 'w') as f: f.writelines(['Fake online data.']) # Calculate accuracy try: zhunquelv = self.accuracy() logger.debug(f'Accuracy is {zhunquelv}, labels are {self.labels}.') except: logger.debug( f'Accuracy can not be calculated, labels are {self.labels}') raise ValueError( f'Accuracy can not be calculated, labels are {self.labels}') # Send accuracy back to UI as remembered send( dict( mode='Online', cmd='zhunquelv', zhunquelv=str(zhunquelv), # Covert accuracy into {str} moxinglujing=self.moxinglujing, shujulujing=self.shujulujing, timestamp=time.time())) self.state = 'Idle' logger.debug('Stopped online collection.') return 0
def offline_kaishicaiji(self, shujulujingqianzhui, timestamp=0, send=send): """Start offline collection Arguments: shujulujingqianzhui {str} -- The prefix of data path, '.cnt' will be added for real data path Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 for success, 1 for fail """ # Send OK means I has got everything in need, # but not guartee that all the things are correct, # if incorrect, I will reply Error in further send(real_time_reply.OK()) # The state should be 'Idle' self.force_Idle() if self.check_state('Idle', 'offline_kaishicaiji', send=send) == 1: return 1 # Try to mkdir and check of [shujulujingqianzhui] dir try: mkdir(os.path.dirname(shujulujingqianzhui)) except: onerror(runtime_error.FileError, shujulujingqianzhui, send=send) return 1 # Workload self.get_ready(state='Offline') path = f'{shujulujingqianzhui}.mat' if not USE_BACKEND: self._shujulujing = path try: self.send_backend( dict(cmd='kaishicaiji', mat_path=path, model_path='[empty]')) except: logger.info('Fail to start offline recording in backend.') traceback.print_exc() # Start self.record function as separate daemon threading # t = threading.Thread(target=self.record, args=(path,)) # t.setDaemon(True) # t.start() logger.debug('Started offline collection.') return 0
def __init__(self, ip=IP, port=PORT): """Default init Keyword Arguments: ip {str} -- Legal IP address, like 'localhost' or '127.0.0.1' (default: {IP}) port {int} -- Legal port, like 65535 (default: {PORT}) """ # Init server self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server.bind((ip, port)) logger.info(f'TCP Server is parepared listening on {ip}:{port}') # self.server.listen(1) # Init clients pool self._clientpool = []
def send(self, msg, encoding='utf-8'): """Send [msg] to connected TCP Client Arguments: msg {str} -- [description] """ # Dumps dict if isinstance(msg, dict): msg = json.dumps(msg, ensure_ascii=False).encode(encoding) # Encode str if isinstance(msg, str): msg = msg.encode(encoding) # Send self.client.sendall(msg) logger.info(f'Sent {msg} to {self.address}') logger.debug(f'Sent {msg} to {self.address}')
def force_Idle(self): """Force State to Idle, used for kaishicaiji by-force. """ if self.state == 'Idle': return 0 msg = f'Current state is {self.state}, setting it to Idle by-force.' logger.info(msg) logger.debug(msg) # Stop backend logger.debug('Send jieshucaiji to backend.') try: self.send_backend(dict(cmd='jieshucaiji')) except: logger.info('Fail to stop offline recording in backend.') traceback.print_exc() # workload self.state = 'Idle'
def response_query(self, gujibiaoqian, timestamp=0, send=send): self.latest_query_send( dict(mode='QueryReply', gujibiaoqian=gujibiaoqian, timestamp=time.time())) zhenshibiaoqian = self.latest_zhenshibiaoqian if all([gujibiaoqian == '1', zhenshibiaoqian == '1']): self.send_UI( dict(mode='Online', cmd='kaishiyundong', timestamp=time.time())) self.labels.append((gujibiaoqian, zhenshibiaoqian)) logger.info( f'Estimated label: {gujibiaoqian}, True label: {zhenshibiaoqian}') logger.debug( f'Estimated label: {gujibiaoqian}, True label: {zhenshibiaoqian}') logger.debug(f'Labels is {self.labels}') pass
def get_ready(self, state='Idle', moxinglujing=None, shujulujing=None, send_UI=send): """Get ready for comming operation, switch STATE into 'Idle', empty LABELS, when STATE is switch into 'Online', make sure it has a valid send_UI. Keyword Arguments: state {str} -- Witch STATE will be set. (default: {'Idle'}) moxinglujing {str} -- The path of model. (default: {None}) shujulujing {str} -- The path of data. (default: {None}) send_UI {func} -- Method of send_ui, means send to UI TCP client, to tell UI something when income TCP client may not be UI. (default: {send}) """ self.state = state self._labels = [] self.moxinglujing = moxinglujing self.shujulujing = shujulujing self.send_UI = send_UI logger.info(f'Worker is ready to go, {state}.')
def __init__(self, client, address, onclose=None): """Start [client] for listening at [address], [onclose] is a function that will be called when client is closed. Arguments: client {Client instance} -- The connected TCP Client address {str} -- Address str Keyword Arguments: onclose {func} -- Method will be called when client is closed (default: {None}) """ # Setup client and onclose handler self.client = client self.address = address if onclose is None: self.onclose = self.default_onclose else: self.onclose = onclose # Start listening t = threading.Thread(target=self.listening) t.setDaemon(True) t.start() logger.info(f'New client started {address}')
def __init__(self, ip=IP, port=PORT): self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server.bind((ip, port)) logger.info(f'TCP Server is ready to listen on {ip}:{port}')
def start(self): """TCP server starts, now it serves forever, if it is disconnected, it will start a new listening immediately. """ while True: try: self.server.listen(1) logger.info(f'TCP Server starts listening.') # Accept in comming connection client, address = self.server.accept() logger.info( f'New connection is established: {address}:{client}') # Say hi........... # client.sendall(b'hello') # Intending I am a EEG device, # and I am serving. interval = 0.1 passed_time = 0 states = ['rest', 'imag', 'rest', 'imag'] idx = 0 t = time.time() print(states[idx]) # Whether the data slice contains a trigger on head self.new_switch = True while True: # Make up bits according to [state] and [interval] bits = make_up_package( self.make_signal(state=states[idx], interval=interval)) # Send bits client.sendall(bits) time.sleep(interval - (time.time() - t) % interval) # Update passed_time passed_time += interval # The state will be updated every 5 seconds if passed_time > 5: # Every time we update idx, # new_switch should be set self.new_switch = True # Update idx idx += 1 idx %= len(states) print(states[idx]) # Reset passed_time passed_time = 0 except ConnectionAbortedError: continue except KeyboardInterrupt: break client.close()
import numpy as np import time import os import sys import struct import socket print(__file__) # noqa sys.path.append(os.path.dirname(__file__)) # noqa from local_profile import IP, PORT, BUF_SIZE, NUM_CHANNEL, SFREQ, logger logger.info('---- New Session ----') def make_up_package(floats): """Make up Dry EEG device package Arguments: floats {list} -- List of float values, the values will be sent as simulation of an EEG device Returns: bits {bytes} -- Well formulated bytes to simulate an EEG device """ # Fixed stuffs # 0-1-2-3-4 _token = b'@ABCD' # 5 _type = chr(1).encode()
def online_kaishicaiji(self, moxinglujing, shujulujingqianzhui, timestamp=0, send=send): """Start Online collection Arguments: moxinglujing {str} -- The path of model, it should be an existing path shujulujingqianzhui {str} -- The prefix of data path, '.cnt' will be added in real data path Keyword Arguments: timestamp {int} -- [description] (default: {0}) send {func} -- Sending method (default: {send}) Returns: {int} -- 0 for success, 1 for fail """ send(real_time_reply.OK()) # Check moxinglujing if not os.path.exists(os.path.dirname(moxinglujing)): onerror(runtime_error.FileError, moxinglujing, send=send) return 1 # Try to mkdir and check of {shujulujingqianzhui} try: mkdir(os.path.dirname(shujulujingqianzhui)) except: onerror(runtime_error.FileError, shujulujingqianzhui, send=send) return 1 # The state should be 'Idle' self.force_Idle() if self.check_state('Idle', 'online_kaishicaiji', send=send) == 1: return 1 # Workload path = f'{shujulujingqianzhui}.mat' if not USE_BACKEND: self._shujulujing = path # Remember Send-to-UI method, # as Start online collection can only be triggered by UI. self.get_ready(state='Online', moxinglujing=moxinglujing, shujulujing=path, send_UI=send) try: self.send_backend( dict(cmd='kaishicaiji', mat_path=path, model_path=moxinglujing)) except: logger.info('Fail to start online recording in backend.') traceback.print_exc() # Start daemon thread for data collection and start it # t = threading.Thread(target=self.record, args=(path, moxinglujing)) # t.setDaemon(True) # t.start() logger.debug('Started online collection.') return 0
def listening(self): """ Listen and handling incoming message """ while True: try: # Get data data = self.client.recv(BUF_SIZE) logger.info(f'Received {data}, from {self.address}') logger.debug( '{dash} New data received {dash}'.format(dash='-' * 8)) logger.debug(f'Received {data}, from {self.address}') # If empty package received, it means the client to be closed. assert (not data == b'') # Parse data using JSON format, # Decode data try: decoded_data = data.decode('utf-8') except: logger.info(f'{data} can not be decoded.') logger.debug(f'{data} can not be decoded.') continue # send ParseError if parsing is failed try: D = json.loads(decoded_data) except: logger.debug( f'{decoded_data} can not be loaded by JSON, try linked expection.' ) try: split = decoded_data.split('}{') D = list() for s in split: if not s.startswith('{'): s = '{' + s if not s.endswith('}'): s = s + '}' D.append(json.loads(s)) logger.debug(f'Link exception success: {D}.') except: logger.error( f'{decoded_data} can not be loaded by JSON') logger.error('{}'.format(traceback.format_exc())) self.send( real_time_reply.ParseError(detail=decoded_data)) continue # print(D) # Deal with D if isinstance(D, list): for d in D: self.deal(d) else: self.deal(D) except Exception: traceback.print_exc() logger.debug(traceback.format_exc()) # Close the client self.client.close() # Stop listening break # Run onclose function self.onclose() logger.info(f'Connection closed {self.client}.')
def accept_backend(self, timestamp=0, send=send): self.send_backend = send logger.info('Backend connection established.') pass
import socket import threading import traceback print(__file__) # noqa sys.path.append(os.path.dirname(__file__)) # noqa from worker import Worker from local_profile import IP, PORT, BUF_SIZE from local_profile import logger, RealtimeReply, RuntimeError from local_profile import USE_BACKEND, IP_EEG_DEVICE, PORT_EEG_DEVICE from backend_toolbox import new_backend import local_profile CurrentDirectory = os.path.dirname(local_profile.__file__) logger.info('---- New Session ----') logger.info('---- Version 2020-05-29 ----') # Worker instance worker = Worker() # Real-time reply instance real_time_reply = RealtimeReply() # runtime error instance runtime_error = RuntimeError() def reg_timestamp(timestamp, tmp=time.time()): """Regularize time stamp and rescale it into time.time() Arguments: timestamp {object} -- Input time stamp.