Merge pull request #292 from systemik/master
Add support for waveshare oledhat display.
This commit is contained in:
commit
d814de75ab
pwnagotchi
@ -168,7 +168,7 @@ ui:
|
|||||||
display:
|
display:
|
||||||
enabled: true
|
enabled: true
|
||||||
rotation: 180
|
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'
|
type: 'waveshare_2'
|
||||||
# Possible options red/yellow/black (black used for monocromatic displays)
|
# Possible options red/yellow/black (black used for monocromatic displays)
|
||||||
color: 'black'
|
color: 'black'
|
||||||
|
@ -130,6 +130,9 @@ class Display(View):
|
|||||||
def is_waveshare_v2(self):
|
def is_waveshare_v2(self):
|
||||||
return self._display_type in ('waveshare_2', 'ws_2', 'waveshare2', 'ws2')
|
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):
|
def is_waveshare_any(self):
|
||||||
return self.is_waveshare_v1() or self.is_waveshare_v2()
|
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._display.init(self._display.PART_UPDATE)
|
||||||
self._render_cb = self._waveshare_render
|
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:
|
else:
|
||||||
logging.critical("unknown display type %s" % self._display_type)
|
logging.critical("unknown display type %s" % self._display_type)
|
||||||
|
|
||||||
@ -192,6 +203,8 @@ class Display(View):
|
|||||||
self._display.clear()
|
self._display.clear()
|
||||||
elif self.is_waveshare_any():
|
elif self.is_waveshare_any():
|
||||||
self._display.Clear(WHITE)
|
self._display.Clear(WHITE)
|
||||||
|
elif self.is_oledhat():
|
||||||
|
self._display.clear()
|
||||||
else:
|
else:
|
||||||
logging.critical("unknown display type %s" % self._display_type)
|
logging.critical("unknown display type %s" % self._display_type)
|
||||||
|
|
||||||
@ -237,6 +250,9 @@ class Display(View):
|
|||||||
elif self.is_waveshare_v2():
|
elif self.is_waveshare_v2():
|
||||||
self._display.displayPartial(buf)
|
self._display.displayPartial(buf)
|
||||||
|
|
||||||
|
def _oledhat_render(self):
|
||||||
|
self._display.display(self._canvas)
|
||||||
|
|
||||||
def _waveshare_bc_render(self):
|
def _waveshare_bc_render(self):
|
||||||
buf_black = self._display.getbuffer(self._canvas)
|
buf_black = self._display.getbuffer(self._canvas)
|
||||||
# emptyImage = Image.new('1', (self._display.height, self._display.width), 255)
|
# emptyImage = Image.new('1', (self._display.height, self._display.width), 255)
|
||||||
|
@ -24,6 +24,15 @@ def setup_display_specifics(config):
|
|||||||
face_pos = (0, 0)
|
face_pos = (0, 0)
|
||||||
name_pos = (0, 0)
|
name_pos = (0, 0)
|
||||||
status_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_font = fonts.Medium
|
||||||
status_max_length = None
|
status_max_length = None
|
||||||
|
|
||||||
@ -34,7 +43,16 @@ def setup_display_specifics(config):
|
|||||||
height = 104
|
height = 104
|
||||||
face_pos = (0, 37)
|
face_pos = (0, 37)
|
||||||
name_pos = (5, 18)
|
name_pos = (5, 18)
|
||||||
|
channel_pos = (0, 0)
|
||||||
|
aps_pos = (25, 0)
|
||||||
status_pos = (102, 18)
|
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_font = fonts.Small
|
||||||
status_max_length = 20
|
status_max_length = 20
|
||||||
|
|
||||||
@ -45,10 +63,39 @@ def setup_display_specifics(config):
|
|||||||
height = 96
|
height = 96
|
||||||
face_pos = (0, int(height / 4))
|
face_pos = (0, int(height / 4))
|
||||||
name_pos = (5, int(height * .15))
|
name_pos = (5, int(height * .15))
|
||||||
|
channel_pos = (0, 0)
|
||||||
|
aps_pos = (25, 0)
|
||||||
status_pos = (int(width / 2) - 15, int(height * .15))
|
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_font = fonts.Medium
|
||||||
status_max_length = (width - status_pos[0]) // 6
|
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',
|
elif config['ui']['display']['type'] in ('ws_1', 'ws1', 'waveshare_1', 'waveshare1',
|
||||||
'ws_2', 'ws2', 'waveshare_2', 'waveshare2'):
|
'ws_2', 'ws2', 'waveshare_2', 'waveshare2'):
|
||||||
if config['ui']['display']['color'] == 'black':
|
if config['ui']['display']['color'] == 'black':
|
||||||
@ -58,7 +105,16 @@ def setup_display_specifics(config):
|
|||||||
height = 122
|
height = 122
|
||||||
face_pos = (0, 40)
|
face_pos = (0, 40)
|
||||||
name_pos = (5, 20)
|
name_pos = (5, 20)
|
||||||
|
channel_pos = (0, 0)
|
||||||
|
aps_pos = (25, 0)
|
||||||
status_pos = (125, 20)
|
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
|
status_font = fonts.Medium
|
||||||
else:
|
else:
|
||||||
fonts.setup(10, 8, 10, 25)
|
fonts.setup(10, 8, 10, 25)
|
||||||
@ -67,11 +123,20 @@ def setup_display_specifics(config):
|
|||||||
height = 104
|
height = 104
|
||||||
face_pos = (0, int(height / 4))
|
face_pos = (0, int(height / 4))
|
||||||
name_pos = (5, int(height * .15))
|
name_pos = (5, int(height * .15))
|
||||||
|
channel_pos = (0, 0)
|
||||||
|
aps_pos = (25, 0)
|
||||||
status_pos = (int(width / 2) - 15, int(height * .15))
|
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_font = fonts.Medium
|
||||||
status_max_length = (width - status_pos[0]) // 6
|
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):
|
class View(object):
|
||||||
@ -86,30 +151,28 @@ class View(object):
|
|||||||
self._voice = Voice(lang=config['main']['lang'])
|
self._voice = Voice(lang=config['main']['lang'])
|
||||||
|
|
||||||
self._width, self._height, \
|
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={
|
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),
|
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),
|
text_font=fonts.Medium),
|
||||||
|
|
||||||
# 'epoch': LabeledValue(color=BLACK, label='E', value='0000', position=(145, 0), label_font=fonts.Bold,
|
# 'epoch': LabeledValue(color=BLACK, label='E', value='0000', position=(145, 0), label_font=fonts.Bold,
|
||||||
# text_font=fonts.Medium),
|
# 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,
|
label_font=fonts.Bold,
|
||||||
text_font=fonts.Medium),
|
text_font=fonts.Medium),
|
||||||
|
|
||||||
'line1': Line([0, int(self._height * .12), self._width, int(self._height * .12)], color=BLACK),
|
'line1': Line(line1_pos,color=BLACK),
|
||||||
'line2': Line(
|
'line2': Line(line2_pos,color=BLACK),
|
||||||
[0, self._height - int(self._height * .12), self._width, self._height - int(self._height * .12)],
|
|
||||||
color=BLACK),
|
|
||||||
|
|
||||||
'face': Text(value=faces.SLEEP, position=face_pos, color=BLACK, font=fonts.Huge),
|
'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_face': Text(value=None, position=friend_face_pos, font=fonts.Bold, color=BLACK),
|
||||||
'friend_name': Text(value=None, position=(40, (self._height * 0.88) - 13), font=fonts.BoldSmall,
|
'friend_name': Text(value=None, position=friend_name_pos, font=fonts.BoldSmall,
|
||||||
color=BLACK),
|
color=BLACK),
|
||||||
|
|
||||||
'name': Text(value='%s>' % 'pwnagotchi', position=name_pos, color=BLACK, font=fonts.Bold),
|
'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),
|
max_length=status_max_length),
|
||||||
|
|
||||||
'shakes': LabeledValue(label='PWND ', value='0 (00)', color=BLACK,
|
'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),
|
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),
|
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