diff --git a/src/picowatch.py b/src/picowatch.py index c5f9aa3..cc2ee06 100644 --- a/src/picowatch.py +++ b/src/picowatch.py @@ -62,18 +62,18 @@ class Tab(): if isinstance(align_to_right, (list, tuple)): self.align_to_right(*align_to_right) - def head(self, *texts: str): - self.border('=') - self.line(*texts, bordered=False) - self.border('=') + def head(self, *labels: str, border_style: str = '='): + self.border(border_style) + self.line(*labels, bordered=False) + self.border(border_style) - def border(self, text: str = '-'): - sys.stdout.write(text * sum(self.colsize) + '\n') + def border(self, style: str = '-'): + print(style * sum(self.colsize) + '\r') def align_to_right(self, *column_num: int): self.text_to_right = [i - 1 for i in column_num] - def line(self, *texts: str, bordered: bool = None): + def line(self, *texts: str, bordered: bool = None, border_style: str = '-'): lines = {} max_lines = 0 @@ -114,13 +114,13 @@ class Tab(): else: output += ' ' * width - sys.stdout.write(output + '\n') + print(output + '\r') if bordered == False: return if bordered or self.bordered: - self.border('-') + self.border(border_style) class Telnet: @@ -306,7 +306,7 @@ class Pyboard(object): self.send_ctrl_b() def __terminal(self, command: str, stream_output: bool = False) -> Optional[str]: - command = textwrap.dedent(command) + command = textwrap.dedent(command) if not isinstance(command, bytes): command = bytes(command, encoding='utf-8') @@ -603,17 +603,33 @@ class FileSystem(object): return terminal(command, stream_output=stream_output) except Exception as e: raise e - + class Picowatch(object): def __init__(self, pyboard: Pyboard): self.filesystem = FileSystem(pyboard) - signal.signal(signal.SIGINT, lambda sig, frame: self.interrupt()) + signal.signal(signal.SIGINT, lambda signum, frame: self.interrupt()) def boot(self): self.filesystem.pyboard.boot() + def system(self): + self.terminal(""" + import os + import gc + + print('Board:', os.uname().machine, os.uname().version) + print('Free memory:', round(gc.mem_free() / 1024, 2), 'kb.') + """) + + def reset(self): + self.terminal(""" + import machine + machine.soft_reset() + """) + self.interrupt() + def interrupt(self): self.filesystem.pyboard.send_ctrl_c() self.filesystem.pyboard.until_nothing_in_waiting() @@ -678,6 +694,7 @@ class Picowatch(object): for ln in content.decode('utf-8').split('\n'): print(ln) + def upload(self, filepath: str): tab = Tab(4, 30, 15, 15, nb_columns=5) tab.head('[ ]', 'Filename', 'Size (kb)', 'Checksum', 'Exception') @@ -855,6 +872,12 @@ class Picowatch(object): else: print(f'Python file "{filename}" compile to .mpy') + def install(self, package_name: str): + self.terminal(f""" + import mip + mip.install('{package_name}') + """) + def test(self, filename: str): with open(os.path.join(LISTENING_TO, filename), 'r') as fh: self.filesystem.terminal(fh.read(), stream_output=True) @@ -899,29 +922,34 @@ while True: try: match message.strip().split(' '): case ['?' | 'help']: - print('These are common Picowatch keywords:\n') + print('These are common Picowatch keywords:') tab = Tab(12, 10, 32, nb_columns=4) - tab.head('Keywords', 'Shortcut', 'Parameters', 'Description') - tab.line('help', '?', '', 'Show keywords and their description') - tab.line('boot', '.', '', 'Do a soft reset and run main.py (if exists) in REPL mode') - tab.line('test', '!', '[] (default: main.py)', 'Run a script from PC on the Pyboard and print out the results in raw-REPL mode') - tab.line('run', '!!', '[] (default: main.py)', 'Run a script on the Pyboard and print out the results in raw-REPL mode') - tab.line('ctrl + C', '', '', 'Interrupts the currently running code in REPL or raw-REPL mode') - tab.line('ctrl + D', 'exit', '', 'Exit Picowatch Terminal') - tab.line('ctrl + Z', 'exit', '', 'Same as ctrl + D, Exit Picowatch Terminal') - tab.line('uname', 'os', '', 'Pyboard name and version') - tab.line('scan', 'ls', '[] (default: /)', 'List information about the file(s) on the Pyboard') - tab.line('edit', 'vim', ' []', 'Edit specified file from the PC (vim or vscode is required)') - tab.line('source', 'cat', '', 'Concatenate source code to standard output') - tab.line('delete', 'rm', '', 'Delete file or directory contents on the Pyboard') - tab.line('upload', 'put', '', 'Upload file or directory contents from the PC to the Pyboard') + tab.head('Keywdords', 'Shortcut', 'Parameters', 'Description') + tab.line('help', '?', '', 'Show keywords and their description.') + tab.line('modules', '??', '', 'List availables modules on the Pyboard.') + tab.line('boot', '.', '', 'Perform a soft reset and run main.py (if exists) in REPL mode.') + tab.line('test', '!', '[] (default: main.py)', 'Run a script from PC on the Pyboard and print out the results in raw-REPL mode.') + tab.line('run', '!!', '[] (default: main.py)', 'Run a script on the Pyboard and print out the results in raw-REPL mode.') + tab.line('ctrl + C', '', '', 'Interrupts the currently running code in REPL or raw-REPL mode.') + tab.line('ctrl + D', 'exit', '', 'Exit Picowatch Terminal.') + tab.line('ctrl + Z', 'exit', '', 'Same as ctrl + D, Exit Picowatch Terminal.') + tab.line('system', 'os', '', 'Pyboard name and version.') + tab.line('reset', 'rs', '', 'Perform a soft reset from the REPL.') + tab.line('scan', 'ls', '[] (default: /)', 'List information about the file(s) on the Pyboard.') + tab.line('edit', 'vim', ' []', 'Edit specified file from the PC (vim or vscode is required).') + tab.line('source', 'cat', '', 'Concatenate source code to standard output.') + tab.line('delete', 'rm', '', 'Delete file or directory contents on the Pyboard.') + tab.line('upload', 'put', '', 'Upload file or directory contents from the PC to the Pyboard.') tab.line('download', 'get', '', 'Download file or directory contents from the Pyboard to the PC. Warning: this may cause file corruption.') - tab.line('compare', 'diff', ' []', 'Compare source code from PC with source code from the Pyboard (vim or vscode is required)') - tab.line('compile', 'mpy', '', 'Compile source file to mpy file') - tab.line('status', 'mod', '', 'Show the working tree status (Git is required)') - tab.line('commit', 'sync', '[] (default: "")', 'Synchronize Pyboard along with associated commit(s) (Git is required)') - case ['os' | 'uname']: - picowatch.terminal('import os;print(os.uname().machine, os.uname().version)') + tab.line('compare', 'diff', ' []', 'Compare source code from PC with source code from the Pyboard (vim or vscode is required).') + tab.line('compile', 'mpy', '', 'Compile source file to mpy file.') + tab.line('install', 'mip', '', 'Install packages from micropython-lib and from third-party sites (including GitHub) - *Network-capable boards only.') + tab.line('status', 'mod', '', 'Show the working tree status (Git is required).') + tab.line('commit', 'sync', '[] (default: "")', 'Synchronize Pyboard along with associated commit(s) (Git is required).') + case ['??' | 'modules']: + picowatch.terminal(f'help("modules")') + case ['os' | 'system']: + picowatch.system() case ['ls' | 'scan', *file]: picowatch.listing(file[0] if file else '/') case ['vim' | 'edit', file, *use_vim]: @@ -946,13 +974,15 @@ while True: case ['mpy' | 'compile', file]: picowatch.compile(file) case ['mip' | 'install', package_name]: - print('# TODO') + picowatch.install(package_name) case ['!' | 'test', *file]: picowatch.test(file[0] if file else 'main.py') case ['!!' | 'run', *file]: picowatch.launch(file[0] if file else 'main.py') case ['.'| 'boot']: picowatch.boot() + case ['rs' | 'reset']: + picowatch.reset() case ['exit']: sys.exit('Picowatch Terminal disconnected!') case _: