201 lines
5.0 KiB
Python
201 lines
5.0 KiB
Python
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
|