Initial commit, screen code mostly working, a couple of symbols missing from the font, keypresses work but is not programmed yet

This commit is contained in:
Tom Charnock 2024-12-27 16:00:43 +01:00
commit adcf6da8eb
20 changed files with 21003 additions and 0 deletions

1
.envrc Normal file
View File

@ -0,0 +1 @@
use flake

3434
board_layout/0.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 105 KiB

3488
board_layout/1x2.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 109 KiB

3632
board_layout/2.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 115 KiB

3432
board_layout/3.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 109 KiB

3347
board_layout/4.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 102 KiB

99
characters.py Normal file
View File

@ -0,0 +1,99 @@
characters = [
[
[
[
[
[None, None, None, None], #00000
["\u2423", "\u002e", "\u003c", "\u0031"], #00001 [SPACE, FULLSTOP, LESS THAN, 1]
],
[
["\u21b9", "\u002c", None, "\u0032"], #00010 [TAB, COMMA, None, 2]
["\u0065", "\u0045", "\u003d", "\u0035"], #00011 [e, E, EQUALS, 5]
],
],
[
[
["\u232b", "\u003a", None, "\u0033"], #00100 [BACKSPACE, :, None, 3]
["\u0061", "\u0041", "\u002b", "\u0036"], #00101 [a, A, PLUS, 6]
],
[
["\u0072", "\u0052", "\u002f", "\u1f50e"], #00110 [r, R, SLASH, CTRL+F]
["\u0075", "\u0055", "\u0027", "\u0038"], #00111 [u, U, APOSTROPHE, 8]
],
],
],
[
[
[
["\u238b", "\u003b", None, "\u0034"], #01000 [ESCAPE, SEMICOLON, None, 4]
["\u0069", "\u0049", "\u002a", "\u0037"], #01001 [i, I, ASTERISK, 7]
],
[
["\u0063", "\u0043", "\u005c", "\u261d"], #01010 [c, C, BACKSLASH, CTRL+A]
["\u0078", "\u0058", "\u0022", "\u0039"], #01011 [x, X, DOUBLE QUOTES, 9]
],
],
[
[
["\u006c", "\u004c", "\u007e", "\u2190\u2318"], #01100 [l, L, TILDE, SUPER LEFT]
["\u007a", "\u005a", "\u003e", "\u2192\u2318"], #01101 [z, Z, GREATER THAN, SUPER RIGHT]
],
[
["\u0064", "\u0044", "\u0060", "\u29c8"], #01110 [d, D, TICK, PASTE]
["\u0068", "\u0048", "\u0040", "\u0030"], #01111 [h, H, AT, 0]
],
],
],
],
[
[
[
[
["\u23ce", "\u21e7\u23ce", "\u002d", "\u2399"], #10000 [RETURN, SHIFT RETURN, MINUS, PRINT SCREEN]
["\u006f", "\u004f", "\u0029", "\u2193"], #10001 [o, O, CLOSE BRACKET, DOWN]
],
[
["\u006d", "\u004d", "\u0028", "\u2192"], #10010 [m, M, OPEN BRACKET, RIGHT]
["\u0070", "\u0050", "\u005f", None], #10011 [p, P, UNDERSCORE, None]
],
],
[
[
["\u0066", "\u0046", "\u0023", "\u2191"], #10100 [f, F, HASH, UP]
["\u0077", "\u0057", "\u007c", None], #10101 [w, W, PIPE, None]
],
[
["\u006a", "\u004a", "\u0025", None], #10110 [j, J, PERCENT, None]
["\u0071", "\u0051", "\u003f", None], #10111 [q, Q, QUESTION MARK, None]
],
],
],
[
[
[
["\u0079", "\u0059", "\u0024", "\u2318"], #11000 [y, Y, DOLLAR, LEFT]
["\u0062", "\u0042", "\u007d", None], #11001 [b, B, CLOSE CURLY BRACKET, None]
],
[
["\u006b", "\u004b", "\u007b", None], #11010 [k, K, OPEN CURLY BRACKET, None]
["\u0067", "\u0047", "\u0021", None], #11011 [g, G, EXCLAMATION MARK, None]
],
],
[
[
["\u0073", "\u0053", "\u005e", "\u21e4"], #11100 [s, S, CIRCUMFLEX, HOME]
["\u0076", "\u0056", "\u005d", "\u21e5"], #11101 [v, V, CLOSE SQUARE BRACKET, END]
],
[
["\u006e", "\u004e", "\u005b", "\u29c9"], #11110 [n, N, OPEN SQUARE BRACKET, CTRL+C]
["\u0074", "\u0054", "\u0026", ""], #11111 [t, T, AMPERSAND, SUPER]
],
],
],
],
]
def get_character_set():
return sorted(list(set(sum([list(a) for a in sum(sum(sum(sum(sum(characters, []), []), []), []), []) if a is not None], []))))
missing = ["-", "_"]

332
code.py Normal file
View File

@ -0,0 +1,332 @@
import time
import board
import math
import random
import busio
from digitalio import DigitalInOut, Direction, Pull
import displayio
from vectorio import Rectangle, Circle, Polygon
from adafruit_display_text import label
from adafruit_bitmap_font import bitmap_font
import gc9a01
import usb_hid
from characters import characters
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
kbd = Keyboard(usb_hid.devices)
font = bitmap_font.load_font("fonts/VictorMonoNerdFont-SemiBoldItalic-32.pcf")
displayio.release_displays()
mode_labels = [
["Letters", "Words", "Predictive"],
["Lettres", "Mots", "Predictif"]
]
language_labels = ["English", "Francais"]
backlight_labels = ["Backlight", "Retroeclairage"]
tft_clk = board.GP2
tft_mosi= board.GP3
tft_rst = board.GP4
tft_dc = board.GP1
tft_cs = board.GP0
tft_bl = DigitalInOut(board.GP5)
tft_bl.direction = Direction.OUTPUT
tft_bl.value = True
key0 = DigitalInOut(board.GP6)
key0.pull = Pull.UP
key1 = DigitalInOut(board.GP7)
key1.pull = Pull.UP
key2 = DigitalInOut(board.GP8)
key2.pull = Pull.UP
key3 = DigitalInOut(board.GP9)
key3.pull = Pull.UP
key4 = DigitalInOut(board.GP10)
key4.pull = Pull.UP
key5 = DigitalInOut(board.GP11)
key5.pull = Pull.UP
key6 = DigitalInOut(board.GP12)
key6.pull = Pull.UP
spi = busio.SPI(clock=tft_clk, MOSI=tft_mosi)
display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)
display = gc9a01.GC9A01(display_bus, width=240, height=240)
main_display = displayio.Group()
display.root_group = main_display
label_position_radius = 90
top_text = label.Label(
font,
text=" "*10,
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
top = displayio.Group(scale=1)
top.x, top.y = 120, 50
top.append(top_text)
main_display.append(top)
middle_text = label.Label(
font,
text=" "*8,
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
middle = displayio.Group(scale=1)
middle.x, middle.y = 120, 110
middle.append(middle_text)
main_display.append(middle)
bottom_text = label.Label(
font,
text=" "*14,
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
bottom = displayio.Group(scale=1)
bottom.x, bottom.y = 120, 170
bottom.append(bottom_text)
main_display.append(bottom)
key0_text = label.Label(
font,
text = " ",
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
key0_colour = (219, 97, 71)
key0_palette = displayio.Palette(1)
key0_palette[0] = (0, 0, 0)
key0_display = displayio.Group(scale=1)
key0_angle = - 2. * math.pi / 3.
key0_display.x = int(120 + label_position_radius * math.sin(key0_angle))
key0_display.y = int(120 - label_position_radius * math.cos(key0_angle))
key0_display.append(key0_text)
main_display.append(Circle(pixel_shader=key0_palette, radius=16, x=key0_display.x, y=key0_display.y))
main_display.append(key0_display)
key1_text = label.Label(
font,
text = " ",
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
key1_colour = (100, 150, 40)
key1_palette = displayio.Palette(1)
key1_palette[0] = (0, 0, 0)
key1_display = displayio.Group(scale=1)
key1_angle = - math.pi / 3.
key1_display.x = int(120 + label_position_radius * math.sin(key1_angle))
key1_display.y = int(120 - label_position_radius * math.cos(key1_angle))
key1_display.append(key1_text)
main_display.append(Circle(pixel_shader=key1_palette, radius=16, x=key1_display.x, y=key1_display.y))
main_display.append(key1_display)
key2_text = label.Label(
font,
text = " ",
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
key2_colour = (40, 150, 100)
key2_palette = displayio.Palette(1)
key2_palette[0] = (0, 0, 0)
key2_display = displayio.Group(scale=1)
key2_angle = 0
key2_display.x = int(120 + label_position_radius * math.sin(key2_angle))
key2_display.y = int(120 - label_position_radius * math.cos(key2_angle))
key2_display.append(key2_text)
main_display.append(Circle(pixel_shader=key2_palette, radius=16, x=key2_display.x, y=key2_display.y))
main_display.append(key2_display)
key3_text = label.Label(
font,
text = " ",
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
key3_colour = (100, 40, 150)
key3_palette = displayio.Palette(1)
key3_palette[0] = (0, 0, 0)
key3_display = displayio.Group(scale=1)
key3_angle = math.pi / 3.
key3_display.x = int(120 + label_position_radius * math.sin(key3_angle))
key3_display.y = int(120 - label_position_radius * math.cos(key3_angle))
key3_display.append(key3_text)
main_display.append(Circle(pixel_shader=key3_palette, radius=16, x=key3_display.x, y=key3_display.y))
main_display.append(key3_display)
key4_text = label.Label(
font,
text = " ",
color=0xffffff,
anchor_point=(0.5, 0.5),
anchored_position=(0, 0)
)
key4_colour = (40, 40, 150)
key4_palette = displayio.Palette(1)
key4_palette[0] = (0, 0, 0)
key4_display = displayio.Group(scale=1)
key4_angle = 2. * math.pi / 3.
key4_display.x = int(120 + label_position_radius * math.sin(key4_angle))
key4_display.y = int(120 - label_position_radius * math.cos(key4_angle))
key4_display.append(key4_text)
main_display.append(Circle(pixel_shader=key4_palette, radius=16, x=key4_display.x, y=key4_display.y))
main_display.append(key4_display)
key5_colour = (0, 100, 30)
key5_palette = displayio.Palette(1)
key5_palette[0] = (0, 0, 0)
main_display.append(Circle(pixel_shader=key5_palette, radius=16, x=120-32, y=120))
key6_colour = (15, 100, 200)
key6_palette = displayio.Palette(1)
key6_palette[0] = (0, 0, 0)
main_display.append(Circle(pixel_shader=key6_palette, radius=16, x=120+32, y=120))
def swap_to_settings_display():
key0_text.text = ""
key1_text.text = ""
key2_text.text = ""
key3_text.text = ""
key4_text.text = ""
def settings_display(mode, language, location):
print(mode, language, location, mode_labels[language][mode])
display.refresh()
top_text.text = mode_labels[language][mode]
top_text.color = 0x1c4d2d if location == 0 else 0xffffff
middle_text.text = language_labels[language]
middle_text.color = 0x1c4d2d if location == 1 else 0xffffff
bottom_text.text = backlight_labels[language]
bottom_text.color = 0x1c4d2d if location == 2 else 0xffffff
def swap_to_character_display():
top_text.text = ""
middle_text.text = ""
bottom_text.text = ""
def edit_character(pin, character, key_text, key_palette, colour):
if pin is 0:
key_palette[0] = (0, 0, 0)
if character is None:
key_text.text = ""
else:
key_text.text = character
else:
key_text.text = ""
key_palette[0] = colour
def character_display(pin0, pin1, pin2, pin3, pin4, selection):
display.refresh()
edit_character(pin0, characters[1][pin1][pin2][pin3][pin4][selection], key0_text, key0_palette, key0_colour)
edit_character(pin1, characters[pin0][1][pin2][pin3][pin4][selection], key1_text, key1_palette, key1_colour)
edit_character(pin2, characters[pin0][pin1][1][pin3][pin4][selection], key2_text, key2_palette, key2_colour)
edit_character(pin3, characters[pin0][pin1][pin2][1][pin4][selection], key3_text, key3_palette, key3_colour)
edit_character(pin4, characters[pin0][pin1][pin2][pin3][1][selection], key4_text, key4_palette, key4_colour)
def mode_display(selection):
if selection is 0:
key5_palette[0] = (0, 0, 0)
key6_palette[0] = (0, 0, 0)
elif selection is 1:
key5_palette[0] = key5_colour
key6_palette[0] = (0, 0, 0)
elif selection is 2:
key5_palette[0] = (0, 0, 0)
key6_palette[0] = key6_colour
elif selection is 3:
key5_palette[0] = key5_colour
key6_palette[0] = key6_colour
def pressed(key):
return not key.value
def poll():
return [pressed(key0), pressed(key1), pressed(key2), pressed(key3), pressed(key4), pressed(key5), pressed(key6)]
def main():
for selection in range(4):
mode_display(selection)
character_display(0, 0, 0, 0, 0, selection)
time.sleep(1)
character_display(0, 0, 0, 0, 1, selection)
time.sleep(1)
character_display(0, 0, 0, 1, 0, selection)
time.sleep(1)
character_display(0, 0, 1, 0, 0, selection)
time.sleep(1)
character_display(0, 1, 0, 0, 0, selection)
time.sleep(1)
character_display(1, 0, 0, 0, 0, selection)
time.sleep(1)
character_display(0, 0, 0, 1, 1, selection)
time.sleep(1)
character_display(0, 0, 1, 0, 1, selection)
time.sleep(1)
character_display(0, 1, 0, 0, 1, selection)
time.sleep(1)
character_display(1, 0, 0, 0, 1, selection)
time.sleep(1)
character_display(0, 0, 1, 1, 0, selection)
time.sleep(1)
character_display(0, 1, 0, 1, 0, selection)
time.sleep(1)
character_display(1, 0, 0, 1, 0, selection)
time.sleep(1)
character_display(0, 1, 1, 0, 0, selection)
time.sleep(1)
character_display(1, 0, 1, 0, 0, selection)
time.sleep(1)
character_display(1, 1, 0, 0, 0, selection)
time.sleep(1)
character_display(0, 0, 1, 1, 1, selection)
time.sleep(1)
character_display(0, 1, 0, 1, 1, selection)
time.sleep(1)
character_display(1, 0, 0, 1, 1, selection)
time.sleep(1)
character_display(0, 1, 1, 1, 0, selection)
time.sleep(1)
character_display(1, 0, 1, 1, 0, selection)
time.sleep(1)
character_display(1, 1, 1, 0, 0, selection)
time.sleep(1)
character_display(0, 1, 1, 1, 1, selection)
time.sleep(1)
character_display(1, 1, 1, 0, 1, selection)
time.sleep(1)
character_display(1, 1, 0, 1, 1, selection)
time.sleep(1)
character_display(1, 0, 1, 1, 1, selection)
time.sleep(1)
character_display(0, 1, 1, 1, 1, selection)
time.sleep(1)
character_display(1, 1, 1, 1, 1, selection)
time.sleep(1)
tft_bl.value = False
while True:
pass
# keypresses = poll()
# if any(keypresses):
# kbd.send(Keycode.A)
# time.sleep(1)
main()

57
flake.lock generated Normal file
View File

@ -0,0 +1,57 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 0,
"narHash": "sha256-Qn3nPMSopRQJgmvHzVqPcE3I03zJyl8cSbgnnltfFDY=",
"path": "/nix/store/avxvalb7xf8x4avmrbcvn1vr5yy46kxs-source",
"type": "path"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"utils": "utils"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

18
flake.nix Normal file
View File

@ -0,0 +1,18 @@
{
inputs = {
utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, utils }: utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
circup
tio
];
};
}
);
}

BIN
flash_nuke.uf2 Normal file

Binary file not shown.

1
fonts/.envrc Normal file
View File

@ -0,0 +1 @@
use flake

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

15
fonts/convert_font.py Normal file
View File

@ -0,0 +1,15 @@
import os, sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import characters
import fontforge
font = fontforge.open("VictorMonoNerdFont-SemiBoldItalic.ttf")
font.selection.none()
for char in characters.get_character_set():
font.selection.select(("more",), ord(char))
font.selection.invert()
font.clear()
size = 32
font.selection.all()
font.bitmapSizes = ((size,),)
font.regenBitmaps((size,))
font.generate(f"VictorMonoNerdFont-SemiBoldItalic.bdf", bitmap_type="bdf", bitmap_resolution=96)

57
fonts/flake.lock generated Normal file
View File

@ -0,0 +1,57 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 0,
"narHash": "sha256-Qn3nPMSopRQJgmvHzVqPcE3I03zJyl8cSbgnnltfFDY=",
"path": "/nix/store/avxvalb7xf8x4avmrbcvn1vr5yy46kxs-source",
"type": "path"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs",
"utils": "utils"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

17
fonts/flake.nix Normal file
View File

@ -0,0 +1,17 @@
{
inputs = {
utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, utils }: utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
{
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
( python3.withPackages ( ps: [ ps.fontforge ] ) )
];
};
}
);
}

20
setup.sh Normal file
View File

@ -0,0 +1,20 @@
#!/bin/bash
echo "Flashing $1"
cp $1 /run/media/skyrgobbler/RPI-RP2/.
echo "Letting settle"
while [[ ! -d /run/media/skyrgobbler/CIRCUITPY ]]
do
sleep 1
done
echo "Making font directory"
mkdir /run/media/skyrgobbler/CIRCUITPY/fonts
echo "Adding fonts"
cp fonts/VictorMonoNerdFont-SemiBoldItalic-32.pcf /run/media/skyrgobbler/CIRCUITPY/fonts/.
echo "Installing libraries"
circup install adafruit_display_text
circup install adafruit_hid
circup install gc9a01
echo "Adding character map"
cp characters.py /run/media/skyrgobbler/CIRCUITPY/.
echo "Adding code"
cp code.py /run/media/skyrgobbler/CIRCUITPY/.