Remove unnecessary files and update license to BSD
This commit is contained in:
26
LICENSE
26
LICENSE
@@ -1,21 +1,13 @@
|
||||
MIT License
|
||||
Copyright (c) 2017 Julian Todd, Adafruit Industries, Thomas Kluyver and contributors
|
||||
|
||||
Copyright (c) 2017 Adafruit Industries
|
||||
BSD 3-clause license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import logging
|
||||
|
||||
from ipykernel.kernelbase import Kernel
|
||||
import pkg_resources
|
||||
|
||||
from jupyter_micropython_kernel.pyboard import Pyboard
|
||||
|
||||
|
||||
# Create global logger for debug messages.
|
||||
logger = logging.getLogger(__name__)
|
||||
# Get version from setuptools. This is used to tell Jupyter the version of
|
||||
# this kernel.
|
||||
version = pkg_resources.require('jupyter_micropython_kernel')[0].version
|
||||
|
||||
|
||||
|
||||
def make_micropython_kernel(port, baud):
|
||||
# Create a MicroPython kernel class and return it. This is done so instance
|
||||
# specific config like port and baud rate can be set. Unfortunately the
|
||||
# IPython kernel wrapper design doesn't appear to allow for
|
||||
# instance-specific configuration (i.e. you don't create the instance
|
||||
# and call its constructor to control how it's built). As a workaround
|
||||
# we'll just build a separate kernel class with a class-specific port and
|
||||
# baud rate baked in.
|
||||
class MicroPythonKernel(Kernel):
|
||||
implementation = 'micropython'
|
||||
implementation_version = version
|
||||
language = 'micropython'
|
||||
language_version = version
|
||||
language_info = {
|
||||
'name': 'python',
|
||||
'mimetype': 'text/x-python',
|
||||
'file_extension': '.py',
|
||||
}
|
||||
banner = 'MicroPython Kernel - port: {} - baud: {}'.format(port, baud)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
# Open MicroPython board and enter raw REPL which resets the board
|
||||
# and makes it ready to accept commands.
|
||||
logger.debug('Opening33 MicroPython board connection on port: {} baud: {}'.format(port, baud))
|
||||
self._board = Pyboard(port, baudrate=baud)
|
||||
self._board.enter_raw_repl()
|
||||
|
||||
def do_execute(self, code, silent, store_history=True,
|
||||
user_expressions=None, allow_stdin=False):
|
||||
|
||||
logger.debug("Received executing ccccode", [code])
|
||||
|
||||
# Run the specified code on the connected MicroPython board.
|
||||
|
||||
try:
|
||||
result, error = self._board.exec_raw(code)
|
||||
except KeyboardInterrupt as e:
|
||||
logger.debug([e, dir(e)])
|
||||
result = b"thing"
|
||||
error = b"thang"
|
||||
|
||||
logger.debug('Result: {} Error: {}'.format(result, error))
|
||||
# If there was an error send it back, otherwise send the result.
|
||||
# Make sure to convert this to a JSON serializable string from the
|
||||
# raw bytes (assumes UTF-8 encoding). This doesn't really feel
|
||||
# like the right way to send back errors but the docs are really
|
||||
# hard to figure out what's expected (do you send a stream_content
|
||||
# with name stderr? is there more to return?).
|
||||
failed = error is not None and len(error) > 0
|
||||
response = result.decode('utf-8') if not failed else error.decode('utf-8')
|
||||
|
||||
# Send the result when not in silent mode.
|
||||
if not silent:
|
||||
stream_content = {'name': 'stdout', 'text': response }
|
||||
self.send_response(self.iopub_socket, 'stream', stream_content)
|
||||
return {'status': 'ok' if not failed else 'error',
|
||||
# The base class increments the execution count
|
||||
'execution_count': self.execution_count,
|
||||
'payload': [],
|
||||
'user_expressions': {},
|
||||
}
|
||||
|
||||
def do_shutdown(self, restart):
|
||||
# Be nice and try to exit the raw REPL, but ignore any failure
|
||||
# in case the connection is already dead.
|
||||
logger.debug('Shutting down MicroPython board connection.')
|
||||
try:
|
||||
self._board.exit_raw_repl()
|
||||
except:
|
||||
pass
|
||||
self._board.close()
|
||||
|
||||
return MicroPythonKernel
|
||||
@@ -1,349 +0,0 @@
|
||||
# MicroPython board communication class from MicroPython source:
|
||||
# https://github.com/micropython/micropython/blob/master/tools/pyboard.py
|
||||
#!/usr/bin/env python
|
||||
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
"""
|
||||
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')
|
||||
|
||||
Or:
|
||||
|
||||
pyb = pyboard.Pyboard('192.168.1.1')
|
||||
|
||||
Then:
|
||||
|
||||
pyb.enter_raw_repl()
|
||||
pyb.exec('pyb.LED(1).on()')
|
||||
pyb.exit_raw_repl()
|
||||
|
||||
Note: if using Python2 then pyb.exec must be written as pyb.exec_.
|
||||
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')
|
||||
|
||||
This script can also be run directly. To execute a local script, use:
|
||||
|
||||
./pyboard.py test.py
|
||||
|
||||
Or:
|
||||
|
||||
python pyboard.py test.py
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
try:
|
||||
stdout = sys.stdout.buffer
|
||||
except AttributeError:
|
||||
# Python2 doesn't have buffer attr
|
||||
stdout = sys.stdout
|
||||
|
||||
def stdout_write_bytes(b):
|
||||
b = b.replace(b"\x04", b"")
|
||||
stdout.write(b)
|
||||
stdout.flush()
|
||||
|
||||
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, device, baudrate=115200, user='micro', password='python', wait=0):
|
||||
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
|
||||
delayed = False
|
||||
for attempt in range(wait + 1):
|
||||
try:
|
||||
self.serial = serial.Serial(device, baudrate=baudrate, interCharTimeout=1)
|
||||
break
|
||||
except (OSError, IOError): # Py2 and Py3 have different errors
|
||||
if wait == 0:
|
||||
continue
|
||||
if attempt == 0:
|
||||
sys.stdout.write('Waiting {} seconds for pyboard '.format(wait))
|
||||
delayed = True
|
||||
time.sleep(1)
|
||||
sys.stdout.write('.')
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
if delayed:
|
||||
print('')
|
||||
raise PyboardError('failed to access ' + device)
|
||||
if delayed:
|
||||
print('')
|
||||
|
||||
def close(self):
|
||||
self.serial.close()
|
||||
|
||||
def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None):
|
||||
try:
|
||||
data = self.serial.read(min_num_bytes)
|
||||
except KeyboardInterrupt as e:
|
||||
logger.debug("KKeyboard interrupt caught, sending to Micropython")
|
||||
self.serial.write(b'\x03')
|
||||
data = b"KKK"
|
||||
|
||||
if data_consumer:
|
||||
data_consumer(data)
|
||||
timeout_count = 0
|
||||
while True:
|
||||
try:
|
||||
if data.endswith(ending):
|
||||
break
|
||||
elif self.serial.inWaiting() > 0:
|
||||
new_data = self.serial.read(1)
|
||||
data = data + new_data
|
||||
if data_consumer:
|
||||
data_consumer(new_data)
|
||||
timeout_count = 0
|
||||
else:
|
||||
timeout_count += 1
|
||||
if timeout is not None and timeout_count >= 100 * timeout:
|
||||
break
|
||||
time.sleep(0.01)
|
||||
except KeyboardInterrupt as e:
|
||||
logger.debug("Keyboard interrupt caught, sending to Micropython")
|
||||
self.serial.write(b'\x03')
|
||||
return data
|
||||
|
||||
def enter_raw_repl(self):
|
||||
self.serial.write(b'\r\x03\x03') # ctrl-C twice: interrupt any running program
|
||||
|
||||
# flush input (without relying on serial.flushInput())
|
||||
n = self.serial.inWaiting()
|
||||
while n > 0:
|
||||
self.serial.read(n)
|
||||
n = self.serial.inWaiting()
|
||||
|
||||
self.serial.write(b'\r\x01') # ctrl-A: enter raw REPL
|
||||
data = self.read_until(1, b'raw REPL; CTRL-B to exit\r\n>')
|
||||
if not data.endswith(b'raw REPL; CTRL-B to exit\r\n>'):
|
||||
print(data)
|
||||
raise PyboardError('could not enter raw repl')
|
||||
|
||||
self.serial.write(b'\x04') # ctrl-D: soft reset
|
||||
data = self.read_until(1, b'soft reboot\r\n')
|
||||
if not data.endswith(b'soft reboot\r\n'):
|
||||
print(data)
|
||||
raise PyboardError('could not enter raw repl')
|
||||
# By splitting this into 2 reads, it allows boot.py to print stuff,
|
||||
# which will show up after the soft reboot and before the raw REPL.
|
||||
# Modification from original pyboard.py below:
|
||||
# Add a small delay and send Ctrl-C twice after soft reboot to ensure
|
||||
# any main program loop in main.py is interrupted.
|
||||
time.sleep(0.5)
|
||||
self.serial.write(b'\x03\x03')
|
||||
# End modification above.
|
||||
data = self.read_until(1, b'raw REPL; CTRL-B to exit\r\n')
|
||||
if not data.endswith(b'raw REPL; CTRL-B to exit\r\n'):
|
||||
print(data)
|
||||
raise PyboardError('could not enter raw repl')
|
||||
|
||||
def exit_raw_repl(self):
|
||||
self.serial.write(b'\r\x02') # ctrl-B: enter friendly REPL
|
||||
|
||||
def follow(self, timeout, data_consumer=None):
|
||||
# wait for normal output
|
||||
data = self.read_until(1, b'\x04', timeout=timeout, data_consumer=data_consumer)
|
||||
if not data.endswith(b'\x04'):
|
||||
raise PyboardError('timeout waiting for first EOF reception')
|
||||
data = data[:-1]
|
||||
|
||||
# wait for error output
|
||||
data_err = self.read_until(1, b'\x04', timeout=timeout)
|
||||
if not data_err.endswith(b'\x04'):
|
||||
raise PyboardError('timeout waiting for second EOF reception')
|
||||
data_err = data_err[:-1]
|
||||
|
||||
# return normal and error output
|
||||
return data, data_err
|
||||
|
||||
def exec_raw_no_follow(self, command):
|
||||
if isinstance(command, bytes):
|
||||
command_bytes = command
|
||||
else:
|
||||
command_bytes = bytes(command, encoding='utf8')
|
||||
|
||||
# check we have a prompt
|
||||
data = self.read_until(1, b'>')
|
||||
if not data.endswith(b'>'):
|
||||
raise PyboardError('could not enter raw repl')
|
||||
|
||||
# write command
|
||||
for i in range(0, len(command_bytes), 256):
|
||||
self.serial.write(command_bytes[i:min(i + 256, len(command_bytes))])
|
||||
time.sleep(0.01)
|
||||
self.serial.write(b'\x04')
|
||||
|
||||
# check if we could exec command
|
||||
data = self.serial.read(2)
|
||||
if data != b'OK':
|
||||
raise PyboardError('could not exec command')
|
||||
|
||||
def exec_raw(self, command, timeout=10, data_consumer=None):
|
||||
self.exec_raw_no_follow(command);
|
||||
return self.follow(timeout, data_consumer)
|
||||
|
||||
def eval(self, expression):
|
||||
ret = self.exec_('print({})'.format(expression))
|
||||
ret = ret.strip()
|
||||
return ret
|
||||
|
||||
def exec_(self, command):
|
||||
ret, ret_err = self.exec_raw(command)
|
||||
if ret_err:
|
||||
raise PyboardError('exception', ret, ret_err)
|
||||
return ret
|
||||
|
||||
def execfile(self, filename):
|
||||
with open(filename, 'rb') as f:
|
||||
pyfile = f.read()
|
||||
return self.exec_(pyfile)
|
||||
|
||||
def get_time(self):
|
||||
t = str(self.eval('pyb.RTC().datetime()'), encoding='utf8')[1:-1].split(', ')
|
||||
return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6])
|
||||
|
||||
# in Python2 exec is a keyword so one must use "exec_"
|
||||
# but for Python3 we want to provide the nicer version "exec"
|
||||
setattr(Pyboard, "exec", Pyboard.exec_)
|
||||
|
||||
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 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 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('-c', '--command', help='program passed in as string')
|
||||
cmd_parser.add_argument('-w', '--wait', default=0, type=int, help='seconds to wait for USB connected board to become available')
|
||||
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('files', nargs='*', help='input files')
|
||||
args = cmd_parser.parse_args()
|
||||
|
||||
def execbuffer(buf):
|
||||
try:
|
||||
pyb = Pyboard(args.device, args.baudrate, args.user, args.password, args.wait)
|
||||
pyb.enter_raw_repl()
|
||||
ret, ret_err = pyb.exec_raw(buf, timeout=None, data_consumer=stdout_write_bytes)
|
||||
pyb.exit_raw_repl()
|
||||
pyb.close()
|
||||
except PyboardError as er:
|
||||
print(er)
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
if ret_err:
|
||||
stdout_write_bytes(ret_err)
|
||||
sys.exit(1)
|
||||
|
||||
if args.command is not None:
|
||||
execbuffer(args.command.encode('utf-8'))
|
||||
|
||||
for filename in args.files:
|
||||
with open(filename, 'rb') as f:
|
||||
pyfile = f.read()
|
||||
execbuffer(pyfile)
|
||||
|
||||
if args.follow or (args.command is None and len(args.files) == 0):
|
||||
try:
|
||||
pyb = Pyboard(args.device, args.baudrate, args.user, args.password, args.wait)
|
||||
ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes)
|
||||
pyb.close()
|
||||
except PyboardError as er:
|
||||
print(er)
|
||||
sys.exit(1)
|
||||
except KeyboardInterrupt:
|
||||
sys.exit(1)
|
||||
if ret_err:
|
||||
stdout_write_bytes(ret_err)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user