2014-03-24 12:42:06 +00:00
|
|
|
"""
|
|
|
|
pyboard interface
|
|
|
|
|
|
|
|
This module provides the Pyboard class, used to communicate with and
|
|
|
|
control the pyboard over a serial USB connection.
|
|
|
|
|
|
|
|
Example usage:
|
|
|
|
|
|
|
|
import pyboard
|
|
|
|
pyb = pyboard.Pyboard('/dev/ttyACM0')
|
|
|
|
pyb.enter_raw_repl()
|
|
|
|
pyb.exec('pyb.Led(1).on()')
|
|
|
|
pyb.exit_raw_repl()
|
|
|
|
|
2014-04-03 21:12:01 +00:00
|
|
|
To run a script from the local machine on the board and print out the results:
|
|
|
|
|
|
|
|
import pyboard
|
|
|
|
pyboard.execfile('test.py', device='/dev/ttyACM0')
|
|
|
|
|
2014-03-24 12:42:06 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
import time
|
|
|
|
import serial
|
|
|
|
|
2014-04-13 12:48:33 +00:00
|
|
|
class PyboardError(BaseException):
|
|
|
|
pass
|
|
|
|
|
2014-03-24 12:42:06 +00:00
|
|
|
class Pyboard:
|
|
|
|
def __init__(self, serial_device):
|
|
|
|
self.serial = serial.Serial(serial_device)
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.serial.close()
|
|
|
|
|
2014-04-14 00:47:36 +00:00
|
|
|
def read_until(self, min_num_bytes, ending, timeout=10):
|
|
|
|
data = self.serial.read(min_num_bytes)
|
|
|
|
timeout_count = 0
|
|
|
|
while True:
|
|
|
|
if self.serial.inWaiting() > 0:
|
|
|
|
data = data + self.serial.read(self.serial.inWaiting())
|
|
|
|
time.sleep(0.01)
|
|
|
|
timeout_count = 0
|
|
|
|
elif data.endswith(ending):
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
timeout_count += 1
|
|
|
|
if timeout_count >= 10 * timeout:
|
|
|
|
break
|
|
|
|
time.sleep(0.1)
|
|
|
|
return data
|
|
|
|
|
2014-03-24 12:42:06 +00:00
|
|
|
def enter_raw_repl(self):
|
|
|
|
self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL
|
|
|
|
self.serial.write(b'\x04') # ctrl-D: soft reset
|
2014-04-14 00:47:36 +00:00
|
|
|
data = self.read_until(1, b'to exit\r\n>')
|
2014-03-24 12:42:06 +00:00
|
|
|
if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'):
|
|
|
|
print(data)
|
2014-04-13 12:48:33 +00:00
|
|
|
raise PyboardError('could not enter raw repl')
|
2014-03-24 12:42:06 +00:00
|
|
|
|
|
|
|
def exit_raw_repl(self):
|
|
|
|
self.serial.write(b'\r\x02') # ctrl-B: enter friendly REPL
|
|
|
|
|
|
|
|
def eval(self, expression):
|
|
|
|
ret = self.exec('print({})'.format(expression))
|
|
|
|
ret = ret.strip()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def exec(self, command):
|
|
|
|
command_bytes = bytes(command, encoding='ascii')
|
2014-04-03 21:12:01 +00:00
|
|
|
for i in range(0, len(command_bytes), 32):
|
|
|
|
self.serial.write(command_bytes[i:min(i+32, len(command_bytes))])
|
2014-03-24 12:42:06 +00:00
|
|
|
time.sleep(0.01)
|
|
|
|
self.serial.write(b'\x04')
|
|
|
|
data = self.serial.read(2)
|
|
|
|
if data != b'OK':
|
2014-04-13 12:48:33 +00:00
|
|
|
raise PyboardError('could not exec command')
|
2014-04-14 00:47:36 +00:00
|
|
|
data = self.read_until(2, b'\x04>')
|
2014-03-24 12:42:06 +00:00
|
|
|
if not data.endswith(b'\x04>'):
|
|
|
|
print(data)
|
2014-04-13 12:48:33 +00:00
|
|
|
raise PyboardError('timeout waiting for EOF reception')
|
2014-03-24 12:42:06 +00:00
|
|
|
if data.startswith(b'Traceback') or data.startswith(b' File '):
|
|
|
|
print(data)
|
2014-04-13 12:48:33 +00:00
|
|
|
raise PyboardError('command failed')
|
2014-04-03 21:44:37 +00:00
|
|
|
return data[:-2]
|
2014-04-03 21:12:01 +00:00
|
|
|
|
|
|
|
def execfile(self, filename):
|
|
|
|
with open(filename) as f:
|
|
|
|
pyfile = f.read()
|
|
|
|
return self.exec(pyfile)
|
2014-03-24 12:42:06 +00:00
|
|
|
|
|
|
|
def get_time(self):
|
|
|
|
t = str(self.exec('pyb.time()'), encoding='ascii').strip().split()[1].split(':')
|
|
|
|
return int(t[0]) * 3600 + int(t[1]) * 60 + int(t[2])
|
|
|
|
|
2014-04-03 21:12:01 +00:00
|
|
|
def execfile(filename, device='/dev/ttyACM0'):
|
|
|
|
pyb = Pyboard(device)
|
|
|
|
pyb.enter_raw_repl()
|
|
|
|
output = pyb.execfile(filename)
|
2014-04-03 21:44:37 +00:00
|
|
|
print(str(output, encoding='ascii'), end='')
|
2014-04-03 21:12:01 +00:00
|
|
|
pyb.exit_raw_repl()
|
|
|
|
pyb.close()
|
|
|
|
|
2014-03-24 12:42:06 +00:00
|
|
|
def run_test():
|
|
|
|
device = '/dev/ttyACM0'
|
|
|
|
pyb = Pyboard(device)
|
|
|
|
pyb.enter_raw_repl()
|
|
|
|
print('opened device {}'.format(device))
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
if True:
|
|
|
|
for i in range(2):
|
|
|
|
print("press USR button")
|
|
|
|
pyb.exec('while pyb.switch(): pyb.delay(10)')
|
|
|
|
pyb.exec('while not pyb.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()
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
run_test()
|