From 9e0d8a43227c39d987a54285d7b79a1a29dfe082 Mon Sep 17 00:00:00 2001 From: smathis Date: Thu, 24 Oct 2024 10:34:19 +0200 Subject: [PATCH] Added a new script utils/decodeMasterMACStatusR10.py which allows to decode the R10 status message of the MasterMACs controller. Also fixed a bug in utils/deltatau.py (error when printing too much text at once) --- utils/decodeMasterMACStatusR10.py | 208 ++++++++++++++++++++++++++++++ utils/deltatau.py | 1 + 2 files changed, 209 insertions(+) create mode 100755 utils/decodeMasterMACStatusR10.py diff --git a/utils/decodeMasterMACStatusR10.py b/utils/decodeMasterMACStatusR10.py new file mode 100755 index 0000000..26f71b2 --- /dev/null +++ b/utils/decodeMasterMACStatusR10.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python3 + +import curses + +# List of tuples which encodes the states given in the file description. +# Index first with the bit index, then with the bit value +interpretation = [ + ("Not ready to be switched on", "Ready to be switched on"), # Bit 0 + ("Not switched on", "Switched on"), # Bit 1 + ("Disabled", "Enabled"), # Bit 2 + ("Ok", "Fault condition set"), # Bit 3 + ("Motor supply voltage absent ", "Motor supply voltage present"), # Bit 4 + ("Motor performs quick stop", "Ok"), # Bit 5 + ("Switch on enabled", "Switch on disabled"), # Bit 6 + ("Ok", "RWarning: Movement function was called while motor is still moving. The function call is ignored"), # Bit 7 + ("Motor is idle", "Motor is currently moving"), # Bit 8 + ("Motor does not execute command messages (local mode)", "Motor does execute command messages (remote mode)"), # Bit 9 + ("Target not reached", "Target reached"), # Bit 10 + ("Ok", "Internal limit active"), # Bit 11 + ("Not specified", "Not specified"), # Bit 12 + ("Not specified", "Not specified"), # Bit 13 + ("No event set or event has not occurred yet", "Set event has occurred"), # Bit 14 + ("Axis off (power disabled)", "Axis on (power enabled)"), # Bit 15 +] + +def decode(value, big_endian: bool = False): + + interpreted = [] + + bit_list = [(value >> shift_ind) & 1 + for shift_ind in range(value.bit_length())] # little endian + + if big_endian: + bit_list.reverse() # big endian + + for (bit, interpretations) in zip(bit_list, interpretation): + interpreted.append(interpretations[bit]) + return (bit_list, interpreted) + +def print_decoded(bit_list, interpreted): + for (idx, (bit_value, msg)) in enumerate(zip(bit_list, interpreted)): + print(f"Bit {idx} = {bit_value}: {msg}") + +def interactive(): + stdscr = curses.initscr() + curses.noecho() + curses.cbreak() + stdscr.keypad(True) + stdscr.scrollok(True) + + stdscr.addstr(">> ") + stdscr.refresh() + + history = [""] + ptr = len(history) - 1 + + while True: + c = stdscr.getch() + if c == curses.KEY_RIGHT: + (y, x) = stdscr.getyx() + if x < len(history[ptr]) + 3: + stdscr.move(y, x+1) + stdscr.refresh() + elif c == curses.KEY_LEFT: + (y, x) = stdscr.getyx() + if x > 3: + stdscr.move(y, x-1) + stdscr.refresh() + elif c == curses.KEY_UP: + if ptr > 0: + ptr -= 1 + stdscr.addch("\r") + stdscr.clrtoeol() + stdscr.addstr(">> " + history[ptr]) + elif c == curses.KEY_DOWN: + if ptr < len(history) - 1: + ptr += 1 + stdscr.addch("\r") + stdscr.clrtoeol() + stdscr.addstr(">> " + history[ptr]) + elif c == curses.KEY_ENTER or c == ord('\n') or c == ord('\r'): + if history[ptr] == 'quit': + break + + # because of arrow keys move back to the end of the line + (y, x) = stdscr.getyx() + stdscr.move(y, 3+len(history[ptr])) + + if history[ptr]: + result = interpret_inputs(history[ptr].split()) + if result is None: + stdscr.addstr(f"\nBAD INPUT: Expected input of 'value [big_endian]', where 'value' is an int or a float and 'big_endian' is an optional boolean argument.") + else: + (arg, big_endian) = result + (bit_list, interpreted) = decode(arg, big_endian) + for (idx, (bit_value, msg)) in enumerate(zip(bit_list, interpreted)): + stdscr.addstr(f"\nBit {idx} = {bit_value}: {msg}") + stdscr.refresh() + + if ptr == len(history) - 1 and history[ptr] != "": + history += [""] + else: + history[-1] = "" + ptr = len(history) - 1 + + stdscr.addstr("\n>> ") + stdscr.refresh() + + else: + if ptr < len(history) - 1: # Modifying previous input + if len(history[-1]) == 0: + history[-1] = history[ptr] + ptr = len(history) - 1 + + else: + history += [history[ptr]] + ptr = len(history) - 1 + + if c == curses.KEY_BACKSPACE: + if len(history[ptr]) == 0: + continue + (y, x) = stdscr.getyx() + history[ptr] = history[ptr][0:x-4] + history[ptr][x-3:] + stdscr.addch("\r") + stdscr.clrtoeol() + stdscr.addstr(">> " + history[ptr]) + stdscr.move(y, x-1) + stdscr.refresh() + + else: + (y, x) = stdscr.getyx() + history[ptr] = history[ptr][0:x-3] + chr(c) + history[ptr][x-3:] + stdscr.addch("\r") + stdscr.clrtoeol() + stdscr.addstr(">> " + history[ptr]) + stdscr.move(y, x+1) + stdscr.refresh() + + # to quit + curses.nocbreak() + stdscr.keypad(False) + curses.echo() + curses.endwin() + +def interpret_inputs(inputs): + + number = None + big_endian = False + try: + number = int(float(inputs[0])) + if len(inputs) > 1: + second_arg = inputs[1] + if second_arg == "True" or second_arg == "true": + big_endian = True + elif second_arg == "False" or second_arg == "false": + big_endian = False + else: + big_endian = bool(int(second_arg)) + return (number, big_endian) + except: + return None + +if __name__ == "__main__": + from sys import argv + + if len(argv) == 1: + # Start interactive mode + interactive() + else: + + result = interpret_inputs(argv[1:]) + + if result is None: + print(""" + Decode R10 message of MasterMACs + ------------------ + + MasterMACs returns its status message (R10) as a floating-point number. + The bits of this float encode different states. These states are stored + in the interpretation variable. + + This script can be used in two different ways: + + Option 1: Single Command + ------------------------ + + Usage: decodeMasterMACStatusR10.py value [big_endian] + + 'value' is the return value of a R10 command. This value is interpreted + bit-wise and the result is printed out. The optional second argument can + be used to specify whether the input value needs to be interpreted as + little or big endian. Default is False. + + Option 2: CLI Mode + ------------------ + + Usage: decodeMasterMACStatusR10.py + + A prompt will be opened. Type in the return value of a R10 command, hit + enter and the interpretation will be printed in the prompt. After that, + the next value can be typed in. Type 'quit' to close the prompt. + """) + else: + print("Motor status") + print("============") + (arg, big_endian) = result + (bit_list, interpreted) = decode(arg, big_endian) + print_decoded(bit_list, interpreted) diff --git a/utils/deltatau.py b/utils/deltatau.py index c4aaeb7..7914e4f 100755 --- a/utils/deltatau.py +++ b/utils/deltatau.py @@ -64,6 +64,7 @@ if __name__ == "__main__": curses.noecho() curses.cbreak() stdscr.keypad(True) + stdscr.scrollok(True) stdscr.addstr(">> ") stdscr.refresh()