v0.8.933
This commit is contained in:
80
yoRadio/src/ILI9488/GFXcanvas16T.h
Normal file
80
yoRadio/src/ILI9488/GFXcanvas16T.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef _GFXcanvas16T_H_
|
||||
#define _GFXcanvas16T_H_
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
template<const uint16_t w, uint16_t h>
|
||||
class GFXcanvas16T : public Adafruit_GFX
|
||||
{
|
||||
public:
|
||||
GFXcanvas16T() : Adafruit_GFX(w, h) {};
|
||||
void drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
|
||||
int16_t t;
|
||||
switch (rotation) {
|
||||
case 1:
|
||||
t = x;
|
||||
x = WIDTH - 1 - y;
|
||||
y = t;
|
||||
break;
|
||||
case 2:
|
||||
x = WIDTH - 1 - x;
|
||||
y = HEIGHT - 1 - y;
|
||||
break;
|
||||
case 3:
|
||||
t = x;
|
||||
x = y;
|
||||
y = HEIGHT - 1 - t;
|
||||
break;
|
||||
}
|
||||
buffer[x + y * WIDTH] = color;
|
||||
}
|
||||
void fillScreen(uint16_t color)
|
||||
{
|
||||
uint32_t i, pixels = WIDTH * HEIGHT;
|
||||
for (i = 0; i < pixels; i++) buffer[i] = color;
|
||||
}
|
||||
uint16_t *getBuffer(void)
|
||||
{
|
||||
return buffer;
|
||||
}
|
||||
#if 1
|
||||
template<class T>
|
||||
void print(T target, const char* name = 0, bool as_progmem = false)
|
||||
{
|
||||
static const uint16_t per_line = 10;
|
||||
uint32_t remain = WIDTH * HEIGHT;
|
||||
uint16_t* p = buffer;
|
||||
if (!name) name = "canvas16";
|
||||
if (as_progmem) target.print(F("const "));
|
||||
target.print(F("uint16_t ")); target.print(name); target.print(F("[] "));
|
||||
if (as_progmem) target.print(F("PROGMEM "));
|
||||
target.println(F("=")); target.println(F("{"));
|
||||
while (remain > per_line)
|
||||
{
|
||||
target.print(F(" "));
|
||||
for (uint16_t i = 0; i < per_line; i++)
|
||||
{
|
||||
target.print(F("0x")); target.print(*p++, HEX); target.print(F(", "));
|
||||
}
|
||||
remain -= per_line;
|
||||
if (remain > 0) target.println();
|
||||
#if defined (ESP8266)
|
||||
yield();
|
||||
#endif
|
||||
}
|
||||
if (remain > 0) target.print(F(" "));
|
||||
while (remain-- > 0)
|
||||
{
|
||||
target.print(F("0x")); target.print(*p++, HEX); target.print(F(", "));
|
||||
}
|
||||
target.println();
|
||||
target.println(F("};"));
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
uint16_t buffer[w * h];
|
||||
};
|
||||
|
||||
#endif
|
||||
719
yoRadio/src/ILI9488/ILI9486_SPI.cpp
Normal file
719
yoRadio/src/ILI9488/ILI9486_SPI.cpp
Normal file
@@ -0,0 +1,719 @@
|
||||
// created by Jean-Marc Zingg to be a standalone ILI9486_SPI library (instead of the GxCTRL_ILI9486_SPI class for the GxTFT library)
|
||||
// code extracts taken from https://github.com/Bodmer/TFT_HX8357
|
||||
// spi kludge handling solution found in https://github.com/Bodmer/TFT_eSPI
|
||||
// code extracts taken from https://github.com/adafruit/Adafruit-GFX-Library
|
||||
//
|
||||
// License: GNU GENERAL PUBLIC LICENSE V3, see LICENSE
|
||||
//
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ILI9488 || DSP_MODEL==DSP_ILI9486
|
||||
|
||||
#include <SPI.h>
|
||||
#include "ILI9486_SPI.h"
|
||||
|
||||
#define SPI_SPEED 40000000UL
|
||||
//#define SPI_SPEED 20000000 // max reliable speed is 20Mhz for RPi SPI kludge
|
||||
//#define SPI_SPEED 4000000
|
||||
|
||||
#define ILI9486_SPI_CASET 0x2A
|
||||
#define ILI9486_SPI_PASET 0x2B
|
||||
#define ILI9486_SPI_RAMWR 0x2C
|
||||
#define ILI9486_SPI_RAMRD 0x2E
|
||||
#define ILI9486_SPI_MADCTL 0x36
|
||||
#define MADCTL_MY 0x80
|
||||
#define MADCTL_MX 0x40
|
||||
#define MADCTL_MV 0x20
|
||||
#define MADCTL_ML 0x10
|
||||
#define MADCTL_BGR 0x08
|
||||
#define MADCTL_MH 0x04
|
||||
|
||||
#define ILI9488_INVOFF 0x20
|
||||
#define ILI9488_INVON 0x21
|
||||
|
||||
//ILI9486_SPI::ILI9486_SPI(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(320, 480), _spi_settings(SPI_SPEED, MSBFIRST, SPI_MODE0)
|
||||
ILI9486_SPI::ILI9486_SPI(int8_t cs, int8_t dc, int8_t rst) : ILI9486_SPI(&SPI, cs, dc, rst) { }
|
||||
|
||||
ILI9486_SPI::ILI9486_SPI(SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(320, 480), _spi_settings(SPI_SPEED, MSBFIRST, SPI_MODE0)
|
||||
{
|
||||
_spi = spiClass;
|
||||
_spi16_mode = true;
|
||||
_cs = cs;
|
||||
_dc = dc;
|
||||
_rst = rst;
|
||||
_bgr = MADCTL_BGR;
|
||||
#if defined(ESP8266)
|
||||
if ((_cs >= 0) && (_dc >= 0))
|
||||
{
|
||||
_cs_pinmask = (uint32_t) digitalPinToBitMask(_cs);
|
||||
_dc_pinmask = (uint32_t) digitalPinToBitMask(_dc);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cs_pinmask = 0;
|
||||
_dc_pinmask = 0;
|
||||
}
|
||||
#endif
|
||||
_x_address_set = -1;
|
||||
_x_address_set = -1;
|
||||
digitalWrite(_cs, HIGH);
|
||||
digitalWrite(_dc, HIGH);
|
||||
pinMode(_cs, OUTPUT);
|
||||
pinMode(_dc, OUTPUT);
|
||||
if (rst >= 0)
|
||||
{
|
||||
digitalWrite(rst, HIGH);
|
||||
pinMode(rst, OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
// *** (overridden) virtual methods ***
|
||||
|
||||
#if defined(ESP8266) && true // This is for the RPi display that needs 16 bits
|
||||
|
||||
#define CMD_BITS (16-1)
|
||||
|
||||
void ILI9486_SPI::drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
// Range checking
|
||||
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
|
||||
if (_spi16_mode && _cs_pinmask)
|
||||
{
|
||||
_spi->beginTransaction(_spi_settings);
|
||||
GPOC = _cs_pinmask;
|
||||
SPI1U1 = (CMD_BITS << SPILMOSI) | (CMD_BITS << SPILMISO);
|
||||
// No need to send x if it has not changed (speeds things up)
|
||||
if (_x_address_set != x)
|
||||
{
|
||||
GPOC = _dc_pinmask;
|
||||
SPI1W0 = ILI9486_SPI_CASET << (CMD_BITS + 1 - 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _dc_pinmask;
|
||||
SPI1W0 = x >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = x << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = x >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = x << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
_x_address_set = x;
|
||||
}
|
||||
// No need to send y if it has not changed (speeds things up)
|
||||
if (_y_address_set != y)
|
||||
{
|
||||
GPOC = _dc_pinmask;
|
||||
SPI1W0 = ILI9486_SPI_PASET << (CMD_BITS + 1 - 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _dc_pinmask;
|
||||
SPI1W0 = y >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = y << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = y >> 0;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
SPI1W0 = y << 8;
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
_y_address_set = y;
|
||||
}
|
||||
GPOC = _dc_pinmask;
|
||||
SPI1W0 = ILI9486_SPI_RAMWR << (CMD_BITS + 1 - 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _dc_pinmask;
|
||||
SPI1W0 = (color >> 8) | (color << 8);
|
||||
SPI1CMD |= SPIBUSY;
|
||||
while (SPI1CMD & SPIBUSY) {}
|
||||
GPOS = _cs_pinmask;
|
||||
_spi->endTransaction();
|
||||
}
|
||||
else
|
||||
{
|
||||
_startTransaction();
|
||||
_setWindow(x, y, 1, 1);
|
||||
_writeColor16(color, 1);
|
||||
_endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void ILI9486_SPI::drawPixel(int16_t x, int16_t y, uint16_t color)
|
||||
{
|
||||
if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_startTransaction();
|
||||
_setWindow(x, y, 1, 1);
|
||||
_writeColor16(color, 1);
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ILI9486_SPI::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
|
||||
{
|
||||
// if ((x < 0) || (y < 0) || (w < 1) || (h < 1) || (x + w > _width) || (y + h > _height))
|
||||
// {
|
||||
// Serial.print("fillRect("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(") oops? "); delay(1);
|
||||
// }
|
||||
// a correct clipping is the goal. try to achieve this
|
||||
if (x < 0) w += x, x = 0;
|
||||
if (y < 0) h += y, y = 0;
|
||||
if (x + w > _width) w = _width - x;
|
||||
if (y + h > _height) h = _height - y;
|
||||
if ((w < 1) || (h < 1)) return;
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h);
|
||||
_writeColor16(color, uint32_t(w) * uint32_t(h));
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
|
||||
{
|
||||
fillRect(x, y, 1, h, color);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
|
||||
{
|
||||
fillRect(x, y, w, 1, color);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::fillScreen(uint16_t color)
|
||||
{
|
||||
fillRect(0, 0, _width, _height, color);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::setRotation(uint8_t r)
|
||||
{
|
||||
Adafruit_GFX::setRotation(r);
|
||||
_startTransaction();
|
||||
if (_spi16_mode)
|
||||
{
|
||||
_writeCommand16(ILI9486_SPI_MADCTL);
|
||||
switch (r & 3)
|
||||
{
|
||||
case 0:
|
||||
_writeData16(MADCTL_MX | _bgr);
|
||||
break;
|
||||
case 1:
|
||||
_writeData16(MADCTL_MV | _bgr);
|
||||
break;
|
||||
case 2:
|
||||
_writeData16(MADCTL_MY | _bgr);
|
||||
break;
|
||||
case 3:
|
||||
_writeData16(MADCTL_MX | MADCTL_MY | MADCTL_MV | _bgr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeCommand(ILI9486_SPI_MADCTL);
|
||||
switch (r & 3)
|
||||
{
|
||||
case 0:
|
||||
_writeData(MADCTL_MX | _bgr);
|
||||
break;
|
||||
case 1:
|
||||
_writeData(MADCTL_MV | _bgr);
|
||||
break;
|
||||
case 2:
|
||||
_writeData(MADCTL_MY | _bgr);
|
||||
break;
|
||||
case 3:
|
||||
_writeData(MADCTL_MX | MADCTL_MY | MADCTL_MV | _bgr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::invertDisplay(bool i)
|
||||
{
|
||||
/*_bgr = i ? MADCTL_BGR : 0x00;
|
||||
setRotation(rotation);*/
|
||||
sendCommand(i ? ILI9488_INVON : ILI9488_INVOFF);
|
||||
}
|
||||
|
||||
// *** other public methods ***
|
||||
|
||||
void ILI9486_SPI::setSpiKludge(bool rpi_spi16_mode)
|
||||
{
|
||||
_spi16_mode = rpi_spi16_mode;
|
||||
}
|
||||
|
||||
void ILI9486_SPI::init(void)
|
||||
{
|
||||
digitalWrite(_cs, HIGH);
|
||||
_spi->begin();
|
||||
_spi->beginTransaction( { SPI_SPEED, MSBFIRST, SPI_MODE0 } );
|
||||
_spi->endTransaction();
|
||||
if (_rst >= 0)
|
||||
{
|
||||
digitalWrite(_rst, LOW);
|
||||
delay(20);
|
||||
digitalWrite(_rst, HIGH);
|
||||
}
|
||||
delay(200);
|
||||
_startTransaction();
|
||||
if (_spi16_mode)
|
||||
{
|
||||
_writeCommand16(0x3A);
|
||||
_writeData16(0x55); // use 16 bits per pixel color
|
||||
_writeCommand16(0x36);
|
||||
_writeData16(0x48); // MX, BGR == rotation 0
|
||||
// PGAMCTRL(Positive Gamma Control)
|
||||
_writeCommand16(0xE0);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x1F);
|
||||
_writeData16(0x1C);
|
||||
_writeData16(0x0C);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x08);
|
||||
_writeData16(0x48);
|
||||
_writeData16(0x98);
|
||||
_writeData16(0x37);
|
||||
_writeData16(0x0A);
|
||||
_writeData16(0x13);
|
||||
_writeData16(0x04);
|
||||
_writeData16(0x11);
|
||||
_writeData16(0x0D);
|
||||
_writeData16(0x00);
|
||||
// NGAMCTRL(Negative Gamma Control)
|
||||
_writeCommand16(0xE1);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x32);
|
||||
_writeData16(0x2E);
|
||||
_writeData16(0x0B);
|
||||
_writeData16(0x0D);
|
||||
_writeData16(0x05);
|
||||
_writeData16(0x47);
|
||||
_writeData16(0x75);
|
||||
_writeData16(0x37);
|
||||
_writeData16(0x06);
|
||||
_writeData16(0x10);
|
||||
_writeData16(0x03);
|
||||
_writeData16(0x24);
|
||||
_writeData16(0x20);
|
||||
_writeData16(0x00);
|
||||
// Digital Gamma Control 1
|
||||
_writeCommand16(0xE2);
|
||||
_writeData16(0x0F);
|
||||
_writeData16(0x32);
|
||||
_writeData16(0x2E);
|
||||
_writeData16(0x0B);
|
||||
_writeData16(0x0D);
|
||||
_writeData16(0x05);
|
||||
_writeData16(0x47);
|
||||
_writeData16(0x75);
|
||||
_writeData16(0x37);
|
||||
_writeData16(0x06);
|
||||
_writeData16(0x10);
|
||||
_writeData16(0x03);
|
||||
_writeData16(0x24);
|
||||
_writeData16(0x20);
|
||||
_writeData16(0x00);
|
||||
_writeCommand16(0x11); // Sleep OUT
|
||||
delay(150); // wait some time
|
||||
_writeCommand16(0x29); // Display ON
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeCommand(0x3A);
|
||||
_writeData(0x66); // 18 bit colour for native SPI
|
||||
_writeCommand(0x36);
|
||||
_writeData(0x48); // MX, BGR == rotation 0
|
||||
// PGAMCTRL(Positive Gamma Control)
|
||||
#if DSP_MODEL==DSP_ILI9486
|
||||
_writeCommand(0xE0);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x1F);
|
||||
_writeData(0x1C);
|
||||
_writeData(0x0C);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x08);
|
||||
_writeData(0x48);
|
||||
_writeData(0x98);
|
||||
_writeData(0x37);
|
||||
_writeData(0x0A);
|
||||
_writeData(0x13);
|
||||
_writeData(0x04);
|
||||
_writeData(0x11);
|
||||
_writeData(0x0D);
|
||||
_writeData(0x00);
|
||||
// NGAMCTRL(Negative Gamma Control)
|
||||
_writeCommand(0xE1);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x32);
|
||||
_writeData(0x2E);
|
||||
_writeData(0x0B);
|
||||
_writeData(0x0D);
|
||||
_writeData(0x05);
|
||||
_writeData(0x47);
|
||||
_writeData(0x75);
|
||||
_writeData(0x37);
|
||||
_writeData(0x06);
|
||||
_writeData(0x10);
|
||||
_writeData(0x03);
|
||||
_writeData(0x24);
|
||||
_writeData(0x20);
|
||||
_writeData(0x00);
|
||||
// Digital Gamma Control 1
|
||||
_writeCommand(0xE2);
|
||||
_writeData(0x0F);
|
||||
_writeData(0x32);
|
||||
_writeData(0x2E);
|
||||
_writeData(0x0B);
|
||||
_writeData(0x0D);
|
||||
_writeData(0x05);
|
||||
_writeData(0x47);
|
||||
_writeData(0x75);
|
||||
_writeData(0x37);
|
||||
_writeData(0x06);
|
||||
_writeData(0x10);
|
||||
_writeData(0x03);
|
||||
_writeData(0x24);
|
||||
_writeData(0x20);
|
||||
_writeData(0x00);
|
||||
#endif
|
||||
_writeCommand(0x11); // Sleep OUT
|
||||
delay(150); // wait some time
|
||||
_writeCommand(0x29); // Display ON
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h);
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::pushColors(const uint16_t* data, uint16_t n)
|
||||
{
|
||||
_startTransaction();
|
||||
_writeColor16(data, n);
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::setBackLight(bool lit)
|
||||
{
|
||||
_startTransaction();
|
||||
if (_spi16_mode) _writeCommand16(lit ? 0x29 : 0x28); // Display ON / Display OFF
|
||||
else _writeCommand(lit ? 0x29 : 0x28); // Display ON / Display OFF
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
uint16_t ILI9486_SPI::color565(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
|
||||
}
|
||||
|
||||
// code extract taken from Adafruit_SPITFT::drawRGBBitmap https://github.com/adafruit/Adafruit-GFX-Library
|
||||
void ILI9486_SPI::drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, int16_t w, int16_t h)
|
||||
{
|
||||
if (!pcolors) return; // canvas might be empty
|
||||
int16_t x2, y2; // Lower-right coord
|
||||
if (( x >= _width ) || // Off-edge right
|
||||
( y >= _height) || // " top
|
||||
((x2 = (x + w - 1)) < 0 ) || // " left
|
||||
((y2 = (y + h - 1)) < 0) ) return; // " bottom
|
||||
|
||||
int16_t bx1 = 0, by1 = 0; // Clipped top-left within bitmap
|
||||
int16_t saveW = w; // Save original bitmap width value
|
||||
if (x < 0) // Clip left
|
||||
{
|
||||
w += x;
|
||||
bx1 = -x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) // Clip top
|
||||
{
|
||||
h += y;
|
||||
by1 = -y;
|
||||
y = 0;
|
||||
}
|
||||
if (x2 >= _width ) w = _width - x; // Clip right
|
||||
if (y2 >= _height) h = _height - y; // Clip bottom
|
||||
|
||||
pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h); // Clipped area
|
||||
while (h--) // For each (clipped) scanline...
|
||||
{
|
||||
_writeColor16(pcolors, w); // Push one (clipped) row
|
||||
pcolors += saveW; // Advance pointer by one full (unclipped) line
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
// code extract taken from Adafruit_SPITFT::drawRGBBitmap https://github.com/adafruit/Adafruit-GFX-Library
|
||||
void ILI9486_SPI::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h)
|
||||
{
|
||||
const uint16_t* pcolors = bitmap;
|
||||
int16_t x2, y2; // Lower-right coord
|
||||
if (( x >= _width ) || // Off-edge right
|
||||
( y >= _height) || // " top
|
||||
((x2 = (x + w - 1)) < 0 ) || // " left
|
||||
((y2 = (y + h - 1)) < 0) ) return; // " bottom
|
||||
|
||||
int16_t bx1 = 0, by1 = 0; // Clipped top-left within bitmap
|
||||
int16_t saveW = w; // Save original bitmap width value
|
||||
if (x < 0) // Clip left
|
||||
{
|
||||
w += x;
|
||||
bx1 = -x;
|
||||
x = 0;
|
||||
}
|
||||
if (y < 0) // Clip top
|
||||
{
|
||||
h += y;
|
||||
by1 = -y;
|
||||
y = 0;
|
||||
}
|
||||
if (x2 >= _width ) w = _width - x; // Clip right
|
||||
if (y2 >= _height) h = _height - y; // Clip bottom
|
||||
|
||||
pcolors += by1 * saveW + bx1; // Offset bitmap ptr to clipped top-left
|
||||
_startTransaction();
|
||||
_setWindow(x, y, w, h); // Clipped area
|
||||
while (h--) // For each (clipped) scanline...
|
||||
{
|
||||
for (int16_t i = 0; i < w; i++) // Push one (clipped) row
|
||||
{
|
||||
_writeColor16(pgm_read_word(pcolors + i), 1);
|
||||
}
|
||||
pcolors += saveW; // Advance pointer by one full (unclipped) line
|
||||
}
|
||||
_endTransaction();
|
||||
}
|
||||
|
||||
// *** private methods
|
||||
|
||||
void ILI9486_SPI::_setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
|
||||
{
|
||||
uint16_t xe = x + w - 1;
|
||||
uint16_t ye = y + h - 1;
|
||||
if (_spi16_mode)
|
||||
{
|
||||
_writeCommand16(ILI9486_SPI_CASET);
|
||||
uint16_t columns[] = {uint16_t(x >> 8), uint16_t(x & 0xFF), uint16_t(xe >> 8), uint16_t(xe & 0xFF)};
|
||||
_writeData16(columns, 4);
|
||||
_writeCommand16(ILI9486_SPI_PASET);
|
||||
uint16_t rows[] = {uint16_t(y >> 8), uint16_t(y & 0xFF), uint16_t(ye >> 8), uint16_t(ye & 0xFF)};
|
||||
_writeData16(rows, 4);
|
||||
_writeCommand16(ILI9486_SPI_RAMWR);
|
||||
}
|
||||
else
|
||||
{
|
||||
_writeCommand(ILI9486_SPI_CASET);
|
||||
_writeData16(x);
|
||||
_writeData16(xe);
|
||||
_writeCommand(ILI9486_SPI_PASET);
|
||||
_writeData16(y);
|
||||
_writeData16(ye);
|
||||
_writeCommand(ILI9486_SPI_RAMWR);
|
||||
}
|
||||
_x_address_set = -1;
|
||||
_x_address_set = -1;
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_startTransaction()
|
||||
{
|
||||
_spi->beginTransaction(_spi_settings);
|
||||
if (_cs >= 0) digitalWrite(_cs, LOW);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_endTransaction()
|
||||
{
|
||||
if (_cs >= 0) digitalWrite(_cs, HIGH);
|
||||
_spi->endTransaction();
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeCommand(uint8_t cmd)
|
||||
{
|
||||
digitalWrite(_dc, LOW);
|
||||
_spi->transfer(cmd);
|
||||
digitalWrite(_dc, HIGH);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::sendCommand(uint8_t cmd)
|
||||
{
|
||||
_startTransaction();
|
||||
if (_cs >= 0)
|
||||
digitalWrite(_cs, LOW);
|
||||
|
||||
digitalWrite(_dc, LOW); // Command mode
|
||||
_spi->transfer(cmd); // Send the command byte
|
||||
|
||||
digitalWrite(_dc, HIGH);
|
||||
|
||||
|
||||
if (_cs >= 0)
|
||||
digitalWrite(_cs, HIGH);
|
||||
_endTransaction();
|
||||
|
||||
|
||||
/* digitalWrite(_dc, LOW);
|
||||
_spi->transfer(cmd);
|
||||
digitalWrite(_dc, HIGH);*/
|
||||
}
|
||||
void ILI9486_SPI::_writeCommand16(uint16_t cmd)
|
||||
{
|
||||
digitalWrite(_dc, LOW);
|
||||
_writeData16(cmd);
|
||||
digitalWrite(_dc, HIGH);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData(uint8_t data)
|
||||
{
|
||||
digitalWrite(_dc, HIGH);
|
||||
_spi->transfer(data);
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData16(uint16_t data)
|
||||
{
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
_spi->write16(data);
|
||||
#else
|
||||
_spi->transfer(data >> 8);
|
||||
_spi->transfer(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData16(uint16_t data, uint32_t n)
|
||||
{
|
||||
#if (defined (ESP8266) || defined(ESP32)) && true // fastest
|
||||
uint16_t swapped = ((data << 8) | (data >> 8));
|
||||
_spi->writePattern((uint8_t*)&swapped, 2, n);
|
||||
#elif (defined (ESP8266) || defined(ESP32))
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->write16(data);
|
||||
}
|
||||
#else // wdt on ESP8266
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->transfer(data >> 8);
|
||||
_spi->transfer(data);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeData16(const uint16_t* data, uint32_t n)
|
||||
{
|
||||
#if (defined (ESP8266) || defined(ESP32) || (TEENSYDUINO == 147)) && true // fastest
|
||||
static const uint16_t swap_buffer_size = 64; // optimal for ESP8266 SPI
|
||||
static const uint32_t max_chunk = swap_buffer_size / 2; // uint16_t's
|
||||
uint8_t swap_buffer[swap_buffer_size];
|
||||
const uint8_t* p1 = reinterpret_cast<const uint8_t*> (data);
|
||||
const uint8_t* p2 = p1 + 1;
|
||||
while (n > 0)
|
||||
{
|
||||
uint32_t chunk = min(max_chunk, n);
|
||||
n -= chunk;
|
||||
uint8_t* p3 = swap_buffer;
|
||||
uint8_t* p4 = p3 + 1;
|
||||
uint16_t ncopy = chunk;
|
||||
while (ncopy-- > 0)
|
||||
{
|
||||
*p3 = *p2; p3 += 2; p2 += 2;
|
||||
*p4 = *p1; p4 += 2; p1 += 2;
|
||||
}
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
_spi->transferBytes(swap_buffer, 0, 2 * chunk);
|
||||
#elif defined(ARDUINO_ARCH_SAM) // same speed
|
||||
_spi->transfer(SS, swap_buffer, 2 * chunk);
|
||||
#else
|
||||
_spi->transfer(swap_buffer, 0, 2 * chunk);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
while (n-- > 0)
|
||||
{
|
||||
uint16_t color = (*data++);
|
||||
#if (defined (ESP8266) || defined(ESP32)) && false // faster
|
||||
_spi->write16(color);
|
||||
#else
|
||||
_spi->transfer(color >> 8);
|
||||
_spi->transfer(color);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ILI9486_SPI::_writeColor16(uint16_t data, uint32_t n)
|
||||
{
|
||||
if (_spi16_mode) return _writeData16(data, n);
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
uint8_t rgb888[] = {uint8_t((data & 0xF800) >> 8), uint8_t((data & 0x07E0) >> 3), uint8_t((data & 0x001F) << 3)};
|
||||
_spi->writePattern(rgb888, 3, n);
|
||||
#else // wdt on ESP8266
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->transfer(uint8_t((data & 0xF800) >> 8));
|
||||
_spi->transfer(uint8_t((data & 0x07E0) >> 3));
|
||||
_spi->transfer(uint8_t((data & 0x001F) << 3));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if (defined (ESP8266) || defined(ESP32))
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transferBytes(data, 0, n)
|
||||
#elif defined(ARDUINO_ARCH_SAM)
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transfer(SS, data, n)
|
||||
#elif (TEENSYDUINO == 147)
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transfer(data, 0, n)
|
||||
#elif defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32F4)
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->write(data, n)
|
||||
#else
|
||||
// valid for all other platforms? else comment out next line
|
||||
#define SPI_WRITE_BYTES(data, n) _spi->transfer(data, n)
|
||||
#endif
|
||||
|
||||
|
||||
void ILI9486_SPI::_writeColor16(const uint16_t* data, uint32_t n)
|
||||
{
|
||||
if (_spi16_mode) return _writeData16(data, n);
|
||||
#if defined(SPI_WRITE_BYTES)
|
||||
static const uint16_t rgb888_buffer_size = 60; // 64 optimal for ESP8266 SPI
|
||||
static const uint32_t max_chunk = rgb888_buffer_size / 3; // rgb888
|
||||
uint8_t rgb888_buffer[rgb888_buffer_size];
|
||||
while (n > 0)
|
||||
{
|
||||
uint32_t chunk = min(max_chunk, n);
|
||||
n -= chunk;
|
||||
uint8_t* p = rgb888_buffer;
|
||||
uint16_t ncopy = chunk;
|
||||
while (ncopy-- > 0)
|
||||
{
|
||||
*p++ = uint8_t((*data & 0xF800) >> 8);
|
||||
*p++ = uint8_t((*data & 0x07E0) >> 3);
|
||||
*p++ = uint8_t((*data & 0x001F) << 3);
|
||||
data++;
|
||||
}
|
||||
SPI_WRITE_BYTES(rgb888_buffer, 3 * chunk);
|
||||
}
|
||||
#else
|
||||
while (n-- > 0)
|
||||
{
|
||||
_spi->transfer(uint8_t((*data & 0xF800) >> 8));
|
||||
_spi->transfer(uint8_t((*data & 0x07E0) >> 3));
|
||||
_spi->transfer(uint8_t((*data & 0x001F) << 3));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
65
yoRadio/src/ILI9488/ILI9486_SPI.h
Normal file
65
yoRadio/src/ILI9488/ILI9486_SPI.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// created by Jean-Marc Zingg to be a standalone ILI9486_SPI library (instead of the GxCTRL_ILI9486_SPI class for the GxTFT library)
|
||||
// code extracts taken from https://github.com/Bodmer/TFT_HX8357
|
||||
// spi kludge handling solution found in https://github.com/Bodmer/TFT_eSPI
|
||||
// code extracts taken from https://github.com/adafruit/Adafruit-GFX-Library
|
||||
//
|
||||
// License: GNU GENERAL PUBLIC LICENSE V3, see LICENSE
|
||||
//
|
||||
|
||||
#ifndef _ILI9486_SPI_H_
|
||||
#define _ILI9486_SPI_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#include "GFXcanvas16T.h"
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
|
||||
class ILI9486_SPI : public Adafruit_GFX
|
||||
{
|
||||
public:
|
||||
ILI9486_SPI(int8_t cs, int8_t dc, int8_t rst);
|
||||
ILI9486_SPI(SPIClass *spiClass, int8_t cs, int8_t dc, int8_t rst);
|
||||
// (overridden) virtual methods
|
||||
virtual void drawPixel(int16_t x, int16_t y, uint16_t color);
|
||||
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
|
||||
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
|
||||
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
|
||||
virtual void fillScreen(uint16_t color);
|
||||
virtual void setRotation(uint8_t r);
|
||||
virtual void invertDisplay(bool i);
|
||||
// other public methods
|
||||
void setSpiKludge(bool rpi_spi16_mode = true); // call with false before init to disable
|
||||
void init(void);
|
||||
void setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void pushColors(const uint16_t* data, uint16_t n); // fast one
|
||||
void setBackLight(bool lit);
|
||||
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
|
||||
void drawRGBBitmap(int16_t x, int16_t y, uint16_t *pcolors, int16_t w, int16_t h);
|
||||
void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h);
|
||||
virtual void _startTransaction();
|
||||
virtual void _endTransaction();
|
||||
void _writeCommand(uint8_t cmd);
|
||||
void sendCommand(uint8_t cmd);
|
||||
private:
|
||||
void _setWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
|
||||
void _writeCommand16(uint16_t cmd);
|
||||
void _writeData(uint8_t data);
|
||||
void _writeData16(uint16_t data);
|
||||
void _writeData16(uint16_t data, uint32_t n);
|
||||
void _writeData16(const uint16_t* data, uint32_t n);
|
||||
// note: only use for pixel data, RGB888 on ILI9488, ILI9486 native SPI
|
||||
void _writeColor16(uint16_t data, uint32_t n);
|
||||
void _writeColor16(const uint16_t* data, uint32_t n);
|
||||
private:
|
||||
bool _spi16_mode;
|
||||
SPISettings _spi_settings;
|
||||
SPIClass *_spi;
|
||||
int8_t _cs, _dc, _rst;
|
||||
int8_t _bgr;
|
||||
int32_t _x_address_set, _y_address_set;
|
||||
uint32_t _cs_pinmask, _dc_pinmask;
|
||||
};
|
||||
|
||||
#endif
|
||||
1699
yoRadio/src/ILI9488/test_canvas.h
Normal file
1699
yoRadio/src/ILI9488/test_canvas.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
#ifndef options_h
|
||||
#define options_h
|
||||
|
||||
#define YOVERSION "0.8.920"
|
||||
#define YOVERSION "0.8.933"
|
||||
|
||||
/*******************************************************
|
||||
DO NOT EDIT THIS FILE.
|
||||
@@ -44,6 +44,8 @@ The connection tables are located here https://github.com/e2002/yoradio#connecti
|
||||
/* !!! DSP_ST7789_240 requires further development when used in conjunction with the VS1053 module !!! See the link https://www.instructables.com/Adding-CS-Pin-to-13-LCD/ */
|
||||
#define DSP_ST7796 19 // 480x320 3.5' https://aliexpress.com/item/1005004632953455.html?sku_id=12000029911293172
|
||||
#define DSP_GC9A01A 20 // 240x240 1.28' https://aliexpress.com/item/1005004069703494.html?sku_id=12000029869654615
|
||||
#define DSP_ILI9488 21 // 480x320 3.5' https://aliexpress.com/item/1005001999296476.html?sku_id=12000018365356570
|
||||
#define DSP_ILI9486 22 // (Testing mode) 480x320 3.5' https://aliexpress.com/item/1005001999296476.html?sku_id=12000018365356568
|
||||
#define DSP_CUSTOM 101 // your display
|
||||
|
||||
#ifndef DSP_MODEL
|
||||
|
||||
68
yoRadio/src/displays/conf/displayILI9488conf.h
Normal file
68
yoRadio/src/displays/conf/displayILI9488conf.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*************************************************************************************
|
||||
ST7796 480X320 displays configuration file.
|
||||
Copy this file to yoRadio/src/displays/conf/displayST7789conf_custom.h
|
||||
and modify it
|
||||
More info on https://github.com/e2002/yoradio/wiki/Widgets#widgets-description
|
||||
*************************************************************************************/
|
||||
|
||||
#ifndef displayILI9488conf_h
|
||||
#define displayILI9488conf_h
|
||||
|
||||
#define DSP_WIDTH 480
|
||||
#define DSP_HEIGHT 320
|
||||
#define TFT_FRAMEWDT 10
|
||||
#define MAX_WIDTH DSP_WIDTH-TFT_FRAMEWDT*2
|
||||
#define PLMITEMS 11
|
||||
#define PLMITEMLENGHT 40
|
||||
#define PLMITEMHEIGHT 32
|
||||
|
||||
#define bootLogoTop 110
|
||||
|
||||
/* SROLLS */ /* {{ left, top, fontsize, align }, buffsize, uppercase, width, scrolldelay, scrolldelta, scrolltime } */
|
||||
const ScrollConfig metaConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 4, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 7, 40 };
|
||||
const ScrollConfig title1Conf PROGMEM = {{ TFT_FRAMEWDT, 62, 2, WA_LEFT }, 140, true, MAX_WIDTH-6*2*7-6, 5000, 7, 40 };
|
||||
const ScrollConfig title2Conf PROGMEM = {{ TFT_FRAMEWDT, 86, 2, WA_LEFT }, 140, true, MAX_WIDTH, 5000, 7, 40 };
|
||||
const ScrollConfig playlistConf PROGMEM = {{ TFT_FRAMEWDT, 146, 3, WA_LEFT }, 140, true, MAX_WIDTH, 1000, 7, 40 };
|
||||
const ScrollConfig apTitleConf PROGMEM = {{ TFT_FRAMEWDT, TFT_FRAMEWDT, 4, WA_CENTER }, 140, false, MAX_WIDTH, 0, 7, 40 };
|
||||
const ScrollConfig apSettConf PROGMEM = {{ TFT_FRAMEWDT, 320-TFT_FRAMEWDT-16, 2, WA_LEFT }, 140, false, MAX_WIDTH, 0, 7, 40 };
|
||||
const ScrollConfig weatherConf PROGMEM = {{ TFT_FRAMEWDT, 116, 2, WA_LEFT }, 140, true, MAX_WIDTH, 0, 7, 40 };
|
||||
|
||||
/* BACKGROUNDS */ /* {{ left, top, fontsize, align }, width, height, outlined } */
|
||||
const FillConfig metaBGConf PROGMEM = {{ 0, 0, 0, WA_LEFT }, DSP_WIDTH, 50, false };
|
||||
const FillConfig volbarConf PROGMEM = {{ TFT_FRAMEWDT, DSP_HEIGHT-TFT_FRAMEWDT-8, 0, WA_LEFT }, MAX_WIDTH, 8, true };
|
||||
const FillConfig playlBGConf PROGMEM = {{ 0, 138, 0, WA_LEFT }, DSP_WIDTH, 36, false };
|
||||
const FillConfig heapbarConf PROGMEM = {{ 0, DSP_HEIGHT-2, 0, WA_LEFT }, DSP_WIDTH, 2, false };
|
||||
|
||||
/* WIDGETS */ /* { left, top, fontsize, align } */
|
||||
const WidgetConfig bootstrConf PROGMEM = { 0, 243, 1, WA_CENTER };
|
||||
const WidgetConfig bitrateConf PROGMEM = { 6, 62, 2, WA_RIGHT };
|
||||
const WidgetConfig voltxtConf PROGMEM = { 0, DSP_HEIGHT-38, 2, WA_CENTER };
|
||||
const WidgetConfig iptxtConf PROGMEM = { TFT_FRAMEWDT, DSP_HEIGHT-38, 2, WA_LEFT };
|
||||
const WidgetConfig rssiConf PROGMEM = { TFT_FRAMEWDT, DSP_HEIGHT-38, 2, WA_RIGHT };
|
||||
const WidgetConfig numConf PROGMEM = { 0, 200, 70, WA_CENTER };
|
||||
const WidgetConfig apNameConf PROGMEM = { TFT_FRAMEWDT, 88, 3, WA_CENTER };
|
||||
const WidgetConfig apName2Conf PROGMEM = { TFT_FRAMEWDT, 120, 3, WA_CENTER };
|
||||
const WidgetConfig apPassConf PROGMEM = { TFT_FRAMEWDT, 173, 3, WA_CENTER };
|
||||
const WidgetConfig apPass2Conf PROGMEM = { TFT_FRAMEWDT, 205, 3, WA_CENTER };
|
||||
const WidgetConfig clockConf PROGMEM = { 16, 224, 70, WA_RIGHT }; /* 52 is a fixed font size. do not change */
|
||||
const WidgetConfig vuConf PROGMEM = { TFT_FRAMEWDT, 136, 1, WA_LEFT };
|
||||
|
||||
const WidgetConfig bootWdtConf PROGMEM = { 0, 216, 1, WA_CENTER };
|
||||
const ProgressConfig bootPrgConf PROGMEM = { 90, 14, 4 };
|
||||
|
||||
/* BANDS */ /* { onebandwidth, onebandheight, bandsHspace, bandsVspace, numofbands, fadespeed } */
|
||||
const VUBandsConfig bandsConf PROGMEM = { 32, 130, 4, 2, 10, 10 };
|
||||
|
||||
/* STRINGS */
|
||||
const char numtxtFmt[] PROGMEM = "%d";
|
||||
const char rssiFmt[] PROGMEM = "WiFi %d";
|
||||
const char iptxtFmt[] PROGMEM = "%s";
|
||||
const char voltxtFmt[] PROGMEM = "%d";
|
||||
const char bitrateFmt[] PROGMEM = "%d kBs";
|
||||
|
||||
/* MOVES */ /* { left, top, width } */
|
||||
const MoveConfig clockMove PROGMEM = { 0, 176, -1 };
|
||||
const MoveConfig weatherMove PROGMEM = { 8, 120, MAX_WIDTH };
|
||||
const MoveConfig weatherMoveVU PROGMEM = { 89, 120, 381 };
|
||||
|
||||
#endif
|
||||
219
yoRadio/src/displays/displayILI9488.cpp
Normal file
219
yoRadio/src/displays/displayILI9488.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
#include "../core/options.h"
|
||||
#if DSP_MODEL==DSP_ILI9488 || DSP_MODEL==DSP_ILI9486
|
||||
|
||||
#include "displayILI9488.h"
|
||||
//#include <SPI.h>
|
||||
#include "fonts/bootlogo.h"
|
||||
#include "../core/player.h"
|
||||
#include "../core/config.h"
|
||||
#include "../core/network.h"
|
||||
|
||||
#ifndef DEF_SPI_FREQ
|
||||
#define DEF_SPI_FREQ 40000000UL /* set it to 0 for system default */
|
||||
#endif
|
||||
|
||||
#define TAKE_MUTEX() if(player.mutex_pl) xSemaphoreTake(player.mutex_pl, portMAX_DELAY)
|
||||
#define GIVE_MUTEX() if(player.mutex_pl) xSemaphoreGive(player.mutex_pl)
|
||||
|
||||
#if DSP_HSPI
|
||||
DspCore::DspCore(): ILI9486_SPI(&SPI2, TFT_CS, TFT_DC, TFT_RST) {}
|
||||
#else
|
||||
DspCore::DspCore(): ILI9486_SPI(TFT_CS, TFT_DC, TFT_RST) {}
|
||||
#endif
|
||||
|
||||
#include "tools/utf8RusGFX.h"
|
||||
|
||||
void DspCore::initDisplay() {
|
||||
setSpiKludge(false);
|
||||
init();
|
||||
//if(DEF_SPI_FREQ > 0) setSPISpeed(DEF_SPI_FREQ);
|
||||
cp437(true);
|
||||
setTextWrap(false);
|
||||
setTextSize(1);
|
||||
fillScreen(0x0000);
|
||||
invert();
|
||||
flip();
|
||||
}
|
||||
|
||||
void DspCore::drawLogo(uint16_t top) { drawRGBBitmap((width() - 99) / 2, top, bootlogo2, 99, 64); }
|
||||
|
||||
void DspCore::drawPlaylist(uint16_t currentItem, char* currentItemText) {
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
plMenu[i][0] = '\0';
|
||||
}
|
||||
config.fillPlMenu(plMenu, currentItem - 5, PLMITEMS);
|
||||
setTextSize(3);
|
||||
int yStart = (height() / 2 - PLMITEMHEIGHT / 2) - PLMITEMHEIGHT * (PLMITEMS - 1) / 2 + 3;
|
||||
|
||||
for (byte i = 0; i < PLMITEMS; i++) {
|
||||
if (i == 5) {
|
||||
strlcpy(currentItemText, plMenu[i], PLMITEMLENGHT - 1);
|
||||
} else {
|
||||
setTextColor(config.theme.playlist[abs(i - 5)-1], config.theme.background);
|
||||
setCursor(TFT_FRAMEWDT, yStart + i * PLMITEMHEIGHT);
|
||||
fillRect(0, yStart + i * PLMITEMHEIGHT - 1, width(), PLMITEMHEIGHT - 6, config.theme.background);
|
||||
print(utf8Rus(plMenu[i], true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DspCore::clearDsp(bool black) { fillScreen(black?0:config.theme.background); }
|
||||
|
||||
GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
|
||||
return gfxFont->glyph + c;
|
||||
}
|
||||
|
||||
uint8_t DspCore::_charWidth(unsigned char c){
|
||||
GFXglyph *glyph = pgm_read_glyph_ptr(&DS_DIGI56pt7b, c - 0x20);
|
||||
return pgm_read_byte(&glyph->xAdvance);
|
||||
}
|
||||
|
||||
uint16_t DspCore::textWidth(const char *txt){
|
||||
uint16_t w = 0, l=strlen(txt);
|
||||
for(uint16_t c=0;c<l;c++) w+=_charWidth(txt[c]);
|
||||
return w;
|
||||
}
|
||||
|
||||
void DspCore::_getTimeBounds() {
|
||||
_timewidth = textWidth(_timeBuf);
|
||||
char buf[4];
|
||||
strftime(buf, 4, "%H", &network.timeinfo);
|
||||
_dotsLeft=textWidth(buf);
|
||||
}
|
||||
|
||||
void DspCore::_clockSeconds(){
|
||||
setTextSize(4);
|
||||
setTextColor(config.theme.seconds, config.theme.background);
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*4*2, clockTop-clockTimeHeight+1);
|
||||
sprintf(_bufforseconds, "%02d", network.timeinfo.tm_sec);
|
||||
print(_bufforseconds); /* print seconds */
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI56pt7b);
|
||||
setTextColor((network.timeinfo.tm_sec % 2 == 0) ? config.theme.clock : config.theme.background, config.theme.background);
|
||||
setCursor(_timeleft+_dotsLeft, clockTop);
|
||||
print(":"); /* print dots */
|
||||
setFont();
|
||||
}
|
||||
|
||||
void DspCore::_clockDate(){
|
||||
if(_olddateleft>0)
|
||||
dsp.fillRect(_olddateleft, clockTop+10, _olddatewidth, CHARHEIGHT, config.theme.background);
|
||||
setTextColor(config.theme.date, config.theme.background);
|
||||
setCursor(_dateleft, clockTop+15);
|
||||
setTextSize(2);
|
||||
print(_dateBuf); /* print date */
|
||||
strlcpy(_oldDateBuf, _dateBuf, sizeof(_dateBuf));
|
||||
_olddatewidth = _datewidth;
|
||||
_olddateleft = _dateleft;
|
||||
setTextSize(4);
|
||||
setTextColor(config.theme.dow, config.theme.background);
|
||||
setCursor(width() - 8 - clockRightSpace - CHARWIDTH*4*2, clockTop-CHARHEIGHT*4+4);
|
||||
print(utf8Rus(dow[network.timeinfo.tm_wday], false)); /* print dow */
|
||||
}
|
||||
|
||||
void DspCore::_clockTime(){
|
||||
if(_oldtimeleft>0) dsp.fillRect(_oldtimeleft, clockTop-clockTimeHeight+1, _oldtimewidth, clockTimeHeight, config.theme.background);
|
||||
_timeleft = width()-clockRightSpace-CHARWIDTH*4*2-24-_timewidth;
|
||||
setTextSize(1);
|
||||
setFont(&DS_DIGI56pt7b);
|
||||
setTextColor(config.theme.clock, config.theme.background);
|
||||
setCursor(_timeleft, clockTop);
|
||||
print(_timeBuf);
|
||||
setFont();
|
||||
strlcpy(_oldTimeBuf, _timeBuf, sizeof(_timeBuf));
|
||||
_oldtimewidth = _timewidth;
|
||||
_oldtimeleft = _timeleft;
|
||||
drawFastVLine(width()-clockRightSpace-CHARWIDTH*4*2-18, clockTop-clockTimeHeight, clockTimeHeight+4, config.theme.div); /*divider vert*/
|
||||
drawFastHLine(width()-clockRightSpace-CHARWIDTH*4*2-18, clockTop-clockTimeHeight+37, 59, config.theme.div); /*divider hor*/
|
||||
sprintf(_buffordate, "%2d %s %d", network.timeinfo.tm_mday,mnths[network.timeinfo.tm_mon], network.timeinfo.tm_year+1900);
|
||||
strlcpy(_dateBuf, utf8Rus(_buffordate, true), sizeof(_dateBuf));
|
||||
_datewidth = strlen(_dateBuf) * CHARWIDTH*2;
|
||||
_dateleft = width() - 10 - clockRightSpace - _datewidth;
|
||||
}
|
||||
|
||||
void DspCore::printClock(uint16_t top, uint16_t rightspace, uint16_t timeheight, bool redraw){
|
||||
clockTop = top;
|
||||
clockRightSpace = rightspace;
|
||||
clockTimeHeight = timeheight;
|
||||
strftime(_timeBuf, sizeof(_timeBuf), "%H:%M", &network.timeinfo);
|
||||
if(strcmp(_oldTimeBuf, _timeBuf)!=0 || redraw){
|
||||
_getTimeBounds();
|
||||
_clockTime();
|
||||
if(strcmp(_oldDateBuf, _dateBuf)!=0 || redraw) _clockDate();
|
||||
}
|
||||
_clockSeconds();
|
||||
}
|
||||
|
||||
void DspCore::clearClock(){
|
||||
dsp.fillRect(_timeleft, clockTop-clockTimeHeight, _timewidth+CHARWIDTH*3*2+24, clockTimeHeight+12+CHARHEIGHT, config.theme.background);
|
||||
}
|
||||
|
||||
void DspCore::startWrite(void) {
|
||||
TAKE_MUTEX();
|
||||
ILI9486_SPI::startWrite();
|
||||
}
|
||||
|
||||
void DspCore::endWrite(void) {
|
||||
ILI9486_SPI::endWrite();
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::loop(bool force) {
|
||||
|
||||
}
|
||||
|
||||
void DspCore::charSize(uint8_t textsize, uint8_t& width, uint16_t& height){
|
||||
width = textsize * CHARWIDTH;
|
||||
height = textsize * CHARHEIGHT;
|
||||
}
|
||||
|
||||
void DspCore::setTextSize(uint8_t s){
|
||||
Adafruit_GFX::setTextSize(s);
|
||||
}
|
||||
|
||||
void DspCore::flip(){
|
||||
setRotation(config.store.flipscreen?3:1);
|
||||
}
|
||||
|
||||
void DspCore::invert(){
|
||||
TAKE_MUTEX();
|
||||
invertDisplay(config.store.invertdisplay);
|
||||
GIVE_MUTEX();
|
||||
}
|
||||
|
||||
void DspCore::sleep(void) {
|
||||
sendCommand(ILI9488_SLPIN); delay(150); sendCommand(ILI9488_DISPOFF); delay(150);
|
||||
}
|
||||
|
||||
void DspCore::wake(void) {
|
||||
sendCommand(ILI9488_DISPON); delay(150); sendCommand(ILI9488_SLPOUT); delay(150);
|
||||
}
|
||||
|
||||
void DspCore::writePixel(int16_t x, int16_t y, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x > _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
ILI9486_SPI::drawPixel(x, y, color);
|
||||
}
|
||||
|
||||
void DspCore::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
|
||||
if(_clipping){
|
||||
if ((x < _cliparea.left) || (x >= _cliparea.left+_cliparea.width) || (y < _cliparea.top) || (y > _cliparea.top + _cliparea.height)) return;
|
||||
}
|
||||
ILI9486_SPI::writeFillRect(x, y, w, h, color);
|
||||
}
|
||||
|
||||
void DspCore::setClipping(clipArea ca){
|
||||
_cliparea = ca;
|
||||
_clipping = true;
|
||||
}
|
||||
|
||||
void DspCore::clearClipping(){
|
||||
_clipping = false;
|
||||
}
|
||||
|
||||
void DspCore::setNumFont(){
|
||||
setFont(&DS_DIGI56pt7b);
|
||||
setTextSize(1);
|
||||
}
|
||||
#endif
|
||||
39
yoRadio/src/displays/displayILI9488.h
Normal file
39
yoRadio/src/displays/displayILI9488.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef displayILI9488_h
|
||||
#define displayILI9488_h
|
||||
#include "../core/options.h"
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Adafruit_GFX.h>
|
||||
#include "../ILI9488/ILI9486_SPI.h"
|
||||
#include "fonts/DS_DIGI56pt7b.h" // https://tchapi.github.io/Adafruit-GFX-Font-Customiser/
|
||||
#include "tools/l10n.h"
|
||||
|
||||
#define CHARWIDTH 6
|
||||
#define CHARHEIGHT 8
|
||||
|
||||
typedef GFXcanvas16 Canvas;
|
||||
#include "widgets/widgets.h"
|
||||
#include "widgets/pages.h"
|
||||
|
||||
#if __has_include("conf/displayST7796conf_custom.h")
|
||||
#include "conf/displayILI9488conf_custom.h"
|
||||
#else
|
||||
#include "conf/displayILI9488conf.h"
|
||||
#endif
|
||||
|
||||
#define BOOT_PRG_COLOR 0xE68B
|
||||
#define BOOT_TXT_COLOR 0xFFFF
|
||||
#define PINK 0xF97F
|
||||
|
||||
#define ILI9488_SLPIN 0x10
|
||||
#define ILI9488_SLPOUT 0x11
|
||||
#define ILI9488_DISPOFF 0x28
|
||||
#define ILI9488_DISPON 0x29
|
||||
|
||||
class DspCore: public ILI9486_SPI {
|
||||
#include "tools/commongfx.h"
|
||||
};
|
||||
|
||||
extern DspCore dsp;
|
||||
|
||||
#endif
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "displayST7796.h"
|
||||
#elif DSP_MODEL==DSP_GC9A01A
|
||||
#include "displayGC9A01A.h"
|
||||
#elif DSP_MODEL==DSP_ILI9488 || DSP_MODEL==DSP_ILI9486
|
||||
#include "displayILI9488.h"
|
||||
#endif
|
||||
|
||||
//extern DspCore dsp;
|
||||
|
||||
Reference in New Issue
Block a user