Merge pull request #234

Display update for 2.9.2 no AI
This commit is contained in:
Jayofelony
2024-12-01 12:53:22 +01:00
committed by GitHub
16 changed files with 316 additions and 131 deletions

View File

@ -1,12 +1,12 @@
# board GPIO:
# Key1:
# Key2:
# Key3:
# Key4:
#
# Key1: GPIO 16
# Key2: GPIO 20
# Key3: GPIO 21
# Key4: GPIO 26
# IR: GPIO 23
# Touch chipset:
# HW info: https://argon40.com/products/pod-display-2-8inch
# HW datasheet:
# HW MANUAL: https://cdn.shopify.com/s/files/1/0556/1660/2177/files/ARGON_POD_MANUAL.pdf?v=1668390711%0A
import logging
@ -44,6 +44,9 @@ class ArgonPod(DisplayImpl):
def initialize(self):
logging.info("Initializing Argon Pod display")
logging.info("Available pins for GPIO Buttons: 16, 20, 21, 26")
logging.info("IR available on GPIO 23")
logging.info("Backlight pin available on GPIO 18")
from pwnagotchi.ui.hw.libs.argon.argonpod.ILI9341 import ILI9341
self._display = ILI9341(0, 0, 22, 18)

View File

@ -1,9 +1,7 @@
import logging
import pwnagotchi.ui.fonts as fonts
from pwnagotchi.ui.hw.base import DisplayImpl
class DisplayHatMini(DisplayImpl):
def __init__(self, config):
super(DisplayHatMini, self).__init__(config, 'displayhatmini')
@ -29,11 +27,14 @@ class DisplayHatMini(DisplayImpl):
'font': fonts.status_font(fonts.Medium),
'max': 20
}
return self._layout
def initialize(self):
logging.info("initializing Display Hat Mini")
logging.info("Initializing Display Hat Mini")
logging.info("Available pins for GPIO Buttons A/B/X/Y: 5, 6, 16, 24")
logging.info("Available pins for RGB Led: 17, 27, 22")
logging.info("Backlight pin available on GPIO 13")
logging.info("I2C bus available on stemma QT and Breakout Garden headers")
from pwnagotchi.ui.hw.libs.pimoroni.displayhatmini.ST7789 import ST7789
self._display = ST7789(0,1,9,13)

View File

@ -8,7 +8,7 @@
# ui.display.blcolor = "olive"
#
# Contrast should be between 30-50, default is 40
# Backlight are predefined in the epd.py
# Backlight are predefined in the lcd.py
# Available backlight colors:
# white, grey, maroon, red, purple, fuchsia, green,
# lime, olive, yellow, navy, blue, teal, aqua
@ -48,10 +48,16 @@ class GfxHat(DisplayImpl):
def initialize(self):
contrast = self._config['contrast'] if 'contrast' in self._config else 40
blcolor = self._config['blcolor'] if 'blcolor' in self._config else 'OLIVE'
logging.info("initializing Pimoroni GfxHat")
logging.info("initializing Pimoroni GfxHat - Contrast: %d Backlight color: %s" % (contrast, blcolor))
from pwnagotchi.ui.hw.libs.pimoroni.gfxhat.epd import EPD
self._display = EPD(contrast=contrast)
logging.info("Initializing Pimoroni GfxHat - Contrast: %d Backlight color: %s" % (contrast, blcolor))
logging.info("Available config options: ui.display.contrast and ui.display.color")
logging.info("Contrast should be between 30-50, default is 40")
logging.info("Backlight are predefined in the lcd.py")
logging.info("Available backlight colors:")
logging.info("white, grey, maroon, red, purple, fuchsia, green,")
logging.info("lime, olive, yellow, navy, blue, teal, aqua")
logging.info("Touch control work in progress (6 touch buttons with short and long press and LED feedback)")
from pwnagotchi.ui.hw.libs.pimoroni.gfxhat.lcd import LCD
self._display = LCD(contrast=contrast)
self._display.Init(color_name=blcolor)
self._display.Clear()

View File

@ -52,11 +52,11 @@ class I2COled(DisplayImpl):
i2caddr = self._config['i2c_addr'] if 'i2c_addr' in self._config else 0x3C
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 SSD1306 based %dx%d I2C Oled Display on address 0x%X" % (width, height, i2caddr))
logging.info("Available config options: ui.display.width, ui.display.height and ui.display.i2caddr")
logging.info("initializing %dx%d I2C Oled Display on address 0x%X" % (width, height, i2caddr))
from pwnagotchi.ui.hw.libs.i2coled.epd import EPD
self._display = EPD(address=i2caddr, width=width, height=height)
from pwnagotchi.ui.hw.libs.i2coled.oled import OLED
self._display = OLED(address=i2caddr, width=width, height=height)
self._display.Init()
self._display.Clear()

View File

@ -9,7 +9,7 @@ EPD_HEIGHT = 64
# 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
class EPD(object):
class OLED(object):
def __init__(self, address=0x3C, width=EPD_WIDTH, height=EPD_HEIGHT):
self.width = width

View File

@ -9,7 +9,7 @@ LED_MAP = [2, 1, 0, 5, 4, 3]
def setup():
"""Set up the backlight on GFX HAT."""
global _sn3218
import sn3218 as _sn3218
from . import sn3218 as _sn3218
_sn3218.enable()
_sn3218.enable_leds(0b111111111111111111)

View File

@ -1,55 +0,0 @@
from . import st7567
from . import backlight
CONTRAST = 40
# Define RGB colors
WHITE = (255, 255, 255)
GREY = (255, 255, 255)
MAROON = (128, 0, 0)
RED = (255, 0, 0)
PURPLE = (128, 0, 128)
FUCHSIA = (255, 0, 255)
GREEN = (0, 128, 0)
LIME = (0, 255, 0)
OLIVE = (128, 128, 0)
YELLOW = (255, 255, 0)
NAVY = (0, 0, 128)
BLUE = (0, 0, 255)
TEAL = (0, 128, 128)
AQUA = (0, 255, 255)
# Map color names to RGB values
color_map = {
'WHITE': WHITE,
'GREY' : GREY,
'MAROON': MAROON,
'RED': RED,
'PURPLE': PURPLE,
'FUCHSIA': FUCHSIA,
'GREEN' : GREEN,
'LIME' : LIME,
'OLIVE' : OLIVE,
'YELLOW' : YELLOW,
'NAVY' : NAVY,
'BLUE' : BLUE,
'TEAL' : TEAL,
'AQUA' : AQUA
}
class EPD(object):
def __init__(self, contrast=CONTRAST, blcolor=('OLIVE')):
self.disp = st7567.ST7567()
self.disp.contrast(contrast)
def Init(self, color_name):
self.disp.setup()
blcolor = color_map.get(color_name.upper(), OLIVE) # Default to olive if color not found
backlight.set_all(*blcolor)
backlight.show()
def Clear(self):
self.disp.clear()
def Display(self, image):
self.disp.show(image)

View File

