muwerk mupplet Display Library
muwerk applets; mupplets: functional units that support specific hardware or reusable applications
Loading...
Searching...
No Matches
max72xx_matrix.h
1// max72xx_matrix.h - 8x8 led matrix controller by MAX7219 or MAX7221 module driver
2
3#pragma once
4
5#include <Adafruit_GFX.h>
6#include "max72xx.h"
7
8namespace ustd {
9
19class Max72xxMatrix : public Adafruit_GFX {
20 private:
21 // hardware configuration
22 Max72XX driver;
23
24 // runtime - pixel and module logic
25 uint8_t hDisplays;
26 uint8_t *bitmap;
27 uint8_t bitmapSize;
28 uint8_t *matrixPosition;
29 uint8_t *matrixRotation;
30 uint8_t *outputBuffer;
31
32 public:
43 Max72xxMatrix(uint8_t csPin, uint8_t hDisplays = 1, uint8_t vDisplays = 1, uint8_t rotation = 0)
44 : Adafruit_GFX(hDisplays << 3, vDisplays << 3), driver(csPin, hDisplays * vDisplays),
45 hDisplays(hDisplays) {
46 uint8_t displays = hDisplays * vDisplays;
47 bitmapSize = displays * 8;
48 bitmap = (uint8_t *)malloc(bitmapSize + (4 * displays));
49 matrixPosition = bitmap + bitmapSize;
50 matrixRotation = matrixPosition + displays;
51 outputBuffer = matrixRotation + displays;
52
53 for (uint8_t display = 0; display < displays; display++) {
54 matrixPosition[display] = display;
55 matrixRotation[display] = rotation;
56 }
57 }
58
59 virtual ~Max72xxMatrix() {
60 free(bitmap);
61 }
62
65 void begin() {
66 if (bitmap != nullptr) {
67 // Initialize hardware
68 driver.begin();
69 driver.setTestMode(false);
70 driver.setScanLimit(8);
71 driver.setDecodeMode(B00000000);
72
73 // Clear the display
74 fillScreen(0);
75 write();
76 }
77 }
78
83 inline void setPowerSave(bool powersave) {
84 driver.setPowerSave(powersave);
85 }
86
90 inline void setIntensity(uint8_t intensity) {
91 driver.setIntensity(intensity);
92 }
93
98 inline void setTestMode(bool testmode) {
99 driver.setTestMode(testmode);
100 }
101
108 void write() {
109 if (bitmap != nullptr) {
110 for (uint8_t opcode = Max72XX::digit7; opcode >= Max72XX::digit0; opcode--) {
111 uint16_t endOffset = opcode - Max72XX::digit0;
112 uint16_t startOffset = bitmapSize + endOffset;
113 uint8_t *pPtr = outputBuffer;
114 do {
115 startOffset -= 8;
116 pPtr[0] = opcode;
117 pPtr[1] = bitmap[startOffset];
118 pPtr += 2;
119 } while (startOffset > endOffset);
120 driver.sendBlock(outputBuffer, bitmapSize / 4);
121 }
122 }
123 }
124
130 void setPosition(uint8_t display, uint8_t x, uint8_t y) {
131 if (bitmap != nullptr) {
132 matrixPosition[x + hDisplays * y] = display;
133 }
134 }
135
144 void setRotation(uint8_t display, uint8_t rotation) {
145 if (bitmap != nullptr) {
146 matrixRotation[display] = rotation;
147 }
148 }
149
153 inline bool getTextWrap() const {
154 return wrap;
155 }
156
160 inline int16_t getCursorX() const {
161 return cursor_x;
162 }
163
167 inline int16_t getCursorY() const {
168 return cursor_y;
169 };
170
185 void getCharBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny,
186 int16_t *maxx, int16_t *maxy) {
187 charBounds(c, x, y, minx, miny, maxx, maxy);
188 }
189
206 bool printFormatted(int16_t x, int16_t y, int16_t w, int16_t align, String content,
207 uint8_t baseLine, uint8_t yAdvance = 0) {
208 int16_t xx = 0, yy = 0;
209 uint16_t ww = 0, hh = 0;
210 bool old_wrap = wrap;
211 wrap = false;
212 getTextBounds(content, 0, 0, &xx, &yy, &ww, &hh);
213 wrap = old_wrap;
214
215 switch (align) {
216 default:
217 case 0:
218 // left
219 xx = 0;
220 break;
221 case 1:
222 // center
223 xx = (w - ww) / 2;
224 break;
225 case 2:
226 // right
227 xx = w - ww;
228 break;
229 }
230 if (yAdvance && (hh % yAdvance)) {
231 hh = ((hh / yAdvance) + 1) * yAdvance;
232 }
233 GFXcanvas1 tmp(w, hh);
234 if (gfxFont) {
235 tmp.setFont(gfxFont);
236 }
237 tmp.fillScreen(textbgcolor);
238 tmp.setTextWrap(false);
239 tmp.setCursor(xx, baseLine ? baseLine : -1 * yy);
240 tmp.setTextColor(textcolor, textbgcolor);
241 tmp.print(content);
242 // fillRect(x, y, w, hh, textbgcolor);
243 drawBitmap(x, y, tmp.getBuffer(), w, hh, textcolor, textbgcolor);
244 // set cursor after last printed character
245 setCursor(x + tmp.getCursorX(), y + (baseLine ? baseLine : -1 * yy));
246 return w >= (int16_t)ww;
247 }
248
249 public:
250 // overrides of virtual functions
251
255 virtual void fillScreen(uint16_t color) {
256 if (bitmap != nullptr) {
257 memset(bitmap, color ? 0xff : 0, bitmapSize);
258 }
259 }
260
266 void drawPixel(int16_t xx, int16_t yy, uint16_t color) {
267 if (bitmap == nullptr) {
268 return;
269 }
270
271 // Operating in bytes is faster and takes less code to run. We don't
272 // need values above 200, so switch from 16 bit ints to 8 bit unsigned
273 // ints (bytes).
274 // Keep xx as int16_t so fix 16 panel limit
275 int16_t x = xx;
276 uint8_t y = yy;
277 uint8_t tmp;
278
279 if (rotation) {
280 // Implement Adafruit's rotation.
281 if (rotation >= 2) {
282 // rotation == 2 || rotation == 3
283 x = _width - 1 - x;
284 }
285
286 if (rotation == 1 || rotation == 2) {
287 // rotation == 1 || rotation == 2
288 y = _height - 1 - y;
289 }
290
291 if (rotation & 1) {
292 // rotation == 1 || rotation == 3
293 tmp = x;
294 x = y;
295 y = tmp;
296 }
297 }
298
299 if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
300 // Ignore pixels outside the canvas.
301 return;
302 }
303
304 // Translate the x, y coordinate according to the layout of the
305 // displays. They can be ordered and rotated (0, 90, 180, 270).
306
307 uint8_t display = matrixPosition[(x >> 3) + hDisplays * (y >> 3)];
308 x &= 0b111;
309 y &= 0b111;
310
311 uint8_t r = matrixRotation[display];
312 if (r >= 2) {
313 // 180 or 270 degrees
314 x = 7 - x;
315 }
316 if (r == 1 || r == 2) {
317 // 90 or 180 degrees
318 y = 7 - y;
319 }
320 if (r & 1) {
321 // 90 or 270 degrees
322 tmp = x;
323 x = y;
324 y = tmp;
325 }
326
327 uint8_t d = display / hDisplays;
328 x += (display - d * hDisplays) << 3; // x += (display % hDisplays) * 8
329 y += d << 3; // y += (display / hDisplays) * 8
330
331 // Update the color bit in our bitmap buffer.
332
333 uint8_t *ptr = bitmap + x + WIDTH * (y >> 3);
334 uint8_t val = 1 << (y & 0b111);
335
336 if (color) {
337 *ptr |= val;
338 } else {
339 *ptr &= ~val;
340 }
341 }
342};
343} // namespace ustd
The MAX72XX Controller Class.
Definition: max72xx.h:14
void begin()
Definition: max72xx.h:52
@ digit0
Digit 0.
Definition: max72xx.h:24
@ digit7
Digit 7.
Definition: max72xx.h:31
void setPowerSave(bool powersave)
Definition: max72xx.h:93
void setIntensity(uint8_t intensity)
Definition: max72xx.h:78
void setTestMode(bool testmode)
Definition: max72xx.h:104
void sendBlock(uint8_t *buffer, uint8_t size)
Definition: max72xx.h:126
void setScanLimit(uint8_t scanlimit)
Definition: max72xx.h:85
void setDecodeMode(uint8_t mode)
Definition: max72xx.h:71
The MAX72XX Matrix Display Class.
Definition: max72xx_matrix.h:19
void setRotation(uint8_t display, uint8_t rotation)
Definition: max72xx_matrix.h:144
void setPosition(uint8_t display, uint8_t x, uint8_t y)
Definition: max72xx_matrix.h:130
void setIntensity(uint8_t intensity)
Definition: max72xx_matrix.h:90
virtual void fillScreen(uint16_t color)
Definition: max72xx_matrix.h:255
void setTestMode(bool testmode)
Definition: max72xx_matrix.h:98
void begin()
Definition: max72xx_matrix.h:65
void write()
Definition: max72xx_matrix.h:108
bool getTextWrap() const
Definition: max72xx_matrix.h:153
int16_t getCursorY() const
Definition: max72xx_matrix.h:167
void drawPixel(int16_t xx, int16_t yy, uint16_t color)
Definition: max72xx_matrix.h:266
int16_t getCursorX() const
Definition: max72xx_matrix.h:160
void getCharBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy)
Definition: max72xx_matrix.h:185
Max72xxMatrix(uint8_t csPin, uint8_t hDisplays=1, uint8_t vDisplays=1, uint8_t rotation=0)
Definition: max72xx_matrix.h:43
void setPowerSave(bool powersave)
Definition: max72xx_matrix.h:83
bool printFormatted(int16_t x, int16_t y, int16_t w, int16_t align, String content, uint8_t baseLine, uint8_t yAdvance=0)
Definition: max72xx_matrix.h:206
The muwerk namespace.
Definition: display_digits_max72xx.h:10