|
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