diff --git a/.gitignore b/.gitignore index b9d6bd9..2588f90 100644 --- a/.gitignore +++ b/.gitignore @@ -213,3 +213,4 @@ pip-log.txt #Mr Developer .mr.developer.cfg +pybcdc.inf diff --git a/Lib/ST7735.py b/Lib/ST7735/__init__.py similarity index 99% rename from Lib/ST7735.py rename to Lib/ST7735/__init__.py index 157cff6..a1d72e2 100644 --- a/Lib/ST7735.py +++ b/Lib/ST7735/__init__.py @@ -336,7 +336,6 @@ class TFT(object) : def fill( self, aColor ) : '''Fill screen with the given color.''' self.fillrect(Point(0, 0), self.size, aColor) - self._draw(self.size.x * self.size.y, aColor) def _draw( self, aPixels, aColor ) : '''Send given color to the device aPixels times.''' diff --git a/Lib/basicfont.py b/Lib/ST7735/basicfont.py similarity index 100% rename from Lib/basicfont.py rename to Lib/ST7735/basicfont.py diff --git a/Lib/seriffont.py b/Lib/ST7735/seriffont.py similarity index 100% rename from Lib/seriffont.py rename to Lib/ST7735/seriffont.py diff --git a/Lib/terminalfont.py b/Lib/ST7735/terminalfont.py similarity index 100% rename from Lib/terminalfont.py rename to Lib/ST7735/terminalfont.py diff --git a/Lib/ultrasonic.py b/Lib/ultrasonic.py new file mode 100644 index 0000000..8771b6b --- /dev/null +++ b/Lib/ultrasonic.py @@ -0,0 +1,82 @@ +## +# Ultrasonic library for MicroPython's pyboard. +# Compatible with HC-SR04 and SRF04. +# +# Copyright 2014 - Sergio Conde Gómez +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +## + +import pyb + +# Pin configuration. +# WARNING: Do not use PA4-X5 or PA5-X6 as the echo pin without a 1k resistor. + +def wait( aCount ): + j = 0; + for i in range(aCount): + j += i + +class Ultrasonic: + def __init__(self, tPin, ePin): + self.triggerPin = tPin + self.echoPin = ePin + + # Init trigger pin (out) + self.trigger = pyb.Pin(self.triggerPin) + self.trigger.init(pyb.Pin.OUT_PP, pyb.Pin.PULL_NONE) + self.trigger.low() + + # Init echo pin (in) + self.echo = pyb.Pin(self.echoPin) + self.echo.init(pyb.Pin.IN, pyb.Pin.PULL_NONE) + + def distance_in_inches(self): + return (self.distance_in_cm() * 0.3937) + + def distance_in_cm(self): + start = 0 + end = 0 + + # Create a microseconds counter. + micros = pyb.Timer(2, prescaler=83, period=0x3fffffff) + micros.counter(0) + + # Send a 10us pulse. + self.trigger.high() + pyb.udelay(10) + self.trigger.low() + + # Wait 'till whe pulse starts. + while self.echo.value() == 0: + start = micros.counter() + + j = 0 + + # Wait 'till the pulse is gone. + while self.echo.value() == 1 and j < 1000: +# print("wait end") +# wait(1000) + j += 1 + end = micros.counter() + + # Deinit the microseconds counter + micros.deinit() + + # Calc the duration of the recieved pulse, divide the result by + # 2 (round-trip) and divide it by 29 (the speed of sound is + # 340 m/s and that is 29 us/cm). + dist_in_cm = ((end - start) / 2) / 29 + + return dist_in_cm diff --git a/boot.py b/boot.py new file mode 100644 index 0000000..0bee9b0 --- /dev/null +++ b/boot.py @@ -0,0 +1,9 @@ +# boot.py -- run on boot-up +# can run arbitrary Python, but best to keep it minimal + +import pyb +from ST7735 import * + +#pyb.main('main.py') # main script to run after this one +#pyb.usb_mode('CDC+MSC') # act as a serial and a storage device +#pyb.usb_mode('CDC+HID') # act as a serial device and a mouse diff --git a/led.py b/led.py new file mode 100644 index 0000000..52e4da1 --- /dev/null +++ b/led.py @@ -0,0 +1,15 @@ +#LED testing. + +from pyb import * + +dC = 5 + +def test( ): + l = LED(4) + for i in range(255): + l.intensity(i) + delay(dC) + for i in range(255, 0, -1): + l.intensity(i) + delay(dC) + l.off() diff --git a/shell.py b/shell.py new file mode 100644 index 0000000..274ea8e --- /dev/null +++ b/shell.py @@ -0,0 +1,365 @@ +"""Implement a simple shell for running on MicroPython.""" + +# from __future__ import print_function + +import os +import sys +import cmd +import pyb +import time + +# TODO: +# - Need to figure out how to get input without echo for term_size +# - Add sys.stdin.isatty() for when we support reading from a file +# - Need to integrate readline in a python callable way (into cmd.py) +# so that the up-arrow works. +# - Need to define input command to use this under windows + +MONTH = ('', 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec') + + +def term_size(): + """Print out a sequence of ANSI escape code which will report back the + size of the window. + """ + # ESC 7 - Save cursor position + # ESC 8 - Restore cursor position + # ESC [r - Enable scrolling for entire display + # ESC [row;colH - Move to cursor position + # ESC [6n - Device Status Report - send ESC [row;colR + repl= None + if 'repl_source' in dir(pyb): + repl = pyb.repl_source() + if repl is None: + repl = pyb.USB_VCP() + repl.send(b'\x1b7\x1b[r\x1b[999;999H\x1b[6n') + pos = b'' + while True: + char = repl.recv(1) + if char == b'R': + break + if char != b'\x1b' and char != b'[': + pos += char + repl.send(b'\x1b8') + (height, width) = [int(i, 10) for i in pos.split(b';')] + return height, width + +# def term_size(): +# return (25, 80) + + +def get_mode(filename): + try: + return os.stat(filename)[0] + except OSError: + return 0 + + +def get_stat(filename): + try: + return os.stat(filename) + except OSError: + return (0, 0, 0, 0, 0, 0, 0, 0) + + +def mode_exists(mode): + return mode & 0xc000 != 0 + + +def mode_isdir(mode): + return mode & 0x4000 != 0 + + +def mode_isfile(mode): + return mode & 0x8000 != 0 + + +def print_cols(words, termwidth=79): + """Takes a single column of words, and prints it as multiple columns that + will fit in termwidth columns. + """ + width = max([len(word) for word in words]) + nwords = len(words) + ncols = max(1, (termwidth + 1) // (width + 1)) + nrows = (nwords + ncols - 1) // ncols + for row in range(nrows): + for i in range(row, nwords, nrows): + print('%-*s' % (width, words[i]), + end='\n' if i + nrows >= nwords else ' ') + + +def print_long(files): + """Prints detailed information about each file passed in.""" + for file in files: + stat = get_stat(file) + mode = stat[0] + if mode_isdir(mode): + mode_str = '/' + else: + mode_str = '' + size = stat[6] + mtime = stat[8] + localtime = time.localtime(mtime) + print('%6d %s %2d %02d:%02d %s%s' % (size, MONTH[localtime[1]], + localtime[2], localtime[4], localtime[5], file, mode_str)) + + +def sdcard_present(): + """Determine if the sdcard is present. This current solution is specific + to the pyboard. We should really have a pyb.scard.detected() method + or something. + """ + return pyb.Pin.board.SD.value() == 0 + + +class Shell(cmd.Cmd): + """Implements the shell as a command line interpreter.""" + + def __init__(self, **kwargs): + (self.term_height, self.term_width) = term_size() + cmd.Cmd.__init__(self, **kwargs) + + self.stdout_to_shell = self.stdout + + self.cur_dir = os.getcwd() + self.set_prompt() + + def set_prompt(self): + self.prompt = self.cur_dir + '> ' + + def resolve_path(self, path): + if path[0] != '/': + # Relative path + if self.cur_dir[-1] == '/': + path = self.cur_dir + path + else: + path = self.cur_dir + '/' + path + comps = path.split('/') + new_comps = [] + for comp in comps: + if comp == '.': + continue + if comp == '..' and len(new_comps) > 1: + new_comps.pop() + else: + new_comps.append(comp) + if len(new_comps) == 1: + return new_comps[0] + '/' + return '/'.join(new_comps) + + def emptyline(self): + """We want empty lines to do nothing. By default they would repeat the + previous command. + + """ + pass + + def postcmd(self, stop, line): + self.stdout.close() + self.stdout = self.stdout_to_shell + self.set_prompt() + return stop + + def line_to_args(self, line): + """This will convert the line passed into the do_xxx functions into + an array of arguments and handle the Output Redirection Operator. + """ + args = line.split() + if '>' in args: + self.stdout = open(args[-1], 'a') + return args[:-2] + else: + return args + + def help_args(self): + self.stdout.write('Prints out command line arguments.\n') + + def do_args(self, line): + args = self.line_to_args(line) + for idx in range(len(args)): + print("arg[%d] = '%s'" % (idx, args[idx])) + + def help_cat(self): + self.stdout.write('Concatinate files and send to stdout.\n') + + def do_cat(self, line): + args = self.line_to_args(line) + for filename in args: + filename = self.resolve_path(filename) + mode = get_mode(filename) + if not mode_exists(mode): + self.stdout.write("Cannot access '%s': No such file\n" % + filename) + continue + if not mode_isfile(mode): + self.stdout.write("'%s': is not a file\n" % filename) + continue + with open(filename, 'r') as txtfile: + for line in txtfile: + self.stdout.write(line) + + def help_cd(self): + self.stdout.write('Changes the current directory\n') + + def do_cd(self, line): + args = self.line_to_args(line) + try: + dirname = self.resolve_path(args[0]) + except IndexError: + dirname = '/' + mode = get_mode(dirname) + if mode_isdir(mode): + self.cur_dir = dirname + else: + self.stdout.write("Directory '%s' does not exist\n" % dirname) + + def help_echo(self): + self.stdout.write('Display a line of text.\n') + + def do_echo(self, line): + args = self.line_to_args(line) + self.stdout.write(args[0]) + self.stdout.write('\n') + + def help_help(self): + self.stdout.write('List available commands with "help" or detailed ' + + 'help with "help cmd".\n') + + def do_help(self, line): + cmd.Cmd.do_help(self, line) + + def help_ls(self): + self.stdout.write('List directory contents.\n' + + 'Use ls -a to show hidden files') + + def do_ls(self, line): + args = self.line_to_args(line) + show_invisible = False + show_long = False + while len(args) > 0 and args[0][0] == '-': + if args[0] == '-a': + show_invisible = True + elif args[0] == '-l': + show_long = True + else: + self.stdout.write("Unrecognized option '%s'" % args[0]) + return + args.remove(args[0]) + if len(args) == 0: + args.append('.') + for idx in range(len(args)): + dirname = self.resolve_path(args[idx]) + mode = get_mode(dirname) + if not mode_exists(mode): + self.stdout.write("Cannot access '%s': No such file or " + "directory\n" % dirname) + continue + if not mode_isdir(mode): + self.stdout.write(dirname) + self.stdout.write('\n') + continue + files = [] + if len(args) > 1: + if idx > 0: + self.stdout.write('\n') + self.stdout.write("%s:\n" % dirname) + for filename in os.listdir(dirname): + if dirname[-1] == '/': + full_filename = dirname + filename + else: + full_filename = dirname + '/' + filename + + mode = get_mode(full_filename) + if not show_long and mode_isdir(mode): + filename += '/' + if (show_invisible or + (filename[0] != '.' and filename[-1] != '~')): + files.append(filename) + if (len(files) > 0): + if show_long: + print_long(sorted(files)) + else: + print_cols(sorted(files), self.term_width) + + def help_micropython(self): + self.stdout.write('Micropython! Call any scripts! Interactive mode! ' + + 'Quit with exit()') + + def do_micropython(self, line): + args = self.line_to_args(line) + source = None + if len(args) == 1: + source = args[-1] + source = self.resolve_path(source) + mode = get_mode(source) + if not mode_exists(mode): + self.stdout.write("Cannot access '%s': No such file\n" % + source) + return + if not mode_isfile(mode): + self.stdout.write("'%s': is not a file\n" % source) + return + if source is None: + print('[Micropython]') + while True: + code_str = '' + line = input('|>>> ') + if line[0:4] == 'exit': + break + code_str += '%s\n' % line + if line[-1] == ':': + while True: + line = input('|... ') + if line == '': + break + code_str += '%s\n' % line + exec(code_str) + else: + code_str = '' + with open(source, 'r') as code: + for line in code: + code_str = code_str + line + '\n' + exec(code_str) + + def help_mkdir(self): + self.stdout.write('Create directory.') + + def do_mkdir(self, line): + args = self.line_to_args(line) + target = args[0] + mode = get_mode(target) + if not mode_exists(mode): + os.mkdir(target) + else: + print('%s already exists.' % target) + + def help_rm(self): + self.stdout.write('Delete files and directories.') + + def do_rm(self, line): + args = self.line_to_args(line) + if args[0] in ('pybcdc.inf', 'README.txt', 'boot.py', 'main.py'): + print('This file cannot be deleted') + try: + os.remove(args[0]) + except: + try: + os.rmdir(args[0]) + except: + print('%s is not a file or directory.' % args[0]) + + def help_EOF(self): + self.stdout.write('Control-D to quit.\n') + + def do_EOF(self, _): + # The prompt will have been printed, so print a newline so that the + # REPL prompt shows up properly. + print('') + return True + + +def run(): + Shell().cmdloop() + +run()