diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..900c260 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,53 @@ +# Travis CI configuration for automated .mpy file generation. +# Author: Tony DiCola +# License: Public Domain +# This configuration will work with Travis CI (travis-ci.org) to automacially +# build .mpy files for MicroPython when a new tagged release is created. This +# file is relatively generic and can be shared across multiple repositories by +# following these steps: +# 1. Copy this file into a .travis.yml file in the root of the repository. +# 2. Change the deploy > file section below to list each of the .mpy files +# that should be generated. The config will automatically look for +# .py files with the same name as the source for generating the .mpy files. +# Note that the .mpy extension should be lower case! +# 3. Commit the .travis.yml file and push it to GitHub. +# 4. Go to travis-ci.org and find the repository (it needs to be setup to access +# your github account, and your github account needs access to write to the +# repo). Flip the 'ON' switch on for Travis and the repo, see the Travis +# docs for more details: https://docs.travis-ci.com/user/getting-started/ +# 5. Get a GitHub 'personal access token' which has at least 'public_repo' or +# 'repo' scope: https://help.github.com/articles/creating-an-access-token-for-command-line-use/ +# Keep this token safe and secure! Anyone with the token will be able to +# access and write to your GitHub repositories. Travis will use the token +# to attach the .mpy files to the release. +# 6. In the Travis CI settings for the repository that was enabled find the +# environment variable editing page: https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings +# Add an environment variable named GITHUB_TOKEN and set it to the value +# of the GitHub personal access token above. Keep 'Display value in build +# log' flipped off. +# 7. That's it! Tag a release and Travis should go to work to add .mpy files +# to the release. It takes about a 2-3 minutes for a worker to spin up, +# build mpy-cross, and add the binaries to the release. +language: generic + +sudo: true + +deploy: + provider: releases + api_key: $GITHUB_TOKEN + file: + - "framebuf.mpy" + skip_cleanup: true + on: + tags: true + +before_install: +- sudo apt-get -yqq update +- sudo apt-get install -y build-essential git python python-pip +- git clone https://github.com/adafruit/micropython.git +- make -C micropython/mpy-cross +- export PATH=$PATH:$PWD/micropython/mpy-cross/ +- sudo pip install shyaml + +before_deploy: +- shyaml get-values deploy.file < .travis.yml | sed 's/.mpy/.py/' | xargs -L1 mpy-cross diff --git a/framebuf.py b/framebuf.py new file mode 100755 index 0000000..fc8fd61 --- /dev/null +++ b/framebuf.py @@ -0,0 +1,124 @@ +# Pure python implementation of MicroPython framebuf module. +# This is intended for boards with limited flash memory and the inability to +# use the native C version of the framebuf module. This python module can be +# added to the board's file system to provide a functionally identical framebuf +# interface but at the expense of speed (this python version will be _much_ +# slower than the C version). +# This is a direct port of the framebuf module C code to python: +# https://github.com/micropython/micropython/blob/master/extmod/modframebuf.c +# Original file created by Damien P. George. +# Python port below created by Tony DiCola. + + +# Framebuf format constats: +MVLSB = 0 # Single bit displays (like SSD1306 OLED) +RGB565 = 1 # 16-bit color displays +GS4_HMSB = 2 # Unimplemented! + + +class MVLSBFormat: + + def setpixel(self, fb, x, y, color): + index = (y >> 3) * fb.stride + x + offset = y & 0x07 + fb.buf[index] = (fb.buf[index] & ~(0x01 << offset)) | ((color != 0) << offset) + + def getpixel(self, fb, x, y): + index = (y >> 3) * fb.stride + x + offset = y & 0x07 + return ((fb.buf[index] >> offset) & 0x01) + + def fill_rect(self, fb, x, y, width, height, color): + while height > 0: + index = (y >> 3) * fb.stride + x + offset = y & 0x07 + for ww in range(width): + fb.buf[index+ww] = (fb.buf[index+ww] & ~(0x01 << offset)) | ((color != 0) << offset) + y += 1 + height -= 1 + + +class RGB565Format: + + def setpixel(self, fb, x, y, color): + index = (x + y * fb.stride) * 2 + fb.buf[index] = (color >> 8) & 0xFF + fb.buf[index+1] = color & 0xFF + + def getpixel(self, fb, x, y): + index = (x + y * fb.stride) * 2 + return (fb.buf[index] << 8) | fb.buf[index+1] + + def fill_rect(self, fb, x, y, width, height, color): + while height > 0: + for ww in range(width): + index = (ww + x + y * fb.stride) * 2 + fb.buf[index] = (color >> 8) & 0xFF + fb.buf[index+1] = color & 0xFF + y += 1 + height -= 1 + + +class FrameBuffer: + + def __init__(self, buf, width, height, buf_format=MVLSB, stride=None): + self.buf = buf + self.width = width + self.height = height + self.stride = stride + if self.stride is None: + self.stride = width + if buf_format == MVLSB: + self.format = MVLSBFormat() + elif buf_format == RGB565: + self.format = RGB565Format() + else: + raise ValueError('invalid format') + + def fill(self, color): + self.format.fill_rect(self, 0, 0, self.width, self.height, color) + + def fill_rect(self, x, y, width, height, color): + if width < 1 or height < 1 or (x+width) <= 0 or (y+height) <= 0 or y >= self.height or x >= self.width: + return + xend = min(self.width, x+width) + yend = min(self.height, y+height) + x = max(x, 0) + y = max(y, 0) + self.format.fill_rect(self, x, y, xend-x, yend-y, color) + + def pixel(self, x, y, color=None): + if x < 0 or x >= self.width or y < 0 or y >= self.height: + return + if color is None: + return self.format.getpixel(self, x, y) + else: + self.format.setpixel(self, x, y, color) + + def hline(self, x, y, width, color): + self.fill_rect(x, y, width, 1, color) + + def vline(self, x, y, height, color): + self.fill_rect(x, y, 1, height, color) + + def rect(self, x, y, width, height, color): + self.fill_rect(x, y, width, 1, color) + self.fill_rect(x, y+height, width, 1, color) + self.fill_rect(self, x, y, 1, height, color) + self.fill_rect(self, x+width, y, 1, height, color) + + def line(self): + raise NotImplementedError() + + def blit(self): + raise NotImplementedError() + + def scroll(self): + raise NotImplementedError() + + def text(self): + raise NotImplementedError() + + +class FrameBuffer1(FrameBuffer): + pass