1
1
import time
2
2
from datetime import datetime
3
- #from inputmodule.inputmodule.ledmatrix import LedMatrix, Pattern
3
+ # from inputmodule.inputmodule.ledmatrix import LedMatrix, Pattern
4
+
5
+ FWK_MAGIC = [0x32 , 0xAC ]
6
+ FWK_VID = 0x32AC
7
+ LED_MATRIX_PID = 0x20
8
+ QTPY_PID = 0x001F
9
+ INPUTMODULE_PIDS = [LED_MATRIX_PID , QTPY_PID ]
10
+ RESPONSE_SIZE = 32
11
+
12
+ import serial
4
13
5
14
# TODO: Import
6
15
from enum import IntEnum
16
+
17
+
7
18
class PatternVals (IntEnum ):
19
+ Percentage = 0x00
20
+ Gradient = 0x01
21
+ DoubleGradient = 0x02
22
+ DisplayLotus = 0x03
23
+ ZigZag = 0x04
8
24
FullBrightness = 0x05
25
+ DisplayPanic = 0x06
26
+ DisplayLotus2 = 0x07
27
+
28
+
9
29
class CommandVals (IntEnum ):
10
30
Brightness = 0x00
11
31
Pattern = 0x01
32
+ BootloaderReset = 0x02
33
+ Sleep = 0x03
34
+ Animate = 0x04
35
+ Panic = 0x05
36
+ Draw = 0x06
37
+ StageGreyCol = 0x07
38
+ DrawGreyColBuffer = 0x08
39
+ SetText = 0x09
40
+ StartGame = 0x10
41
+ GameControl = 0x11
42
+ GameStatus = 0x12
43
+ SetColor = 0x13
44
+ DisplayOn = 0x14
45
+ InvertScreen = 0x15
46
+ SetPixelColumn = 0x16
47
+ FlushFramebuffer = 0x17
48
+ ClearRam = 0x18
49
+ ScreenSaver = 0x19
50
+ SetFps = 0x1A
51
+ SetPowerMode = 0x1B
52
+ PwmFreq = 0x1E
53
+ DebugMode = 0x1F
54
+ Version = 0x20
55
+
12
56
13
57
class Pattern :
14
58
width = 9
15
59
height = 34
16
- vals = []
60
+
61
+ def __init__ (self ):
62
+ """Empty pattern with all LEDs off"""
63
+ self ._vals = [[0 for _ in range (self .height )] for _ in range (self .width )]
17
64
18
65
def percentage (p ):
19
- Pattern ()
66
+ """A percentage of LEDs on, increasing vertically from the bottom"""
67
+ pattern = Pattern ()
68
+ pattern ._vals = [
69
+ [(0xFF if (y * 100 / 34 > p ) else 0 ) for y in range (pattern .height )]
70
+ for _ in range (pattern .width )
71
+ ]
72
+ return pattern
20
73
21
74
def from_string (s ):
22
- Pattern ()
75
+ # TODO
76
+ return Pattern ()
23
77
24
78
def set (self , x , y , val ):
25
- pass
79
+ """Set a specific LED to a brightness value"""
80
+ assert val >= 0 and val <= 0xFF
81
+ assert x >= 0 and x <= self .width
82
+ assert y >= 0 and y <= self .height
83
+ self ._vals [x ][y ] = val
84
+
85
+ def to_bw_vals (self ):
86
+ """To list of 39 byte values [Int]"""
87
+ vals = [0x00 for _ in range (39 )]
88
+ for x , col in enumerate (self ._vals ):
89
+ for y , val in enumerate (col ):
90
+ if val == 0xFF :
91
+ i = x + self .width * y
92
+ vals [int (i / 8 )] |= 1 << i % 8
93
+ return vals
94
+
95
+ def to_gray_vals (self ):
96
+ """To [[]]"""
97
+ return self ._vals
98
+
26
99
27
- class InputModule :
100
+ class ModuleNotFoundException ( Exception ) :
28
101
pass
29
102
103
+
30
104
class LedMatrix (object ):
31
- def __init__ (self , name ):
32
- self .name = name
105
+ def __init__ (self , dev_path = None ):
106
+ self .dev_path = dev_path
107
+
108
+ if dev_path is None :
109
+ pass
110
+
33
111
self .fw_version = "0.1.9"
34
112
self .sleeping = True
35
- self .brightness = 100
113
+ # self.brightness = 100
114
+ self .dev_path = "/dev/tty0"
115
+ # self.dev_path = None
116
+ self .dev = None
117
+ # TODO: Check if it's there
118
+ # raise ModuleNotFoundException(f"Module {port} not found")
119
+ if False :
120
+ raise ModuleNotFoundException ("No Module found" )
36
121
37
- def find_all ():
38
- return [1 , 2 ]
122
+ def from_port (port ):
123
+ """Connect to an LED matrix by specifying the serial port name/path"""
124
+ return LedMatrix (port )
125
+
126
+ def left ():
127
+ """Connect to the left LED matrix"""
128
+ # TODO
129
+ raise ModuleNotFoundException ("Left Module not found" )
130
+
131
+ def right ():
132
+ """Connect to the right LED matrix"""
133
+ # TODO
134
+ raise ModuleNotFoundException ("Right Module not found" )
135
+
136
+ def list_ports ():
137
+ """List all serial ports with LED matrices"""
138
+ return ["/dev/ttyACM0" ]
39
139
40
140
def __enter__ (self ):
41
- #print('entering' )
141
+ self . dev = serial . Serial ( self . dev_path , 115200 )
42
142
return self
43
143
44
144
def __exit__ (self , exc_type , exc_val , exc_tb ):
45
- pass
46
- #print('leaving')
145
+ self .dev .close ()
47
146
48
147
def enter_bootloader (self ):
49
- pass
148
+ """Put the module in bootloader mode to update the firmware"""
149
+ self .raw_command (CommandVals .BootloaderReset , [0x00 ])
50
150
51
- def raw_command (self , command , vals ):
52
- pass
151
+ def raw_command (self , command , parameters = [], with_response = False ):
152
+ """Send a raw command with command ID and payload bytes"""
153
+ vals = FWK_MAGIC + [command ] + parameters
154
+ self .dev .write (command )
155
+ if with_response :
156
+ res = self .dev .read (RESPONSE_SIZE )
157
+ return res
53
158
54
159
def set_bw (self , pattern ):
55
- pass
160
+ """Draw a black and white pattern on the LED matrix"""
161
+ vals = pattern .to_bw_vals ()
162
+ self .raw_command (CommandVals .Draw , vals )
56
163
57
164
def set_grayscale (self , pattern ):
58
- pass
165
+ """Draw a greyscale pattern on the LED matrix"""
166
+ for x in range (0 , pattern .width ):
167
+ vals = pattern .to_gray_vals ()[x ]
168
+ self ._send_col (x , vals )
169
+ self ._commit_cols ()
170
+
171
+ def _send_col (self , x , vals ):
172
+ """Stage greyscale values for a single column. Must be committed with commit_cols()"""
173
+ command = FWK_MAGIC + [CommandVals .StageGreyCol , x ] + vals
174
+ self .dev .write (command )
175
+
176
+ def _commit_cols (self ):
177
+ """Commit the changes from sending individual cols with send_col(), displaying the matrix.
178
+ This makes sure that the matrix isn't partially updated."""
179
+ command = FWK_MAGIC + [CommandVals .DrawGreyColBuffer , 0x00 ]
180
+ self .dev .write (command )
59
181
60
182
# TODO: Properties for things like sleeping, brightness, ...
61
183
@property
62
- def radius (self ):
63
- """The radius property."""
64
- print ("Get radius" )
65
- return self ._radius
66
-
67
- @radius .setter
68
- def radius (self , value ):
69
- print ("Set radius" )
70
- self ._radius = value
184
+ def brightness (self ):
185
+ """Get current module brightness"""
186
+ res = self .raw_command (CommandVals .Brightness , with_response = True )
187
+ return int (res [0 ])
71
188
189
+ @brightness .setter
190
+ def brightness (self , value ):
191
+ """Change brightness"""
192
+ self .raw_command (CommandVals .Brightness , [value ])
72
193
73
- #
74
- matrices = LedMatrix .find_all ()
75
- print (f"{ len (matrices )} LED Matrices connected to the system" )
76
194
77
- with LedMatrix ( "COM1" ) as matrix :
195
+ def demo_interaction ( matrix ) :
78
196
print (f"Firmware version: { matrix .fw_version } " )
79
197
80
198
print (f"Sleep status: { matrix .sleeping } " )
81
199
print (f"Going to sleep and back" )
82
200
matrix .sleeping = True
83
201
matrix .sleeping = False
84
202
85
- print (f"Current brightness: { matrix .brightness } " )
203
+ # print(f"Current brightness: {matrix.brightness}")
86
204
print ("Setting 100% brightness" )
87
205
matrix .brightness = 100
88
206
print ("Setting 50% brightness" )
@@ -101,12 +219,12 @@ def radius(self, value):
101
219
print ("Iterating through a couple of built-in patterns, 1s each" )
102
220
pattern_commands = [
103
221
PatternVals .FullBrightness ,
104
- # PatternVals.Gradient,
105
- # PatternVals.DoubleGradient,
106
- # PatternVals.DisplayLotus,
107
- # PatternVals.ZigZag,
108
- # PatternVals.DisplayPanic,
109
- # PatternVals.DisplayLotus2
222
+ PatternVals .Gradient ,
223
+ PatternVals .DoubleGradient ,
224
+ PatternVals .DisplayLotus ,
225
+ PatternVals .ZigZag ,
226
+ PatternVals .DisplayPanic ,
227
+ PatternVals .DisplayLotus2 ,
110
228
]
111
229
for pattern in pattern_commands :
112
230
matrix .raw_command (CommandVals .Pattern , [pattern ])
@@ -136,3 +254,33 @@ def radius(self, value):
136
254
current_time = datetime .now ().strftime ("%H:%M" )
137
255
print ("Current Time =" , current_time )
138
256
matrix .set_bw (Pattern .from_string (current_time ))
257
+
258
+
259
+ def demo ():
260
+ matrices = LedMatrix .list_ports ()
261
+ print (f"{ len (matrices )} LED Matrices connected to the system" )
262
+
263
+ try :
264
+ # Open specific
265
+ with LedMatrix .from_port ("COM1" ) as matrix :
266
+ pass
267
+ except ModuleNotFoundException as e :
268
+ print (e )
269
+
270
+ # Left and right matrix, fails if only one is connected
271
+ try :
272
+ with LedMatrix .left () as left_matrix , LedMatrix .right () as right_matrix :
273
+ print (f"Left: { left_matrix } , Right: { right_matrix } " )
274
+ except ModuleNotFoundException as e :
275
+ print (e )
276
+
277
+ # Choose first available matrix (best if just one is connected)
278
+ try :
279
+ with LedMatrix () as matrix :
280
+ demo_interaction (matrix )
281
+ except ModuleNotFoundException as e :
282
+ print (e )
283
+
284
+
285
+ if __name__ == "__main__" :
286
+ demo ()
0 commit comments