#!/usr/bin/env python3 # 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(): # Imported here, because curses is not available in Windows. Using the # interactive mode therefore fails on Windows, but at least the single # command mode can be used (which would not be possible if we would import # curses at the top level) import curses 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)