import struct from typing import Optional, Union, List class DataMessage: """It is typing used of the abstract interface of ReSampleEntry which is defined in c extension. **Response Message Format** :: | | 1 | 2 | 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 ----------------------------------------------------------------- | header | data ........................................ | header message header ===== ================== value description ===== ================== 0 system message 1 parameter error 2 general message 3 data message ===== ================== 1. system message (header=0) :: | | 1 | 2 | 3 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 ----------------------------------------------------------------- | header=0xFF | length | message ..................... | #. data message see :class:`DataMessageEncoderType` for more detail **Command format** 1. command 1. greeting echo greeting response: ``greeting`` #. sync, sync:DEVICE, sync:DEVICE,... return current Data server is sync or not. response: ``start:DEVICE``, ``stop:DEVICE`` for each connected device #. broadcast:MESSAGE broadcast MESSAGE, send to controller #. start, stop start/stop routine data streaming. 2. response 1. scan, scan:update, scan:done controller scanned, found device updated #. connected, connected:DEVICE device connected #. disconnected, disconnected:DEVICE device disconnected #. start:DEVICE,..., stop:DEVICE,... #. low_power:STATE (ups power using) #. message::MESSAGE, message:DEVICE:MESSAGE data notify message #. broadcast:MESSAGE broadcast MESSAGE, receive from controller #. info:MESSAGE, warn:MESSAGE, error:MESSAGE message for command response """ HEADER_SYSTEM = 0xFF __slots__ = () GREETING = 'greeting' SYNC = 'sync' BROADCAST = 'broadcast' START_DATA_STREAM = 'start' STOP_DATA_STREAM = 'stop' SCAN = 'scan' SCAN_STATE = ('', 'update', 'done') LOW_POWER = 'low_power' LOW_POWER_STATE = ('UPS', 'EXT', 'OFF') @classmethod def response(cls, message: str) -> bytes: message = message.encode() return struct.pack('<2B%ds' % len(message), cls.HEADER_SYSTEM, len(message), message) @classmethod def greeting(cls) -> str: return cls.GREETING @classmethod def scan(cls, state: Optional[str] = None) -> str: if state is None: return cls.SCAN + ':done' elif state == '': return cls.SCAN elif state in cls.SCAN_STATE: return cls.SCAN + ':' + state else: raise ValueError() @classmethod def sync(cls, sync: bool) -> str: return 'start' if sync else 'stop' @classmethod def low_power(cls, ups_state: str): if ups_state in cls.LOW_POWER_STATE: return cls.LOW_POWER + ':' + ups_state else: raise ValueError() @classmethod def start(cls, device: Union[None, int, List[int]] = None) -> str: if device is None: return 'start' elif isinstance(device, int): return 'start:' + str(device) else: return 'start:' + ','.join(map(str, device)) @classmethod def stop(cls, device: Union[None, int, List[int]] = None) -> str: if device is None: return 'stop' elif isinstance(device, int): return 'stop:' + str(device) else: return 'stop:' + ','.join(map(str, device)) @classmethod def message(cls, message: str, device: Optional[int] = None) -> str: if device is None: return 'message::' + message else: return 'message:' + str(device) + ':' + message @classmethod def broadcast(cls, message: str) -> str: return 'broadcast:' + message @classmethod def connected(cls, device: Optional[int] = None) -> str: if device is None: return 'connected' else: return 'connected:' + str(device) @classmethod def disconnected(cls, device: Optional[int] = None) -> str: if device is None: return 'disconnected' else: return 'disconnected:' + str(device) @classmethod def info(cls, message: str) -> str: return 'info:' + message @classmethod def warn(cls, message: str) -> str: return 'warn:' + message @classmethod def error(cls, message: str) -> str: return 'error:' + message