udisplay lib

This commit is contained in:
gemu2015 2021-04-11 12:30:50 +02:00
parent b5777aeb25
commit 16e397dbd7
6 changed files with 774 additions and 0 deletions

View File

@ -1243,6 +1243,16 @@ void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
textsize_y = (s_y > 0) ? s_y : 1;
}
void Adafruit_GFX::setwidth(uint16_t w) {
WIDTH = w;
_width = w;
}
void Adafruit_GFX::setheight(uint16_t h) {
HEIGHT = h;
_height = h;
}
/**************************************************************************/
/*!
@brief Set rotation setting for display

View File

@ -187,6 +187,10 @@ virtual void
/************************************************************************/
int16_t height(void) const { return _height; }
void setwidth(uint16_t w);
void setheight(uint16_t h);
/************************************************************************/
/*!
@brief Get rotation setting for display

View File

@ -0,0 +1,30 @@
#######################################
# Syntax Coloring Map
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
ST7789 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
setRotation KEYWORD2
setAddrWindow KEYWORD2
pushColor KEYWORD2
drawPixel KEYWORD2
drawFastVLine KEYWORD2
drawFastHLine KEYWORD2
fillRect KEYWORD2
setRotation KEYWORD2
setRotation KEYWORD2
height KEYWORD2
width KEYWORD2
invertDisplay KEYWORD2
drawImage KEYWORD2
setScrollArea KEYWORD2
scroll KEYWORD2

View File

@ -0,0 +1,9 @@
name=universal display Library
version=0.1
author=Gerhard Mutz
maintainer=Gerhard Mutz
sentence=This is a library a couple of displays.
paragraph=This is a library a couple of displays.
category=Display
url=https://github.com/arendst/Tasmota
architectures=*

View File

@ -0,0 +1,607 @@
/*
uDisplay.cpp - universal display driver support for Tasmota
Copyright (C) 2021 Gerhard Mutz and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include <Wire.h>
#include <SPI.h>
#include "uDisplay.h"
const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\
UDISP_YELLOW,UDISP_NAVY,UDISP_DARKGREEN,UDISP_DARKCYAN,UDISP_MAROON,UDISP_PURPLE,UDISP_OLIVE,\
UDISP_LIGHTGREY,UDISP_DARKGREY,UDISP_ORANGE,UDISP_GREENYELLOW,UDISP_PINK};
uint16_t uDisplay::GetColorFromIndex(uint8_t index) {
if (index >= sizeof(udisp_colors) / 2) index = 0;
return udisp_colors[index];
}
extern uint8_t *buffer;
uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
// analyse decriptor
uint8_t section = 0;
dsp_ncmds = 0;
char linebuff[128];
while (*lp) {
uint16_t llen = strlen_ln(lp);
strncpy(linebuff, lp, llen);
linebuff[llen] = 0;
lp += llen;
char *lp1 = linebuff;
if (*lp1 == '#') break;
if (*lp1 == '\n') lp1++;
while (*lp1 == ' ') lp1++;
//Serial.printf(">> %s\n",lp1);
if (*lp1 != ';') {
// check ids:
if (*lp1 == ':') {
// id line
lp1++;
section = *lp1++;
} else {
switch (section) {
case 'H':
// header line
// SD1306,128,64,1,I2C,5a,*,*,*
str2c(&lp1, dname, sizeof(dname));
char ibuff[16];
gxs = next_val(&lp1);
setwidth(gxs);
gys = next_val(&lp1);
setheight(gys);
bpp = next_val(&lp1);
str2c(&lp1, ibuff, sizeof(ibuff));
if (!strncmp(ibuff, "I2C", 3)) {
interface = _UDSP_I2C;
i2caddr = next_hex(&lp1);
i2c_scl = next_val(&lp1);
i2c_sda = next_val(&lp1);
reset = next_val(&lp1);
section = 0;
} else if (!strncmp(ibuff, "SPI", 3)) {
interface = _UDSP_SPI;
spi_nr = next_val(&lp1);
spi_cs = next_val(&lp1);
spi_clk = next_val(&lp1);
spi_mosi = next_val(&lp1);
spi_dc = next_val(&lp1);
bpanel = next_val(&lp1);
reset = next_val(&lp1);
spi_miso = next_val(&lp1);
spi_speed = next_val(&lp1);
section = 0;
Serial.printf("%d %d %d %d %d %d %d %d\n", spi_cs, spi_clk, spi_mosi, spi_dc, bpanel, reset, spi_miso, spi_speed);
}
break;
case 'S':
splash_font = next_val(&lp1);
splash_size = next_val(&lp1);
fg_col = next_val(&lp1);
if (bpp == 16) {
fg_col = GetColorFromIndex(fg_col);
}
bg_col = next_val(&lp1);
if (bpp == 16) {
bg_col = GetColorFromIndex(bg_col);
}
splash_xp = next_val(&lp1);
splash_yp = next_val(&lp1);
break;
case 'I':
// init data
if (interface == _UDSP_I2C) {
dsp_cmds[dsp_ncmds++] = next_hex(&lp1);
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
}
} else {
while (1) {
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
} else {
break;
}
if (dsp_ncmds >= sizeof(dsp_cmds)) break;
}
}
break;
case 'o':
str2c(&lp1, ibuff, sizeof(ibuff));
dsp_off = strtol(ibuff, 0, 16);
break;
case 'O':
str2c(&lp1, ibuff, sizeof(ibuff));
dsp_on = strtol(ibuff, 0, 16);
break;
case '0':
rot_0 = next_hex(&lp1);
break;
case '1':
rot_1 = next_hex(&lp1);
break;
case '2':
rot_2 = next_hex(&lp1);
break;
case '3':
rot_3 = next_hex(&lp1);
break;
case 'A':
saw_1 = next_hex(&lp1);
saw_2 = next_hex(&lp1);
saw_3 = next_hex(&lp1);
break;
}
}
}
if (*lp == '\n') {
lp++;
} else {
lp = strchr(lp, '\n');
if (!lp) break;
lp++;
}
}
}
Renderer *uDisplay::Init(void) {
if (reset >= 0) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
delay(50);
digitalWrite(reset, LOW);
delay(50);
digitalWrite(reset, HIGH);
delay(200);
}
if (interface == _UDSP_I2C) {
Wire.begin(i2c_sda, i2c_scl);
if (bpp < 16) {
if (buffer) free(buffer);
buffer = (uint8_t*)calloc((width()*height()*bpp)/8, 1);
for (uint32_t cnt = 0; cnt < dsp_ncmds; cnt++) {
i2c_command(dsp_cmds[cnt]);
}
}
}
if (interface == _UDSP_SPI) {
if (bpanel >= 0) {
#ifdef ESP32
ledcSetup(ESP32_PWM_CHANNEL, 4000, 8);
ledcAttachPin(bpanel, ESP32_PWM_CHANNEL);
ledcWrite(ESP32_PWM_CHANNEL, 128);
#else
pinMode(bpanel, OUTPUT);
digitalWrite(bpanel, HIGH);
#endif // ESP32
}
if (spi_dc >= 0) {
pinMode(spi_dc, OUTPUT);
digitalWrite(spi_dc, HIGH);
}
if (spi_cs >= 0) {
pinMode(spi_cs, OUTPUT);
digitalWrite(spi_cs, HIGH);
}
spiSettings = SPISettings(spi_speed, MSBFIRST, SPI_MODE3);
#ifdef ESP8266
SPI.begin();
uspi = &SPI;
#else
if (spi_nr != 1) {
uspi = new SPIClass(HSPI);
} else {
uspi = &SPI;
}
uspi->begin(spi_clk, spi_miso, spi_mosi, -1);
#endif
uint16_t index = 0;
SPI_BEGIN_TRANSACTION
while (1) {
uint8_t iob;
SPI_CS_LOW
SPI_DC_LOW
iob = dsp_cmds[index++];
uspi->write(iob);
SPI_DC_HIGH
uint8_t args = dsp_cmds[index++];
//Serial.printf("cmd, args %x, %d ", iob, args&0x7f);
for (uint32_t cnt = 0; cnt < (args & 0x7f); cnt++) {
iob = dsp_cmds[index++];
//Serial.printf("%02x ", iob );
uspi->write(iob);
}
SPI_CS_HIGH
//Serial.printf("\n");
if (args & 0x80) delay(120);
if (index >= dsp_ncmds) break;
}
SPI_END_TRANSACTION
}
return this;
}
void uDisplay::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
setRotation(rot);
invertDisplay(false);
setTextWrap(false);
cp437(true);
setTextFont(font);
setTextSize(size);
setTextColor(fg_col, bg_col);
setCursor(0,0);
fillScreen(bg_col);
Updateframe();
}
void uDisplay::spi_command(uint8_t val) {
SPI_BEGIN_TRANSACTION
SPI_DC_LOW
SPI_CS_LOW
uspi->write(val);
SPI_CS_HIGH
SPI_DC_HIGH
SPI_END_TRANSACTION
}
void uDisplay::i2c_command(uint8_t val) {
//Serial.printf("%02x\n",val );
Wire.beginTransmission(i2caddr);
Wire.write(0);
Wire.write(val);
Wire.endTransmission();
}
#define SH1106_SETLOWCOLUMN 0
#define SH1106_SETHIGHCOLUMN 0x10
#define SH1106_SETSTARTLINE 0x40
void uDisplay::Updateframe(void) {
if (interface == _UDSP_I2C) {
i2c_command(SH1106_SETLOWCOLUMN | 0x0); // low col = 0
i2c_command(SH1106_SETHIGHCOLUMN | 0x0); // hi col = 0
i2c_command(SH1106_SETSTARTLINE | 0x0); // line #0
uint8_t ys = gys >> 3;
uint8_t xs = gxs >> 3;
//uint8_t xs = 132 >> 3;
uint8_t m_row = 0;
uint8_t m_col = 2;
uint16_t p = 0;
uint8_t i, j, k = 0;
for ( i = 0; i < ys; i++) {
// send a bunch of data in one xmission
i2c_command(0xB0 + i + m_row);//set page address
i2c_command(m_col & 0xf);//set lower column address
i2c_command(0x10 | (m_col >> 4));//set higher column address
for( j = 0; j < 8; j++){
Wire.beginTransmission(i2caddr);
Wire.write(0x40);
for ( k = 0; k < xs; k++, p++) {
Wire.write(buffer[p]);
}
Wire.endTransmission();
}
}
}
}
void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::drawFastVLine(x, y, h, color);
return;
}
// Rudimentary clipping
if ((x >= _width) || (y >= _height)) return;
if ((y + h - 1) >= _height) h = _height - y;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, 1, h);
while (h--) {
uspi->write16(color);
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::drawFastHLine(x, y, w, color);
return;
}
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((x+w-1) >= _width) w = _width-x;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, w, 1);
while (w--) {
uspi->write16(color);
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::fillScreen(uint16_t color) {
fillRect(0, 0, gxs, gys, color);
}
// fill a rectangle
void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::fillRect(x, y, w, h, color);
return;
}
// rudimentary clipping (drawChar w/big text requires this)
if((x >= gxs) || (y >= gys)) return;
if((x + w - 1) >= gxs) w = gxs - x;
if((y + h - 1) >= gys) h = gys - y;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, w, h);
for (y = h; y > 0; y--) {
for (x = w; x > 0; x--) {
uspi->write16(color);
}
}
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::Splash(void) {
setTextFont(splash_font);
setTextSize(splash_size);
DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0);
Updateframe();
}
void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
if (!x0 && !y0 && !x1 && !y1) {
SPI_CS_HIGH
SPI_END_TRANSACTION
} else {
SPI_CS_LOW
SPI_BEGIN_TRANSACTION
setAddrWindow_int(x0, y0, x1 - x0, y1 - y0 );
}
}
void uDisplay::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
SPI_DC_LOW
uspi->write(saw_1);
SPI_DC_HIGH
uspi->write32(xa);
SPI_DC_LOW
uspi->write(saw_2);
SPI_DC_HIGH
uspi->write32(ya);
SPI_DC_LOW
uspi->write(saw_3); // write to RAM
SPI_DC_HIGH
}
void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean first) {
uint16_t color;
while (len--) {
color = *data++;
uspi->write16(color);
}
}
void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) {
if (interface != _UDSP_SPI) {
Renderer::drawPixel(x, y, color);
return;
}
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
SPI_BEGIN_TRANSACTION
SPI_CS_LOW
setAddrWindow_int(x, y, 1, 1);
uspi->write16(color);
SPI_CS_HIGH
SPI_END_TRANSACTION
}
void uDisplay::setRotation(uint8_t m) {
if (interface != _UDSP_SPI) {
Renderer::setRotation(m);
return;
}
switch (rotation) {
case 0:
if (interface == _UDSP_SPI) spi_command(rot_0);
_width = gxs;
_height = gys;
break;
case 1:
if (interface == _UDSP_SPI) spi_command(rot_1);
_width = gys;
_height = gxs;
break;
case 2:
if (interface == _UDSP_SPI) spi_command(rot_2);
_width = gxs;
_height = gys;
break;
case 3:
if (interface == _UDSP_SPI) spi_command(rot_3);
_width = gys;
_height = gxs;
break;
}
}
void uDisplay::DisplayOnff(int8_t on) {
if (interface == _UDSP_I2C) {
if (on) {
i2c_command(dsp_on);
} else {
i2c_command(dsp_off);
}
} else {
if (on) {
spi_command(dsp_on);
if (bpanel >= 0) {
#ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
#else
digitalWrite(bpanel, HIGH);
#endif
}
} else {
spi_command(dsp_off);
if (bpanel >= 0) {
#ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, 0);
#else
digitalWrite(bpanel, LOW);
#endif
}
}
}
}
void uDisplay::dim(uint8_t dim) {
dimmer = dim;
if (dimmer > 15) dimmer = 15;
dimmer = ((float)dimmer / 15.0) * 255.0;
#ifdef ESP32
ledcWrite(ESP32_PWM_CHANNEL, dimmer);
#endif
}
uint8_t uDisplay::strlen_ln(char *str) {
for (uint32_t cnt = 0; cnt < 256; cnt++) {
if (!str[cnt] || str[cnt] == '\n') return cnt;
}
return 0;
}
char *uDisplay::devname(void) {
return dname;
}
uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) {
char *lp = *sp;
if (len) len--;
char *cp = strchr(lp, ',');
if (cp) {
while (1) {
if (*lp == ',') {
*vp = 0;
*sp = lp + 1;
return 0;
}
if (len) {
*vp++ = *lp++;
len--;
} else {
lp++;
}
}
} else {
uint8_t slen = strlen(lp);
if (slen) {
strlcpy(vp, *sp, len);
*sp = lp + slen;
return 0;
}
}
return 1;
}
int32_t uDisplay::next_val(char **sp) {
char ibuff[16];
str2c(sp, ibuff, sizeof(ibuff));
return atoi(ibuff);
}
uint32_t uDisplay::next_hex(char **sp) {
char ibuff[16];
str2c(sp, ibuff, sizeof(ibuff));
return strtol(ibuff, 0, 16);
}

View File

@ -0,0 +1,114 @@
#ifndef _UDISP_
#define _UDISP_
#include <Adafruit_GFX.h>
#include <renderer.h>
#define _UDSP_I2C 1
#define _UDSP_SPI 2
#define UDISP1_WHITE 1
#define UDISP1_BLACK 0
// Color definitions
#define UDISP_BLACK 0x0000 /* 0, 0, 0 */
#define UDISP_NAVY 0x000F /* 0, 0, 128 */
#define UDISP_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define UDISP_DARKCYAN 0x03EF /* 0, 128, 128 */
#define UDISP_MAROON 0x7800 /* 128, 0, 0 */
#define UDISP_PURPLE 0x780F /* 128, 0, 128 */
#define UDISP_OLIVE 0x7BE0 /* 128, 128, 0 */
#define UDISP_LIGHTGREY 0xC618 /* 192, 192, 192 */
#define UDISP_DARKGREY 0x7BEF /* 128, 128, 128 */
#define UDISP_BLUE 0x001F /* 0, 0, 255 */
#define UDISP_GREEN 0x07E0 /* 0, 255, 0 */
#define UDISP_CYAN 0x07FF /* 0, 255, 255 */
#define UDISP_RED 0xF800 /* 255, 0, 0 */
#define UDISP_MAGENTA 0xF81F /* 255, 0, 255 */
#define UDISP_YELLOW 0xFFE0 /* 255, 255, 0 */
#define UDISP_WHITE 0xFFFF /* 255, 255, 255 */
#define UDISP_ORANGE 0xFD20 /* 255, 165, 0 */
#define UDISP_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
#define UDISP_PINK 0xF81F
#define SPI_BEGIN_TRANSACTION uspi->beginTransaction(spiSettings);
#define SPI_END_TRANSACTION uspi->endTransaction();
#define SPI_CS_LOW if (spi_cs >= 0) digitalWrite(spi_cs, LOW);
#define SPI_CS_HIGH if (spi_cs >= 0) digitalWrite(spi_cs, HIGH);
#define SPI_DC_LOW if (spi_dc >= 0) digitalWrite(spi_dc, LOW);
#define SPI_DC_HIGH if (spi_dc >= 0) digitalWrite(spi_dc, HIGH);
#define ESP32_PWM_CHANNEL 1
class uDisplay : public Renderer {
public:
uDisplay(char *);
Renderer *Init(void);
void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font);
void Updateframe();
void DisplayOnff(int8_t on);
void Splash(void);
char *devname(void);
uint16_t fgcol(void) const { return fg_col; };
uint16_t bgcol(void) const { return bg_col; };
void dim(uint8_t dim);
uint16_t GetColorFromIndex(uint8_t index);
void setRotation(uint8_t m);
void fillScreen(uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void pushColors(uint16_t *data, uint16_t len, boolean first);
private:
void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
uint32_t str2c(char **sp, char *vp, uint32_t len);
void i2c_command(uint8_t val);
void spi_command(uint8_t val);
uint8_t strlen_ln(char *str);
int32_t next_val(char **sp);
uint32_t next_hex(char **sp);
void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
char dname[16];
int8_t bpp;
uint8_t interface;
uint8_t i2caddr;
int8_t i2c_scl;
int8_t i2c_sda;
int8_t reset;
uint8_t dsp_cmds[128];
uint8_t dsp_ncmds;
uint8_t dsp_on;
uint8_t dsp_off;
uint16_t splash_font;
uint16_t splash_size;
uint16_t splash_xp;
uint16_t splash_yp;
uint16_t fg_col;
uint16_t bg_col;
uint16_t gxs;
uint16_t gys;
int8_t spi_cs;
int8_t spi_clk;
int8_t spi_mosi;
int8_t spi_dc;
int8_t bpanel;
int8_t spi_miso;
uint8_t dimmer;
SPIClass *uspi;
SPISettings spiSettings;
uint32_t spi_speed;
uint8_t spi_nr = 1;
uint8_t rot_0;
uint8_t rot_1;
uint8_t rot_2;
uint8_t rot_3;
uint8_t saw_1;
uint8_t saw_2;
uint8_t saw_3;
uint8_t flags;
};
#endif // _UDISP_