@ -1,57 +1,55 @@
"""Library for the GFX HAT ST7567 SPI LCD."""
from .st7567 import ST7567
from . import st7567
from . import backlight
CONTRAST = 40
st7567 = ST7567()
# Define RGB colors
WHITE = (255, 255, 255)
GREY = (255, 255, 255)
MAROON = (128, 0, 0)
RED = (255, 0, 0)
PURPLE = (128, 0, 128)
FUCHSIA = (255, 0, 255)
GREEN = (0, 128, 0)
LIME = (0, 255, 0)
OLIVE = (128, 128, 0)
YELLOW = (255, 255, 0)
NAVY = (0, 0, 128)
BLUE = (0, 0, 255)
TEAL = (0, 128, 128)
AQUA = (0, 255, 255)
dimensions = st7567.dimensions
# Map color names to RGB values
color_map = {
'WHITE': WHITE,
'GREY' : GREY,
'MAROON': MAROON,
'RED': RED,
'PURPLE': PURPLE,
'FUCHSIA': FUCHSIA,
'GREEN' : GREEN,
'LIME' : LIME,
'OLIVE' : OLIVE,
'YELLOW' : YELLOW,
'NAVY' : NAVY,
'BLUE' : BLUE,
'TEAL' : TEAL,
'AQUA' : AQUA
}
class LCD(object):
def clear():
"""Clear GFX HAT's display buffer."""
st7567.clear()
def __init__(self, contrast=CONTRAST, blcolor=('OLIVE')):
self.disp = st7567.ST7567()
self.disp.contrast(contrast)
def Init(self, color_name):
self.disp.setup()
blcolor = color_map.get(color_name.upper(), OLIVE) # Default to olive if color not found
backlight.set_all(*blcolor)
backlight.show()
def set_pixel(x, y, value):
"""Set a single pixel in GTX HAT's display buffer.
def Clear(self):
self.disp.clear()
:param x: X position (from 0 to 127)
:param y: Y position (from 0 to 63)
:param value: pixel state 1 = On, 0 = Off
"""
st7567.set_pixel(x, y, value)
def show():
"""Update GFX HAT with the current buffer contents."""
st7567.show()
def contrast(value):
"""Change GFX HAT LCD contrast."""
st7567.contrast(value)
def rotation(r=0):
"""Set the display rotation.
:param r: Specify the rotation in degrees: 0, or 180
"""
if r == 0:
st7567.rotated = False
elif r == 180:
st7567.rotated = True
else:
raise ValueError('Rotation must be 0 or 180 degrees')
def get_rotation():
"""Get the display rotation value.
Returns an integer, either 0, or 180
"""
return 180 if st7567.rotated else 0
def Display(self, image):
self.disp.show(image)

View File

