From a17e1e0c69f8ca442a60a9814f2a7399704c490e Mon Sep 17 00:00:00 2001 From: nitko12 Date: Mon, 21 Sep 2020 13:24:50 +0200 Subject: [PATCH] Added maze example + fixes. --- .../05-Inkplate_SD_BMP_pictures.ino | 9 +- .../4-Inkplate_Mandelbrot_set.ino | 74 ++++++ .../5-Inkplate_Maze_Generator.ino | 122 ++++++++++ src/Inkplate.cpp | 211 +++++++++--------- src/Inkplate.h | 12 +- src/include/ImageBMP.cpp | 16 +- 6 files changed, 319 insertions(+), 125 deletions(-) create mode 100644 examples/4. Others/4-Inkplate_Mandelbrot_set/4-Inkplate_Mandelbrot_set.ino create mode 100644 examples/4. Others/5-Inkplate_Maze_Generator/5-Inkplate_Maze_Generator.ino diff --git a/examples/2. Advanced Inkplate Features/05-Inkplate_SD_BMP_pictures/05-Inkplate_SD_BMP_pictures.ino b/examples/2. Advanced Inkplate Features/05-Inkplate_SD_BMP_pictures/05-Inkplate_SD_BMP_pictures.ino index f0e2108..99ac26b 100644 --- a/examples/2. Advanced Inkplate Features/05-Inkplate_SD_BMP_pictures/05-Inkplate_SD_BMP_pictures.ino +++ b/examples/2. Advanced Inkplate Features/05-Inkplate_SD_BMP_pictures/05-Inkplate_SD_BMP_pictures.ino @@ -21,11 +21,10 @@ 15 July 2020 by e-radionica.com */ -#include "Inkplate.h" //Include Inkplate library to the sketch -#include "SdFat.h" //Include library for SD card -Inkplate display( - INKPLATE_1BIT); // Create an object on Inkplate library and also set library into 1 Bit mode (BW) -SdFile file; // Create SdFile object used for accessing files on SD card +#include "Inkplate.h" //Include Inkplate library to the sketch +#include "SdFat.h" //Include library for SD card +Inkplate display(INKPLATE_3BIT); // Create an object on Inkplate library and also set library into 1 Bit mode (BW) +SdFile file; // Create SdFile object used for accessing files on SD card void setup() { diff --git a/examples/4. Others/4-Inkplate_Mandelbrot_set/4-Inkplate_Mandelbrot_set.ino b/examples/4. Others/4-Inkplate_Mandelbrot_set/4-Inkplate_Mandelbrot_set.ino new file mode 100644 index 0000000..d5708d3 --- /dev/null +++ b/examples/4. Others/4-Inkplate_Mandelbrot_set/4-Inkplate_Mandelbrot_set.ino @@ -0,0 +1,74 @@ +#include "Inkplate.h" + +#define MAXITERATIONS 150 + +Inkplate display(INKPLATE_1BIT); + +// Takes a long time to render, cca 3 minutes + +// Explore different positions to draw +// Some interesting ones can be found here http://www.cuug.ab.ca/dewara/mandelbrot/Mandelbrowser.html +double xFrom = -0.7423, xTo = -0.8463; +double yFrom = 0.1092, yTo = 0.2102; + +void setup() +{ + Serial.begin(115200); + display.begin(); +} + +void loop() +{ + display.clearDisplay(); + for (int j = 0; j < 600; ++j) + { + for (int i = 0; i < 800; ++i) + display.drawPixel( + i, j, colorAt(xFrom + (double)i * (xTo - xFrom) / 800.0, yFrom + (double)j * (yTo - yFrom) / 600.0)); + // for whole set: + // display.drawPixel(i, j, colorAt(-2.0 + (3.0 * (double)i / 800.0), -1.0 + 2.0 * (double)j / 600.0)); + Serial.println(j); + } + display.display(); + delay(5000); +} + +struct complex +{ + double re; + double im; +}; + +void addComplex(struct complex *z, struct complex *c) +{ + z->re += c->re; + z->im += c->im; +} + +void squareComplex(struct complex *z) +{ + double re = z->re; + double im = z->im; + z->re = re * re - im * im; + z->im = 2 * re * im; +} + +double modulusComplexSqr(struct complex *z) +{ + return z->re * z->re + z->im * z->im; +} + + +uint8_t colorAt(double x, double y) +{ + struct complex z = {0.0, 0.0}; + struct complex c = {x, y}; + + int i; + for (i = 0; i < MAXITERATIONS && modulusComplexSqr(&z) <= 4.0; ++i) + { + squareComplex(&z); + addComplex(&z, &c); + } + return i == MAXITERATIONS; +} \ No newline at end of file diff --git a/examples/4. Others/5-Inkplate_Maze_Generator/5-Inkplate_Maze_Generator.ino b/examples/4. Others/5-Inkplate_Maze_Generator/5-Inkplate_Maze_Generator.ino new file mode 100644 index 0000000..5c2fad7 --- /dev/null +++ b/examples/4. Others/5-Inkplate_Maze_Generator/5-Inkplate_Maze_Generator.ino @@ -0,0 +1,122 @@ +#include "Inkplate.h" + +Inkplate display(INKPLATE_1BIT); + +const int cellSize = 10; + +const int w = 790 / cellSize, h = 590 / cellSize; +char maze[w * h]; + +int dx[] = {-1, 0, 0, 1}; +int dy[] = {0, -1, 1, 0}; + +void setup() +{ + Serial.begin(115200); + display.begin(); + // Generate and display the maze + generateMaze(maze, w, h); + showMaze(maze, w, h); +} + +void loop() +{ +} + +// Display the maze +void showMaze(const char *maze, int width, int height) +{ + for (int y = 0; y < height; y++) + for (int x = 0; x < width; x++) + if (maze[x + y * width] == 1) + for (int i = 0; i < 4; ++i) + { + int xx = x + dx[i]; + int yy = y + dy[i]; + if (0 <= xx && xx < w && 0 <= yy && yy < h && maze[yy * width + xx] == 1) + display.drawLine(3 + x * cellSize + cellSize / 2, 3 + y * cellSize + cellSize / 2, + 3 + x * cellSize + cellSize / 2 + (dx[i] * cellSize / 2), + 3 + y * cellSize + cellSize / 2 + (dy[i] * cellSize / 2), BLACK); + } + + display.display(); +} + +// Carve the maze starting at x, y. +void carveMaze(char *maze, int width, int height, int x, int y) +{ + int x1, y1; + int x2, y2; + int dx, dy; + int dir, count; + + dir = random(4); + count = 0; + while (count < 4) + { + dx = 0; + dy = 0; + switch (dir) + { + case 0: + dx = 1; + break; + case 1: + dy = 1; + break; + case 2: + dx = -1; + break; + default: + dy = -1; + break; + } + x1 = x + dx; + y1 = y + dy; + x2 = x1 + dx; + y2 = y1 + dy; + if (x2 > 0 && x2 < width && y2 > 0 && y2 < height && maze[y1 * width + x1] == 1 && maze[y2 * width + x2] == 1) + { + maze[y1 * width + x1] = 0; + maze[y2 * width + x2] = 0; + x = x2; + y = y2; + dir = random(4); + count = 0; + } + else + { + dir = (dir + 1) % 4; + count += 1; + } + } +} + +// Generate maze in matrix maze with size width, height. +void generateMaze(char *maze, int width, int height) +{ + int x, y; + + // Initialize the maze. + for (x = 0; x < width * height; x++) + { + maze[x] = 1; + } + maze[1 * width + 1] = 0; + + // Seed the random number generator. + srand(time(0)); + + // Carve the maze. + for (y = 1; y < height; y += 2) + { + for (x = 1; x < width; x += 2) + { + carveMaze(maze, width, height, x, y); + } + } + + // Set up the entry and exit. + maze[0 * width + 1] = 0; + maze[(height - 1) * width + (width - 2)] = 0; +} diff --git a/src/Inkplate.cpp b/src/Inkplate.cpp index aebfaa5..49823e1 100644 --- a/src/Inkplate.cpp +++ b/src/Inkplate.cpp @@ -1,94 +1,94 @@ #include "Inkplate.h" #define CL 0x01 -#define CL_SET \ - { \ - GPIO.out_w1ts = CL; \ +#define CL_SET \ + { \ + GPIO.out_w1ts = CL; \ } -#define CL_CLEAR \ - { \ - GPIO.out_w1tc = CL; \ +#define CL_CLEAR \ + { \ + GPIO.out_w1tc = CL; \ } #define CKV 0x01 -#define CKV_SET \ - { \ - GPIO.out1_w1ts.val = CKV; \ +#define CKV_SET \ + { \ + GPIO.out1_w1ts.val = CKV; \ } -#define CKV_CLEAR \ - { \ - GPIO.out1_w1tc.val = CKV; \ +#define CKV_CLEAR \ + { \ + GPIO.out1_w1tc.val = CKV; \ } #define SPH 0x02 -#define SPH_SET \ - { \ - GPIO.out1_w1ts.val = SPH; \ +#define SPH_SET \ + { \ + GPIO.out1_w1ts.val = SPH; \ } -#define SPH_CLEAR \ - { \ - GPIO.out1_w1tc.val = SPH; \ +#define SPH_CLEAR \ + { \ + GPIO.out1_w1tc.val = SPH; \ } #define LE 0x04 -#define LE_SET \ - { \ - GPIO.out_w1ts = LE; \ +#define LE_SET \ + { \ + GPIO.out_w1ts = LE; \ } -#define LE_CLEAR \ - { \ - GPIO.out_w1tc = LE; \ +#define LE_CLEAR \ + { \ + GPIO.out_w1tc = LE; \ } #define OE 0 -#define OE_SET \ - { \ - digitalWriteMCP(OE, HIGH); \ +#define OE_SET \ + { \ + digitalWriteMCP(OE, HIGH); \ } -#define OE_CLEAR \ - { \ - digitalWriteMCP(OE, LOW); \ +#define OE_CLEAR \ + { \ + digitalWriteMCP(OE, LOW); \ } #define GMOD 1 -#define GMOD_SET \ - { \ - digitalWriteMCP(GMOD, HIGH); \ +#define GMOD_SET \ + { \ + digitalWriteMCP(GMOD, HIGH); \ } -#define GMOD_CLEAR \ - { \ - digitalWriteMCP(GMOD, LOW); \ +#define GMOD_CLEAR \ + { \ + digitalWriteMCP(GMOD, LOW); \ } #define SPV 2 -#define SPV_SET \ - { \ - digitalWriteMCP(SPV, HIGH); \ +#define SPV_SET \ + { \ + digitalWriteMCP(SPV, HIGH); \ } -#define SPV_CLEAR \ - { \ - digitalWriteMCP(SPV, LOW); \ +#define SPV_CLEAR \ + { \ + digitalWriteMCP(SPV, LOW); \ } #define WAKEUP 3 -#define WAKEUP_SET \ - { \ - digitalWriteMCP(WAKEUP, HIGH); \ +#define WAKEUP_SET \ + { \ + digitalWriteMCP(WAKEUP, HIGH); \ } -#define WAKEUP_CLEAR \ - { \ - digitalWriteMCP(WAKEUP, LOW); \ +#define WAKEUP_CLEAR \ + { \ + digitalWriteMCP(WAKEUP, LOW); \ } #define PWRUP 4 -#define PWRUP_SET \ - { \ - digitalWriteMCP(PWRUP, HIGH); \ +#define PWRUP_SET \ + { \ + digitalWriteMCP(PWRUP, HIGH); \ } -#define PWRUP_CLEAR \ - { \ - digitalWriteMCP(PWRUP, LOW); \ +#define PWRUP_CLEAR \ + { \ + digitalWriteMCP(PWRUP, LOW); \ } #define VCOM 5 -#define VCOM_SET \ - { \ - digitalWriteMCP(VCOM, HIGH); \ +#define VCOM_SET \ + { \ + digitalWriteMCP(VCOM, HIGH); \ } -#define VCOM_CLEAR \ - { \ - digitalWriteMCP(VCOM, LOW); \ +#define VCOM_CLEAR \ + { \ + digitalWriteMCP(VCOM, LOW); \ } #define GPIO0_ENABLE 8 @@ -198,14 +198,14 @@ void Inkplate::display1b() uint8_t data; uint8_t dram; einkOn(); - cleanFast(0, 1); - cleanFast(1, 16); - cleanFast(2, 1); - cleanFast(0, 11); - cleanFast(2, 1); - cleanFast(1, 16); - cleanFast(2, 1); - cleanFast(0, 11); + cleanFast(0, 1); + cleanFast(1, 16); + cleanFast(2, 1); + cleanFast(0, 11); + cleanFast(2, 1); + cleanFast(1, 16); + cleanFast(2, 1); + cleanFast(0, 11); for (int k = 0; k < 4; ++k) { uint8_t *DMemoryNewPtr = DMemoryNew + 59999; @@ -303,14 +303,14 @@ void Inkplate::display1b() void Inkplate::display3b() { einkOn(); - cleanFast(0, 1); - cleanFast(1, 16); - cleanFast(2, 1); - cleanFast(0, 11); - cleanFast(2, 1); - cleanFast(1, 16); - cleanFast(2, 1); - cleanFast(0, 11); + cleanFast(0, 1); + cleanFast(1, 16); + cleanFast(2, 1); + cleanFast(0, 11); + cleanFast(2, 1); + cleanFast(1, 16); + cleanFast(2, 1); + cleanFast(0, 11); for (int k = 0; k < 8; ++k) { @@ -489,50 +489,50 @@ void Inkplate::cleanFast(uint8_t c, uint8_t rep) } } -//Turn off epaper power supply and put all digital IO pins in high Z state +// Turn off epaper power supply and put all digital IO pins in high Z state void Inkplate::einkOff() { if (getPanelState() == 0) return; - OE_CLEAR; + OE_CLEAR; GMOD_CLEAR; GPIO.out &= ~(DATA | LE | CL); - CKV_CLEAR; + CKV_CLEAR; SPH_CLEAR; SPV_CLEAR; - VCOM_CLEAR; - delay(6); + VCOM_CLEAR; + delay(6); PWRUP_CLEAR; WAKEUP_CLEAR; - delay(50); + delay(50); pinsZstate(); - setPanelState(0); + setPanelState(0); } -//Turn on supply for epaper display (TPS65186) [+15 VDC, -15VDC, +22VDC, -20VDC, +3.3VDC, VCOM] +// Turn on supply for epaper display (TPS65186) [+15 VDC, -15VDC, +22VDC, -20VDC, +3.3VDC, VCOM] void Inkplate::einkOn() { if (getPanelState() == 1) return; WAKEUP_SET; - delay(1); - Wire.beginTransmission(0x48); + delay(1); + Wire.beginTransmission(0x48); Wire.write(0x09); - Wire.write(B00011011); //Power up seq. - Wire.write(B00000000); //Power up delay (3mS per rail) - Wire.write(B00011011); //Power down seq. - Wire.write(B00000000); //Power down delay (6mS per rail) + Wire.write(B00011011); // Power up seq. + Wire.write(B00000000); // Power up delay (3mS per rail) + Wire.write(B00011011); // Power down seq. + Wire.write(B00000000); // Power down delay (6mS per rail) Wire.endTransmission(); - - PWRUP_SET; - - //Enable all rails + + PWRUP_SET; + + // Enable all rails Wire.beginTransmission(0x48); Wire.write(0x01); Wire.write(B00111111); Wire.endTransmission(); - pinsAsOutputs(); + pinsAsOutputs(); LE_CLEAR; OE_CLEAR; CL_CLEAR; @@ -541,11 +541,11 @@ void Inkplate::einkOn() SPV_SET; CKV_CLEAR; OE_CLEAR; - VCOM_SET; - Wire.beginTransmission(0x48); + VCOM_SET; + Wire.beginTransmission(0x48); Wire.write(0x0D); - Wire.write(B10000000); - Wire.endTransmission(); + Wire.write(B10000000); + Wire.endTransmission(); delay(5); Wire.beginTransmission(0x48); @@ -554,11 +554,12 @@ void Inkplate::einkOn() Wire.requestFrom(0x48, 1); setTemperature(Wire.read()); - - pinModeMCP(7, INPUT_PULLUP); - while(!digitalReadMCP(7)); - OE_SET; - setPanelState(1); + + pinModeMCP(7, INPUT_PULLUP); + while (!digitalReadMCP(7)) + ; + OE_SET; + setPanelState(1); } // LOW LEVEL FUNCTIONS @@ -594,7 +595,7 @@ void Inkplate::hscan_start(uint32_t _d) GPIO.out_w1ts = (_d) | CL; GPIO.out_w1tc = DATA | CL; SPH_SET; - CKV_SET; + CKV_SET; } void Inkplate::vscan_end() diff --git a/src/Inkplate.h b/src/Inkplate.h index d329324..8ee580e 100644 --- a/src/Inkplate.h +++ b/src/Inkplate.h @@ -7,9 +7,9 @@ #error "Wrong board selected! Select ESP32 Wrover from board menu!" #endif +#include "SPI.h" #include "include/Graphics.h" #include "include/System.h" -#include "SPI.h" #include "libs/SdFat/SdFat.h" #include "include/defines.h" @@ -19,7 +19,7 @@ extern SdFat sd; class Inkplate : public System, public Graphics { -public: + public: Inkplate(uint8_t _mode); void begin(void); @@ -30,6 +30,7 @@ public: void einkOn(); void einkOff(); + void cleanFast(uint8_t c, uint8_t rep); bool joinAP(const char *ssid, const char *pass) { @@ -44,12 +45,11 @@ public: return NetworkClient::isConnected(); }; -private: + private: void precalculateGamma(uint8_t *c, float gamma); void display1b(); void display3b(); - void cleanFast(uint8_t c, uint8_t rep); void vscan_start(); void vscan_end(); void hscan_start(uint32_t _d = 0); @@ -60,7 +60,9 @@ private: uint8_t _beginDone = 0; - const uint8_t waveform3Bit[8][8] = {{0, 0, 0, 0, 1, 1, 1, 0}, {1, 2, 2, 2, 1, 1, 1, 0}, {0, 1, 2, 1, 1, 2, 1, 0}, {0, 2, 1, 2, 1, 2, 1, 0}, {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0}, {1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}}; + const uint8_t waveform3Bit[8][8] = {{0, 0, 0, 0, 1, 1, 1, 0}, {1, 2, 2, 2, 1, 1, 1, 0}, {0, 1, 2, 1, 1, 2, 1, 0}, + {0, 2, 1, 2, 1, 2, 1, 0}, {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0}, + {1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}}; const uint32_t waveform[50] = { 0x00000008, 0x00000008, 0x00200408, 0x80281888, 0x60A81898, 0x60A8A8A8, 0x60A8A8A8, 0x6068A868, 0x6868A868, 0x6868A868, 0x68686868, 0x6A686868, 0x5A686868, 0x5A686868, 0x5A586A68, 0x5A5A6A68, 0x5A5A6A68, 0x55566A68, diff --git a/src/include/ImageBMP.cpp b/src/include/ImageBMP.cpp index 353bce1..9d88797 100644 --- a/src/include/ImageBMP.cpp +++ b/src/include/ImageBMP.cpp @@ -101,7 +101,7 @@ bool Image::drawBitmapFromSd(SdFile *p, int x, int y, bool dither, bool invert) { int16_t n = ROWSIZE(w, c); p->read(pixelBuffer, n); - displayBmpLine(x, y + bmpHeader.height - i, &bmpHeader, dither, invert); + displayBmpLine(x, y + bmpHeader.height - i - 1, &bmpHeader, dither, invert); } return 1; } @@ -144,7 +144,7 @@ bool Image::drawBitmapFromBuffer(uint8_t *buf, int x, int y, bool dither, bool i for (int i = 0; i < bmpHeader.height; ++i) { memcpy(pixelBuffer, bufferPtr, ROWSIZE(bmpHeader.width, bmpHeader.color)); - displayBmpLine(x, y + bmpHeader.height - i, &bmpHeader, dither, invert); + displayBmpLine(x, y + bmpHeader.height - i - 1, &bmpHeader, dither, invert); bufferPtr += ROWSIZE(bmpHeader.width, bmpHeader.color); } @@ -166,8 +166,7 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d writePixel(x + j, y, (invert ^ (palette[0] < palette[1])) ^ !!(pixelBuffer[j >> 3] & (1 << (7 - (j & 7))))); break; // as for 2 bit, literally cannot find an example online or in PS, so skipped - case 4: - { + case 4: { uint8_t px = pixelBuffer[j >> 1] & (j & 1 ? 0x0F : 0xF0) >> (j & 1 ? 0 : 4); uint8_t val; @@ -183,8 +182,7 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d writePixel(x + j, y, val); break; } - case 8: - { + case 8: { uint8_t px = pixelBuffer[j]; uint8_t val; @@ -200,8 +198,7 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d writePixel(x + j, y, val); break; } - case 16: - { + case 16: { uint16_t px = ((uint16_t)pixelBuffer[(j << 1) | 1] << 8) | pixelBuffer[(j << 1)]; uint8_t r = (px & 0x7C00) >> 7; @@ -222,8 +219,7 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d writePixel(x + j, y, val); break; } - case 24: - { + case 24: { uint8_t r = pixelBuffer[j * 3]; uint8_t g = pixelBuffer[j * 3 + 1]; uint8_t b = pixelBuffer[j * 3 + 2];