Include PaPiRus drivers in project

This commit is contained in:
James Hooker 2019-09-30 11:20:35 +01:00
parent f54dd891fd
commit b25092c97b
5 changed files with 263 additions and 3 deletions

View File

@ -123,11 +123,11 @@ class Display(View):
self._display = InkyPHAT(self._display_color) self._display = InkyPHAT(self._display_color)
self._display.set_border(InkyPHAT.BLACK) self._display.set_border(InkyPHAT.BLACK)
self._render_cb = self._inky_render self._render_cb = self._inky_render
elif self._is_papirus(): elif self._is_papirus():
from papirus import Papirus from pwnagotchi.ui.papirus.epd import EPD
os.environ['EPD_SIZE'] = '2.0' os.environ['EPD_SIZE'] = '2.0'
self._display = Papirus() self._display = EPD()
self._display.clear() self._display.clear()
self._render_cb = self._papirus_render self._render_cb = self._papirus_render

View File

@ -0,0 +1,213 @@
#qCopyright 2013-2015 Pervasive Displays, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at:
#
# http:#www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied. See the License for the specific language
# governing permissions and limitations under the License.
from PIL import Image
from PIL import ImageOps
from pwnagotchi.ui.papirus.lm75b import LM75B
import re
import os
import sys
if sys.version_info < (3,):
def b(x):
return x
else:
def b(x):
return x.encode('ISO-8859-1')
class EPDError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class EPD(object):
"""EPD E-Ink interface
to use:
from EPD import EPD
epd = EPD([path='/path/to/epd'], [auto=boolean], [rotation = 0|90|180|270])
image = Image.new('1', epd.size, 0)
# draw on image
epd.clear() # clear the panel
epd.display(image) # tranfer image data
epd.update() # refresh the panel image - not needed if auto=true
"""
PANEL_RE = re.compile('^([A-Za-z]+)\s+(\d+\.\d+)\s+(\d+)x(\d+)\s+COG\s+(\d+)\s+FILM\s+(\d+)\s*$', flags=0)
def __init__(self, *args, **kwargs):
self._epd_path = '/dev/epd'
self._width = 200
self._height = 96
self._panel = 'EPD 2.0'
self._cog = 0
self._film = 0
self._auto = False
self._lm75b = LM75B()
self._rotation = 0
self._uselm75b = True
if len(args) > 0:
self._epd_path = args[0]
elif 'epd' in kwargs:
self._epd_path = kwargs['epd']
if ('auto' in kwargs) and kwargs['auto']:
self._auto = True
if ('rotation' in kwargs):
rot = kwargs['rotation']
if rot in (0, 90, 180, 270):
self._rotation = rot
else:
raise EPDError('rotation can only be 0, 90, 180 or 270')
with open(os.path.join(self._epd_path, 'version')) as f:
self._version = f.readline().rstrip('\n')
with open(os.path.join(self._epd_path, 'panel')) as f:
line = f.readline().rstrip('\n')
m = self.PANEL_RE.match(line)
if m is None:
raise EPDError('invalid panel string')
self._panel = m.group(1) + ' ' + m.group(2)
self._width = int(m.group(3))
self._height = int(m.group(4))
self._cog = int(m.group(5))
self._film = int(m.group(6))
if self._width < 1 or self._height < 1:
raise EPDError('invalid panel geometry')
if self._rotation in (90, 270):
self._width, self._height = self._height, self._width
@property
def size(self):
return (self._width, self._height)
@property
def width(self):
return self._width
@property
def height(self):
return self._height
@property
def panel(self):
return self._panel
@property
def version(self):
return self._version
@property
def cog(self):
return self._cog
@property
def film(self):
return self._film
@property
def auto(self):
return self._auto
@auto.setter
def auto(self, flag):
if flag:
self._auto = True
else:
self._auto = False
@property
def rotation(self):
return self._rotation
@rotation.setter
def rotation(self, rot):
if rot not in (0, 90, 180, 270):
raise EPDError('rotation can only be 0, 90, 180 or 270')
if abs(self._rotation - rot) == 90 or abs(self._rotation - rot) == 270:
self._width, self._height = self._height, self._width
self._rotation = rot
@property
def use_lm75b(self):
return self._uselm75b
@use_lm75b.setter
def use_lm75b(self, flag):
if flag:
self._uselm75b = True
else:
self._uselm75b = False
def error_status(self):
with open(os.path.join(self._epd_path, 'error'), 'r') as f:
return(f.readline().rstrip('\n'))
def rotation_angle(self, rotation):
angles = { 90 : Image.ROTATE_90, 180 : Image.ROTATE_180, 270 : Image.ROTATE_270 }
return angles[rotation]
def display(self, image):
# attempt grayscale conversion, and then to single bit
# better to do this before calling this if the image is to
# be dispayed several times
if image.mode != "1":
image = ImageOps.grayscale(image).convert("1", dither=Image.FLOYDSTEINBERG)
if image.mode != "1":
raise EPDError('only single bit images are supported')
if image.size != self.size:
raise EPDError('image size mismatch')
if self._rotation != 0:
image = image.transpose(self.rotation_angle(self._rotation))
with open(os.path.join(self._epd_path, 'LE', 'display_inverse'), 'r+b') as f:
f.write(image.tobytes())
if self.auto:
self.update()
def update(self):
self._command('U')
def partial_update(self):
self._command('P')
def fast_update(self):
self._command('F')
def clear(self):
self._command('C')
def _command(self, c):
if self._uselm75b:
with open(os.path.join(self._epd_path, 'temperature'), 'wb') as f:
f.write(b(repr(self._lm75b.getTempC())))
with open(os.path.join(self._epd_path, 'command'), 'wb') as f:
f.write(b(c))

View File

@ -0,0 +1,46 @@
# Minimal support for LM75b temperature sensor on the Papirus HAT / Papirus Zero
# This module allows you to read the temperature.
# The OS-output (Over-temperature Shutdown) connected to GPIO xx (pin 11) is not supported
# by this module
#
from __future__ import (print_function, division)
import smbus
LM75B_ADDRESS = 0x48
LM75B_TEMP_REGISTER = 0
LM75B_CONF_REGISTER = 1
LM75B_THYST_REGISTER = 2
LM75B_TOS_REGISTER = 3
LM75B_CONF_NORMAL = 0
class LM75B(object):
def __init__(self, address=LM75B_ADDRESS, busnum=1):
self._address = address
self._bus = smbus.SMBus(busnum)
self._bus.write_byte_data(self._address, LM75B_CONF_REGISTER, LM75B_CONF_NORMAL)
def getTempCFloat(self):
"""Return temperature in degrees Celsius as float"""
raw = self._bus.read_word_data(self._address, LM75B_TEMP_REGISTER) & 0xFFFF
raw = ((raw << 8) & 0xFF00) + (raw >> 8)
return (raw / 32.0) / 8.0
def getTempFFloat(self):
"""Return temperature in degrees Fahrenheit as float"""
return (self.getTempCFloat() * (9.0 / 5.0)) + 32.0
def getTempC(self):
"""Return temperature in degrees Celsius as integer, so it can be
used to write to /dev/epd/temperature"""
raw = self._bus.read_word_data(self._address, LM75B_TEMP_REGISTER) & 0xFFFF
raw = ((raw << 8) & 0xFF00) + (raw >> 8)
return (raw + 128) // 256 # round to nearest integer
if __name__ == "__main__":
sens = LM75B()
print(sens.getTempC(), sens.getTempFFloat())

View File

@ -9,3 +9,4 @@ tweepy
file_read_backwards file_read_backwards
numpy numpy
inky inky
smbus