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