Merge branch 'main' into fix-argcomplete

This commit is contained in:
Szymon Borecki
2023-08-26 19:26:20 +02:00
committed by GitHub
13 changed files with 191 additions and 93 deletions
+14 -7
View File
@@ -42,7 +42,8 @@ class ChameleonCLI:
"""
def __init__(self):
self.completer = chameleon_utils.CustomNestedCompleter.from_nested_dict(chameleon_cli_unit.root_commands)
self.completer = chameleon_utils.CustomNestedCompleter.from_nested_dict(
chameleon_cli_unit.root_commands)
self.session = prompt_toolkit.PromptSession(completer=self.completer,
history=FileHistory(pathlib.Path.home() / ".chameleon_history"))
@@ -103,12 +104,14 @@ class ChameleonCLI:
else:
# wait user input
try:
cmd_str = self.session.prompt(ANSI(self.get_prompt())).strip()
cmd_str = self.session.prompt(
ANSI(self.get_prompt())).strip()
except EOFError:
closing = True
except KeyboardInterrupt:
closing = True
cmd_strs = cmd_str.replace("\r\n", "\n").replace("\r", "\n").split("\n")
cmd_strs = cmd_str.replace(
"\r\n", "\n").replace("\r", "\n").split("\n")
cmd_str = cmd_strs.pop(0)
if closing or cmd_str in ["exit", "quit", "q", "e"]:
@@ -129,18 +132,21 @@ class ChameleonCLI:
print("".ljust(18, "-") + "".ljust(10) + "".ljust(30, "-"))
for cmd_name, cmd_node in chameleon_cli_unit.root_commands.items():
cmd_title = f"{colorama.Fore.GREEN}{cmd_name}{colorama.Style.RESET_ALL}"
help_line = (f" - {cmd_title}".ljust(37)) + f"[ {cmd_node.help_text} ]"
help_line = (f" - {cmd_title}".ljust(37)
) + f"[ {cmd_node.help_text} ]"
print(help_line)
continue
tree_node, arg_list = self.get_cmd_node(chameleon_cli_unit.root_commands[root_cmd], argv[1:])
tree_node, arg_list = self.get_cmd_node(
chameleon_cli_unit.root_commands[root_cmd], argv[1:])
if not tree_node.cls:
# Found tree node is a group without an implementation, print children
print("".ljust(18, "-") + "".ljust(10) + "".ljust(30, "-"))
for child in tree_node.children:
cmd_title = f"{colorama.Fore.GREEN}{child.name}{colorama.Style.RESET_ALL}"
help_line = (f" - {cmd_title}".ljust(37)) + f"[ {child.help_text} ]"
help_line = (f" - {cmd_title}".ljust(37)
) + f"[ {child.help_text} ]"
print(help_line)
continue
@@ -170,7 +176,8 @@ class ChameleonCLI:
except (chameleon_utils.UnexpectedResponseError, chameleon_utils.ArgsParserError) as e:
print(f"{colorama.Fore.RED}{str(e)}{colorama.Style.RESET_ALL}")
except Exception:
print(f"CLI exception: {colorama.Fore.RED}{traceback.format_exc()}{colorama.Style.RESET_ALL}")
print(
f"CLI exception: {colorama.Fore.RED}{traceback.format_exc()}{colorama.Style.RESET_ALL}")
if __name__ == '__main__':
+118 -59
View File
@@ -158,8 +158,10 @@ hw_mode = hw.subgroup('mode', 'Device mode get/set')
hw_slot = hw.subgroup('slot', 'Emulation tag slot.')
hw_slot_nick = hw_slot.subgroup('nick', 'Get/Set tag nick name for slot')
hw_settings = hw.subgroup('settings', 'Chameleon settings management')
hw_settings_animation = hw_settings.subgroup('animation', 'Manage wake-up and sleep animation modes')
hw_settings_button_press = hw_settings.subgroup('btnpress', 'Manage button press function')
hw_settings_animation = hw_settings.subgroup(
'animation', 'Manage wake-up and sleep animation modes')
hw_settings_button_press = hw_settings.subgroup(
'btnpress', 'Manage button press function')
hf = CLITree('hf', 'high frequency tag/reader')
hf_14a = hf.subgroup('14a', 'ISO14443-a tag read/write/info...')
@@ -169,7 +171,8 @@ hf_mf_detection = hf.subgroup(
lf = CLITree('lf', 'low frequency tag/reader')
lf_em = lf.subgroup('em', 'EM410x read/write/emulator')
lf_em_sim = lf_em.subgroup('sim', 'Manage EM410x emulation data for selected slot')
lf_em_sim = lf_em.subgroup(
'sim', 'Manage EM410x emulation data for selected slot')
root_commands: dict[str, CLITree] = {
'hw': hw,
@@ -194,7 +197,8 @@ class HWConnect(BaseCLIUnit):
platform_name = uname().release
if 'Microsoft' in platform_name:
path = os.environ["PATH"].split(os.pathsep)
path.append("/mnt/c/Windows/System32/WindowsPowerShell/v1.0/")
path.append(
"/mnt/c/Windows/System32/WindowsPowerShell/v1.0/")
for prefix in path:
fn = os.path.join(prefix, "powershell.exe")
if not os.path.isdir(fn) and os.access(fn, os.X_OK):
@@ -221,7 +225,8 @@ class HWConnect(BaseCLIUnit):
args.port = port.device
break
if args.port is None: # If no chameleon was found, exit
print("Chameleon not found, please connect the device or try connecting manually with the -p flag.")
print(
"Chameleon not found, please connect the device or try connecting manually with the -p flag.")
return
self.device_com.open(args.port)
print(" { Chameleon connected } ")
@@ -253,7 +258,8 @@ class HWModeGet(DeviceRequiredUnit):
pass
def on_exec(self, args: argparse.Namespace):
print(f"- Device Mode ( Tag {'Reader' if self.cmd.is_reader_device_mode() else 'Emulator'} )")
print(
f"- Device Mode ( Tag {'Reader' if self.cmd.is_reader_device_mode() else 'Emulator'} )")
@hw_chipid.command('get', 'Get device chipset ID')
@@ -351,7 +357,8 @@ class HFMFNested(ReaderRequiredUnit):
help="The block where the key of the card is known")
parser.add_argument('--type-known', type=str, required=True, choices=type_choices,
help="The key type of the tag")
parser.add_argument('--key-known', type=str, required=True, metavar="hex", help="tag sector key")
parser.add_argument('--key-known', type=str,
required=True, metavar="hex", help="tag sector key")
parser.add_argument('--block-target', type=int, metavar="decimal",
help="The key of the target block to recover")
parser.add_argument('--type-target', type=str, choices=type_choices,
@@ -370,10 +377,13 @@ class HFMFNested(ReaderRequiredUnit):
:return:
"""
# acquire
dist_resp = self.cmd.detect_nt_distance(block_known, type_known, key_known)
nt_resp = self.cmd.acquire_nested(block_known, type_known, key_known, block_target, type_target)
dist_resp = self.cmd.detect_nt_distance(
block_known, type_known, key_known)
nt_resp = self.cmd.acquire_nested(
block_known, type_known, key_known, block_target, type_target)
# parse
dist_obj = chameleon_cstruct.parse_nt_distance_detect_result(dist_resp.data)
dist_obj = chameleon_cstruct.parse_nt_distance_detect_result(
dist_resp.data)
nt_obj = chameleon_cstruct.parse_nested_nt_acquire_group(nt_resp.data)
# create cmd
cmd_param = f"{dist_obj['uid']} {dist_obj['dist']}"
@@ -405,7 +415,8 @@ class HFMFNested(ReaderRequiredUnit):
print(f" - [{len(key_list)} candidate keys found ]")
for key in key_list:
key_bytes = bytearray.fromhex(key)
ret = self.cmd.auth_mf1_key(block_target, type_target, key_bytes)
ret = self.cmd.auth_mf1_key(
block_target, type_target, key_bytes)
if ret.status == chameleon_status.Device.HF_TAG_OK:
return key
else:
@@ -429,8 +440,10 @@ class HFMFNested(ReaderRequiredUnit):
type_target = args.type_target
if block_target is not None and type_target is not None:
type_target = 0x60 if type_target == 'A' or type_target == 'a' else 0x61
print(f" - {colorama.Fore.CYAN}Nested recover one key running...{colorama.Style.RESET_ALL}")
key = self.recover_a_key(block_known, type_known, key_known, block_target, type_target)
print(
f" - {colorama.Fore.CYAN}Nested recover one key running...{colorama.Style.RESET_ALL}")
key = self.recover_a_key(
block_known, type_known, key_known, block_target, type_target)
if key is None:
print("No keys found, you can retry recover.")
else:
@@ -439,7 +452,8 @@ class HFMFNested(ReaderRequiredUnit):
print("Please input block_target and type_target")
self.args_parser().print_help()
else:
raise NotImplementedError("hf mf nested recover all key not implement.")
raise NotImplementedError(
"hf mf nested recover all key not implement.")
return
@@ -464,9 +478,11 @@ class HFMFDarkside(ReaderRequiredUnit):
first_recover = True
retry_count = 0
while retry_count < 0xFF:
darkside_resp = self.cmd.acquire_darkside(block_target, type_target, first_recover, 15)
darkside_resp = self.cmd.acquire_darkside(
block_target, type_target, first_recover, 15)
first_recover = False # not first run.
darkside_obj = chameleon_cstruct.parse_darkside_acquire_result(darkside_resp.data)
darkside_obj = chameleon_cstruct.parse_darkside_acquire_result(
darkside_resp.data)
self.darkside_list.append(darkside_obj)
recover_params = f"{darkside_obj['uid']}"
for darkside_item in self.darkside_list:
@@ -497,7 +513,8 @@ class HFMFDarkside(ReaderRequiredUnit):
# auth key
for key in key_list:
key_bytes = bytearray.fromhex(key)
auth_ret = self.cmd.auth_mf1_key(block_target, type_target, key_bytes)
auth_ret = self.cmd.auth_mf1_key(
block_target, type_target, key_bytes)
if auth_ret.status == chameleon_status.Device.HF_TAG_OK:
return key
return None
@@ -520,7 +537,8 @@ class BaseMF1AuthOpera(ReaderRequiredUnit):
help="The block where the key of the card is known")
parser.add_argument('-t', '--type', type=str, required=True, choices=type_choices,
help="The key type of the tag")
parser.add_argument('-k', '--key', type=str, required=True, metavar="hex", help="tag sector key")
parser.add_argument('-k', '--key', type=str,
required=True, metavar="hex", help="tag sector key")
return parser
def get_param(self, args):
@@ -562,9 +580,11 @@ class HFMFWRBL(BaseMF1AuthOpera):
if not re.match(r"^[a-fA-F0-9]{32}$", args.data):
raise ArgsParserError("Data must include 32 HEX symbols")
param.data = bytearray.fromhex(args.data)
resp = self.cmd.write_mf1_block(param.block, param.type, param.key, param.data)
resp = self.cmd.write_mf1_block(
param.block, param.type, param.key, param.data)
if resp.status == chameleon_status.Device.HF_TAG_OK:
print(f" - {colorama.Fore.GREEN}Write done.{colorama.Style.RESET_ALL}")
print(
f" - {colorama.Fore.GREEN}Write done.{colorama.Style.RESET_ALL}")
else:
print(f" - {colorama.Fore.RED}Write fail.{colorama.Style.RESET_ALL}")
@@ -573,7 +593,8 @@ class HFMFWRBL(BaseMF1AuthOpera):
class HFMFDetectionEnable(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
parser.add_argument('-e', '--enable', type=int, required=True, choices=[1, 0], help="1 = enable, 0 = disable")
parser.add_argument('-e', '--enable', type=int, required=True,
choices=[1, 0], help="1 = enable, 0 = disable")
return parser
# hf mf detection enable -e 1
@@ -628,7 +649,8 @@ class HFMFDetectionDecrypt(DeviceRequiredUnit):
# get output
output_str = process.get_output_sync()
# print(output_str)
sea_obj = re.search(r"([a-fA-F0-9]{12})", output_str, flags=re.MULTILINE)
sea_obj = re.search(
r"([a-fA-F0-9]{12})", output_str, flags=re.MULTILINE)
if sea_obj is not None:
keys.append(sea_obj[1])
@@ -638,19 +660,22 @@ class HFMFDetectionDecrypt(DeviceRequiredUnit):
def on_exec(self, args: argparse.Namespace):
buffer = bytearray()
index = 0
count = int.from_bytes(self.cmd.get_mf1_detection_count().data, "little", signed=False)
count = int.from_bytes(
self.cmd.get_mf1_detection_count().data, "little", signed=False)
if count == 0:
print(" - No detection log to download")
return
print(f" - MF1 detection log count = {count}, start download", end="")
while index < count:
tmp = self.cmd.get_mf1_detection_log(index).data
recv_count = int(len(tmp) / HFMFDetectionDecrypt.detection_log_size)
recv_count = int(
len(tmp) / HFMFDetectionDecrypt.detection_log_size)
index += recv_count
buffer.extend(tmp)
print(".", end="")
print()
print(f" - Download done ({len(buffer)}bytes), start parse and decrypt")
print(
f" - Download done ({len(buffer)}bytes), start parse and decrypt")
result_maps = chameleon_cstruct.parse_mf1_detection_result(buffer)
for uid in result_maps.keys():
@@ -662,18 +687,22 @@ class HFMFDetectionDecrypt(DeviceRequiredUnit):
# print(f" - A record: { result_maps[block]['A'] }")
records = result_maps_for_uid[block]['A']
if len(records) > 1:
result_maps[uid][block]['A'] = self.decrypt_by_list(records)
result_maps[uid][block]['A'] = self.decrypt_by_list(
records)
if 'B' in result_maps_for_uid[block]:
# print(f" - B record: { result_maps[block]['B'] }")
records = result_maps_for_uid[block]['B']
if len(records) > 1:
result_maps[uid][block]['B'] = self.decrypt_by_list(records)
result_maps[uid][block]['B'] = self.decrypt_by_list(
records)
print(" > Result ---------------------------")
for block in result_maps_for_uid.keys():
if 'A' in result_maps_for_uid[block]:
print(f" > Block {block}, A key result: {result_maps_for_uid[block]['A']}")
print(
f" > Block {block}, A key result: {result_maps_for_uid[block]['A']}")
if 'B' in result_maps_for_uid[block]:
print(f" > Block {block}, B key result: {result_maps_for_uid[block]['B']}")
print(
f" > Block {block}, B key result: {result_maps_for_uid[block]['B']}")
return
@@ -681,8 +710,10 @@ class HFMFDetectionDecrypt(DeviceRequiredUnit):
class HFMFELoad(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
parser.add_argument('-f', '--file', type=str, required=True, help="file path")
parser.add_argument('-t', '--type', type=str, required=False, help="content type", choices=['bin', 'hex'])
parser.add_argument('-f', '--file', type=str,
required=True, help="file path")
parser.add_argument('-t', '--type', type=str, required=False,
help="content type", choices=['bin', 'hex'])
return parser
# hf mf eload -f test.bin -t bin
@@ -695,7 +726,8 @@ class HFMFELoad(DeviceRequiredUnit):
elif file.endswith('.eml'):
content_type = 'hex'
else:
raise Exception("Unknown file format, Specify content type with -t option")
raise Exception(
"Unknown file format, Specify content type with -t option")
else:
content_type = args.type
buffer = bytearray()
@@ -728,8 +760,10 @@ class HFMFELoad(DeviceRequiredUnit):
class HFMFERead(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
parser.add_argument('-f', '--file', type=str, required=True, help="file path")
parser.add_argument('-t', '--type', type=str, required=False, help="content type", choices=['bin', 'hex'])
parser.add_argument('-f', '--file', type=str,
required=True, help="file path")
parser.add_argument('-t', '--type', type=str, required=False,
help="content type", choices=['bin', 'hex'])
return parser
def on_exec(self, args: argparse.Namespace):
@@ -740,7 +774,8 @@ class HFMFERead(DeviceRequiredUnit):
elif file.endswith('.eml'):
content_type = 'hex'
else:
raise Exception("Unknown file format, Specify content type with -t option")
raise Exception(
"Unknown file format, Specify content type with -t option")
else:
content_type = args.type
@@ -756,7 +791,8 @@ class HFMFERead(DeviceRequiredUnit):
elif tag_type == chameleon_cmd.TagSpecificType.TAG_TYPE_MIFARE_4096:
block_count = 256
else:
raise Exception("Card in current slot is not Mifare Classic/Plus in SL1 mode")
raise Exception(
"Card in current slot is not Mifare Classic/Plus in SL1 mode")
with open(file, 'wb') as fd:
block = 0
@@ -800,16 +836,20 @@ class HFMFSettings(DeviceRequiredUnit):
def on_exec(self, args: argparse.Namespace):
if args.gen1a != -1:
self.cmd.set_mf1_gen1a_mode(args.gen1a)
print(f' - Set gen1a mode to {"enabled" if args.gen1a else "disabled"} success')
print(
f' - Set gen1a mode to {"enabled" if args.gen1a else "disabled"} success')
if args.gen2 != -1:
self.cmd.set_mf1_gen2_mode(args.gen2)
print(f' - Set gen2 mode to {"enabled" if args.gen2 else "disabled"} success')
print(
f' - Set gen2 mode to {"enabled" if args.gen2 else "disabled"} success')
if args.coll != -1:
self.cmd.set_mf1_block_anti_coll_mode(args.coll)
print(f' - Set anti-collision mode to {"enabled" if args.coll else "disabled"} success')
print(
f' - Set anti-collision mode to {"enabled" if args.coll else "disabled"} success')
if args.write != -1:
self.cmd.set_mf1_write_mode(args.write)
print(f' - Set write mode to {chameleon_cmd.MifareClassicWriteMode(args.write)} success')
print(
f' - Set write mode to {chameleon_cmd.MifareClassicWriteMode(args.write)} success')
print(' - Emulator settings updated')
@@ -817,9 +857,12 @@ class HFMFSettings(DeviceRequiredUnit):
class HFMFSim(DeviceRequiredUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
parser.add_argument('--sak', type=str, required=True, help="Select AcKnowledge(hex)", metavar="hex")
parser.add_argument('--atqa', type=str, required=True, help="Answer To Request(hex)", metavar="hex")
parser.add_argument('--uid', type=str, required=True, help="Unique ID(hex)", metavar="hex")
parser.add_argument('--sak', type=str, required=True,
help="Select AcKnowledge(hex)", metavar="hex")
parser.add_argument('--atqa', type=str, required=True,
help="Answer To Request(hex)", metavar="hex")
parser.add_argument('--uid', type=str, required=True,
help="Unique ID(hex)", metavar="hex")
return parser
# hf mf sim --sak 08 --atqa 0400 --uid DEADBEEF
@@ -859,14 +902,16 @@ class LFEMRead(ReaderRequiredUnit):
def on_exec(self, args: argparse.Namespace):
resp = self.cmd.read_em_410x()
id_hex = resp.data.hex()
print(f" - EM410x ID(10H): {colorama.Fore.GREEN}{id_hex}{colorama.Style.RESET_ALL}")
print(
f" - EM410x ID(10H): {colorama.Fore.GREEN}{id_hex}{colorama.Style.RESET_ALL}")
class LFEMCardRequiredUnit(DeviceRequiredUnit):
@staticmethod
def add_card_arg(parser: ArgumentParserNoExit):
parser.add_argument("--id", type=str, required=True, help="EM410x tag id", metavar="hex")
parser.add_argument("--id", type=str, required=True,
help="EM410x tag id", metavar="hex")
return parser
def before_exec(self, args: argparse.Namespace):
@@ -963,7 +1008,8 @@ class HWSlotList(DeviceRequiredUnit):
# hw slot list
def on_exec(self, args: argparse.Namespace):
data = self.cmd.get_slot_info().data
selected = chameleon_cmd.SlotNumber.from_fw(self.cmd.get_active_slot().data[0])
selected = chameleon_cmd.SlotNumber.from_fw(
self.cmd.get_active_slot().data[0])
enabled = self.cmd.get_enabled_slots().data
for slot in chameleon_cmd.SlotNumber:
print(
@@ -980,11 +1026,16 @@ class HWSlotList(DeviceRequiredUnit):
if args.extend:
config = self.cmd.get_mf1_emulator_settings().data
print(' - Mifare Classic emulator settings:')
print(f' Detection (mfkey32) mode: {"enabled" if config[0] else "disabled"}')
print(f' Gen1A magic mode: {"enabled" if config[1] else "disabled"}')
print(f' Gen2 magic mode: {"enabled" if config[2] else "disabled"}')
print(f' Use anti-collision data from block 0: {"enabled" if config[3] else "disabled"}')
print(f' Write mode: {chameleon_cmd.MifareClassicWriteMode(config[4])}')
print(
f' Detection (mfkey32) mode: {"enabled" if config[0] else "disabled"}')
print(
f' Gen1A magic mode: {"enabled" if config[1] else "disabled"}')
print(
f' Gen2 magic mode: {"enabled" if config[2] else "disabled"}')
print(
f' Use anti-collision data from block 0: {"enabled" if config[3] else "disabled"}')
print(
f' Write mode: {chameleon_cmd.MifareClassicWriteMode(config[4])}')
@hw_slot.command('change', 'Set emulation tag slot activated.')
@@ -1078,7 +1129,8 @@ class HWSlotEnableSet(SlotIndexRequireUnit):
def args_parser(self) -> ArgumentParserNoExit or None:
parser = ArgumentParserNoExit()
self.add_slot_args(parser)
parser.add_argument('-e', '--enable', type=int, required=True, help="1 is Enable or 0 Disable", choices=[0, 1])
parser.add_argument('-e', '--enable', type=int, required=True,
help="1 is Enable or 0 Disable", choices=[0, 1])
return parser
# hw slot enable -s 1 -e 0
@@ -1086,7 +1138,8 @@ class HWSlotEnableSet(SlotIndexRequireUnit):
slot_num = args.slot
enable = args.enable
self.cmd.set_slot_enable(slot_num, enable)
print(f' - Set slot {slot_num} {"enable" if enable else "disable"} success.')
print(
f' - Set slot {slot_num} {"enable" if enable else "disable"} success.')
@lf_em_sim.command('set', 'Set simulated em410x card id')
@@ -1123,7 +1176,8 @@ class HWSlotNickSet(SlotIndexRequireUnit, SenseTypeRequireUnit):
parser = ArgumentParserNoExit()
self.add_slot_args(parser)
self.add_sense_type_args(parser)
parser.add_argument('-n', '--name', type=str, required=True, help="Your tag nick name for slot")
parser.add_argument('-n', '--name', type=str,
required=True, help="Your tag nick name for slot")
return parser
# hw slot nick set -s 1 -st 1 -n Save the test name
@@ -1242,7 +1296,8 @@ class HWSettingsAnimationSet(DeviceRequiredUnit):
def on_exec(self, args: argparse.Namespace):
mode = args.mode
self.cmd.set_settings_animation(mode)
print("Animation mode change success. Do not forget to store your settings in flash!")
print(
"Animation mode change success. Do not forget to store your settings in flash!")
@hw_settings.command('store', 'Store current settings to flash')
@@ -1280,7 +1335,8 @@ class HWFactoryReset(DeviceRequiredUnit):
parser.description = "Permanently wipes Chameleon to factory settings. " \
"This will delete all your slot data and custom settings. " \
"There's no going back."
parser.add_argument("--i-know-what-im-doing", default=False, action="store_true", help="Just to be sure :)")
parser.add_argument("--i-know-what-im-doing", default=False,
action="store_true", help="Just to be sure :)")
return parser
def on_exec(self, args: argparse.Namespace):
@@ -1312,7 +1368,8 @@ class HWBatteryInfo(DeviceRequiredUnit):
print(f" voltage -> {voltage}mV")
print(f" percentage -> {percentage}%")
if percentage < HWBatteryInfo.BATTERY_LOW_LEVEL:
print(f"{colorama.Fore.RED}[!] Low battery, please charge.{colorama.Style.RESET_ALL}")
print(
f"{colorama.Fore.RED}[!] Low battery, please charge.{colorama.Style.RESET_ALL}")
@hw_settings_button_press.command('get', 'Get button press function of Button A and Button B.')
@@ -1331,8 +1388,10 @@ class HWButtonSettingsGet(DeviceRequiredUnit):
for button in button_list:
resp = self.cmd.get_button_press_fun(button)
resp_long = self.cmd.get_long_button_press_fun(button)
button_fn = chameleon_cmd.ButtonPressFunction.from_int(resp.data[0])
button_long_fn = chameleon_cmd.ButtonPressFunction.from_int(resp_long.data[0])
button_fn = chameleon_cmd.ButtonPressFunction.from_int(
resp.data[0])
button_long_fn = chameleon_cmd.ButtonPressFunction.from_int(
resp_long.data[0])
print(f" - {colorama.Fore.GREEN}{button} {colorama.Fore.YELLOW}short{colorama.Style.RESET_ALL}:"
" {button_fn}")
print(f" usage: {button_fn.usage()}")
+12 -6
View File
@@ -70,7 +70,8 @@ class ChameleonCom:
error = None
try:
# open serial port
self.serial_instance = serial.Serial(port=port, baudrate=115200)
self.serial_instance = serial.Serial(
port=port, baudrate=115200)
except Exception as e:
error = e
finally:
@@ -98,7 +99,8 @@ class ChameleonCom:
:return:
"""
if not self.isOpen():
raise NotOpenException("Please call open() function to start device.")
raise NotOpenException(
"Please call open() function to start device.")
@staticmethod
def lrc_calc(array):
@@ -196,7 +198,8 @@ class ChameleonCom:
if callable(fn_call):
# delete wait task from map
del self.wait_response_map[data_cmd]
fn_call(data_cmd, data_status, data_response)
fn_call(data_cmd, data_status,
data_response)
else:
self.wait_response_map[data_cmd]['response'] = Response(data_cmd, data_status,
data_response)
@@ -227,7 +230,8 @@ class ChameleonCom:
task_close = task['close']
# register to wait map
if 'callback' in task and callable(task['callback']):
self.wait_response_map[task_cmd] = {'callback': task['callback']} # The callback for this task
self.wait_response_map[task_cmd] = {
'callback': task['callback']} # The callback for this task
else:
self.wait_response_map[task_cmd] = {'response': None}
# set start time
@@ -258,7 +262,8 @@ class ChameleonCom:
if time.time() > self.wait_response_map[task_cmd]['end_time']:
if 'callback' in self.wait_response_map[task_cmd]:
# not sync, call function to notify timeout.
self.wait_response_map[task_cmd]['callback'](task_cmd, None, None)
self.wait_response_map[task_cmd]['callback'](
task_cmd, None, None)
else:
# sync mode, set timeout flag
self.wait_response_map[task_cmd]['is_timeout'] = True
@@ -303,7 +308,8 @@ class ChameleonCom:
del self.wait_response_map[cmd]
# make data frame
data_frame = self.make_data_frame_bytes(cmd, status, data)
task = {'cmd': cmd, 'frame': data_frame, 'timeout': timeout, 'close': close}
task = {'cmd': cmd, 'frame': data_frame,
'timeout': timeout, 'close': close}
if callable(callback):
task['callback'] = callback
self.send_data_queue.put(task)
+2 -1
View File
@@ -43,7 +43,8 @@ def parse_nested_nt_acquire_group(data: bytearray):
"""
group = []
if len(data) % 9 != 0:
raise ValueError("Nt data length error, except: { nt(4byte), nt_enc(4byte), par(1byte) } * N")
raise ValueError(
"Nt data length error, except: { nt(4byte), nt_enc(4byte), par(1byte) } * N")
i = 0
while i < len(data):
group.append({
+12 -6
View File
@@ -57,9 +57,11 @@ def expect_response(accepted_responses: Union[int, list[int]]):
if ret.status not in accepted_responses:
if ret.status in chameleon_status.Device and ret.status in chameleon_status.message:
raise UnexpectedResponseError(chameleon_status.message[ret.status])
raise UnexpectedResponseError(
chameleon_status.message[ret.status])
else:
raise UnexpectedResponseError(f"Unexpected response and unknown status {ret.status}")
raise UnexpectedResponseError(
f"Unexpected response and unknown status {ret.status}")
return ret
@@ -137,7 +139,8 @@ class CustomNestedCompleter(NestedCompleter):
elif isinstance(value, dict):
options[key] = cls.from_nested_dict(value)
elif isinstance(value, set):
options[key] = cls.from_nested_dict({item: None for item in value})
options[key] = cls.from_nested_dict(
{item: None for item in value})
elif isinstance(value, CLITree):
if value.cls:
# CLITree is a standalone command
@@ -160,7 +163,8 @@ class CustomNestedCompleter(NestedCompleter):
for child_node in node.children:
if child_node.cls and child_node.cls().args_parser():
# CLITree is a standalone command with arguments
options[child_node.name] = ArgparseCompleter(child_node.cls().args_parser())
options[child_node.name] = ArgparseCompleter(
child_node.cls().args_parser())
else:
# CLITree is a command group
options[child_node.name] = cls.from_clitree(child_node)
@@ -240,7 +244,8 @@ class ArgparseCompleter(Completer):
parsed.append(value)
if check_arg(unparsed):
parsed, unparsed, suggestions = self.check_tokens(parsed, unparsed)
parsed, unparsed, suggestions = self.check_tokens(
parsed, unparsed)
else:
# Show all possible values
@@ -251,7 +256,8 @@ class ArgparseCompleter(Completer):
else:
# No choices, process further arguments
if check_arg(unparsed):
parsed, unparsed, suggestions = self.check_tokens(parsed, unparsed)
parsed, unparsed, suggestions = self.check_tokens(
parsed, unparsed)
break
elif any(opt.startswith(token) for opt in action.option_strings):
for opt in action.option_strings: