|
1 | 1 | # The MIT License (MIT) |
2 | 2 | # |
3 | | -# Copyright (c) 2017 Dave Astels for ZombieWizard |
| 3 | +# Copyright (c) 2017 Dave Astels |
4 | 4 | # |
5 | 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy |
6 | 6 | # of this software and associated documentation files (the "Software"), to deal |
|
34 | 34 |
|
35 | 35 | class DotstarFeatherwing: |
36 | 36 | """Test, Image, and Animation support for the DotStar featherwing""" |
37 | | - |
38 | | - blank_stripe = [(0, 0, 0), |
39 | | - (0, 0, 0), |
40 | | - (0, 0, 0), |
41 | | - (0, 0, 0), |
42 | | - (0, 0, 0), |
43 | | - (0, 0, 0)] |
| 37 | + |
| 38 | + blank_stripe = [(0, 0, 0), |
| 39 | + (0, 0, 0), |
| 40 | + (0, 0, 0), |
| 41 | + (0, 0, 0), |
| 42 | + (0, 0, 0), |
| 43 | + (0, 0, 0)] |
44 | 44 | """A blank stripe, used internally to separate characters as they are shifted onto the display.""" |
45 | | - |
46 | | - font_3 = {' ': [ 0, 0, 0], |
47 | | - 'A': [62, 05, 62], |
48 | | - 'B': [63, 37, 26], |
49 | | - 'C': [30, 33, 18], |
50 | | - 'D': [63, 33, 30], |
51 | | - 'E': [63, 37, 33], |
52 | | - 'F': [63, 5, 1], |
53 | | - 'G': [30, 41, 26], |
54 | | - 'H': [63, 4, 63], |
55 | | - 'I': [33, 63, 33], |
56 | | - 'J': [33, 31, 1], |
57 | | - 'K': [63, 4, 59], |
58 | | - 'L': [63, 32, 32], |
59 | | - 'M': [63, 2, 63], |
60 | | - 'N': [63, 12, 63], |
61 | | - 'O': [30, 33, 30], |
62 | | - 'P': [63, 5, 2], |
63 | | - 'Q': [30, 33, 62], |
64 | | - 'R': [63, 5, 58], |
65 | | - 'S': [18, 37, 26], |
66 | | - 'T': [ 1, 63, 1], |
67 | | - 'U': [31, 32, 63], |
68 | | - 'V': [31, 32, 31], |
69 | | - 'W': [63, 16, 63], |
70 | | - 'X': [59, 4, 59], |
71 | | - 'Y': [ 3, 60, 3], |
72 | | - 'Z': [49, 45, 35], |
73 | | - '0': [30, 33, 30], |
74 | | - '1': [34, 63, 32], |
75 | | - '2': [50, 41, 38], |
76 | | - '3': [33, 37, 26], |
77 | | - '4': [ 7, 4, 63], |
78 | | - '5': [23, 37, 25], |
79 | | - '6': [30, 41, 25], |
80 | | - '7': [49, 9, 7], |
81 | | - '8': [26, 37, 26], |
82 | | - '9': [38, 41, 30], |
83 | | - '!': [ 0, 47, 0], |
84 | | - '?': [ 2, 41, 6], |
85 | | - '.': [ 0, 32, 0], |
86 | | - '-': [ 8, 8, 8], |
87 | | - '_': [32, 32, 32], |
88 | | - '+': [ 8, 28, 8], |
89 | | - '/': [48, 12, 3], |
90 | | - '*': [20, 8, 20], |
91 | | - '=': [20, 20, 20], |
92 | | - 'UNKNOWN': [63, 33, 63] } |
93 | | - """A sample font that uses 3 pixel wide characters.""" |
94 | | - |
95 | | - |
96 | | - def __init__(self, clock, data, brightness=1.0): |
| 45 | + |
| 46 | + def __init__(self, clock, data, brightness=1.0): |
97 | 47 | """Create an interface for the display. |
98 | 48 |
|
99 | 49 | :param pin clock: The clock pin for the featherwing |
100 | 50 | :param pin data: The data pin for the featherwing |
101 | 51 | :param float brightness: Optional brightness (0.0-1.0) that defaults to 1.0 |
102 | 52 | """ |
103 | | - self.rows = 6 |
104 | | - self.columns = 12 |
105 | | - self.display = adafruit_dotstar.DotStar(clock, data, self.rows * self.columns, brightness, False) |
106 | | - |
| 53 | + self.rows = 6 |
| 54 | + self.columns = 12 |
| 55 | + self.display = adafruit_dotstar.DotStar(clock, data, self.rows * self.columns, brightness, False) |
| 56 | + |
| 57 | + |
| 58 | + def clear(self): |
| 59 | + """Clear the display. |
| 60 | + Does NOT update the LEDs |
| 61 | + """ |
| 62 | + self.display.fill((0,0,0)) |
| 63 | + |
| 64 | + |
| 65 | + def fill(self, color): |
| 66 | + """Fills the wing with a color. |
| 67 | + Does NOT update the LEDs. |
| 68 | +
|
| 69 | + :param (int, int, int) color: the color to fill with |
| 70 | + """ |
| 71 | + self.display.fill(color) |
107 | 72 |
|
| 73 | + |
| 74 | + def show(self): |
| 75 | + """Update the LEDs. |
| 76 | + """ |
| 77 | + self.display.show() |
| 78 | + |
| 79 | + |
| 80 | + def set_color(self, row, column, color): |
| 81 | + """Set the color of the specified pixel. |
| 82 | +
|
| 83 | + :param int row: The row (0-5) of the pixel to set |
| 84 | + :param int column: The column (0-11) of the pixel to set |
| 85 | + :param (int, int, int) color: The color to set the pixel to |
| 86 | + """ |
| 87 | + self.display[row * self.columns + column] = color |
| 88 | + |
| 89 | + |
108 | 90 | def shift_into_left(self, stripe): |
109 | 91 | """ Shift a column of pixels into the left side of the display. |
110 | 92 |
|
111 | | - :param [int] stripe: A column of pixel colours |
| 93 | + :param [(int, int, int)] stripe: A column of pixel colors |
112 | 94 | """ |
113 | | - for r in range(self.rows): |
114 | | - rightmost = r * self.columns |
115 | | - for c in range(self.columns - 1): |
116 | | - self.display[rightmost + c] = self.display[rightmost + c + 1] |
117 | | - self.display[rightmost + self.columns - 1] = stripe[r] |
118 | | - self.display.show() |
| 95 | + for r in range(self.rows): |
| 96 | + rightmost = r * self.columns |
| 97 | + for c in range(self.columns - 1): |
| 98 | + self.display[rightmost + c] = self.display[rightmost + c + 1] |
| 99 | + self.display[rightmost + self.columns - 1] = stripe[r] |
| 100 | + self.display.show() |
119 | 101 |
|
120 | 102 |
|
121 | | - def shift_into_right(self, stripe): |
| 103 | + def shift_into_right(self, stripe): |
122 | 104 | """ Shift a column of pixels into the rightside of the display. |
123 | 105 |
|
124 | | - :param [int] stripe: A column of pixel colours |
| 106 | + :param [(int, int, int)] stripe: A column of pixel colors |
125 | 107 | """ |
126 | | - for r in range(self.rows): |
127 | | - leftmost = ((r + 1) * self.columns) - 1 |
128 | | - for c in range(self.columns - 1): |
129 | | - self.display[leftmost - c] = self.display[(leftmost - c) -1] |
130 | | - self.display[(leftmost - self.columns) + 1] = stripe[r] |
131 | | - self.display.show() |
132 | | - |
133 | | - |
134 | | - def number_to_pixels(self, x, colour): |
| 108 | + for r in range(self.rows): |
| 109 | + leftmost = ((r + 1) * self.columns) - 1 |
| 110 | + for c in range(self.columns - 1): |
| 111 | + self.display[leftmost - c] = self.display[(leftmost - c) -1] |
| 112 | + self.display[(leftmost - self.columns) + 1] = stripe[r] |
| 113 | + self.display.show() |
| 114 | + |
| 115 | + |
| 116 | + def number_to_pixels(self, x, color): |
135 | 117 | """Convert an integer (0..63) into an array of 6 pixels. |
136 | 118 |
|
137 | 119 | :param int x: integer to convert into binary pixel values; LSB is topmost. |
138 | | - :param (int) colour: the colour to set "on" pixels to |
| 120 | + :param (int, int, int) color: the color to set "on" pixels to |
139 | 121 | """ |
140 | | - val = x |
141 | | - pixels = [] |
142 | | - for b in range(self.rows): |
143 | | - if val & 1 == 0: |
144 | | - pixels.append((0, 0, 0)) |
145 | | - else: |
146 | | - pixels.append(colour) |
147 | | - val = val >> 1 |
148 | | - return pixels |
149 | | - |
150 | | - |
151 | | - def character_to_numbers(self, font, char): |
| 122 | + val = x |
| 123 | + pixels = [] |
| 124 | + for b in range(self.rows): |
| 125 | + if val & 1 == 0: |
| 126 | + pixels.append((0, 0, 0)) |
| 127 | + else: |
| 128 | + pixels.append(color) |
| 129 | + val = val >> 1 |
| 130 | + return pixels |
| 131 | + |
| 132 | + |
| 133 | + def character_to_numbers(self, font, char): |
152 | 134 | """Convert a letter to the sequence of column values to display. |
153 | 135 |
|
154 | 136 | :param {char -> [int]} font: the font to use to convert characters to glyphs |
155 | 137 | :param char letter: the char to convert |
156 | 138 | """ |
157 | | - return font[letter] |
158 | | - |
| 139 | + return font[char] |
159 | 140 |
|
160 | | - def clear(self): |
161 | | - """Clear the display. |
162 | | - Does NOT update the LEDs |
163 | | - """ |
164 | | - self.display.fill((0,0,0)) |
165 | 141 |
|
166 | | - |
167 | | - def shift_in_character(self, font, c, colour=(0x00, 0x40, 0x00), delay=0.2): |
| 142 | + def shift_in_character(self, font, c, color=(0x00, 0x40, 0x00), delay=0.2): |
168 | 143 | """Shifts a single character onto the display from the right edge. |
169 | 144 |
|
170 | 145 | :param {char -> [int]} font: the font to use to convert characters to glyphs |
171 | 146 | :param char c: the char to convert |
172 | | - :param (int) colour: the color to use for each pixel turned on |
| 147 | + :param (int, int, int) color: the color to use for each pixel turned on |
173 | 148 | :param float delay: the time to wait between shifting in columns |
174 | 149 | """ |
175 | 150 | if c.upper() in font: |
176 | | - matrix = self.character_to_numbers(font, c.upper()) |
177 | | - else: |
178 | | - matrix = self.character_to_numbers(font, 'UNKNOWN') |
179 | | - for stripe in matrix: |
180 | | - self.shift_into_right(self.number_to_pixels(stripe, colour)) |
| 151 | + matrix = self.character_to_numbers(font, c.upper()) |
| 152 | + else: |
| 153 | + matrix = self.character_to_numbers(font, 'UNKNOWN') |
| 154 | + for stripe in matrix: |
| 155 | + self.shift_into_right(self.number_to_pixels(stripe, color)) |
181 | 156 | time.sleep(delay) |
182 | | - self.shift_into_right(self.blank_stripe) |
| 157 | + self.shift_into_right(self.blank_stripe) |
183 | 158 | time.sleep(delay) |
184 | 159 |
|
185 | 160 |
|
186 | | - def shift_in_string(self, font, s, colour=(0x00, 0x40, 0x00), delay=0.2): |
| 161 | + def shift_in_string(self, font, s, color=(0x00, 0x40, 0x00), delay=0.2): |
187 | 162 | """Shifts a string onto the display from the right edge. |
188 | 163 |
|
189 | 164 | :param {char -> [int]} font: the font to use to convert characters to glyphs |
190 | 165 | :param string s: the char to convert |
191 | | - :param (int) colour: the color to use for each pixel turned on |
| 166 | + :param (int, int, int)) color: the color to use for each pixel turned on |
192 | 167 | :param float delay: the time to wait between shifting in columns |
193 | 168 | """ |
194 | | - for c in s: |
195 | | - self.shift_in_character(font, c, colour, delay) |
| 169 | + for c in s: |
| 170 | + self.shift_in_character(font, c, color, delay) |
196 | 171 |
|
197 | | - |
198 | | - # Display an image |
199 | | - def display_image(self, image, colour): |
200 | | - """Display an mono-coloured image. |
| 172 | + |
| 173 | + # Display an image |
| 174 | + def display_image(self, image, color): |
| 175 | + """Display an mono-colored image. |
201 | 176 |
|
202 | 177 | :param [string] image: the textual bitmap, 'X' for set pixels, anything else for others |
203 | | - :param (int) colour: the colour to set "on" pixels to |
| 178 | + :param (int) color: the color to set "on" pixels to |
204 | 179 | """ |
205 | | - self.display_coloured_image(image, {'X': colour}) |
206 | | - |
| 180 | + self.display_colored_image(image, {'X': color}) |
| 181 | + |
207 | 182 |
|
208 | | - def display_coloured_image(self, image, colours): |
209 | | - """Display an multi-coloured image. |
| 183 | + def display_colored_image(self, image, colors): |
| 184 | + """Display an multi-colored image. |
210 | 185 |
|
211 | | - :param [string] image: the textual bitmap, character are looked up in colours for the |
212 | | - corresponding pixel colour, anything not in the map is off |
213 | | - :param {char -> [int]} colours: a map of characters in the image data to colours to use |
| 186 | + :param [string] image: the textual bitmap, character are looked up in colors for the |
| 187 | + corresponding pixel color, anything not in the map is off |
| 188 | + :param {char -> (int, int, int)} colors: a map of characters in the image data to colors to use |
214 | 189 | """ |
215 | | - for r in range(self.rows): |
216 | | - for c in range(self.columns): |
217 | | - index = r * self.columns + ((self.columns - 1) - c) |
218 | | - key = image[r][c] |
219 | | - if key in colours: |
220 | | - self.display[index] = colours[key] |
221 | | - else: |
222 | | - self.display[index] = (0, 0, 0) |
223 | | - self.display.show() |
224 | | - |
225 | | - |
226 | | - def display_animation(self, animation, colours, delay=0.1): |
227 | | - """Display a multi-coloured animation. |
228 | | -
|
229 | | - :param [[string]] animation: a list of textual bitmaps, each as described in display_coloured_image |
230 | | - :param {char -> [int]} colours: a map of characters in the image data to colours to use |
| 190 | + for r in range(self.rows): |
| 191 | + for c in range(self.columns): |
| 192 | + index = r * self.columns + ((self.columns - 1) - c) |
| 193 | + key = image[r][c] |
| 194 | + if key in colors: |
| 195 | + self.display[index] = colors[key] |
| 196 | + else: |
| 197 | + self.display[index] = (0, 0, 0) |
| 198 | + self.display.show() |
| 199 | + |
| 200 | + |
| 201 | + def display_animation(self, animation, colors, count=1, delay=0.1): |
| 202 | + """Display a multi-colored animation. |
| 203 | +
|
| 204 | + :param [[string]] animation: a list of textual bitmaps, each as described in display_colored_image |
| 205 | + :param {char -> (int, int, int)} colors: a map of characters in the image data to colors to use |
231 | 206 | :param float delay: the amount of time (seconds) to wait between frames |
232 | 207 | """ |
233 | | - self.clear() |
234 | | - while True: |
235 | | - for frame in animation: |
236 | | - self.display_coloured_image(frame, colours) |
237 | | - time.sleep(delay) |
238 | | - |
| 208 | + self.clear() |
| 209 | + while count > 0: |
| 210 | + for frame in animation: |
| 211 | + self.display_colored_image(frame, colors) |
| 212 | + time.sleep(delay) |
| 213 | + count = count - 1 |
| 214 | + |
239 | 215 |
|
240 | 216 |
|
241 | 217 |
|
|
0 commit comments