Files
controller-wisetopdataserver/python/biopro/devlib/main.py
T
2021-12-20 14:52:55 +08:00

1121 lines
33 KiB
Python

"""
Command line
------------
Usage ::
env PYTHONPATH=RaspBerryPi3/python python -m biopro.devlib.main -L RaspBerryPi3/python/res/devlib/json/ ...
"""
import json as _json
from pprint import pprint
from shutil import copyfile
from biopro.recording import RecordingMetaFile, RecordingData
from biopro.util.cli import *
from biopro.util.console import hex_table, hex_value
from biopro.util.text import Table
from .data import DataDecodeFormat
from .encoder import *
from .library import *
# noinspection PyUnusedLocal
class Main(CliMain):
"""command line for testing device library.
"""
def __init__(self):
super().__init__()
self._argument: List[str] = []
self.repository = DeviceLibraryRepository()
self._library: Optional[DeviceLibrary] = None
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help_usage('[OPTIONS]', 'COMMAND')
self.print_help_usage('[OPTIONS]', 'LIBRARY[:VERSION]')
self.print_help_usage('[OPTIONS]', 'LIBRARY[:VERSION]', 'COMMAND', 'ARGS...')
self.print_help(print_usage=False)
@cli_flags('-r')
def _recursive(self, opt: str):
""""""
self.recursive = True
@cli_options('-L', '--library', value='PATH')
def _library_path(self, opt: str, value: str):
"""library search path"""
self.repository.add_library_path(value)
@cli_command('help')
def _help_command(self, act, argv: List[str]):
"""print help"""
if len(argv) == 0:
self.print_help()
else:
# use wrong type of library
# we expect sub-command do nothing but '-h',
# so library would not be used.
self._library = ''
self.parsing([argv[0], '-h'])
@cli_command('list')
def _list_command(self, act, argv: List[str]):
"""list library in path"""
return _MainListCommand(act, self)
@cli_command('match')
def _find_command(self, act, argv: List[str]):
"""find library in path by device response info"""
return _MainMatchCommand(act, self)
@cli_command('load')
def _load_command(self, act, argv: List[str]):
"""load library with library file name"""
return _MainLoadCommand
@cli_command('match-rule')
def _match_command(self, act, argv: List[str]):
"""list library matching rule"""
if self._library is None:
raise RuntimeError('cannot call this command without LIBRARY')
return _MainSimpleLibraryCommand(act, self._library)
@cli_command('parameter')
def _para_command(self, act, argv: List[str]):
"""dump library parameter"""
if self._library is None:
raise RuntimeError('cannot call this command without LIBRARY')
return _MainParameterCommand(act, self._library)
@cli_command('encode')
def _encode_command(self, act, argv: List[str]):
"""encode parameter"""
if self._library is None:
raise RuntimeError('cannot call this command without LIBRARY')
return _MainEncodeCommand(act, self._library)
@cli_command('decode')
def _decode_command(self, act, argv: List[str]):
"""decode parameter"""
return _MainDecodeCommand(act, self)
@cli_command('instruction')
def _instruction_command(self, act, argv: List[str]):
"""call instruction"""
if self._library is None:
raise RuntimeError('cannot call this command without LIBRARY')
return _MainInstructionCommand(act, self._library)
@cli_command('ins-eval')
def _instruction_eval_command(self, act, argv: List[str]):
"""eval instruction"""
return _MainInstructionEvalCommand
@cli_command('compress')
def _compress_command(self, act, argv: List[str]):
"""compress devlib"""
return _MainCompressCommand
@cli_command('data')
def _data_command(self, act, argv: List[str]):
"""data decoder"""
return _MainDataCommand
@cli_arguments('*', left_all=True)
def _argument_handle(self, pos: int, value: str):
""""""
self._argument.append(value)
def run(self):
if len(self._argument) == 0:
self._help('')
else:
library_expr = self._argument[0]
library_name, library_version = part_suffix(library_expr, ':')
self._library = library = self.repository.get_library(library_name, library_version)
if library is None:
print('library ' + library_expr + ' not found')
elif len(self._argument) == 1:
# dump library content
pprint(library.as_json(), width=120)
else:
# redirect command
command = self._argument[1]
args = self._argument[2:]
self.invoke_subcommand(command, args)
# noinspection PyUnusedLocal
class _MainLoadCommand(CliSubCommandMain):
def __init__(self, command: str):
super().__init__(command)
self.file_name = None
self.print_file_name = False
self.dump_library = False
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_arguments(0, value='NAME')
def _file_name(self, pos: int, value: str):
"""library file name"""
self.file_name = value
@cli_flags('--dump')
def _dump_library(self, flag: str):
"""dump library content after loading successfully"""
self.dump_library = True
@cli_flags('--path')
def _print_file_name(self, flag: str):
"""print the file path of loaded library"""
self.print_file_name = True
def run(self):
if self.file_name is None:
raise RuntimeError('lost NAME')
library = self._load_library()
if self.dump_library:
pprint(library.as_json(), width=120)
def _load_library(self) -> DeviceLibrary:
p = Path(self.file_name)
if p.exists():
if self.print_file_name:
print(str(p))
return DeviceLibrary.load(p)
else:
raise FileNotFoundError(str(p))
# noinspection PyUnusedLocal
class _MainListCommand(CliSubCommandMain):
def __init__(self, command: str, main: Main):
super().__init__(command)
self._main = main
self.show_library_path = False
self.show_all_result = False
self._check_options = []
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_flags('--show-path')
def _show_library_path(self, opt: str):
"""print library file path"""
self.show_library_path = True
@cli_options('--check', value='ITEM,...')
def _check_options(self, opt: str, value: str):
""""""
if ',' in value:
self._check_options.extend(value.split(','))
else:
self._check_options.append(value)
@cli_flags('--list-all')
def _list_all(self, opt: str):
""""""
self.show_all_result = True
@cli_flags('--list-check-item')
def _list_check_options(self, opt: str):
""""""
t = Table('ITEM', 'description')
t.append('match', 'check match rule')
t.set_format(1, align_right=False)
t.print()
self.force_return()
def run(self):
repository = self._main.repository
repository.on_error = self._on_error
repository.invalid_cache()
all_lib = repository.get_library_all()
if len(self._check_options) == 0:
for lib in all_lib:
if self.show_library_path:
print(lib.name, lib.version, lib.file_path)
else:
print(lib.name, lib.version)
else:
for it in self._check_options:
if it == 'match':
self._check_match(all_lib)
else:
print('unknown check item : ' + it)
def _on_error(self, lib_path: Path, th: BaseException):
print('error', lib_path, ':', th)
def _check_match(self, all_lib: List[DeviceLibrary]):
d1: Dict[DeviceMatchRule, DeviceLibrary] = {}
for lib in all_lib:
match_rule = lib.match_rule
if isinstance(match_rule, DeviceMatchRule):
match_rule = [match_rule]
for m in match_rule:
d1[m] = lib
x = [0, 0, 0, 0, 0, 0]
for m in d1.keys():
e = m.major_product_number
if e is not None:
v = e.to_number
if v is not None:
x[0] = max(x[0], v)
e = m.minor_product_number
if e is not None:
v = e.to_number
if v is not None:
x[1] = max(x[1], v)
e = m.major_version_number
if e is not None:
v = e.to_number
if v is not None:
x[2] = max(x[2], v)
e = m.minor_version_number
if e is not None:
v = e.to_number
if v is not None:
x[3] = max(x[3], v)
e = m.serial_year_number
if e is not None:
v = e.to_number
if v is not None:
x[4] = max(x[4], v)
e = m.serial_month_number
if e is not None:
v = e.to_number
if v is not None:
x[5] = max(x[5], v)
for p1 in range(x[0] + 1):
for p2 in range(x[1] + 1):
for v1 in range(x[2] + 1):
for v2 in range(x[3] + 1):
for s1 in range(x[4] + 1):
for s2 in range(x[5] + 1):
serial = DeviceSerialNumber(p1, p2, v1, v2, s1, s2)
response = DeviceResponseInfo(None, serial, EMPTY_ADDRESS)
ds = list(filter(lambda it: it.is_device_match(response), d1.values()))
if len(ds) > 1 or self.show_all_result:
header = str(serial)
for i, d in enumerate(ds):
if self.show_library_path:
p = d.file_path
else:
p = ''
print(header if i == 0 else ' ' * len(header), d.name, d.version, p)
# noinspection PyUnusedLocal
class _MainMatchCommand(_MainListCommand):
def __init__(self, command: str, main: Main):
super().__init__(command, main)
self.device_name = None
self.major_product_number = None
self.minor_product_number = None
self.major_version_number = None
self.minor_version_number = None
self.serial_year_number = 0
self.serial_month_number = 0
self.show_response_info = False
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_flags('--show-resp')
def _show_response_info(self, opt: str):
"""print response information"""
self.show_response_info = True
@cli_arguments(0, value='NAME')
def _device_name(self, pos: int, value: str):
"""device name"""
self.device_name = value
@cli_arguments('*', value='VALUE')
def _args(self, pos: int, value: str):
"""device serial numbers. required at least 4, at most 6 numbers"""
if pos == 1:
self.major_product_number = int(value)
elif pos == 2:
self.minor_product_number = int(value)
elif pos == 3:
self.major_version_number = int(value)
elif pos == 4:
self.minor_version_number = int(value)
elif pos == 5:
self.serial_year_number = int(value)
elif pos == 6:
self.serial_month_number = int(value)
else:
raise RuntimeError('unknown arguments : ' + value)
def run(self):
if self.device_name is None:
raise RuntimeError('lost NAME')
if self.major_product_number is None:
raise RuntimeError('lost major product number')
if self.minor_product_number is None:
raise RuntimeError('lost minor product number')
if self.major_version_number is None:
raise RuntimeError('lost major version number')
if self.minor_version_number is None:
raise RuntimeError('lost minor version number')
response = DeviceResponseInfo(self.device_name,
DeviceSerialNumber(self.major_product_number,
self.minor_product_number,
self.major_version_number,
self.minor_version_number,
self.serial_year_number,
self.serial_month_number),
EMPTY_ADDRESS)
if self.show_response_info:
pprint(response.as_json(), indent=1)
repository = self._main.repository
for lib in repository.get_library_all():
if lib.is_device_match(response):
if self.show_library_path:
print(lib.name, lib.version, lib.file_path)
else:
print(lib.name, lib.version)
break
else:
print('no library match')
# noinspection PyUnusedLocal
class _MainInstructionEvalCommand(CliSubCommandMain):
def __init__(self, command: str):
super().__init__(command)
self.parameter: Dict[str, Any] = {}
self.instruction: List[str] = []
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_options('-P', value='KEY=VALUE')
def _parameter(self, opt: str, value: str):
"""set parameter P value"""
p, v = part_suffix(value, '=')
self.parameter[p] = int(v)
@cli_options('-f', value='FILE')
def _file(self, opt: str, value: str):
"""use file"""
with open(value) as f:
for line in f:
if line.startswith('#'):
continue
line = line.strip()
if len(line) == 0:
continue
if '=' in line:
self._parameter('', line)
else:
self.instruction.append(line)
@cli_arguments('*', value='EXPR')
def _instruction(self, pos: int, value: str):
"""instruction expression"""
if pos == 0:
# clean content loaded from file
self.instruction.clear()
self.instruction.append(value)
def run(self):
scope = ContextScope(self.parameter)
for expression in self.instruction:
try:
instruction = InstructionContent.parse(expression)
except RuntimeError as e:
print(e)
else:
buffer = []
try:
instruction.build_instruction(scope, buffer)
except KeyError as e:
print(e, 'not defined')
else:
print(hex_line(buffer))
# noinspection PyUnusedLocal
class _MainSimpleLibraryCommand(CliSubCommandMain):
def __init__(self, command: str, library: DeviceLibrary):
super().__init__(command)
self.library = library
self.output_file = None
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_options('-o', '--output', value='FILE')
def _output_file(self, opt: str, value: str):
"""output file path"""
self.output_file = value
def run(self):
if self.command == 'match-rule':
self._dump_match_rule()
else:
raise RuntimeError('unknown command : ' + self.command)
def _dump_match_rule(self):
lib = self.library
for rule in lib.match_rule:
np = rule.local_name_pattern
p1 = rule.major_product_number
p2 = rule.minor_product_number
v1 = rule.major_version_number
v2 = rule.minor_version_number
s1 = rule.serial_year_number
s2 = rule.serial_month_number
np = np if np is not None else '.*'
p1 = p1.as_json()
p2 = p2.as_json()
v1 = v1.as_json()
v2 = v2.as_json()
s1 = s1.as_json() if s1 is not None else '*'
s2 = s2.as_json() if s2 is not None else '*'
print(repr(np), ':', p1, '.', p2, '/', v1, '.', v2, '/', s1, '.', s2, sep='')
# noinspection PyUnusedLocal
class _MainEncodeCommand(_MainSimpleLibraryCommand):
def __init__(self, command: str, library: DeviceLibrary):
super().__init__(command, library)
self.parameter_file = None
self.encode_all_parameter = False
@cli_arguments(0, value='[FILE]')
def _parameter_file(self, pos: int, value: str):
"""load parameter file"""
self.parameter_file = value
@cli_flags('-A', '--all')
def _all_parameter(self, opt: str):
"""encode all parameter"""
self.encode_all_parameter = True
def run(self):
if self.parameter_file is None:
raise RuntimeError('lost parameter file')
# load configuration
try:
configuration = DeviceConfigurationDecoder.load(self.parameter_file)
except IOError as e:
raise RuntimeError('load parameter file : ' + self.parameter_file) from e
# load library
library = self.library
# init parameter
parameter = DeviceParameter(library)
# overwrite configuration
parameter.overwrite(configuration)
# transform to configuration
configuration = DeviceParameterConfiguration(library, parameter)
# encode
encoder = DeviceConfigurationEncoder(all_parameter=self.encode_all_parameter)
data = encoder.encode(configuration)
# output
if self.output_file is None:
hex_table(data)
else:
with open(self.output_file, 'bw') as f:
f.write(data)
# noinspection PyUnusedLocal
class _MainDecodeCommand(CliSubCommandMain):
def __init__(self, command: str, main: Main):
super().__init__(command)
self._main = main
self.parameter_file = None
self.use_library: Tuple[str, Optional[str]] = None
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_arguments(0, value='FILE')
def _parameter_file(self, pos: int, value: str):
"""parameter json file or data file"""
self.parameter_file = value
@cli_options('-L', '--library', value='LIBRARY[:VERSION]')
def _use_library(self, flag: str, value: str):
"""use library to fit configuration"""
self.use_library = part_suffix(value, ':')
def run(self):
if self.parameter_file is None:
raise RuntimeError('lost parameter file')
# load parameter
try:
configuration = DeviceConfigurationDecoder.load(self.parameter_file)
except IOError as e:
raise RuntimeError('load parameter file : ' + self.parameter_file) from e
if self.use_library is None:
pprint(configuration.as_json(), width=120)
else:
# load library
library_name, library_version = self.use_library
library = self._main.repository.get_library(library_name, library_version)
if library is None:
raise RuntimeError('library ' + library_name + ' not found')
# init configuration
parameter = DeviceParameter(library)
# overwrite configuration
parameter.overwrite(configuration)
# output
configuration = DeviceParameterConfiguration(library, parameter)
pprint(configuration.as_json(), width=120)
# noinspection PyUnusedLocal
class _MainDeviceCommand(_MainSimpleLibraryCommand):
def __init__(self, command: str, library: DeviceLibrary):
super().__init__(command, library)
self.parameter = DeviceParameter(library)
self._cache_device: CompletedDevice = None
self._cache_context: Scope = None
self._extend_parameter_options()
def _extend_parameter_options(self):
p = self.parameter
m: Dict[str, str] = {}
h: List[CliHandleOption] = []
for k in p.keys():
info = self.library.parameter_table[k]
o = '--' + k.lower().replace('_', '-')
m[o] = k
h.append(CliHandleOption(o, help_doc=info.description))
if len(h) > 0:
# noinspection PyShadowingNames
def _callback(flag: str, value: Optional[str]):
k = m[flag]
info = self.library.parameter_table[k]
if isinstance(info.domain, ParameterCollectionDomain):
p.oper_parameter(k, value)
else:
p.set_parameter(k, int(value))
self.extend_options_callback(_callback, *h,
help_section='options for ' + self.library.name)
@cli_options('-p', '--parameter', value='FILE')
def _parameter_file(self, opt: str, value: str):
"""load parameter json file or data file"""
# load configuration
try:
configuration = DeviceConfigurationDecoder.load(value)
except IOError as e:
raise RuntimeError('load parameter file : ' + value) from e
# overwrite configuration
self.parameter.overwrite(configuration)
def run(self):
raise RuntimeError()
def _new_device(self) -> CompletedDevice:
if self._cache_device is None:
# init device
self._cache_device = DebugDevice(None, self.library, 0)
self._cache_device.parameter.overwrite(self.parameter)
return self._cache_device
def _new_context(self) -> Scope:
if self._cache_context is None:
library = self.library
device = self._new_device()
# init context
self._cache_context = library.constant.chain(DeviceParameterScope(device.parameter))
return self._cache_context
# noinspection PyUnusedLocal
class _MainParameterCommand(_MainDeviceCommand):
def __init__(self, command: str, library: DeviceLibrary):
super().__init__(command, library)
self.only_recording_parameter = False
self.raw_parameter_value = False
self.generate_meta_file = False
self.parameter_name = None
self.parameter_value = None
@cli_flags('-r')
def _only_recording_parameter(self, flag: str):
"""only recording parameter"""
self.only_recording_parameter = True
if self.raw_parameter_value or self.generate_meta_file:
raise RuntimeError('only one of -r, -R or -m')
@cli_flags('-R')
def _raw_parameter_value(self, flag: str):
"""use raw parameter value"""
self.raw_parameter_value = True
if self.only_recording_parameter or self.generate_meta_file:
raise RuntimeError('only one of -r, -R or -m')
@cli_flags('-m')
def _generate_meta_file(self, flag: str):
"""generate meta file"""
self.generate_meta_file = True
if self.raw_parameter_value or self.only_recording_parameter:
raise RuntimeError('only one of -r, -R or -m')
@cli_arguments(0, '[PARAMETER]')
def _parameter_name(self, pos: int, value: str):
"""get/set parameter"""
self.parameter_name = value
@cli_arguments(1, '[VALUE]')
def _parameter_value(self, pos: int, value: str):
"""set parameter"""
self.parameter_value = value
def run(self):
if self.parameter_name is None:
self._run_no_arg()
else:
self._run_with_arg()
def _run_no_arg(self):
lib = self.library
parameter = self.parameter
if self.generate_meta_file:
configuration = DeviceParameterConfiguration(lib, parameter)
if self.output_file is None:
output_file = self.library.name
else:
output_file = self.output_file
meta = RecordingMetaFile(output_file)
meta.configuration = configuration
meta.write()
if self.output_file is None:
print('generate', meta.filepath)
return
elif self.raw_parameter_value:
j = parameter.as_json()
else:
configuration = DeviceParameterConfiguration(lib, parameter)
if self.only_recording_parameter:
j = configuration.as_json()
else:
j = configuration.as_json(list_hide=True)
if self.output_file is None:
pprint(j, width=120)
else:
with open(self.output_file, 'w') as f:
_json.dump(j, f, indent=2)
def _run_with_arg(self):
lib = self.library
parameter = self.parameter
device = self._new_device()
parameter_value = device.get_parameter(self.parameter_name)
if self.parameter_value is not None:
device.set_parameter(self.parameter_name, self.parameter_value)
parameter_value = device.get_parameter(self.parameter_name)
# TODO option flag for overwrite parameter file
print(parameter_value)
# noinspection PyUnusedLocal
class _MainInstructionCommand(_MainDeviceCommand):
def __init__(self, command: str, library: DeviceLibrary):
super().__init__(command, library)
self.instruction = None
self._check_options = []
@cli_arguments(0, value='INSTRUCTION')
def _instruction(self, pos: int, value: str):
"""instruction call"""
self.instruction = value
@cli_options('--check', value='ITEM,...')
def _check_options(self, opt: str, value: str):
""""""
if ',' in value:
self._check_options.extend(value.split(','))
else:
self._check_options.append(value)
@cli_flags('--list-check-item')
def _list_check_options(self, opt: str):
""""""
t = Table('ITEM', 'description')
t.append('all', 'eval all instruction')
t.set_format(1, align_right=False)
t.print()
self.force_return()
def run(self):
# load library
library = self.library
if len(self._check_options) == 0:
if self.instruction is None:
for instruction in library.instruction_table:
print(instruction)
else:
library.instruction_table.invoke_instruction(self._receive,
self._new_context(),
self.instruction)
else:
for it in self._check_options:
if it == 'all':
self._check_eval_all()
else:
print('unknown check item : ' + it)
def _check_eval_all(self):
table = self.library.instruction_table
context = self._new_context()
for instruction in table:
print()
print(instruction)
table.invoke_instruction(self._receive, context, instruction)
@staticmethod
def _receive(ins: SingleInstruction):
if isinstance(ins, BuiltinInstruction):
buf = [
ins.instruction_type & 0xF0,
(ins.instruction_oper & 0xF0),
]
print('%-32s%s' % (ins.name, hex_line(buf)))
elif isinstance(ins, InternalInstruction):
print('%-32s%s' % (ins.name, str(ins.instruction_parameter)))
if ins.name == '_cdr':
data_format: str = ins.instruction_parameter
context = ContextScope()
InternalInstruction.cdr_parse(context, data_format)
for k in context.locals():
print(' %-30s%s' % (k, context[k]))
else:
cnt = ins.instruction_content
buf = [
ins.instruction_type & 0xF0,
(ins.instruction_oper & 0xF0) | (len(cnt) & 0x0F),
*cnt
]
print('%-32s%s' % (ins.name, hex_line(buf)))
# noinspection PyUnusedLocal
class _MainCompressCommand(CliSubCommandMain):
def __init__(self, command: str):
super().__init__(command)
self.source_file_list: List[str] = []
self.make_directory_parent = False
self.flag_target_first = False
self.flag_overwrite = False
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_flags('-p', '--parent')
def _parent(self, opt: str):
"""make parent of target directory if not exists"""
self.make_directory_parent = True
@cli_flags('-f', '--force')
def _force(self, opt: str):
"""overwrite if target file exist"""
self.flag_overwrite = True
@cli_flags('-t')
def _target_first(self, opt: str):
"""output directory"""
self.flag_target_first = True
@cli_arguments('+', value='FILE')
def _file(self, pos: int, value: str):
""""""
self.source_file_list.append(value)
def run(self):
if len(self.source_file_list) == 0:
if self._target_first:
raise RuntimeError('lost source file')
else:
raise RuntimeError('lost target directory')
if self.flag_target_first:
target_directory = self.source_file_list[0]
source_file = self.source_file_list[1:]
else:
target_directory = self.source_file_list[-1]
source_file = self.source_file_list[:-1]
target_directory = Path(target_directory)
if not target_directory.exists():
target_directory.mkdir(parents=True)
elif not target_directory.is_dir():
raise NotADirectoryError(str(target_directory))
for p in source_file:
if p.endswith(DeviceLibrary.FILE_EXT[0]):
p = Path(p)
t = target_directory / p.name.replace(DeviceLibrary.FILE_EXT[0], DeviceLibrary.FILE_EXT[1])
if t.exists() and self.flag_overwrite:
t.unlink()
self.compress(p, t)
elif p.endswith(DeviceLibrary.FILE_EXT[1]):
# just move
p = Path(p)
t = (target_directory / p.name).with_suffix(DeviceLibrary.FILE_EXT[1])
if t.exists() and self.flag_overwrite:
t.unlink()
copyfile(p, t)
else:
raise RuntimeError('unknown file type : ' + p)
@classmethod
def compress(cls, source: Path, target: Path):
if not source.exists():
raise FileNotFoundError(str(source))
if target.exists():
raise FileExistsError(str(target))
with source.open('rb') as _s, target.open('wb') as _t:
_t.write(DeviceLibrary.FILE_HEADER)
with gzip.GzipFile(fileobj=_t) as _g:
r = _s.read(1024)
while len(r):
_g.write(r)
r = _s.read(1024)
# noinspection PyUnusedLocal
class _MainDataCommand(CliSubCommandMain):
def __init__(self, command: str):
super().__init__(command)
self.data_format: str = None
self.data_content: Union[List[str], bytes] = []
@cli_flags('-h', '--help', force_return=True)
def _help(self, opt: str):
"""print help document"""
self.print_help()
@cli_arguments(0, value='FORMAT')
def _data_format(self, pos: int, value: str):
"""data decoder name"""
self.data_format = value
@cli_arguments('*', value='CONTENT')
def _data_content(self, pos: int, value: str):
"""data content in hex"""
self.data_content.append(value)
def run(self):
data_format = DataDecodeFormat.parse(self.data_format)
if isinstance(self.data_content, list):
data_content = bytes(map(hex_value, self.data_content))
else:
data_content = self.data_content
data = data_format.decode(data_content)
if data is None:
print('None')
elif isinstance(data, bytes):
print(hex_line(data))
else:
data: RecordingData = data
t = Table(column=3)
t.append('time stamp', data.time_stamp, 'ms')
t.append('sample rate', data.sample_rate, '1/s')
t.append('time', 'channel', 'value')
for s, c, v in data:
t.append('%.2f' % s, str(c), str(v))
t.print()
if __name__ == '__main__':
Main().main()