Merge pull request #292 from systemik/master
Add support for waveshare oledhat display.
This commit is contained in:
commit
d814de75ab
@ -168,7 +168,7 @@ ui:
|
||||
display:
|
||||
enabled: true
|
||||
rotation: 180
|
||||
# Possible options inkyphat/inky, papirus/papi, waveshare_1/ws_1 or waveshare_2/ws_2
|
||||
# Possible options inkyphat/inky, papirus/papi, waveshare_1/ws_1 or waveshare_2/ws_2, oledhat
|
||||
type: 'waveshare_2'
|
||||
# Possible options red/yellow/black (black used for monocromatic displays)
|
||||
color: 'black'
|
||||
|
@ -130,6 +130,9 @@ class Display(View):
|
||||
def is_waveshare_v2(self):
|
||||
return self._display_type in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2')
|
||||
|
||||
def is_oledhat(self):
|
||||
return self._display_type in ('oledhat')
|
||||
|
||||
def is_waveshare_any(self):
|
||||
return self.is_waveshare_v1() or self.is_waveshare_v2()
|
||||
|
||||
@ -176,6 +179,14 @@ class Display(View):
|
||||
self._display.init(self._display.PART_UPDATE)
|
||||
self._render_cb = self._waveshare_render
|
||||
|
||||
elif self.is_oledhat():
|
||||
logging.info("initializing oledhat display")
|
||||
from pwnagotchi.ui.waveshare.oledhat.epd import EPD
|
||||
self._display = EPD()
|
||||
self._display.init()
|
||||
self._display.Clear()
|
||||
self._render_cb = self._oledhat_render
|
||||
|
||||
else:
|
||||
logging.critical("unknown display type %s" % self._display_type)
|
||||
|
||||
@ -192,6 +203,8 @@ class Display(View):
|
||||
self._display.clear()
|
||||
elif self.is_waveshare_any():
|
||||
self._display.Clear(WHITE)
|
||||
elif self.is_oledhat():
|
||||
self._display.clear()
|
||||
else:
|
||||
logging.critical("unknown display type %s" % self._display_type)
|
||||
|
||||
@ -237,6 +250,9 @@ class Display(View):
|
||||
elif self.is_waveshare_v2():
|
||||
self._display.displayPartial(buf)
|
||||
|
||||
def _oledhat_render(self):
|
||||
self._display.display(self._canvas)
|
||||
|
||||
def _waveshare_bc_render(self):
|
||||
buf_black = self._display.getbuffer(self._canvas)
|
||||
# emptyImage = Image.new('1', (self._display.height, self._display.width), 255)
|
||||
|
@ -24,6 +24,15 @@ def setup_display_specifics(config):
|
||||
face_pos = (0, 0)
|
||||
name_pos = (0, 0)
|
||||
status_pos = (0, 0)
|
||||
channel_pos = (0, 0)
|
||||
aps_pos = (0, 0)
|
||||
uptime_pos = (0, 0)
|
||||
line1_pos = [(0, 0),(0, 0)]
|
||||
line2_pos = (0, 0)
|
||||
friend_face = (0, 0)
|
||||
friend_name = (0, 0)
|
||||
shakes_pos = (0, 0)
|
||||
mode_pos = (0, 0)
|
||||
status_font = fonts.Medium
|
||||
status_max_length = None
|
||||
|
||||
@ -34,7 +43,16 @@ def setup_display_specifics(config):
|
||||
height = 104
|
||||
face_pos = (0, 37)
|
||||
name_pos = (5, 18)
|
||||
channel_pos = (0, 0)
|
||||
aps_pos = (25, 0)
|
||||
status_pos = (102, 18)
|
||||
uptime_pos = (width - 65, 0)
|
||||
line1_pos = [0, int(height * .12), width, int(height * .12)]
|
||||
line2_pos = [0, height - int(height * .12), width, height - int(height * .12)]
|
||||
friend_face_pos = (0, (height * 0.88) - 15)
|
||||
friend_name_pos = (40, (height * 0.88) - 13)
|
||||
shakes_pos = (0, height - int(height * .12) + 1)
|
||||
mode_pos = (width - 25, height - int(height * .12) + 1)
|
||||
status_font = fonts.Small
|
||||
status_max_length = 20
|
||||
|
||||
@ -45,10 +63,39 @@ def setup_display_specifics(config):
|
||||
height = 96
|
||||
face_pos = (0, int(height / 4))
|
||||
name_pos = (5, int(height * .15))
|
||||
channel_pos = (0, 0)
|
||||
aps_pos = (25, 0)
|
||||
status_pos = (int(width / 2) - 15, int(height * .15))
|
||||
uptime_pos = (width - 65, 0)
|
||||
line1_pos = [0, int(height * .12), width, int(height * .12)]
|
||||
line2_pos = [0, height - int(height * .12), width, height - int(height * .12)]
|
||||
friend_face_pos = (0, (height * 0.88) - 15)
|
||||
friend_name_pos = (40, (height * 0.88) - 13)
|
||||
shakes_pos = (0, height - int(height * .12) + 1)
|
||||
mode_pos = mode_pos = (width - 25, height - int(height * .12) + 1)
|
||||
status_font = fonts.Medium
|
||||
status_max_length = (width - status_pos[0]) // 6
|
||||
|
||||
if config['ui']['display']['type'] in ('oledhat'):
|
||||
fonts.setup(8, 8, 8, 8)
|
||||
|
||||
width = 128
|
||||
height = 64
|
||||
face_pos = (0, 32)
|
||||
name_pos = (0, 10)
|
||||
channel_pos = (0, 0)
|
||||
aps_pos = (25, 0)
|
||||
status_pos = (30, 18)
|
||||
uptime_pos = (width - 58, 0)
|
||||
line1_pos = [0, 9, width, 9]
|
||||
line2_pos = [0, 53, width, 53]
|
||||
friend_face_pos = (0, (height * 0.88) - 15)
|
||||
friend_name_pos = (40, (height * 0.88) - 13)
|
||||
shakes_pos = (0, 53)
|
||||
mode_pos = (width - 25, 10 )
|
||||
status_font = fonts.Small
|
||||
status_max_length = 20
|
||||
|
||||
elif config['ui']['display']['type'] in ('ws_1', 'ws1', 'waveshare_1', 'waveshare1',
|
||||
'ws_2', 'ws2', 'waveshare_2', 'waveshare2'):
|
||||
if config['ui']['display']['color'] == 'black':
|
||||
@ -58,7 +105,16 @@ def setup_display_specifics(config):
|
||||
height = 122
|
||||
face_pos = (0, 40)
|
||||
name_pos = (5, 20)
|
||||
channel_pos = (0, 0)
|
||||
aps_pos = (25, 0)
|
||||
status_pos = (125, 20)
|
||||
uptime_pos = (width - 65, 0)
|
||||
line1_pos = [0, int(height * .12), width, int(height * .12)]
|
||||
line2_pos = [0, height - int(height * .12), width, height - int(height * .12)]
|
||||
friend_face_pos = (0, (height * 0.88) - 15)
|
||||
friend_name_pos = (40, (height * 0.88) - 13)
|
||||
shakes_pos = (0, height - int(height * .12) + 1)
|
||||
mode_pos = mode_pos = (width - 25, height - int(height * .12) + 1)
|
||||
status_font = fonts.Medium
|
||||
else:
|
||||
fonts.setup(10, 8, 10, 25)
|
||||
@ -67,11 +123,20 @@ def setup_display_specifics(config):
|
||||
height = 104
|
||||
face_pos = (0, int(height / 4))
|
||||
name_pos = (5, int(height * .15))
|
||||
channel_pos = (0, 0)
|
||||
aps_pos = (25, 0)
|
||||
status_pos = (int(width / 2) - 15, int(height * .15))
|
||||
uptime_pos = (width - 65, 0)
|
||||
line1_pos = [0, int(height * .12), width, int(height * .12)]
|
||||
line2_pos = [0, height - int(height * .12), width, height - int(height * .12)]
|
||||
friend_face_pos = (0, (height * 0.88) - 15)
|
||||
friend_name_pos = (40, (height * 0.88) - 13)
|
||||
shakes_pos = (0, height - int(height * .12) + 1)
|
||||
mode_pos = mode_pos = (width - 25, height - int(height * .12) + 1)
|
||||
status_font = fonts.Medium
|
||||
status_max_length = (width - status_pos[0]) // 6
|
||||
|
||||
return width, height, face_pos, name_pos, status_pos, status_font, status_max_length
|
||||
return width, height, face_pos, name_pos, channel_pos, aps_pos, status_pos, uptime_pos, line1_pos, line2_pos, friend_face_pos, friend_name_pos, shakes_pos, mode_pos, status_font, status_max_length
|
||||
|
||||
|
||||
class View(object):
|
||||
@ -86,30 +151,28 @@ class View(object):
|
||||
self._voice = Voice(lang=config['main']['lang'])
|
||||
|
||||
self._width, self._height, \
|
||||
face_pos, name_pos, status_pos, status_font, status_max_length = setup_display_specifics(config)
|
||||
face_pos, name_pos, channel_pos, aps_pos, status_pos, uptime_pos, line1_pos, line2_pos, friend_face_pos, friend_name_pos, shakes_pos, mode_pos, status_font, status_max_length = setup_display_specifics(config)
|
||||
|
||||
self._state = State(state={
|
||||
'channel': LabeledValue(color=BLACK, label='CH', value='00', position=(0, 0), label_font=fonts.Bold,
|
||||
'channel': LabeledValue(color=BLACK, label='CH', value='00', position=channel_pos, label_font=fonts.Bold,
|
||||
text_font=fonts.Medium),
|
||||
'aps': LabeledValue(color=BLACK, label='APS', value='0 (00)', position=(30, 0), label_font=fonts.Bold,
|
||||
'aps': LabeledValue(color=BLACK, label='APS', value='0 (00)', position=aps_pos, label_font=fonts.Bold,
|
||||
text_font=fonts.Medium),
|
||||
|
||||
# 'epoch': LabeledValue(color=BLACK, label='E', value='0000', position=(145, 0), label_font=fonts.Bold,
|
||||
# text_font=fonts.Medium),
|
||||
|
||||
'uptime': LabeledValue(color=BLACK, label='UP', value='00:00:00', position=(self._width - 65, 0),
|
||||
'uptime': LabeledValue(color=BLACK, label='UP', value='00:00:00', position=uptime_pos,
|
||||
label_font=fonts.Bold,
|
||||
text_font=fonts.Medium),
|
||||
|
||||
'line1': Line([0, int(self._height * .12), self._width, int(self._height * .12)], color=BLACK),
|
||||
'line2': Line(
|
||||
[0, self._height - int(self._height * .12), self._width, self._height - int(self._height * .12)],
|
||||
color=BLACK),
|
||||
'line1': Line(line1_pos,color=BLACK),
|
||||
'line2': Line(line2_pos,color=BLACK),
|
||||
|
||||
'face': Text(value=faces.SLEEP, position=face_pos, color=BLACK, font=fonts.Huge),
|
||||
|
||||
'friend_face': Text(value=None, position=(0, (self._height * 0.88) - 15), font=fonts.Bold, color=BLACK),
|
||||
'friend_name': Text(value=None, position=(40, (self._height * 0.88) - 13), font=fonts.BoldSmall,
|
||||
'friend_face': Text(value=None, position=friend_face_pos, font=fonts.Bold, color=BLACK),
|
||||
'friend_name': Text(value=None, position=friend_name_pos, font=fonts.BoldSmall,
|
||||
color=BLACK),
|
||||
|
||||
'name': Text(value='%s>' % 'pwnagotchi', position=name_pos, color=BLACK, font=fonts.Bold),
|
||||
@ -123,9 +186,9 @@ class View(object):
|
||||
max_length=status_max_length),
|
||||
|
||||
'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK,
|
||||
position=(0, self._height - int(self._height * .12) + 1), label_font=fonts.Bold,
|
||||
position=shakes_pos, label_font=fonts.Bold,
|
||||
text_font=fonts.Medium),
|
||||
'mode': Text(value='AUTO', position=(self._width - 25, self._height - int(self._height * .12) + 1),
|
||||
'mode': Text(value='AUTO', position=mode_pos,
|
||||
font=fonts.Bold, color=BLACK),
|
||||
})
|
||||
|
||||
|
136
pwnagotchi/ui/waveshare/oledhat/SH1106.py
Normal file
136
pwnagotchi/ui/waveshare/oledhat/SH1106.py
Normal file
@ -0,0 +1,136 @@
|
||||
from . import config
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
import numpy as np
|
||||
|
||||
Device_SPI = config.Device_SPI
|
||||
Device_I2C = config.Device_I2C
|
||||
|
||||
LCD_WIDTH = 128 #LCD width
|
||||
LCD_HEIGHT = 64 #LCD height
|
||||
|
||||
class SH1106(object):
|
||||
def __init__(self):
|
||||
self.width = LCD_WIDTH
|
||||
self.height = LCD_HEIGHT
|
||||
#Initialize DC RST pin
|
||||
self._dc = config.DC_PIN
|
||||
self._rst = config.RST_PIN
|
||||
self._bl = config.BL_PIN
|
||||
self.Device = config.Device
|
||||
|
||||
|
||||
""" Write register address and data """
|
||||
def command(self, cmd):
|
||||
if(self.Device == Device_SPI):
|
||||
GPIO.output(self._dc, GPIO.LOW)
|
||||
config.spi_writebyte([cmd])
|
||||
else:
|
||||
config.i2c_writebyte(0x00, cmd)
|
||||
|
||||
# def data(self, val):
|
||||
# GPIO.output(self._dc, GPIO.HIGH)
|
||||
# config.spi_writebyte([val])
|
||||
|
||||
def Init(self):
|
||||
if (config.module_init() != 0):
|
||||
return -1
|
||||
"""Initialize dispaly"""
|
||||
self.reset()
|
||||
self.command(0xAE);#--turn off oled panel
|
||||
self.command(0x02);#---set low column address
|
||||
self.command(0x10);#---set high column address
|
||||
self.command(0x40);#--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
|
||||
self.command(0x81);#--set contrast control register
|
||||
self.command(0xA0);#--Set SEG/Column Mapping
|
||||
self.command(0xC0);#Set COM/Row Scan Direction
|
||||
self.command(0xA6);#--set normal display
|
||||
self.command(0xA8);#--set multiplex ratio(1 to 64)
|
||||
self.command(0x3F);#--1/64 duty
|
||||
self.command(0xD3);#-set display offset Shift Mapping RAM Counter (0x00~0x3F)
|
||||
self.command(0x00);#-not offset
|
||||
self.command(0xd5);#--set display clock divide ratio/oscillator frequency
|
||||
self.command(0x80);#--set divide ratio, Set Clock as 100 Frames/Sec
|
||||
self.command(0xD9);#--set pre-charge period
|
||||
self.command(0xF1);#Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
|
||||
self.command(0xDA);#--set com pins hardware configuration
|
||||
self.command(0x12);
|
||||
self.command(0xDB);#--set vcomh
|
||||
self.command(0x40);#Set VCOM Deselect Level
|
||||
self.command(0x20);#-Set Page Addressing Mode (0x00/0x01/0x02)
|
||||
self.command(0x02);#
|
||||
self.command(0xA4);# Disable Entire Display On (0xa4/0xa5)
|
||||
self.command(0xA6);# Disable Inverse Display On (0xa6/a7)
|
||||
time.sleep(0.1)
|
||||
self.command(0xAF);#--turn on oled panel
|
||||
|
||||
|
||||
def reset(self):
|
||||
"""Reset the display"""
|
||||
GPIO.output(self._rst,GPIO.HIGH)
|
||||
time.sleep(0.1)
|
||||
GPIO.output(self._rst,GPIO.LOW)
|
||||
time.sleep(0.1)
|
||||
GPIO.output(self._rst,GPIO.HIGH)
|
||||
time.sleep(0.1)
|
||||
|
||||
def getbuffer(self, image):
|
||||
# print "bufsiz = ",(self.width/8) * self.height
|
||||
buf = [0xFF] * ((self.width//8) * self.height)
|
||||
image_monocolor = image.convert('1')
|
||||
imwidth, imheight = image_monocolor.size
|
||||
pixels = image_monocolor.load()
|
||||
# print "imwidth = %d, imheight = %d",imwidth,imheight
|
||||
if(imwidth == self.width and imheight == self.height):
|
||||
#print ("Vertical")
|
||||
for y in range(imheight):
|
||||
for x in range(imwidth):
|
||||
# Set the bits for the column of pixels at the current position.
|
||||
if pixels[x, y] == 0:
|
||||
buf[x + (y // 8) * self.width] &= ~(1 << (y % 8))
|
||||
# print x,y,x + (y * self.width)/8,buf[(x + y * self.width) / 8]
|
||||
|
||||
elif(imwidth == self.height and imheight == self.width):
|
||||
#print ("Vertical")
|
||||
for y in range(imheight):
|
||||
for x in range(imwidth):
|
||||
newx = y
|
||||
newy = self.height - x - 1
|
||||
if pixels[x, y] == 0:
|
||||
buf[(newx + (newy // 8 )*self.width) ] &= ~(1 << (y % 8))
|
||||
return buf
|
||||
|
||||
|
||||
# def ShowImage(self,Image):
|
||||
# self.SetWindows()
|
||||
# GPIO.output(self._dc, GPIO.HIGH);
|
||||
# for i in range(0,self.width * self.height/8):
|
||||
# config.spi_writebyte([~Image[i]])
|
||||
|
||||
def ShowImage(self, pBuf):
|
||||
for page in range(0,8):
|
||||
# set page address #
|
||||
self.command(0xB0 + page);
|
||||
# set low column address #
|
||||
self.command(0x02);
|
||||
# set high column address #
|
||||
self.command(0x10);
|
||||
# write data #
|
||||
time.sleep(0.01)
|
||||
if(self.Device == Device_SPI):
|
||||
GPIO.output(self._dc, GPIO.HIGH);
|
||||
for i in range(0,self.width):#for(int i=0;i<self.width; i++)
|
||||
if(self.Device == Device_SPI):
|
||||
config.spi_writebyte([~pBuf[i+self.width*page]]);
|
||||
else :
|
||||
config.i2c_writebyte(0x40, ~pBuf[i+self.width*page])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def clear(self):
|
||||
"""Clear contents of image buffer"""
|
||||
_buffer = [0xff]*(self.width * self.height//8)
|
||||
self.ShowImage(_buffer)
|
||||
#print "%d",_buffer[i:i+4096]
|
0
pwnagotchi/ui/waveshare/oledhat/__init__.py
Normal file
0
pwnagotchi/ui/waveshare/oledhat/__init__.py
Normal file
111
pwnagotchi/ui/waveshare/oledhat/config.py
Normal file
111
pwnagotchi/ui/waveshare/oledhat/config.py
Normal file
@ -0,0 +1,111 @@
|
||||
# /*****************************************************************************
|
||||
# * | File : config.py
|
||||
# * | Author : Waveshare team
|
||||
# * | Function : Hardware underlying interface,for Jetson nano
|
||||
# * | Info :
|
||||
# *----------------
|
||||
# * | This version: V1.0
|
||||
# * | Date : 2019-06-06
|
||||
# * | Info :
|
||||
# ******************************************************************************/
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation 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
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR 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.
|
||||
#
|
||||
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
from smbus import SMBus
|
||||
import spidev
|
||||
|
||||
import ctypes
|
||||
# import spidev
|
||||
|
||||
# Pin definition
|
||||
RST_PIN = 25
|
||||
DC_PIN = 24
|
||||
CS_PIN = 8
|
||||
BL_PIN = 18
|
||||
BUSY_PIN = 18
|
||||
|
||||
Device_SPI = 1
|
||||
Device_I2C = 0
|
||||
|
||||
|
||||
|
||||
if(Device_SPI == 1):
|
||||
Device = Device_SPI
|
||||
spi = spidev.SpiDev(0, 0)
|
||||
else :
|
||||
Device = Device_I2C
|
||||
address = 0x3C
|
||||
bus = SMBus(1)
|
||||
|
||||
def digital_write(pin, value):
|
||||
GPIO.output(pin, value)
|
||||
|
||||
def digital_read(pin):
|
||||
return GPIO.input(BUSY_PIN)
|
||||
|
||||
def delay_ms(delaytime):
|
||||
time.sleep(delaytime / 1000.0)
|
||||
|
||||
def spi_writebyte(data):
|
||||
# SPI.writebytes(data)
|
||||
spi.writebytes([data[0]])
|
||||
|
||||
def i2c_writebyte(reg, value):
|
||||
bus.write_byte_data(address, reg, value)
|
||||
|
||||
# time.sleep(0.01)
|
||||
def module_init():
|
||||
# print("module_init")
|
||||
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setwarnings(False)
|
||||
GPIO.setup(RST_PIN, GPIO.OUT)
|
||||
GPIO.setup(DC_PIN, GPIO.OUT)
|
||||
GPIO.setup(CS_PIN, GPIO.OUT)
|
||||
GPIO.setup(BL_PIN, GPIO.OUT)
|
||||
|
||||
|
||||
# SPI.max_speed_hz = 2000000
|
||||
# SPI.mode = 0b00
|
||||
# i2c_writebyte(0xff,0xff)
|
||||
if(Device == Device_SPI):
|
||||
# spi.SYSFS_software_spi_begin()
|
||||
# spi.SYSFS_software_spi_setDataMode(0);
|
||||
# spi.SYSFS_software_spi_setClockDivider(1);
|
||||
spi.max_speed_hz = 2000000
|
||||
spi.mode = 0b00
|
||||
|
||||
GPIO.output(CS_PIN, 0)
|
||||
GPIO.output(BL_PIN, 1)
|
||||
GPIO.output(DC_PIN, 0)
|
||||
return 0
|
||||
|
||||
def module_exit():
|
||||
if(Device == Device_SPI):
|
||||
spi.SYSFS_software_spi_end()
|
||||
else :
|
||||
bus.close()
|
||||
GPIO.output(RST_PIN, 0)
|
||||
GPIO.output(DC_PIN, 0)
|
||||
|
||||
|
||||
|
||||
### END OF FILE ###
|
32
pwnagotchi/ui/waveshare/oledhat/epd.py
Normal file
32
pwnagotchi/ui/waveshare/oledhat/epd.py
Normal file
@ -0,0 +1,32 @@
|
||||
from . import SH1106
|
||||
import time
|
||||
from . import config
|
||||
import traceback
|
||||
|
||||
from PIL import Image,ImageDraw,ImageFont
|
||||
|
||||
|
||||
# Display resolution
|
||||
EPD_WIDTH = 64
|
||||
EPD_HEIGHT = 128
|
||||
|
||||
disp = SH1106.SH1106()
|
||||
|
||||
class EPD(object):
|
||||
|
||||
def __init__(self):
|
||||
self.reset_pin = config.RST_PIN
|
||||
self.dc_pin = config.DC_PIN
|
||||
self.busy_pin = config.BUSY_PIN
|
||||
self.cs_pin = config.CS_PIN
|
||||
self.width = EPD_WIDTH
|
||||
self.height = EPD_HEIGHT
|
||||
|
||||
def init(self):
|
||||
disp.Init()
|
||||
|
||||
def Clear(self):
|
||||
disp.clear()
|
||||
|
||||
def display(self, image):
|
||||
disp.ShowImage(disp.getbuffer(image))
|
Loading…
x
Reference in New Issue
Block a user