Initial commit; Added previously untracked files.
This commit is contained in:
commit
131878133d
430
code.py
Normal file
430
code.py
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
import busio
|
||||||
|
import board
|
||||||
|
from board import *
|
||||||
|
from rainbowio import colorwheel
|
||||||
|
import waveshare_LCD1602
|
||||||
|
from digitalio import DigitalInOut, Direction, Pull
|
||||||
|
import time
|
||||||
|
import board
|
||||||
|
import usb_hid
|
||||||
|
from adafruit_hid.keyboard import Keyboard
|
||||||
|
from keyboard_layout_win_uk import KeyboardLayout
|
||||||
|
from keycode_win_uk import Keycode
|
||||||
|
"""Default I2C ports on boards that have one"""
|
||||||
|
i2c = busio.I2C(GP19, GP18)
|
||||||
|
|
||||||
|
buttonOne = DigitalInOut(board.GP0)
|
||||||
|
buttonOne.pull = Pull.UP
|
||||||
|
|
||||||
|
buttonTwo = DigitalInOut(board.GP1)
|
||||||
|
buttonTwo.pull = Pull.UP
|
||||||
|
|
||||||
|
buttonThree = DigitalInOut(board.GP2)
|
||||||
|
buttonThree.pull = Pull.UP
|
||||||
|
|
||||||
|
kbd = Keyboard(usb_hid.devices)
|
||||||
|
layout = KeyboardLayout(kbd)
|
||||||
|
|
||||||
|
|
||||||
|
lcd = waveshare_LCD1602.LCD1602(i2c, 16, 2)
|
||||||
|
lcd.setCursor(0,0)
|
||||||
|
|
||||||
|
|
||||||
|
def macro_parser(macroFileName=(str)):
|
||||||
|
|
||||||
|
file = open("macros/" + macroFileName, 'r')
|
||||||
|
|
||||||
|
clearScr = 1
|
||||||
|
lineToShow = ""
|
||||||
|
holdingKeys = 0
|
||||||
|
sendCombo = 0
|
||||||
|
keysToPress = []
|
||||||
|
for line in file:
|
||||||
|
print(line)
|
||||||
|
|
||||||
|
|
||||||
|
line = line.replace("\n", "")
|
||||||
|
workingLine = line
|
||||||
|
|
||||||
|
sleepingTime = 0
|
||||||
|
|
||||||
|
if line == "HOLD":
|
||||||
|
|
||||||
|
holdingKeys = 1
|
||||||
|
|
||||||
|
if line == "RELEASE":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
sendCombo = 1
|
||||||
|
|
||||||
|
if sendCombo == 1:
|
||||||
|
|
||||||
|
if len(keysToPress) == 1:
|
||||||
|
|
||||||
|
kbd.send(keysToPress[0])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
kbd.release_all()
|
||||||
|
|
||||||
|
elif len(keysToPress) == 2:
|
||||||
|
|
||||||
|
kbd.send(keysToPress[0], keysToPress[1])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
kbd.release_all()
|
||||||
|
|
||||||
|
elif len(keysToPress) == 3:
|
||||||
|
|
||||||
|
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
kbd.release_all()
|
||||||
|
|
||||||
|
elif len(keysToPress) == 4:
|
||||||
|
|
||||||
|
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
kbd.release_all()
|
||||||
|
|
||||||
|
elif len(keysToPress) == 5:
|
||||||
|
|
||||||
|
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3], keysToPress[4])
|
||||||
|
|
||||||
|
kbd.release_all()
|
||||||
|
|
||||||
|
elif len(keysToPress) == 6:
|
||||||
|
|
||||||
|
kbd.send(keysToPress[0], keysToPress[1], keysToPress[2], keysToPress[3], keysToPress[4], keysToPress[5])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
kbd.release_all()
|
||||||
|
|
||||||
|
sendCombo = 0
|
||||||
|
|
||||||
|
holdingKeys = 0
|
||||||
|
|
||||||
|
keysToPress = []
|
||||||
|
|
||||||
|
if line == "super":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.WINDOWS)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.WINDOWS)
|
||||||
|
|
||||||
|
if line == "escape":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.ESCAPE)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.ESCAPE)
|
||||||
|
|
||||||
|
if line == "tab":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.TAB)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.TAB)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if line == "windows":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.WINDOWS)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.WINDOWS)
|
||||||
|
|
||||||
|
if line == "ctrl":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.LEFT_CONTROL)
|
||||||
|
else:
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.LEFT_CONTROL)
|
||||||
|
|
||||||
|
|
||||||
|
if line == "shift":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.LEFT_SHIFT)
|
||||||
|
else:
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.LEFT_SHIFT)
|
||||||
|
|
||||||
|
if line.startswith("LCD_SHOW \""):
|
||||||
|
|
||||||
|
line = line.replace("LCD_SHOW \"", "\"")
|
||||||
|
|
||||||
|
line = line.replace('"', "")
|
||||||
|
|
||||||
|
lineToShow = line
|
||||||
|
|
||||||
|
clearScr = 0
|
||||||
|
|
||||||
|
if line.startswith("#"):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if line == "":
|
||||||
|
pass
|
||||||
|
|
||||||
|
if line.startswith("WAIT"):
|
||||||
|
|
||||||
|
line = line.replace("WAIT", "")
|
||||||
|
line = line.replace(" ", "")
|
||||||
|
|
||||||
|
sleepingTime = line
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
clearScr = 1
|
||||||
|
|
||||||
|
if line.startswith('"') and line.endswith('"'):
|
||||||
|
|
||||||
|
lineLength = len(line)
|
||||||
|
|
||||||
|
tempLine = ""
|
||||||
|
|
||||||
|
currentLine = line
|
||||||
|
|
||||||
|
for i in range(0, lineLength):
|
||||||
|
|
||||||
|
if i == 0:
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif i != (lineLength - 1):
|
||||||
|
|
||||||
|
tempLine = tempLine + currentLine[i]
|
||||||
|
|
||||||
|
line = tempLine
|
||||||
|
|
||||||
|
if holdingKeys == 0:
|
||||||
|
|
||||||
|
layout.write(line)
|
||||||
|
|
||||||
|
line = currentLine
|
||||||
|
|
||||||
|
if len(tempLine) == 1:
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(layout.keycodes(tempLine)[0])
|
||||||
|
|
||||||
|
|
||||||
|
if line == "downarrow":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.DOWN_ARROW)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.DOWN_ARROW)
|
||||||
|
|
||||||
|
|
||||||
|
elif line == "uparrow":
|
||||||
|
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.UP_ARROW)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.UP_ARROW)
|
||||||
|
|
||||||
|
|
||||||
|
elif line == "leftarrow":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.LEFT_ARROW)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.LEFT_ARROW)
|
||||||
|
elif line == "space":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.SPACE)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.SPACE)
|
||||||
|
|
||||||
|
elif line == "capslock":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.CAPS_LOCK)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.CAPS_LOCK)
|
||||||
|
|
||||||
|
|
||||||
|
elif line == "rightarrow":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.RIGHT_ARROW)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.RIGHT_ARROW)
|
||||||
|
|
||||||
|
elif line == "forwardslash":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.FORWARD_SLASH)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.FORWARD_SLASH)
|
||||||
|
|
||||||
|
|
||||||
|
elif line == "backslash":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.BACKSLASH)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.BACKSLASH)
|
||||||
|
|
||||||
|
elif line == "backspace":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.BACKSPACE)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.BACKSPACE)
|
||||||
|
|
||||||
|
|
||||||
|
elif line == "enter":
|
||||||
|
if holdingKeys == 1:
|
||||||
|
|
||||||
|
keysToPress.append(Keycode.ENTER)
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
kbd.send(Keycode.ENTER)
|
||||||
|
|
||||||
|
|
||||||
|
print("KEYS_PRESSED: " + str(len(keysToPress)))
|
||||||
|
|
||||||
|
if clearScr == 1 and workingLine.startswith("WAIT "):
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
lcd.setCursor(0,1)
|
||||||
|
lcd.printout("> "+workingLine)
|
||||||
|
lcd.setCursor(0,0)
|
||||||
|
lcd.printout(lineToShow)
|
||||||
|
print(lineToShow)
|
||||||
|
|
||||||
|
if lineToShow != "":
|
||||||
|
|
||||||
|
lineToShow = ""
|
||||||
|
else:
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
lcd.setCursor(0,1)
|
||||||
|
lcd.printout("> "+workingLine)
|
||||||
|
|
||||||
|
|
||||||
|
time.sleep(float(sleepingTime))
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
|
||||||
|
if not buttonOne.value:
|
||||||
|
lcd.clear()
|
||||||
|
lcd.setCursor(0,0)
|
||||||
|
lcd.printout("Install Arch")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
macro_parser("archinstall.mcr")
|
||||||
|
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
elif not buttonTwo.value:
|
||||||
|
lcd.clear()
|
||||||
|
lcd.setCursor(0,0)
|
||||||
|
lcd.printout("Macro Syntax")
|
||||||
|
time.sleep(1)
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
macro_parser("syntax.mcr")
|
||||||
|
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
elif not buttonThree.value:
|
||||||
|
lcd.clear()
|
||||||
|
lcd.setCursor(0,0)
|
||||||
|
lcd.printout("Test Macro")
|
||||||
|
time.sleep(1)
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
macro_parser("test.mcr")
|
||||||
|
|
||||||
|
|
||||||
|
lcd.clear()
|
||||||
|
|
||||||
|
lcd.setCursor(0,0)
|
||||||
|
|
||||||
|
lcd.printout("Kico v4")
|
||||||
|
|
||||||
|
lcd.setCursor(0,1)
|
||||||
|
|
||||||
|
lcd.printout("Hit a key!")
|
||||||
|
|
BIN
lib/adafruit_ahtx0.mpy
Normal file
BIN
lib/adafruit_ahtx0.mpy
Normal file
Binary file not shown.
0
lib/adafruit_bus_device/__init__.py
Normal file
0
lib/adafruit_bus_device/__init__.py
Normal file
BIN
lib/adafruit_bus_device/i2c_device.mpy
Normal file
BIN
lib/adafruit_bus_device/i2c_device.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_bus_device/spi_device.mpy
Normal file
BIN
lib/adafruit_bus_device/spi_device.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/__init__.mpy
Normal file
BIN
lib/adafruit_hid/__init__.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/consumer_control.mpy
Normal file
BIN
lib/adafruit_hid/consumer_control.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/consumer_control_code.mpy
Normal file
BIN
lib/adafruit_hid/consumer_control_code.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/keyboard.mpy
Normal file
BIN
lib/adafruit_hid/keyboard.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/keyboard_layout_base.mpy
Normal file
BIN
lib/adafruit_hid/keyboard_layout_base.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/keyboard_layout_us.mpy
Normal file
BIN
lib/adafruit_hid/keyboard_layout_us.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/keycode.mpy
Normal file
BIN
lib/adafruit_hid/keycode.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_hid/mouse.mpy
Normal file
BIN
lib/adafruit_hid/mouse.mpy
Normal file
Binary file not shown.
0
lib/adafruit_register/__init__.py
Normal file
0
lib/adafruit_register/__init__.py
Normal file
BIN
lib/adafruit_register/i2c_bcd_alarm.mpy
Normal file
BIN
lib/adafruit_register/i2c_bcd_alarm.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_register/i2c_bcd_datetime.mpy
Normal file
BIN
lib/adafruit_register/i2c_bcd_datetime.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_register/i2c_bit.mpy
Normal file
BIN
lib/adafruit_register/i2c_bit.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_register/i2c_bits.mpy
Normal file
BIN
lib/adafruit_register/i2c_bits.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_register/i2c_struct.mpy
Normal file
BIN
lib/adafruit_register/i2c_struct.mpy
Normal file
Binary file not shown.
BIN
lib/adafruit_register/i2c_struct_array.mpy
Normal file
BIN
lib/adafruit_register/i2c_struct_array.mpy
Normal file
Binary file not shown.
BIN
lib/keyboard_layout_win_uk.mpy
Normal file
BIN
lib/keyboard_layout_win_uk.mpy
Normal file
Binary file not shown.
BIN
lib/keycode_win_uk.mpy
Normal file
BIN
lib/keycode_win_uk.mpy
Normal file
Binary file not shown.
0
lib/lcd/__init__.py
Normal file
0
lib/lcd/__init__.py
Normal file
95
lib/lcd/i2c_pcf8574_interface.py
Normal file
95
lib/lcd/i2c_pcf8574_interface.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# Copyright (C) 2017 Dan Halbert
|
||||||
|
# Adapted from https://github.com/dbrgn/RPLCD, Copyright (C) 2013-2016 Danilo Bargen
|
||||||
|
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
# this software and associated documentation 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 furnished 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
|
||||||
|
# FOR 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.
|
||||||
|
|
||||||
|
"""Low-level interface to PCF8574."""
|
||||||
|
|
||||||
|
import busio
|
||||||
|
import board
|
||||||
|
import microcontroller
|
||||||
|
from adafruit_bus_device.i2c_device import I2CDevice
|
||||||
|
|
||||||
|
from .lcd import LCD_4BITMODE, LCD_BACKLIGHT, LCD_NOBACKLIGHT, PIN_ENABLE
|
||||||
|
|
||||||
|
|
||||||
|
class I2CPCF8574Interface:
|
||||||
|
|
||||||
|
# Bit values to turn backlight on/off. Indexed by a boolean.
|
||||||
|
_BACKLIGHT_VALUES = (LCD_NOBACKLIGHT, LCD_BACKLIGHT)
|
||||||
|
|
||||||
|
def __init__(self, i2c, address):
|
||||||
|
"""
|
||||||
|
CharLCD via PCF8574 I2C port expander.
|
||||||
|
|
||||||
|
Pin mapping::
|
||||||
|
|
||||||
|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
|
||||||
|
D7 | D6 | D5 | D4 | BL | EN | RW | RS
|
||||||
|
|
||||||
|
:param address: The I2C address of your LCD.
|
||||||
|
"""
|
||||||
|
self.address = address
|
||||||
|
|
||||||
|
self._backlight_pin_state = LCD_BACKLIGHT
|
||||||
|
|
||||||
|
self.i2c = i2c
|
||||||
|
self.i2c_device = I2CDevice(self.i2c, self.address)
|
||||||
|
self.data_buffer = bytearray(1)
|
||||||
|
|
||||||
|
def deinit(self):
|
||||||
|
self.i2c.deinit()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def data_bus_mode(self):
|
||||||
|
return LCD_4BITMODE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def backlight(self):
|
||||||
|
return self._backlight_pin_state == LCD_BACKLIGHT
|
||||||
|
|
||||||
|
@backlight.setter
|
||||||
|
def backlight(self, value):
|
||||||
|
self._backlight_pin_state = self._BACKLIGHT_VALUES[value]
|
||||||
|
with self.i2c_device:
|
||||||
|
self._i2c_write(self._backlight_pin_state)
|
||||||
|
|
||||||
|
# Low level commands
|
||||||
|
|
||||||
|
def send(self, value, rs_mode):
|
||||||
|
"""Send the specified value to the display in 4-bit nibbles.
|
||||||
|
The rs_mode is either ``_RS_DATA`` or ``_RS_INSTRUCTION``."""
|
||||||
|
self._write4bits(rs_mode | (value & 0xF0) | self._backlight_pin_state)
|
||||||
|
self._write4bits(rs_mode | ((value << 4) & 0xF0) | self._backlight_pin_state)
|
||||||
|
|
||||||
|
def _write4bits(self, value):
|
||||||
|
"""Pulse the `enable` flag to process value."""
|
||||||
|
with self.i2c_device:
|
||||||
|
self._i2c_write(value & ~PIN_ENABLE)
|
||||||
|
# This 1us delay is probably unnecessary, given the time needed
|
||||||
|
# to execute the statements.
|
||||||
|
microcontroller.delay_us(1)
|
||||||
|
self._i2c_write(value | PIN_ENABLE)
|
||||||
|
microcontroller.delay_us(1)
|
||||||
|
self._i2c_write(value & ~PIN_ENABLE)
|
||||||
|
# Wait for command to complete.
|
||||||
|
microcontroller.delay_us(100)
|
||||||
|
|
||||||
|
def _i2c_write(self, value):
|
||||||
|
self.data_buffer[0] = value
|
||||||
|
self.i2c_device.write(self.data_buffer)
|
289
lib/lcd/lcd.py
Normal file
289
lib/lcd/lcd.py
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
# Copyright (C) 2017 Dan Halbert
|
||||||
|
# Adapted from https://github.com/dbrgn/RPLCD, Copyright (C) 2013-2016 Danilo Bargen
|
||||||
|
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
# this software and associated documentation 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 furnished 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
|
||||||
|
# FOR 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 time
|
||||||
|
from micropython import const
|
||||||
|
|
||||||
|
# Commands
|
||||||
|
_LCD_CLEARDISPLAY = const(0x01)
|
||||||
|
_LCD_RETURNHOME = const(0x02)
|
||||||
|
_LCD_ENTRYMODESET = const(0x04)
|
||||||
|
_LCD_DISPLAYCONTROL = const(0x08)
|
||||||
|
_LCD_CURSORSHIFT = const(0x10)
|
||||||
|
_LCD_FUNCTIONSET = const(0x20)
|
||||||
|
_LCD_SETCGRAMADDR = const(0x40)
|
||||||
|
_LCD_SETDDRAMADDR = const(0x80)
|
||||||
|
|
||||||
|
# Flags for display entry mode
|
||||||
|
_LCD_ENTRYRIGHT = const(0x00)
|
||||||
|
_LCD_ENTRYLEFT = const(0x02)
|
||||||
|
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
|
||||||
|
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
|
||||||
|
|
||||||
|
# Flags for display on/off control
|
||||||
|
_LCD_DISPLAYON = const(0x04)
|
||||||
|
_LCD_DISPLAYOFF = const(0x00)
|
||||||
|
_LCD_CURSORON = const(0x02)
|
||||||
|
_LCD_CURSOROFF = const(0x00)
|
||||||
|
_LCD_BLINKON = const(0x01)
|
||||||
|
_LCD_BLINKOFF = const(0x00)
|
||||||
|
|
||||||
|
# Flags for display/cursor shift
|
||||||
|
_LCD_DISPLAYMOVE = const(0x08)
|
||||||
|
_LCD_CURSORMOVE = const(0x00)
|
||||||
|
_LCD_MOVERIGHT = const(0x04)
|
||||||
|
_LCD_MOVELEFT = const(0x00)
|
||||||
|
|
||||||
|
# Flags for function set
|
||||||
|
_LCD_8BITMODE = const(0x10)
|
||||||
|
LCD_4BITMODE = const(0x00)
|
||||||
|
_LCD_2LINE = const(0x08)
|
||||||
|
_LCD_1LINE = const(0x00)
|
||||||
|
_LCD_5x10DOTS = const(0x04)
|
||||||
|
_LCD_5x8DOTS = const(0x00)
|
||||||
|
|
||||||
|
# Flags for backlight control
|
||||||
|
LCD_BACKLIGHT = const(0x08)
|
||||||
|
LCD_NOBACKLIGHT = const(0x00)
|
||||||
|
|
||||||
|
# Flags for RS pin modes
|
||||||
|
_RS_INSTRUCTION = const(0x00)
|
||||||
|
_RS_DATA = const(0x01)
|
||||||
|
|
||||||
|
# Pin bitmasks
|
||||||
|
PIN_ENABLE = const(0x4)
|
||||||
|
PIN_READ_WRITE = const(0x2)
|
||||||
|
PIN_REGISTER_SELECT = const(0x1)
|
||||||
|
|
||||||
|
class CursorMode:
|
||||||
|
HIDE = const(_LCD_CURSOROFF | _LCD_BLINKOFF)
|
||||||
|
LINE = const(_LCD_CURSORON | _LCD_BLINKOFF)
|
||||||
|
BLINK = const(_LCD_CURSOROFF | _LCD_BLINKON)
|
||||||
|
|
||||||
|
MICROSECOND = 1e-6
|
||||||
|
MILLISECOND = 1e-3
|
||||||
|
|
||||||
|
class LCD(object):
|
||||||
|
|
||||||
|
def __init__(self, interface, num_cols=20, num_rows=4, char_height=8):
|
||||||
|
"""
|
||||||
|
Character LCD controller.
|
||||||
|
|
||||||
|
:param interface: Communication interface, such as I2CInterface
|
||||||
|
:param num_rows: Number of display rows (usually 1, 2 or 4). Default: 4.
|
||||||
|
:param num_cols: Number of columns per row (usually 16 or 20). Default 20.
|
||||||
|
:param char_height: Some 1 line displays allow a font height of 10px.
|
||||||
|
Allowed: 8 or 10. Default: 8.
|
||||||
|
"""
|
||||||
|
self.interface = interface
|
||||||
|
|
||||||
|
if char_height not in (8, 10):
|
||||||
|
raise ValueError('The ``char_height`` argument should be either 8 or 10.')
|
||||||
|
self.char_height = char_height
|
||||||
|
|
||||||
|
self.num_rows = num_rows
|
||||||
|
self.num_cols = num_cols
|
||||||
|
|
||||||
|
# get row addresses (varies based on display size)
|
||||||
|
self._row_offsets = (0x00, 0x40, self.num_cols, 0x40 + self.num_cols)
|
||||||
|
|
||||||
|
# Setup initial display configuration
|
||||||
|
displayfunction = self.interface.data_bus_mode | _LCD_5x8DOTS
|
||||||
|
if self.num_rows == 1:
|
||||||
|
displayfunction |= _LCD_1LINE
|
||||||
|
elif self.num_rows in (2, 4):
|
||||||
|
# LCD only uses two lines on 4 row displays
|
||||||
|
displayfunction |= _LCD_2LINE
|
||||||
|
if self.char_height == 10:
|
||||||
|
# For some 1 line displays you can select a 10px font.
|
||||||
|
displayfunction |= _LCD_5x10DOTS
|
||||||
|
|
||||||
|
# Choose 4 or 8 bit mode
|
||||||
|
self.command(0x03)
|
||||||
|
time.sleep(4.5*MILLISECOND)
|
||||||
|
self.command(0x03)
|
||||||
|
time.sleep(4.5*MILLISECOND)
|
||||||
|
self.command(0x03)
|
||||||
|
if self.interface.data_bus_mode == LCD_4BITMODE:
|
||||||
|
# Hitachi manual page 46
|
||||||
|
time.sleep(100*MICROSECOND)
|
||||||
|
self.command(0x02)
|
||||||
|
elif self.interface.data_bus_mode == _LCD_8BITMODE:
|
||||||
|
# Hitachi manual page 45
|
||||||
|
self.command(0x30)
|
||||||
|
time.sleep(4.5*MILLISECOND)
|
||||||
|
self.command(0x30)
|
||||||
|
time.sleep(100*MICROSECOND)
|
||||||
|
self.command(0x30)
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid data bus mode: {}'.format(self.interface.data_bus_mode))
|
||||||
|
|
||||||
|
# Write configuration to display
|
||||||
|
self.command(_LCD_FUNCTIONSET | displayfunction)
|
||||||
|
time.sleep(50*MICROSECOND)
|
||||||
|
|
||||||
|
# Configure entry mode. Define internal fields.
|
||||||
|
self.command(_LCD_ENTRYMODESET | _LCD_ENTRYLEFT)
|
||||||
|
time.sleep(50*MICROSECOND)
|
||||||
|
|
||||||
|
# Configure display mode. Define internal fields.
|
||||||
|
self._display_mode = _LCD_DISPLAYON
|
||||||
|
self._cursor_mode = CursorMode.HIDE
|
||||||
|
self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode)
|
||||||
|
time.sleep(50*MICROSECOND)
|
||||||
|
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self.interface.deinit()
|
||||||
|
|
||||||
|
def set_backlight(self, value):
|
||||||
|
self.interface.backlight = value
|
||||||
|
|
||||||
|
def set_display_enabled(self, value):
|
||||||
|
self._display_mode = _LCD_DISPLAYON if value else _LCD_DISPLAYOFF
|
||||||
|
self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode)
|
||||||
|
time.sleep(50*MICROSECOND)
|
||||||
|
|
||||||
|
def set_cursor_mode(self, value):
|
||||||
|
self._cursor_mode = value
|
||||||
|
self.command(_LCD_DISPLAYCONTROL | self._display_mode | self._cursor_mode)
|
||||||
|
time.sleep(50*MICROSECOND)
|
||||||
|
|
||||||
|
def cursor_pos(self):
|
||||||
|
"""The cursor position as a 2-tuple (row, col)."""
|
||||||
|
return (self._row, self._col)
|
||||||
|
|
||||||
|
def set_cursor_pos(self, row, col):
|
||||||
|
if not (0 <= row < self.num_rows):
|
||||||
|
raise ValueError('row should be in range 0-{}'.format(self.num_rows - 1))
|
||||||
|
if not (0 <= col < self.num_cols):
|
||||||
|
raise ValueError('col should be in range 0-{}'.format(self.num_cols - 1))
|
||||||
|
self._row = row
|
||||||
|
self._col = col
|
||||||
|
self.command(_LCD_SETDDRAMADDR | self._row_offsets[row] + col)
|
||||||
|
time.sleep(50*MICROSECOND)
|
||||||
|
|
||||||
|
def print(self, string):
|
||||||
|
"""
|
||||||
|
Write the specified unicode string to the display.
|
||||||
|
A newline ('\n') will advance to the left side of the next row.
|
||||||
|
Lines that are too long automatically continue on next line.
|
||||||
|
|
||||||
|
Only characters with an ``ord()`` value between 0 and 255 are currently
|
||||||
|
supported.
|
||||||
|
|
||||||
|
"""
|
||||||
|
for char in string:
|
||||||
|
if char == '\n':
|
||||||
|
# Advance to next row, at left side. Wrap around to top row if at bottom.
|
||||||
|
self.set_cursor_pos((self._row + 1) % self.num_rows, 0)
|
||||||
|
else:
|
||||||
|
self.write(ord(char))
|
||||||
|
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Overwrite display with blank characters and reset cursor position."""
|
||||||
|
self.command(_LCD_CLEARDISPLAY)
|
||||||
|
time.sleep(2*MILLISECOND)
|
||||||
|
self.home()
|
||||||
|
|
||||||
|
def home(self):
|
||||||
|
"""Set cursor to initial position and reset any shifting."""
|
||||||
|
self.command(_LCD_RETURNHOME)
|
||||||
|
self._row = 0
|
||||||
|
self._col = 0
|
||||||
|
time.sleep(2*MILLISECOND)
|
||||||
|
|
||||||
|
def shift_display(self, amount):
|
||||||
|
"""Shift the display. Use negative amounts to shift left and positive
|
||||||
|
amounts to shift right."""
|
||||||
|
if amount == 0:
|
||||||
|
return
|
||||||
|
direction = _LCD_MOVERIGHT if amount > 0 else _LCD_MOVELEFT
|
||||||
|
for i in range(abs(amount)):
|
||||||
|
self.command(_LCD_CURSORSHIFT | _LCD_DISPLAYMOVE | direction)
|
||||||
|
time.sleep(50*MICROSECOND)
|
||||||
|
|
||||||
|
def create_char(self, location, bitmap):
|
||||||
|
"""Create a new character.
|
||||||
|
|
||||||
|
The HD44780 supports up to 8 custom characters (location 0-7).
|
||||||
|
|
||||||
|
:param location: The place in memory where the character is stored.
|
||||||
|
Values need to be integers between 0 and 7.
|
||||||
|
:type location: int
|
||||||
|
:param bitmap: The bitmap containing the character. This should be a
|
||||||
|
bytearray of 8 numbers, each representing a 5 pixel row.
|
||||||
|
:type bitmap: bytearray
|
||||||
|
:raises AssertionError: Raised when an invalid location is passed in or
|
||||||
|
when bitmap has an incorrect size.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. sourcecode:: python
|
||||||
|
|
||||||
|
>>> smiley = bytearray(
|
||||||
|
... 0b00000,
|
||||||
|
... 0b01010,
|
||||||
|
... 0b01010,
|
||||||
|
... 0b00000,
|
||||||
|
... 0b10001,
|
||||||
|
... 0b10001,
|
||||||
|
... 0b01110,
|
||||||
|
... 0b00000,
|
||||||
|
... )
|
||||||
|
>>> lcd.create_char(0, smiley)
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not (0 <= location <= 7):
|
||||||
|
raise ValueError('Only locations 0-7 are valid.')
|
||||||
|
if len(bitmap) != 8:
|
||||||
|
raise ValueError('Bitmap should have exactly 8 rows.')
|
||||||
|
|
||||||
|
# Store previous position
|
||||||
|
save_row = self._row
|
||||||
|
save_col = self._col
|
||||||
|
|
||||||
|
# Write character to CGRAM
|
||||||
|
self.command(_LCD_SETCGRAMADDR | location << 3)
|
||||||
|
for row in bitmap:
|
||||||
|
self.interface.send(row, _RS_DATA)
|
||||||
|
|
||||||
|
# Restore cursor pos
|
||||||
|
self.set_cursor_pos(save_row, save_col)
|
||||||
|
|
||||||
|
def command(self, value):
|
||||||
|
"""Send a raw command to the LCD."""
|
||||||
|
self.interface.send(value, _RS_INSTRUCTION)
|
||||||
|
|
||||||
|
def write(self, value):
|
||||||
|
"""Write a raw character byte to the LCD."""
|
||||||
|
self.interface.send(value, _RS_DATA)
|
||||||
|
if self._col < self.num_cols - 1:
|
||||||
|
# Char was placed on current line. No need to reposition cursor.
|
||||||
|
self._col += 1
|
||||||
|
else:
|
||||||
|
# At end of line: go to left side next row. Wrap around to first row if on last row.
|
||||||
|
self._row = (self._row + 1) % self.num_rows
|
||||||
|
self._col = 0
|
||||||
|
|
||||||
|
self.set_cursor_pos(self._row, self._col)
|
||||||
|
|
1
lib/rgb1602/__init__.py
Normal file
1
lib/rgb1602/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from rgb1602.display import Screen
|
164
lib/rgb1602/colours.py
Normal file
164
lib/rgb1602/colours.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
CSS_COLOURS: dict[str, tuple[int, int, int]] = {
|
||||||
|
"aliceblue": (240, 248, 255),
|
||||||
|
"antiquewhite": (250, 235, 215),
|
||||||
|
"aqua": (0, 255, 255),
|
||||||
|
"aquamarine": (127, 255, 212),
|
||||||
|
"azure": (240, 255, 255),
|
||||||
|
"beige": (245, 245, 220),
|
||||||
|
"bisque": (255, 228, 196),
|
||||||
|
"black": (0, 0, 0),
|
||||||
|
"blanchedalmond": (255, 235, 205),
|
||||||
|
"blue": (0, 0, 255),
|
||||||
|
"blueviolet": (138, 43, 226),
|
||||||
|
"brown": (165, 42, 42),
|
||||||
|
"burlywood": (222, 184, 135),
|
||||||
|
"cadetblue": (95, 158, 160),
|
||||||
|
"chartreuse": (127, 255, 0),
|
||||||
|
"chocolate": (210, 105, 30),
|
||||||
|
"coral": (255, 127, 80),
|
||||||
|
"cornflowerblue": (100, 149, 237),
|
||||||
|
"cornsilk": (255, 248, 220),
|
||||||
|
"crimson": (220, 20, 60),
|
||||||
|
"cyan": (0, 255, 255),
|
||||||
|
"darkblue": (0, 0, 139),
|
||||||
|
"darkcyan": (0, 139, 139),
|
||||||
|
"darkgoldenrod": (184, 134, 11),
|
||||||
|
"darkgray": (169, 169, 169),
|
||||||
|
"darkgreen": (0, 100, 0),
|
||||||
|
"darkgrey": (169, 169, 169),
|
||||||
|
"darkkhaki": (189, 183, 107),
|
||||||
|
"darkmagenta": (139, 0, 139),
|
||||||
|
"darkolivegreen": (85, 107, 47),
|
||||||
|
"darkorange": (255, 140, 0),
|
||||||
|
"darkorchid": (153, 50, 204),
|
||||||
|
"darkred": (139, 0, 0),
|
||||||
|
"darksalmon": (233, 150, 122),
|
||||||
|
"darkseagreen": (143, 188, 143),
|
||||||
|
"darkslateblue": (72, 61, 139),
|
||||||
|
"darkslategray": (47, 79, 79),
|
||||||
|
"darkslategrey": (47, 79, 79),
|
||||||
|
"darkturquoise": (0, 206, 209),
|
||||||
|
"darkviolet": (148, 0, 211),
|
||||||
|
"deeppink": (255, 20, 147),
|
||||||
|
"deepskyblue": (0, 191, 255),
|
||||||
|
"dimgray": (105, 105, 105),
|
||||||
|
"dimgrey": (105, 105, 105),
|
||||||
|
"dodgerblue": (30, 144, 255),
|
||||||
|
"firebrick": (178, 34, 34),
|
||||||
|
"floralwhite": (255, 250, 240),
|
||||||
|
"forestgreen": (34, 139, 34),
|
||||||
|
"fuchsia": (255, 0, 255),
|
||||||
|
"gainsboro": (220, 220, 220),
|
||||||
|
"ghostwhite": (248, 248, 255),
|
||||||
|
"gold": (255, 215, 0),
|
||||||
|
"goldenrod": (218, 165, 32),
|
||||||
|
"gray": (128, 128, 128),
|
||||||
|
"green": (0, 128, 0),
|
||||||
|
"greenyellow": (173, 255, 47),
|
||||||
|
"grey": (128, 128, 128),
|
||||||
|
"honeydew": (240, 255, 240),
|
||||||
|
"hotpink": (255, 105, 180),
|
||||||
|
"indianred": (205, 92, 92),
|
||||||
|
"indigo": (75, 0, 130),
|
||||||
|
"ivory": (255, 255, 240),
|
||||||
|
"khaki": (240, 230, 140),
|
||||||
|
"lavender": (230, 230, 250),
|
||||||
|
"lavenderblush": (255, 240, 245),
|
||||||
|
"lawngreen": (124, 252, 0),
|
||||||
|
"lemonchiffon": (255, 250, 205),
|
||||||
|
"lightblue": (173, 216, 230),
|
||||||
|
"lightcoral": (240, 128, 128),
|
||||||
|
"lightcyan": (224, 255, 255),
|
||||||
|
"lightgoldenrodyellow": (250, 250, 210),
|
||||||
|
"lightgray": (211, 211, 211),
|
||||||
|
"lightgreen": (144, 238, 144),
|
||||||
|
"lightgrey": (211, 211, 211),
|
||||||
|
"lightpink": (255, 182, 193),
|
||||||
|
"lightsalmon": (255, 160, 122),
|
||||||
|
"lightseagreen": (32, 178, 170),
|
||||||
|
"lightskyblue": (135, 206, 250),
|
||||||
|
"lightslategray": (119, 136, 153),
|
||||||
|
"lightslategrey": (119, 136, 153),
|
||||||
|
"lightsteelblue": (176, 196, 222),
|
||||||
|
"lightyellow": (255, 255, 224),
|
||||||
|
"lime": (0, 255, 0),
|
||||||
|
"limegreen": (50, 205, 50),
|
||||||
|
"linen": (250, 240, 230),
|
||||||
|
"magenta": (255, 0, 255),
|
||||||
|
"maroon": (128, 0, 0),
|
||||||
|
"mediumaquamarine": (102, 205, 170),
|
||||||
|
"mediumblue": (0, 0, 205),
|
||||||
|
"mediumorchid": (186, 85, 211),
|
||||||
|
"mediumpurple": (147, 112, 219),
|
||||||
|
"mediumseagreen": (60, 179, 113),
|
||||||
|
"mediumslateblue": (123, 104, 238),
|
||||||
|
"mediumspringgreen": (0, 250, 154),
|
||||||
|
"mediumturquoise": (72, 209, 204),
|
||||||
|
"mediumvioletred": (199, 21, 133),
|
||||||
|
"midnightblue": (25, 25, 112),
|
||||||
|
"mintcream": (245, 255, 250),
|
||||||
|
"mistyrose": (255, 228, 225),
|
||||||
|
"moccasin": (255, 228, 181),
|
||||||
|
"navajowhite": (255, 222, 173),
|
||||||
|
"navy": (0, 0, 128),
|
||||||
|
"oldlace": (253, 245, 230),
|
||||||
|
"olive": (128, 128, 0),
|
||||||
|
"olivedrab": (107, 142, 35),
|
||||||
|
"orange": (255, 165, 0),
|
||||||
|
"orangered": (255, 69, 0),
|
||||||
|
"orchid": (218, 112, 214),
|
||||||
|
"palegoldenrod": (238, 232, 170),
|
||||||
|
"palegreen": (152, 251, 152),
|
||||||
|
"paleturquoise": (175, 238, 238),
|
||||||
|
"palevioletred": (219, 112, 147),
|
||||||
|
"papayawhip": (255, 239, 213),
|
||||||
|
"peachpuff": (255, 218, 185),
|
||||||
|
"peru": (205, 133, 63),
|
||||||
|
"pink": (255, 192, 203),
|
||||||
|
"plum": (221, 160, 221),
|
||||||
|
"powderblue": (176, 224, 230),
|
||||||
|
"purple": (128, 0, 128),
|
||||||
|
"rebeccapurple": (102, 51, 153),
|
||||||
|
"red": (255, 0, 0),
|
||||||
|
"rosybrown": (188, 143, 143),
|
||||||
|
"royalblue": (65, 105, 225),
|
||||||
|
"saddlebrown": (139, 69, 19),
|
||||||
|
"salmon": (250, 128, 114),
|
||||||
|
"sandybrown": (244, 164, 96),
|
||||||
|
"seagreen": (46, 139, 87),
|
||||||
|
"seashell": (255, 245, 238),
|
||||||
|
"sienna": (160, 82, 45),
|
||||||
|
"silver": (192, 192, 192),
|
||||||
|
"skyblue": (135, 206, 235),
|
||||||
|
"slateblue": (106, 90, 205),
|
||||||
|
"slategray": (112, 128, 144),
|
||||||
|
"slategrey": (112, 128, 144),
|
||||||
|
"snow": (255, 250, 250),
|
||||||
|
"springgreen": (0, 255, 127),
|
||||||
|
"steelblue": (70, 130, 180),
|
||||||
|
"tan": (210, 180, 140),
|
||||||
|
"teal": (0, 128, 128),
|
||||||
|
"thistle": (216, 191, 216),
|
||||||
|
"tomato": (255, 99, 71),
|
||||||
|
"turquoise": (64, 224, 208),
|
||||||
|
"violet": (238, 130, 238),
|
||||||
|
"wheat": (245, 222, 179),
|
||||||
|
"white": (255, 255, 255),
|
||||||
|
"whitesmoke": (245, 245, 245),
|
||||||
|
"yellow": (255, 255, 0),
|
||||||
|
"yellowgreen": (154, 205, 50),
|
||||||
|
}
|
||||||
|
CSS_COLORS = CSS_COLOURS
|
||||||
|
|
||||||
|
WAVESHARE_COLOURS = {
|
||||||
|
"Deep violet": (148, 0, 110),
|
||||||
|
"Purple": (255, 0, 255),
|
||||||
|
"Blue and white": (144, 249, 15),
|
||||||
|
"Light blue": (0, 128, 60),
|
||||||
|
"Yellow": (255, 209, 0),
|
||||||
|
"Ghost white": (248, 248, 60),
|
||||||
|
"Dark blue": (80, 80, 145),
|
||||||
|
"Red": (255, 0, 0),
|
||||||
|
"Cyan": (0, 255, 0),
|
||||||
|
}
|
||||||
|
WAVESHARE_COLORS = WAVESHARE_COLOURS
|
307
lib/rgb1602/display.py
Normal file
307
lib/rgb1602/display.py
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
# This file converted from MicroPython to CircuitPython
|
||||||
|
# by robjwells. Original copyright Waveshare.
|
||||||
|
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from adafruit_bus_device.i2c_device import I2CDevice
|
||||||
|
from adafruit_register.i2c_struct import UnaryStruct
|
||||||
|
from busio import I2C
|
||||||
|
from microcontroller import Pin
|
||||||
|
|
||||||
|
from rgb1602.colours import CSS_COLOURS
|
||||||
|
|
||||||
|
|
||||||
|
class Constants:
|
||||||
|
# Device I2C Addresses
|
||||||
|
LCD_ADDRESS = 0x7C >> 1
|
||||||
|
RGB_ADDRESS = 0x3e >> 1
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
# CGRAM and DDRAM commands but also their memory addresses
|
||||||
|
LCD_COMMAND_REG = 0x80
|
||||||
|
LCD_SETDDRAMADDR = 0x80 # 0b1_______ Display Data RAM
|
||||||
|
LCD_SETCGRAMADDR = 0x40 # 0b_1______ Character Generator RAM
|
||||||
|
LCD_DATA_REG = 0x40
|
||||||
|
|
||||||
|
# RGB registers
|
||||||
|
REG_RED = 0x04 # 0b_1__ pwm2
|
||||||
|
REG_GREEN = 0x03 # 0b__11 pwm1
|
||||||
|
REG_BLUE = 0x02 # 0b__1_ pwm0
|
||||||
|
|
||||||
|
REG_MODE1 = 0x00 # 0b____
|
||||||
|
REG_MODE2 = 0x01 # 0b___1
|
||||||
|
REG_OUTPUT = 0x08 # 0b1___
|
||||||
|
|
||||||
|
# Commands -- bits of an 8-bit word
|
||||||
|
LCD_CLEARDISPLAY = 0x01 # 0b_______1
|
||||||
|
LCD_RETURNHOME = 0x02 # 0b______1_
|
||||||
|
|
||||||
|
LCD_ENTRYMODESET = 0x04 # 0b_____1__
|
||||||
|
# Used with bits I/D SH:
|
||||||
|
# I/D: 0x02 for entry left, 0x00 for entry right
|
||||||
|
# SH: 0x01 for shift increment, 0x00 for decrement
|
||||||
|
# See "flags for display entry mode"
|
||||||
|
|
||||||
|
LCD_DISPLAYCONTROL = 0x08 # 0b____1___
|
||||||
|
# Used with bits DCB:
|
||||||
|
# D: display on/off,
|
||||||
|
# C: cursor on/off,
|
||||||
|
# B: blink cursor on/off
|
||||||
|
# These are listed below as "flags for display on/off control"
|
||||||
|
|
||||||
|
LCD_CURSORSHIFT = 0x10 # 0b___1____
|
||||||
|
# Cursor or Display Shift
|
||||||
|
# Uses bits S/C R/L - -:
|
||||||
|
# S/C: 0x08 for screen or 0x00 for cursor
|
||||||
|
# R/L: 0x04 for right or 0x00 for left
|
||||||
|
|
||||||
|
LCD_FUNCTIONSET = 0x20 # 0b__1_____
|
||||||
|
# Sets number of display lines, and display font type.
|
||||||
|
# The documentation doesn't mention 8/4 bit mode.
|
||||||
|
|
||||||
|
# flags for display entry mode
|
||||||
|
LCD_ENTRYRIGHT = 0x00 # 0b00
|
||||||
|
LCD_ENTRYLEFT = 0x02 # 0b10
|
||||||
|
LCD_ENTRYSHIFTINCREMENT = 0x01 # 0b01
|
||||||
|
LCD_ENTRYSHIFTDECREMENT = 0x00 # 0b00
|
||||||
|
|
||||||
|
# flags for display on/off control
|
||||||
|
LCD_DISPLAYON = 0x04 # 0b1__
|
||||||
|
LCD_CURSORON = 0x02 # 0b_1_
|
||||||
|
LCD_BLINKON = 0x01 # 0b__1
|
||||||
|
|
||||||
|
LCD_DISPLAYOFF = 0x00 # 0b000
|
||||||
|
LCD_CURSOROFF = 0x00 # 0b000
|
||||||
|
LCD_BLINKOFF = 0x00 # 0b000
|
||||||
|
|
||||||
|
# flags for display/cursor shift
|
||||||
|
LCD_DISPLAYMOVE = 0x08 # 0b1000
|
||||||
|
LCD_CURSORMOVE = 0x00 # 0b0000
|
||||||
|
LCD_MOVERIGHT = 0x04 # 0b0100
|
||||||
|
LCD_MOVELEFT = 0x00 # 0b0000
|
||||||
|
|
||||||
|
# flags for function set
|
||||||
|
|
||||||
|
# I think the modes relate the to the number of bits
|
||||||
|
# sent down the wire at a time, _not_ the colour
|
||||||
|
# depth (as I thought originally).
|
||||||
|
LCD_8BITMODE = 0x10 # 0b10000
|
||||||
|
LCD_4BITMODE = 0x00 # 0b00000
|
||||||
|
|
||||||
|
# Number of lines on the display
|
||||||
|
LCD_2LINE = 0x08 # 0b01000
|
||||||
|
LCD_1LINE = 0x00 # 0b00000
|
||||||
|
LCD_5x8DOTS = 0x00 # 0b00000
|
||||||
|
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
class LCDControl:
|
||||||
|
def __init__(self, i2c: I2CDevice):
|
||||||
|
self.i2c_device = i2c # Required by UnaryStruct
|
||||||
|
|
||||||
|
command_register = UnaryStruct(Constants.LCD_COMMAND_REG, "<B")
|
||||||
|
data_register = UnaryStruct(Constants.LCD_DATA_REG, "<B")
|
||||||
|
|
||||||
|
|
||||||
|
class RGBControl:
|
||||||
|
def __init__(self, i2c: I2CDevice) -> None:
|
||||||
|
self.i2c_device = i2c
|
||||||
|
|
||||||
|
REG_RED = UnaryStruct(Constants.REG_RED, "<B")
|
||||||
|
REG_GREEN = UnaryStruct(Constants.REG_GREEN, "<B")
|
||||||
|
REG_BLUE = UnaryStruct(Constants.REG_BLUE, "<B")
|
||||||
|
|
||||||
|
REG_MODE1 = UnaryStruct(Constants.REG_MODE1, "<B")
|
||||||
|
REG_MODE2 = UnaryStruct(Constants.REG_MODE2, "<B")
|
||||||
|
REG_OUTPUT = UnaryStruct(Constants.REG_OUTPUT, "<B")
|
||||||
|
|
||||||
|
|
||||||
|
class Screen:
|
||||||
|
# Set dimensions as class variables.
|
||||||
|
# Hint is in the module name (LCD1602)!
|
||||||
|
COLS = 16
|
||||||
|
ROWS = 2
|
||||||
|
|
||||||
|
current_colour: tuple[int, int, int]
|
||||||
|
|
||||||
|
_i2c: I2C
|
||||||
|
_lcd: LCDControl
|
||||||
|
_rgb: RGBControl
|
||||||
|
|
||||||
|
def __init__(self, i2c_bus: I2C):
|
||||||
|
self._i2c = i2c_bus
|
||||||
|
self._lcd = LCDControl(I2CDevice(self._i2c, Constants.LCD_ADDRESS))
|
||||||
|
self._rgb = RGBControl(I2CDevice(self._i2c, Constants.RGB_ADDRESS))
|
||||||
|
self._reset_display()
|
||||||
|
|
||||||
|
def _reset_display(self):
|
||||||
|
"""Initialise the display to its standard settings.
|
||||||
|
|
||||||
|
It is unclear to me (rjw) why some of these are necessary, as
|
||||||
|
there seems to be no difference in removing some of the below.
|
||||||
|
*However* I have not removed what remains because it wasn't
|
||||||
|
*obviously unnecessary*, unlike the now-removed lines.
|
||||||
|
"""
|
||||||
|
# Send function set command sequence
|
||||||
|
show_function = (
|
||||||
|
Constants.LCD_4BITMODE | Constants.LCD_2LINE | Constants.LCD_5x8DOTS
|
||||||
|
)
|
||||||
|
self._command(Constants.LCD_FUNCTIONSET | show_function)
|
||||||
|
sleep(0.05)
|
||||||
|
|
||||||
|
# turn the display on with no cursor or blinking default
|
||||||
|
show_control = (
|
||||||
|
Constants.LCD_DISPLAYON | Constants.LCD_CURSOROFF | Constants.LCD_BLINKOFF
|
||||||
|
)
|
||||||
|
self._command(Constants.LCD_DISPLAYCONTROL | show_control)
|
||||||
|
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
# Initialize to default text direction (for romance languages)
|
||||||
|
self._showmode = Constants.LCD_ENTRYLEFT | Constants.LCD_ENTRYSHIFTDECREMENT
|
||||||
|
self._command(Constants.LCD_ENTRYMODESET | self._showmode)
|
||||||
|
|
||||||
|
# backlight init
|
||||||
|
self._set_rgb_register("REG_MODE1", 0)
|
||||||
|
# set LEDs controllable by both PWM and GRPPWM registers
|
||||||
|
self._set_rgb_register("REG_OUTPUT", 0xFF)
|
||||||
|
# set MODE2 values
|
||||||
|
# 0010 0000 -> 0x20 (DMBLNK to 1, ie blinky mode)
|
||||||
|
self._set_rgb_register("REG_MODE2", 0x20)
|
||||||
|
self.set_white()
|
||||||
|
|
||||||
|
def _command(self, cmd: int):
|
||||||
|
assert 0 <= cmd <= 255, f"Command {cmd} out of range."
|
||||||
|
self._lcd.command_register = cmd
|
||||||
|
|
||||||
|
def _write_byte(self, data: int) -> None:
|
||||||
|
assert 0 <= data <= 255, f"Command {data} out of range."
|
||||||
|
self._lcd.data_register = data
|
||||||
|
|
||||||
|
def _set_rgb_register(self, reg: str, data: int) -> None:
|
||||||
|
assert reg in (
|
||||||
|
"REG_RED",
|
||||||
|
"REG_BLUE",
|
||||||
|
"REG_GREEN",
|
||||||
|
"REG_MODE1",
|
||||||
|
"REG_MODE2",
|
||||||
|
"REG_OUTPUT",
|
||||||
|
), f"Register {reg} is not a known register."
|
||||||
|
assert 0 <= data <= 255, f"Data {data} is out of range."
|
||||||
|
setattr(self._rgb, reg, data)
|
||||||
|
|
||||||
|
def _set_rgb_mode(self, mode: int, value: int) -> None:
|
||||||
|
assert 0 <= value <= 0xFF, "Value not in range."
|
||||||
|
if mode == 1:
|
||||||
|
self._set_rgb_register("REG_MODE1", value)
|
||||||
|
elif mode == 2:
|
||||||
|
self._set_rgb_register("REG_MODE2", value)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unknown mode: {repr(mode)}")
|
||||||
|
|
||||||
|
def set_rgb(self, r: int, g: int, b: int):
|
||||||
|
assert 0 <= r <= 255, f"Red value {r} out of range."
|
||||||
|
assert 0 <= g <= 255, f"Green value {g} out of range."
|
||||||
|
assert 0 <= b <= 255, f"Blue value {b} out of range."
|
||||||
|
|
||||||
|
self._set_rgb_register("REG_RED", r)
|
||||||
|
self._set_rgb_register("REG_GREEN", g)
|
||||||
|
self._set_rgb_register("REG_BLUE", b)
|
||||||
|
self.current_colour = (r, g, b)
|
||||||
|
|
||||||
|
def position_cursor(self, *, col: int, row: int):
|
||||||
|
assert (
|
||||||
|
0 <= col < self.COLS
|
||||||
|
), f"Column {col} is out of bounds (max {self.COLS - 1})."
|
||||||
|
assert (
|
||||||
|
0 <= row < self.ROWS
|
||||||
|
), f"Row {row} is out of bounds (max {self.ROWS - 1})."
|
||||||
|
|
||||||
|
if row == 0:
|
||||||
|
col |= 0x80
|
||||||
|
else:
|
||||||
|
col |= 0xC0
|
||||||
|
|
||||||
|
assert self._i2c.try_lock(), "Could not lock"
|
||||||
|
self._i2c.writeto(
|
||||||
|
Constants.LCD_ADDRESS, bytearray([Constants.LCD_SETDDRAMADDR, col])
|
||||||
|
)
|
||||||
|
self._i2c.unlock()
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self._command(Constants.LCD_CLEARDISPLAY)
|
||||||
|
sleep(0.002)
|
||||||
|
|
||||||
|
def write_bytes(self, arg: bytes):
|
||||||
|
for byte in arg:
|
||||||
|
self._write_byte(byte)
|
||||||
|
|
||||||
|
def write_at_position(self, text: str | bytes, *, col: int, row: int) -> None:
|
||||||
|
self.position_cursor(col=col, row=row)
|
||||||
|
self.write_bytes(self._ensure_bytes(text))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _ensure_bytes(s: str | bytes) -> bytes:
|
||||||
|
if isinstance(s, bytes):
|
||||||
|
return s
|
||||||
|
# Not JIS X 0213 but close enough if you’re careful.
|
||||||
|
return bytes(s, "jisx0213")
|
||||||
|
|
||||||
|
def update(
|
||||||
|
self, first_line: str | bytes, second_line: str | bytes | None = None
|
||||||
|
) -> None:
|
||||||
|
first = self._ensure_bytes(first_line)
|
||||||
|
self.clear()
|
||||||
|
self.write_bytes(first[: self.COLS])
|
||||||
|
if second_line is not None:
|
||||||
|
self.position_cursor(col=0, row=1)
|
||||||
|
second = self._ensure_bytes(second_line)
|
||||||
|
self.write_bytes(second[: self.COLS])
|
||||||
|
|
||||||
|
def set_white(self) -> None:
|
||||||
|
self.set_css_colour("white")
|
||||||
|
|
||||||
|
def set_css_colour(self, colour_name: str) -> None:
|
||||||
|
self.set_rgb(*CSS_COLOURS[colour_name])
|
||||||
|
|
||||||
|
def set_css_color(self, color_name: str) -> None:
|
||||||
|
self.set_css_colour(color_name)
|
||||||
|
|
||||||
|
def set_backlight_power(self, on: bool) -> None:
|
||||||
|
data = 0xFF if on else 0x00
|
||||||
|
self._set_rgb_register("REG_OUTPUT", data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def special_char(c: str) -> bytes:
|
||||||
|
if c == "\\":
|
||||||
|
raise ValueError("\\ (backslash) is not in the character set.")
|
||||||
|
elif ord(c) < ord("}"):
|
||||||
|
# Everything matches ASCII up to }, except for \ -> ¥.
|
||||||
|
return c.encode("ascii")
|
||||||
|
|
||||||
|
chars = {
|
||||||
|
"→": b"\x7E",
|
||||||
|
"←": b"\x7F",
|
||||||
|
"•": b"\xA5",
|
||||||
|
"☐": b"\xDB",
|
||||||
|
"°": b"\xDF",
|
||||||
|
"alpha": b"\xE0",
|
||||||
|
"beta": b"\xE2",
|
||||||
|
"epsilon": b"\xE3",
|
||||||
|
"mu": b"\xE4",
|
||||||
|
"sigma": b"\xE5",
|
||||||
|
"rho": b"\xE6",
|
||||||
|
"√": b"\xE8",
|
||||||
|
"theta": b"\xF2",
|
||||||
|
"omega": b"\xF4",
|
||||||
|
"SIGMA": b"\xF6",
|
||||||
|
"pi": b"\xF7",
|
||||||
|
"÷": b"\xFD",
|
||||||
|
"block": b"\xFF",
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
return chars[c]
|
||||||
|
except KeyError:
|
||||||
|
raise ValueError(f"Character {repr(c)} is not a registered special character.")
|
45
lib/rgb1602/examples.py
Normal file
45
lib/rgb1602/examples.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
from time import sleep
|
||||||
|
|
||||||
|
from rgb1602.colours import CSS_COLOURS, WAVESHARE_COLOURS
|
||||||
|
from rgb1602.display import Screen
|
||||||
|
|
||||||
|
|
||||||
|
def _show_colours(
|
||||||
|
screen: Screen,
|
||||||
|
delay: int,
|
||||||
|
colours: dict[str, tuple[int, int, int]],
|
||||||
|
colour_set_name: str,
|
||||||
|
) -> None:
|
||||||
|
original_rgb = screen.current_colour
|
||||||
|
for colour_name, rgb in sorted(colours.items()):
|
||||||
|
screen.set_rgb(*rgb)
|
||||||
|
screen.update(colour_set_name, colour_name)
|
||||||
|
sleep(delay)
|
||||||
|
screen.set_rgb(*original_rgb)
|
||||||
|
|
||||||
|
|
||||||
|
def show_css_colours(screen: Screen, delay: int = 2) -> None:
|
||||||
|
_show_colours(screen, delay, CSS_COLOURS, "CSS named colour")
|
||||||
|
|
||||||
|
|
||||||
|
def show_waveshare_colours(screen: Screen, delay: int = 2) -> None:
|
||||||
|
_show_colours(screen, delay, WAVESHARE_COLOURS, "Waveshare")
|
||||||
|
|
||||||
|
|
||||||
|
def show_discoloration_sample(screen: Screen) -> None:
|
||||||
|
from math import sin
|
||||||
|
|
||||||
|
screen.update(f"Waveshare", "Hello, world!")
|
||||||
|
t = 0
|
||||||
|
while True:
|
||||||
|
r = int((abs(sin(3.14 * t / 180))) * 255)
|
||||||
|
g = int((abs(sin(3.14 * (t + 60) / 180))) * 255)
|
||||||
|
b = int((abs(sin(3.14 * (t + 120) / 180))) * 255)
|
||||||
|
t = (t + 3) % 360
|
||||||
|
|
||||||
|
screen.set_rgb(r, g, b)
|
||||||
|
screen.write_at_position(
|
||||||
|
str(t).encode() + screen.special_char("°") + b" ", col=10, row=0
|
||||||
|
)
|
||||||
|
|
||||||
|
sleep(0.3)
|
234
lib/waveshare_lcd1602.py
Normal file
234
lib/waveshare_lcd1602.py
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) Waveshare
|
||||||
|
# SPDX-FileCopyrightText: Copyright (c) 2022 Neradoc
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# In order to keep basic compatibility with the orifinal library, ignore "bad" names.
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
"""
|
||||||
|
`waveshare_lcd1602`
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Drive for Waveshare's I2C character display LCD1602.
|
||||||
|
A port of Waveshare's RGB1602 Micropython library.
|
||||||
|
|
||||||
|
* Author(s): Neradoc
|
||||||
|
|
||||||
|
Implementation Notes
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
**Hardware:**
|
||||||
|
|
||||||
|
* `Waveshare LCD1602 RGB Module <https://www.waveshare.com/wiki/LCD1602_RGB_Module>`_
|
||||||
|
|
||||||
|
**Software and Dependencies:**
|
||||||
|
|
||||||
|
* Adafruit CircuitPython firmware for the supported boards:
|
||||||
|
https://circuitpython.org/downloads
|
||||||
|
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
|
||||||
|
"""
|
||||||
|
|
||||||
|
import time
|
||||||
|
from adafruit_bus_device.i2c_device import I2CDevice
|
||||||
|
|
||||||
|
try:
|
||||||
|
from typing import Union
|
||||||
|
import busio
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
__version__ = "0.0.0-auto.0"
|
||||||
|
__repo__ = "https://github.com/Neradoc/Circuitpython_Waveshare_LCD1602.git"
|
||||||
|
|
||||||
|
# Device I2C Arress
|
||||||
|
LCD_ADDRESS = 0x7C >> 1
|
||||||
|
RGB_ADDRESS = 0xC0 >> 1
|
||||||
|
|
||||||
|
# color define
|
||||||
|
|
||||||
|
REG_RED = 0x04
|
||||||
|
REG_GREEN = 0x03
|
||||||
|
REG_BLUE = 0x02
|
||||||
|
REG_MODE1 = 0x00
|
||||||
|
REG_MODE2 = 0x01
|
||||||
|
REG_OUTPUT = 0x08
|
||||||
|
LCD_CLEARDISPLAY = 0x01
|
||||||
|
LCD_RETURNHOME = 0x02
|
||||||
|
LCD_ENTRYMODESET = 0x04
|
||||||
|
LCD_DISPLAYCONTROL = 0x08
|
||||||
|
LCD_CURSORSHIFT = 0x10
|
||||||
|
LCD_FUNCTIONSET = 0x20
|
||||||
|
LCD_SETCGRAMADDR = 0x40
|
||||||
|
LCD_SETDDRAMADDR = 0x80
|
||||||
|
|
||||||
|
# flags for display entry mode
|
||||||
|
LCD_ENTRYRIGHT = 0x00
|
||||||
|
LCD_ENTRYLEFT = 0x02
|
||||||
|
LCD_ENTRYSHIFTINCREMENT = 0x01
|
||||||
|
LCD_ENTRYSHIFTDECREMENT = 0x00
|
||||||
|
|
||||||
|
# flags for display on/off control
|
||||||
|
LCD_DISPLAYON = 0x04
|
||||||
|
LCD_DISPLAYOFF = 0x00
|
||||||
|
LCD_CURSORON = 0x02
|
||||||
|
LCD_CURSOROFF = 0x00
|
||||||
|
LCD_BLINKON = 0x01
|
||||||
|
LCD_BLINKOFF = 0x00
|
||||||
|
|
||||||
|
# flags for display/cursor shift
|
||||||
|
LCD_DISPLAYMOVE = 0x08
|
||||||
|
LCD_CURSORMOVE = 0x00
|
||||||
|
LCD_MOVERIGHT = 0x04
|
||||||
|
LCD_MOVELEFT = 0x00
|
||||||
|
|
||||||
|
# flags for function set
|
||||||
|
LCD_8BITMODE = 0x10
|
||||||
|
LCD_4BITMODE = 0x00
|
||||||
|
LCD_2LINE = 0x08
|
||||||
|
LCD_1LINE = 0x00
|
||||||
|
LCD_5X8DOTS = 0x00
|
||||||
|
|
||||||
|
|
||||||
|
class LCD1602:
|
||||||
|
"""
|
||||||
|
Setup a new RGB LCD1602 display
|
||||||
|
|
||||||
|
:param busio.I2C i2c: I2C bus object to use.
|
||||||
|
:param int columns: The number of columns on the display.
|
||||||
|
:param int rows: The number of rows on the display.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, i2c: busio.I2C, columns: int, rows: int):
|
||||||
|
self.lcd_device = I2CDevice(i2c, LCD_ADDRESS)
|
||||||
|
#self.rgb_device = I2CDevice(i2c, RGB_ADDRESS)
|
||||||
|
self._row = rows
|
||||||
|
self._col = columns
|
||||||
|
|
||||||
|
self._showfunction = LCD_4BITMODE | LCD_1LINE | LCD_5X8DOTS
|
||||||
|
self.begin(self._row, self._col)
|
||||||
|
|
||||||
|
def command(self, cmd: int):
|
||||||
|
"""
|
||||||
|
Send a command.
|
||||||
|
|
||||||
|
:param int cmd: The command code.
|
||||||
|
"""
|
||||||
|
with self.lcd_device:
|
||||||
|
self.lcd_device.write(bytes([0x80]) + chr(cmd))
|
||||||
|
|
||||||
|
def write(self, data: int):
|
||||||
|
"""
|
||||||
|
Write a data byte.
|
||||||
|
|
||||||
|
:param int data: The data byte to write.
|
||||||
|
"""
|
||||||
|
with self.lcd_device:
|
||||||
|
self.lcd_device.write(bytes([0x40]) + chr(data))
|
||||||
|
|
||||||
|
def setReg(self, reg, data):
|
||||||
|
"""
|
||||||
|
Set the value of a register.
|
||||||
|
|
||||||
|
:param int reg: The register to write to.
|
||||||
|
:param int data: The data byte to write.
|
||||||
|
"""
|
||||||
|
#with self.rgb_device:
|
||||||
|
# self.rgb_device.write(bytes([reg]) + chr(data))
|
||||||
|
|
||||||
|
def setRGB(self, r, g, b):
|
||||||
|
"""
|
||||||
|
Set the color of the RGB backlight.
|
||||||
|
|
||||||
|
:param int r: Red byte.
|
||||||
|
:param int g: Green byte.
|
||||||
|
:param int b: Blue byte.
|
||||||
|
"""
|
||||||
|
self.setReg(REG_RED, r)
|
||||||
|
self.setReg(REG_GREEN, g)
|
||||||
|
self.setReg(REG_BLUE, b)
|
||||||
|
|
||||||
|
def setCursor(self, col, row):
|
||||||
|
"""
|
||||||
|
Place the cursor on the display.
|
||||||
|
|
||||||
|
:param int col: The column.
|
||||||
|
:param int row: The row.
|
||||||
|
"""
|
||||||
|
if row == 0:
|
||||||
|
col |= 0x80
|
||||||
|
else:
|
||||||
|
col |= 0xC0
|
||||||
|
with self.lcd_device:
|
||||||
|
self.lcd_device.write(bytearray([0x80, col]))
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
"""Clear the display."""
|
||||||
|
self.command(LCD_CLEARDISPLAY)
|
||||||
|
time.sleep(0.002)
|
||||||
|
|
||||||
|
def printout(self, arg: Union[str, int]):
|
||||||
|
"""
|
||||||
|
Print a string to the display. Ints are converted to strings.
|
||||||
|
|
||||||
|
:param str|int arg: The string or int to printout.
|
||||||
|
"""
|
||||||
|
if isinstance(arg, int):
|
||||||
|
arg = str(arg)
|
||||||
|
|
||||||
|
for x in bytearray(arg, "utf-8"):
|
||||||
|
self.write(x)
|
||||||
|
|
||||||
|
def display(self):
|
||||||
|
"""Turn on the display."""
|
||||||
|
self._showcontrol |= LCD_DISPLAYON
|
||||||
|
self.command(LCD_DISPLAYCONTROL | self._showcontrol)
|
||||||
|
|
||||||
|
def begin(self, columns: int, rows: int): # pylint: disable=unused-argument
|
||||||
|
"""
|
||||||
|
Initial configuration, called from init.
|
||||||
|
|
||||||
|
:param int columns: The number of columns on the display.
|
||||||
|
:param int rows: The number of rows on the display.
|
||||||
|
"""
|
||||||
|
if rows > 1:
|
||||||
|
self._showfunction |= LCD_2LINE
|
||||||
|
|
||||||
|
self._numlines = rows
|
||||||
|
self._currline = 0
|
||||||
|
|
||||||
|
time.sleep(0.05)
|
||||||
|
|
||||||
|
# Send function set command sequence
|
||||||
|
self.command(LCD_FUNCTIONSET | self._showfunction)
|
||||||
|
# delayMicroseconds(4500); # wait more than 4.1ms
|
||||||
|
time.sleep(0.005)
|
||||||
|
# second try
|
||||||
|
self.command(LCD_FUNCTIONSET | self._showfunction)
|
||||||
|
# delayMicroseconds(150);
|
||||||
|
time.sleep(0.005)
|
||||||
|
# third go
|
||||||
|
self.command(LCD_FUNCTIONSET | self._showfunction)
|
||||||
|
# finally, set # lines, font size, etc.
|
||||||
|
self.command(LCD_FUNCTIONSET | self._showfunction)
|
||||||
|
# turn the display on with no cursor or blinking default
|
||||||
|
self._showcontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF
|
||||||
|
self.display()
|
||||||
|
# clear it off
|
||||||
|
self.clear()
|
||||||
|
# Initialize to default text direction (for romance languages)
|
||||||
|
self._showmode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT
|
||||||
|
# set the entry mode
|
||||||
|
self.command(LCD_ENTRYMODESET | self._showmode)
|
||||||
|
# backlight init
|
||||||
|
self.setReg(REG_MODE1, 0)
|
||||||
|
# set LEDs controllable by both PWM and GRPPWM registers
|
||||||
|
self.setReg(REG_OUTPUT, 0xFF)
|
||||||
|
# set MODE2 values
|
||||||
|
# 0010 0000 -> 0x20 (DMBLNK to 1, ie blinky mode)
|
||||||
|
self.setReg(REG_MODE2, 0x20)
|
||||||
|
self.setColorWhite()
|
||||||
|
|
||||||
|
def setColorWhite(self):
|
||||||
|
"""Set the color of the RGB backlight to white."""
|
||||||
|
self.setRGB(255, 255, 255)
|
194
macros/archinstall.mcr
Normal file
194
macros/archinstall.mcr
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# First Boot
|
||||||
|
|
||||||
|
"loadkeys uk"
|
||||||
|
WAIT 1
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
"archinstall"
|
||||||
|
WAIT 1
|
||||||
|
enter
|
||||||
|
WAIT 10
|
||||||
|
|
||||||
|
|
||||||
|
# Locales
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
enter
|
||||||
|
forwardslash
|
||||||
|
"uk"
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
forwardslash
|
||||||
|
"en_gb."
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Mirrors
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
forwardslash
|
||||||
|
"kin"
|
||||||
|
enter
|
||||||
|
WAIT 5
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
|
||||||
|
# Partitions
|
||||||
|
|
||||||
|
# EXT4 Main Drive
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
space
|
||||||
|
enter
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Encryption
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
LCD_SHOW "Password? (5s)"
|
||||||
|
WAIT 5
|
||||||
|
enter
|
||||||
|
LCD_SHOW "Password? (5s)"
|
||||||
|
WAIT 5
|
||||||
|
enter
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
space
|
||||||
|
enter
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Bootloader
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
|
||||||
|
# Pick GRUB
|
||||||
|
|
||||||
|
forwardslash
|
||||||
|
"grub"
|
||||||
|
enter
|
||||||
|
|
||||||
|
|
||||||
|
# Hostname
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
|
||||||
|
# Clear out pre-filled hostname
|
||||||
|
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
backspace
|
||||||
|
|
||||||
|
# Entering new hostname
|
||||||
|
|
||||||
|
LCD_SHOW "Hostname? (5s)"
|
||||||
|
WAIT 5
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Users
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Prompt for username + password
|
||||||
|
|
||||||
|
LCD_SHOW "Username? (5s)"
|
||||||
|
WAIT 5
|
||||||
|
enter
|
||||||
|
LCD_SHOW "Password? (5s)"
|
||||||
|
WAIT 5
|
||||||
|
enter
|
||||||
|
LCD_SHOW "Password? (5s)"
|
||||||
|
WAIT 5
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Profile
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
forwardslash
|
||||||
|
"Min"
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Audio servers
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Networking
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Time and Date
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
forwardslash
|
||||||
|
"london"
|
||||||
|
enter
|
||||||
|
WAIT 1
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
||||||
|
|
||||||
|
# Install
|
||||||
|
|
||||||
|
downarrow
|
||||||
|
downarrow
|
||||||
|
enter
|
||||||
|
enter
|
0
macros/syntax.mcr
Normal file
0
macros/syntax.mcr
Normal file
59
macros/test.mcr
Normal file
59
macros/test.mcr
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
LCD_SHOW "Hi"
|
||||||
|
|
||||||
|
# test comment
|
||||||
|
|
||||||
|
WAIT 3
|
||||||
|
|
||||||
|
HOLD
|
||||||
|
|
||||||
|
super
|
||||||
|
|
||||||
|
"d"
|
||||||
|
|
||||||
|
RELEASE
|
||||||
|
|
||||||
|
"text editor"
|
||||||
|
|
||||||
|
enter
|
||||||
|
|
||||||
|
HOLD
|
||||||
|
|
||||||
|
ctrl
|
||||||
|
|
||||||
|
"n"
|
||||||
|
|
||||||
|
RELEASE
|
||||||
|
|
||||||
|
tab
|
||||||
|
|
||||||
|
forwardslash
|
||||||
|
|
||||||
|
space
|
||||||
|
|
||||||
|
backslash
|
||||||
|
|
||||||
|
HOLD
|
||||||
|
|
||||||
|
shift
|
||||||
|
|
||||||
|
"a"
|
||||||
|
|
||||||
|
RELEASE
|
||||||
|
|
||||||
|
enter
|
||||||
|
|
||||||
|
capslock
|
||||||
|
|
||||||
|
"caps"
|
||||||
|
|
||||||
|
capslock
|
||||||
|
|
||||||
|
enter
|
||||||
|
|
||||||
|
"lowercase"
|
||||||
|
|
||||||
|
backspace
|
||||||
|
|
||||||
|
enter
|
||||||
|
|
||||||
|
"sentence longer than 16 chars..."
|
0
settings.toml
Normal file
0
settings.toml
Normal file
Loading…
x
Reference in New Issue
Block a user