summaryrefslogtreecommitdiff
path: root/tools/proxyclient/m1n1/shell.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/proxyclient/m1n1/shell.py')
-rw-r--r--tools/proxyclient/m1n1/shell.py213
1 files changed, 213 insertions, 0 deletions
diff --git a/tools/proxyclient/m1n1/shell.py b/tools/proxyclient/m1n1/shell.py
new file mode 100644
index 0000000..06e0605
--- /dev/null
+++ b/tools/proxyclient/m1n1/shell.py
@@ -0,0 +1,213 @@
+# SPDX-License-Identifier: MIT
+import atexit, serial, os, struct, code, traceback, readline, rlcompleter, sys
+import __main__
+import builtins
+import re
+
+from .proxy import *
+from .proxyutils import *
+from .utils import *
+from . import sysreg
+from inspect import isfunction, signature
+
+__all__ = ["ExitConsole", "run_shell"]
+
+class HistoryConsole(code.InteractiveConsole):
+ def __init__(self, locals=None, filename="<console>",
+ histfile=os.path.expanduser("~/.m1n1-history")):
+ code.InteractiveConsole.__init__(self, locals, filename)
+ self.histfile = histfile
+ self.init_history(histfile)
+ self.poll_func = None
+
+ def init_history(self, histfile):
+ readline.parse_and_bind("tab: complete")
+ if hasattr(readline, "read_history_file"):
+ try:
+ readline.read_history_file(histfile)
+ except FileNotFoundError:
+ pass
+
+ def save_history(self):
+ readline.set_history_length(10000)
+ readline.write_history_file(self.histfile)
+
+ def showtraceback(self):
+ type, value, tb = sys.exc_info()
+ traceback.print_exception(type, value, tb)
+
+ def runcode(self, code):
+ super().runcode(code)
+ if self.poll_func:
+ self.poll_func()
+ if "mon" in self.locals:
+ try:
+ self.locals["mon"].poll()
+ except Exception as e:
+ print(f"mon.poll() failed: {e!r}")
+ if "u" in self.locals:
+ self.locals["u"].push_simd()
+
+
+class ExitConsole(SystemExit):
+ pass
+cmd_list = {}
+subcmd_list = {}
+# Debug levels
+DBL_NONE = 0
+DBL_INFO = 1
+DBL_TRACE = 2
+DBL_DEBUG = 3
+DBL_EDEBUG = 4
+
+db_level = DBL_NONE
+
+def debug_cmd(db=None):
+ '''Set debug level to integer %d(none)...%d(extreme debug)''' % (DBL_NONE, DBL_EDEBUG)
+ global db_level
+ if db:
+ db_level = db
+ print("debug level=%d" % db_level)
+
+def help_cmd(arg=None):
+ if db_level >= DBL_DEBUG:
+ print("arg=%s" % repr(arg))
+ if arg:
+ #cmd = arg.__qualname__
+ if callable(arg):
+ cmd = arg.__name__
+ elif isinstance(arg, str):
+ cmd = arg
+ else:
+ print("Unknown command: %s" % repr(arg))
+ return
+ if db_level >= DBL_DEBUG:
+ print("cmd=%s" % repr(cmd))
+ if cmd not in cmd_list:
+ print("Undocumented command %s" % cmd)
+ return
+ hinfo = cmd_list[cmd]
+ if isinstance(hinfo, str):
+ print("%-10s : %s" % (cmd, hinfo))
+ return
+ if cmd in subcmd_list:
+ clist = subcmd_list[cmd]
+ aname = cmd
+ if db_level >= DBL_DEBUG:
+ print("subcmd_list[%s] = %s" %
+ (repr(cmd), repr(clist)))
+ else:
+ print("command %s is not documented" % cmd)
+ return
+ else:
+ clist = cmd_list
+ aname = 'top level'
+ print("Note: To display a category's commands quote the name e.g. help('HV')")
+ print("List of %s commands:" % aname)
+ for cmd in clist.keys():
+ hinfo = clist[cmd]
+ if isinstance(hinfo, str):
+ msg = hinfo.strip().split('\n', 1)[0]
+ elif isinstance(hinfo, int):
+ msg = "%s category - %d subcommands" % (cmd, hinfo)
+ else:
+ print("%s ?" % cmd)
+ continue
+ if len(cmd) <= 10:
+ print("%-10s : %s" % (cmd, msg))
+ else:
+ print("%s:\n %s" % (cmd, msg))
+
+#locals is a dictionary for constructing the
+# InteractiveConsole with. It adds in the callables
+# in proxy utils iface and sysreg into locals
+def run_shell(locals, msg=None, exitmsg=None, poll_func=None):
+ saved_display = sys.displayhook
+ try:
+ def display(val):
+ if isinstance(val, int) and not isinstance(val, bool):
+ builtins._ = val
+ print(hex(val))
+ elif callable(val):
+ val()
+ else:
+ saved_display(val)
+
+ sys.displayhook = display
+
+ # convenience
+ locals["h"] = hex
+ locals["sysreg"] = sysreg
+
+ if "proxy" in locals and "p" not in locals:
+ locals["p"] = locals["proxy"]
+ if "utils" in locals and "u" not in locals:
+ locals["u"] = locals["utils"]
+
+ for obj_name in ("iface", "p", "u"):
+ obj = locals.get(obj_name)
+ obj_class = type(obj)
+ if obj is None:
+ continue
+
+ for attr in dir(obj_class):
+ if attr in locals or attr.startswith('_'):
+ continue
+
+ member = getattr(obj_class, attr)
+ if callable(member) and not isinstance(member, property):
+ cmd = getattr(obj, attr)
+ locals[attr] = cmd
+
+ for attr in dir(sysreg):
+ locals[attr] = getattr(sysreg, attr)
+
+ locals['help'] = help_cmd
+ locals['debug'] = debug_cmd
+ for obj_name in locals.keys():
+ obj = locals.get(obj_name)
+ if obj is None or obj_name.startswith('_'):
+ continue
+ if callable(obj) and not isinstance(obj, property):
+ try:
+ desc = obj_name + str(signature(obj))
+ except:
+ continue
+ qn = obj.__qualname__
+ if qn.find('.') > 0:
+ a = qn.split('.')
+ if a[0] not in subcmd_list:
+ subcmd_list[a[0]] = {}
+ if a[0] not in cmd_list:
+ cmd_list[a[0]] = 1
+ else:
+ cmd_list[a[0]] += 1
+ clist = subcmd_list[a[0]]
+ else:
+ clist = None
+ if locals[obj_name].__doc__:
+ desc += " - " + locals[obj_name].__doc__
+ cmd_list[obj_name] = desc
+ if isinstance(clist, dict):
+ clist[obj_name] = desc
+
+ con = HistoryConsole(locals)
+ con.poll_func = poll_func
+ try:
+ con.interact(msg, exitmsg)
+ except ExitConsole as e:
+ if len(e.args):
+ return e.args[0]
+ else:
+ return
+ finally:
+ con.save_history()
+
+ finally:
+ sys.displayhook = saved_display
+
+if __name__ == "__main__":
+ from .setup import *
+ locals = dict(__main__.__dict__)
+
+ run_shell(locals, msg="Have fun!")