-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcube_control.py
More file actions
executable file
·180 lines (153 loc) · 4.89 KB
/
Copy pathcube_control.py
File metadata and controls
executable file
·180 lines (153 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#!/usr/bin/env python3
"""
Cube Control - Master control script for LED cube
Provides menu system for visualization selection and settings
"""
import os
import sys
# Configure PyOpenGL platform before any OpenGL imports
# EGL is only for Linux - macOS uses native OpenGL
if sys.platform == 'linux':
os.environ['PYOPENGL_PLATFORM'] = 'egl'
import argparse
import time
import atexit
from pathlib import Path
# Import the controller
from cube.controller import CubeController
def main():
parser = argparse.ArgumentParser(
description="LED Cube Control - Master control interface"
)
parser.add_argument(
"--width",
type=int,
default=64,
help="Display width in pixels (default: 64)"
)
parser.add_argument(
"--height",
type=int,
default=64,
help="Display height in pixels (default: 64)"
)
parser.add_argument(
"--fps",
type=int,
default=60,
help="Target frames per second for menu rendering (default: 60)"
)
# Hardware-specific options (only used when not in preview mode)
parser.add_argument(
"--pinout",
type=str,
default="AdafruitMatrixBonnet",
help="Hardware pinout configuration (default: AdafruitMatrixBonnet)"
)
parser.add_argument(
"--num-planes",
type=int,
default=10,
help="Color depth in bit-planes (4-11, default: 10)"
)
parser.add_argument(
"--num-address-lines",
type=int,
default=5,
help="Address lines: 4 for 32-pixel tall, 5 for 64-pixel (default: 5)"
)
parser.add_argument(
"--num-panels",
type=int,
default=4,
help="Number of cube panels/faces (1-6, default: 6)"
)
parser.add_argument(
"--brightness",
type=float,
default=80.0,
help="Default brightness percentage (1-90, default: 60)"
)
parser.add_argument(
"--gamma",
type=float,
default=1.0,
help="Default gamma correction value (0.5-3.0, default: 2.2)"
)
parser.add_argument(
"--scale",
type=int,
default=1,
help="Content scale factor - scales up internal content within fixed window size. "
"scale=2 renders at half resolution and scales up for chunky pixels (default: 1)"
)
parser.add_argument(
"--backend",
type=str,
choices=["auto", "pygame", "pyglet", "piomatter"],
default="auto",
help="Display backend to use: auto, pygame, pyglet, or piomatter (default: auto)",
)
parser.add_argument(
"--ssh-key-hold",
type=float,
default=0.15,
dest="ssh_key_hold_duration",
help="SSH keyboard hold duration in seconds for smooth input (0.05-0.5, default: 0.15)"
)
args = parser.parse_args()
# Validate arguments
if args.num_panels < 1 or args.num_panels > 6:
parser.error("--num-panels must be between 1 and 6")
if args.brightness < 1 or args.brightness > 90:
parser.error("--brightness must be between 1 and 90")
if args.gamma < 0.5 or args.gamma > 3.0:
parser.error("--gamma must be between 0.5 and 3.0")
if args.scale < 1 or args.scale > 20:
parser.error("--scale must be between 1 and 20")
if args.ssh_key_hold_duration < 0.05 or args.ssh_key_hold_duration > 0.5:
parser.error("--ssh-key-hold must be between 0.05 and 0.5")
# Print startup banner
print("=" * 60)
print("LED CUBE CONTROL")
print("=" * 60)
print(f"Window Size: {args.width}×{args.height}")
if args.scale > 1:
render_width = args.width // args.scale
render_height = args.height // args.scale
print(f"Render Resolution: {render_width}×{render_height} (scale {args.scale}x)")
print(f"Target FPS: {args.fps}")
print(f"Default Brightness: {args.brightness}%")
print(f"Default Gamma: {args.gamma}")
print("=" * 60)
print()
# Create and run controller
controller = None
try:
controller = CubeController(
width=args.width,
height=args.height,
num_panels=args.num_panels,
num_address_lines=args.num_address_lines,
fps=args.fps,
default_brightness=args.brightness,
default_gamma=args.gamma,
scale=args.scale,
ssh_key_hold_duration=args.ssh_key_hold_duration,
backend=args.backend,
)
# Register cleanup as atexit handler (safety net)
atexit.register(controller.cleanup)
controller.run()
except KeyboardInterrupt:
print("\n\nShutting down...")
except Exception as e:
print(f"\n\nError: {e}")
import traceback
traceback.print_exc()
finally:
# Always cleanup, even on error
if controller:
controller.cleanup()
if __name__ == "__main__":
main()