|
@@ -0,0 +1,200 @@
|
|
1
|
+#!/usr/bin/python
|
|
2
|
+
|
|
3
|
+# Testing the LED lights
|
|
4
|
+
|
|
5
|
+import random
|
|
6
|
+import time
|
|
7
|
+import argparse
|
|
8
|
+import struct
|
|
9
|
+
|
|
10
|
+# Set up command-line operations
|
|
11
|
+parser = argparse.ArgumentParser(description="Make the LPD8806 LEDs glow random colors")
|
|
12
|
+parser.add_argument('-s', '--step', type=int, default=1,
|
|
13
|
+ help='Amount in RGB to increase/decrease at every interval. Lower value '
|
|
14
|
+ 'will be slower and smoother, higher will be faster but jumpier.')
|
|
15
|
+parser.add_argument('-i', '--interval', type=float, default=0.1,
|
|
16
|
+ help='Time in seconds to wait between every interval (step). Lower value '
|
|
17
|
+ 'will be slower and more jagged and jumpy, higher will be faster and smoother.')
|
|
18
|
+parser.add_argument('-g', '--glow_pause', type=float, default=2,
|
|
19
|
+ help='Time in seconds to wait at maximum glow')
|
|
20
|
+parser.add_argument('-d', '--dim_pause', type=float, default=1,
|
|
21
|
+ help='Time in seconds to wait while LEDs are off')
|
|
22
|
+parser.add_argument('-m', '--minimum', type=int, default=0,
|
|
23
|
+ help='The minimum value to fade out to, the "dim" setting. (0 - 255)')
|
|
24
|
+parser.add_argument('-n', '--no_dim', action='store_true', default=False,
|
|
25
|
+ help='Instead of fading out to a dim minimum, only pause at max glow'
|
|
26
|
+ 'and then fade to the next random color.')
|
|
27
|
+parser.add_argument('-v', '--verbose', action='store_true', default=False,
|
|
28
|
+ help='Display debug printouts of the current and target colors at every '
|
|
29
|
+ 'sub-interval')
|
|
30
|
+
|
|
31
|
+# Set the spi file
|
|
32
|
+dev = "/dev/spidev0.0"
|
|
33
|
+
|
|
34
|
+# Open SPI device
|
|
35
|
+spidev = file(dev, "wb")
|
|
36
|
+
|
|
37
|
+# Number of LEDs in my strip
|
|
38
|
+height = 32
|
|
39
|
+
|
|
40
|
+# Calculate gamma correction table. This includes
|
|
41
|
+# LPD8806-specific conversion (7-bit color w/high bit set).
|
|
42
|
+gamma = bytearray(256)
|
|
43
|
+for i in range(256):
|
|
44
|
+ gamma[i] = 0x80 | int(pow(float(i) / 255.0, 2.5) * 127.0 + 0.5)
|
|
45
|
+
|
|
46
|
+# Create a bytearray to display
|
|
47
|
+# R, G, B byte per pixel, plus extra '0' byte at end for latch.
|
|
48
|
+step = parser.parse_args().step
|
|
49
|
+interval = parser.parse_args().interval
|
|
50
|
+glow_pause = parser.parse_args().glow_pause
|
|
51
|
+dim_pause = parser.parse_args().dim_pause
|
|
52
|
+minimum = parser.parse_args().minimum
|
|
53
|
+no_dim = parser.parse_args().no_dim
|
|
54
|
+verbose = parser.parse_args().verbose
|
|
55
|
+if verbose: print "Allocating..."
|
|
56
|
+array = bytearray(height * 3 + 1)
|
|
57
|
+
|
|
58
|
+def test_gamma(strip, gamma):
|
|
59
|
+ # First a test:
|
|
60
|
+ for i, color in enumerate(gamma):
|
|
61
|
+ print str(i) + ": " + str(color) + " (" + repr(struct.pack('>B', color)) + ")"
|
|
62
|
+ for y in range(height):
|
|
63
|
+ value = [0]*3
|
|
64
|
+ y3 = y * 3
|
|
65
|
+ strip[y3] = color
|
|
66
|
+ strip[y3 + 1] = color
|
|
67
|
+ strip[y3 + 2] = color
|
|
68
|
+ spidev.write(strip)
|
|
69
|
+ spidev.flush()
|
|
70
|
+ time.sleep(0.5)
|
|
71
|
+
|
|
72
|
+def rgb_to_gamma(color, gamma):
|
|
73
|
+ """Translate normal RGB colors to the first occurrence in the gamma array
|
|
74
|
+
|
|
75
|
+ The LPD8806 skips over a lot of RGB colors by using the same color at many
|
|
76
|
+ different indices. This method just takes a gamma index: color, finds what
|
|
77
|
+ color byte the gamma array contains at that index, and then searches the
|
|
78
|
+ array from the beginning to find the first occurrence of that color byte
|
|
79
|
+ and returns that gamma index instead. That way, all representable colors can
|
|
80
|
+ be reduced to the indexes in gamma that start new colors, thereby making
|
|
81
|
+ equivalencies between colors that are actually equal a lot easier.
|
|
82
|
+
|
|
83
|
+ Arguments:
|
|
84
|
+ color -- triple tuple representing RGB respectively for the desired color
|
|
85
|
+ gamma -- bytearray of 256 corrected colors to choose from for the LPD8806 LEDs
|
|
86
|
+
|
|
87
|
+ """
|
|
88
|
+ gamma_r = gamma.index(struct.pack('>B', gamma[color[0]]))
|
|
89
|
+ gamma_g = gamma.index(struct.pack('>B', gamma[color[1]]))
|
|
90
|
+ gamma_b = gamma.index(struct.pack('>B', gamma[color[2]]))
|
|
91
|
+ return gamma_r, gamma_g, gamma_b
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+def get_current_color(strip, gamma):
|
|
95
|
+ """Extract gamma-indexed RBG tuple from the first LED in the strip.
|
|
96
|
+
|
|
97
|
+ The strip is ordered in GRB format, but this method returns RGB. Also note
|
|
98
|
+ that this method only checks the color of the first LED, and does not take
|
|
99
|
+ into account the rest of the strip's colors.
|
|
100
|
+
|
|
101
|
+ Arguments:
|
|
102
|
+ strip -- bytearray of the latest written colors to the LED strip. Array is
|
|
103
|
+ three times the length of the strip plus one for '0' byte latch.
|
|
104
|
+ gamma -- bytearray of 256 corrected colors to choose from for the LPD8806 LEDs
|
|
105
|
+
|
|
106
|
+ """
|
|
107
|
+ gamma_r = gamma.index(struct.pack('>B', strip[1]))
|
|
108
|
+ gamma_g = gamma.index(struct.pack('>B', strip[0]))
|
|
109
|
+ gamma_b = gamma.index(struct.pack('>B', strip[2]))
|
|
110
|
+ return gamma_r, gamma_g, gamma_b
|
|
111
|
+
|
|
112
|
+def fade_to_color(color, strip, gamma, step=1, interval=0.1, pause=1):
|
|
113
|
+ """Increment/Decrement LED colors to the target color and pause.
|
|
114
|
+
|
|
115
|
+ Will convert the RGB color to the gamma-indexed version internally.
|
|
116
|
+
|
|
117
|
+ Arguments:
|
|
118
|
+ color -- triple tuple representing RGB respectively for the desired color
|
|
119
|
+ strip -- bytearray of the latest written colors to the LED strip. Array is
|
|
120
|
+ three times the length of the strip plus one for '0' byte latch.
|
|
121
|
+ gamma -- bytearray of 256 corrected colors to choose from for the LPD8806 LEDs
|
|
122
|
+
|
|
123
|
+ Keyword Arguments:
|
|
124
|
+ step -- amount in RGB to increment/decrement at each interval (default 1)
|
|
125
|
+ interval -- time in seconds between each increment/decrement (default 0.1)
|
|
126
|
+ pause -- time in seconds to wait once fade is complete (default 1)
|
|
127
|
+
|
|
128
|
+ """
|
|
129
|
+ if verbose: print "color desired: " + str(color)
|
|
130
|
+ # Convert color to a gamma-indexed value that this method will certainly reach
|
|
131
|
+ color = rgb_to_gamma(color, gamma)
|
|
132
|
+ if verbose: print "gamma-indexed color: " + str(color)
|
|
133
|
+ strip_length = (len(strip) - 1) / 3
|
|
134
|
+ current = get_current_color(strip, gamma)
|
|
135
|
+ counter = 0
|
|
136
|
+ while (current != color):
|
|
137
|
+ # Near the end of the gamma spectrum, some colors are missing, so skip over
|
|
138
|
+ # them if they are encountered.
|
|
139
|
+ skip_nums = [234, 235, 242, 243, 248, 249, 252, 253]
|
|
140
|
+ skip_g = 1
|
|
141
|
+ skip_r = 1
|
|
142
|
+ skip_b = 1
|
|
143
|
+ if current[1] in skip_nums: skip_g = 2
|
|
144
|
+ if current[0] in skip_nums: skip_r = 2
|
|
145
|
+ if current[2] in skip_nums: skip_b = 2
|
|
146
|
+ # Fill strip with next color
|
|
147
|
+ for y in range(strip_length):
|
|
148
|
+ y3 = y * 3
|
|
149
|
+ strip[y3] = gamma[current[1]] + \
|
|
150
|
+ (cmp(color[1], current[1]) * skip_g)
|
|
151
|
+ strip[y3 + 1] = gamma[current[0]] + \
|
|
152
|
+ (cmp(color[0], current[0]) * skip_r)
|
|
153
|
+ strip[y3 + 2] = gamma[current[2]] + \
|
|
154
|
+ (cmp(color[2], current[2]) * skip_b)
|
|
155
|
+ # Increment counter. If at next step, then write to spi and wait
|
|
156
|
+ counter = counter + 1
|
|
157
|
+ if counter % step == 0:
|
|
158
|
+ spidev.write(strip)
|
|
159
|
+ spidev.flush()
|
|
160
|
+ time.sleep(interval)
|
|
161
|
+ # Update the current color for the while condition comparison
|
|
162
|
+ current = get_current_color(strip, gamma)
|
|
163
|
+ if verbose: print str(current) + " | " + str(color)
|
|
164
|
+
|
|
165
|
+# Now write to the spi port!
|
|
166
|
+if verbose: print "Displaying..."
|
|
167
|
+
|
|
168
|
+# Firstly, clear the strip and set array to values that are known
|
|
169
|
+for y in range(height):
|
|
170
|
+ value = [0]*3
|
|
171
|
+ y3 = y * 3
|
|
172
|
+ array[y3] = gamma[value[1]]
|
|
173
|
+ array[y3 + 1] = gamma[value[0]]
|
|
174
|
+ array[y3 + 2] = gamma[value[2]]
|
|
175
|
+spidev.write(array)
|
|
176
|
+spidev.flush()
|
|
177
|
+
|
|
178
|
+# Now, glow
|
|
179
|
+while True:
|
|
180
|
+ color = tuple([random.randint(0, len(gamma)-1) for x in range(3)])
|
|
181
|
+ # Wrap in try/except block for graceful exiting via KeyboardInterrupt
|
|
182
|
+ try:
|
|
183
|
+ fade_to_color(color, array, gamma, step=step,
|
|
184
|
+ interval=interval, pause=glow_pause)
|
|
185
|
+ time.sleep(glow_pause)
|
|
186
|
+ if not no_dim:
|
|
187
|
+ fade_to_color((minimum, minimum, minimum), array, gamma, step=step,
|
|
188
|
+ interval=interval, pause=dim_pause)
|
|
189
|
+ time.sleep(dim_pause)
|
|
190
|
+ except KeyboardInterrupt:
|
|
191
|
+ # Clear out array
|
|
192
|
+ for y in range(height):
|
|
193
|
+ value = [0]*3
|
|
194
|
+ y3 = y * 3
|
|
195
|
+ array[y3] = gamma[value[1]]
|
|
196
|
+ array[y3 + 1] = gamma[value[0]]
|
|
197
|
+ array[y3 + 2] = gamma[value[2]]
|
|
198
|
+ spidev.write(array)
|
|
199
|
+ spidev.flush()
|
|
200
|
+ exit(0)
|