mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
I2C oled driver mods by NurseJackass
I2C oled config can be added in the config.toml Default is 128x64 display on i2c address 0x3C ui.display.type = "i2coled" ui.display.i2c_addr = 0x3C ui.display.width = 128 ui.display.height = 64
This commit is contained in:
@ -3,20 +3,33 @@
|
|||||||
# https://github.com/adafruit/Adafruit_Python_SSD1306
|
# https://github.com/adafruit/Adafruit_Python_SSD1306
|
||||||
# SMBus parts coming from BLavery's lib_oled96 repo:
|
# SMBus parts coming from BLavery's lib_oled96 repo:
|
||||||
# https://github.com/BLavery/lib_oled96
|
# https://github.com/BLavery/lib_oled96
|
||||||
|
# I2C address, width and height import from config.toml made by NurseJackass
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import pwnagotchi.ui.fonts as fonts
|
import pwnagotchi.ui.fonts as fonts
|
||||||
from pwnagotchi.ui.hw.base import DisplayImpl
|
from pwnagotchi.ui.hw.base import DisplayImpl
|
||||||
|
|
||||||
|
#
|
||||||
|
# Default is 128x64 display on i2c address 0x3C
|
||||||
|
#
|
||||||
|
# Configure i2c address and dimensions in config.toml:
|
||||||
|
#
|
||||||
|
# ui.display.type = "i2coled"
|
||||||
|
# ui.display.i2c_addr = 0x3C
|
||||||
|
# ui.display.width = 128
|
||||||
|
# ui.display.height = 64
|
||||||
|
#
|
||||||
|
|
||||||
class I2COled(DisplayImpl):
|
class I2COled(DisplayImpl):
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
|
self._config = config['ui']['display']
|
||||||
super(I2COled, self).__init__(config, 'i2coled')
|
super(I2COled, self).__init__(config, 'i2coled')
|
||||||
|
|
||||||
def layout(self):
|
def layout(self):
|
||||||
fonts.setup(8, 8, 8, 10, 10, 8)
|
fonts.setup(8, 8, 8, 10, 10, 8)
|
||||||
self._layout['width'] = 128
|
self._layout['width'] = self._config['width'] if 'width' in self._config else 128
|
||||||
self._layout['height'] = 64
|
self._layout['height'] = self._config['height'] if 'height' in self._config else 64
|
||||||
self._layout['face'] = (0, 30)
|
self._layout['face'] = (0, 30)
|
||||||
self._layout['name'] = (0, 10)
|
self._layout['name'] = (0, 10)
|
||||||
self._layout['channel'] = (72, 10)
|
self._layout['channel'] = (72, 10)
|
||||||
@ -36,10 +49,14 @@ class I2COled(DisplayImpl):
|
|||||||
return self._layout
|
return self._layout
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
logging.info("initializing 128x64 I2C Oled Display on address 0x3C")
|
i2caddr = self._config['i2c_addr'] if 'i2c_addr' in self._config else 0x3C
|
||||||
logging.info("To change resolution or address check pwnagotchi/ui/hw/libs/i2coled/epd.py")
|
width = self._config['width'] if 'width' in self._config else 128
|
||||||
|
height = self._config['height'] if 'height' in self._config else 64
|
||||||
|
|
||||||
|
logging.info("initializing %dx%d I2C Oled Display on address 0x%X" % (width, height, i2caddr))
|
||||||
|
|
||||||
from pwnagotchi.ui.hw.libs.i2coled.epd import EPD
|
from pwnagotchi.ui.hw.libs.i2coled.epd import EPD
|
||||||
self._display = EPD()
|
self._display = EPD(address=i2caddr, width=width, height=height)
|
||||||
self._display.Init()
|
self._display.Init()
|
||||||
self._display.Clear()
|
self._display.Clear()
|
||||||
|
|
||||||
|
@ -100,13 +100,19 @@ class SSD1306Base(object):
|
|||||||
"""Send command byte to display."""
|
"""Send command byte to display."""
|
||||||
# I2C write.
|
# I2C write.
|
||||||
assert(len(cmd) <= 31)
|
assert(len(cmd) <= 31)
|
||||||
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
|
try:
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.cmd_mode, list(cmd))
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
def data(self, data):
|
def data(self, data):
|
||||||
"""Send byte of data to display."""
|
"""Send byte of data to display."""
|
||||||
# I2C write.
|
# I2C write.
|
||||||
for i in range(0, len(data), 31):
|
try:
|
||||||
self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31]))
|
for i in range(0, len(data), 31):
|
||||||
|
self.bus.write_i2c_block_data(self.addr, self.data_mode, list(data[i:i+31]))
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
|
def begin(self, vccstate=SSD1306_SWITCHCAPVCC):
|
||||||
"""Initialize display."""
|
"""Initialize display."""
|
||||||
@ -116,7 +122,7 @@ class SSD1306Base(object):
|
|||||||
self._initialize()
|
self._initialize()
|
||||||
# Turn on the display.
|
# Turn on the display.
|
||||||
self.command(SSD1306_DISPLAYON)
|
self.command(SSD1306_DISPLAYON)
|
||||||
|
|
||||||
def ShowImage(self):
|
def ShowImage(self):
|
||||||
"""
|
"""
|
||||||
The image on the "canvas" is flushed through to the hardware display.
|
The image on the "canvas" is flushed through to the hardware display.
|
||||||
@ -128,10 +134,12 @@ class SSD1306Base(object):
|
|||||||
self.command(SSD1306_PAGEADDR)
|
self.command(SSD1306_PAGEADDR)
|
||||||
self.command(0) # Page start address. (0 = reset)
|
self.command(0) # Page start address. (0 = reset)
|
||||||
self.command(self._pages-1) # Page end address.
|
self.command(self._pages-1) # Page end address.
|
||||||
|
try:
|
||||||
for i in range(0, len(self._buffer), 16):
|
for i in range(0, len(self._buffer), 16):
|
||||||
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
|
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
|
||||||
def getbuffer(self, image):
|
def getbuffer(self, image):
|
||||||
"""Set buffer to value of Python Imaging Library image. The image should
|
"""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.
|
be in 1 bit mode and a size equal to the display size.
|
||||||
@ -229,7 +237,7 @@ class SSD1306_128_64(SSD1306Base):
|
|||||||
class SSD1306_128_32(SSD1306Base):
|
class SSD1306_128_32(SSD1306Base):
|
||||||
def __init__(self, width, height, address=None, bus=None):
|
def __init__(self, width, height, address=None, bus=None):
|
||||||
# Call base class constructor.
|
# Call base class constructor.
|
||||||
super(SSD1306_128_64, self).__init__(128, 64, address, bus)
|
super(SSD1306_128_32, self).__init__(128, 32, address, bus)
|
||||||
|
|
||||||
def _initialize(self):
|
def _initialize(self):
|
||||||
# 128x32 pixel specific initialization.
|
# 128x32 pixel specific initialization.
|
||||||
|
@ -8,20 +8,27 @@ EPD_HEIGHT = 64
|
|||||||
# disp = SSD1306.SSD1306_128_32(128, 32, address=0x3C)
|
# disp = SSD1306.SSD1306_128_32(128, 32, address=0x3C)
|
||||||
# disp = SSD1306.SSD1306_96_16(96, 16, address=0x3C)
|
# disp = SSD1306.SSD1306_96_16(96, 16, address=0x3C)
|
||||||
# If you change for different resolution, you have to modify the layout in pwnagotchi/ui/hw/i2coled.py
|
# If you change for different resolution, you have to modify the layout in pwnagotchi/ui/hw/i2coled.py
|
||||||
disp = SSD1306.SSD1306_128_64(128, 64, address=0x3C)
|
|
||||||
|
|
||||||
class EPD(object):
|
class EPD(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, address=0x3D, width=EPD_WIDTH, height=EPD_HEIGHT):
|
||||||
self.width = EPD_WIDTH
|
self.width = width
|
||||||
self.height = EPD_HEIGHT
|
self.height = height
|
||||||
|
|
||||||
|
# choose subclass based on dimensions
|
||||||
|
if height == 32:
|
||||||
|
self.disp = SSD1306.SSD1306_128_32(width, height, address)
|
||||||
|
elif height == 16:
|
||||||
|
self.disp = SSD1306.SSD1306_96_16(width, height, address)
|
||||||
|
else:
|
||||||
|
self.disp = SSD1306.SSD1306_128_64(width, height, address)
|
||||||
|
|
||||||
def Init(self):
|
def Init(self):
|
||||||
disp.begin()
|
self.disp.begin()
|
||||||
|
|
||||||
def Clear(self):
|
def Clear(self):
|
||||||
disp.clear()
|
self.disp.clear()
|
||||||
|
|
||||||
def display(self, image):
|
def display(self, image):
|
||||||
disp.getbuffer(image)
|
self.disp.getbuffer(image)
|
||||||
disp.ShowImage()
|
self.disp.ShowImage()
|
@ -106,7 +106,7 @@ class SSD1306Base(object):
|
|||||||
self._initialize()
|
self._initialize()
|
||||||
# Turn on the display.
|
# Turn on the display.
|
||||||
self.command(SSD1306_DISPLAYON)
|
self.command(SSD1306_DISPLAYON)
|
||||||
|
|
||||||
def ShowImage(self):
|
def ShowImage(self):
|
||||||
"""
|
"""
|
||||||
The image on the "canvas" is flushed through to the hardware display.
|
The image on the "canvas" is flushed through to the hardware display.
|
||||||
@ -118,10 +118,10 @@ class SSD1306Base(object):
|
|||||||
self.command(SSD1306_PAGEADDR)
|
self.command(SSD1306_PAGEADDR)
|
||||||
self.command(0) # Page start address. (0 = reset)
|
self.command(0) # Page start address. (0 = reset)
|
||||||
self.command(self._pages-1) # Page end address.
|
self.command(self._pages-1) # Page end address.
|
||||||
|
|
||||||
for i in range(0, len(self._buffer), 16):
|
for i in range(0, len(self._buffer), 16):
|
||||||
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
|
self.bus.write_i2c_block_data(self.addr, self.data_mode, self._buffer[i:i+16])
|
||||||
|
|
||||||
def getbuffer(self, image):
|
def getbuffer(self, image):
|
||||||
"""Set buffer to value of Python Imaging Library image. The image should
|
"""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.
|
be in 1 bit mode and a size equal to the display size.
|
||||||
|
@ -95,11 +95,8 @@ class ST7789(object):
|
|||||||
offset_left=0,
|
offset_left=0,
|
||||||
offset_top=0):
|
offset_top=0):
|
||||||
"""Create an instance of the display using SPI communication.
|
"""Create an instance of the display using SPI communication.
|
||||||
|
|
||||||
Must provide the GPIO pin number for the D/C pin and the SPI driver.
|
Must provide the GPIO pin number for the D/C pin and the SPI driver.
|
||||||
|
|
||||||
Can optionally provide the GPIO pin number for the reset pin as the rst parameter.
|
Can optionally provide the GPIO pin number for the reset pin as the rst parameter.
|
||||||
|
|
||||||
:param port: SPI port number
|
:param port: SPI port number
|
||||||
:param cs: SPI chip-select number (0 or 1 for BCM
|
:param cs: SPI chip-select number (0 or 1 for BCM
|
||||||
:param backlight: Pin for controlling backlight
|
:param backlight: Pin for controlling backlight
|
||||||
@ -109,7 +106,6 @@ class ST7789(object):
|
|||||||
:param rotation: Rotation of display connected to ST7789
|
:param rotation: Rotation of display connected to ST7789
|
||||||
:param invert: Invert display
|
:param invert: Invert display
|
||||||
:param spi_speed_hz: SPI speed (in Hz)
|
:param spi_speed_hz: SPI speed (in Hz)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if rotation not in [0, 90, 180, 270]:
|
if rotation not in [0, 90, 180, 270]:
|
||||||
raise ValueError("Invalid rotation {}".format(rotation))
|
raise ValueError("Invalid rotation {}".format(rotation))
|
||||||
@ -287,9 +283,7 @@ class ST7789(object):
|
|||||||
|
|
||||||
def begin(self):
|
def begin(self):
|
||||||
"""Set up the display
|
"""Set up the display
|
||||||
|
|
||||||
Deprecated. Included in __init__.
|
Deprecated. Included in __init__.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -326,9 +320,7 @@ class ST7789(object):
|
|||||||
|
|
||||||
def display(self, image):
|
def display(self, image):
|
||||||
"""Write the provided image to the hardware.
|
"""Write the provided image to the hardware.
|
||||||
|
|
||||||
:param image: Should be RGB format and the same dimensions as the display hardware.
|
:param image: Should be RGB format and the same dimensions as the display hardware.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Set address bounds to entire display.
|
# Set address bounds to entire display.
|
||||||
self.set_window()
|
self.set_window()
|
||||||
|
Reference in New Issue
Block a user