diff --git a/pwnagotchi/ui/display.py b/pwnagotchi/ui/display.py index 3fd343f2..1f08c71b 100644 --- a/pwnagotchi/ui/display.py +++ b/pwnagotchi/ui/display.py @@ -112,6 +112,9 @@ class Display(View): def is_waveshare2in66(self): return self._implementation.name == 'waveshare2in66' + def is_waveshare2in66b(self): + return self._implementation.name == 'waveshare2in66b' + def is_waveshare2in66g(self): return self._implementation.name == 'waveshare2in66g' diff --git a/pwnagotchi/ui/hw/__init__.py b/pwnagotchi/ui/hw/__init__.py index f5d523c4..13fbfa99 100644 --- a/pwnagotchi/ui/hw/__init__.py +++ b/pwnagotchi/ui/hw/__init__.py @@ -36,6 +36,8 @@ from pwnagotchi.ui.hw.waveshare2in9d import Waveshare2in9d from pwnagotchi.ui.hw.waveshare2in13b_V3 import Waveshare2in13bV3 from pwnagotchi.ui.hw.waveshare2in36g import Waveshare2in36g from pwnagotchi.ui.hw.waveshare2in66 import Waveshare2in66 +from pwnagotchi.ui.hw.waveshare2in66b import Waveshare2in66b +from pwnagotchi.ui.hw.waveshare2in66g import Waveshare2in66g from pwnagotchi.ui.hw.waveshare3in0g import Waveshare3in0g from pwnagotchi.ui.hw.waveshare3in7 import Waveshare3in7 from pwnagotchi.ui.hw.waveshare3in52 import Waveshare3in52 @@ -172,8 +174,8 @@ def display_for(config): elif config['ui']['display']['type'] == 'waveshare2in13b_v3': return Waveshare2in13bV3 - elif config['ui']['display']['type'] == 'waveshare2in23g': - return Waveshare2in23g + elif config['ui']['display']['type'] == 'waveshare2in13g': + return Waveshare2in13g elif config['ui']['display']['type'] == 'waveshare2in36g': return Waveshare2in36g @@ -181,6 +183,12 @@ def display_for(config): elif config['ui']['display']['type'] == 'waveshare2in66': return Waveshare2in66 + elif config['ui']['display']['type'] == 'waveshare2in66b': + return Waveshare2in66b + + elif config['ui']['display']['type'] == 'waveshare2in66g': + return Waveshare2in66g + elif config['ui']['display']['type'] == 'waveshare3in0g': return Waveshare3in0g diff --git a/pwnagotchi/ui/hw/libs/waveshare/v2in66b/epd2in66b.py b/pwnagotchi/ui/hw/libs/waveshare/v2in66b/epd2in66b.py new file mode 100644 index 00000000..4ced4d7c --- /dev/null +++ b/pwnagotchi/ui/hw/libs/waveshare/v2in66b/epd2in66b.py @@ -0,0 +1,189 @@ +# ***************************************************************************** +# * | File : epd2in66b.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V1.1 +# * | Date : 2022-08-9 +# # | Info : python demo +# ----------------------------------------------------------------------------- +# 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 logging +from .. import epdconfig + +# Display resolution +EPD_WIDTH = 152 +EPD_HEIGHT = 296 + +logger = logging.getLogger(__name__) + + +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.cs_pin = epdconfig.CS_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, 0) + epdconfig.delay_ms(5) + epdconfig.digital_write(self.reset_pin, 1) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, 0) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([command]) + epdconfig.digital_write(self.cs_pin, 1) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte([data]) + epdconfig.digital_write(self.cs_pin, 1) + + # send a lot of data + def send_data2(self, data): + epdconfig.digital_write(self.dc_pin, 1) + epdconfig.digital_write(self.cs_pin, 0) + epdconfig.spi_writebyte2(data) + epdconfig.digital_write(self.cs_pin, 1) + + def ReadBusy(self): + logger.debug("e-Paper busy") + while (epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy + epdconfig.delay_ms(20) + logger.debug("e-Paper busy release") + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(0x12) + epdconfig.delay_ms(30) + self.ReadBusy() + + self.send_command(0x11) # setting gaet number + self.send_data(0x03) + + self.setWindows(0, 0, self.width - 1, self.height - 1) + + self.send_command(0x21) + self.send_data(0x00) + self.send_data(0x80) + + self.setCursor(0, 0) + self.ReadBusy() + + return 0 + + def setWindows(self, Xstart, Ystart, Xend, Yend): + self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION + self.send_data((Xstart >> 3) & 0x1F) + self.send_data((Xend >> 3) & 0x1F) + + self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION + self.send_data(Ystart & 0xFF) + self.send_data((Ystart >> 8) & 0x01) + self.send_data(Yend & 0xFF) + self.send_data((Yend >> 8) & 0x01) + + def setCursor(self, Xstart, Ystart): + self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER + self.send_data(Xstart & 0x1F) + + self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER + self.send_data(Ystart & 0xFF) + self.send_data((Ystart >> 8) & 0x01) + + def turnon_display(self): + self.send_command(0x20) + self.ReadBusy() + + def getbuffer(self, image): + # logger.debug("bufsiz = ",int(self.width/8) * self.height) + buf = [0xFF] * (int(self.width / 8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # logger.debug("imwidth = %d, imheight = %d",imwidth,imheight) + if (imwidth == self.width and imheight == self.height): + logger.debug("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[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) + elif (imwidth == self.height and imheight == self.width): + logger.debug("Horizontal") + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, Blackimage, Redimage): + if (Blackimage == None or Redimage == None): + return + Redimage_1 = [0x00] * len(Redimage) + for i in range(len(Redimage)): + Redimage_1[i] = ~Redimage[i] + self.send_command(0x24) + self.send_data2(Blackimage) + + self.send_command(0x26) + self.send_data2(Redimage_1) + + self.turnon_display() + + def Clear(self): + if self.width % 8 == 0: + linewidth = int(self.width / 8) + else: + linewidth = int(self.width / 8) + 1 + + self.send_command(0x24) + self.send_data2([0xff] * int(self.height * linewidth)) + + self.send_command(0x26) + self.send_data2([0x00] * int(self.height * linewidth)) + + self.turnon_display() + + def sleep(self): + self.send_command(0X10) # DEEP_SLEEP_MODE + self.send_data(0x01) + + epdconfig.delay_ms(2000) + epdconfig.module_exit() + +### END OF FILE ### diff --git a/pwnagotchi/ui/hw/waveshare2in66b.py b/pwnagotchi/ui/hw/waveshare2in66b.py new file mode 100644 index 00000000..eb874753 --- /dev/null +++ b/pwnagotchi/ui/hw/waveshare2in66b.py @@ -0,0 +1,45 @@ +import logging + +import pwnagotchi.ui.fonts as fonts +from pwnagotchi.ui.hw.base import DisplayImpl + + +class Waveshare2in66b(DisplayImpl): + def __init__(self, config): + super(Waveshare2in66b, self).__init__(config, 'waveshare2in66b') + self._display = None + + def layout(self): + fonts.setup(10, 8, 10, 18, 25, 9) + self._layout['width'] = 152 + self._layout['height'] = 296 + self._layout['face'] = (0, 43) + self._layout['name'] = (0, 14) + self._layout['channel'] = (0, 0) + self._layout['aps'] = (0, 71) + self._layout['uptime'] = (0, 25) + self._layout['line1'] = [0, 12, 152, 12] + self._layout['line2'] = [0, 116, 152, 116] + self._layout['friend_face'] = (12, 88) + self._layout['friend_name'] = (1, 103) + self._layout['shakes'] = (26, 117) + self._layout['mode'] = (0, 117) + self._layout['status'] = { + 'pos': (65, 26), + 'font': fonts.status_font(fonts.Small), + 'max': 12 + } + return self._layout + + def initialize(self): + logging.info("initializing waveshare 2.66b inch lcd display") + from pwnagotchi.ui.hw.libs.waveshare.v2in66b.epd2in66b import EPD + self._display = EPD() + self._display.init() + self._display.Clear() + + def render(self, canvas): + self._display.display(canvas) + + def clear(self): + self._display.Clear() diff --git a/pwnagotchi/utils.py b/pwnagotchi/utils.py index 3c62d7e0..4158f94b 100644 --- a/pwnagotchi/utils.py +++ b/pwnagotchi/utils.py @@ -348,6 +348,12 @@ def load_config(args): elif config['ui']['display']['type'] in 'waveshare2in66': config['ui']['display']['type'] = 'waveshare2in66' + elif config['ui']['display']['type'] in 'waveshare2in66b': + config['ui']['display']['type'] = 'waveshare2in66b' + + elif config['ui']['display']['type'] in 'waveshare2in66g': + config['ui']['display']['type'] = 'waveshare2in66g' + elif config['ui']['display']['type'] in 'waveshare3in0g': config['ui']['display']['type'] = 'waveshare3in0g'