From cd14188bc8b4cd942ea7ea5cf5eb27955d8695ae Mon Sep 17 00:00:00 2001 From: Daniel Campora Date: Sun, 28 Jun 2015 14:01:27 +0200 Subject: [PATCH] tools: Add telnet support to pyboard.py. The adapter class "TelnetToSerial" is used to access the Telnet connection using the same API as with the serial connection. The function pyboard.run-test() has been removed to made the module generic and because this small test is no longer needed. --- tests/run-tests | 8 ++- tools/pyboard.py | 152 ++++++++++++++++++++++++++--------------------- 2 files changed, 89 insertions(+), 71 deletions(-) diff --git a/tests/run-tests b/tests/run-tests index bd2cbfd029..b4baff2b83 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -266,17 +266,19 @@ def run_tests(pyb, tests, args): def main(): cmd_parser = argparse.ArgumentParser(description='Run tests for Micro Python.') cmd_parser.add_argument('--target', default='unix', help='the target platform') - cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device of the target board') + cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') + cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') + cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') + cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('-d', '--test-dirs', nargs='*', help='input test directories (if no files given)') cmd_parser.add_argument('--write-exp', action='store_true', help='save .exp files to run tests w/o CPython') cmd_parser.add_argument('--emit', default='bytecode', help='Micro Python emitter to use (bytecode or native)') - cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') cmd_parser.add_argument('files', nargs='*', help='input test files') args = cmd_parser.parse_args() if args.target == 'pyboard' or args.target == 'wipy': import pyboard - pyb = pyboard.Pyboard(args.device, args.baudrate) + pyb = pyboard.Pyboard(args.device, args.baudrate, args.user, args.password) pyb.enter_raw_repl() elif args.target == 'unix': pyb = None diff --git a/tools/pyboard.py b/tools/pyboard.py index 223f3be16f..9157c6058f 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -10,6 +10,13 @@ Example usage: import pyboard pyb = pyboard.Pyboard('/dev/ttyACM0') + +Or: + + pyb = pyboard.Pyboard('192.168.1.1') + +Then: + pyb.enter_raw_repl() pyb.exec('pyb.LED(1).on()') pyb.exit_raw_repl() @@ -31,7 +38,6 @@ Or: import sys import time -import serial def stdout_write_bytes(b): sys.stdout.buffer.write(b) @@ -40,9 +46,76 @@ def stdout_write_bytes(b): class PyboardError(BaseException): pass +class TelnetToSerial: + def __init__(self, ip, user, password, read_timeout=None): + import telnetlib + self.tn = telnetlib.Telnet(ip, timeout=15) + self.read_timeout = read_timeout + if b'Login as:' in self.tn.read_until(b'Login as:', timeout=read_timeout): + self.tn.write(bytes(user, 'ascii') + b"\r\n") + + if b'Password:' in self.tn.read_until(b'Password:', timeout=read_timeout): + # needed because of internal implementation details of the telnet server + time.sleep(0.2) + self.tn.write(bytes(password, 'ascii') + b"\r\n") + + if b'for more information.' in self.tn.read_until(b'Type "help()" for more information.', timeout=read_timeout): + # login succesful + from collections import deque + self.fifo = deque() + return + + raise PyboardError('Failed to establish a telnet connection with the board') + + def __del__(self): + self.close() + + def close(self): + try: + self.tn.close() + except: + # the telnet object might not exist yet, so ignore this one + pass + + def read(self, size=1): + while len(self.fifo) < size: + timeout_count = 0 + data = self.tn.read_eager() + if len(data): + self.fifo.extend(data) + timeout_count = 0 + else: + time.sleep(0.25) + if self.read_timeout is not None and timeout_count > 4 * self.read_timeout: + break + timeout_count += 1 + + data = b'' + while len(data) < size and len(self.fifo) > 0: + data += bytes([self.fifo.popleft()]) + return data + + def write(self, data): + self.tn.write(data) + return len(data) + + def inWaiting(self): + n_waiting = len(self.fifo) + if not n_waiting: + data = self.tn.read_eager() + self.fifo.extend(data) + return len(data) + else: + return n_waiting + class Pyboard: - def __init__(self, serial_device, baudrate=115200): - self.serial = serial.Serial(serial_device, baudrate=baudrate, interCharTimeout=1) + def __init__(self, device, baudrate=115200, user='micro', password='python'): + if device and device[0].isdigit() and device[-1].isdigit() and device.count('.') == 3: + # device looks like an IP address + self.serial = TelnetToSerial(device, user, password, read_timeout=10) + else: + import serial + self.serial = serial.Serial(device, baudrate=baudrate, interCharTimeout=1) def close(self): self.serial.close() @@ -155,85 +228,28 @@ class Pyboard: t = str(self.eval('pyb.RTC().datetime()'), encoding='utf8')[1:-1].split(', ') return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6]) -def execfile(filename, device='/dev/ttyACM0'): - pyb = Pyboard(device) +def execfile(filename, device='/dev/ttyACM0', baudrate=115200, user='micro', password='python'): + pyb = Pyboard(device, baudrate, user, password) pyb.enter_raw_repl() output = pyb.execfile(filename) stdout_write_bytes(output) pyb.exit_raw_repl() pyb.close() -def run_test(device): - pyb = Pyboard(device) - pyb.enter_raw_repl() - print('opened device {}'.format(device)) - - pyb.exec('import pyb') # module pyb no longer imported by default, required for pyboard tests - print('seconds since boot:', pyb.get_time()) - - pyb.exec('def apply(l, f):\r\n for item in l:\r\n f(item)\r\n') - - pyb.exec('leds=[pyb.LED(l) for l in range(1, 5)]') - pyb.exec('apply(leds, lambda l:l.off())') - - ## USR switch test - - pyb.exec('switch = pyb.Switch()') - - for i in range(2): - print("press USR button") - pyb.exec('while switch(): pyb.delay(10)') - pyb.exec('while not switch(): pyb.delay(10)') - - print('USR switch passed') - - ## accel test - - if True: - print("hold level") - pyb.exec('accel = pyb.Accel()') - pyb.exec('while abs(accel.x()) > 10 or abs(accel.y()) > 10: pyb.delay(10)') - - print("tilt left") - pyb.exec('while accel.x() > -10: pyb.delay(10)') - pyb.exec('leds[0].on()') - - print("tilt forward") - pyb.exec('while accel.y() < 10: pyb.delay(10)') - pyb.exec('leds[1].on()') - - print("tilt right") - pyb.exec('while accel.x() < 10: pyb.delay(10)') - pyb.exec('leds[2].on()') - - print("tilt backward") - pyb.exec('while accel.y() > -10: pyb.delay(10)') - pyb.exec('leds[3].on()') - - print('accel passed') - - print('seconds since boot:', pyb.get_time()) - - pyb.exec('apply(leds, lambda l:l.off())') - - pyb.exit_raw_repl() - pyb.close() - def main(): import argparse cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.') - cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device of the pyboard') + cmd_parser.add_argument('--device', default='/dev/ttyACM0', help='the serial device or the IP address of the pyboard') + cmd_parser.add_argument('-b', '--baudrate', default=115200, help='the baud rate of the serial device') + cmd_parser.add_argument('-u', '--user', default='micro', help='the telnet login username') + cmd_parser.add_argument('-p', '--password', default='python', help='the telnet login password') cmd_parser.add_argument('--follow', action='store_true', help='follow the output after running the scripts [default if no scripts given]') - cmd_parser.add_argument('--test', action='store_true', help='run a small test suite on the pyboard') cmd_parser.add_argument('files', nargs='*', help='input files') args = cmd_parser.parse_args() - if args.test: - run_test(device=args.device) - for filename in args.files: try: - pyb = Pyboard(args.device) + pyb = Pyboard(args.device, args.baudrate, args.user, args.password) pyb.enter_raw_repl() with open(filename, 'rb') as f: pyfile = f.read() @@ -251,7 +267,7 @@ def main(): if args.follow or len(args.files) == 0: try: - pyb = Pyboard(args.device) + pyb = Pyboard(args.device, args.baudrate, args.user, args.password) ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes) pyb.close() except PyboardError as er: