Skip to content

Commit 4af5289

Browse files
committed
python: Enable packaging via hatch
``` > cd python > python3 -m build > ls -1 dist framework16_inputmodule-0.1.0-py3-none-any.whl framework16_inputmodule-0.1.0.tar.gz mkdir temp && temp python3 -m venv venv source venv/bin/activate > python3 -m pip install ../dist/framework16_inputmodule-0.1.0.tar.gz > inputmodulectl > inputmodulegui ``` Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent b8016d6 commit 4af5289

File tree

11 files changed

+271
-105
lines changed

11 files changed

+271
-105
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ message.bin
2121
# Python
2222
__pycache__
2323

24+
# Hatch
25+
_version.py
26+
2427
# pyinstaller
2528
build/
2629
dist/

python/README.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# Framework Laptop 16 - Input Module Firmware/Software
2+
3+
This repository contains both the firmware for the Framework Laptop 16 input modules,
4+
as well as the tool to control them.
5+
6+
Rust firmware project setup based off of: https://github.com/rp-rs/rp2040-project-template
7+
8+
## Modules
9+
10+
See pages of the individual modules for details about how they work and how
11+
they're controlled.
12+
13+
- [LED Matrix](ledmatrix/README.md)
14+
- [Minimal C1 Input Module](c1minimal/README.md)
15+
- [2nd Display](b1display/README.md)
16+
- [QT PY RP2040](qtpy/README.md)
17+
18+
## Generic Features
19+
20+
All modules are built with an RP2040 microcontroller
21+
Features that all modules share
22+
23+
- Firmware written in bare-metal Rust
24+
- Reset into RP2040 bootloader when firmware crashes/panics
25+
- Sleep Mode to save power
26+
- API over USB ACM Serial Port - Requires no Drivers on Windows and Linux
27+
- Go to sleep
28+
- Reset into bootloader
29+
- Control and read module state (brightness, displayed image, ...)
30+
31+
## Control from the host
32+
33+
To build your own application see the: [API command documentation](commands.md)
34+
35+
Or use our `inputmodule-control` app, which you can download from the latest
36+
[GH Actions](https://github.com/FrameworkComputer/led_matrix_fw/actions) run or
37+
the [release page](https://github.com/FrameworkComputer/led_matrix_fw/releases).
38+
Optionally there are is also a [Python script](python.md).
39+
40+
For device specific commands, see their individual documentation pages.
41+
42+
###### Permissions on Linux
43+
To ensure that the input module's port is accessible, install the `udev` rule and trigger a reload:
44+
45+
```
46+
sudo cp release/50-framework-inputmodule.rules /etc/udev/rules.d/
47+
sudo udevadm control --reload && sudo udevadm trigger
48+
```
49+
50+
##### Common commands:
51+
52+
###### Listing available devices
53+
54+
```sh
55+
> inputmodule-control --list
56+
/dev/ttyACM0
57+
VID 0x32AC
58+
PID 0x0020
59+
SN FRAKDEAM0020110001
60+
Product LED_Matrix
61+
/dev/ttyACM1
62+
VID 0x32AC
63+
PID 0x0021
64+
SN FRAKDEAM0000000000
65+
Product B1_Display
66+
```
67+
68+
###### Apply command to single device
69+
70+
By default a command will be sent to all devices that can be found, to apply it
71+
to a single device, specify the COM port.
72+
In this example the command is targeted at `b1-display`, so it will only apply
73+
to this module type.
74+
75+
```
76+
# Example on Linux
77+
> inputmodule-control --serial-dev /dev/ttyACM0 b1-display --pattern black
78+
79+
# Example on Windows
80+
> inputmodule-control.exe --serial-dev COM5 b1-display --pattern black
81+
```
82+
83+
###### Send command when device connects
84+
85+
By default the app tries to connect with the device and aborts if it can't
86+
connect. But you might want to start the app, have it wait until the device is
87+
connected and then send the command.
88+
89+
```
90+
> inputmodule-control b1-display --pattern black
91+
Failed to find serial devivce. Please manually specify with --serial-dev
92+
93+
# No failure, waits until the device is connected, sends command and exits
94+
> inputmodule-control --wait-for-device b1-display --pattern black
95+
96+
# If the device is already connected, it does nothing, just wait 1s.
97+
# This means you can run this command by a system service and restart it when
98+
# it finishes. Then it will only ever do anything if the device reconnects.
99+
> inputmodule-control --wait-for-device b1-display --pattern black
100+
Device already present. No need to wait. Not executing command.
101+
```
102+
103+
## Update the Firmware
104+
105+
First, put the module into bootloader mode.
106+
107+
This can be done either by pressing the bootsel button while plugging it in or
108+
by using one of the following commands:
109+
110+
```sh
111+
inputmodule-control led-matrix --bootloader
112+
inputmodule-control b1-display --bootloader
113+
inputmodule-control c1-minimal --bootloader
114+
```
115+
116+
Then the module will present itself in the same way as a USB thumb drive.
117+
Copy the UF2 firmware file onto it and the device will flash and reset automatically.
118+
Alternatively when building from source, run one of the following commands:
119+
120+
```sh
121+
cargo run -p ledmatrix
122+
cargo run -p b1display
123+
cargo run -p c1minimal
124+
```
125+
126+
## Building the firmware
127+
128+
Dependencies: Rust
129+
130+
Prepare Rust toolchain (once):
131+
132+
```sh
133+
rustup target install thumbv6m-none-eabi
134+
cargo install flip-link
135+
```
136+
137+
Build:
138+
139+
```sh
140+
cargo make --cwd ledmatrix
141+
cargo make --cwd b1display
142+
cargo make --cwd c1minimal
143+
```
144+
145+
Generate the UF2 update file:
146+
147+
```sh
148+
cargo make --cwd ledmatrix uf2
149+
cargo make --cwd b1display uf2
150+
cargo make --cwd c1minimal uf2
151+
```
152+
153+
## Building the Application
154+
155+
Dependencies: Rust, pkg-config, libudev
156+
157+
Currently have to specify the build target because it's not possible to specify a per package build target.
158+
Tracking issue: https://github.com/rust-lang/cargo/issues/9406
159+
160+
```
161+
# Build it
162+
> cargo make --cwd inputmodule-control
163+
164+
# Build and run it, showing the tool version
165+
> cargo make --cwd inputmodule-control run -- --version
166+
```
167+
168+
### Check the firmware version of the device
169+
170+
###### In-band using commandline
171+
172+
```sh
173+
> inputmodule-control b1-display --version
174+
Device Version: 0.1.3
175+
```
176+
177+
###### By looking at the USB descriptor
178+
179+
On Linux:
180+
181+
```sh
182+
> lsusb -d 32ac: -v 2> /dev/null | grep -P 'ID 32ac|bcdDevice'
183+
Bus 003 Device 078: ID 32ac:0021 Framework Laptop 16 B1 Display
184+
bcdDevice 0.10
185+
```
186+
187+
## Rust Panic
188+
189+
When the Rust code panics, the RP2040 resets itself into bootloader mode.
190+
This means a new firmware can be written to overwrite the old one.
191+
192+
Additionally the panic message is written to XIP RAM, which can be read with [picotool](https://github.com/raspberrypi/picotool):
193+
194+
```sh
195+
sudo picotool save -r 0x15000000 0x15004000 message.bin
196+
strings message.bin | head
197+
```

python/framework16_inputmodules/ledmatrix_control.py renamed to python/framework16_inputmodules/cli.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
from serial.tools import list_ports
77

88
# Local dependencies
9-
import gui
10-
from inputmodule import (
9+
from framework16_inputmodules import gui
10+
from framework16_inputmodules.inputmodule import (
1111
INPUTMODULE_PIDS,
1212
send_command,
1313
get_version,
@@ -18,15 +18,15 @@
1818
GameOfLifeStartParam,
1919
GameControlVal,
2020
)
21-
from gui.games import (
21+
from framework16_inputmodules.gui.games import (
2222
snake,
2323
snake_embedded,
2424
pong_embedded,
2525
game_of_life_embedded,
2626
wpm_demo,
2727
)
28-
from gui.ledmatrix import random_eq, clock, blinking
29-
from inputmodule.ledmatrix import (
28+
from framework16_inputmodules.gui.ledmatrix import random_eq, clock, blinking
29+
from framework16_inputmodules.inputmodule.ledmatrix import (
3030
eq,
3131
breathing,
3232
camera,
@@ -44,7 +44,7 @@
4444
image_bl,
4545
image_greyscale,
4646
)
47-
from inputmodule.b1display import (
47+
from framework16_inputmodules.inputmodule.b1display import (
4848
b1image_bl,
4949
invert_screen_cmd,
5050
screen_saver_cmd,
@@ -56,14 +56,18 @@
5656
display_on_cmd,
5757
display_string,
5858
)
59-
from inputmodule.c1minimal import set_color, get_color, RGB_COLORS
59+
from framework16_inputmodules.inputmodule.c1minimal import (
60+
set_color,
61+
get_color,
62+
RGB_COLORS,
63+
)
6064

6165
# Optional dependencies:
6266
# from PIL import Image
6367
# import PySimpleGUI as sg
6468

6569

66-
def main():
70+
def main_cli():
6771
parser = argparse.ArgumentParser()
6872
parser.add_argument(
6973
"-l", "--list", help="List all compatible devices", action="store_true"
@@ -387,5 +391,11 @@ def print_devs(ports):
387391
print(f" Product: {port.product}")
388392

389393

394+
def main_gui():
395+
devices = find_devs() # show=False, verbose=False)
396+
print("Found {} devices".format(len(devices)))
397+
gui.run_gui(devices)
398+
399+
390400
if __name__ == "__main__":
391-
main()
401+
main_cli()

python/framework16_inputmodules/gui/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,18 @@
44

55
import PySimpleGUI as sg
66

7-
from inputmodule import (
7+
from framework16_inputmodules.inputmodule import (
88
send_command,
99
get_version,
1010
brightness,
1111
get_brightness,
1212
bootloader,
1313
CommandVals,
1414
)
15-
from gui.games import snake
16-
from gui.ledmatrix import countdown, random_eq, clock
17-
from gui.gui_threading import stop_thread, is_dev_disconnected
18-
from inputmodule.ledmatrix import (
15+
from framework16_inputmodules.gui.games import snake
16+
from framework16_inputmodules.gui.ledmatrix import countdown, random_eq, clock
17+
from framework16_inputmodules.gui.gui_threading import stop_thread, is_dev_disconnected
18+
from framework16_inputmodules.inputmodule.ledmatrix import (
1919
percentage,
2020
pattern,
2121
animate,

python/framework16_inputmodules/gui/games.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,18 @@
44
import time
55
import threading
66

7-
from inputmodule import GameControlVal, send_command, CommandVals, Game
8-
from inputmodule.ledmatrix import show_string, WIDTH, HEIGHT, render_matrix
7+
from framework16_inputmodules.inputmodule import (
8+
GameControlVal,
9+
send_command,
10+
CommandVals,
11+
Game,
12+
)
13+
from framework16_inputmodules.inputmodule.ledmatrix import (
14+
show_string,
15+
WIDTH,
16+
HEIGHT,
17+
render_matrix,
18+
)
919

1020
# Constants
1121
ARG_UP = 0

python/framework16_inputmodules/gui/ledmatrix.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,18 @@
22
import time
33
import random
44

5-
from gui.gui_threading import reset_thread, is_thread_stopped, is_dev_disconnected
6-
from inputmodule.ledmatrix import light_leds, show_string, eq, breathing
7-
from inputmodule import brightness
5+
from framework16_inputmodules.gui.gui_threading import (
6+
reset_thread,
7+
is_thread_stopped,
8+
is_dev_disconnected,
9+
)
10+
from framework16_inputmodules.inputmodule.ledmatrix import (
11+
light_leds,
12+
show_string,
13+
eq,
14+
breathing,
15+
)
16+
from framework16_inputmodules.inputmodule import brightness
817

918

1019
def countdown(dev, seconds):

python/framework16_inputmodules/inputmodule/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import serial
33

44
# TODO: Make independent from GUI
5-
from gui.gui_threading import disconnect_dev
5+
from framework16_inputmodules.gui.gui_threading import disconnect_dev
66

77
FWK_MAGIC = [0x32, 0xAC]
88
FWK_VID = 0x32AC

python/framework16_inputmodules/inputmodule/b1display.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import sys
22

3-
from inputmodule import send_command, CommandVals, FWK_MAGIC
3+
from framework16_inputmodules.inputmodule import send_command, CommandVals, FWK_MAGIC
44

55
B1_WIDTH = 300
66
B1_HEIGHT = 400

python/framework16_inputmodules/inputmodule/c1minimal.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from inputmodule import send_command, CommandVals
1+
from framework16_inputmodules.inputmodule import send_command, CommandVals
22

33
RGB_COLORS = ["white", "black", "red", "green", "blue", "cyan", "yellow", "purple"]
44

python/framework16_inputmodules/inputmodule/ledmatrix.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import serial
44

5-
import font
6-
from inputmodule import (
5+
from framework16_inputmodules import font
6+
from framework16_inputmodules.inputmodule import (
77
send_command,
88
CommandVals,
99
PatternVals,

0 commit comments

Comments
 (0)