From 3e31533c20047ebeadb49feee3f51a85e130a9c7 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 00:08:49 -0400 Subject: [PATCH 01/13] flexible x & y offsets --- adafruit_rgb_display/rgb.py | 5 ++++- adafruit_rgb_display/st7789.py | 13 +++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index 06d8a61..2b1b19d 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -192,7 +192,8 @@ class DisplaySPI(Display): """Base class for SPI type devices""" #pylint: disable-msg=too-many-arguments def __init__(self, spi, dc, cs, rst=None, width=1, height=1, - baudrate=12000000, polarity=0, phase=0): + baudrate=12000000, polarity=0, phase=0, *, + x_offset=0, y_offset=0): self.spi_device = spi_device.SPIDevice(spi, cs, baudrate=baudrate, polarity=polarity, phase=phase) self.dc_pin = dc @@ -201,6 +202,8 @@ def __init__(self, spi, dc, cs, rst=None, width=1, height=1, if self.rst: self.rst.switch_to_output(value=0) self.reset() + self._X_START = x_offset + self._Y_START = y_offset super().__init__(width, height) #pylint: enable-msg=too-many-arguments diff --git a/adafruit_rgb_display/st7789.py b/adafruit_rgb_display/st7789.py index cefe518..e735aef 100644 --- a/adafruit_rgb_display/st7789.py +++ b/adafruit_rgb_display/st7789.py @@ -104,7 +104,6 @@ class ST7789(DisplaySPI): _PAGE_SET = _RASET _RAM_WRITE = _RAMWR _RAM_READ = _RAMRD - _Y_START = 80 _INIT = ( (_SWRESET, None), (_SLPOUT, None), @@ -113,14 +112,16 @@ class ST7789(DisplaySPI): ) #pylint: disable-msg=useless-super-delegation, too-many-arguments - def __init__(self, spi, dc, cs, rst=None, width=240, height=240, - baudrate=16000000, polarity=0, phase=0): + def __init__(self, spi, dc, cs, rst=None, width=240, height=320, + baudrate=16000000, polarity=0, phase=0, *, + x_offset=0, y_offset=0): super().__init__(spi, dc, cs, rst, width, height, - baudrate=baudrate, polarity=polarity, phase=phase) - + baudrate=baudrate, polarity=polarity, phase=phase, + x_offset=x_offset, y_offset=y_offset) def init(self): + super().init() - cols = struct.pack('>HH', 0, self.width) + cols = struct.pack('>HH', self._X_START, self.width + self._X_START) rows = struct.pack('>HH', self._Y_START, self.height + self._Y_START) for command, data in ( (_CASET, cols), From 0cd0e69ba7848fd8633c1380820c4bd16a3df576 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 03:20:49 -0400 Subject: [PATCH 02/13] image for pillow --- adafruit_rgb_display/rgb.py | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index 2b1b19d..f4277f9 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -41,9 +41,15 @@ __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_RGB_Display.git" # This is the size of the buffer to be used for fill operations, in 16-bit -# units. We use 256, which is 512 bytes — size of the DMA buffer on SAMD21. +# units. #We use 256, which is 512 bytes — size of the DMA buffer on SAMD21. _BUFFER_SIZE = const(256) - +# If we're on CPython, we have more memory, so get a big ol chunk! +try: + import platform + if "CPython" in platform.python_implementation(): + _BUFFER_SIZE = const(320*240) # blit the whole thing at once +except ImportError: + pass def color565(r, g=0, b=0): """Convert red, green and blue values (0-255) into a 16-bit 565 encoding. As @@ -157,6 +163,27 @@ def pixel(self, x, y, color=None): self._block(x, y, x, y, self._encode_pixel(color)) return None + def image(self, img, rotation=0): + + """Set buffer to value of Python Imaging Library image. The image should + be in 1 bit mode and a size equal to the display size.""" + from PIL import Image + + if img.mode != 'RGB': + raise ValueError('Image must be in mode RGB') + if not rotation in (0, 90, 180, 270): + raise ValueError('Rotation must be 0/90/180/270') + if rotation != 0: + img = img.rotate(rotation, expand=True) + imwidth, imheight = img.size + if imwidth != self.width or imheight != self.height: + raise ValueError('Image must be same dimensions as display ({0}x{1}).' \ + .format(self.width, self.height)) + # Grab all the pixels from the image, faster than getpixel. + r, g, b = img.split() + pixels = Image.merge("RGB",(b,g,r)).convert("BGR;16").tobytes() + self._block(0, 0, self.width-1, self.height - 1, pixels) + #pylint: disable-msg=too-many-arguments def fill_rectangle(self, x, y, width, height, color): """Draw a rectangle at specified position with specified width and From b8349fea155b7c948f25005b5df070b356b43d63 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 03:22:04 -0400 Subject: [PATCH 03/13] fix colors --- adafruit_rgb_display/rgb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index f4277f9..a1e588c 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -181,7 +181,7 @@ def image(self, img, rotation=0): .format(self.width, self.height)) # Grab all the pixels from the image, faster than getpixel. r, g, b = img.split() - pixels = Image.merge("RGB",(b,g,r)).convert("BGR;16").tobytes() + pixels = Image.merge("RGB",(b,r,g)).convert("BGR;16").tobytes() self._block(0, 0, self.width-1, self.height - 1, pixels) #pylint: disable-msg=too-many-arguments From 288c132f937882f5796f584a0dd5bfa711dda2e8 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 03:22:48 -0400 Subject: [PATCH 04/13] linux demo --- examples/rgbdisplay_minipitftstats.py | 86 +++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 examples/rgbdisplay_minipitftstats.py diff --git a/examples/rgbdisplay_minipitftstats.py b/examples/rgbdisplay_minipitftstats.py new file mode 100644 index 0000000..944ac70 --- /dev/null +++ b/examples/rgbdisplay_minipitftstats.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- + +import time +import subprocess +import random +import digitalio +import board +from PIL import Image, ImageDraw, ImageFont +from adafruit_rgb_display.rgb import color565 +import adafruit_rgb_display.st7789 as st7789 + + +# Configuration for CS and DC pins (these are FeatherWing defaults on M0/M4): +cs_pin = digitalio.DigitalInOut(board.CE0) +dc_pin = digitalio.DigitalInOut(board.D25) +reset_pin = None + +# Config for display baudrate (default max is 24mhz): +BAUDRATE = 64000000 + +# Setup SPI bus using hardware SPI: +spi = board.SPI() + +# Create the ST7789 display: +disp = st7789.ST7789(spi, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, + width=135, height=240, x_offset=53, y_offset=40) + +# Create blank image for drawing. +# Make sure to create image with mode 'RGB' for full color. +height = disp.width # we swap height/width to rotate it to landscape! +width = disp.height +image = Image.new('RGB', (width, height)) +rotation = 90 + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) + +# Draw a black filled box to clear the image. +draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0)) +disp.image(image, rotation) +# Draw some shapes. +# First define some constants to allow easy resizing of shapes. +padding = -2 +top = padding +bottom = height-padding +# Move left to right keeping track of the current x position for drawing shapes. +x = 0 + + +# Alternatively load a TTF font. Make sure the .ttf font file is in the +# same directory as the python script! +# Some other nice fonts to try: http://www.dafont.com/bitmap.php +font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 24) + +while True: + # Draw a black filled box to clear the image. + draw.rectangle((0, 0, width, height), outline=0, fill=0) + + # Shell scripts for system monitoring from here: + # https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-load + cmd = "hostname -I | cut -d\' \' -f1" + IP = "IP: "+subprocess.check_output(cmd, shell=True).decode("utf-8") + cmd = "top -bn1 | grep load | awk '{printf \"CPU Load: %.2f\", $(NF-2)}'" + CPU = subprocess.check_output(cmd, shell=True).decode("utf-8") + cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%s MB %.2f%%\", $3,$2,$3*100/$2 }'" + MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8") + cmd = "df -h | awk '$NF==\"/\"{printf \"Disk: %d/%d GB %s\", $3,$2,$5}'" + Disk = subprocess.check_output(cmd, shell=True).decode("utf-8") + cmd = "cat /sys/class/thermal/thermal_zone0/temp | awk \'{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}\'" + Temp = subprocess.check_output(cmd, shell=True).decode("utf-8") + + # Write four lines of text. + y = top + draw.text((x, y), IP, font=font, fill="#FFFFFF") + y += font.getsize(IP)[1] + draw.text((x, y), CPU, font=font, fill="#FFFF00") + y += font.getsize(CPU)[1] + draw.text((x, y), MemUsage, font=font, fill="#00FF00") + y += font.getsize(MemUsage)[1] + draw.text((x, y), Disk, font=font, fill="#0000FF") + y += font.getsize(Disk)[1] + draw.text((x, y), Temp, font=font, fill="#FF00FF") + + # Display image. + disp.image(image, rotation) + time.sleep(.1) From 9e8f99feacae2919ffe8166361fe9698c0f1aa14 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 14:36:42 -0400 Subject: [PATCH 05/13] fix color swapping - slow but can optimize later --- adafruit_rgb_display/rgb.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index a1e588c..4209e17 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -169,8 +169,8 @@ def image(self, img, rotation=0): be in 1 bit mode and a size equal to the display size.""" from PIL import Image - if img.mode != 'RGB': - raise ValueError('Image must be in mode RGB') + if not img.mode in ('RGB', 'RGBA'): + raise ValueError('Image must be in mode RGB or RGBA') if not rotation in (0, 90, 180, 270): raise ValueError('Rotation must be 0/90/180/270') if rotation != 0: @@ -179,9 +179,15 @@ def image(self, img, rotation=0): if imwidth != self.width or imheight != self.height: raise ValueError('Image must be same dimensions as display ({0}x{1}).' \ .format(self.width, self.height)) - # Grab all the pixels from the image, faster than getpixel. - r, g, b = img.split() - pixels = Image.merge("RGB",(b,r,g)).convert("BGR;16").tobytes() + pixels = bytearray(self.width * self.height * 2) + # Iterate through the pixels + for x in range(self.width): # yes this double loop is slow, + for y in range(self.height): # but these displays are small! + pix = color565(img.getpixel((x, y))) + pixels[2*(y * self.width + x)] = pix >> 8 + pixels[2*(y * self.width + x) + 1] = pix & 0xFF + + #print([hex(x) for x in pixels]) self._block(0, 0, self.width-1, self.height - 1, pixels) #pylint: disable-msg=too-many-arguments From 77bc9ea51f72edfb61ba7094edeeb1e1ee0e62b7 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 14:38:36 -0400 Subject: [PATCH 06/13] very basic but slow/functional fbcp --- examples/rgbdisplay_fbcp.py | 160 ++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 examples/rgbdisplay_fbcp.py diff --git a/examples/rgbdisplay_fbcp.py b/examples/rgbdisplay_fbcp.py new file mode 100644 index 0000000..18ca704 --- /dev/null +++ b/examples/rgbdisplay_fbcp.py @@ -0,0 +1,160 @@ +import time +import random +import digitalio +import board +from PIL import Image, ImageDraw, ImageFont +from adafruit_rgb_display.rgb import color565 +import adafruit_rgb_display.st7789 as st7789 +import os, sys +import fcntl, mmap, struct + +# definitions from linux/fb.h +FBIOGET_VSCREENINFO = 0x4600 +FBIOGET_FSCREENINFO = 0x4602 +FBIOBLANK = 0x4611 + +FB_TYPE_PACKED_PIXELS= 0 +FB_TYPE_PLANES = 1 +FB_TYPE_INTERLEAVED_PLANES = 2 +FB_TYPE_TEXT = 3 +FB_TYPE_VGA_PLANES = 4 +FB_TYPE_FOURCC = 5 + +FB_VISUAL_MONO01 = 0 +FB_VISUAL_MONO10 = 1 +FB_VISUAL_TRUECOLOR = 2 +FB_VISUAL_PSEUDOCOLOR = 3 +FB_VISUAL_DIRECTCOLOR = 4 +FB_VISUAL_STATIC_PSEUDOCOLOR = 5 +FB_VISUAL_FOURCC = 6 + +FB_BLANK_UNBLANK = 0 +FB_BLANK_POWERDOWN = 4 + + + +class Bitfield: + def __init__(self, offset, length, msb_right): + self.offset = offset + self.length = length + self.msb_right = msb_right + +# Kind of like a pygame Surface object, or not! +# http://www.pygame.org/docs/ref/surface.html +class Framebuffer: + + def __init__(self, dev): + self.dev = dev + self.fbfd = os.open(dev, os.O_RDWR) + vinfo = struct.unpack("8I12I16I4I", fcntl.ioctl(self.fbfd, FBIOGET_VSCREENINFO, " "*((8+12+16+4)*4))) + finfo = struct.unpack("16cL4I3HI", fcntl.ioctl(self.fbfd, FBIOGET_FSCREENINFO, " "*48)) + + bytes_per_pixel = (vinfo[6] + 7) // 8 + screensize = vinfo[0] * vinfo[1] * bytes_per_pixel + + fbp = mmap.mmap(self.fbfd, screensize, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ) + + self.fbp = fbp + self.xres = vinfo[0] + self.yres = vinfo[1] + self.xoffset = vinfo[4] + self.yoffset = vinfo[5] + self.bits_per_pixel = vinfo[6] + self.bytes_per_pixel = bytes_per_pixel + self.grayscale = vinfo[7] + self.red = Bitfield(vinfo[8], vinfo[9], vinfo[10]) + self.green = Bitfield(vinfo[11], vinfo[12], vinfo[13]) + self.blue = Bitfield(vinfo[14], vinfo[15], vinfo[16]) + self.transp = Bitfield(vinfo[17], vinfo[18], vinfo[19]) + self.nonstd = vinfo[20] + self.name = b''.join([x for x in finfo[0:15] if x != b'\x00']) + self.type = finfo[18] + self.visual = finfo[20] + self.line_length = finfo[24] + self.screensize = screensize + + def close(self): + self.fbp.close() + os.close(self.fbfd) + + def blank(self, blank): + # Blanking is not supported by all drivers + try: + if blank: + fcntl.ioctl(self.fbfd, FBIOBLANK, FB_BLANK_POWERDOWN) + else: + fcntl.ioctl(self.fbfd, FBIOBLANK, FB_BLANK_UNBLANK) + except IOError: + pass + + def __str__(self): + visual_list = ['MONO01', 'MONO10', 'TRUECOLOR', 'PSEUDOCOLOR', 'DIRECTCOLOR', 'STATIC PSEUDOCOLOR', 'FOURCC'] + type_list = ['PACKED_PIXELS', 'PLANES', 'INTERLEAVED_PLANES', 'TEXT', 'VGA_PLANES', 'FOURCC'] + visual_name = 'unknown' + if self.visual < len(visual_list): + visual_name = visual_list[self.visual] + type_name = 'unknown' + if self.type < len(type_list): + type_name = type_list[self.type] + + return \ + "mode \"%sx%s\"\n" % (self.xres, self.yres) + \ + " nonstd %s\n" % self.nonstd + \ + " rgba %s/%s,%s/%s,%s/%s,%s/%s\n" % (self.red.length, self.red.offset, self.green.length, self.green.offset, self.blue.length, self.blue.offset, self.transp.length, self.transp.offset) + \ + "endmode\n" + \ + "\n" + \ + "Frame buffer device information:\n" + \ + " Device : %s\n" % self.dev + \ + " Name : %s\n" % self.name + \ + " Size : (%d, %d)\n" % (self.xres, self.yres) + \ + " Length : %s\n" % self.screensize + \ + " BPP : %d\n" % self.bits_per_pixel + \ + " Type : %s\n" % type_name + \ + " Visual : %s\n" % visual_name + \ + " LineLength : %s\n" % self.line_length + +device = '/dev/fb0' +fb = Framebuffer(device) +print(fb) + +# Configuration for CS and DC pins (these are FeatherWing defaults on M0/M4): +cs_pin = digitalio.DigitalInOut(board.CE0) +dc_pin = digitalio.DigitalInOut(board.D25) +reset_pin = None + +# Config for display baudrate (default max is 24mhz): +BAUDRATE = 64000000 + +# Setup SPI bus using hardware SPI: +spi = board.SPI() + +# Create the ST7789 display: +disp = st7789.ST7789(spi, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, + width=135, height=240, x_offset=53, y_offset=40) + +height = disp.width # we swap height/width to rotate it to landscape! +width = disp.height +image = Image.new('RGB', (width, height)) +rotation = 90 + +# Get drawing object to draw on image. +draw = ImageDraw.Draw(image) + +# Draw a black filled box to clear the image. +draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0)) +disp.image(image, rotation) + +while True: + t = time.monotonic() + fb.fbp.seek(0) + b = fb.fbp.read(fb.screensize) + fbimage = Image.frombytes('RGBA', (fb.xres, fb.yres), b, 'raw') + b, g, r, a = fbimage.split() + fbimage = Image.merge("RGB",(r,g,b)) + fbimage = fbimage.resize((width, height)) + + disp.image(fbimage, rotation) + print(1.0 / (time.monotonic()-t)) +fb.close() + + From 170d73e464b91124e00238c456af663a8227aa97 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 14:44:27 -0400 Subject: [PATCH 07/13] button tester --- examples/rgbdisplay_minipitfttest.py | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 examples/rgbdisplay_minipitfttest.py diff --git a/examples/rgbdisplay_minipitfttest.py b/examples/rgbdisplay_minipitfttest.py new file mode 100644 index 0000000..a3a25c5 --- /dev/null +++ b/examples/rgbdisplay_minipitfttest.py @@ -0,0 +1,31 @@ +import time +import random +import digitalio +import board + +from adafruit_rgb_display.rgb import color565 +import adafruit_rgb_display.st7789 as st7789 + +# Configuration for CS and DC pins for Raspberry Pi +cs_pin = digitalio.DigitalInOut(board.CE0) +dc_pin = digitalio.DigitalInOut(board.D25) +reset_pin = None +BAUDRATE = 64000000 # The pi can be very fast! +# Create the ST7789 display: +display = st7789.ST7789(board.SPI(), cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, + width=135, height=240, x_offset=53, y_offset=40) + +buttonA = digitalio.DigitalInOut(board.D23) +buttonB = digitalio.DigitalInOut(board.D24) +buttonA.switch_to_input() +buttonB.switch_to_input() + +# Main loop: +while True: + if not buttonA.value: # button A pressed + display.fill(color565(255, 0, 0)) # red + elif not buttonB.value: # button B pressed + display.fill(color565(0, 0, 255)) # blue + else: + display.fill(color565(0, 255, 0)) # green + From 0363bb6c310e6cddb090b215a557038ee9f497f2 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sun, 15 Sep 2019 15:43:50 -0400 Subject: [PATCH 08/13] test backlight --- examples/rgbdisplay_minipitfttest.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/rgbdisplay_minipitfttest.py b/examples/rgbdisplay_minipitfttest.py index a3a25c5..fd6ba02 100644 --- a/examples/rgbdisplay_minipitfttest.py +++ b/examples/rgbdisplay_minipitfttest.py @@ -15,6 +15,9 @@ display = st7789.ST7789(board.SPI(), cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, width=135, height=240, x_offset=53, y_offset=40) +backlight = digitalio.DigitalInOut(board.D22) +backlight.switch_to_output() +backlight.value = True buttonA = digitalio.DigitalInOut(board.D23) buttonB = digitalio.DigitalInOut(board.D24) buttonA.switch_to_input() @@ -22,10 +25,14 @@ # Main loop: while True: - if not buttonA.value: # button A pressed - display.fill(color565(255, 0, 0)) # red - elif not buttonB.value: # button B pressed - display.fill(color565(0, 0, 255)) # blue + if not buttonA.value and not buttonB.value: + backlight.value = False # turn off backlight else: + backlight.value = True # turn on backlight + if buttonB.value and not buttonA.value: # just button A pressed + display.fill(color565(255, 0, 0)) # red + if buttonA.value and not buttonB.value: # just button B pressed + display.fill(color565(0, 0, 255)) # blue + if buttonA.value and buttonB.value: # none pressed display.fill(color565(0, 255, 0)) # green From 04bff0a9ae9fa01c7cf5ad329e77a4217b96e7ba Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Fri, 20 Sep 2019 23:32:50 -0400 Subject: [PATCH 09/13] fix tab/spaces --- examples/rgbdisplay_fbcp.py | 146 ++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 73 deletions(-) diff --git a/examples/rgbdisplay_fbcp.py b/examples/rgbdisplay_fbcp.py index 18ca704..1570efe 100644 --- a/examples/rgbdisplay_fbcp.py +++ b/examples/rgbdisplay_fbcp.py @@ -34,84 +34,84 @@ class Bitfield: - def __init__(self, offset, length, msb_right): - self.offset = offset - self.length = length - self.msb_right = msb_right + def __init__(self, offset, length, msb_right): + self.offset = offset + self.length = length + self.msb_right = msb_right # Kind of like a pygame Surface object, or not! # http://www.pygame.org/docs/ref/surface.html class Framebuffer: - - def __init__(self, dev): - self.dev = dev - self.fbfd = os.open(dev, os.O_RDWR) - vinfo = struct.unpack("8I12I16I4I", fcntl.ioctl(self.fbfd, FBIOGET_VSCREENINFO, " "*((8+12+16+4)*4))) - finfo = struct.unpack("16cL4I3HI", fcntl.ioctl(self.fbfd, FBIOGET_FSCREENINFO, " "*48)) - - bytes_per_pixel = (vinfo[6] + 7) // 8 - screensize = vinfo[0] * vinfo[1] * bytes_per_pixel - - fbp = mmap.mmap(self.fbfd, screensize, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ) - - self.fbp = fbp - self.xres = vinfo[0] - self.yres = vinfo[1] - self.xoffset = vinfo[4] - self.yoffset = vinfo[5] - self.bits_per_pixel = vinfo[6] - self.bytes_per_pixel = bytes_per_pixel - self.grayscale = vinfo[7] - self.red = Bitfield(vinfo[8], vinfo[9], vinfo[10]) - self.green = Bitfield(vinfo[11], vinfo[12], vinfo[13]) - self.blue = Bitfield(vinfo[14], vinfo[15], vinfo[16]) - self.transp = Bitfield(vinfo[17], vinfo[18], vinfo[19]) - self.nonstd = vinfo[20] - self.name = b''.join([x for x in finfo[0:15] if x != b'\x00']) - self.type = finfo[18] - self.visual = finfo[20] - self.line_length = finfo[24] - self.screensize = screensize - - def close(self): - self.fbp.close() - os.close(self.fbfd) - - def blank(self, blank): - # Blanking is not supported by all drivers - try: - if blank: - fcntl.ioctl(self.fbfd, FBIOBLANK, FB_BLANK_POWERDOWN) - else: - fcntl.ioctl(self.fbfd, FBIOBLANK, FB_BLANK_UNBLANK) - except IOError: - pass - - def __str__(self): - visual_list = ['MONO01', 'MONO10', 'TRUECOLOR', 'PSEUDOCOLOR', 'DIRECTCOLOR', 'STATIC PSEUDOCOLOR', 'FOURCC'] - type_list = ['PACKED_PIXELS', 'PLANES', 'INTERLEAVED_PLANES', 'TEXT', 'VGA_PLANES', 'FOURCC'] - visual_name = 'unknown' - if self.visual < len(visual_list): - visual_name = visual_list[self.visual] - type_name = 'unknown' - if self.type < len(type_list): - type_name = type_list[self.type] - - return \ - "mode \"%sx%s\"\n" % (self.xres, self.yres) + \ - " nonstd %s\n" % self.nonstd + \ - " rgba %s/%s,%s/%s,%s/%s,%s/%s\n" % (self.red.length, self.red.offset, self.green.length, self.green.offset, self.blue.length, self.blue.offset, self.transp.length, self.transp.offset) + \ - "endmode\n" + \ - "\n" + \ - "Frame buffer device information:\n" + \ - " Device : %s\n" % self.dev + \ - " Name : %s\n" % self.name + \ + + def __init__(self, dev): + self.dev = dev + self.fbfd = os.open(dev, os.O_RDWR) + vinfo = struct.unpack("8I12I16I4I", fcntl.ioctl(self.fbfd, FBIOGET_VSCREENINFO, " "*((8+12+16+4)*4))) + finfo = struct.unpack("16cL4I3HI", fcntl.ioctl(self.fbfd, FBIOGET_FSCREENINFO, " "*48)) + + bytes_per_pixel = (vinfo[6] + 7) // 8 + screensize = vinfo[0] * vinfo[1] * bytes_per_pixel + + fbp = mmap.mmap(self.fbfd, screensize, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ) + + self.fbp = fbp + self.xres = vinfo[0] + self.yres = vinfo[1] + self.xoffset = vinfo[4] + self.yoffset = vinfo[5] + self.bits_per_pixel = vinfo[6] + self.bytes_per_pixel = bytes_per_pixel + self.grayscale = vinfo[7] + self.red = Bitfield(vinfo[8], vinfo[9], vinfo[10]) + self.green = Bitfield(vinfo[11], vinfo[12], vinfo[13]) + self.blue = Bitfield(vinfo[14], vinfo[15], vinfo[16]) + self.transp = Bitfield(vinfo[17], vinfo[18], vinfo[19]) + self.nonstd = vinfo[20] + self.name = b''.join([x for x in finfo[0:15] if x != b'\x00']) + self.type = finfo[18] + self.visual = finfo[20] + self.line_length = finfo[24] + self.screensize = screensize + + def close(self): + self.fbp.close() + os.close(self.fbfd) + + def blank(self, blank): + # Blanking is not supported by all drivers + try: + if blank: + fcntl.ioctl(self.fbfd, FBIOBLANK, FB_BLANK_POWERDOWN) + else: + fcntl.ioctl(self.fbfd, FBIOBLANK, FB_BLANK_UNBLANK) + except IOError: + pass + + def __str__(self): + visual_list = ['MONO01', 'MONO10', 'TRUECOLOR', 'PSEUDOCOLOR', 'DIRECTCOLOR', 'STATIC PSEUDOCOLOR', 'FOURCC'] + type_list = ['PACKED_PIXELS', 'PLANES', 'INTERLEAVED_PLANES', 'TEXT', 'VGA_PLANES', 'FOURCC'] + visual_name = 'unknown' + if self.visual < len(visual_list): + visual_name = visual_list[self.visual] + type_name = 'unknown' + if self.type < len(type_list): + type_name = type_list[self.type] + + return \ + "mode \"%sx%s\"\n" % (self.xres, self.yres) + \ + " nonstd %s\n" % self.nonstd + \ + " rgba %s/%s,%s/%s,%s/%s,%s/%s\n" % (self.red.length, self.red.offset, self.green.length, self.green.offset, self.blue.length, self.blue.offset, self.transp.length, self.transp.offset) + \ + "endmode\n" + \ + "\n" + \ + "Frame buffer device information:\n" + \ + " Device : %s\n" % self.dev + \ + " Name : %s\n" % self.name + \ " Size : (%d, %d)\n" % (self.xres, self.yres) + \ - " Length : %s\n" % self.screensize + \ + " Length : %s\n" % self.screensize + \ " BPP : %d\n" % self.bits_per_pixel + \ - " Type : %s\n" % type_name + \ - " Visual : %s\n" % visual_name + \ - " LineLength : %s\n" % self.line_length + " Type : %s\n" % type_name + \ + " Visual : %s\n" % visual_name + \ + " LineLength : %s\n" % self.line_length device = '/dev/fb0' fb = Framebuffer(device) @@ -130,7 +130,7 @@ def __str__(self): # Create the ST7789 display: disp = st7789.ST7789(spi, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, - width=135, height=240, x_offset=53, y_offset=40) + width=135, height=240, x_offset=53, y_offset=40) height = disp.width # we swap height/width to rotate it to landscape! width = disp.height From 074a59dcdf2c8c0ae335ca819c68d2672b2c9049 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Fri, 20 Sep 2019 23:37:44 -0400 Subject: [PATCH 10/13] some linting --- examples/rgbdisplay_fbcp.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/examples/rgbdisplay_fbcp.py b/examples/rgbdisplay_fbcp.py index 1570efe..d6f71d4 100644 --- a/examples/rgbdisplay_fbcp.py +++ b/examples/rgbdisplay_fbcp.py @@ -1,19 +1,21 @@ import time -import random import digitalio import board from PIL import Image, ImageDraw, ImageFont from adafruit_rgb_display.rgb import color565 import adafruit_rgb_display.st7789 as st7789 -import os, sys -import fcntl, mmap, struct +import os +import sys +import fcntl +import mmap +import struct # definitions from linux/fb.h FBIOGET_VSCREENINFO = 0x4600 FBIOGET_FSCREENINFO = 0x4602 FBIOBLANK = 0x4611 -FB_TYPE_PACKED_PIXELS= 0 +FB_TYPE_PACKED_PIXELS = 0 FB_TYPE_PLANES = 1 FB_TYPE_INTERLEAVED_PLANES = 2 FB_TYPE_TEXT = 3 @@ -42,17 +44,23 @@ def __init__(self, offset, length, msb_right): # Kind of like a pygame Surface object, or not! # http://www.pygame.org/docs/ref/surface.html class Framebuffer: - + def __init__(self, dev): self.dev = dev self.fbfd = os.open(dev, os.O_RDWR) - vinfo = struct.unpack("8I12I16I4I", fcntl.ioctl(self.fbfd, FBIOGET_VSCREENINFO, " "*((8+12+16+4)*4))) - finfo = struct.unpack("16cL4I3HI", fcntl.ioctl(self.fbfd, FBIOGET_FSCREENINFO, " "*48)) + vinfo = struct.unpack("8I12I16I4I", + fcntl.ioctl(self.fbfd, + FBIOGET_VSCREENINFO, + " "*((8+12+16+4)*4))) + finfo = struct.unpack("16cL4I3HI", + fcntl.ioctl(self.fbfd, + FBIOGET_FSCREENINFO, " "*48)) bytes_per_pixel = (vinfo[6] + 7) // 8 screensize = vinfo[0] * vinfo[1] * bytes_per_pixel - fbp = mmap.mmap(self.fbfd, screensize, flags=mmap.MAP_SHARED, prot=mmap.PROT_READ) + fbp = mmap.mmap(self.fbfd, screensize, + flags=mmap.MAP_SHARED, prot=mmap.PROT_READ) self.fbp = fbp self.xres = vinfo[0] @@ -149,8 +157,8 @@ def __str__(self): fb.fbp.seek(0) b = fb.fbp.read(fb.screensize) fbimage = Image.frombytes('RGBA', (fb.xres, fb.yres), b, 'raw') - b, g, r, a = fbimage.split() - fbimage = Image.merge("RGB",(r,g,b)) + b, g, r, a = fbimage.split() + fbimage = Image.merge("RGB", (r, g, b)) fbimage = fbimage.resize((width, height)) disp.image(fbimage, rotation) From 830c48246646cdfa4abbe2c2aa95e9104352316c Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Fri, 20 Sep 2019 23:44:14 -0400 Subject: [PATCH 11/13] more linting --- examples/rgbdisplay_fbcp.py | 22 ++++++++++++---------- examples/rgbdisplay_minipitftstats.py | 6 ++---- examples/rgbdisplay_minipitfttest.py | 3 --- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/examples/rgbdisplay_fbcp.py b/examples/rgbdisplay_fbcp.py index d6f71d4..a4ca288 100644 --- a/examples/rgbdisplay_fbcp.py +++ b/examples/rgbdisplay_fbcp.py @@ -1,14 +1,12 @@ import time -import digitalio -import board -from PIL import Image, ImageDraw, ImageFont -from adafruit_rgb_display.rgb import color565 -import adafruit_rgb_display.st7789 as st7789 import os -import sys import fcntl import mmap import struct +import digitalio +import board +from PIL import Image, ImageDraw +import adafruit_rgb_display.st7789 as st7789 # definitions from linux/fb.h FBIOGET_VSCREENINFO = 0x4600 @@ -96,11 +94,14 @@ def blank(self, blank): pass def __str__(self): - visual_list = ['MONO01', 'MONO10', 'TRUECOLOR', 'PSEUDOCOLOR', 'DIRECTCOLOR', 'STATIC PSEUDOCOLOR', 'FOURCC'] - type_list = ['PACKED_PIXELS', 'PLANES', 'INTERLEAVED_PLANES', 'TEXT', 'VGA_PLANES', 'FOURCC'] + visual_list = ['MONO01', 'MONO10', 'TRUECOLOR', + 'PSEUDOCOLOR', 'DIRECTCOLOR', + 'STATIC PSEUDOCOLOR', 'FOURCC'] + type_list = ['PACKED_PIXELS', 'PLANES', 'INTERLEAVED_PLANES', + 'TEXT', 'VGA_PLANES', 'FOURCC'] visual_name = 'unknown' if self.visual < len(visual_list): - visual_name = visual_list[self.visual] + visual_name = visual_list[self.visual] type_name = 'unknown' if self.type < len(type_list): type_name = type_list[self.type] @@ -137,7 +138,8 @@ def __str__(self): spi = board.SPI() # Create the ST7789 display: -disp = st7789.ST7789(spi, cs=cs_pin, dc=dc_pin, rst=reset_pin, baudrate=BAUDRATE, +disp = st7789.ST7789(spi, cs=cs_pin, dc=dc_pin, rst=reset_pin, + baudrate=BAUDRATE, width=135, height=240, x_offset=53, y_offset=40) height = disp.width # we swap height/width to rotate it to landscape! diff --git a/examples/rgbdisplay_minipitftstats.py b/examples/rgbdisplay_minipitftstats.py index 944ac70..bf2c5c3 100644 --- a/examples/rgbdisplay_minipitftstats.py +++ b/examples/rgbdisplay_minipitftstats.py @@ -2,11 +2,9 @@ import time import subprocess -import random import digitalio import board from PIL import Image, ImageDraw, ImageFont -from adafruit_rgb_display.rgb import color565 import adafruit_rgb_display.st7789 as st7789 @@ -77,9 +75,9 @@ y += font.getsize(CPU)[1] draw.text((x, y), MemUsage, font=font, fill="#00FF00") y += font.getsize(MemUsage)[1] - draw.text((x, y), Disk, font=font, fill="#0000FF") + draw.text((x, y), Disk, font=font, fill="#0000FF") y += font.getsize(Disk)[1] - draw.text((x, y), Temp, font=font, fill="#FF00FF") + draw.text((x, y), Temp, font=font, fill="#FF00FF") # Display image. disp.image(image, rotation) diff --git a/examples/rgbdisplay_minipitfttest.py b/examples/rgbdisplay_minipitfttest.py index fd6ba02..08287e1 100644 --- a/examples/rgbdisplay_minipitfttest.py +++ b/examples/rgbdisplay_minipitfttest.py @@ -1,5 +1,3 @@ -import time -import random import digitalio import board @@ -35,4 +33,3 @@ display.fill(color565(0, 0, 255)) # blue if buttonA.value and buttonB.value: # none pressed display.fill(color565(0, 255, 0)) # green - From 2507ca6785b1593ae617b2d6b5601c2d9e26c1be Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sat, 21 Sep 2019 00:55:07 -0400 Subject: [PATCH 12/13] more lint --- adafruit_rgb_display/rgb.py | 17 +++++++---------- examples/rgbdisplay_fbcp.py | 17 +++++++++++------ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index 4209e17..9fca362 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -112,8 +112,8 @@ class Display: #pylint: disable-msg=no-member _COLUMN_SET = None _RAM_WRITE = None _RAM_READ = None - _X_START = 0 - _Y_START = 0 + X_START = 0 + Y_START = 0 _INIT = () _ENCODE_PIXEL = ">H" _ENCODE_POS = ">HH" @@ -132,8 +132,8 @@ def init(self): #pylint: disable-msg=invalid-name,too-many-arguments def _block(self, x0, y0, x1, y1, data=None): """Read or write a block of data.""" - self.write(self._COLUMN_SET, self._encode_pos(x0 + self._X_START, x1 + self._X_START)) - self.write(self._PAGE_SET, self._encode_pos(y0 + self._Y_START, y1 + self._Y_START)) + self.write(self._COLUMN_SET, self._encode_pos(x0 + self.X_START, x1 + self.X_START)) + self.write(self._PAGE_SET, self._encode_pos(y0 + self.Y_START, y1 + self.Y_START)) if data is None: size = struct.calcsize(self._DECODE_PIXEL) return self.read(self._RAM_READ, @@ -164,14 +164,11 @@ def pixel(self, x, y, color=None): return None def image(self, img, rotation=0): - """Set buffer to value of Python Imaging Library image. The image should be in 1 bit mode and a size equal to the display size.""" - from PIL import Image - if not img.mode in ('RGB', 'RGBA'): raise ValueError('Image must be in mode RGB or RGBA') - if not rotation in (0, 90, 180, 270): + if rotation not in (0, 90, 180, 270): raise ValueError('Rotation must be 0/90/180/270') if rotation != 0: img = img.rotate(rotation, expand=True) @@ -235,8 +232,8 @@ def __init__(self, spi, dc, cs, rst=None, width=1, height=1, if self.rst: self.rst.switch_to_output(value=0) self.reset() - self._X_START = x_offset - self._Y_START = y_offset + self.X_START = x_offset + self.Y_START = y_offset super().__init__(width, height) #pylint: enable-msg=too-many-arguments diff --git a/examples/rgbdisplay_fbcp.py b/examples/rgbdisplay_fbcp.py index a4ca288..025b883 100644 --- a/examples/rgbdisplay_fbcp.py +++ b/examples/rgbdisplay_fbcp.py @@ -33,7 +33,7 @@ -class Bitfield: +class Bitfield: # pylint: disable=too-few-public-methods def __init__(self, offset, length, msb_right): self.offset = offset self.length = length @@ -41,7 +41,7 @@ def __init__(self, offset, length, msb_right): # Kind of like a pygame Surface object, or not! # http://www.pygame.org/docs/ref/surface.html -class Framebuffer: +class Framebuffer: # pylint: disable=too-many-instance-attributes def __init__(self, dev): self.dev = dev @@ -109,7 +109,14 @@ def __str__(self): return \ "mode \"%sx%s\"\n" % (self.xres, self.yres) + \ " nonstd %s\n" % self.nonstd + \ - " rgba %s/%s,%s/%s,%s/%s,%s/%s\n" % (self.red.length, self.red.offset, self.green.length, self.green.offset, self.blue.length, self.blue.offset, self.transp.length, self.transp.offset) + \ + " rgba %s/%s,%s/%s,%s/%s,%s/%s\n" % (self.red.length, + self.red.offset, + self.green.length, + self.green.offset, + self.blue.length, + self.blue.offset, + self.transp.length, + self.transp.offset) + \ "endmode\n" + \ "\n" + \ "Frame buffer device information:\n" + \ @@ -157,7 +164,7 @@ def __str__(self): while True: t = time.monotonic() fb.fbp.seek(0) - b = fb.fbp.read(fb.screensize) + b = fb.fbp.read(fb.screensize) fbimage = Image.frombytes('RGBA', (fb.xres, fb.yres), b, 'raw') b, g, r, a = fbimage.split() fbimage = Image.merge("RGB", (r, g, b)) @@ -166,5 +173,3 @@ def __str__(self): disp.image(fbimage, rotation) print(1.0 / (time.monotonic()-t)) fb.close() - - From 297ad9ff3bcd69b3e3c317995a291d0921027978 Mon Sep 17 00:00:00 2001 From: Adafruit Adabot Date: Sat, 21 Sep 2019 00:58:23 -0400 Subject: [PATCH 13/13] more lint --- adafruit_rgb_display/rgb.py | 12 ++++++------ examples/rgbdisplay_minipitftstats.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/adafruit_rgb_display/rgb.py b/adafruit_rgb_display/rgb.py index 9fca362..c6d8288 100644 --- a/adafruit_rgb_display/rgb.py +++ b/adafruit_rgb_display/rgb.py @@ -112,8 +112,8 @@ class Display: #pylint: disable-msg=no-member _COLUMN_SET = None _RAM_WRITE = None _RAM_READ = None - X_START = 0 - Y_START = 0 + _X_START = 0 # pylint: disable=invalid-name + _Y_START = 0 # pylint: disable=invalid-name _INIT = () _ENCODE_PIXEL = ">H" _ENCODE_POS = ">HH" @@ -132,8 +132,8 @@ def init(self): #pylint: disable-msg=invalid-name,too-many-arguments def _block(self, x0, y0, x1, y1, data=None): """Read or write a block of data.""" - self.write(self._COLUMN_SET, self._encode_pos(x0 + self.X_START, x1 + self.X_START)) - self.write(self._PAGE_SET, self._encode_pos(y0 + self.Y_START, y1 + self.Y_START)) + self.write(self._COLUMN_SET, self._encode_pos(x0 + self._X_START, x1 + self._X_START)) + self.write(self._PAGE_SET, self._encode_pos(y0 + self._Y_START, y1 + self._Y_START)) if data is None: size = struct.calcsize(self._DECODE_PIXEL) return self.read(self._RAM_READ, @@ -232,8 +232,8 @@ def __init__(self, spi, dc, cs, rst=None, width=1, height=1, if self.rst: self.rst.switch_to_output(value=0) self.reset() - self.X_START = x_offset - self.Y_START = y_offset + self._X_START = x_offset + self._Y_START = y_offset super().__init__(width, height) #pylint: enable-msg=too-many-arguments diff --git a/examples/rgbdisplay_minipitftstats.py b/examples/rgbdisplay_minipitftstats.py index bf2c5c3..213b188 100644 --- a/examples/rgbdisplay_minipitftstats.py +++ b/examples/rgbdisplay_minipitftstats.py @@ -64,7 +64,7 @@ MemUsage = subprocess.check_output(cmd, shell=True).decode("utf-8") cmd = "df -h | awk '$NF==\"/\"{printf \"Disk: %d/%d GB %s\", $3,$2,$5}'" Disk = subprocess.check_output(cmd, shell=True).decode("utf-8") - cmd = "cat /sys/class/thermal/thermal_zone0/temp | awk \'{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}\'" + cmd = "cat /sys/class/thermal/thermal_zone0/temp | awk \'{printf \"CPU Temp: %.1f C\", $(NF-0) / 1000}\'" # pylint: disable=line-too-long Temp = subprocess.check_output(cmd, shell=True).decode("utf-8") # Write four lines of text.