@ -0,0 +1,214 @@
import sys
import warnings
__version__ = '1.2.7'
I2C_ADDRESS = 0x54
CMD_ENABLE_OUTPUT = 0x00
CMD_SET_PWM_VALUES = 0x01
CMD_ENABLE_LEDS = 0x13
CMD_UPDATE = 0x16
CMD_RESET = 0x17
if sys.version_info < (3, ):
SMBUS = "python-smbus"
else:
SMBUS = "python3-smbus"
# Helper function to avoid exception chaining output in python3.
# use exec to shield newer syntax from older python
if sys.version_info < (3, 3):
def _raise_from_none(exc):
raise exc
else:
exec("def _raise_from_none(exc): raise exc from None")
try:
from smbus import SMBus
except ImportError:
err_string = "This library requires {smbus}\nInstall with: sudo apt install {smbus}".format(smbus=SMBUS)
import_error = ImportError(err_string)
_raise_from_none(import_error)
def i2c_bus_id():
"""
Returns the i2c bus ID.
"""
with open('/proc/cpuinfo') as cpuinfo:
revision = [l[12:-1] for l in cpuinfo if l[:8] == "Revision"][0]
# https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
return 1 if int(revision, 16) >= 4 else 0
def enable():
"""
Enables output.
"""
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_ENABLE_OUTPUT, [0x01])
def disable():
"""
Disables output.
"""
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_ENABLE_OUTPUT, [0x00])
def reset():
"""
Resets all internal registers.
"""
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_RESET, [0xFF])
def enable_leds(enable_mask):
"""
Enables or disables each LED channel. The first 18 bit values are
used to determine the state of each channel (1=on, 0=off) if fewer
than 18 bits are provided the remaining channels are turned off.
Args:
enable_mask (int): up to 18 bits of data
Raises:
TypeError: if enable_mask is not an integer.
"""
if not isinstance(enable_mask, int):
raise TypeError("enable_mask must be an integer")
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_ENABLE_LEDS,
[enable_mask & 0x3F, (enable_mask >> 6) & 0x3F, (enable_mask >> 12) & 0X3F])
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_UPDATE, [0xFF])
def channel_gamma(channel, gamma_table):
"""
Overrides the gamma table for a single channel.
Args:
channel (int): channel number
gamma_table (list): list of 256 gamma correction values
Raises:
TypeError: if channel is not an integer.
ValueError: if channel is not in the range 0..17.
TypeError: if gamma_table is not a list.
"""
global channel_gamma_table
if not isinstance(channel, int):
raise TypeError("channel must be an integer")
if channel not in range(18):
raise ValueError("channel be an integer in the range 0..17")
if not isinstance(gamma_table, list) or len(gamma_table) != 256:
raise TypeError("gamma_table must be a list of 256 integers")
channel_gamma_table[channel] = gamma_table
def output(values):
"""
Outputs a new set of values to the driver.
Args:
values (list): channel number
Raises:
TypeError: if values is not a list of 18 integers.
"""
if not isinstance(values, list) or len(values) != 18:
raise TypeError("values must be a list of 18 integers")
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_SET_PWM_VALUES, [channel_gamma_table[i][values[i]] for i in range(18)])
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_UPDATE, [0xFF])
def output_raw(values):
"""
Outputs a new set of values to the driver.
Similar to output(), but does not use channel_gamma_table.
Args:
values (list): channel number
Raises:
TypeError: if values is not a list of 18 integers.
"""
# SMBus.write_i2c_block_data does the type check, so we don't have to
if len(values) != 18:
raise TypeError("values must be a list of 18 integers")
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_SET_PWM_VALUES, values)
i2c.write_i2c_block_data(I2C_ADDRESS, CMD_UPDATE, [0xFF])
try:
i2c = SMBus(i2c_bus_id())
except IOError as e:
warntxt="""
###### ###### ###### ###### ###### ###### ###### ######
i2c initialization failed - is i2c enabled on this system?
See https://github.com/pimoroni/sn3218/wiki/missing-i2c
###### ###### ###### ###### ###### ###### ###### ######
"""
warnings.warn(warntxt)
raise(e)
# generate a good default gamma table
default_gamma_table = [int(pow(255, float(i - 1) / 255)) for i in range(256)]
channel_gamma_table = [default_gamma_table] * 18
enable_leds(0b111111111111111111)
def test_cycles():
print("sn3218 test cycles")
import time
import math
# enable output
enable()
enable_leds(0b111111111111111111)
print(">> test enable mask (on/off)")
enable_mask = 0b000000000000000000
output([0x10] * 18)
for i in range(10):
enable_mask = ~enable_mask
enable_leds(enable_mask)
time.sleep(0.15)
print(">> test enable mask (odd/even)")
enable_mask = 0b101010101010101010
output([0x10] * 18)
for i in range(10):
enable_mask = ~enable_mask
enable_leds(enable_mask)
time.sleep(0.15)
print(">> test enable mask (rotate)")
enable_mask = 0b100000100000100000
output([0x10] * 18)
for i in range(10):
enable_mask = ((enable_mask & 0x01) << 18) | enable_mask >> 1
enable_leds(enable_mask)
time.sleep(0.15)
print(">> test gamma gradient")
enable_mask = 0b111111111111111111
enable_leds(enable_mask)
for i in range(256):
output([((j * (256//18)) + (i * (256//18))) % 256 for j in range(18)])
time.sleep(0.01)
print(">> test gamma fade")
enable_mask = 0b111111111111111111
enable_leds(enable_mask)
for i in range(512):
output([int((math.sin(float(i)/64.0) + 1.0) * 128.0)]*18)
time.sleep(0.01)
# turn everything off and disable output
output([0 for i in range(18)])
disable()
if __name__ == "__main__":
test_cycles()

View File

@ -1,6 +1,6 @@
# board GPIO:
# A: GPIO22
# B: GPIO23
# A: GPIO23
# B: GPIO24
#
# HW datasheet: https://learn.adafruit.com/adafruit-1-3-color-tft-bonnet-for-raspberry-pi/overview
@ -38,7 +38,10 @@ class MiniPitft(DisplayImpl):
return self._layout
def initialize(self):
logging.info("initializing Adafruit Mini Pi Tft 240x240")
logging.info("Initializing Adafruit Mini Pi Tft 240x240")
logging.info("Available pins for GPIO Buttons: 23, 24")
logging.info("Backlight pin available on GPIO 22")
logging.info("I2C bus available on stemma QT header")
from pwnagotchi.ui.hw.libs.adafruit.minipitft.ST7789 import ST7789
self._display = ST7789(0,0,25,22)

View File

@ -1,6 +1,6 @@
# board GPIO:
# A: GPIO22
# B: GPIO23
# A: GPIO23
# B: GPIO24
#
# HW datasheet: https://learn.adafruit.com/adafruit-1-3-color-tft-bonnet-for-raspberry-pi/overview
@ -39,6 +39,9 @@ class MiniPitft2(DisplayImpl):
def initialize(self):
logging.info("initializing Adafruit Mini Pi Tft 135x240")
logging.info("Available pins for GPIO Buttons: 23, 24")
logging.info("Backlight pin available on GPIO 22")
logging.info("I2C bus available on stemma QT header")
from pwnagotchi.ui.hw.libs.adafruit.minipitft2.ST7789 import ST7789
self._display = ST7789(0,0,25,22)

View File

@ -45,6 +45,10 @@ class PirateAudio(DisplayImpl):
def initialize(self):
logging.info("Initializing PirateAudio - display only")
logging.info("Available pins for GPIO Buttons A/B/X/Y: 5, 6, 16, 20 or 24")
logging.info("refer to the pimoroni site or pinout.xyz")
logging.info("Backlight pin available on GPIO 13")
logging.info("I2S for the DAC available on pins: 18, 19 and 21")
from pwnagotchi.ui.hw.libs.pimoroni.pirateaudio.ST7789 import ST7789
self._display = ST7789(0,1,9,13)

View File

@ -50,6 +50,9 @@ class Pitft(DisplayImpl):
def initialize(self):
logging.info("Initializing adafruit pitft 320x240 screen")
logging.info("Available pins for GPIO Buttons on the 3,2inch: 17, 22, 23, 27")
logging.info("Available pins for GPIO Buttons on the 2,8inch: 26, 13, 12, 6, 5")
logging.info("Backlight pin available on GPIO 18")
from pwnagotchi.ui.hw.libs.adafruit.pitft.ILI9341 import ILI9341
self._display = ILI9341(0, 0, 25, 18)

View File

@ -44,6 +44,9 @@ class TftBonnet(DisplayImpl):
def initialize(self):
logging.info("initializing Adafruit Tft Bonnet")
logging.info("Available pins for GPIO Buttons Up/Down/Left/Right/Center/A/B: 17, 22, 27, 23, 4, 5, 6")
logging.info("Backlight pin available on GPIO 26")
logging.info("I2C bus available on stemma QT header")
from pwnagotchi.ui.hw.libs.adafruit.tftbonnet.ST7789 import ST7789
self._display = ST7789(0,0,25,26)

View File

@ -49,6 +49,7 @@ class Waveshareoledlcd(DisplayImpl):
def initialize(self):
logging.info("initializing Waveshare OLED/LCD hat")
logging.info("Available pins for GPIO Buttons K1/K2/K3/K4: 4, 17, 23, 24")
from pwnagotchi.ui.hw.libs.waveshare.oled.oledlcd.ST7789 import ST7789
self._display = ST7789(0,0,22,18)

View File

@ -49,6 +49,7 @@ class Waveshareoledlcdvert(DisplayImpl):
def initialize(self):
logging.info("initializing Waveshare OLED/LCD hat vertical mode")
logging.info("Available pins for GPIO Buttons K1/K2/K3/K4: 4, 17, 23, 24")
from pwnagotchi.ui.hw.libs.waveshare.oled.oledlcd.ST7789vert import ST7789
self._display = ST7789(0,0,22,18)