diff --git a/Inkplate.cpp b/Inkplate.cpp index 9139c4b..fdee54b 100644 --- a/Inkplate.cpp +++ b/Inkplate.cpp @@ -10,14 +10,17 @@ SdFat sd(&spi2); //--------------------------STATIC FUNCTIONS-------------------------------------------- //For precise 1uS timing, we cannot use delayMicroseconds(), instead we use ASM with nop command. Initial Z value will be difeerent on different CPU speeds! (for 240 MHz CPU Clock z = 25) -void usleep1() { +void usleep1() +{ int z = 25; - while (z--) { + while (z--) + { asm("NOP"); }; } -void ckvClock() { +void ckvClock() +{ CKV_CLEAR; usleep1(); CKV_SET; @@ -25,12 +28,15 @@ void ckvClock() { } //--------------------------USER FUNCTIONS-------------------------------------------- -Inkplate::Inkplate(uint8_t _mode) : Adafruit_GFX(E_INK_WIDTH, E_INK_HEIGHT) { +Inkplate::Inkplate(uint8_t _mode) : Adafruit_GFX(E_INK_WIDTH, E_INK_HEIGHT) +{ _displayMode = _mode; } -void Inkplate::begin(void) { - if(_beginDone == 1) return; +void Inkplate::begin(void) +{ + if (_beginDone == 1) + return; Wire.begin(); mcp.begin(0); mcp.pinMode(VCOM, OUTPUT); @@ -58,21 +64,23 @@ void Inkplate::begin(void) { pinMode(25, OUTPUT); pinMode(26, OUTPUT); pinMode(27, OUTPUT); //D7 - + //TOUCHPAD PINS mcp.pinMode(10, INPUT); mcp.pinMode(11, INPUT); mcp.pinMode(12, INPUT); - + //Battery voltage Switch MOSFET mcp.pinMode(9, OUTPUT); - - D_memory_new = (uint8_t*)ps_malloc(600 * 100); - _partial = (uint8_t*)ps_malloc(600*100); - _pBuffer = (uint8_t*) ps_malloc(120000); - D_memory4Bit = (uint8_t*)ps_malloc(240000); - if (D_memory_new == NULL || _partial == NULL || _pBuffer == NULL || D_memory4Bit == NULL) { - do { + + D_memory_new = (uint8_t *)ps_malloc(600 * 100); + _partial = (uint8_t *)ps_malloc(600 * 100); + _pBuffer = (uint8_t *)ps_malloc(120000); + D_memory4Bit = (uint8_t *)ps_malloc(240000); + if (D_memory_new == NULL || _partial == NULL || _pBuffer == NULL || D_memory4Bit == NULL) + { + do + { delay(100); } while (true); } @@ -80,37 +88,43 @@ void Inkplate::begin(void) { memset(_partial, 0, 60000); memset(_pBuffer, 0, 120000); memset(D_memory4Bit, 255, 240000); - + //precalculateGamma(gammaLUT, INKPLATE_GAMMA); precalculateGamma(gammaLUT, 1); _beginDone = 1; } //Draw function, used by Adafruit GFX. -void Inkplate::drawPixel(int16_t x0, int16_t y0, uint16_t color) { - if (x0 > 799 || y0 > 599 || x0 < 0 || y0 < 0) return; +void Inkplate::drawPixel(int16_t x0, int16_t y0, uint16_t color) +{ + if (x0 > 799 || y0 > 599 || x0 < 0 || y0 < 0) + return; - switch (_rotation) { - case 1: - _swap_int16_t(x0, y0); - x0 = _width - x0 - 1; - break; - case 2: - x0 = _width - x0 - 1; - y0 = _height - y0 - 1; - break; - case 3: - _swap_int16_t(x0, y0); - y0 = _width - y0 - 1; - break; + switch (_rotation) + { + case 1: + _swap_int16_t(x0, y0); + x0 = _width - x0 - 1; + break; + case 2: + x0 = _width - x0 - 1; + y0 = _height - y0 - 1; + break; + case 3: + _swap_int16_t(x0, y0); + y0 = _width - y0 - 1; + break; } - if (_displayMode == 0) { + if (_displayMode == 0) + { int x = x0 / 8; int x_sub = x0 % 8; uint8_t temp = *(_partial + 100 * y0 + x); //D_memory_new[99 * y0 + x]; *(_partial + 100 * y0 + x) = ~pixelMaskLUT[x_sub] & temp | (color ? pixelMaskLUT[x_sub] : 0); - } else { + } + else + { color &= 7; int x = x0 / 2; int x_sub = x0 % 2; @@ -120,61 +134,75 @@ void Inkplate::drawPixel(int16_t x0, int16_t y0, uint16_t color) { } } -void Inkplate::clearDisplay() { +void Inkplate::clearDisplay() +{ //Clear 1 bit per pixel display buffer - if (_displayMode == 0) memset(_partial, 0, 60000); + if (_displayMode == 0) + memset(_partial, 0, 60000); //Clear 3 bit per pixel display buffer - if (_displayMode == 1) memset(D_memory4Bit, 255, 240000); + if (_displayMode == 1) + memset(D_memory4Bit, 255, 240000); } //Function that displays content from RAM to screen -void Inkplate::display() { - if (_displayMode == 0) display1b(); - if (_displayMode == 1) display3b(); +void Inkplate::display() +{ + if (_displayMode == 0) + display1b(); + if (_displayMode == 1) + display3b(); } -void Inkplate::partialUpdate() { - if(_displayMode == 1) return; - if(_blockPartial == 1) display1b(); +void Inkplate::partialUpdate() +{ + if (_displayMode == 1) + return; + if (_blockPartial == 1) + display1b(); uint16_t _pos = 59999; uint32_t _send; uint8_t data; uint8_t diffw, diffb; uint32_t n = 119999; uint8_t dram; - - for (int i = 0; i < 600; i++) { - for (int j = 0; j < 100; j++) { - diffw = ((*(D_memory_new+_pos))^(*(_partial+_pos)))&(~(*(_partial+_pos))); - diffb = ((*(D_memory_new+_pos))^(*(_partial+_pos)))&((*(_partial+_pos))); - _pos--; - *(_pBuffer+n) = LUTW[diffw>>4] & (LUTB[diffb>>4]); - n--; - *(_pBuffer+n) = LUTW[diffw&0x0F] & (LUTB[diffb&0x0F]); - n--; - } - } - + + for (int i = 0; i < 600; i++) + { + for (int j = 0; j < 100; j++) + { + diffw = ((*(D_memory_new + _pos)) ^ (*(_partial + _pos))) & (~(*(_partial + _pos))); + diffb = ((*(D_memory_new + _pos)) ^ (*(_partial + _pos))) & ((*(_partial + _pos))); + _pos--; + *(_pBuffer + n) = LUTW[diffw >> 4] & (LUTB[diffb >> 4]); + n--; + *(_pBuffer + n) = LUTW[diffw & 0x0F] & (LUTB[diffb & 0x0F]); + n--; + } + } + einkOn(); - for (int k = 0; k < 5; k++) { + for (int k = 0; k < 5; k++) + { vscan_start(); n = 119999; - for (int i = 0; i < 600; i++) { - data = *(_pBuffer + n); + for (int i = 0; i < 600; i++) + { + data = *(_pBuffer + n); + _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); + hscan_start(_send); + n--; + for (int j = 0; j < 199; j++) + { + data = *(_pBuffer + n); _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - hscan_start(_send); - n--; - for (int j = 0; j < 199; j++) { - data = *(_pBuffer + n); - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; - GPIO.out_w1tc = DATA | CL; - n--; + GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1tc = DATA | CL; + n--; } - GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - vscan_end(); + vscan_end(); } delayMicroseconds(230); } @@ -214,53 +242,63 @@ void Inkplate::partialUpdate() { vscan_start(); einkOff(); einkOff(); - for(int i = 0; i<60000; i++) { - *(D_memory_new+i) &= *(_partial+i); - *(D_memory_new+i) |= (*(_partial+i)); + for (int i = 0; i < 60000; i++) + { + *(D_memory_new + i) &= *(_partial + i); + *(D_memory_new + i) |= (*(_partial + i)); } } -void Inkplate::drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char* _p, int16_t _w, int16_t _h) { - if (_displayMode != INKPLATE_3BIT) return; - uint8_t _rem = _w % 2; +void Inkplate::drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h) +{ + if (_displayMode != INKPLATE_3BIT) + return; + uint8_t _rem = _w % 2; int i, j; int xSize = _w / 2 + _rem; - for (i = 0; i < _h; i++) { - for (j = 0; j < xSize - 1; j++) { - drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4)>>1); - drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff)>>1); + for (i = 0; i < _h; i++) + { + for (j = 0; j < xSize - 1; j++) + { + drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1); + drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1); } - drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4)>>1); - if (_rem == 0) drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff)>>1); + drawPixel((j * 2) + _x, i + _y, (*(_p + xSize * (i) + j) >> 4) >> 1); + if (_rem == 0) + drawPixel((j * 2) + 1 + _x, i + _y, (*(_p + xSize * (i) + j) & 0xff) >> 1); } } -void Inkplate::setRotation(uint8_t r) { +void Inkplate::setRotation(uint8_t r) +{ _rotation = r % 4; - switch (rotation) { - case 0: - _width = E_INK_WIDTH; - _height = E_INK_HEIGHT; - break; - case 1: - _width = E_INK_HEIGHT; - _height = E_INK_WIDTH; - break; - case 2: - _width = E_INK_WIDTH; - _height = E_INK_HEIGHT; - break; - case 3: - _width = E_INK_HEIGHT; - _height = E_INK_WIDTH; - break; + switch (rotation) + { + case 0: + _width = E_INK_WIDTH; + _height = E_INK_HEIGHT; + break; + case 1: + _width = E_INK_HEIGHT; + _height = E_INK_WIDTH; + break; + case 2: + _width = E_INK_WIDTH; + _height = E_INK_HEIGHT; + break; + case 3: + _width = E_INK_HEIGHT; + _height = E_INK_WIDTH; + break; } } //Turn off epapewr supply and put all digital IO pins in high Z state -void Inkplate::einkOff() { - if(_panelOn == 0) return; +void Inkplate::einkOff() +{ + if (_panelOn == 0) + return; _panelOn = 0; GMOD_CLEAR; OE_CLEAR; @@ -276,8 +314,10 @@ void Inkplate::einkOff() { } //Turn on supply for epaper display (TPS65186) [+15 VDC, -15VDC, +22VDC, -20VDC, +3.3VDC, VCOM] -void Inkplate::einkOn() { - if(_panelOn == 1) return; +void Inkplate::einkOn() +{ + if (_panelOn == 1) + return; _panelOn = 1; pinsAsOutputs(); WAKEUP_SET; @@ -288,103 +328,130 @@ void Inkplate::einkOn() { Wire.write(0x01); Wire.write(B00111111); Wire.endTransmission(); - + delay(40); - + Wire.beginTransmission(0x48); Wire.write(0x0D); Wire.write(B10000000); Wire.endTransmission(); - + delay(2); - + Wire.beginTransmission(0x48); Wire.write(0x00); Wire.endTransmission(); - + Wire.requestFrom(0x48, 1); _temperature = Wire.read(); - LE_CLEAR; //setpin_le(FALSE); - OE_CLEAR; //setpin_oe(FALSE); - CL_CLEAR; //setpin_cl(FALSE); + LE_CLEAR; //setpin_le(FALSE); + OE_CLEAR; //setpin_oe(FALSE); + CL_CLEAR; //setpin_cl(FALSE); SPH_SET; //setpin_sph(FALSE); - GMOD_SET; //setpin_gmode(FALSE); + GMOD_SET; //setpin_gmode(FALSE); SPV_SET; //setpin_spv(FALSE); - CKV_CLEAR; //setpin_ckv(FALSE); + CKV_CLEAR; //setpin_ckv(FALSE); OE_SET; } -void Inkplate::selectDisplayMode(uint8_t _mode) { - if(_mode != _displayMode) { - _displayMode = _mode&1; - memset(D_memory_new, 0, 60000); - memset(_partial, 0, 60000); - memset(_pBuffer, 0, 120000); - memset(D_memory4Bit, 255, 240000); - _blockPartial = 1; - } +void Inkplate::selectDisplayMode(uint8_t _mode) +{ + if (_mode != _displayMode) + { + _displayMode = _mode & 1; + memset(D_memory_new, 0, 60000); + memset(_partial, 0, 60000); + memset(_pBuffer, 0, 120000); + memset(D_memory4Bit, 255, 240000); + _blockPartial = 1; + } } -uint8_t Inkplate::getDisplayMode() { +uint8_t Inkplate::getDisplayMode() +{ return _displayMode; } -int Inkplate::drawBitmapFromSD(SdFile* p, int x, int y, bool invert) { - if(sdCardOk == 0) return 0; - struct bitmapHeader bmpHeader; - readBmpHeaderSd(p, &bmpHeader); - if (bmpHeader.signature != 0x4D42 || bmpHeader.compression != 0 || !(bmpHeader.color == 1 || bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24)) return 0; +int Inkplate::drawBitmapFromSD(SdFile *p, int x, int y, bool invert) +{ + if (sdCardOk == 0) + return 0; + struct bitmapHeader bmpHeader; + readBmpHeaderSd(p, &bmpHeader); + if (bmpHeader.signature != 0x4D42 || bmpHeader.compression != 0 || !(bmpHeader.color == 1 || bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24)) + return 0; - if ((bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24 || bmpHeader.color == 32) && getDisplayMode() != INKPLATE_3BIT) { - selectDisplayMode(INKPLATE_3BIT); - } + if ((bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24 || bmpHeader.color == 32) && getDisplayMode() != INKPLATE_3BIT) + { + selectDisplayMode(INKPLATE_3BIT); + } - if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT) { - selectDisplayMode(INKPLATE_1BIT); - } - - if (bmpHeader.color == 1) drawMonochromeBitmapSd(p, bmpHeader, x, y, invert); - if (bmpHeader.color == 4) drawGrayscaleBitmap4Sd(p, bmpHeader, x, y, invert); - if (bmpHeader.color == 8) drawGrayscaleBitmap8Sd(p, bmpHeader, x, y, invert); - if (bmpHeader.color == 24) drawGrayscaleBitmap24Sd(p, bmpHeader, x, y, invert); + if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT) + { + selectDisplayMode(INKPLATE_1BIT); + } + + if (bmpHeader.color == 1) + drawMonochromeBitmapSd(p, bmpHeader, x, y, invert); + if (bmpHeader.color == 4) + drawGrayscaleBitmap4Sd(p, bmpHeader, x, y, invert); + if (bmpHeader.color == 8) + drawGrayscaleBitmap8Sd(p, bmpHeader, x, y, invert); + if (bmpHeader.color == 24) + drawGrayscaleBitmap24Sd(p, bmpHeader, x, y, invert); return 1; } -int Inkplate::drawBitmapFromSD(char* fileName, int x, int y, bool invert) { - if(sdCardOk == 0) return 0; +int Inkplate::drawBitmapFromSD(char *fileName, int x, int y, bool invert) +{ + if (sdCardOk == 0) + return 0; SdFile dat; - if (dat.open(fileName, O_RDONLY)) { + if (dat.open(fileName, O_RDONLY)) + { return drawBitmapFromSD(&dat, x, y, invert); - } else { + } + else + { return 0; } } -int Inkplate::drawBitmapFromWeb(WiFiClient* s, int x, int y, int len, bool invert) { +int Inkplate::drawBitmapFromWeb(WiFiClient *s, int x, int y, int len, bool invert) +{ struct bitmapHeader bmpHeader; readBmpHeaderWeb(s, &bmpHeader); - if (bmpHeader.signature != 0x4D42 || bmpHeader.compression != 0 || !(bmpHeader.color == 1 || bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24)) return 0; + if (bmpHeader.signature != 0x4D42 || bmpHeader.compression != 0 || !(bmpHeader.color == 1 || bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24)) + return 0; - if ((bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24 || bmpHeader.color == 32) && getDisplayMode() != INKPLATE_3BIT) { + if ((bmpHeader.color == 4 || bmpHeader.color == 8 || bmpHeader.color == 24 || bmpHeader.color == 32) && getDisplayMode() != INKPLATE_3BIT) + { selectDisplayMode(INKPLATE_3BIT); } - if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT) { + if (bmpHeader.color == 1 && getDisplayMode() != INKPLATE_1BIT) + { selectDisplayMode(INKPLATE_1BIT); } - - if (bmpHeader.color == 1) drawMonochromeBitmapWeb(s, bmpHeader, x, y, len, invert); - if (bmpHeader.color == 4) drawGrayscaleBitmap4Web(s, bmpHeader, x, y, len, invert); - if (bmpHeader.color == 8) drawGrayscaleBitmap8Web(s, bmpHeader, x, y, len, invert); - if (bmpHeader.color == 24) drawGrayscaleBitmap24Web(s, bmpHeader, x, y, len, invert); + + if (bmpHeader.color == 1) + drawMonochromeBitmapWeb(s, bmpHeader, x, y, len, invert); + if (bmpHeader.color == 4) + drawGrayscaleBitmap4Web(s, bmpHeader, x, y, len, invert); + if (bmpHeader.color == 8) + drawGrayscaleBitmap8Web(s, bmpHeader, x, y, len, invert); + if (bmpHeader.color == 24) + drawGrayscaleBitmap24Web(s, bmpHeader, x, y, len, invert); return 1; } -int Inkplate::drawBitmapFromWeb(char* url, int x, int y, bool invert) { - if (WiFi.status() != WL_CONNECTED) return 0; +int Inkplate::drawBitmapFromWeb(char *url, int x, int y, bool invert) +{ + if (WiFi.status() != WL_CONNECTED) + return 0; int ret = 0; bool sleep = WiFi.getSleep(); @@ -396,46 +463,101 @@ int Inkplate::drawBitmapFromWeb(char* url, int x, int y, bool invert) { http.begin(url); int httpCode = http.GET(); - if (httpCode == 200) { + if (httpCode == 200) + { int32_t len = http.getSize(); - if (len > 0) { - WiFiClient * dat = http.getStreamPtr(); + if (len > 0) + { + WiFiClient *dat = http.getStreamPtr(); ret = drawBitmapFromWeb(dat, x, y, len, invert); } } - + http.end(); WiFi.setSleep(sleep); return ret; } -int Inkplate::sdCardInit() { - spi2.begin(14, 12, 13, 15); - sdCardOk = sd.begin(15, SD_SCK_MHZ(25)); - return sdCardOk; +void Inkplate::drawThickLine(int x1, int y1, int x2, int y2, int color, float thickness) +{ + float deg = atan2f((float)(y2 - y1), (float)(x2 - x1)); + + float l1 = tan(deg); + float k1 = (float)y1 - l1 * (float)x1; + + float degShift = (l1 < 0 ? M_PI_2 : -M_PI_2); + + int x3 = (int)round((float)x1 + thickness / 2.0 * cos(deg + degShift)); + int y3 = (int)round((float)y1 + thickness / 2.0 * sin(deg + degShift)); + + int x4 = (int)round((float)x2 + thickness / 2.0 * cos(deg + degShift)); + int y4 = (int)round((float)y2 + thickness / 2.0 * sin(deg + degShift)); + + x1 = (int)round((float)x1 + thickness / 2.0 * cos(deg - degShift)); + y1 = (int)round((float)y1 + thickness / 2.0 * sin(deg - degShift)); + + x2 = (int)round((float)x2 + thickness / 2.0 * cos(deg - degShift)); + y2 = (int)round((float)y2 + thickness / 2.0 * sin(deg - degShift)); + + fillTriangle(x1, y1, x2, y2, x3, y3, color); + fillTriangle(x2, y2, x4, y4, x3, y3, color); } -SdFat Inkplate::getSdFat() { - return sd; +void Inkplate::drawGradientLine(int x1, int y1, int x2, int y2, int color1, int color2, float thickness) +{ + int n = color2 - color1; + + float px = (float)(x2 - x1) / (float)n; + float py = (float)(y2 - y1) / (float)n; + + for (int i = 0; i < n; ++i) + { + if (abs(thickness + 1) < 0.1) + drawLine((int)((float)x1 + (float)i * px), (int)((float)y1 + (float)i * py), + (int)((float)x1 + (float)(i + 1) * px), (int)((float)y1 + (float)(i + 1) * py), + color1 + i); + else + drawThickLine((int)((float)x1 + (float)i * px), (int)((float)y1 + (float)i * py), + (int)((float)x1 + (float)(i + 1) * px), (int)((float)y1 + (float)(i + 1) * py), + color1 + i, + thickness); + } } -SPIClass Inkplate::getSPI() { - return spi2; +int Inkplate::sdCardInit() +{ + spi2.begin(14, 12, 13, 15); + sdCardOk = sd.begin(15, SD_SCK_MHZ(25)); + return sdCardOk; } -uint8_t Inkplate::getPanelState() { +SdFat Inkplate::getSdFat() +{ + return sd; +} + +SPIClass Inkplate::getSPI() +{ + return spi2; +} + +uint8_t Inkplate::getPanelState() +{ return _panelOn; } -uint8_t Inkplate::readTouchpad(uint8_t _pad) { - return mcp.digitalRead((_pad&3)+10); +uint8_t Inkplate::readTouchpad(uint8_t _pad) +{ + return mcp.digitalRead((_pad & 3) + 10); } -int8_t Inkplate::readTemperature() { +int8_t Inkplate::readTemperature() +{ return _temperature; } -double Inkplate::readBattery() { +double Inkplate::readBattery() +{ mcp.digitalWrite(9, HIGH); delay(1); int adc = analogRead(35); @@ -486,14 +608,15 @@ void Inkplate::vscan_write() void Inkplate::hscan_start(uint32_t _d) { SPH_CLEAR; - GPIO.out_w1ts = (_d) | CL; - GPIO.out_w1tc = DATA | CL; + GPIO.out_w1ts = (_d) | CL; + GPIO.out_w1tc = DATA | CL; //CL_SET; //CL_CLEAR; SPH_SET; } -void Inkplate::vscan_end() { +void Inkplate::vscan_end() +{ CKV_CLEAR; LE_SET; LE_CLEAR; @@ -502,7 +625,8 @@ void Inkplate::vscan_end() { } //Clear screan before new screen update using waveform -void Inkplate::clean() { +void Inkplate::clean() +{ einkOn(); int m = 0; cleanFast(0, 1); //white @@ -519,26 +643,37 @@ void Inkplate::clean() { } //Clears content from epaper diplay as fast as ESP32 can. -void Inkplate::cleanFast(uint8_t c, uint8_t rep) { +void Inkplate::cleanFast(uint8_t c, uint8_t rep) +{ einkOn(); uint8_t data; - if (c == 0) { - data = B10101010; //White - } else if (c == 1) { - data = B01010101; //Black - } else if (c == 2) { - data = B00000000; //Discharge - } else if (c == 3) { - data = B11111111; //Skip + if (c == 0) + { + data = B10101010; //White + } + else if (c == 1) + { + data = B01010101; //Black + } + else if (c == 2) + { + data = B00000000; //Discharge + } + else if (c == 3) + { + data = B11111111; //Skip } uint32_t _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - for (int i = 0; i < rep; i++) { + for (int i = 0; i < rep; i++) + { unsigned int x, y; vscan_start(); - for (y = 0; y < 600; y++) { - hscan_start(_send); - for (x = 0; x < 100; x++) { + for (y = 0; y < 600; y++) + { + hscan_start(_send); + for (x = 0; x < 100; x++) + { GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; GPIO.out_w1ts = (_send) | CL; @@ -546,14 +681,15 @@ void Inkplate::cleanFast(uint8_t c, uint8_t rep) { } GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - vscan_end(); + vscan_end(); } delayMicroseconds(230); } } -void Inkplate::cleanFast2(uint8_t c, uint8_t n, uint16_t d) { - /* +void Inkplate::cleanFast2(uint8_t c, uint8_t n, uint16_t d) +{ + /* uint8_t data; if (c == 0) { data = B10101010; //White @@ -587,7 +723,8 @@ void Inkplate::cleanFast2(uint8_t c, uint8_t n, uint16_t d) { */ } -void Inkplate::pinsZstate() { +void Inkplate::pinsZstate() +{ //CONTROL PINS pinMode(0, INPUT); pinMode(2, INPUT); @@ -608,7 +745,8 @@ void Inkplate::pinsZstate() { pinMode(27, INPUT); //D7 } -void Inkplate::pinsAsOutputs() { +void Inkplate::pinsAsOutputs() +{ //CONTROL PINS pinMode(0, OUTPUT); pinMode(2, OUTPUT); @@ -631,10 +769,12 @@ void Inkplate::pinsAsOutputs() { //--------------------------PRIVATE FUNCTIONS-------------------------------------------- //Display content from RAM to display (1 bit per pixel,. monochrome picture). -void Inkplate::display1b() { - for(int i = 0; i<60000; i++) { - *(D_memory_new+i) &= *(_partial+i); - *(D_memory_new+i) |= (*(_partial+i)); +void Inkplate::display1b() +{ + for (int i = 0; i < 60000; i++) + { + *(D_memory_new + i) &= *(_partial + i); + *(D_memory_new + i) |= (*(_partial + i)); } uint16_t _pos; uint32_t _send; @@ -650,67 +790,72 @@ void Inkplate::display1b() { cleanFast(1, 12); cleanFast(2, 1); cleanFast(0, 11); - for (int k = 0; k < 5; k++) { - _pos = 59999; + for (int k = 0; k < 5; k++) + { + _pos = 59999; vscan_start(); - for (int i = 0; i < 600; i++) { - dram = *(D_memory_new + _pos); - data = LUTB[(dram >> 4)&0x0F]; + for (int i = 0; i < 600; i++) + { + dram = *(D_memory_new + _pos); + data = LUTB[(dram >> 4) & 0x0F]; _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - hscan_start(_send); - data = LUTB[dram & 0x0F]; + hscan_start(_send); + data = LUTB[dram & 0x0F]; _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - _pos--; - for (int j = 0; j < 99; j++) { - dram = *(D_memory_new + _pos); - data = LUTB[(dram >> 4)&0x0F]; + _pos--; + for (int j = 0; j < 99; j++) + { + dram = *(D_memory_new + _pos); + data = LUTB[(dram >> 4) & 0x0F]; _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; data = LUTB[dram & 0x0F]; _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - _pos--; + _pos--; } - GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - vscan_end(); + vscan_end(); } delayMicroseconds(230); } - - _pos = 59999; - vscan_start(); - for (int i = 0; i < 600; i++) { - dram = *(D_memory_new + _pos); - data = LUT2[(dram >> 4)&0x0F]; + + _pos = 59999; + vscan_start(); + for (int i = 0; i < 600; i++) + { + dram = *(D_memory_new + _pos); + data = LUT2[(dram >> 4) & 0x0F]; + _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); + hscan_start(_send); + data = LUT2[dram & 0x0F]; + _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); + GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1tc = DATA | CL; + _pos--; + for (int j = 0; j < 99; j++) + { + dram = *(D_memory_new + _pos); + data = LUT2[(dram >> 4) & 0x0F]; _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - hscan_start(_send); - data = LUT2[dram & 0x0F]; + GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1tc = DATA | CL; + data = LUT2[dram & 0x0F]; _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - _pos--; - for (int j = 0; j < 99; j++) { - dram = *(D_memory_new + _pos); - data = LUT2[(dram >> 4)&0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; - GPIO.out_w1tc = DATA | CL; - data = LUT2[dram & 0x0F]; - _send = ((data & B00000011) << 4) | (((data & B00001100) >> 2) << 18) | (((data & B00010000) >> 4) << 23) | (((data & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; - GPIO.out_w1tc = DATA | CL; - _pos--; - } - GPIO.out_w1ts = (_send) | CL; - GPIO.out_w1tc = DATA | CL; - vscan_end(); + _pos--; } - delayMicroseconds(230); + GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1tc = DATA | CL; + vscan_end(); + } + delayMicroseconds(230); /* for (int k = 0; k < 1; k++) { vscan_start(); @@ -742,7 +887,8 @@ void Inkplate::display1b() { } //Display content from RAM to display (3 bit per pixel,. 8 level of grayscale, STILL IN PROGRESSS, we need correct wavefrom to get good picture, use it only for pictures not for GFX). -void Inkplate::display3b() { +void Inkplate::display3b() +{ einkOn(); cleanFast(0, 1); cleanFast(1, 12); @@ -752,58 +898,61 @@ void Inkplate::display3b() { cleanFast(1, 12); cleanFast(2, 1); cleanFast(0, 11); - - for (int k = 0; k < 7; k++) { - uint8_t *dp = D_memory4Bit + 239999; - uint32_t _send; - uint8_t pix1; - uint8_t pix2; - uint8_t pix3; - uint8_t pix4; - uint8_t pixel; - uint8_t pixel2; - - vscan_start(); - for (int i = 0; i < 600; i++) { - pixel = 0B00000000; + + for (int k = 0; k < 7; k++) + { + uint8_t *dp = D_memory4Bit + 239999; + uint32_t _send; + uint8_t pix1; + uint8_t pix2; + uint8_t pix3; + uint8_t pix4; + uint8_t pixel; + uint8_t pixel2; + + vscan_start(); + for (int i = 0; i < 600; i++) + { + pixel = 0B00000000; + pixel2 = 0B00000000; + pix1 = *(dp--); + pix2 = *(dp--); + pix3 = *(dp--); + pix4 = *(dp--); + pixel |= (waveform3Bit[pix1 & 0x07][k] << 6) | (waveform3Bit[(pix1 >> 4) & 0x07][k] << 4) | (waveform3Bit[pix2 & 0x07][k] << 2) | (waveform3Bit[(pix2 >> 4) & 0x07][k] << 0); + pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); + + _send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | (((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25); + hscan_start(_send); + _send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | (((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25); + GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1tc = DATA | CL; + + for (int j = 0; j < 99; j++) + { + + pixel = 0B00000000; pixel2 = 0B00000000; - pix1 = *(dp--); + pix1 = *(dp--); pix2 = *(dp--); - pix3 = *(dp--); + pix3 = *(dp--); pix4 = *(dp--); - pixel |= ( waveform3Bit[pix1&0x07][k] << 6) | ( waveform3Bit[(pix1>>4)&0x07][k] << 4) | ( waveform3Bit[pix2&0x07][k] << 2) | ( waveform3Bit[(pix2>>4)&0x07][k] << 0); - pixel2 |= ( waveform3Bit[pix3&0x07][k] << 6) | ( waveform3Bit[(pix3>>4)&0x07][k] << 4) | ( waveform3Bit[pix4&0x07][k] << 2) | ( waveform3Bit[(pix4>>4)&0x07][k] << 0); + pixel |= (waveform3Bit[pix1 & 0x07][k] << 6) | (waveform3Bit[(pix1 >> 4) & 0x07][k] << 4) | (waveform3Bit[pix2 & 0x07][k] << 2) | (waveform3Bit[(pix2 >> 4) & 0x07][k] << 0); + pixel2 |= (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); _send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | (((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25); - hscan_start(_send); + GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1tc = DATA | CL; + _send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | (((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25); GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - - for (int j = 0; j < 99; j++) { - - pixel = 0B00000000; - pixel2 = 0B00000000; - pix1 = *(dp--); - pix2 = *(dp--); - pix3 = *(dp--); - pix4 = *(dp--); - pixel |= ( waveform3Bit[pix1&0x07][k] << 6) | ( waveform3Bit[(pix1>>4)&0x07][k] << 4) | ( waveform3Bit[pix2&0x07][k] << 2) | ( waveform3Bit[(pix2>>4)&0x07][k] << 0); - pixel2 |= ( waveform3Bit[pix3&0x07][k] << 6) | ( waveform3Bit[(pix3>>4)&0x07][k] << 4) | ( waveform3Bit[pix4&0x07][k] << 2) | ( waveform3Bit[(pix4>>4)&0x07][k] << 0); - - _send = ((pixel & B00000011) << 4) | (((pixel & B00001100) >> 2) << 18) | (((pixel & B00010000) >> 4) << 23) | (((pixel & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; - GPIO.out_w1tc = DATA | CL; - - _send = ((pixel2 & B00000011) << 4) | (((pixel2 & B00001100) >> 2) << 18) | (((pixel2 & B00010000) >> 4) << 23) | (((pixel2 & B11100000) >> 5) << 25); - GPIO.out_w1ts = (_send) | CL; - GPIO.out_w1tc = DATA | CL; - } - GPIO.out_w1ts = (_send) | CL; - GPIO.out_w1tc = DATA | CL; - vscan_end(); } - delayMicroseconds(230); + GPIO.out_w1ts = (_send) | CL; + GPIO.out_w1tc = DATA | CL; + vscan_end(); + } + delayMicroseconds(230); } cleanFast(2, 1); cleanFast(3, 1); @@ -811,15 +960,18 @@ void Inkplate::display3b() { einkOff(); } -uint32_t Inkplate::read32(uint8_t* c) { +uint32_t Inkplate::read32(uint8_t *c) +{ return (*(c) | (*(c + 1) << 8) | (*(c + 2) << 16) | (*(c + 3) << 24)); } -uint16_t Inkplate::read16(uint8_t* c) { +uint16_t Inkplate::read16(uint8_t *c) +{ return (*(c) | (*(c + 1) << 8)); } -void Inkplate::readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h) { +void Inkplate::readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h) +{ uint8_t header[100]; _f->rewind(); _f->read(header, 100); @@ -834,7 +986,8 @@ void Inkplate::readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h) { return; } -void Inkplate::readBmpHeaderWeb(WiFiClient *_s, struct bitmapHeader *_h) { +void Inkplate::readBmpHeaderWeb(WiFiClient *_s, struct bitmapHeader *_h) +{ uint8_t header[34]; _s->read(header, 34); _h->signature = read16(header + 0); @@ -848,7 +1001,8 @@ void Inkplate::readBmpHeaderWeb(WiFiClient *_s, struct bitmapHeader *_h) { return; } -int Inkplate::drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) { +int Inkplate::drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; uint8_t paddingBits = w % 32; @@ -856,20 +1010,25 @@ int Inkplate::drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, i f->seekSet(bmpHeader.startRAW); int i, j; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { uint32_t pixelRow = f->read() << 24 | f->read() << 16 | f->read() << 8 | f->read(); if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < 32; n++) { + for (int n = 0; n < 32; n++) + { drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n)))); } } - if (paddingBits) { + if (paddingBits) + { uint32_t pixelRow = f->read() << 24 | f->read() << 16 | f->read() << 8 | f->read(); if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < paddingBits; n++) { + for (int n = 0; n < paddingBits; n++) + { drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n)))); } } @@ -878,7 +1037,8 @@ int Inkplate::drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, i return 1; } -int Inkplate::drawGrayscaleBitmap4Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) { +int Inkplate::drawGrayscaleBitmap4Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; uint8_t paddingBits = w % 8; @@ -886,21 +1046,26 @@ int Inkplate::drawGrayscaleBitmap4Sd(SdFile *f, struct bitmapHeader bmpHeader, i f->seekSet(bmpHeader.startRAW); int i, j; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { uint32_t pixelRow = f->read() << 24 | f->read() << 16 | f->read() << 8 | f->read(); if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < 8; n++) { - drawPixel((i * 8) + n + x, h - 1 - j + y, (pixelRow & (0xFULL << (28 - n*4))) >> (28 - n*4 + 1)); + for (int n = 0; n < 8; n++) + { + drawPixel((i * 8) + n + x, h - 1 - j + y, (pixelRow & (0xFULL << (28 - n * 4))) >> (28 - n * 4 + 1)); } } - if (paddingBits) { + if (paddingBits) + { uint32_t pixelRow = f->read() << 24 | f->read() << 16 | f->read() << 8 | f->read(); if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < paddingBits; n++) { - drawPixel((i * 8) + n + x, h - 1 - j + y, ((pixelRow & (0xFULL << (28 - n*4)))) >> (28 - n*4 + 1)); + for (int n = 0; n < paddingBits; n++) + { + drawPixel((i * 8) + n + x, h - 1 - j + y, ((pixelRow & (0xFULL << (28 - n * 4)))) >> (28 - n * 4 + 1)); } } } @@ -908,23 +1073,28 @@ int Inkplate::drawGrayscaleBitmap4Sd(SdFile *f, struct bitmapHeader bmpHeader, i return 1; } -int Inkplate::drawGrayscaleBitmap8Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) { +int Inkplate::drawGrayscaleBitmap8Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; char padding = w % 4; f->seekSet(bmpHeader.startRAW); int i, j; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { uint8_t px = 0; if (invert) - px = 255-f->read(); + px = 255 - f->read(); else px = f->read(); - drawPixel(i + x, h - 1 - j + y, px>>5); + drawPixel(i + x, h - 1 - j + y, px >> 5); } - if (padding) { - for (int p = 0; p < 4-padding; p++) { + if (padding) + { + for (int p = 0; p < 4 - padding; p++) + { f->read(); } } @@ -933,14 +1103,17 @@ int Inkplate::drawGrayscaleBitmap8Sd(SdFile *f, struct bitmapHeader bmpHeader, i return 1; } -int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) { +int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; char padding = w % 4; f->seekSet(bmpHeader.startRAW); int i, j; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { //This is the proper way of converting True Color (24 Bit RGB) bitmap file into grayscale, but it takes waaay too much time (full size picture takes about 17s to decode!) //float px = (0.2126 * (readByteFromSD(&file) / 255.0)) + (0.7152 * (readByteFromSD(&file) / 255.0)) + (0.0722 * (readByteFromSD(&file) / 255.0)); //px = pow(px, 1.5); @@ -949,15 +1122,17 @@ int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, //So then, we are convertng it to grayscale using good old average and gamma correction (from LUT). With this metod, it is still slow (full size image takes 4 seconds), but much beter than prev mentioned method. uint8_t px = 0; if (invert) - px = ((255-f->read()) * 2126 / 10000) + ((255-f->read()) * 7152 / 10000) + ((255-f->read()) * 722 / 10000); + px = ((255 - f->read()) * 2126 / 10000) + ((255 - f->read()) * 7152 / 10000) + ((255 - f->read()) * 722 / 10000); else px = (f->read() * 2126 / 10000) + (f->read() * 7152 / 10000) + (f->read() * 722 / 10000); //drawPixel(i + x, h - j + y, gammaLUT[px]); - drawPixel(i + x, h - 1 - j + y, px>>5); - //drawPixel(i + x, h - j + y, px/32); + drawPixel(i + x, h - 1 - j + y, px >> 5); + //drawPixel(i + x, h - j + y, px/32); } - if (padding) { - for (int p = 0; p < padding; p++) { + if (padding) + { + for (int p = 0; p < padding; p++) + { f->read(); } } @@ -966,42 +1141,50 @@ int Inkplate::drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, return 1; } -int Inkplate::drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) { +int Inkplate::drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; uint8_t paddingBits = w % 32; int total = len - 34; w /= 32; - uint8_t* buf = (uint8_t*) ps_malloc(total); + uint8_t *buf = (uint8_t *)ps_malloc(total); if (buf == NULL) return 0; int pnt = 0; - while (pnt < total) { + while (pnt < total) + { int toread = s->available(); - if (toread > 0) { - int read = s->read(buf+pnt, toread); + if (toread > 0) + { + int read = s->read(buf + pnt, toread); if (read > 0) pnt += read; } } int i, j, k = bmpHeader.startRAW - 34; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++]; if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < 32; n++) { + for (int n = 0; n < 32; n++) + { drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n)))); } } - if (paddingBits) { + if (paddingBits) + { uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++]; if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < paddingBits; n++) { + for (int n = 0; n < paddingBits; n++) + { drawPixel((i * 32) + n + x, h - 1 - j + y, !(pixelRow & (1ULL << (31 - n)))); } } @@ -1012,43 +1195,51 @@ int Inkplate::drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHead return 1; } -int Inkplate::drawGrayscaleBitmap4Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) { +int Inkplate::drawGrayscaleBitmap4Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; char paddingBits = w % 8; int total = len - 34; w /= 8; - uint8_t* buf = (uint8_t*) ps_malloc(total); + uint8_t *buf = (uint8_t *)ps_malloc(total); if (buf == NULL) return 0; int pnt = 0; - while (pnt < total) { + while (pnt < total) + { int toread = s->available(); - if (toread > 0) { - int read = s->read(buf+pnt, toread); + if (toread > 0) + { + int read = s->read(buf + pnt, toread); if (read > 0) pnt += read; } } int i, j, k = bmpHeader.startRAW - 34; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++]; if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < 8; n++) { - drawPixel((i * 8) + n + x, h - 1 - j + y, (pixelRow & (0xFULL << (28 - n*4))) >> (28 - n*4 + 1)); + for (int n = 0; n < 8; n++) + { + drawPixel((i * 8) + n + x, h - 1 - j + y, (pixelRow & (0xFULL << (28 - n * 4))) >> (28 - n * 4 + 1)); } } - if (paddingBits) { + if (paddingBits) + { uint32_t pixelRow = buf[k++] << 24 | buf[k++] << 16 | buf[k++] << 8 | buf[k++]; if (invert) pixelRow = ~pixelRow; - for (int n = 0; n < paddingBits; n++) { - drawPixel((i * 8) + n + x, h - 1 - j + y, ((pixelRow & (0xFULL << (28 - n*4)))) >> (28 - n*4 + 1)); + for (int n = 0; n < paddingBits; n++) + { + drawPixel((i * 8) + n + x, h - 1 - j + y, ((pixelRow & (0xFULL << (28 - n * 4)))) >> (28 - n * 4 + 1)); } } } @@ -1058,38 +1249,45 @@ int Inkplate::drawGrayscaleBitmap4Web(WiFiClient *s, struct bitmapHeader bmpHead return 1; } -int Inkplate::drawGrayscaleBitmap8Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) { +int Inkplate::drawGrayscaleBitmap8Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; char padding = w % 4; int total = len - 34; - uint8_t* buf = (uint8_t*) ps_malloc(total); + uint8_t *buf = (uint8_t *)ps_malloc(total); if (buf == NULL) return 0; int pnt = 0; - while (pnt < total) { + while (pnt < total) + { int toread = s->available(); - if (toread > 0) { - int read = s->read(buf+pnt, toread); + if (toread > 0) + { + int read = s->read(buf + pnt, toread); if (read > 0) pnt += read; } } int i, j, k = bmpHeader.startRAW - 34; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { uint8_t px = 0; if (invert) - px = 255-buf[k++]; + px = 255 - buf[k++]; else px = buf[k++]; - drawPixel(i + x, h - 1 - j + y, px>>5); + drawPixel(i + x, h - 1 - j + y, px >> 5); } - if (padding) { - for (int p = 0; p < 4-padding; p++) { + if (padding) + { + for (int p = 0; p < 4 - padding; p++) + { k++; } } @@ -1100,29 +1298,34 @@ int Inkplate::drawGrayscaleBitmap8Web(WiFiClient *s, struct bitmapHeader bmpHead return 1; } -int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) { +int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert) +{ int w = bmpHeader.width; int h = bmpHeader.height; char padding = w % 4; int total = len - 34; - uint8_t* buf = (uint8_t*) ps_malloc(total); + uint8_t *buf = (uint8_t *)ps_malloc(total); if (buf == NULL) return 0; int pnt = 0; - while (pnt < total) { + while (pnt < total) + { int toread = s->available(); - if (toread > 0) { - int read = s->read(buf+pnt, toread); + if (toread > 0) + { + int read = s->read(buf + pnt, toread); if (read > 0) pnt += read; } } int i, j, k = bmpHeader.startRAW - 34; - for (j = 0; j < h; j++) { - for (i = 0; i < w; i++) { + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { //This is the proper way of converting True Color (24 Bit RGB) bitmap file into grayscale, but it takes waaay too much time (full size picture takes about 17s to decode!) //float px = (0.2126 * (readByteFromSD(&file) / 255.0)) + (0.7152 * (readByteFromSD(&file) / 255.0)) + (0.0722 * (readByteFromSD(&file) / 255.0)); //px = pow(px, 1.5); @@ -1131,15 +1334,17 @@ int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHea //So then, we are convertng it to grayscale using good old average and gamma correction (from LUT). With this metod, it is still slow (full size image takes 4 seconds), but much beter than prev mentioned method. uint8_t px = 0; if (invert) - px = ((255-buf[k++]) * 2126 / 10000) + ((255-buf[k++]) * 7152 / 10000) + ((255-buf[k++]) * 722 / 10000); + px = ((255 - buf[k++]) * 2126 / 10000) + ((255 - buf[k++]) * 7152 / 10000) + ((255 - buf[k++]) * 722 / 10000); else px = (buf[k++] * 2126 / 10000) + (buf[k++] * 7152 / 10000) + (buf[k++] * 722 / 10000); //drawPixel(i + x, h - j + y, gammaLUT[px]); - drawPixel(i + x, h - 1 - j + y, px>>5); + drawPixel(i + x, h - 1 - j + y, px >> 5); //drawPixel(i + x, h - j + y, px/32); } - if (padding) { - for (int p = 0; p < padding; p++) { + if (padding) + { + for (int p = 0; p < padding; p++) + { k++; } } @@ -1150,8 +1355,10 @@ int Inkplate::drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHea return 1; } -void Inkplate::precalculateGamma(uint8_t* c, float gamma) { - for (int i = 0; i < 256; i++) { +void Inkplate::precalculateGamma(uint8_t *c, float gamma) +{ + for (int i = 0; i < 256; i++) + { c[i] = int(round((pow(i / 255.0, gamma)) * 15)); } } diff --git a/Inkplate.h b/Inkplate.h index d5a888f..25b5ebb 100644 --- a/Inkplate.h +++ b/Inkplate.h @@ -17,69 +17,134 @@ #include "SdFat.h" #include "WiFiClient.h" -#define INKPLATE_GAMMA 1.45 -#define E_INK_WIDTH 800 -#define E_INK_HEIGHT 600 -#define BLACK 1 -#define WHITE 0 -#define GPIO0_ENABLE 8 -#define INKPLATE_1BIT 0 -#define INKPLATE_3BIT 1 -#define PAD1 0 -#define PAD2 1 -#define PAD3 2 +#define INKPLATE_GAMMA 1.45 +#define E_INK_WIDTH 800 +#define E_INK_HEIGHT 600 +#define BLACK 1 +#define WHITE 0 +#define GPIO0_ENABLE 8 +#define INKPLATE_1BIT 0 +#define INKPLATE_3BIT 1 +#define PAD1 0 +#define PAD2 1 +#define PAD3 2 -#define DATA 0x0E8C0030 //D0-D7 = GPIO4 GPIO5 GPIO18 GPIO19 GPIO23 GPIO25 GPIO26 GPIO27 +#define DATA 0x0E8C0030 //D0-D7 = GPIO4 GPIO5 GPIO18 GPIO19 GPIO23 GPIO25 GPIO26 GPIO27 -#define CL 0x01 //GPIO0 -#define CL_SET {GPIO.out_w1ts = CL;} -#define CL_CLEAR {GPIO.out_w1tc = CL;} +#define CL 0x01 //GPIO0 +#define CL_SET \ + { \ + GPIO.out_w1ts = CL; \ + } +#define CL_CLEAR \ + { \ + GPIO.out_w1tc = CL; \ + } -#define LE 0x04 //GPIO2 -#define LE_SET {GPIO.out_w1ts = LE;} -#define LE_CLEAR {GPIO.out_w1tc = LE;} +#define LE 0x04 //GPIO2 +#define LE_SET \ + { \ + GPIO.out_w1ts = LE; \ + } +#define LE_CLEAR \ + { \ + GPIO.out_w1tc = LE; \ + } -#define CKV 0x01 //GPIO32 -#define CKV_SET {GPIO.out1_w1ts.val = CKV;} -#define CKV_CLEAR {GPIO.out1_w1tc.val = CKV;} +#define CKV 0x01 //GPIO32 +#define CKV_SET \ + { \ + GPIO.out1_w1ts.val = CKV; \ + } +#define CKV_CLEAR \ + { \ + GPIO.out1_w1tc.val = CKV; \ + } -#define SPH 0x02 //GPIO33 -#define SPH_SET {GPIO.out1_w1ts.val = SPH;} -#define SPH_CLEAR {GPIO.out1_w1tc.val = SPH;} +#define SPH 0x02 //GPIO33 +#define SPH_SET \ + { \ + GPIO.out1_w1ts.val = SPH; \ + } +#define SPH_CLEAR \ + { \ + GPIO.out1_w1tc.val = SPH; \ + } //#define SPV 15 //GPIO15 //#define SPV_SET {digitalWrite(SPV, HIGH);} //#define SPV_CLEAR {digitalWrite(SPV, LOW);} //I/O Expander - A Channel -#define GMOD 1 //GPIOA1 -#define GMOD_SET {mcp.digitalWrite(GMOD, HIGH);} -#define GMOD_CLEAR {mcp.digitalWrite(GMOD, LOW);} +#define GMOD 1 //GPIOA1 +#define GMOD_SET \ + { \ + mcp.digitalWrite(GMOD, HIGH); \ + } +#define GMOD_CLEAR \ + { \ + mcp.digitalWrite(GMOD, LOW); \ + } -#define OE 0 //GPIOA0 -#define OE_SET {mcp.digitalWrite(OE, HIGH);} -#define OE_CLEAR {mcp.digitalWrite(OE, LOW);} +#define OE 0 //GPIOA0 +#define OE_SET \ + { \ + mcp.digitalWrite(OE, HIGH); \ + } +#define OE_CLEAR \ + { \ + mcp.digitalWrite(OE, LOW); \ + } -#define SPV 2 //GPIOA5 -#define SPV_SET {mcp.digitalWrite(SPV, HIGH);} -#define SPV_CLEAR {mcp.digitalWrite(SPV, LOW);} +#define SPV 2 //GPIOA5 +#define SPV_SET \ + { \ + mcp.digitalWrite(SPV, HIGH); \ + } +#define SPV_CLEAR \ + { \ + mcp.digitalWrite(SPV, LOW); \ + } -#define WAKEUP 3 //GPIOA3 -#define WAKEUP_SET {mcp.digitalWrite(WAKEUP, HIGH);} -#define WAKEUP_CLEAR {mcp.digitalWrite(WAKEUP, LOW);} +#define WAKEUP 3 //GPIOA3 +#define WAKEUP_SET \ + { \ + mcp.digitalWrite(WAKEUP, HIGH); \ + } +#define WAKEUP_CLEAR \ + { \ + mcp.digitalWrite(WAKEUP, LOW); \ + } -#define PWRUP 4 //GPIOA4 -#define PWRUP_SET {mcp.digitalWrite(PWRUP, HIGH);} -#define PWRUP_CLEAR {mcp.digitalWrite(PWRUP, LOW);} +#define PWRUP 4 //GPIOA4 +#define PWRUP_SET \ + { \ + mcp.digitalWrite(PWRUP, HIGH); \ + } +#define PWRUP_CLEAR \ + { \ + mcp.digitalWrite(PWRUP, LOW); \ + } -#define VCOM 5 //GPIOA6 -#define VCOM_SET {mcp.digitalWrite(VCOM, HIGH);} -#define VCOM_CLEAR {mcp.digitalWrite(VCOM, LOW);} +#define VCOM 5 //GPIOA6 +#define VCOM_SET \ + { \ + mcp.digitalWrite(VCOM, HIGH); \ + } +#define VCOM_CLEAR \ + { \ + mcp.digitalWrite(VCOM, LOW); \ + } #define CKV_CLOCK ckvClock(); #ifndef _swap_int16_t -#define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; } +#define _swap_int16_t(a, b) \ + { \ + int16_t t = a; \ + a = b; \ + b = t; \ + } #endif extern Adafruit_MCP23017 mcp; @@ -88,12 +153,13 @@ extern SdFat sd; static void ckvClock(); static void usleep1(); -class Inkplate : public Adafruit_GFX { - public: - uint8_t* D_memory_new; - uint8_t* _partial; - uint8_t* D_memory4Bit; - uint8_t * _pBuffer; +class Inkplate : public Adafruit_GFX +{ +public: + uint8_t *D_memory_new; + uint8_t *_partial; + uint8_t *D_memory4Bit; + uint8_t *_pBuffer; const uint8_t LUT2[16] = {B10101010, B10101001, B10100110, B10100101, B10011010, B10011001, B10010110, B10010101, B01101010, B01101001, B01100110, B01100101, B01011010, B01011001, B01010110, B01010101}; const uint8_t LUTW[16] = {B11111111, B11111110, B11111011, B11111010, B11101111, B11101110, B11101011, B11101010, B10111111, B10111110, B10111011, B10111010, B10101111, B10101110, B10101011, B10101010}; const uint8_t LUTB[16] = {B11111111, B11111101, B11110111, B11110101, B11011111, B11011101, B11010111, B11010101, B01111111, B01111101, B01110111, B01110101, B01011111, B01011101, B01010111, B01010101}; @@ -101,82 +167,85 @@ class Inkplate : public Adafruit_GFX { const uint8_t pixelMaskGLUT[2] = {B00001111, B11110000}; const uint8_t discharge[16] = {B11111111, B11111100, B11110011, B11110000, B11001111, B11001100, B11000011, B11000000, B00111111, B00111100, B00110011, B00110000, B00001111, B00001100, B00000011, B00000000}; //BLACK->WHITE - //THIS IS OKAYISH WAVEFORM FOR GRAYSCALE. IT CAN BE MUCH BETTER. + //THIS IS OKAYISH WAVEFORM FOR GRAYSCALE. IT CAN BE MUCH BETTER. const uint8_t waveform3Bit[8][7] = {{0, 0, 0, 0, 1, 1, 1}, {0, 0, 1, 1, 1, 2, 1}, {0, 1, 1, 2, 1, 2, 1}, {0, 0, 1, 1, 2, 1, 2}, {1, 1, 1, 2, 2, 1, 2}, {0, 0, 1, 1, 1, 2, 2}, {0, 1, 1, 2, 1, 2, 2}, {0, 0, 0, 0, 0, 0, 2}}; - //const uint8_t waveform3Bit[8][12] = {{3,3,3,1,1,1,1,1,1,1,2,0}, {3,3,3,3,1,1,1,1,1,1,2,0}, {3,3,3,3,3,1,1,1,1,1,2,0}, {3,3,3,3,3,3,1,1,1,1,2,0}, {3,3,3,3,3,3,3,1,1,1,2,0}, {3,3,3,3,3,3,3,2,1,1,2,0}, {3,3,3,3,3,3,3,3,3,1,2,0}, {3,3,3,3,3,3,3,3,3,3,2,0}}; - //const uint8_t waveform3Bit[16][12] = {{0,0,0,0,0,0,1,2,1,1,0,3},{0,0,1,1,1,2,2,2,1,1,0,3},{0,0,0,1,1,2,2,2,1,1,0,3}, {0,0,0,1,2,1,2,1,2,1,3}, {0,0,2,1,2,1,2,1,2,1,3}, {0,0,1,2,2,1,1,1,1,2,0,3}, {0,0,0,2,1,1,1,1,0,2,0,3}, {0,0,2,1,2,2,1,1,1,2,0,3}, {0,0,0,2,2,2,1,1,1,2,0,3}, {0,0,0,0,0,0,2,1,1,2,0,3}, {0,0,0,0,0,2,2,1,1,2,0,3}, {0,0,0,0,0,1,1,1,2,2,0,3}, {0,0,0,0,1,2,1,2,1,2,0,3}, {0,0,0,0,1,1,2,2,1,2,0,3},{0,0,0,0,1,1,1,2,2,2,0,3}, {0,0,0,0,0,0,0,0,0,2,0,3}}; - //PVI waveform for cleaning screen, not sure if it is correct, but it cleans screen properly. + //const uint8_t waveform3Bit[8][12] = {{3,3,3,1,1,1,1,1,1,1,2,0}, {3,3,3,3,1,1,1,1,1,1,2,0}, {3,3,3,3,3,1,1,1,1,1,2,0}, {3,3,3,3,3,3,1,1,1,1,2,0}, {3,3,3,3,3,3,3,1,1,1,2,0}, {3,3,3,3,3,3,3,2,1,1,2,0}, {3,3,3,3,3,3,3,3,3,1,2,0}, {3,3,3,3,3,3,3,3,3,3,2,0}}; + //const uint8_t waveform3Bit[16][12] = {{0,0,0,0,0,0,1,2,1,1,0,3},{0,0,1,1,1,2,2,2,1,1,0,3},{0,0,0,1,1,2,2,2,1,1,0,3}, {0,0,0,1,2,1,2,1,2,1,3}, {0,0,2,1,2,1,2,1,2,1,3}, {0,0,1,2,2,1,1,1,1,2,0,3}, {0,0,0,2,1,1,1,1,0,2,0,3}, {0,0,2,1,2,2,1,1,1,2,0,3}, {0,0,0,2,2,2,1,1,1,2,0,3}, {0,0,0,0,0,0,2,1,1,2,0,3}, {0,0,0,0,0,2,2,1,1,2,0,3}, {0,0,0,0,0,1,1,1,2,2,0,3}, {0,0,0,0,1,2,1,2,1,2,0,3}, {0,0,0,0,1,1,2,2,1,2,0,3},{0,0,0,0,1,1,1,2,2,2,0,3}, {0,0,0,0,0,0,0,0,0,2,0,3}}; + //PVI waveform for cleaning screen, not sure if it is correct, but it cleans screen properly. const uint32_t waveform[50] = {0x00000008, 0x00000008, 0x00200408, 0x80281888, 0x60a81898, 0x60a8a8a8, 0x60a8a8a8, 0x6068a868, 0x6868a868, 0x6868a868, 0x68686868, 0x6a686868, 0x5a686868, 0x5a686868, 0x5a586a68, 0x5a5a6a68, 0x5a5a6a68, 0x55566a68, 0x55565a64, 0x55555654, 0x55555556, 0x55555556, 0x55555556, 0x55555516, 0x55555596, 0x15555595, 0x95955595, 0x95959595, 0x95949495, 0x94949495, 0x94949495, 0xa4949494, 0x9494a4a4, 0x84a49494, 0x84948484, 0x84848484, 0x84848484, 0x84848484, 0xa5a48484, 0xa9a4a4a8, 0xa9a8a8a8, 0xa5a9a9a4, 0xa5a5a5a4, 0xa1a5a5a1, 0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0x15151515, 0x11111111}; - - struct bitmapHeader { - uint16_t signature; - uint32_t fileSize; - uint32_t startRAW; - uint32_t dibHeaderSize; - uint32_t width; - uint32_t height; - uint16_t color; - uint32_t compression; - }; - + + struct bitmapHeader + { + uint16_t signature; + uint32_t fileSize; + uint32_t startRAW; + uint32_t dibHeaderSize; + uint32_t width; + uint32_t height; + uint16_t color; + uint32_t compression; + }; + Inkplate(uint8_t _mode); - void begin(void); + void begin(void); void drawPixel(int16_t x0, int16_t y0, uint16_t color); void clearDisplay(); void display(); void partialUpdate(); - void drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char* _p, int16_t _w, int16_t _h); - void setRotation(uint8_t); + void drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h); + void setRotation(uint8_t); void einkOff(void); void einkOn(void); void selectDisplayMode(uint8_t _mode); - uint8_t getDisplayMode(); - int drawBitmapFromSD(SdFile* p, int x, int y, bool invert = false); - int drawBitmapFromSD(char* fileName, int x, int y, bool invert = false); - int drawBitmapFromWeb(WiFiClient* s, int x, int y, int len, bool invert = false); - int drawBitmapFromWeb(char* url, int x, int y, bool invert = false); - int sdCardInit(); - SdFat getSdFat(); - SPIClass getSPI(); - uint8_t getPanelState(); + uint8_t getDisplayMode(); + int drawBitmapFromSD(SdFile *p, int x, int y, bool invert = false); + int drawBitmapFromSD(char *fileName, int x, int y, bool invert = false); + int drawBitmapFromWeb(WiFiClient *s, int x, int y, int len, bool invert = false); + int drawBitmapFromWeb(char *url, int x, int y, bool invert = false); + void drawThickLine(int x1, int y1, int x2, int y2, int color, float thickness); + void drawGradientLine(int x1, int y1, int x2, int y2, int color1, int color2, float thickness = -1); + int sdCardInit(); + SdFat getSdFat(); + SPIClass getSPI(); + uint8_t getPanelState(); uint8_t readTouchpad(uint8_t); int8_t readTemperature(); double readBattery(); - void vscan_start(); - void vscan_write(); - void hscan_start(uint32_t _d = 0); - void vscan_end(); - void clean(); + void vscan_start(); + void vscan_write(); + void hscan_start(uint32_t _d = 0); + void vscan_end(); + void clean(); void cleanFast(uint8_t c, uint8_t rep); void cleanFast2(uint8_t c, uint8_t n, uint16_t d); void pinsZstate(); void pinsAsOutputs(); - private: - uint8_t gammaLUT[256]; +private: + uint8_t gammaLUT[256]; int8_t _temperature; uint8_t _panelOn = 0; uint8_t _rotation = 0; uint8_t _displayMode = 0; //By default, 1 bit mode is used - int sdCardOk = 0; - uint8_t _blockPartial = 1; - uint8_t _beginDone = 0; - - void display1b(); + int sdCardOk = 0; + uint8_t _blockPartial = 1; + uint8_t _beginDone = 0; + + void display1b(); void display3b(); - uint32_t read32(uint8_t* c); - uint16_t read16(uint8_t* c); - void readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h); + uint32_t read32(uint8_t *c); + uint16_t read16(uint8_t *c); + void readBmpHeaderSd(SdFile *_f, struct bitmapHeader *_h); void readBmpHeaderWeb(WiFiClient *_s, struct bitmapHeader *_h); - int drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert); + int drawMonochromeBitmapSd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert); int drawGrayscaleBitmap4Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert); int drawGrayscaleBitmap8Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert); - int drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert); + int drawGrayscaleBitmap24Sd(SdFile *f, struct bitmapHeader bmpHeader, int x, int y, bool invert); int drawMonochromeBitmapWeb(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert); int drawGrayscaleBitmap4Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert); int drawGrayscaleBitmap8Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert); int drawGrayscaleBitmap24Web(WiFiClient *s, struct bitmapHeader bmpHeader, int x, int y, int len, bool invert); - void precalculateGamma(uint8_t* c, float gamma); + void precalculateGamma(uint8_t *c, float gamma); }; #endif diff --git a/examples/3. Projects/1-Weather_station_example/1-Weather_station_example.ino b/examples/3. Projects/1-Weather_station_example/1-Weather_station_example.ino index 7379411..ef317b8 100644 --- a/examples/3. Projects/1-Weather_station_example/1-Weather_station_example.ino +++ b/examples/3. Projects/1-Weather_station_example/1-Weather_station_example.ino @@ -6,51 +6,59 @@ https://e-radionica.com/en/blog/add-inkplate-6-to-arduino-ide/ This example will show you how you can use Inkplate 6 to display API data, - in this example Metaweather public weather API which provide weather info. - As a result, you get a functional weather station which shows today's - forecast and 3 days forecast on your Inkplate display. + e.g. Metaweather public weather API IMPORTANT: - Make sure you have changed your desired city, timezone and WiFi credentials below. - You will also need to install ArduinoJSON library. - Download from here: https://github.com/bblanchon/ArduinoJson + Make sure to change your desired city, timezone and wifi credentials below + Also have ArduinoJSON installed in your Arduino libraries Want to learn more about Inkplate? Visit www.inkplate.io Looking to get support? Write on our forums: http://forum.e-radionica.com/en/ 28 July 2020 by e-radionica.com */ -// ---------------- CHANGE HERE ---------------: +// ---------- CHANGE HERE -------------: -int timeZone = 2; //Update your timezone here. 2 means UTC+2 +// Time zone for adding hours +int timeZone = 2; -char city[128] = "ZAGREB"; //Enter city name you wish to get forecast for +// City search query +char city[128] = "ZAGREB"; -// Change to your WiFi SSID and password -char *ssid = ""; -char *pass = ""; +// Change to your wifi ssid and password +char *ssid = "e-radionica.com"; +char *pass = "croduino"; -#define DELAY_MS 15000 //Delay between screen refreshes goes here - -// ---------------------------------------------- +// ---------------------------------- +// Include Inkplate library to the sketch #include "Inkplate.h" -#include "Network.h" //Header file for easier code readability -//Include custom fonts & icons used + +// Header file for easier code readability +#include "Network.h" + +// Including fonts used #include "Fonts/Roboto_Light_48.h" #include "Fonts/Roboto_Light_36.h" #include "Fonts/Roboto_Light_120.h" -#include "icons.h" //Generated using embedded iconConvert.py script -Inkplate display(INKPLATE_1BIT); //Inkplate object +// Including icons generated by the py file +#include "icons.h" -Network network; // All our network functions are in this object, see Network.h +// Delay between API calls +#define DELAY_MS 15000 -//Constants used for drawing icons +// Inkplate object +Inkplate display(INKPLATE_1BIT); + +// All our network functions are in this object, see Network.h +Network network; + +// Contants used for drawing icons char abbrs[32][16] = {"sn", "sl", "h", "t", "hr", "lr", "s", "hc", "lc", "c"}; const uint8_t *logos[16] = {icon_sn, icon_sl, icon_h, icon_t, icon_hr, icon_lr, icon_s, icon_hc, icon_lc, icon_c}; -//Variables for storing temperature +// Variables for storing temperature char temps[8][4] = { "0F", "0F", @@ -58,7 +66,7 @@ char temps[8][4] = { "0F", }; -//Variables for storing days of the week +// Variables for storing days of the week char days[8][4] = { "", "", @@ -66,13 +74,18 @@ char days[8][4] = { "", }; -long refreshes = 0; //Variable for counting partial refreshes -const int fullRefresh = 10; //Constant to determine when to full update +// Variable for counting partial refreshes +long refreshes = 0; -//Variables for storing current time and weather info +// Constant to determine when to full update +const int fullRefresh = 10; + +// Variables for storing current time and weather info char currentTemp[16] = "0F"; char currentWind[16] = "0m/s"; + char currentTime[16] = "9:41"; + char currentWeather[32] = "-"; char currentWeatherAbbr[8] = "th"; @@ -85,18 +98,18 @@ void drawTime(); void setup() { - //Begin serial and and begin display + // Begin serial and display Serial.begin(115200); - display.begin(); //Call this function only once! + display.begin(); - //Initial cleaning of buffer and physical screen + // Initial cleaning of buffer and physical screen display.clearDisplay(); display.clean(); - //Calling our begin from network.h file + // Calling our begin from network.h file network.begin(city); - //If city not found, write error message and stop + // If city not found, do nothing if (network.location == -1) { display.setCursor(50, 290); @@ -107,57 +120,57 @@ void setup() ; } - //Welcome screen + // Welcome screen display.setCursor(50, 290); display.setTextSize(3); display.print(F("Welcome to Inkplate 6 weather example!")); display.display(); - //Wait a bit before proceeding - delay(3000); + // Wait a bit before proceeding + delay(5000); } void loop() { - //Clear display + // Clear display display.clearDisplay(); - //Get all relevant data, see Network.cpp for info + // Get all relevant data, see Network.cpp for info network.getTime(currentTime); network.getDays(days[0], days[1], days[2], days[3]); network.getData(city, temps[0], temps[1], temps[2], temps[3], currentTemp, currentWind, currentTime, currentWeather, currentWeatherAbbr); - //Draw data, see functions below in Network.cpp for info + // Draw data, see functions below for info drawWeather(); drawCurrent(); drawTemps(); drawCity(); drawTime(); - //Refresh full screen every fullRefresh times + // Refresh full screen every fullRefresh times, defined above if (refreshes % fullRefresh == 0) display.display(); else display.partialUpdate(); - //Go to sleep before checking again + // Go to sleep before checking again esp_sleep_enable_timer_wakeup(1000L * DELAY_MS); (void)esp_light_sleep_start(); ++refreshes; } -//Function for drawing weather info +// Function for drawing weather info void drawWeather() { // Searching for weather state abbreviation for (int i = 0; i < 10; ++i) { - //If found draw specified icon, draw it + // If found draw specified icon if (strcmp(abbrs[i], currentWeatherAbbr) == 0) display.drawBitmap(50, 50, logos[i], 152, 152, BLACK); } - //Draw current weather state + // Draw weather state display.setTextColor(BLACK, WHITE); display.setFont(&Roboto_Light_36); display.setTextSize(1); @@ -165,10 +178,10 @@ void drawWeather() display.println(currentWeather); } -//Function for drawing current time +// Function for drawing current time void drawTime() { - //Drawing current time stored in currentTime variable + // Drawing current time display.setTextColor(BLACK, WHITE); display.setFont(&Roboto_Light_36); display.setTextSize(1); @@ -177,10 +190,10 @@ void drawTime() display.println(currentTime); } -//Function for drawing city name +// Function for drawing city name void drawCity() { - //Drawing city name + // Drawing city name display.setTextColor(BLACK, WHITE); display.setFont(&Roboto_Light_36); display.setTextSize(1); @@ -189,10 +202,10 @@ void drawCity() display.println(city); } -//Function for drawing temperatures +// Function for drawing temperatures void drawTemps() { - //Drawing 4 black rectangles into which temperatures will be written + // Drawing 4 black rectangles in which temperatures will be written int rectWidth = 150; int rectSpacing = (800 - rectWidth * 4) / 5; @@ -203,7 +216,6 @@ void drawTemps() int textMargin = 6; - //Setting font specifics, writing the actual weather info display.setFont(&Roboto_Light_48); display.setTextSize(1); display.setTextColor(WHITE, BLACK); @@ -220,7 +232,7 @@ void drawTemps() display.setCursor(4 * rectSpacing + 3 * rectWidth + textMargin, 300 + textMargin + 70); display.println(days[3]); - //Drawing temperature values into black rectangles + // Drawing temperature values into black rectangles display.setFont(&Roboto_Light_48); display.setTextSize(1); display.setTextColor(WHITE, BLACK); @@ -242,10 +254,10 @@ void drawTemps() display.println(F("C")); } -//Current weather drawing function +// Current weather drawing function void drawCurrent() { - //Drawing current information + // Drawing current information // Temperature: display.setFont(&Roboto_Light_120); @@ -264,7 +276,7 @@ void drawCurrent() display.setCursor(x, y); display.println(F("C")); - //Wind: + // Wind: display.setFont(&Roboto_Light_120); display.setTextSize(1); display.setTextColor(BLACK, WHITE); @@ -281,7 +293,7 @@ void drawCurrent() display.setCursor(x, y); display.println(F("m/s")); - //Labels underneath + // Labels underneath display.setFont(&Roboto_Light_36); display.setTextSize(1); diff --git a/examples/3. Projects/1-Weather_station_example/Network.cpp b/examples/3. Projects/1-Weather_station_example/Network.cpp index 5f7f925..bd5f46d 100644 --- a/examples/3. Projects/1-Weather_station_example/Network.cpp +++ b/examples/3. Projects/1-Weather_station_example/Network.cpp @@ -1,5 +1,5 @@ -//Network.cpp contains various functions and classes that enable Weather station -//They have been declared in seperate file to increase readability +// Network.cpp contains various functions and classes that enable Weather station +// They have been declared in seperate file to increase readability #include "Network.h" #include @@ -9,13 +9,13 @@ #include -//WiFiMulti object declaration +// WiFiMulti object declaration WiFiMulti WiFiMulti; -//Static Json from ArduinoJson library +// Static Json from ArduinoJson library StaticJsonDocument<6000> doc; -//Declared week days +// Declared week days char weekDays[8][8] = { "Mon", "Tue", @@ -28,92 +28,89 @@ char weekDays[8][8] = { void Network::begin(char *city) { - //Initiating wifi, like in BasicHttpClient example + // Initiating wifi, like in BasicHttpClient example WiFi.mode(WIFI_STA); WiFiMulti.addAP(ssid, pass); Serial.print(F("Waiting for WiFi to connect...")); while ((WiFiMulti.run() != WL_CONNECTED)) { - //Printing a dot to Serial monitor every second while waiting to connect + // Printing a dot to Serial monitor every second while waiting to connect Serial.print(F(".")); delay(1000); } Serial.println(F(" connected")); - //Find internet time + // Find internet time setTime(); - //Search for given cities woeid + // Search for given cities woeid findCity(city); - //reduce power by making WiFi module sleep + // reduce power by making WiFi module sleep WiFi.setSleep(1); } -//Gets time from ntp server +// Gets time from ntp server void Network::getTime(char *timeStr) { - //Get seconds since 1.1.1970. + // Get seconds since 1.1.1970. time_t nowSecs = time(nullptr); - //Struct used to store time + // Used to store time struct tm timeinfo; gmtime_r(&nowSecs, &timeinfo); //Copies time string into timeStr strncpy(timeStr, asctime(&timeinfo) + 11, 5); - //Setting time string timezone + // Setting time string timezone int hr = 10 * timeStr[0] + timeStr[1] + timeZone; - //Better defined modulo, in case timezone makes hours to go below 0 + // Better defined modulo, in case timezone makes hours to go below 0 hr = (hr % 24 + 24) % 24; - //Adding time to '0' char makes it into whatever time char, for both digits + // Adding time to '0' char makes it into whatever time char, for both digits timeStr[0] = hr / 10 + '0'; timeStr[1] = hr % 10 + '0'; } -//Helper function to convert float to char* void formatTemp(char *str, float temp) { - //Built in function for float to char* conversion + // Built in function for float to char* conversion dtostrf(temp, 2, 0, str); } -//Helper function to convert float to char* void formatWind(char *str, float wind) { - //Built in function for float to char* conversion + // Built in function for float to char* conversion dtostrf(wind, 2, 0, str); } -//Function that connects to API and gets the weather data void Network::getData(char *city, char *temp1, char *temp2, char *temp3, char *temp4, char *currentTemp, char *currentWind, char *currentTime, char *currentWeather, char *currentWeatherAbbr) { - //Return if wifi isn't connected + // Return if wifi isn't connected if (WiFi.status() != WL_CONNECTED) return; - //Wake up WiFi if sleeping and save inital state + // Wake up if sleeping and save inital state bool sleep = WiFi.getSleep(); WiFi.setSleep(false); - //HTTP object used to make get request + // Http object used to make get request HTTPClient http; http.getStream().setNoDelay(true); http.getStream().setTimeout(1); - //Add woeid to api call. woeid is API specific variable name used to set location + // Add woeid to api call char url[256]; sprintf(url, "https://www.metaweather.com/api/location/%d/", location); - //Initiate http + // Initiate http http.begin(url); - //Actually make HTTPS GET request + // Actually do request int httpCode = http.GET(); if (httpCode == 200) { @@ -121,10 +118,10 @@ void Network::getData(char *city, char *temp1, char *temp2, char *temp3, char *t if (len > 0) { - //Try parsing JSON object + // Try parsing JSON object DeserializationError error = deserializeJson(doc, http.getStream()); - //If an error happens print it to Serial monitor + // If an error happens print it to Serial monitor if (error) { Serial.print(F("deserializeJson() failed: ")); @@ -132,8 +129,8 @@ void Network::getData(char *city, char *temp1, char *temp2, char *temp3, char *t } else { - //Set all data got from internet using formatTemp and formatWind defined above - //This part relies heavily on ArduinoJson library + // Set all data got from internet using formatTemp and formatWind defined above + // This part relies heavily on ArduinoJson library formatTemp(currentTemp, doc["consolidated_weather"][0][F("the_temp")].as()); formatWind(currentWind, doc["consolidated_weather"][0][F("wind_speed")].as()); @@ -149,18 +146,17 @@ void Network::getData(char *city, char *temp1, char *temp2, char *temp3, char *t } } - //Clear document and end http + // Clear document and end http doc.clear(); http.end(); - //Return to initial state + // Return to initial state WiFi.setSleep(sleep); } -//Used to set correct time received from NTP server void Network::setTime() { - //Used for setting correct time + // Used for setting correct time configTime(0, 0, "pool.ntp.org", "time.nist.gov"); Serial.print(F("Waiting for NTP time sync: ")); @@ -176,7 +172,7 @@ void Network::setTime() Serial.println(); - //Used to store time info + // Used to store time info struct tm timeinfo; gmtime_r(&nowSecs, &timeinfo); @@ -184,17 +180,16 @@ void Network::setTime() Serial.print(asctime(&timeinfo)); } -//From epoch received from NTP server, get day of the week void Network::getDays(char *day, char *day1, char *day2, char *day3) { // Seconds since 1.1.1970. time_t nowSecs = time(nullptr); - //Find weekday + // Find weekday - //We get seconds since 1970, add 3600 (1 hour) times the time zone and add 3 to - //make monday the first day of the week, as 1.1.1970. was a thursday - //finally do mod 7 to insure our day is within [0, 6] + // We get seconds since 1970, add 3600 (1 hour) times the time zone and add 3 to + // make monday the first day of the week, as 1.1.1970. was a thursday + // finally do mod 7 to insure our day is within [0, 6] int dayWeek = ((long)((nowSecs + 3600L * timeZone) / 86400L) + 3) % 7; // Copy day data to globals in main file @@ -204,32 +199,31 @@ void Network::getDays(char *day, char *day1, char *day2, char *day3) strncpy(day3, weekDays[(dayWeek + 3) % 7], 3); } -//Make API query to receive city woeid - city identification specific to API void Network::findCity(char *city) { - //If not connected to WiFi, return + // If not connected to wifi, return if (WiFi.status() != WL_CONNECTED) return; - //Wake WiFi module and save initial state + // Wake wifi module and save initial state bool sleep = WiFi.getSleep(); WiFi.setSleep(false); - //HTTP object + // Http object HTTPClient http; http.getStream().setNoDelay(true); http.getStream().setTimeout(1); - //Add query parameter to URL + // Add query param to url char url[256]; strcpy(url, "https://www.metaweather.com/api/location/search/?query="); strcat(url, city); - //Initiate HTTP + // Initiate http http.begin(url); - //Make GET HTTP request + // Do get request int httpCode = http.GET(); if (httpCode == 200) // 200: http success { @@ -237,10 +231,10 @@ void Network::findCity(char *city) if (len > 0) { - //Try to parse JSON object + // Try to parse JSON object DeserializationError error = deserializeJson(doc, http.getStream()); - //Print error to Serial monitor if one exists + // Print error to Serial monitor if one exsists if (error) { Serial.print(F("deserializeJson() failed: ")); @@ -248,14 +242,14 @@ void Network::findCity(char *city) } else { - //Empty list means no matches for the city + // Empty list means no matches if (doc.size() == 0) { Serial.println(F("City not found")); } else { - //woeid id used for fetching data later on + // Woeid id used for fetching data later on location = doc[0]["woeid"].as(); Serial.println(F("Found city, woied:")); @@ -265,10 +259,10 @@ void Network::findCity(char *city) } } - //Clear document and end http + // Clear document and end http doc.clear(); http.end(); - //Return module to initial state + // Return module to initial state WiFi.setSleep(sleep); -}; +}; \ No newline at end of file diff --git a/examples/3. Projects/1-Weather_station_example/iconConvert.py b/examples/3. Projects/1-Weather_station_example/iconConvert.py index 4c30e61..387d38f 100644 --- a/examples/3. Projects/1-Weather_station_example/iconConvert.py +++ b/examples/3. Projects/1-Weather_station_example/iconConvert.py @@ -5,8 +5,6 @@ # # Takes all files from /icons and saves them to /binary_icons # -#July 2020 by e-radionica.com -# # ----------- from PIL import Image