Add initial display support

Add initial display support for Lcd, Oled, Matrix, Tft and e-paper - Need more docs
This commit is contained in:
Theo Arends 2018-08-18 18:11:22 +02:00
parent 4cde6bb463
commit b12c8d39d5
34 changed files with 6007 additions and 877 deletions

View File

@ -0,0 +1,46 @@
Thank you for opening an issue on an Adafruit Arduino library repository. To
improve the speed of resolution please review the following guidelines and
common troubleshooting steps below before creating the issue:
- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use
the forums at http://forums.adafruit.com to ask questions and troubleshoot why
something isn't working as expected. In many cases the problem is a common issue
that you will more quickly receive help from the forum community. GitHub issues
are meant for known defects in the code. If you don't know if there is a defect
in the code then start with troubleshooting on the forum first.
- **If following a tutorial or guide be sure you didn't miss a step.** Carefully
check all of the steps and commands to run have been followed. Consult the
forum if you're unsure or have questions about steps in a guide/tutorial.
- **For Arduino projects check these very common issues to ensure they don't apply**:
- For uploading sketches or communicating with the board make sure you're using
a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes
very hard to tell the difference between a data and charge cable! Try using the
cable with other devices or swapping to another cable to confirm it is not
the problem.
- **Be sure you are supplying adequate power to the board.** Check the specs of
your board and plug in an external power supply. In many cases just
plugging a board into your computer is not enough to power it and other
peripherals.
- **Double check all soldering joints and connections.** Flakey connections
cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints.
- **Ensure you are using an official Arduino or Adafruit board.** We can't
guarantee a clone board will have the same functionality and work as expected
with this code and don't support them.
If you're sure this issue is a defect in the code and checked the steps above
please fill in the following fields to provide enough troubleshooting information.
You may delete the guideline and text above to just leave the following details:
- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE**
- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO
VERSION HERE**
- List the steps to reproduce the problem below (if possible attach a sketch or
copy the sketch code in too): **LIST REPRO STEPS BELOW**

View File

@ -0,0 +1,26 @@
Thank you for creating a pull request to contribute to Adafruit's GitHub code!
Before you open the request please review the following guidelines and tips to
help it be more easily integrated:
- **Describe the scope of your change--i.e. what the change does and what parts
of the code were modified.** This will help us understand any risks of integrating
the code.
- **Describe any known limitations with your change.** For example if the change
doesn't apply to a supported platform of the library please mention it.
- **Please run any tests or examples that can exercise your modified code.** We
strive to not break users of the code and running tests/examples helps with this
process.
Thank you again for contributing! We will try to test and integrate the change
as soon as we can, but be aware we have many GitHub repositories to manage and
can't immediately respond to every request. There is no need to bump or check in
on a pull request (it will clutter the discussion of the request).
Also don't be worried if the request is closed or not integrated--sometimes the
priorities of Adafruit's GitHub code (education, ease of use) might not match the
priorities of the pull request. Don't fret, the open source community thrives on
forks and GitHub makes it easy to keep your changes in a forked repo.
After reviewing the guidelines above you can delete this text from the pull request.

View File

@ -0,0 +1,695 @@
/***************************************************
This is our library for the Adafruit ILI9341 Breakout and Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include "Adafruit_ILI9341.h"
#ifndef ARDUINO_STM32_FEATHER
#include "pins_arduino.h"
#ifndef RASPI
#include "wiring_private.h"
#endif
#endif
#include <limits.h>
#define MADCTL_MY 0x80
#define MADCTL_MX 0x40
#define MADCTL_MV 0x20
#define MADCTL_ML 0x10
#define MADCTL_RGB 0x00
#define MADCTL_BGR 0x08
#define MADCTL_MH 0x04
/*
* Control Pins
* */
#ifdef USE_FAST_PINIO
#define SPI_DC_HIGH() *dcport |= dcpinmask
#define SPI_DC_LOW() *dcport &= ~dcpinmask
#define SPI_CS_HIGH() *csport |= cspinmask
#define SPI_CS_LOW() *csport &= ~cspinmask
#else
#define SPI_DC_HIGH() digitalWrite(_dc, HIGH)
#define SPI_DC_LOW() digitalWrite(_dc, LOW)
#define SPI_CS_HIGH() digitalWrite(_cs, HIGH)
#define SPI_CS_LOW() digitalWrite(_cs, LOW)
#endif
/*
* Software SPI Macros
* */
#ifdef USE_FAST_PINIO
#define SSPI_MOSI_HIGH() *mosiport |= mosipinmask
#define SSPI_MOSI_LOW() *mosiport &= ~mosipinmask
#define SSPI_SCK_HIGH() *clkport |= clkpinmask
#define SSPI_SCK_LOW() *clkport &= ~clkpinmask
#define SSPI_MISO_READ() ((*misoport & misopinmask) != 0)
#else
#define SSPI_MOSI_HIGH() digitalWrite(_mosi, HIGH)
#define SSPI_MOSI_LOW() digitalWrite(_mosi, LOW)
#define SSPI_SCK_HIGH() digitalWrite(_sclk, HIGH)
#define SSPI_SCK_LOW() digitalWrite(_sclk, LOW)
#define SSPI_MISO_READ() digitalRead(_miso)
#endif
#define SSPI_BEGIN_TRANSACTION()
#define SSPI_END_TRANSACTION()
#define SSPI_WRITE(v) spiWrite(v)
#define SSPI_WRITE16(s) SSPI_WRITE((s) >> 8); SSPI_WRITE(s)
#define SSPI_WRITE32(l) SSPI_WRITE((l) >> 24); SSPI_WRITE((l) >> 16); SSPI_WRITE((l) >> 8); SSPI_WRITE(l)
#define SSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ SSPI_WRITE(((uint8_t*)(c))[i+1]); SSPI_WRITE(((uint8_t*)(c))[i]); }
/*
* Hardware SPI Macros
* */
#ifndef ESP32
#define SPI_OBJECT SPI
#else
#define SPI_OBJECT _spi
#endif
#if defined (__AVR__) || defined(TEENSYDUINO) || defined(ARDUINO_ARCH_STM32F1)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClockDivider(SPI_CLOCK_DIV2);
#elif defined (__arm__)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClockDivider(11);
#elif defined(ESP8266) || defined(ESP32)
#define HSPI_SET_CLOCK() SPI_OBJECT.setFrequency(_freq);
#elif defined(RASPI)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClock(_freq);
#elif defined(ARDUINO_ARCH_STM32F1)
#define HSPI_SET_CLOCK() SPI_OBJECT.setClock(_freq);
#else
#define HSPI_SET_CLOCK()
#endif
#ifdef SPI_HAS_TRANSACTION
#define HSPI_BEGIN_TRANSACTION() SPI_OBJECT.beginTransaction(SPISettings(_freq, MSBFIRST, SPI_MODE0))
#define HSPI_END_TRANSACTION() SPI_OBJECT.endTransaction()
#else
#define HSPI_BEGIN_TRANSACTION() HSPI_SET_CLOCK(); SPI_OBJECT.setBitOrder(MSBFIRST); SPI_OBJECT.setDataMode(SPI_MODE0)
#define HSPI_END_TRANSACTION()
#endif
#ifdef ESP32
#define SPI_HAS_WRITE_PIXELS
#endif
#if defined(ESP8266) || defined(ESP32)
// Optimized SPI (ESP8266 and ESP32)
#define HSPI_READ() SPI_OBJECT.transfer(0)
#define HSPI_WRITE(b) SPI_OBJECT.write(b)
#define HSPI_WRITE16(s) SPI_OBJECT.write16(s)
#define HSPI_WRITE32(l) SPI_OBJECT.write32(l)
#ifdef SPI_HAS_WRITE_PIXELS
#define SPI_MAX_PIXELS_AT_ONCE 32
#define HSPI_WRITE_PIXELS(c,l) SPI_OBJECT.writePixels(c,l)
#else
#define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<((l)/2); i++){ SPI_WRITE16(((uint16_t*)(c))[i]); }
#endif
#else
// Standard Byte-by-Byte SPI
#if defined (__AVR__) || defined(TEENSYDUINO)
static inline uint8_t _avr_spi_read(void) __attribute__((always_inline));
static inline uint8_t _avr_spi_read(void) {
uint8_t r = 0;
SPDR = r;
while(!(SPSR & _BV(SPIF)));
r = SPDR;
return r;
}
#define HSPI_WRITE(b) {SPDR = (b); while(!(SPSR & _BV(SPIF)));}
#define HSPI_READ() _avr_spi_read()
#else
#define HSPI_WRITE(b) SPI_OBJECT.transfer((uint8_t)(b))
#define HSPI_READ() HSPI_WRITE(0)
#endif
#define HSPI_WRITE16(s) HSPI_WRITE((s) >> 8); HSPI_WRITE(s)
#define HSPI_WRITE32(l) HSPI_WRITE((l) >> 24); HSPI_WRITE((l) >> 16); HSPI_WRITE((l) >> 8); HSPI_WRITE(l)
#define HSPI_WRITE_PIXELS(c,l) for(uint32_t i=0; i<(l); i+=2){ HSPI_WRITE(((uint8_t*)(c))[i+1]); HSPI_WRITE(((uint8_t*)(c))[i]); }
#endif
/*
* Final SPI Macros
* */
#if defined (ARDUINO_ARCH_ARC32)
#define SPI_DEFAULT_FREQ 16000000
#elif defined (__AVR__) || defined(TEENSYDUINO)
#define SPI_DEFAULT_FREQ 8000000
#elif defined(ESP8266) || defined(ESP32)
#define SPI_DEFAULT_FREQ 40000000
#elif defined(RASPI)
#define SPI_DEFAULT_FREQ 80000000
#elif defined(ARDUINO_ARCH_STM32F1)
#define SPI_DEFAULT_FREQ 36000000
#else
#define SPI_DEFAULT_FREQ 24000000
#endif
#define SPI_BEGIN() if(_sclk < 0){SPI_OBJECT.begin();}
#define SPI_BEGIN_TRANSACTION() if(_sclk < 0){HSPI_BEGIN_TRANSACTION();}
#define SPI_END_TRANSACTION() if(_sclk < 0){HSPI_END_TRANSACTION();}
#define SPI_WRITE16(s) if(_sclk < 0){HSPI_WRITE16(s);}else{SSPI_WRITE16(s);}
#define SPI_WRITE32(l) if(_sclk < 0){HSPI_WRITE32(l);}else{SSPI_WRITE32(l);}
#define SPI_WRITE_PIXELS(c,l) if(_sclk < 0){HSPI_WRITE_PIXELS(c,l);}else{SSPI_WRITE_PIXELS(c,l);}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t Adafruit_ILI9341::color565(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}
Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t mosi,
int8_t sclk, int8_t rst, int8_t miso) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) {
_cs = cs;
_dc = dc;
_rst = rst;
_sclk = sclk;
_mosi = mosi;
_miso = miso;
_freq = 0;
#ifdef USE_FAST_PINIO
csport = portOutputRegister(digitalPinToPort(_cs));
cspinmask = digitalPinToBitMask(_cs);
dcport = portOutputRegister(digitalPinToPort(_dc));
dcpinmask = digitalPinToBitMask(_dc);
clkport = portOutputRegister(digitalPinToPort(_sclk));
clkpinmask = digitalPinToBitMask(_sclk);
mosiport = portOutputRegister(digitalPinToPort(_mosi));
mosipinmask = digitalPinToBitMask(_mosi);
if(miso >= 0){
misoport = portInputRegister(digitalPinToPort(_miso));
misopinmask = digitalPinToBitMask(_miso);
} else {
misoport = 0;
misopinmask = 0;
}
#endif
}
Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) {
_cs = cs;
_dc = dc;
_rst = rst;
_sclk = -1;
_mosi = -1;
_miso = -1;
_freq = 0;
#ifdef USE_FAST_PINIO
csport = portOutputRegister(digitalPinToPort(_cs));
cspinmask = digitalPinToBitMask(_cs);
dcport = portOutputRegister(digitalPinToPort(_dc));
dcpinmask = digitalPinToBitMask(_dc);
clkport = 0;
clkpinmask = 0;
mosiport = 0;
mosipinmask = 0;
misoport = 0;
misopinmask = 0;
#endif
}
#ifdef ESP32
void Adafruit_ILI9341::begin(uint32_t freq, SPIClass &spi)
#else
void Adafruit_ILI9341::begin(uint32_t freq)
#endif
{
#ifdef ESP32
_spi = spi;
#endif
if(!freq){
freq = SPI_DEFAULT_FREQ;
}
_freq = freq;
// Control Pins
pinMode(_dc, OUTPUT);
digitalWrite(_dc, LOW);
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
// Software SPI
if(_sclk >= 0){
pinMode(_mosi, OUTPUT);
digitalWrite(_mosi, LOW);
pinMode(_sclk, OUTPUT);
digitalWrite(_sclk, HIGH);
if(_miso >= 0){
pinMode(_miso, INPUT);
}
}
// Hardware SPI
SPI_BEGIN();
// toggle RST low to reset
if (_rst >= 0) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(100);
digitalWrite(_rst, LOW);
delay(100);
digitalWrite(_rst, HIGH);
delay(200);
}
startWrite();
writeCommand(0xEF);
spiWrite(0x03);
spiWrite(0x80);
spiWrite(0x02);
writeCommand(0xCF);
spiWrite(0x00);
spiWrite(0XC1);
spiWrite(0X30);
writeCommand(0xED);
spiWrite(0x64);
spiWrite(0x03);
spiWrite(0X12);
spiWrite(0X81);
writeCommand(0xE8);
spiWrite(0x85);
spiWrite(0x00);
spiWrite(0x78);
writeCommand(0xCB);
spiWrite(0x39);
spiWrite(0x2C);
spiWrite(0x00);
spiWrite(0x34);
spiWrite(0x02);
writeCommand(0xF7);
spiWrite(0x20);
writeCommand(0xEA);
spiWrite(0x00);
spiWrite(0x00);
writeCommand(ILI9341_PWCTR1); //Power control
spiWrite(0x23); //VRH[5:0]
writeCommand(ILI9341_PWCTR2); //Power control
spiWrite(0x10); //SAP[2:0];BT[3:0]
writeCommand(ILI9341_VMCTR1); //VCM control
spiWrite(0x3e);
spiWrite(0x28);
writeCommand(ILI9341_VMCTR2); //VCM control2
spiWrite(0x86); //--
writeCommand(ILI9341_MADCTL); // Memory Access Control
spiWrite(0x48);
writeCommand(ILI9341_VSCRSADD); // Vertical scroll
SPI_WRITE16(0); // Zero
writeCommand(ILI9341_PIXFMT);
spiWrite(0x55);
writeCommand(ILI9341_FRMCTR1);
spiWrite(0x00);
spiWrite(0x18);
writeCommand(ILI9341_DFUNCTR); // Display Function Control
spiWrite(0x08);
spiWrite(0x82);
spiWrite(0x27);
writeCommand(0xF2); // 3Gamma Function Disable
spiWrite(0x00);
writeCommand(ILI9341_GAMMASET); //Gamma curve selected
spiWrite(0x01);
writeCommand(ILI9341_GMCTRP1); //Set Gamma
spiWrite(0x0F);
spiWrite(0x31);
spiWrite(0x2B);
spiWrite(0x0C);
spiWrite(0x0E);
spiWrite(0x08);
spiWrite(0x4E);
spiWrite(0xF1);
spiWrite(0x37);
spiWrite(0x07);
spiWrite(0x10);
spiWrite(0x03);
spiWrite(0x0E);
spiWrite(0x09);
spiWrite(0x00);
writeCommand(ILI9341_GMCTRN1); //Set Gamma
spiWrite(0x00);
spiWrite(0x0E);
spiWrite(0x14);
spiWrite(0x03);
spiWrite(0x11);
spiWrite(0x07);
spiWrite(0x31);
spiWrite(0xC1);
spiWrite(0x48);
spiWrite(0x08);
spiWrite(0x0F);
spiWrite(0x0C);
spiWrite(0x31);
spiWrite(0x36);
spiWrite(0x0F);
writeCommand(ILI9341_SLPOUT); //Exit Sleep
delay(120);
writeCommand(ILI9341_DISPON); //Display on
delay(120);
endWrite();
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
}
/*********************************************************************************************/
void Adafruit_ILI9341::setScrollStart(uint16_t start)
{
startWrite();
writeCommand(0x37);
spiWrite(start>>8);
spiWrite(start);
endWrite();
}
void Adafruit_ILI9341::setScrollMargins(uint16_t top, uint16_t bottom)
{
uint16_t height = _height - (top + bottom);
startWrite();
writeCommand(0x33);
spiWrite(top>>8);
spiWrite(top);
spiWrite(height>>8);
spiWrite(height);
spiWrite(bottom>>8);
spiWrite(bottom);
endWrite();
}
/*********************************************************************************************/
void Adafruit_ILI9341::setRotation(uint8_t m) {
rotation = m % 4; // can't be higher than 3
switch (rotation) {
case 0:
m = (MADCTL_MX | MADCTL_BGR);
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
break;
case 1:
m = (MADCTL_MV | MADCTL_BGR);
_width = ILI9341_TFTHEIGHT;
_height = ILI9341_TFTWIDTH;
break;
case 2:
m = (MADCTL_MY | MADCTL_BGR);
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
break;
case 3:
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
_width = ILI9341_TFTHEIGHT;
_height = ILI9341_TFTWIDTH;
break;
}
startWrite();
writeCommand(ILI9341_MADCTL);
spiWrite(m);
endWrite();
}
void Adafruit_ILI9341::invertDisplay(boolean i) {
startWrite();
writeCommand(i ? ILI9341_INVON : ILI9341_INVOFF);
endWrite();
}
void Adafruit_ILI9341::scrollTo(uint16_t y) {
startWrite();
writeCommand(ILI9341_VSCRSADD);
SPI_WRITE16(y);
endWrite();
}
uint8_t Adafruit_ILI9341::spiRead() {
if(_sclk < 0){
return HSPI_READ();
}
if(_miso < 0){
return 0;
}
uint8_t r = 0;
for (uint8_t i=0; i<8; i++) {
SSPI_SCK_LOW();
SSPI_SCK_HIGH();
r <<= 1;
if (SSPI_MISO_READ()){
r |= 0x1;
}
}
return r;
}
void Adafruit_ILI9341::spiWrite(uint8_t b) {
if(_sclk < 0){
HSPI_WRITE(b);
return;
}
for(uint8_t bit = 0x80; bit; bit >>= 1){
if((b) & bit){
SSPI_MOSI_HIGH();
} else {
SSPI_MOSI_LOW();
}
SSPI_SCK_LOW();
SSPI_SCK_HIGH();
}
}
/*
* Transaction API
* */
void Adafruit_ILI9341::startWrite(void){
SPI_BEGIN_TRANSACTION();
SPI_CS_LOW();
}
void Adafruit_ILI9341::endWrite(void){
SPI_CS_HIGH();
SPI_END_TRANSACTION();
}
void Adafruit_ILI9341::writeCommand(uint8_t cmd){
SPI_DC_LOW();
spiWrite(cmd);
SPI_DC_HIGH();
}
void Adafruit_ILI9341::setAddrWindow(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);
writeCommand(ILI9341_CASET); // Column addr set
SPI_WRITE32(xa);
writeCommand(ILI9341_PASET); // Row addr set
SPI_WRITE32(ya);
writeCommand(ILI9341_RAMWR); // write to RAM
}
void Adafruit_ILI9341::pushColor(uint16_t color) {
startWrite();
SPI_WRITE16(color);
endWrite();
}
void Adafruit_ILI9341::writePixel(uint16_t color){
SPI_WRITE16(color);
}
void Adafruit_ILI9341::writePixels(uint16_t * colors, uint32_t len){
SPI_WRITE_PIXELS((uint8_t*)colors , len * 2);
}
void Adafruit_ILI9341::writeColor(uint16_t color, uint32_t len){
#ifdef SPI_HAS_WRITE_PIXELS
if(_sclk >= 0){
for (uint32_t t=0; t<len; t++){
writePixel(color);
}
return;
}
static uint16_t temp[SPI_MAX_PIXELS_AT_ONCE];
size_t blen = (len > SPI_MAX_PIXELS_AT_ONCE)?SPI_MAX_PIXELS_AT_ONCE:len;
uint16_t tlen = 0;
for (uint32_t t=0; t<blen; t++){
temp[t] = color;
}
while(len){
tlen = (len>blen)?blen:len;
writePixels(temp, tlen);
len -= tlen;
}
#else
uint8_t hi = color >> 8, lo = color;
if(_sclk < 0){ //AVR Optimization
for (uint32_t t=len; t; t--){
HSPI_WRITE(hi);
HSPI_WRITE(lo);
}
return;
}
for (uint32_t t=len; t; t--){
spiWrite(hi);
spiWrite(lo);
}
#endif
}
void Adafruit_ILI9341::writePixel(int16_t x, int16_t y, uint16_t color) {
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
setAddrWindow(x,y,1,1);
writePixel(color);
}
void Adafruit_ILI9341::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color){
if((x >= _width) || (y >= _height)) return;
int16_t x2 = x + w - 1, y2 = y + h - 1;
if((x2 < 0) || (y2 < 0)) return;
// Clip left/top
if(x < 0) {
x = 0;
w = x2 + 1;
}
if(y < 0) {
y = 0;
h = y2 + 1;
}
// Clip right/bottom
if(x2 >= _width) w = _width - x;
if(y2 >= _height) h = _height - y;
int32_t len = (int32_t)w * h;
setAddrWindow(x, y, w, h);
writeColor(color, len);
}
void Adafruit_ILI9341::writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color){
writeFillRect(x, y, 1, h, color);
}
void Adafruit_ILI9341::writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color){
writeFillRect(x, y, w, 1, color);
}
uint8_t Adafruit_ILI9341::readcommand8(uint8_t c, uint8_t index) {
uint32_t freq = _freq;
if(_freq > 24000000){
_freq = 24000000;
}
startWrite();
writeCommand(0xD9); // woo sekret command?
spiWrite(0x10 + index);
writeCommand(c);
uint8_t r = spiRead();
endWrite();
_freq = freq;
return r;
}
void Adafruit_ILI9341::drawPixel(int16_t x, int16_t y, uint16_t color){
startWrite();
writePixel(x, y, color);
endWrite();
}
void Adafruit_ILI9341::drawFastVLine(int16_t x, int16_t y,
int16_t h, uint16_t color) {
startWrite();
writeFastVLine(x, y, h, color);
endWrite();
}
void Adafruit_ILI9341::drawFastHLine(int16_t x, int16_t y,
int16_t w, uint16_t color) {
startWrite();
writeFastHLine(x, y, w, color);
endWrite();
}
void Adafruit_ILI9341::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color) {
startWrite();
writeFillRect(x,y,w,h,color);
endWrite();
}
// Adapted from https://github.com/PaulStoffregen/ILI9341_t3
// by Marc MERLIN. See examples/pictureEmbed to use this.
// 5/6/2017: function name and arguments have changed for compatibility
// with current GFX library and to avoid naming problems in prior
// implementation. Formerly drawBitmap() with arguments in different order.
void Adafruit_ILI9341::drawRGBBitmap(int16_t x, int16_t y,
uint16_t *pcolors, int16_t w, int16_t h) {
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
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
startWrite();
setAddrWindow(x, y, w, h); // Clipped area
while(h--) { // For each (clipped) scanline...
writePixels(pcolors, w); // Push one (clipped) row
pcolors += saveW; // Advance pointer by one full (unclipped) line
}
endWrite();
}

View File

@ -0,0 +1,206 @@
/******************************************************************
This is our library for the Adafruit ILI9341 Breakout and Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required
to interface (RST is optional)
Adafruit invests time and resources providing this open source
code, please support Adafruit and open-source hardware by
purchasing products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
*******************************************************************/
#ifndef _ADAFRUIT_ILI9341H_
#define _ADAFRUIT_ILI9341H_
#if ARDUINO >= 100
#include "Arduino.h"
#include "Print.h"
#else
#include "WProgram.h"
#endif
#include <SPI.h>
#include "Adafruit_GFX.h"
#if defined(ARDUINO_STM32_FEATHER)
typedef volatile uint32 RwReg;
#endif
#if defined(ARDUINO_FEATHER52)
typedef volatile uint32_t RwReg;
#endif
#define ILI9341_TFTWIDTH 240
#define ILI9341_TFTHEIGHT 320
#define ILI9341_NOP 0x00
#define ILI9341_SWRESET 0x01
#define ILI9341_RDDID 0x04
#define ILI9341_RDDST 0x09
#define ILI9341_SLPIN 0x10
#define ILI9341_SLPOUT 0x11
#define ILI9341_PTLON 0x12
#define ILI9341_NORON 0x13
#define ILI9341_RDMODE 0x0A
#define ILI9341_RDMADCTL 0x0B
#define ILI9341_RDPIXFMT 0x0C
#define ILI9341_RDIMGFMT 0x0D
#define ILI9341_RDSELFDIAG 0x0F
#define ILI9341_INVOFF 0x20
#define ILI9341_INVON 0x21
#define ILI9341_GAMMASET 0x26
#define ILI9341_DISPOFF 0x28
#define ILI9341_DISPON 0x29
#define ILI9341_CASET 0x2A
#define ILI9341_PASET 0x2B
#define ILI9341_RAMWR 0x2C
#define ILI9341_RAMRD 0x2E
#define ILI9341_PTLAR 0x30
#define ILI9341_MADCTL 0x36
#define ILI9341_VSCRSADD 0x37
#define ILI9341_PIXFMT 0x3A
#define ILI9341_FRMCTR1 0xB1
#define ILI9341_FRMCTR2 0xB2
#define ILI9341_FRMCTR3 0xB3
#define ILI9341_INVCTR 0xB4
#define ILI9341_DFUNCTR 0xB6
#define ILI9341_PWCTR1 0xC0
#define ILI9341_PWCTR2 0xC1
#define ILI9341_PWCTR3 0xC2
#define ILI9341_PWCTR4 0xC3
#define ILI9341_PWCTR5 0xC4
#define ILI9341_VMCTR1 0xC5
#define ILI9341_VMCTR2 0xC7
#define ILI9341_RDID1 0xDA
#define ILI9341_RDID2 0xDB
#define ILI9341_RDID3 0xDC
#define ILI9341_RDID4 0xDD
#define ILI9341_GMCTRP1 0xE0
#define ILI9341_GMCTRN1 0xE1
/*
#define ILI9341_PWCTR6 0xFC
*/
// Color definitions
#define ILI9341_BLACK 0x0000 /* 0, 0, 0 */
#define ILI9341_NAVY 0x000F /* 0, 0, 128 */
#define ILI9341_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define ILI9341_DARKCYAN 0x03EF /* 0, 128, 128 */
#define ILI9341_MAROON 0x7800 /* 128, 0, 0 */
#define ILI9341_PURPLE 0x780F /* 128, 0, 128 */
#define ILI9341_OLIVE 0x7BE0 /* 128, 128, 0 */
#define ILI9341_LIGHTGREY 0xC618 /* 192, 192, 192 */
#define ILI9341_DARKGREY 0x7BEF /* 128, 128, 128 */
#define ILI9341_BLUE 0x001F /* 0, 0, 255 */
#define ILI9341_GREEN 0x07E0 /* 0, 255, 0 */
#define ILI9341_CYAN 0x07FF /* 0, 255, 255 */
#define ILI9341_RED 0xF800 /* 255, 0, 0 */
#define ILI9341_MAGENTA 0xF81F /* 255, 0, 255 */
#define ILI9341_YELLOW 0xFFE0 /* 255, 255, 0 */
#define ILI9341_WHITE 0xFFFF /* 255, 255, 255 */
#define ILI9341_ORANGE 0xFD20 /* 255, 165, 0 */
#define ILI9341_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
#define ILI9341_PINK 0xF81F
#if defined (ARDUINO_STM32_FEATHER) // doesnt work on wiced feather
#undef USE_FAST_PINIO
#elif defined (__AVR__) || defined(TEENSYDUINO) || defined(ESP8266) || defined (ESP32) || defined(__arm__)
#define USE_FAST_PINIO
#endif
class Adafruit_ILI9341 : public Adafruit_GFX {
protected:
public:
Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _MOSI, int8_t _SCLK, int8_t _RST = -1, int8_t _MISO = -1);
Adafruit_ILI9341(int8_t _CS, int8_t _DC, int8_t _RST = -1);
#ifndef ESP32
void begin(uint32_t freq = 0);
#else
void begin(uint32_t freq = 0, SPIClass &spi=SPI);
#endif
void setScrollStart(uint16_t start);
void setScrollMargins(uint16_t top, uint16_t bottom);
void setRotation(uint8_t r);
void invertDisplay(boolean i);
void scrollTo(uint16_t y);
// Required Non-Transaction
void drawPixel(int16_t x, int16_t y, uint16_t color);
// Transaction API
void startWrite(void);
void endWrite(void);
void writePixel(int16_t x, int16_t y, uint16_t color);
void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
// Transaction API not used by GFX
void setAddrWindow(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
void writePixel(uint16_t color);
void writePixels(uint16_t * colors, uint32_t len);
void writeColor(uint16_t color, uint32_t len);
void pushColor(uint16_t color);
// Recommended Non-Transaction
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
using Adafruit_GFX::drawRGBBitmap; // Check base class first
void drawRGBBitmap(int16_t x, int16_t y,
uint16_t *pcolors, int16_t w, int16_t h);
uint8_t readcommand8(uint8_t reg, uint8_t index = 0);
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
private:
#ifdef ESP32
SPIClass _spi;
#endif
uint32_t _freq;
#if defined (__AVR__) || defined(TEENSYDUINO)
int8_t _cs, _dc, _rst, _sclk, _mosi, _miso;
#ifdef USE_FAST_PINIO
volatile uint8_t *mosiport, *misoport, *clkport, *dcport, *csport;
uint8_t mosipinmask, misopinmask, clkpinmask, cspinmask, dcpinmask;
#endif
#elif defined (__arm__)
int32_t _cs, _dc, _rst, _sclk, _mosi, _miso;
#ifdef USE_FAST_PINIO
volatile RwReg *mosiport, *misoport, *clkport, *dcport, *csport;
uint32_t mosipinmask, misopinmask, clkpinmask, cspinmask, dcpinmask;
#endif
#elif defined (ESP8266) || defined (ESP32)
int8_t _cs, _dc, _rst, _sclk, _mosi, _miso;
#ifdef USE_FAST_PINIO
volatile uint32_t *mosiport, *misoport, *clkport, *dcport, *csport;
uint32_t mosipinmask, misopinmask, clkpinmask, cspinmask, dcpinmask;
#endif
#else
int8_t _cs, _dc, _rst, _sclk, _mosi, _miso;
#endif
void writeCommand(uint8_t cmd);
void spiWrite(uint8_t v);
uint8_t spiRead(void);
};
#endif

View File

@ -0,0 +1,145 @@
/***************************************************
This is our touchscreen painting example for the Adafruit ILI9341 Breakout
----> http://www.adafruit.com/products/1770
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
/** NOT FOR USE WITH THE TOUCH SHIELD, ONLY FOR THE BREAKOUT! **/
#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h>
#include <Adafruit_ILI9341.h>
#include "TouchScreen.h"
// These are the four touchscreen analog pins
#define YP A2 // must be an analog pin, use "An" notation!
#define XM A3 // must be an analog pin, use "An" notation!
#define YM 5 // can be a digital pin
#define XP 4 // can be a digital pin
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940
#define MINPRESSURE 10
#define MAXPRESSURE 1000
// The display uses hardware SPI, plus #9 & #10
#define TFT_CS 10
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;
void setup(void) {
// while (!Serial); // used for leonardo debugging
Serial.begin(9600);
Serial.println(F("Touch Paint!"));
tft.begin();
tft.fillScreen(ILI9341_BLACK);
// make the color selection boxes
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
// select the current color 'red'
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
currentcolor = ILI9341_RED;
}
void loop()
{
// Retrieve a point
TSPoint p = ts.getPoint();
/*
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
*/
// we have some minimum pressure we consider 'valid'
// pressure of 0 means no pressing!
if (p.z < MINPRESSURE || p.z > MAXPRESSURE) {
return;
}
// Scale from ~0->1000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
/*
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
*/
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = ILI9341_RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = ILI9341_YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = ILI9341_GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = ILI9341_CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = ILI9341_BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*6) {
currentcolor = ILI9341_MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == ILI9341_RED)
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
if (oldcolor == ILI9341_YELLOW)
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
if (oldcolor == ILI9341_GREEN)
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
if (oldcolor == ILI9341_CYAN)
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
if (oldcolor == ILI9341_BLUE)
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
if (oldcolor == ILI9341_MAGENTA)
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
}
}
if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}

View File

@ -0,0 +1,253 @@
/***************************************************
This is our touchscreen painting example for the Adafruit TFT FeatherWing
----> http://www.adafruit.com/products/3315
Check out the links above for our tutorials and wiring diagrams
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <SPI.h>
#include <Wire.h> // this is needed even tho we aren't using it
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ILI9341.h> // Hardware-specific library
#include <SD.h>
#include <Adafruit_STMPE610.h>
#ifdef ESP8266
#define STMPE_CS 16
#define TFT_CS 0
#define TFT_DC 15
#define SD_CS 2
#endif
#ifdef ESP32
#define STMPE_CS 32
#define TFT_CS 15
#define TFT_DC 33
#define SD_CS 14
#endif
#if defined (__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_FEATHER_M0) || defined (__AVR_ATmega328P__)
#define STMPE_CS 6
#define TFT_CS 9
#define TFT_DC 10
#define SD_CS 5
#endif
#ifdef TEENSYDUINO
#define TFT_DC 10
#define TFT_CS 4
#define STMPE_CS 3
#define SD_CS 8
#endif
#ifdef ARDUINO_STM32_FEATHER
#define TFT_DC PB4
#define TFT_CS PA15
#define STMPE_CS PC7
#define SD_CS PC5
#endif
#ifdef ARDUINO_NRF52_FEATHER /* BSP 0.6.5 and higher! */
#define TFT_DC 11
#define TFT_CS 31
#define STMPE_CS 30
#define SD_CS 27
#endif
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 3800
#define TS_MAXX 100
#define TS_MINY 100
#define TS_MAXY 3750
#define PENRADIUS 3
void setup(void) {
Serial.begin(115200);
delay(10);
Serial.println("FeatherWing TFT");
if (!ts.begin()) {
Serial.println("Couldn't start touchscreen controller");
while (1);
}
Serial.println("Touchscreen started");
tft.begin();
tft.fillScreen(ILI9341_BLUE);
yield();
Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("failed!");
}
Serial.println("OK!");
bmpDraw("purple.bmp", 0, 0);
}
void loop() {
// Retrieve a point
TS_Point p = ts.getPoint();
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
// Scale from ~0->4000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
if (((p.y-PENRADIUS) > 0) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, ILI9341_RED);
}
}
// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates. It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel). Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster. 20 pixels seems a
// good balance.
#define BUFFPIXEL 20
void bmpDraw(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print(F("Loading image '"));
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print(F("File not found"));
return;
}
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
Serial.print(F("Image size: "));
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col=0; col<w; col++) { // For each pixel...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format, push to display
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft.pushColor(tft.color565(r,g,b));
} // end pixel
} // end scanline
Serial.print(F("Loaded in "));
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println(F("BMP format not recognized."));
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File &f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File &f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}

View File

@ -13,31 +13,36 @@
MIT license, all text above must be included in any redistribution MIT license, all text above must be included in any redistribution
****************************************************/ ****************************************************/
#include "SPI.h" #include "SPI.h"
#include "Adafruit_GFX.h" #include "Adafruit_GFX.h"
#include "TasmotaTFT.h" #include "Adafruit_ILI9341.h"
#define TFT_DC 16 // For the Adafruit shield, these are the default.
#define TFT_CS 15 #define TFT_DC 9
#define TFT_CS 10
TasmotaTFT tft = TasmotaTFT(ILI9341, TFT_CS, TFT_DC); // Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
void setup() { void setup() {
Serial.begin(115200); Serial.begin(9600);
Serial.println("ILI9341 Test!"); Serial.println("ILI9341 Test!");
tft.begin(); tft.begin();
// read diagnostics (optional but can help debug problems) // read diagnostics (optional but can help debug problems)
uint8_t x = tft.readcommand8(TFT_RDMODE); uint8_t x = tft.readcommand8(ILI9341_RDMODE);
Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX); Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(TFT_RDMADCTL); x = tft.readcommand8(ILI9341_RDMADCTL);
Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX); Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(TFT_RDPIXFMT); x = tft.readcommand8(ILI9341_RDPIXFMT);
Serial.print("Pixel Format: 0x"); Serial.println(x, HEX); Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(TFT_RDIMGFMT); x = tft.readcommand8(ILI9341_RDIMGFMT);
Serial.print("Image Format: 0x"); Serial.println(x, HEX); Serial.print("Image Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(TFT_RDSELFDIAG); x = tft.readcommand8(ILI9341_RDSELFDIAG);
Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
Serial.println(F("Benchmark Time (microseconds)")); Serial.println(F("Benchmark Time (microseconds)"));
@ -51,26 +56,26 @@ void setup() {
delay(3000); delay(3000);
Serial.print(F("Lines ")); Serial.print(F("Lines "));
Serial.println(testLines(TFT_CYAN)); Serial.println(testLines(ILI9341_CYAN));
delay(500); delay(500);
Serial.print(F("Horiz/Vert Lines ")); Serial.print(F("Horiz/Vert Lines "));
Serial.println(testFastLines(TFT_RED, TFT_BLUE)); Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
delay(500); delay(500);
Serial.print(F("Rectangles (outline) ")); Serial.print(F("Rectangles (outline) "));
Serial.println(testRects(TFT_GREEN)); Serial.println(testRects(ILI9341_GREEN));
delay(500); delay(500);
Serial.print(F("Rectangles (filled) ")); Serial.print(F("Rectangles (filled) "));
Serial.println(testFilledRects(TFT_YELLOW, TFT_MAGENTA)); Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
delay(500); delay(500);
Serial.print(F("Circles (filled) ")); Serial.print(F("Circles (filled) "));
Serial.println(testFilledCircles(10, TFT_MAGENTA)); Serial.println(testFilledCircles(10, ILI9341_MAGENTA));
Serial.print(F("Circles (outline) ")); Serial.print(F("Circles (outline) "));
Serial.println(testCircles(10, TFT_WHITE)); Serial.println(testCircles(10, ILI9341_WHITE));
delay(500); delay(500);
Serial.print(F("Triangles (outline) ")); Serial.print(F("Triangles (outline) "));
@ -104,31 +109,31 @@ void loop(void) {
unsigned long testFillScreen() { unsigned long testFillScreen() {
unsigned long start = micros(); unsigned long start = micros();
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
yield(); yield();
tft.fillScreen(TFT_RED); tft.fillScreen(ILI9341_RED);
yield(); yield();
tft.fillScreen(TFT_GREEN); tft.fillScreen(ILI9341_GREEN);
yield(); yield();
tft.fillScreen(TFT_BLUE); tft.fillScreen(ILI9341_BLUE);
yield(); yield();
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
yield(); yield();
return micros() - start; return micros() - start;
} }
unsigned long testText() { unsigned long testText() {
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
unsigned long start = micros(); unsigned long start = micros();
tft.setCursor(0, 0); tft.setCursor(0, 0);
tft.setTextColor(TFT_WHITE); tft.setTextSize(1); tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
tft.println("Hello World!"); tft.println("Hello World!");
tft.setTextColor(TFT_YELLOW); tft.setTextSize(2); tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
tft.println(1234.56); tft.println(1234.56);
tft.setTextColor(TFT_RED); tft.setTextSize(3); tft.setTextColor(ILI9341_RED); tft.setTextSize(3);
tft.println(0xDEADBEEF, HEX); tft.println(0xDEADBEEF, HEX);
tft.println(); tft.println();
tft.setTextColor(TFT_GREEN); tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(5); tft.setTextSize(5);
tft.println("Groop"); tft.println("Groop");
tft.setTextSize(2); tft.setTextSize(2);
@ -150,7 +155,7 @@ unsigned long testLines(uint16_t color) {
w = tft.width(), w = tft.width(),
h = tft.height(); h = tft.height();
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
yield(); yield();
x1 = y1 = 0; x1 = y1 = 0;
@ -162,7 +167,7 @@ unsigned long testLines(uint16_t color) {
t = micros() - start; // fillScreen doesn't count against timing t = micros() - start; // fillScreen doesn't count against timing
yield(); yield();
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
yield(); yield();
x1 = w - 1; x1 = w - 1;
@ -175,7 +180,7 @@ unsigned long testLines(uint16_t color) {
t += micros() - start; t += micros() - start;
yield(); yield();
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
yield(); yield();
x1 = 0; x1 = 0;
@ -188,7 +193,7 @@ unsigned long testLines(uint16_t color) {
t += micros() - start; t += micros() - start;
yield(); yield();
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
yield(); yield();
x1 = w - 1; x1 = w - 1;
@ -207,7 +212,7 @@ unsigned long testFastLines(uint16_t color1, uint16_t color2) {
unsigned long start; unsigned long start;
int x, y, w = tft.width(), h = tft.height(); int x, y, w = tft.width(), h = tft.height();
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
start = micros(); start = micros();
for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1); for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2); for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
@ -221,7 +226,7 @@ unsigned long testRects(uint16_t color) {
cx = tft.width() / 2, cx = tft.width() / 2,
cy = tft.height() / 2; cy = tft.height() / 2;
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height()); n = min(tft.width(), tft.height());
start = micros(); start = micros();
for(i=2; i<n; i+=6) { for(i=2; i<n; i+=6) {
@ -238,7 +243,7 @@ unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
cx = tft.width() / 2 - 1, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1; cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height()); n = min(tft.width(), tft.height());
for(i=n; i>0; i-=6) { for(i=n; i>0; i-=6) {
i2 = i / 2; i2 = i / 2;
@ -257,7 +262,7 @@ unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
unsigned long start; unsigned long start;
int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2; int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
start = micros(); start = micros();
for(x=radius; x<w; x+=r2) { for(x=radius; x<w; x+=r2) {
for(y=radius; y<h; y+=r2) { for(y=radius; y<h; y+=r2) {
@ -291,7 +296,7 @@ unsigned long testTriangles() {
int n, i, cx = tft.width() / 2 - 1, int n, i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1; cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
n = min(cx, cy); n = min(cx, cy);
start = micros(); start = micros();
for(i=0; i<n; i+=5) { for(i=0; i<n; i+=5) {
@ -310,7 +315,7 @@ unsigned long testFilledTriangles() {
int i, cx = tft.width() / 2 - 1, int i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1; cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
start = micros(); start = micros();
for(i=min(cx,cy); i>10; i-=5) { for(i=min(cx,cy); i>10; i-=5) {
start = micros(); start = micros();
@ -331,7 +336,7 @@ unsigned long testRoundRects() {
cx = tft.width() / 2 - 1, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1; cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
w = min(tft.width(), tft.height()); w = min(tft.width(), tft.height());
start = micros(); start = micros();
for(i=0; i<w; i+=6) { for(i=0; i<w; i+=6) {
@ -348,7 +353,7 @@ unsigned long testFilledRoundRects() {
cx = tft.width() / 2 - 1, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1; cy = tft.height() / 2 - 1;
tft.fillScreen(TFT_BLACK); tft.fillScreen(ILI9341_BLACK);
start = micros(); start = micros();
for(i=min(tft.width(), tft.height()); i>20; i-=6) { for(i=min(tft.width(), tft.height()); i>20; i-=6) {
i2 = i / 2; i2 = i / 2;

View File

@ -0,0 +1,395 @@
/***************************************************
This is our GFX example for the Adafruit ILI9341 TFT FeatherWing
----> http://www.adafruit.com/products/3315
Check out the links above for our tutorials and wiring diagrams
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#ifdef ESP8266
#define STMPE_CS 16
#define TFT_CS 0
#define TFT_DC 15
#define SD_CS 2
#endif
#ifdef ESP32
#define STMPE_CS 32
#define TFT_CS 15
#define TFT_DC 33
#define SD_CS 14
#endif
#if defined (__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_FEATHER_M0) || defined (__AVR_ATmega328P__)
#define STMPE_CS 6
#define TFT_CS 9
#define TFT_DC 10
#define SD_CS 5
#endif
#ifdef TEENSYDUINO
#define TFT_DC 10
#define TFT_CS 4
#define STMPE_CS 3
#define SD_CS 8
#endif
#ifdef ARDUINO_STM32_FEATHER
#define TFT_DC PB4
#define TFT_CS PA15
#define STMPE_CS PC7
#define SD_CS PC5
#endif
#ifdef ARDUINO_NRF52_FEATHER /* BSP 0.6.5 and higher! */
#define TFT_DC 11
#define TFT_CS 31
#define STMPE_CS 30
#define SD_CS 27
#endif
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
void setup() {
Serial.begin(115200);
delay(10);
Serial.println("FeatherWing TFT Test!");
tft.begin();
// read diagnostics (optional but can help debug problems)
uint8_t x = tft.readcommand8(ILI9341_RDMODE);
Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDMADCTL);
Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDPIXFMT);
Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDIMGFMT);
Serial.print("Image Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDSELFDIAG);
Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
Serial.println(F("Benchmark Time (microseconds)"));
delay(10);
Serial.print(F("Screen fill "));
Serial.println(testFillScreen());
delay(500);
Serial.print(F("Text "));
Serial.println(testText());
delay(3000);
Serial.print(F("Lines "));
Serial.println(testLines(ILI9341_CYAN));
delay(500);
Serial.print(F("Horiz/Vert Lines "));
Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
delay(500);
Serial.print(F("Rectangles (outline) "));
Serial.println(testRects(ILI9341_GREEN));
delay(500);
Serial.print(F("Rectangles (filled) "));
Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
delay(500);
Serial.print(F("Circles (filled) "));
Serial.println(testFilledCircles(10, ILI9341_MAGENTA));
Serial.print(F("Circles (outline) "));
Serial.println(testCircles(10, ILI9341_WHITE));
delay(500);
Serial.print(F("Triangles (outline) "));
Serial.println(testTriangles());
delay(500);
Serial.print(F("Triangles (filled) "));
Serial.println(testFilledTriangles());
delay(500);
Serial.print(F("Rounded rects (outline) "));
Serial.println(testRoundRects());
delay(500);
Serial.print(F("Rounded rects (filled) "));
Serial.println(testFilledRoundRects());
delay(500);
Serial.println(F("Done!"));
}
void loop(void) {
for(uint8_t rotation=0; rotation<4; rotation++) {
tft.setRotation(rotation);
testText();
delay(1000);
}
}
unsigned long testFillScreen() {
unsigned long start = micros();
tft.fillScreen(ILI9341_BLACK);
yield();
tft.fillScreen(ILI9341_RED);
yield();
tft.fillScreen(ILI9341_GREEN);
yield();
tft.fillScreen(ILI9341_BLUE);
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
return micros() - start;
}
unsigned long testText() {
tft.fillScreen(ILI9341_BLACK);
unsigned long start = micros();
tft.setCursor(0, 0);
tft.setTextColor(ILI9341_WHITE); tft.setTextSize(1);
tft.println("Hello World!");
tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
tft.println(1234.56);
tft.setTextColor(ILI9341_RED); tft.setTextSize(3);
tft.println(0xDEADBEEF, HEX);
tft.println();
tft.setTextColor(ILI9341_GREEN);
tft.setTextSize(5);
tft.println("Groop");
tft.setTextSize(2);
tft.println("I implore thee,");
tft.setTextSize(1);
tft.println("my foonting turlingdromes.");
tft.println("And hooptiously drangle me");
tft.println("with crinkly bindlewurdles,");
tft.println("Or I will rend thee");
tft.println("in the gobberwarts");
tft.println("with my blurglecruncheon,");
tft.println("see if I don't!");
return micros() - start;
}
unsigned long testLines(uint16_t color) {
unsigned long start, t;
int x1, y1, x2, y2,
w = tft.width(),
h = tft.height();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = y1 = 0;
y2 = h - 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t = micros() - start; // fillScreen doesn't count against timing
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = w - 1;
y1 = 0;
y2 = h - 1;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = 0;
y1 = h - 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = w - 1;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
t += micros() - start;
yield();
tft.fillScreen(ILI9341_BLACK);
yield();
x1 = w - 1;
y1 = h - 1;
y2 = 0;
start = micros();
for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
x2 = 0;
for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
yield();
return micros() - start;
}
unsigned long testFastLines(uint16_t color1, uint16_t color2) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height();
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
return micros() - start;
}
unsigned long testRects(uint16_t color) {
unsigned long start;
int n, i, i2,
cx = tft.width() / 2,
cy = tft.height() / 2;
tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height());
start = micros();
for(i=2; i<n; i+=6) {
i2 = i / 2;
tft.drawRect(cx-i2, cy-i2, i, i, color);
}
return micros() - start;
}
unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
unsigned long start, t = 0;
int n, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
n = min(tft.width(), tft.height());
for(i=n; i>0; i-=6) {
i2 = i / 2;
start = micros();
tft.fillRect(cx-i2, cy-i2, i, i, color1);
t += micros() - start;
// Outlines are not included in timing results
tft.drawRect(cx-i2, cy-i2, i, i, color2);
yield();
}
return t;
}
unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(x=radius; x<w; x+=r2) {
for(y=radius; y<h; y+=r2) {
tft.fillCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testCircles(uint8_t radius, uint16_t color) {
unsigned long start;
int x, y, r2 = radius * 2,
w = tft.width() + radius,
h = tft.height() + radius;
// Screen is not cleared for this one -- this is
// intentional and does not affect the reported time.
start = micros();
for(x=0; x<w; x+=r2) {
for(y=0; y<h; y+=r2) {
tft.drawCircle(x, y, radius, color);
}
}
return micros() - start;
}
unsigned long testTriangles() {
unsigned long start;
int n, i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
n = min(cx, cy);
start = micros();
for(i=0; i<n; i+=5) {
tft.drawTriangle(
cx , cy - i, // peak
cx - i, cy + i, // bottom left
cx + i, cy + i, // bottom right
tft.color565(i, i, i));
}
return micros() - start;
}
unsigned long testFilledTriangles() {
unsigned long start, t = 0;
int i, cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(i=min(cx,cy); i>10; i-=5) {
start = micros();
tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(0, i*10, i*10));
t += micros() - start;
tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
tft.color565(i*10, i*10, 0));
yield();
}
return t;
}
unsigned long testRoundRects() {
unsigned long start;
int w, i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
w = min(tft.width(), tft.height());
start = micros();
for(i=0; i<w; i+=6) {
i2 = i / 2;
tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 0, 0));
}
return micros() - start;
}
unsigned long testFilledRoundRects() {
unsigned long start;
int i, i2,
cx = tft.width() / 2 - 1,
cy = tft.height() / 2 - 1;
tft.fillScreen(ILI9341_BLACK);
start = micros();
for(i=min(tft.width(), tft.height()); i>20; i-=6) {
i2 = i / 2;
tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
yield();
}
return micros() - start;
}

View File

@ -0,0 +1,125 @@
//This example implements a simple sliding On/Off button. The example
// demonstrates drawing and touch operations.
//
//Thanks to Adafruit forums member Asteroid for the original sketch!
//
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_ILI9341.h>
#include <Adafruit_STMPE610.h>
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 130
#define TS_MAXX 3800
#define TS_MAXY 4000
#define STMPE_CS 8
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
#define TFT_CS 10
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
boolean RecordOn = false;
#define FRAME_X 210
#define FRAME_Y 180
#define FRAME_W 100
#define FRAME_H 50
#define REDBUTTON_X FRAME_X
#define REDBUTTON_Y FRAME_Y
#define REDBUTTON_W (FRAME_W/2)
#define REDBUTTON_H FRAME_H
#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
#define GREENBUTTON_Y FRAME_Y
#define GREENBUTTON_W (FRAME_W/2)
#define GREENBUTTON_H FRAME_H
void drawFrame()
{
tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK);
}
void redBtn()
{
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED);
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE);
drawFrame();
tft.setCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2));
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("ON");
RecordOn = false;
}
void greenBtn()
{
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN);
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE);
drawFrame();
tft.setCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2));
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("OFF");
RecordOn = true;
}
void setup(void)
{
Serial.begin(9600);
tft.begin();
if (!ts.begin()) {
Serial.println("Unable to start touchscreen.");
}
else {
Serial.println("Touchscreen started.");
}
tft.fillScreen(ILI9341_BLUE);
// origin = left,top landscape (USB left upper)
tft.setRotation(1);
redBtn();
}
void loop()
{
// See if there's any touch data for us
if (!ts.bufferEmpty())
{
// Retrieve a point
TS_Point p = ts.getPoint();
// Scale using the calibration #'s
// and rotate coordinate system
p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height());
p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width());
int y = tft.height() - p.x;
int x = p.y;
if (RecordOn)
{
if((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) {
if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) {
Serial.println("Red btn hit");
redBtn();
}
}
}
else //Record is off (RecordOn == false)
{
if((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) {
if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) {
Serial.println("Green btn hit");
greenBtn();
}
}
}
Serial.println(RecordOn);
}
}

View File

@ -0,0 +1,133 @@
//This example implements a simple sliding On/Off button. The example
// demonstrates drawing and touch operations.
//
//Thanks to Adafruit forums member Asteroid for the original sketch!
//
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_ILI9341.h>
#include <TouchScreen.h>
//Touchscreen X+ X- Y+ Y- pins
#define YP A3 // must be an analog pin, use "An" notation!
#define XM A2 // must be an analog pin, use "An" notation!
#define YM 5 // can be a digital pin
#define XP 4 // can be a digital pin
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 120
#define TS_MAXX 920
#define TS_MAXY 940
#define MINPRESSURE 10
#define MAXPRESSURE 1000
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 300 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
#define TFT_CS 10
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
boolean RecordOn = false;
#define FRAME_X 210
#define FRAME_Y 180
#define FRAME_W 100
#define FRAME_H 50
#define REDBUTTON_X FRAME_X
#define REDBUTTON_Y FRAME_Y
#define REDBUTTON_W (FRAME_W/2)
#define REDBUTTON_H FRAME_H
#define GREENBUTTON_X (REDBUTTON_X + REDBUTTON_W)
#define GREENBUTTON_Y FRAME_Y
#define GREENBUTTON_W (FRAME_W/2)
#define GREENBUTTON_H FRAME_H
void drawFrame()
{
tft.drawRect(FRAME_X, FRAME_Y, FRAME_W, FRAME_H, ILI9341_BLACK);
}
void redBtn()
{
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_RED);
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_BLUE);
drawFrame();
tft.setCursor(GREENBUTTON_X + 6 , GREENBUTTON_Y + (GREENBUTTON_H/2));
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("ON");
RecordOn = false;
}
void greenBtn()
{
tft.fillRect(GREENBUTTON_X, GREENBUTTON_Y, GREENBUTTON_W, GREENBUTTON_H, ILI9341_GREEN);
tft.fillRect(REDBUTTON_X, REDBUTTON_Y, REDBUTTON_W, REDBUTTON_H, ILI9341_BLUE);
drawFrame();
tft.setCursor(REDBUTTON_X + 6 , REDBUTTON_Y + (REDBUTTON_H/2));
tft.setTextColor(ILI9341_WHITE);
tft.setTextSize(2);
tft.println("OFF");
RecordOn = true;
}
void setup(void)
{
Serial.begin(9600);
tft.begin();
tft.fillScreen(ILI9341_BLUE);
// origin = left,top landscape (USB left upper)
tft.setRotation(1);
redBtn();
}
void loop()
{
// Retrieve a point
TSPoint p = ts.getPoint();
// See if there's any touch data for us
if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
{
// Scale using the calibration #'s
// and rotate coordinate system
p.x = map(p.x, TS_MINY, TS_MAXY, 0, tft.height());
p.y = map(p.y, TS_MINX, TS_MAXX, 0, tft.width());
int y = tft.height() - p.x;
int x = p.y;
if (RecordOn)
{
if((x > REDBUTTON_X) && (x < (REDBUTTON_X + REDBUTTON_W))) {
if ((y > REDBUTTON_Y) && (y <= (REDBUTTON_Y + REDBUTTON_H))) {
Serial.println("Red btn hit");
redBtn();
}
}
}
else //Record is off (RecordOn == false)
{
if((x > GREENBUTTON_X) && (x < (GREENBUTTON_X + GREENBUTTON_W))) {
if ((y > GREENBUTTON_Y) && (y <= (GREENBUTTON_Y + GREENBUTTON_H))) {
Serial.println("Green btn hit");
greenBtn();
}
}
}
Serial.println(RecordOn);
}
}

View File

@ -0,0 +1,861 @@
#define DRAGON_WIDTH 110
#define DRAGON_HEIGHT 70
const PROGMEM uint16_t dragonBitmap[DRAGON_WIDTH * DRAGON_HEIGHT] = {
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X8C10, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14, 0XAC92, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XB431, 0XA1C9, 0XAA4B, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE18, 0X9A2A, 0X9044,
0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XDEFB, 0XB3B0, 0XA148, 0XB865, 0XC066, 0XC066, 0XAA4B,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAB2E, 0X9864,
0XA865, 0XAAAC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAC92,
0X728B, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XCE18, 0XAB2E, 0XAA4B, 0XAA4B, 0XAA4B, 0XA3AF,
0XB431, 0XB431, 0XB431, 0XA411, 0XA8E6, 0XD086, 0XB865, 0X7043, 0XA865,
0XD086, 0XAA4B, 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XA8E6,
0X9864, 0XC066, 0XD086, 0XB493, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79, 0X830D,
0X80C5, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB431, 0XC066, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XB865, 0X9864,
0XC066, 0XD086, 0XB8E7, 0XB493, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XA1C9,
0XB865, 0X9864, 0XD086, 0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAD14, 0X71A8,
0X9864, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XDEFB, 0XBDF7, 0XBD14, 0XA411, 0XB431, 0XB148, 0XD086, 0XC066,
0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XD086, 0XA865,
0XB865, 0XD086, 0XD086, 0XB1CA, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB3B0,
0XB865, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XBD14, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79, 0X932D, 0X78C5,
0XA865, 0XD086, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XDEFB, 0XAB2E, 0XA0C6, 0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086,
0XB865, 0X78C5, 0X4208, 0X2104, 0X8947, 0X9864, 0X9864, 0X9864, 0XD086,
0XD086, 0XA865, 0X9864, 0XD086, 0XB865, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE18,
0XB148, 0XC066, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB493, 0X89A8, 0X9044,
0XB865, 0XD086, 0XD086, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0X7B8E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XAD14, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XB431, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865,
0X9864, 0XD086, 0XD086, 0XD086, 0XAA4B, 0X9A2A, 0XC066, 0XD086, 0XD086,
0XD086, 0XD086, 0XC066, 0X9044, 0X9864, 0X9864, 0X9044, 0XCE18, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D,
0XB3B0, 0XC066, 0XB865, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XAAAC, 0XBD96, 0XAD14, 0XAAAC, 0X8044, 0X9864,
0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XB431, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XB3B0, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD96, 0XB8E7, 0XB431, 0XEF7D, 0XFFFF,
0XFFFF, 0XFFFF, 0XA32E, 0X9864, 0X9864, 0XAA4B, 0XAA4B, 0X9147, 0XB865,
0X9044, 0XD086, 0XA865, 0XD086, 0XC066, 0XC066, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086,
0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XDE9A, 0XB148, 0XD086, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0XA865, 0X9864,
0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA148, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XC066, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086,
0XA865, 0XAB2E, 0XBD96, 0XEF7D, 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XDEFB, 0XB1CA, 0XD086, 0XD086, 0X9864, 0X822A, 0XBDF7, 0XB493,
0XB148, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864,
0XD086, 0XD086, 0XD086, 0XAA4B, 0XBD14, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XB431, 0XB865, 0XD086, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0XC066, 0XA865, 0X9864,
0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB3B0,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCD96, 0XC066, 0XD086, 0XAA4B, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XDE9A, 0XB865, 0XD086, 0XD086, 0XD086, 0XA865, 0X9147, 0X9C92, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE18, 0X80C5, 0X5822, 0X5A08, 0XDEFB,
0XFFFF, 0XFFFF, 0XCE79, 0XA0C6, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0X9044, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XAB2E, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XEF7D, 0XAA4B, 0XD086, 0XC066, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0XA865, 0XD086, 0X9864, 0X9864,
0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086, 0XD086,
0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XC066, 0XD086, 0XB865, 0X8044, 0X82AB,
0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XAC92, 0XA3AF, 0X92AC,
0XAB2E, 0XAA4B, 0XA1C9, 0X9864, 0XB865, 0XA865, 0XC066, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XB1CA, 0XBD14,
0X9CF3, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XCE18, 0XA8E6, 0XD086, 0XC066, 0XA865, 0XD086, 0XD086,
0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0XC066, 0XD086, 0X9864, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XC066, 0XC515, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086,
0XD086, 0XD086, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB3B0, 0XD086, 0XA865,
0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XC066, 0XA865, 0X8044, 0X4822, 0X9044, 0X9044,
0XD086, 0XD086, 0XD086, 0XD086, 0X8044, 0X9864, 0XD086, 0XD086, 0XD086,
0XAA4B, 0XCE18, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XC066, 0XD086, 0XC066, 0XA865, 0XD086,
0XD086, 0XD086, 0XA865, 0X9864, 0XA865, 0XD086, 0XC066, 0X9864, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9044, 0X3986, 0XCE79,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7,
0XD086, 0XD086, 0XC066, 0XD086, 0XAA4B, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XB431, 0XC066, 0X90C6, 0XAA4B, 0XAA4B, 0XAA4B, 0XAA4B, 0X99C9, 0X9864,
0X9864, 0X9864, 0X6843, 0X6843, 0X5822, 0X4822, 0X7043, 0X9044, 0XC066,
0X9864, 0X7043, 0XC066, 0XB865, 0XD086, 0X7043, 0X8044, 0XC066, 0XD086,
0XD086, 0XD086, 0XD086, 0XC066, 0XB431, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAB2E, 0XD086, 0XD086, 0XC066, 0XA865,
0XD086, 0XD086, 0X9864, 0X9044, 0XC066, 0XD086, 0XC066, 0X9864, 0XA865,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XB865, 0X9864, 0X9864, 0X9864, 0X9044, 0X6843, 0X6843, 0X8044, 0X7B0C,
0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A,
0XB8E7, 0XD086, 0X9864, 0XC066, 0X9864, 0XD086, 0XAA4B, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XA8E6, 0XCE18, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XA148, 0XD086, 0XD086, 0XD086, 0XD086,
0XB148, 0XBD14, 0X9A2A, 0XD086, 0X9864, 0X9864, 0X6843, 0XD086, 0XC066,
0XC066, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0XA865, 0XEF7D, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB1CA, 0XD086, 0XD086, 0XD086,
0X9864, 0XC066, 0X9864, 0X9864, 0XD086, 0XD086, 0XC066, 0X9864, 0XA865,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0X9864,
0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086, 0XA1C9,
0XDE9A, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XDE9A, 0XB8E7, 0XD086, 0XD086, 0X9864, 0XD086, 0X9864, 0XD086, 0XAA4B,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XCE18, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086, 0XC066,
0XD086, 0XAAAC, 0XEF7D, 0XFFFF, 0X932D, 0XB865, 0XB865, 0XC066, 0X7043,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB148, 0XEF7D, 0XBD14, 0XA148,
0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086, 0XD086,
0XD086, 0X8044, 0X9864, 0XA865, 0XD086, 0XD086, 0XC066, 0X9864, 0XA865,
0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086,
0XB865, 0X9864, 0X9864, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086,
0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XDE9A, 0XB8E7, 0XD086, 0XD086, 0XC066, 0XA865, 0XD086, 0X9864,
0XD086, 0XA0C6, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X8C10, 0XB431, 0XEF7D, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14,
0XD086, 0XA1C9, 0X80C5, 0XEF7D, 0XFFFF, 0XB431, 0XD086, 0XB865, 0X9864,
0X8044, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XAA4B, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14, 0XD086,
0XD086, 0XD086, 0XA865, 0XB865, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864,
0X9864, 0X9044, 0X9864, 0X9864, 0XC066, 0XD086, 0XD086, 0XB865, 0X9864,
0X9864, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086,
0XD086, 0X9864, 0XD086, 0X9864, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XB148,
0XA1C9, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XBDF7, 0XD086, 0XBD14, 0XEF7D, 0XFFFF, 0XFFFF, 0XA148, 0XD086,
0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XC066, 0XB431, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XAA4B, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XC066, 0X7043,
0X9864, 0XA865, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0X9864,
0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XAAAC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XA32E, 0XAA4B, 0XAA4B, 0XAA4B, 0XAB2E,
0X9044, 0XD086, 0XA865, 0X9864, 0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XBDF7, 0XDEFB, 0XFFFF, 0XFFFF,
0XFFFF, 0XB431, 0XB865, 0XAC92, 0XFFFF, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0X8947, 0XEF7D, 0XFFFF, 0XFFFF, 0XEF7D,
0X9044, 0XD086, 0XD086, 0XB865, 0XB865, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XA0C6, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XA8E6, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XCE18, 0XC066, 0XD086, 0XA1C9, 0XB431, 0XD086, 0XD086, 0XB493,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAB2E, 0XB865,
0XB3B0, 0XFFFF, 0XFFFF, 0X9AAC, 0XB865, 0XA148, 0XFFFF, 0X9AAC, 0XCD96,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XAA4B, 0XB865, 0X9864, 0X9864, 0X8044, 0X9044, 0X8044, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XA1C9, 0X90C6, 0XD086, 0XB3B0, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086,
0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XB3B0, 0XAA4B, 0X9864, 0X9864, 0XA1C9,
0XAB2E, 0XBD96, 0XFFFF, 0XAA4B, 0XD086, 0XD086, 0XB493, 0XFFFF, 0XAB2E,
0XC066, 0XAAAC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0X8947, 0X9864, 0X9A2A, 0XFFFF, 0X9864, 0XD086, 0XA148, 0XEF7D,
0XA8E6, 0XB431, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XCE79, 0XC066, 0XD086, 0XD086, 0XD086, 0X9044, 0X7043,
0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XFFFF, 0XFFFF, 0XBD14,
0X92AC, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XB865,
0XB865, 0XD086, 0XD086, 0X8044, 0X6843, 0X9864, 0X9864, 0X9864, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XBD96, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB431, 0XB865, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X9147, 0XA865, 0XD086, 0XC066, 0XCE79,
0XFFFF, 0XFFFF, 0XCD96, 0X7926, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XC066, 0X9CF3, 0XC066, 0XD086,
0X8A2A, 0X8947, 0XD086, 0XBD14, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAD14, 0XC066, 0XD086, 0XD086, 0XD086,
0X9864, 0X9864, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865, 0XDEFB,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864,
0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864,
0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865,
0XA148, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAA4B, 0XD086, 0XD086, 0X71A8,
0XD086, 0XD086, 0X9044, 0XD086, 0X9864, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB865, 0XA865, 0XA865,
0XD086, 0XD086, 0X7043, 0X9864, 0X9044, 0XA865, 0XD086, 0XD086, 0XD086,
0XD086, 0XA8E6, 0XB493, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0X9864, 0XB865, 0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864,
0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086,
0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XA0C6, 0XD086,
0XD086, 0XD086, 0XA865, 0X80C5, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086,
0XD086, 0XC066, 0X8B8E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB493, 0XD086,
0XD086, 0X9864, 0XA865, 0XA865, 0XC066, 0XD086, 0XA8E6, 0XEF7D, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAAAC, 0XD086,
0XD086, 0XC066, 0X9864, 0X8044, 0XA865, 0X9044, 0XC066, 0X8044, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9A2A, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XEF7D, 0XA865, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086,
0X9864, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864,
0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0XD086, 0XD086,
0X9864, 0X9864, 0X9864, 0XC066, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0X9864, 0XD086, 0XD086, 0X90C6, 0XCE79, 0XFFFF, 0XFFFF, 0X9C92, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XAB2E, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XEF7D, 0XA0C6, 0XD086, 0XD086, 0XB865, 0X9864, 0XD086, 0XB1CA, 0XDE9A,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XAA4B, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X7043, 0XA865, 0X9044,
0X9044, 0XD086, 0XD086, 0XD086, 0XD086, 0XB1CA, 0XB431, 0X82AB, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBD14, 0XA865, 0XC066, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0XC066, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X7043, 0X8044, 0XDEFB, 0XFFFF,
0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0XA32E, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0X728B, 0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0XAA4B, 0XD086, 0XD086, 0XB865, 0X90C6,
0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XC515, 0X9044, 0XC066, 0XD086, 0XD086, 0XD086, 0X9864, 0X8044,
0XC066, 0X8044, 0X9044, 0XC066, 0XD086, 0XD086, 0XD086, 0XBDF7, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XEF7D, 0X6926, 0XC066, 0XD086,
0XD086, 0XD086, 0X9044, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865,
0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA8E6, 0XAAAC, 0XB431, 0X8410,
0X8C71, 0XFFFF, 0XFFFF, 0XFFFF, 0XAAAC, 0XD086, 0XD086, 0XA865, 0XA32E,
0XB431, 0XB431, 0X8947, 0XC066, 0X9864, 0XD086, 0XD086, 0XD086, 0XC066,
0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XB431, 0XD086, 0XD086,
0XD086, 0XB8E7, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XA0C6, 0XD086, 0XA865, 0X9864, 0X9864, 0X9864,
0X9044, 0X9044, 0XA865, 0X9864, 0XA865, 0X9864, 0XD086, 0XD086, 0XD086,
0XB3B0, 0XFFFF, 0XEF7D, 0XBDF7, 0XB431, 0XAAAC, 0XA148, 0XA865, 0XD086,
0XD086, 0XD086, 0XC066, 0XD086, 0XB865, 0X9044, 0X9864, 0X9864, 0XC066,
0XD086, 0XD086, 0XD086, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB8E7, 0XB493, 0XEF7D, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDE9A, 0XB8E7, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086,
0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XAAAC,
0XD086, 0XD086, 0XD086, 0XD086, 0XB3B0, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XDEFB, 0XB865, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0X8044, 0X9864, 0XB865, 0X8044, 0XC066, 0X6843, 0XD086,
0XD086, 0X9864, 0XA0C6, 0X99C9, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X8044, 0XB865, 0XD086, 0XC066, 0XA865,
0XD086, 0XA865, 0X9864, 0X9864, 0XD086, 0XD086, 0XB865, 0X9864, 0XC066,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB1CA, 0XDEFB, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XDEFB, 0XAB2E, 0X9864, 0XC066, 0XD086, 0XC066, 0X9864, 0X89A8, 0XA865,
0XD086, 0XD086, 0XD086, 0XA865, 0XEF7D, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XAA4B, 0XD086, 0XD086, 0XD086, 0XD086, 0XA148, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XBDF7, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X7043, 0XC066, 0X6843, 0XD086, 0X7043,
0XC066, 0X9044, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XD086, 0X9864, 0XB865, 0XB865,
0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XC066,
0XD086, 0XA865, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9C92,
0XBDF7, 0XBDF7, 0XBDF7, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79, 0XBDF7, 0XCE79, 0XEF7D,
0XAAAC, 0XD086, 0XD086, 0XD086, 0XD086, 0XA1C9, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XA148, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865,
0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCD96,
0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X6843, 0X9044, 0X9864,
0XA865, 0XA865, 0X9044, 0XB865, 0XD086, 0XD086, 0XB865, 0X9864, 0X8044,
0XC066, 0XD086, 0XD086, 0XB865, 0XD086, 0XA865, 0X9044, 0XD086, 0XB865,
0XB865, 0XB865, 0XA865, 0XD086, 0XB865, 0XB865, 0XD086, 0XD086, 0XD086,
0XD086, 0XA865, 0X9864, 0XB865, 0XC066, 0X9864, 0XD086, 0XD086, 0XD086,
0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XA1C9,
0XAB2E, 0XBD14, 0XCE79, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XCE79,
0XB493, 0XB148, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XBD14, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XBDF7, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XA148, 0XD086, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864, 0X9864,
0X9864, 0X9864, 0X7043, 0X9864, 0XD086, 0XD086, 0XA865, 0X9864, 0XB865,
0XD086, 0X9864, 0XD086, 0XC066, 0X7043, 0XD086, 0XD086, 0X9864, 0XC066,
0XA865, 0XD086, 0X9864, 0XD086, 0XC066, 0XA865, 0XD086, 0XA865, 0XC066,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9044, 0X9864,
0XC066, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X9864, 0X9864, 0X9864, 0X9864,
0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA1C9,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XC515, 0XC066, 0XA865,
0XD086, 0XD086, 0XD086, 0XD086, 0XAD14, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0X9044, 0X8044, 0X9864, 0XA865, 0XD086, 0XA865, 0X9864, 0XC066,
0XD086, 0XD086, 0XA865, 0XC066, 0XC066, 0XA865, 0X9864, 0XD086, 0XA865,
0XC066, 0XD086, 0X9864, 0XD086, 0X9864, 0XD086, 0XD086, 0XB865, 0XB865,
0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0X9864, 0X8044, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864,
0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XB8E7, 0XDEFB, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF,
0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0XFFFF, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0XB865,
0XD086, 0X31C3, 0XC066, 0XD086, 0XD086, 0X9864, 0XB865, 0X2305, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0X6843, 0X9864, 0XA865, 0XB865, 0X9864, 0XC066,
0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XA865, 0XD086, 0X9864,
0XD086, 0X9864, 0XD086, 0XD086, 0XA865, 0XC066, 0X9864, 0XD086, 0XD086,
0XD086, 0XC066, 0XA865, 0XB865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X8044, 0X8044, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0X8145, 0X0C66, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506,
0X8145, 0XD086, 0X9105, 0X0506, 0X80E5, 0XD086, 0XD086, 0X9864, 0XD086,
0X9864, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X80E5, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X8044, 0XB865, 0X9864, 0XB865,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0X9864, 0XD086,
0XD086, 0X9864, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865, 0X9864, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0X9864, 0X7043, 0X9864, 0XA865,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XC066, 0X59E5, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X2305, 0XB865, 0XD086, 0X2305, 0X0547, 0X1B65, 0XD086, 0XD086,
0XB865, 0XB865, 0X9864, 0X6985, 0X1B65, 0X0547, 0X0547, 0X0547, 0X0547,
0X0C05, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0X8044, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864,
0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086,
0X9864, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865, 0XA865,
0XA865, 0XD086, 0XD086, 0XA865, 0X9864, 0XC066, 0XD086, 0XD086, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XA865, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0X80E5, 0X0C05, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X1B65, 0XC066, 0X8044, 0X04A6, 0X0547, 0X0547,
0X80E5, 0XD086, 0XD086, 0X9864, 0XA865, 0XD086, 0XD086, 0X1AC4, 0X0405,
0X0547, 0X0547, 0X4285, 0XC066, 0X9864, 0X9864, 0X9864, 0X9864, 0X8044,
0XA865, 0XD086, 0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086,
0X7043, 0XC066, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086,
0XD086, 0XD086, 0XA865, 0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XB865, 0X8044, 0XD086, 0XA865, 0XC066, 0XD086, 0XD086, 0XD086,
0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XA865, 0X59E5, 0X0BA5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0506, 0X3264, 0X98A5, 0X7145, 0X04A6, 0X0547,
0X0547, 0X0547, 0X1BC5, 0XC066, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086,
0X9864, 0XD086, 0X7145, 0X4984, 0X80A4, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0X9864, 0X7043, 0X9864, 0X9864, 0XB865, 0X9864, 0XD086, 0XD086,
0XD086, 0X8044, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0XA865,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X8044, 0XC066, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0XC066, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0XA865, 0X9864,
0X6985, 0X4285, 0X1B65, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0X0445, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4A25, 0XD086, 0XD086, 0XD086,
0X9864, 0X9864, 0XC066, 0XD086, 0XD086, 0X9864, 0X9864, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864,
0XD086, 0XB865, 0X9864, 0X4822, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0X6843, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0X9864,
0XD086, 0XC066, 0X9864, 0X8044, 0X9864, 0X9864, 0X9864, 0X8044, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XA8C5, 0X32C5, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4A25,
0XD086, 0XD086, 0XD086, 0XA865, 0X9864, 0XB865, 0XD086, 0X9864, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0X9864, 0XA865, 0XB865, 0XD086, 0X8044, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0X6843, 0XD086, 0X9044, 0X9864, 0X9044, 0X9864, 0XB865,
0X9864, 0X9864, 0XB865, 0XA865, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086,
0XA865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XC066, 0X9864, 0XA865, 0X9864, 0X9044, 0XA865, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X98A5, 0X32C5, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X32C5, 0XC066, 0XD086, 0XD086, 0XD086, 0XB865, 0X9864,
0X8044, 0X9864, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086,
0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XA865, 0X9864, 0X9864, 0XA865,
0X9864, 0X9044, 0X9864, 0XD086, 0X6843, 0X9864, 0XC066, 0XA865, 0XD086,
0XD086, 0XB865, 0X8044, 0X7043, 0XB865, 0XD086, 0X9864, 0X9864, 0X9864,
0X9864, 0X9864, 0XA865, 0XB865, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086,
0XD086, 0XD086, 0X9044, 0XD086, 0XD086, 0XC066, 0XA865, 0XC066, 0X9864,
0X9864, 0X9044, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X80E5,
0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4285, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086,
0XB865, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086, 0X9044, 0X7043, 0XD086,
0X8044, 0X9044, 0XD086, 0XD086, 0X9044, 0X9864, 0X6843, 0XD086, 0XD086,
0X9864, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XB865, 0XA865,
0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X6985,
0X04A6, 0X4A25, 0X80A4, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086,
0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X9864, 0X8044, 0X9864, 0XC066,
0XD086, 0XD086, 0XC066, 0X6985, 0X0C66, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X4A25,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086,
0XD086, 0XD086, 0XA865, 0X9044, 0XB865, 0XA865, 0X9864, 0X9044, 0X9864,
0XB865, 0X9044, 0XC066, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086, 0XA865,
0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0X9864,
0XB865, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0X4A25, 0X0506, 0X0547, 0X0547, 0X1BC5, 0XA8C5, 0XD086, 0XD086, 0XB865,
0XB865, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864,
0XD086, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XB865, 0X32C5, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0506, 0X8145, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066,
0XA865, 0XD086, 0XD086, 0XB865, 0XB865, 0XD086, 0XB865, 0X8044, 0XB865,
0XA865, 0X8044, 0XA865, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X9864,
0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X8044, 0X7043,
0X7043, 0XC066, 0XD086, 0XC066, 0XA865, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0X6985, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0X2305,
0X32C5, 0X6944, 0XD086, 0XD086, 0XD086, 0X9864, 0XC066, 0XD086, 0XD086,
0X9864, 0XD086, 0XD086, 0X9864, 0XB865, 0XB865, 0XD086, 0XC066, 0XB865,
0XD086, 0X7145, 0X0C66, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0XB865, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XA865, 0XC066, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086,
0X9044, 0XB865, 0X9044, 0XD086, 0XD086, 0XD086, 0XC066, 0XA865, 0XD086,
0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XB865, 0XA865, 0XD086, 0XB865,
0XB865, 0XD086, 0XD086, 0XB865, 0X9864, 0X7043, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X2305, 0X0BA5, 0X0BA5, 0X7145,
0X9864, 0X90A4, 0X58E3, 0XD086, 0XB865, 0XB865, 0XD086, 0X9864, 0XD086,
0XD086, 0X1A63, 0XA8C5, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X32C5, 0XD086,
0XD086, 0XD086, 0XD086, 0XA865, 0X90A4, 0X4183, 0X6985, 0X5924, 0X9044,
0XD086, 0XB865, 0XB865, 0X9044, 0X9864, 0XD086, 0XD086, 0XD086, 0X9864,
0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0XD086, 0XA8C5, 0X1B65, 0X0405,
0X0405, 0X9044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X9864, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X4A25, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X1AC4, 0XD086, 0XD086,
0X9864, 0XD086, 0XD086, 0X4285, 0X04A6, 0X59E5, 0X9864, 0X4224, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0506, 0X98A5, 0XD086, 0XD086, 0X22C4, 0X0506, 0X0547, 0X0547, 0X0547,
0X2305, 0XD086, 0XA865, 0X8044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0X9864, 0XD086, 0XD086, 0X9044, 0XD086, 0XB865, 0X6985, 0X04A6,
0X0547, 0X0547, 0X0547, 0X90A4, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XA865, 0XC066, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XB865, 0X0BA5,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X22C4, 0XA865, 0X9044, 0X9864, 0XD086, 0X6985, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X4A25, 0XD086, 0X98A5, 0X0506, 0X0547, 0X0547,
0X0547, 0X0506, 0X4183, 0X9864, 0X9044, 0XB865, 0XD086, 0XD086, 0XD086,
0X9864, 0XD086, 0XD086, 0X9864, 0XD086, 0X7145, 0X0BA5, 0X0405, 0X04A6,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X32C5, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0X9044, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0X90A4, 0X4285, 0X04A6, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0405, 0XD086, 0XD086, 0X9864, 0XD086, 0X6985, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X1B65, 0XD086, 0X4A25, 0X0547,
0X0547, 0X0547, 0X0547, 0X4A25, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086,
0XD086, 0X8145, 0X0B64, 0XD086, 0XD086, 0XA865, 0X32C5, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X2305,
0X98A5, 0XC066, 0X9864, 0X9864, 0X9864, 0XC066, 0X9864, 0XA865, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X80E5, 0X59E5,
0X0C05, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0XC066, 0XD086, 0X9044, 0XD086,
0X6985, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X98A5,
0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X59E5, 0XD086, 0XB865, 0XB865,
0XD086, 0XD086, 0XA8C5, 0X0C66, 0X0506, 0X98A5, 0XD086, 0X90A4, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0506, 0X70E4, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066,
0X9864, 0X9864, 0X9864, 0X9044, 0X9864, 0XC066, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XC066, 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X68E4, 0X9044,
0X9864, 0XD086, 0X6985, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0445, 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X90A4, 0XA865,
0X9044, 0XD086, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547, 0X32C5, 0XD086,
0X4A25, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X7145, 0X9864, 0X9864,
0XA865, 0XA865, 0XD086, 0XD086, 0X9864, 0XD086, 0XD086, 0X9864, 0XD086,
0XD086, 0X90A4, 0X80E5, 0XC066, 0XD086, 0X7145, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X9864, 0XD086, 0X9864, 0XD086, 0X6985, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X80E5,
0XD086, 0XB865, 0XB865, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547, 0X0547,
0X0506, 0X9044, 0X04A6, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X4285, 0XB865, 0XA865, 0X9864, 0XC066, 0XD086, 0XA865,
0XC066, 0XD086, 0XC066, 0X0C05, 0X0547, 0X0445, 0X4285, 0X58E3, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X9864, 0XD086, 0X9864, 0XD086, 0X4285, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X9864, 0XD086, 0X9864, 0XD086, 0XA8C5, 0X0C66, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0405, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0405, 0X04A6, 0X2305, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X80E5, 0X9864, 0X9864, 0X9864,
0X8044, 0XB865, 0XD086, 0XD086, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X4285, 0XA865, 0X7043, 0XB865, 0XD086, 0X2305,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X2365, 0X9864, 0XB865, 0XB865, 0XA8C5, 0X0C66, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0506, 0X70A4, 0XA865, 0X8044, 0XD086, 0X7145, 0X0506, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0X3224, 0XD086, 0XD086,
0XC066, 0X9864, 0XC066, 0XD086, 0XD086, 0X4A25, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X1B65, 0X32C5, 0X68E4, 0X2365, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X9864, 0XD086, 0X9864, 0XD086,
0XC066, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X2305, 0X6985, 0X59E5, 0X22C4, 0X0445, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0C66, 0XA8C5, 0XA865, 0XA865, 0XD086, 0X2305,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0BA5, 0X0C05, 0X0C66, 0X9044, 0XD086, 0XD086, 0X8145,
0X04A6, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C05, 0XB865, 0XC066,
0X9864, 0X9044, 0XA865, 0XD086, 0XD086, 0XD086, 0X4A25, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X22C4, 0X70E4, 0XB865, 0X9864, 0XC066,
0X2365, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X5924, 0X9864,
0XA865, 0XD086, 0X9864, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X3224, 0X22C4, 0X9864, 0XA865, 0XC066, 0X6985,
0X0BA5, 0X0506, 0X0547, 0X0506, 0X32C5, 0XB865, 0XD086, 0XD086, 0XD086,
0X80E5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0C05, 0X4A25,
0X80E5, 0XD086, 0XB865, 0X4A25, 0X0BA5, 0X22C4, 0X6985, 0X90A4, 0X9864,
0X9864, 0X9864, 0X9044, 0XD086, 0XD086, 0XD086, 0XB865, 0X2305, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X04A6, 0X0547, 0X1B04,
0XC066, 0XD086, 0XC066, 0X4285, 0X0506, 0X0547, 0X0547, 0X0547, 0X4A25,
0XD086, 0XD086, 0XD086, 0XD086, 0X59E5, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X7043, 0XA865,
0XD086, 0XD086, 0XB865, 0X7043, 0X6843, 0X9864, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0X1B65, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X32C5, 0X3264, 0X6985,
0X59E5, 0X04A6, 0X0547, 0X4A25, 0XC066, 0X9864, 0XA865, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X6985, 0X04A6,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0C66, 0X59E5, 0X6883, 0X9864, 0X9864, 0XD086, 0X98A5, 0X4285, 0X32C5,
0X6944, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X2305, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X32C5, 0X6985, 0X6944,
0XC066, 0XC066, 0X9864, 0X9864, 0XB865, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XA865, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X80E5, 0X9864,
0X9864, 0XD086, 0XD086, 0XB865, 0X6985, 0X6985, 0X9044, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XA865, 0X59E5, 0X0C05,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0506, 0X6985, 0XA865, 0XA865, 0XD086, 0XD086, 0XD086, 0X9864, 0XB865,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X6985,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X3264, 0X7145,
0X6985, 0X9864, 0X9044, 0X9864, 0X9864, 0X9864, 0XA865, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X90A4, 0X6985, 0X4285,
0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0445,
0X2305, 0X04A6, 0X90A4, 0XC066, 0X9864, 0X9044, 0X9864, 0X9864, 0X9864,
0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0X58E3, 0X3264,
0X1B65, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X4224, 0X4224, 0X3264, 0X7043, 0X4A25, 0X32C5, 0X49C4,
0X9864, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0X7145, 0X1B65, 0X0506, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X04A6, 0X0547, 0X0547, 0X04A6, 0X80E5, 0XD086, 0XD086, 0XD086, 0XD086,
0XD086, 0XD086, 0XD086, 0XD086, 0XC066, 0X7145, 0X49C4, 0XB865, 0XD086,
0XD086, 0XD086, 0X9044, 0X9864, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0X5883, 0XA865, 0XD086, 0XD086,
0XC066, 0X9864, 0X7145, 0X6985, 0X3264, 0X80E5, 0X7145, 0X32C5, 0X70E4,
0XD086, 0XD086, 0XD086, 0X68E4, 0X4285, 0X04A6, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0405, 0X0547, 0X0547, 0X0547, 0X0506,
0X6985, 0X9864, 0XD086, 0XD086, 0XA865, 0X9864, 0XD086, 0XD086, 0XD086,
0XB865, 0X80E5, 0X80A4, 0XC066, 0XD086, 0XD086, 0X58E3, 0X32C5, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0C66, 0X90A4, 0XA865, 0XA865, 0XD086,
0XD086, 0XD086, 0X6985, 0X0BA5, 0X0405, 0X22C4, 0X0C05, 0X0547, 0X0547,
0X0C66, 0X7145, 0XC066, 0XD086, 0X70A4, 0X4285, 0X58E3, 0X0506, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X59E5, 0XA865, 0X9044,
0X9864, 0X4A25, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X1B65, 0X98A5, 0XD086, 0X9044, 0X7145, 0X8044, 0X04A6,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X1BC5, 0X7145, 0X9864, 0XD086, 0X98A5, 0X2305, 0X0506, 0X0506, 0X32C5,
0X6985, 0X32C5, 0X04A6, 0X0547, 0X0547, 0X0C05, 0X5984, 0XA865, 0X9864,
0X9864, 0X32C5, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X49C4, 0X59E5, 0X22C4,
0X70E4, 0X9864, 0X7145, 0X1B65, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0445, 0X0405, 0X0506, 0X0547, 0X0506,
0X0506, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X2264,
0X0506, 0X0506, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0506, 0X0405, 0X0445, 0X0547,
0X0C66, 0X0445, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0506, 0X90A4, 0X80E5, 0X4224, 0X3224, 0X0506, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0405, 0X0547, 0X0506, 0X1A03, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0B64,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X04A6, 0X1BC5, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547, 0X0547,
0X0547, 0X0547, 0X0547, 0X0547, 0X0547 };

View File

@ -0,0 +1,69 @@
// ILI9341 example with embedded color bitmaps in sketch.
// WILL NOT FIT ON ARDUINO UNO OR OTHER AVR BOARDS;
// uses large bitmap image stored in array!
// Options for converting images to the format used here include:
// http://www.rinkydinkelectronics.com/t_imageconverter565.php
// or
// GIMP (https://www.gimp.org/) as follows:
// 1. File -> Export As
// 2. In Export Image dialog, use 'C source code (*.c)' as filetype.
// 3. Press export to get the export options dialog.
// 4. Type the desired variable name into the 'prefixed name' box.
// 5. Uncheck 'GLIB types (guint8*)'
// 6. Check 'Save as RGB565 (16-bit)'
// 7. Press export to save your image.
// Assuming 'image_name' was typed in the 'prefixed name' box of step 4,
// you can have to include the c file, then using the image can be done with:
// tft.drawRGBBitmap(0, 0, image_name.pixel_data, image_name.width, image_name.height);
// See also https://forum.pjrc.com/threads/35575-Export-for-ILI9341_t3-with-GIMP
#include "SPI.h"
#include <Adafruit_ILI9341.h>
#include "dragon.h"
// For the Adafruit shield, these are the default.
//#define TFT_DC 9
//#define TFT_CS 10
// Feather 32u4 or M0 with TFT FeatherWing:
#define TFT_DC 10
#define TFT_CS 9
// ESP8266:
//#define TFT_DC 15
//#define TFT_CS 0
// Other boards (including Feather boards) may have other pinouts;
// see learn.adafruit.com/adafruit-2-4-tft-touch-screen-featherwing/pinouts
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
void setup() {
tft.begin();
}
void loop(void) {
for(uint8_t r=0; r<4; r++) {
tft.setRotation(r);
tft.fillScreen(ILI9341_BLACK);
for(uint8_t j=0; j<20; j++) {
tft.drawRGBBitmap(
random(-DRAGON_WIDTH , tft.width()),
random(-DRAGON_HEIGHT, tft.height()),
#if defined(__AVR__) || defined(ESP8266)
dragonBitmap,
#else
// Some non-AVR MCU's have a "flat" memory model and don't
// distinguish between flash and RAM addresses. In this case,
// the RAM-resident-optimized drawRGBBitmap in the ILI9341
// library can be invoked by forcibly type-converting the
// PROGMEM bitmap pointer to a non-const uint16_t *.
(uint16_t *)dragonBitmap,
#endif
DRAGON_WIDTH, DRAGON_HEIGHT);
delay(1); // Allow ESP8266 to handle watchdog & WiFi stuff
}
delay(3000);
}
}

View File

@ -0,0 +1,218 @@
/***************************************************
This is our Bitmap drawing example for the Adafruit ILI9341 Breakout and Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_GFX.h> // Core graphics library
#include "Adafruit_ILI9341.h" // Hardware-specific library
#include <SPI.h>
#include <SD.h>
// TFT display and SD card will share the hardware SPI interface.
// Hardware SPI pins are specific to the Arduino board type and
// cannot be remapped to alternate pins. For Arduino Uno,
// Duemilanove, etc., pin 11 = MOSI, pin 12 = MISO, pin 13 = SCK.
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define SD_CS 4
void setup(void) {
Serial.begin(9600);
tft.begin();
yield();
Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("failed!");
}
Serial.println("OK!");
}
void loop() {
for(uint8_t r=0; r<4; r++) {
tft.setRotation(r);
tft.fillScreen(ILI9341_BLUE);
for(int8_t i=-2; i<1; i++) {
bmpDraw("purple.bmp",
(tft.width() / 2) + (i * 120),
(tft.height() / 2) + (i * 160));
}
}
}
// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates. It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel). Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster. 20 pixels seems a
// good balance.
#define BUFFPIXEL 20
void bmpDraw(char *filename, int16_t x, int16_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel buffer (R+G+B per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col, x2, y2, bx1, by1;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print(F("Loading image '"));
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print(F("File not found"));
return;
}
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
Serial.print(F("Image size: "));
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
x2 = x + bmpWidth - 1; // Lower-right corner
y2 = y + bmpHeight - 1;
if((x2 >= 0) && (y2 >= 0)) { // On screen?
w = bmpWidth; // Width/height of section to load/display
h = bmpHeight;
bx1 = by1 = 0; // UL coordinate in BMP file
if(x < 0) { // Clip left
bx1 = -x;
x = 0;
w = x2 + 1;
}
if(y < 0) { // Clip top
by1 = -y;
y = 0;
h = y2 + 1;
}
if(x2 >= tft.width()) w = tft.width() - x; // Clip right
if(y2 >= tft.height()) h = tft.height() - y; // Clip bottom
// Set TFT address window to clipped image bounds
tft.startWrite(); // Requires start/end transaction now
tft.setAddrWindow(x, y, w, h);
for (row=0; row<h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - (row + by1)) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + (row + by1) * rowSize;
pos += bx1 * 3; // Factor in starting column (bx1)
if(bmpFile.position() != pos) { // Need seek?
tft.endWrite(); // End TFT transaction
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
tft.startWrite(); // Start new TFT transaction
}
for (col=0; col<w; col++) { // For each pixel...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
tft.endWrite(); // End TFT transaction
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
tft.startWrite(); // Start new TFT transaction
}
// Convert pixel from BMP to TFT format, push to display
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft.writePixel(tft.color565(r,g,b));
} // end pixel
} // end scanline
tft.endWrite(); // End last TFT transaction
} // end onscreen
Serial.print(F("Loaded in "));
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println(F("BMP format not recognized."));
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File &f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File &f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}

View File

@ -0,0 +1,146 @@
/***************************************************
This is our touchscreen painting example for the Adafruit ILI9341 Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h>
#include <Wire.h> // this is needed even tho we aren't using it
#include <Adafruit_ILI9341.h>
#include <Adafruit_STMPE610.h>
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 130
#define TS_MAXX 3800
#define TS_MAXY 4000
// The STMPE610 uses hardware SPI on the shield, and #8
#define STMPE_CS 8
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
// The display also uses hardware SPI, plus #9 & #10
#define TFT_CS 10
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;
void setup(void) {
// while (!Serial); // used for leonardo debugging
Serial.begin(9600);
Serial.println(F("Touch Paint!"));
tft.begin();
if (!ts.begin()) {
Serial.println("Couldn't start touchscreen controller");
while (1);
}
Serial.println("Touchscreen started");
tft.fillScreen(ILI9341_BLACK);
// make the color selection boxes
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
// select the current color 'red'
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
currentcolor = ILI9341_RED;
}
void loop()
{
// See if there's any touch data for us
if (ts.bufferEmpty()) {
return;
}
/*
// You can also wait for a touch
if (! ts.touched()) {
return;
}
*/
// Retrieve a point
TS_Point p = ts.getPoint();
/*
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
*/
// Scale from ~0->4000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
/*
Serial.print("("); Serial.print(p.x);
Serial.print(", "); Serial.print(p.y);
Serial.println(")");
*/
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = ILI9341_RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = ILI9341_YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = ILI9341_GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = ILI9341_CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = ILI9341_BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*6) {
currentcolor = ILI9341_MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == ILI9341_RED)
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
if (oldcolor == ILI9341_YELLOW)
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
if (oldcolor == ILI9341_GREEN)
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
if (oldcolor == ILI9341_CYAN)
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
if (oldcolor == ILI9341_BLUE)
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
if (oldcolor == ILI9341_MAGENTA)
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
}
}
if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}

View File

@ -0,0 +1,156 @@
/***************************************************
This is our touchscreen painting example for the Adafruit TFT FeatherWing
----> http://www.adafruit.com/products/3315
Check out the links above for our tutorials and wiring diagrams
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/
#include <SPI.h>
#include <Wire.h> // this is needed even tho we aren't using it
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ILI9341.h> // Hardware-specific library
#include <Adafruit_STMPE610.h>
#ifdef ESP8266
#define STMPE_CS 16
#define TFT_CS 0
#define TFT_DC 15
#define SD_CS 2
#endif
#ifdef ESP32
#define STMPE_CS 32
#define TFT_CS 15
#define TFT_DC 33
#define SD_CS 14
#endif
#if defined (__AVR_ATmega32U4__) || defined(ARDUINO_SAMD_FEATHER_M0) || defined (__AVR_ATmega328P__)
#define STMPE_CS 6
#define TFT_CS 9
#define TFT_DC 10
#define SD_CS 5
#endif
#ifdef TEENSYDUINO
#define TFT_DC 10
#define TFT_CS 4
#define STMPE_CS 3
#define SD_CS 8
#endif
#ifdef ARDUINO_STM32_FEATHER
#define TFT_DC PB4
#define TFT_CS PA15
#define STMPE_CS PC7
#define SD_CS PC5
#endif
#ifdef ARDUINO_NRF52_FEATHER /* BSP 0.6.5 and higher! */
#define TFT_DC 11
#define TFT_CS 31
#define STMPE_CS 30
#define SD_CS 27
#endif
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 3800
#define TS_MAXX 100
#define TS_MINY 100
#define TS_MAXY 3750
// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;
void setup(void) {
Serial.begin(115200);
delay(10);
Serial.println("FeatherWing TFT");
if (!ts.begin()) {
Serial.println("Couldn't start touchscreen controller");
while (1);
}
Serial.println("Touchscreen started");
tft.begin();
tft.fillScreen(ILI9341_BLACK);
// make the color selection boxes
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
// select the current color 'red'
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
currentcolor = ILI9341_RED;
}
void loop() {
// Retrieve a point
TS_Point p = ts.getPoint();
Serial.print("X = "); Serial.print(p.x);
Serial.print("\tY = "); Serial.print(p.y);
Serial.print("\tPressure = "); Serial.println(p.z);
// Scale from ~0->4000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = ILI9341_RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = ILI9341_YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = ILI9341_GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = ILI9341_CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = ILI9341_BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*6) {
currentcolor = ILI9341_MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == ILI9341_RED)
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
if (oldcolor == ILI9341_YELLOW)
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
if (oldcolor == ILI9341_GREEN)
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
if (oldcolor == ILI9341_CYAN)
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
if (oldcolor == ILI9341_BLUE)
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
if (oldcolor == ILI9341_MAGENTA)
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
}
}
if (((p.y-PENRADIUS) > 0) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}

View File

@ -0,0 +1,9 @@
name=Adafruit ILI9341
version=1.0.11
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Library for Adafruit ILI9341 displays
paragraph=Library for Adafruit ILI9341 displays
category=Display
url=https://github.com/adafruit/Adafruit_ILI9341
architectures=*

View File

@ -1,41 +0,0 @@
#######################################
# Syntax Coloring Map for TasmotaTFT
# (esp8266)
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
TasmotaTFT KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
setScrollStart KEYWORD2
setScrollMargins KEYWORD2
setAddrWindow KEYWORD2
pushColor KEYWORD2
fillScreen KEYWORD2
drawPixel KEYWORD2
drawFastVLine KEYWORD2
drawFastHLine KEYWORD2
fillRect KEYWORD2
setRotation KEYWORD2
invertDisplay KEYWORD2
showDisplay KEYWORD2
color565 KEYWORD2
readdata KEYWORD2
readcommand8 KEYWORD2
spiwrite KEYWORD2
writecommand KEYWORD2
writedata KEYWORD2
commandList KEYWORD2
spiread KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -1,15 +0,0 @@
{
"name": "TasmotaTFT",
"version": "1.0.1",
"keywords": [
"spi", "io", "tft", "TasmotaTFT"
],
"description": "Library for ILI9341, ILI9481 and ILI9486 displays",
"repository":
{
"type": "git",
"url": "https://github.com/arendst/Sonoff-Tasmota/lib/TasmotaTFT"
},
"frameworks": "arduino",
"platforms": "espressif8266"
}

View File

@ -1,9 +0,0 @@
name=TasmotaTFT
version=1.0.1
author=Theo Arends
maintainer=Theo Arends <theo@arends.com>
sentence=Library for ILI9341, ILI9481 and ILI9486 displays
paragraph=
category=Display
url=
architectures=esp8266

View File

@ -1,616 +0,0 @@
/*
TasmotaTFT.cpp - Adapted implementation of Adafruit ILI9341 for Tasmota
Copyright (C) 2018 Adafruit and Theo Arends
This library 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/>.
*/
/*********************************************************************************************\
* See original Adafruit ILI9341 license text below
*
* Based in Adafruit_ILI9341 v1.0.11
* This is a library for the ILI9341, ILI9481 and ILI9486 TFT LCD using hardware SPI only
*
* These displays use hardware SPI to communicate, 4 or 5 pins are required to interface (RST is optional)
\*********************************************************************************************/
#include "TasmotaTFT.h"
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>
static inline void spi_begin(void) __attribute__((always_inline));
static inline void spi_begin(void) {
SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
}
static inline void spi_end(void) __attribute__((always_inline));
static inline void spi_end(void) {
SPI.endTransaction();
}
struct _sSize
{
int16_t width;
int16_t height;
};
_sSize _size[TFT_MAX] = {
{240, 320}, // ILI9340 / ILI9341
{320, 480}, // ILI9481 / HX8357B
{320, 480} // ILI9486
};
TasmotaTFT::TasmotaTFT(int8_t m, int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(_size[m].width, _size[m].height) {
_mod = m;
_w = _size[m].width;
_h = _size[m].height;
_cs = cs;
_dc = dc;
_rst = rst;
_mosi = _sclk = 0;
}
void TasmotaTFT::writecommand(uint8_t c)
{
digitalWrite(_dc, LOW);
digitalWrite(_sclk, LOW);
digitalWrite(_cs, LOW);
SPI.transfer(c);
digitalWrite(_cs, HIGH);
}
void TasmotaTFT::writedata(uint8_t c)
{
digitalWrite(_dc, HIGH);
digitalWrite(_cs, LOW);
SPI.transfer(c);
digitalWrite(_cs, HIGH);
}
void TasmotaTFT::begin(void)
{
pinMode(_dc, OUTPUT);
digitalWrite(_dc, LOW);
pinMode(_cs, OUTPUT);
digitalWrite(_cs, HIGH);
SPI.begin();
// toggle RST low to reset
if (_rst > 0) {
pinMode(_rst, OUTPUT);
digitalWrite(_rst, HIGH);
delay(100);
digitalWrite(_rst, LOW);
delay(100);
digitalWrite(_rst, HIGH);
delay(200);
}
spi_begin();
if (_mod == ILI9341) { // 320 x 240
writecommand(0xEF); // Display Supplier dependant
writedata(0x03);
writedata(0x80);
writedata(0x02);
writecommand(0xCF); // Display Supplier dependant
writedata(0x00);
writedata(0XC1);
writedata(0X30);
writecommand(0xED); // Display Supplier dependant
writedata(0x64);
writedata(0x03);
writedata(0X12);
writedata(0X81);
writecommand(0xE8); // Display Supplier dependant
writedata(0x85);
writedata(0x00);
writedata(0x78);
writecommand(0xCB); // Display Supplier dependant
writedata(0x39);
writedata(0x2C);
writedata(0x00);
writedata(0x34);
writedata(0x02);
writecommand(0xF7); // Display Supplier dependant
writedata(0x20);
writecommand(0xEA); // Display Supplier dependant
writedata(0x00);
writedata(0x00);
writecommand(0xC0); // Power control 1
writedata(0x23); // VRH[5:0]
writecommand(0xC1); // Power control 2
writedata(0x10); // SAP[2:0];BT[3:0]
writecommand(0xC5); // VCM control 1
writedata(0x3e); // Contrast
writedata(0x28);
writecommand(0xC7); // VCM control 2
writedata(0x86); // --
writecommand(0x36); // Memory Access Control
writedata(0x48);
writecommand(0x3A); // Pixel Format
writedata(0x55);
writecommand(0xB1); // Frame Control in Normal Mode
writedata(0x00);
writedata(0x18);
writecommand(0xB6); // Display Function Control
writedata(0x08);
writedata(0x82);
writedata(0x27);
writecommand(0xF2); // 3Gamma Function Disable
writedata(0x00);
writecommand(0x26); // Gamma curve selected
writedata(0x01);
writecommand(0xE0); // Positive Gamma
writedata(0x0F);
writedata(0x31);
writedata(0x2B);
writedata(0x0C);
writedata(0x0E);
writedata(0x08);
writedata(0x4E);
writedata(0xF1);
writedata(0x37);
writedata(0x07);
writedata(0x10);
writedata(0x03);
writedata(0x0E);
writedata(0x09);
writedata(0x00);
writecommand(0xE1); // Negative Gamma
writedata(0x00);
writedata(0x0E);
writedata(0x14);
writedata(0x03);
writedata(0x11);
writedata(0x07);
writedata(0x31);
writedata(0xC1);
writedata(0x48);
writedata(0x08);
writedata(0x0F);
writedata(0x0C);
writedata(0x31);
writedata(0x36);
writedata(0x0F);
writecommand(0x11); // Exit Sleep
spi_end();
delay(120);
spi_begin();
writecommand(0x29); // Display on
}
else if (_mod == ILI9481) { // 480 x 320
writecommand(0x11); // Exit Sleep
spi_end();
delay(20);
spi_begin();
writecommand(0xD0); // Power Setting
writedata(0x07);
writedata(0x42);
writedata(0x18);
writecommand(0xD1); // VCOM Control
writedata(0x00);
writedata(0x07);
writedata(0x10);
writecommand(0xD2); // Power Setting for Normal Mode
writedata(0x01);
writedata(0x02);
writecommand(0xC0); // Panel Driving Setting
writedata(0x10);
writedata(0x3B);
writedata(0x00);
writedata(0x02);
writedata(0x11);
writecommand(0xC5); // Frame Rate and Inversion Control
writedata(0x08); // 0x03
writecommand(0xC8); // Gamma Setting
writedata(0x00);
writedata(0x32);
writedata(0x36);
writedata(0x45);
writedata(0x06);
writedata(0x16);
writedata(0x37);
writedata(0x75);
writedata(0x77);
writedata(0x54);
writedata(0x0C);
writedata(0x00);
writecommand(0x36); // Address Mode
writedata(0x0A);
writecommand(0x3A); // Pixel Format
writedata(0x55);
writecommand(0x2A); // Column Address
writedata(0x00);
writedata(0x00);
writedata(0x01);
writedata(0x3F);
writecommand(0x2B); // Page Address
writedata(0x00);
writedata(0x00);
writedata(0x01);
writedata(0xDF); // 0xE0
spi_end();
delay(120);
spi_begin();
writecommand(0x29); // Display on
}
else if (_mod == ILI9486) { // 480 x 320
writecommand(0x01); // Soft reset
// writedata(0x00);
spi_end();
delay(50);
spi_begin();
writecommand(0x28); // Display off
// writedata(0x00);
writecommand(0xC0); // Power Control 1
writedata(0x0d);
writedata(0x0d);
writecommand(0xC1); // Power Control 2
writedata(0x43);
writedata(0x00);
writecommand(0xC2); // Power Control 3
writedata(0x00);
writecommand(0xC5); // VCOM Control
writedata(0x00);
writedata(0x48);
writecommand(0xB6); // Display Function Control
writedata(0x00);
writedata(0x22); // 0x42 = Rotate display 180 deg.
writedata(0x3B);
writecommand(0xE0); // PGAMCTRL (Positive Gamma Control)
writedata(0x0f);
writedata(0x24);
writedata(0x1c);
writedata(0x0a);
writedata(0x0f);
writedata(0x08);
writedata(0x43);
writedata(0x88);
writedata(0x32);
writedata(0x0f);
writedata(0x10);
writedata(0x06);
writedata(0x0f);
writedata(0x07);
writedata(0x00);
writecommand(0xE1); // NGAMCTRL (Negative Gamma Control)
writedata(0x0F);
writedata(0x38);
writedata(0x30);
writedata(0x09);
writedata(0x0f);
writedata(0x0f);
writedata(0x4e);
writedata(0x77);
writedata(0x3c);
writedata(0x07);
writedata(0x10);
writedata(0x05);
writedata(0x23);
writedata(0x1b);
writedata(0x00);
writecommand(0x20); // Display Inversion OFF, 0x21 = ON
writecommand(0x36); // Memory Access Control
writedata(0x0A);
writecommand(0x3A); // Interface Pixel Format
writedata(0x55);
writecommand(0x11); // Exit Sleep
spi_end();
delay(150);
spi_begin();
writecommand(0x29); // Display on
}
spi_end();
}
void TasmotaTFT::setScrollStart(uint16_t start)
{
spi_begin();
writecommand(0x37);
writedata(start>>8);
writedata(start);
spi_end();
}
void TasmotaTFT::setScrollMargins(uint16_t top, uint16_t bottom)
{
uint16_t height = _height - (top + bottom);
spi_begin();
writecommand(0x33);
writedata(top>>8);
writedata(top);
writedata(height>>8);
writedata(height);
writedata(bottom>>8);
writedata(bottom);
spi_end();
}
void TasmotaTFT::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
writecommand(TFT_CASET); // Column addr set
writedata(x0 >> 8);
writedata(x0 & 0xFF); // XSTART
writedata(x1 >> 8);
writedata(x1 & 0xFF); // XEND
writecommand(TFT_PASET); // Row addr set
writedata(y0>>8);
writedata(y0); // YSTART
writedata(y1>>8);
writedata(y1); // YEND
writecommand(TFT_RAMWR); // write to RAM
}
void TasmotaTFT::pushColor(uint16_t color)
{
spi_begin();
digitalWrite(_dc, HIGH);
digitalWrite(_cs, LOW);
SPI.transfer(color >> 8);
SPI.transfer(color);
digitalWrite(_cs, HIGH);
spi_end();
}
void TasmotaTFT::drawPixel(int16_t x, int16_t y, uint16_t color)
{
if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
spi_begin();
setAddrWindow(x,y,x+1,y+1);
digitalWrite(_dc, HIGH);
digitalWrite(_cs, LOW);
SPI.transfer(color >> 8);
SPI.transfer(color);
digitalWrite(_cs, HIGH);
spi_end();
}
void TasmotaTFT::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
{
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((y+h-1) >= _height) h = _height-y;
spi_begin();
setAddrWindow(x, y, x, y+h-1);
uint8_t hi = color >> 8, lo = color;
digitalWrite(_dc, HIGH);
digitalWrite(_cs, LOW);
while (h--) {
SPI.transfer(hi);
SPI.transfer(lo);
}
digitalWrite(_cs, HIGH);
spi_end();
}
void TasmotaTFT::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
{
// Rudimentary clipping
if((x >= _width) || (y >= _height)) return;
if((x+w-1) >= _width) w = _width-x;
spi_begin();
setAddrWindow(x, y, x+w-1, y);
uint8_t hi = color >> 8, lo = color;
digitalWrite(_dc, HIGH);
digitalWrite(_cs, LOW);
while (w--) {
SPI.transfer(hi);
SPI.transfer(lo);
}
digitalWrite(_cs, HIGH);
spi_end();
}
void TasmotaTFT::fillScreen(uint16_t color)
{
fillRect(0, 0, _width, _height, color);
}
// fill a rectangle
void TasmotaTFT::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
{
// rudimentary clipping (drawChar w/big text requires this)
if((x >= _width) || (y >= _height)) return;
if((x + w - 1) >= _width) w = _width - x;
if((y + h - 1) >= _height) h = _height - y;
spi_begin();
setAddrWindow(x, y, x+w-1, y+h-1);
uint8_t hi = color >> 8, lo = color;
digitalWrite(_dc, HIGH);
digitalWrite(_cs, LOW);
for(y=h; y>0; y--) {
for(x=w; x>0; x--) {
SPI.transfer(hi);
SPI.transfer(lo);
}
}
digitalWrite(_cs, HIGH);
spi_end();
}
// Pass 8-bit (each) R,G,B, get back 16-bit packed color
uint16_t TasmotaTFT::color565(uint8_t r, uint8_t g, uint8_t b)
{
return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
#define MADCTL_MY 0x80
#define MADCTL_MX 0x40
#define MADCTL_MV 0x20
#define MADCTL_ML 0x10
#define MADCTL_RGB 0x00
#define MADCTL_BGR 0x08
#define MADCTL_MH 0x04
void TasmotaTFT::setRotation(uint8_t m)
{
rotation = m % 4; // can't be higher than 3
switch (rotation) {
case 0:
m = (MADCTL_MX | MADCTL_BGR);
_width = _w;
_height = _h;
break;
case 1:
m = (MADCTL_MV | MADCTL_BGR);
_width = _h;
_height = _w;
break;
case 2:
m = (MADCTL_MY | MADCTL_BGR);
_width = _w;
_height = _h;
break;
case 3:
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
_width = _h;
_height = _w;
break;
}
spi_begin();
writecommand(TFT_MADCTL);
writedata(m);
spi_end();
}
void TasmotaTFT::invertDisplay(boolean i)
{
spi_begin();
writecommand(i ? TFT_INVON : TFT_INVOFF);
spi_end();
}
void TasmotaTFT::showDisplay(boolean i)
{
spi_begin();
writecommand(i ? TFT_DISPON : TFT_DISPOFF);
spi_end();
}
uint8_t TasmotaTFT::readdata(void)
{
digitalWrite(_dc, HIGH);
digitalWrite(_cs, LOW);
uint8_t r = SPI.transfer(0x00);
digitalWrite(_cs, HIGH);
return r;
}
uint8_t TasmotaTFT::readcommand8(uint8_t c, uint8_t index)
{
spi_begin();
digitalWrite(_dc, LOW); // command
digitalWrite(_cs, LOW);
SPI.transfer(0xD9); // woo sekret command?
digitalWrite(_dc, HIGH); // data
SPI.transfer(0x10 + index);
digitalWrite(_cs, HIGH);
digitalWrite(_dc, LOW); // command
digitalWrite(_sclk, LOW);
digitalWrite(_cs, LOW);
SPI.transfer(c);
digitalWrite(_dc, HIGH); // data
uint8_t r = SPI.transfer(0x00);
digitalWrite(_cs, HIGH);
spi_end();
return r;
}
/***************************************************
This is our library for the Adafruit ILI9341 Breakout and Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/

View File

@ -1,137 +0,0 @@
/*
TasmotaTFT.cpp - Adapted implementation of Adafruit ILI9341 for Tasmota
Copyright (C) 2018 Adafruit and Theo Arends
This library 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/>.
*/
#ifndef _TasmotaTFT_h
#define _TasmotaTFT_h
/*********************************************************************************************\
* See original Adafruit ILI9341 license text below
*
* This is a library for the ILI9341, ILI9481 and ILI9486 TFT LCD
*
* These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional)
\*********************************************************************************************/
#include "Arduino.h"
#include "Print.h"
#include <Adafruit_GFX.h>
// Supported TFT LCD drivers
#define ILI9340 0 // 320 x 240
#define ILI9341 0 // 320 x 240
#define ILI9481 1 // 480 x 320
#define HX8357B 1 // 480 x 320
#define ILI9486 2 // 480 x 320
#define TFT_MAX 3
// Common driver registers
#define TFT_RDMODE 0x0A // Get Power Mode
#define TFT_RDMADCTL 0x0B // Get Address Mode
#define TFT_RDPIXFMT 0x0C // Get Pixel Format
#define TFT_RDIMGFMT 0x0D // Get Display Mode
#define TFT_RDSELFDIAG 0x0F // Get Diagnostic Result
#define TFT_INVOFF 0x20 // Exit Invert Mode
#define TFT_INVON 0x21 // Enter Invert Mode
#define TFT_DISPOFF 0x28 // Set Display Off
#define TFT_DISPON 0x29 // Set Display on
#define TFT_CASET 0x2A // Set Column Address
#define TFT_PASET 0x2B // Set Page Address
#define TFT_RAMWR 0x2C // Write Memory Start
#define TFT_MADCTL 0x36 // Set Address Mode
// Color definitions
#define TFT_BLACK 0x0000 /* 0, 0, 0 */
#define TFT_NAVY 0x000F /* 0, 0, 128 */
#define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */
#define TFT_MAROON 0x7800 /* 128, 0, 0 */
#define TFT_PURPLE 0x780F /* 128, 0, 128 */
#define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */
#define TFT_LIGHTGREY 0xC618 /* 192, 192, 192 */
#define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */
#define TFT_BLUE 0x001F /* 0, 0, 255 */
#define TFT_GREEN 0x07E0 /* 0, 255, 0 */
#define TFT_CYAN 0x07FF /* 0, 255, 255 */
#define TFT_RED 0xF800 /* 255, 0, 0 */
#define TFT_MAGENTA 0xF81F /* 255, 0, 255 */
#define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */
#define TFT_WHITE 0xFFFF /* 255, 255, 255 */
#define TFT_ORANGE 0xFD20 /* 255, 165, 0 */
#define TFT_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
#define TFT_PINK 0xF81F
class TasmotaTFT : public Adafruit_GFX {
public:
TasmotaTFT(int8_t _MODEL, int8_t _CS, int8_t _DC, int8_t _RST = -1);
void begin(void);
void setScrollStart(uint16_t start);
void setScrollMargins(uint16_t top, uint16_t bottom);
void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
void pushColor(uint16_t color);
void fillScreen(uint16_t color);
void drawPixel(int16_t x, int16_t y, uint16_t color);
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
void setRotation(uint8_t r);
void invertDisplay(boolean i);
void showDisplay(boolean i);
uint16_t color565(uint8_t r, uint8_t g, uint8_t b);
/* These are not for current use, 8-bit protocol only! */
uint8_t readdata(void);
uint8_t readcommand8(uint8_t reg, uint8_t index = 0);
void spiwrite(uint8_t);
void writecommand(uint8_t c);
void writedata(uint8_t d);
void commandList(uint8_t *addr);
uint8_t spiread(void);
private:
uint8_t tabcolor;
uint8_t _mod;
int16_t _w;
int16_t _h;
int32_t _cs;
int32_t _dc;
int32_t _rst;
int32_t _mosi;
int32_t _miso;
int32_t _sclk;
};
#endif // _TasmotaTFT_h
/***************************************************
This is our library for the Adafruit ILI9341 Breakout and Shield
----> http://www.adafruit.com/products/1651
Check out the links above for our tutorials and wiring diagrams
These displays use SPI to communicate, 4 or 5 pins are required to
interface (RST is optional)
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
Written by Limor Fried/Ladyada for Adafruit Industries.
MIT license, all text above must be included in any redistribution
****************************************************/

View File

@ -1,4 +1,7 @@
/* 6.1.1.6 /* 6.1.1.7
* Add initial display support for Lcd, Oled, Matrix, Tft and e-paper - Need more docs
*
* 6.1.1.6
* Add modulo option to rules like rule1 on Time#Minute|5 do backlog power on;delay 200;power off endon (#3466) * Add modulo option to rules like rule1 on Time#Minute|5 do backlog power on;delay 200;power off endon (#3466)
* *
* 6.1.1.5 * 6.1.1.5

View File

@ -377,18 +377,6 @@
#define D_CMND_LATITUDE "Latitude" #define D_CMND_LATITUDE "Latitude"
#define D_CMND_LONGITUDE "Longitude" #define D_CMND_LONGITUDE "Longitude"
// Commands xdrv_98_display.ino
#define D_CMND_DISPLAY "Display"
#define D_CMND_DISP_ADDRESS "Address"
#define D_CMND_DISP_COLS "Cols"
#define D_CMND_DISP_DIMMER "Dimmer"
#define D_CMND_DISP_MODE "Mode"
#define D_CMND_DISP_MODEL "Model"
#define D_CMND_DISP_REFRESH "Refresh"
#define D_CMND_DISP_ROWS "Rows"
#define D_CMND_DISP_SIZE "Size"
#define D_CMND_DISP_TEXT "Text"
/********************************************************************************************/ /********************************************************************************************/
#define D_ASTERIX "********" #define D_ASTERIX "********"

View File

@ -196,9 +196,7 @@ enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_R
enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX}; enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};
enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART, enum XsnsFunctions {FUNC_PRE_INIT, FUNC_INIT, FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_SECOND, FUNC_PREP_BEFORE_TELEPERIOD, FUNC_JSON_APPEND, FUNC_WEB_APPEND, FUNC_SAVE_BEFORE_RESTART,
FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, FUNC_RULES_PROCESS, FUNC_FREE_MEM, FUNC_COMMAND, FUNC_MQTT_SUBSCRIBE, FUNC_MQTT_INIT, FUNC_MQTT_DATA, FUNC_SET_POWER, FUNC_SHOW_SENSOR, FUNC_RULES_PROCESS, FUNC_FREE_MEM};
FUNC_DISPLAY_POWER, FUNC_DISPLAY_CLEAR, FUNC_DISPLAY_INIT_PARTIAL, FUNC_DISPLAY_INIT_FULL, FUNC_DISPLAY_DRAW_HLINE, FUNC_DISPLAY_DRAW_VLINE, FUNC_DISPLAY_DRAW_CIRCLE,
FUNC_DISPLAY_FILL_CIRCLE, FUNC_DISPLAY_DRAW_RECTANGLE, FUNC_DISPLAY_FILL_RECTANGLE, FUNC_DISPLAY_DRAW_FRAME, FUNC_DISPLAY_FONT_SIZE, FUNC_DISPLAY_DRAW_STRING, FUNC_DISPLAY_ONOFF };
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };

View File

@ -20,7 +20,7 @@
#ifndef _SONOFF_VERSION_H_ #ifndef _SONOFF_VERSION_H_
#define _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_
#define VERSION 0x06010106 #define VERSION 0x06010107
#define D_PROGRAMNAME "Sonoff-Tasmota" #define D_PROGRAMNAME "Sonoff-Tasmota"
#define D_AUTHOR "Theo Arends" #define D_AUTHOR "Theo Arends"

View File

@ -271,6 +271,7 @@
// -- I2C sensors --------------------------------- // -- I2C sensors ---------------------------------
#define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram)
#ifdef USE_I2C #ifdef USE_I2C
#define USE_SHT // Enable SHT1X sensor (+1k4 code) #define USE_SHT // Enable SHT1X sensor (+1k4 code)
#define USE_HTU // Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code) #define USE_HTU // Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code)
@ -295,11 +296,31 @@
// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) // #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code)
// #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) // #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code)
// #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code) // #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code)
// #define USE_DISPLAY // Add I2C Display Support for LCD, Oled and up to eigth Matrices (+19k code)
#define USE_DISPLAY_LCD // Enable Lcd display (I2C addresses 0x27 and 0x3F)
#define USE_DISPLAY_SSD1306 // Enable Oled 128x64 display (I2C addresses 0x3C and 0x3D)
// #define USE_DISPLAY_MATRIX // Enable 8x8 Matrix display (I2C adresses below)
#define MTX_ADDRESS1 0x71 // [DisplayAddress[1]] I2C address of first 8x8 matrix module
#define MTX_ADDRESS2 0x74 // [DisplayAddress[2]] I2C address of second 8x8 matrix module
#define MTX_ADDRESS3 0x75 // [DisplayAddress[3]] I2C address of third 8x8 matrix module
#define MTX_ADDRESS4 0x72 // [DisplayAddress[4]] I2C address of fourth 8x8 matrix module
#define MTX_ADDRESS5 0x73 // [DisplayAddress[5]] I2C address of fifth 8x8 matrix module
#define MTX_ADDRESS6 0x76 // [DisplayAddress[6]] I2C address of sixth 8x8 matrix module
#define MTX_ADDRESS7 0x00 // [DisplayAddress[7]] I2C address of seventh 8x8 matrix module
#define MTX_ADDRESS8 0x00 // [DisplayAddress[8]] I2C address of eigth 8x8 matrix module
#endif // USE_I2C #endif // USE_I2C
// -- SPI sensors --------------------------------- // -- SPI sensors ---------------------------------
//#define USE_SPI // SPI using default library //#define USE_SPI // SPI using library TasmotaTFT
#ifdef USE_SPI #ifdef USE_SPI
#ifndef USE_DISPLAY
#define USE_DISPLAY // Add SPI Display support for 320x240 and 480x320 TFT
#endif
#define USE_DISPLAY_ILI9341 // Enable Tft 480x320 display
// #define USE_DISPLAY_EPAPER // Enable e-paper display
#endif // USE_SPI #endif // USE_SPI
@ -312,9 +333,9 @@
#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) #define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code)
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) #define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code)
#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy meter (+1k7 code) //#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy meter (+1k7 code)
#define SDM120_SPEED 9600 // SDM120-Modbus RS485 serial speed (default: 2400 baud) #define SDM120_SPEED 9600 // SDM120-Modbus RS485 serial speed (default: 2400 baud)
#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy meter (+2k code) //#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy meter (+2k code)
#define SDM630_SPEED 9600 // SDM630-Modbus RS485 serial speed (default: 9600 baud) #define SDM630_SPEED 9600 // SDM630-Modbus RS485 serial speed (default: 9600 baud)
// -- Low level interface devices ----------------- // -- Low level interface devices -----------------
@ -330,7 +351,7 @@
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code) #define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code) //#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code)
#define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+3k code) #define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+3k code)

891
sonoff/xdrv_13_display.ino Normal file
View File

@ -0,0 +1,891 @@
/*
xdrv_13_display.ino - Display support for Sonoff-Tasmota
Copyright (C) 2018 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/>.
*/
#if defined(USE_I2C) || defined(USE_SPI)
#ifdef USE_DISPLAY
#define DISPLAY_MAX_DRIVERS 16 // Max number of display drivers/models supported by xdsp_interface.ino
#define DISPLAY_SCREEN_COLS 40 // Max number of columns to display
#define DISPLAY_SCREEN_ROWS 8 // Max number of lines to display for LCD and Oled using local screen buffer
#define DISPLAY_LOG_COLS DISPLAY_SCREEN_COLS +1 // Number of characters in display log buffer line +1
#define DISPLAY_LOG_ROWS 32 // Number of lines in display log buffer
#define D_CMND_DISPLAY "Display"
#define D_CMND_DISP_ADDRESS "Address"
#define D_CMND_DISP_COLS "Cols"
#define D_CMND_DISP_DIMMER "Dimmer"
#define D_CMND_DISP_MODE "Mode"
#define D_CMND_DISP_MODEL "Model"
#define D_CMND_DISP_REFRESH "Refresh"
#define D_CMND_DISP_ROWS "Rows"
#define D_CMND_DISP_SIZE "Size"
#define D_CMND_DISP_TEXT "Text"
enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_EVERY_50_MSECOND, FUNC_DISPLAY_EVERY_SECOND,
FUNC_DISPLAY_MODEL, FUNC_DISPLAY_MODE, FUNC_DISPLAY_POWER,
FUNC_DISPLAY_CLEAR, FUNC_DISPLAY_DRAW_FRAME,
FUNC_DISPLAY_DRAW_HLINE, FUNC_DISPLAY_DRAW_VLINE, FUNC_DISPLAY_DRAW_LINE,
FUNC_DISPLAY_DRAW_CIRCLE, FUNC_DISPLAY_FILL_CIRCLE,
FUNC_DISPLAY_DRAW_RECTANGLE, FUNC_DISPLAY_FILL_RECTANGLE,
FUNC_DISPLAY_FONT_SIZE, FUNC_DISPLAY_ROTATION, FUNC_DISPLAY_DRAW_STRING, FUNC_DISPLAY_ONOFF };
enum DisplayInitModes { DISPLAY_INIT_MODE, DISPLAY_INIT_PARTIAL, DISPLAY_INIT_FULL };
enum DisplayCommands { CMND_DISP_MODEL, CMND_DISP_MODE, CMND_DISP_REFRESH, CMND_DISP_DIMMER, CMND_DISP_COLS, CMND_DISP_ROWS,
CMND_DISP_SIZE, CMND_DISP_TEXT, CMND_DISP_ADDRESS };
const char kDisplayCommands[] PROGMEM =
D_CMND_DISP_MODEL "|" D_CMND_DISP_MODE "|" D_CMND_DISP_REFRESH "|" D_CMND_DISP_DIMMER "|" D_CMND_DISP_COLS "|" D_CMND_DISP_ROWS "|"
D_CMND_DISP_SIZE "|" D_CMND_DISP_TEXT "|" D_CMND_DISP_ADDRESS ;
const char S_JSON_DISPLAY_COMMAND_VALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s\":\"%s\"}";
const char S_JSON_DISPLAY_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s\":%d}";
const char S_JSON_DISPLAY_COMMAND_INDEX_NVALUE[] PROGMEM = "{\"" D_CMND_DISPLAY "%s%d\":%d}";
char disp_log_buffer[DISPLAY_LOG_ROWS][DISPLAY_LOG_COLS];
char disp_temp[2]; // C or F
uint8_t disp_log_buffer_idx = 0;
uint8_t disp_log_buffer_ptr = 0;
bool disp_log_buffer_active = false;
uint8_t disp_refresh = 1;
uint8_t disp_power = 0;
uint8_t disp_device = 0;
uint8_t disp_subscribed = 0;
int16_t disp_xpos = 0;
int16_t disp_ypos = 0;
uint8_t dsp_init;
uint8_t dsp_font;
uint8_t dsp_flag;
uint8_t dsp_on;
uint8_t dsp_rotation;
uint16_t dsp_x;
uint16_t dsp_y;
uint16_t dsp_x2;
uint16_t dsp_y2;
uint16_t dsp_rad;
uint16_t dsp_color;
int16_t dsp_len;
char *dsp_str;
void DisplayInit(uint8_t mode)
{
dsp_init = mode;
XdspCall(FUNC_DISPLAY_INIT);
}
void DisplayClear()
{
XdspCall(FUNC_DISPLAY_CLEAR);
}
void DisplayDrawHLine(uint16_t x, uint16_t y, int16_t len, uint16_t color)
{
dsp_x = x;
dsp_y = y;
dsp_len = len;
dsp_color = color;
XdspCall(FUNC_DISPLAY_DRAW_HLINE);
}
void DisplayDrawVLine(uint16_t x, uint16_t y, int16_t len, uint16_t color)
{
dsp_x = x;
dsp_y = y;
dsp_len = len;
dsp_color = color;
XdspCall(FUNC_DISPLAY_DRAW_VLINE);
}
void DisplayDrawLine(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color)
{
dsp_x = x;
dsp_y = y;
dsp_x2 = x2;
dsp_y2 = y2;
dsp_color = color;
XdspCall(FUNC_DISPLAY_DRAW_LINE);
}
void DisplayDrawCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color)
{
dsp_x = x;
dsp_y = y;
dsp_rad = rad;
dsp_color = color;
XdspCall(FUNC_DISPLAY_DRAW_CIRCLE);
}
void DisplayDrawFilledCircle(uint16_t x, uint16_t y, uint16_t rad, uint16_t color)
{
dsp_x = x;
dsp_y = y;
dsp_rad = rad;
dsp_color = color;
XdspCall(FUNC_DISPLAY_FILL_CIRCLE);
}
void DisplayDrawRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color)
{
dsp_x = x;
dsp_y = y;
dsp_x2 = x2;
dsp_y2 = y2;
dsp_color = color;
XdspCall(FUNC_DISPLAY_DRAW_RECTANGLE);
}
void DisplayDrawFilledRectangle(uint16_t x, uint16_t y, uint16_t x2, uint16_t y2, uint16_t color)
{
dsp_x = x;
dsp_y = y;
dsp_x2 = x2;
dsp_y2 = y2;
dsp_color = color;
XdspCall(FUNC_DISPLAY_FILL_RECTANGLE);
}
void DisplayDrawFrame()
{
XdspCall(FUNC_DISPLAY_DRAW_FRAME);
}
void DisplaySetFontorSize(uint8_t font)
{
Settings.display_size = font;
XdspCall(FUNC_DISPLAY_FONT_SIZE);
}
void DisplaySetRotation(uint8_t rotation)
{
dsp_rotation = rotation;
XdspCall(FUNC_DISPLAY_ROTATION);
}
void DisplayDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
{
dsp_x = x;
dsp_y = y;
dsp_str = str;
dsp_color = color;
dsp_flag = flag;
XdspCall(FUNC_DISPLAY_DRAW_STRING);
}
void DisplayOnOff(uint8_t on)
{
dsp_on = on;
XdspCall(FUNC_DISPLAY_ONOFF);
}
// get asci number until delimiter and return asci number lenght and value
uint8_t atoiv(char *cp, int16_t *res)
{
uint8_t index = 0;
*res = atoi(cp);
while (*cp) {
if ((*cp>='0' && *cp<='9') || (*cp=='-')) {
cp++;
index++;
} else {
break;
}
}
return index;
}
// get asci number until delimiter and return asci number lenght and value
uint8_t atoiV(char *cp, uint16_t *res)
{
uint8_t index = 0;
*res = atoi(cp);
while (*cp) {
if (*cp>='0' && *cp<='9') {
cp++;
index++;
} else {
break;
}
}
return index;
}
/*********************************************************************************************/
#define DISPLAY_BUFFER_COLS 128 // Max number of characters in linebuf
void DisplayText()
{
uint8_t lpos;
uint8_t escape = 0;
uint8_t var;
uint8_t font_x = 6;
uint8_t font_y = 8;
uint8_t fontnumber = 1;
int16_t lin = 0;
int16_t col = 0;
int16_t fill = 0;
int16_t temp;
int16_t temp1;
uint16_t color = 0;
char linebuf[DISPLAY_BUFFER_COLS];
char *dp = linebuf;
char *cp = XdrvMailbox.data;
memset(linebuf, ' ', sizeof(linebuf));
linebuf[sizeof(linebuf)-1] = 0;
*dp = 0;
while (*cp) {
if (!escape) {
// check for escape
if (*cp == '[') {
escape = 1;
cp++;
// if string in buffer print it
if ((uint32_t)dp - (uint32_t)linebuf) {
if (!fill) { *dp = 0; }
if (col > 0 && lin > 0) {
// use col and lin
DisplayDrawStringAt(col, lin, linebuf, color, 1);
} else {
// use disp_xpos, disp_ypos
DisplayDrawStringAt(disp_xpos, disp_ypos, linebuf, color, 0);
}
memset(linebuf, ' ', sizeof(linebuf));
linebuf[sizeof(linebuf)-1] = 0;
dp = linebuf;
}
} else {
// copy chars
if (dp < (linebuf + DISPLAY_BUFFER_COLS)) { *dp++ = *cp++; }
}
} else {
// check escapes
if (*cp == ']') {
escape = 0;
cp++;
} else {
// analyze escapes
switch (*cp++) {
case 'z':
// clear display
DisplayClear();
disp_xpos = 0;
disp_ypos = 0;
col = 0;
lin = 0;
break;
case 'i':
// init display with partial update
DisplayInit(DISPLAY_INIT_PARTIAL);
break;
case 'I':
// init display with full refresh
DisplayInit(DISPLAY_INIT_FULL);
break;
case 'o':
DisplayOnOff(0);
break;
case 'O':
DisplayOnOff(1);
break;
case 'x':
// set disp_xpos
var = atoiv(cp, &disp_xpos);
cp += var;
break;
case 'y':
// set disp_ypos
var = atoiv(cp, &disp_ypos);
cp += var;
break;
case 'l':
// text line lxx
var = atoiv(cp, &lin);
cp += var;
//display.setCursor(display.getCursorX(),(lin-1)*font_y*txtsize);
break;
case 'c':
// text column cxx
var = atoiv(cp, &col);
cp += var;
//display.setCursor((col-1)*font_x*txtsize,display.getCursorY());
break;
case 'C':
// text color cxx
var = atoiV(cp, &color);
cp += var;
break;
case 'p':
// pad field with spaces fxx
var = atoiv(cp, &fill);
cp += var;
linebuf[fill] = 0;
break;
case 'h':
// hor line to
var = atoiv(cp, &temp);
cp += var;
if (temp < 0) {
DisplayDrawHLine(disp_xpos + temp, disp_ypos, -temp, color);
} else {
DisplayDrawHLine(disp_xpos, disp_ypos, temp, color);
}
disp_xpos += temp;
break;
case 'v':
// vert line to
var = atoiv(cp, &temp);
cp += var;
if (temp < 0) {
DisplayDrawVLine(disp_xpos, disp_ypos + temp, -temp, color);
} else {
DisplayDrawVLine(disp_xpos, disp_ypos, temp, color);
}
disp_ypos += temp;
break;
case 'L':
// any line to
var = atoiv(cp, &temp);
cp += var;
cp++;
var = atoiv(cp, &temp1);
cp += var;
DisplayDrawLine(disp_xpos, disp_ypos, temp, temp1, color);
disp_xpos += temp;
break;
case 'k':
// circle
var = atoiv(cp, &temp);
cp += var;
DisplayDrawCircle(disp_xpos, disp_ypos, temp, color);
break;
case 'K':
// filled circle
var = atoiv(cp, &temp);
cp += var;
DisplayDrawFilledCircle(disp_xpos, disp_ypos, temp, color);
break;
case 'r':
// rectangle
var = atoiv(cp, &temp);
cp += var;
cp++;
var = atoiv(cp, &temp1);
cp += var;
DisplayDrawRectangle(disp_xpos, disp_ypos, temp, temp1, color);
break;
case 'R':
// filled rectangle
var = atoiv(cp, &temp);
cp += var;
cp++;
var = atoiv(cp, &temp1);
cp += var;
DisplayDrawFilledRectangle(disp_xpos, disp_ypos, temp, temp1, color);
break;
case 't': {
if (dp < (linebuf + DISPLAY_BUFFER_COLS) -5) {
snprintf_P(dp, 5, PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute);
dp += 5;
}
break;
}
case 'd':
// force draw grafics buffer
DisplayDrawFrame();
break;
case 's':
case 'f':
// size or font sx
DisplaySetFontorSize(*cp&3);
cp += 1;
break;
case 'a':
// rotation angle
DisplaySetRotation(*cp&3);
cp+=1;
break;
default:
// unknown escape
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("Unknown Escape"));
goto exit;
break;
}
}
}
}
exit:
// now draw buffer
if ((uint32_t)dp - (uint32_t)linebuf) {
if (!fill) { *dp = 0; }
if (col > 0 && lin > 0) {
// use col and lin
DisplayDrawStringAt(col, lin, linebuf, color, 1);
} else {
// use disp_xpos, disp_ypos
DisplayDrawStringAt(disp_xpos, disp_ypos, linebuf, color, 0);
}
}
// draw buffer
DisplayDrawFrame();
}
void DisplayLogBufferIdxInc()
{
disp_log_buffer_idx++;
if (DISPLAY_LOG_ROWS == disp_log_buffer_idx) {
disp_log_buffer_idx = 0;
}
}
void DisplayLogBufferPtrInc()
{
disp_log_buffer_ptr++;
if (DISPLAY_LOG_ROWS == disp_log_buffer_ptr) {
disp_log_buffer_ptr = 0;
}
}
/*
void DisplayPrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
XdspPrintLog(disp_log_buffer[disp_log_buffer_ptr]);
DisplayLogBufferPtrInc();
}
}
}
*/
void DisplayLogBufferInit()
{
disp_log_buffer_idx = 0;
disp_log_buffer_ptr = 0;
disp_log_buffer_active = false;
disp_refresh = Settings.display_refresh;
snprintf_P(disp_log_buffer[disp_log_buffer_idx], sizeof(disp_log_buffer[disp_log_buffer_idx]), PSTR(D_VERSION " %s"), my_version);
DisplayLogBufferIdxInc();
snprintf_P(disp_log_buffer[disp_log_buffer_idx], sizeof(disp_log_buffer[disp_log_buffer_idx]), PSTR("Display mode %d"), Settings.display_mode);
DisplayLogBufferIdxInc();
}
/*********************************************************************************************\
* Sensors
\*********************************************************************************************/
enum SensorQuantity {
JSON_TEMPERATURE,
JSON_HUMIDITY, JSON_LIGHT, JSON_NOISE, JSON_AIRQUALITY,
JSON_PRESSURE, JSON_PRESSUREATSEALEVEL,
JSON_ILLUMINANCE,
JSON_GAS,
JSON_YESTERDAY, JSON_TOTAL, JSON_TODAY,
JSON_PERIOD,
JSON_POWERFACTOR, JSON_COUNTER, JSON_ANALOG_INPUT, JSON_UV_LEVEL,
JSON_CURRENT,
JSON_VOLTAGE,
JSON_POWERUSAGE,
JSON_CO2 };
const char kSensorQuantity[] PROGMEM =
D_JSON_TEMPERATURE "|" // degrees
D_JSON_HUMIDITY "|" D_JSON_LIGHT "|" D_JSON_NOISE "|" D_JSON_AIRQUALITY "|" // percentage
D_JSON_PRESSURE "|" D_JSON_PRESSUREATSEALEVEL "|" // hPa
D_JSON_ILLUMINANCE "|" // lx
D_JSON_GAS "|" // kOhm
D_JSON_YESTERDAY "|" D_JSON_TOTAL "|" D_JSON_TODAY "|" // kWh
D_JSON_PERIOD "|" // Wh
D_JSON_POWERFACTOR "|" D_JSON_COUNTER "|" D_JSON_ANALOG_INPUT "|" D_JSON_UV_LEVEL "|" // No unit
D_JSON_CURRENT "|" // Ampere
D_JSON_VOLTAGE "|" // Volt
D_JSON_POWERUSAGE "|" // Watt
D_JSON_CO2 ; // ppm
void DisplayJsonValue(const char *topic, const char* device, const char* mkey, const char* value)
{
char quantity[TOPSZ];
char spaces[Settings.display_cols[0]];
char source[Settings.display_cols[0] - Settings.display_cols[1]];
char svalue[Settings.display_cols[1] +1];
ShowFreeMem(PSTR("DisplayJsonValue"));
memset(spaces, 0x20, sizeof(spaces));
spaces[sizeof(spaces) -1] = '\0';
// snprintf_P(source, sizeof(source), PSTR("%s/%s%s"), topic, mkey, (DISP_MATRIX == Settings.display_model) ? "" : spaces); // pow1/Voltage
snprintf_P(source, sizeof(source), PSTR("%s/%s%s"), topic, mkey, spaces); // pow1/Voltage
int quantity_code = GetCommandCode(quantity, sizeof(quantity), mkey, kSensorQuantity);
if ((-1 == quantity_code) || !strcmp_P(mkey, S_RSLT_POWER)) { // Ok: Power, Not ok: POWER
return;
}
if (JSON_TEMPERATURE == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s~%s"), value, disp_temp);
}
else if ((quantity_code >= JSON_HUMIDITY) && (quantity_code <= JSON_AIRQUALITY)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%%"), value);
}
else if ((quantity_code >= JSON_PRESSURE) && (quantity_code <= JSON_PRESSUREATSEALEVEL)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_PRESSURE), value);
}
else if (JSON_ILLUMINANCE == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_LUX), value);
}
else if (JSON_GAS == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_KILOOHM), value);
}
else if ((quantity_code >= JSON_YESTERDAY) && (quantity_code <= JSON_TODAY)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_KILOWATTHOUR), value);
}
else if (JSON_PERIOD == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_WATTHOUR), value);
}
else if ((quantity_code >= JSON_POWERFACTOR) && (quantity_code <= JSON_UV_LEVEL)) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s"), value);
}
else if (JSON_CURRENT == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_AMPERE), value);
}
else if (JSON_VOLTAGE == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_VOLT), value);
}
else if (JSON_POWERUSAGE == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_WATT), value);
}
else if (JSON_CO2 == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_PARTS_PER_MILLION), value);
}
snprintf_P(disp_log_buffer[disp_log_buffer_idx], sizeof(disp_log_buffer[disp_log_buffer_idx]), PSTR("%s %s"), source, svalue);
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "mkey [%s], source [%s], value [%s], quantity_code %d, log_buffer [%s]"), mkey, source, value, quantity_code, disp_log_buffer[disp_log_buffer_idx]);
// AddLog(LOG_LEVEL_DEBUG);
DisplayLogBufferIdxInc();
}
void DisplayAnalyzeJson(char *topic, char *json)
{
// //tele/pow2/STATE {"Time":"2017-09-20T11:53:03", "Uptime":10, "Vcc":3.123, "POWER":"ON", "Wifi":{"AP":2, "SSId":"indebuurt2", "RSSI":68, "APMac":"00:22:6B:FE:8E:20"}}
// //tele/pow2/ENERGY {"Time":"2017-09-20T11:53:03", "Total":6.522, "Yesterday":0.150, "Today":0.073, "Period":0.5, "Power":12.1, "Factor":0.56, "Voltage":210.1, "Current":0.102}
// tele/pow1/SENSOR = {"Time":"2018-01-02T17:13:17","ENERGY":{"Total":13.091,"Yesterday":0.060,"Today":0.046,"Period":0.2,"Power":9.8,"Factor":0.49,"Voltage":206.8,"Current":0.096}}
// tele/dual/STATE {"Time":"2017-09-20T11:53:03","Uptime":25,"Vcc":3.178,"POWER1":"OFF","POWER2":"OFF","Wifi":{"AP":2,"SSId":"indebuurt2","RSSI":100,"APMac":"00:22:6B:FE:8E:20"}}
// tele/sc/SENSOR {"Time":"2017-09-20T11:53:09","Temperature":24.0,"Humidity":16.0,"Light":30,"Noise":20,"AirQuality":100,"TempUnit":"C"}
// tele/rf1/SENSOR {"Time":"2017-09-20T11:53:23","BH1750":{"Illuminance":57}}
// tele/wemos5/SENSOR {"Time":"2017-09-20T11:53:53","SHT1X":{"Temperature":20.1,"Humidity":58.9},"HTU21":{"Temperature":20.7,"Humidity":58.5},"BMP280":{"Temperature":21.6,"Pressure":1020.3},"TempUnit":"C"}
// tele/th1/SENSOR {"Time":"2017-09-20T11:54:48","DS18B20":{"Temperature":49.7},"TempUnit":"C"}
const char *tempunit;
// char jsonStr[MESSZ];
// strlcpy(jsonStr, json, sizeof(jsonStr)); // Save original before destruction by JsonObject
String jsonStr = json; // Move from stack to heap to fix watchdogs (20180626)
StaticJsonBuffer<1024> jsonBuf;
JsonObject &root = jsonBuf.parseObject(jsonStr);
if (root.success()) {
tempunit = root[D_JSON_TEMPERATURE_UNIT];
if (tempunit) {
snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%s"), tempunit);
// snprintf_P(log_data, sizeof(log_data), disp_temp);
// AddLog(LOG_LEVEL_DEBUG);
}
for (JsonObject::iterator it = root.begin(); it != root.end(); ++it) {
JsonVariant value = it->value;
if (value.is<JsonObject>()) {
JsonObject& Object2 = value;
for (JsonObject::iterator it2 = Object2.begin(); it2 != Object2.end(); ++it2) {
JsonVariant value2 = it2->value;
if (value2.is<JsonObject>()) {
JsonObject& Object3 = value2;
for (JsonObject::iterator it3 = Object3.begin(); it3 != Object3.end(); ++it3) {
DisplayJsonValue(topic, it->key, it3->key, it3->value.as<const char*>()); // Sensor 56%
}
} else {
DisplayJsonValue(topic, it->key, it2->key, it2->value.as<const char*>()); // Sensor 56%
}
}
} else {
DisplayJsonValue(topic, it->key, it->key, it->value.as<const char*>()); // Topic 56%
}
}
}
}
/*********************************************************************************************\
* Public
\*********************************************************************************************/
void DisplayInitDriver()
{
XdspCall(FUNC_DISPLAY_INIT_DRIVER);
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model);
// AddLog(LOG_LEVEL_DEBUG);
if (Settings.display_model) {
devices_present++;
disp_device = devices_present;
snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%c"), TempUnit());
DisplayLogBufferInit();
}
}
void DisplaySetPower()
{
disp_power = bitRead(XdrvMailbox.index, disp_device -1);
if (Settings.display_model) {
XdspCall(FUNC_DISPLAY_POWER);
}
}
void DisplayMqttSubscribe()
{
/* Subscribe to tele messages only
* Supports the following FullTopic formats
* - %prefix%/%topic%
* - home/%prefix%/%topic%
* - home/level2/%prefix%/%topic% etc.
*/
// if (Settings.display_mode &0x04) {
if (Settings.display_model) {
char stopic[TOPSZ];
char ntopic[TOPSZ];
ntopic[0] = '\0';
strlcpy(stopic, Settings.mqtt_fulltopic, sizeof(stopic));
char *tp = strtok(stopic, "/");
while (tp != NULL) {
if (!strcmp_P(tp, PSTR(MQTT_TOKEN_PREFIX))) {
break;
}
strncat_P(ntopic, PSTR("+/"), sizeof(ntopic)); // Add single-level wildcards
tp = strtok(NULL, "/");
}
strncat(ntopic, Settings.mqtt_prefix[2], sizeof(ntopic)); // Subscribe to tele messages
strncat_P(ntopic, PSTR("/#"), sizeof(ntopic)); // Add multi-level wildcard
MqttSubscribe(ntopic);
disp_subscribed = 1;
} else {
disp_subscribed = 0;
}
}
boolean DisplayMqttData()
{
if (disp_subscribed) {
char stopic[TOPSZ];
snprintf_P(stopic, sizeof(stopic) , PSTR("%s/"), Settings.mqtt_prefix[2]); // tele/
char *tp = strstr(XdrvMailbox.topic, stopic);
if (tp) { // tele/sonoff/SENSOR
if (Settings.display_mode &0x04) {
tp = tp + strlen(stopic); // sonoff/SENSOR
char *topic = strtok(tp, "/"); // sonoff
DisplayAnalyzeJson(topic, XdrvMailbox.data);
}
return true;
}
}
return false;
}
void DisplayLocalSensor()
{
if ((Settings.display_mode &0x02) && (0 == tele_period)) {
DisplayAnalyzeJson(mqtt_topic, mqtt_data);
}
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
boolean DisplayCommand()
{
char command [CMDSZ];
boolean serviced = true;
uint8_t disp_len = strlen(D_CMND_DISPLAY); // Prep for string length change
if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_DISPLAY), disp_len)) { // Prefix
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic +disp_len, kDisplayCommands);
if (-1 == command_code) {
serviced = false; // Unknown command
}
else if (CMND_DISP_MODEL == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < DISPLAY_MAX_DRIVERS)) {
uint8_t last_display_model = Settings.display_model;
Settings.display_model = XdrvMailbox.payload;
if (XdspCall(FUNC_DISPLAY_MODEL)) {
restart_flag = 2; // Restart to re-init interface and add/Remove MQTT subscribe
} else {
Settings.display_model = last_display_model;
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_model);
}
else if (CMND_DISP_MODE == command_code) {
/*
* Matrix LCD / Oled TFT
* 0 = Text Text Text
* 1 = Text up and time Time
* 2 = Date Local sensors Local sensors
* 3 = Day Local sensors and time Local sensors and time
* 4 = Mqtt left and time Mqtt (incl local) sensors Mqtt (incl local) sensors
* 5 = Mqtt up and time Mqtt (incl local) sensors and time Mqtt (incl local) sensors and time
*/
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 5)) {
uint8_t last_display_mode = Settings.display_mode;
Settings.display_mode = XdrvMailbox.payload;
if (!disp_subscribed) {
restart_flag = 2; // Restart to Add/Remove MQTT subscribe
} else {
if (last_display_mode && !Settings.display_mode) { // Switch to mode 0
DisplayInit(DISPLAY_INIT_MODE);
DisplayClear();
}
if (!last_display_mode && Settings.display_mode) { // Switch to non mode 0
DisplayInit(DISPLAY_INIT_MODE);
DisplayLogBufferInit();
}
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_mode);
}
else if (CMND_DISP_REFRESH == command_code) {
if ((XdrvMailbox.payload >= 1) && (XdrvMailbox.payload <= 7)) {
Settings.display_refresh = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_refresh);
}
else if ((CMND_DISP_COLS == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_SCREEN_COLS)) {
Settings.display_cols[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_cols[XdrvMailbox.index -1]);
}
else if (CMND_DISP_DIMMER == command_code) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
Settings.display_dimmer = ((XdrvMailbox.payload +1) * 100) / 666; // Correction for Domoticz (0 - 15)
if (Settings.display_dimmer && !(disp_power)) {
ExecuteCommandPower(disp_device, POWER_ON, SRC_DISPLAY);
}
else if (!Settings.display_dimmer && disp_power) {
ExecuteCommandPower(disp_device, POWER_OFF, SRC_DISPLAY);
}
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_dimmer);
}
else if (CMND_DISP_ROWS == command_code) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_SCREEN_ROWS)) {
Settings.display_rows = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rows);
}
else if (CMND_DISP_SIZE == command_code) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) {
Settings.display_size = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_size);
}
else if (CMND_DISP_TEXT == command_code) {
mqtt_data[0] = '\0';
if (disp_device && XdrvMailbox.data_len > 0) {
if (!Settings.display_mode) {
DisplayText();
} else {
strlcpy(disp_log_buffer[disp_log_buffer_idx], XdrvMailbox.data, sizeof(disp_log_buffer[disp_log_buffer_idx]));
DisplayLogBufferIdxInc();
}
} else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("No Text"));
}
if (mqtt_data[0] == '\0') {
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_VALUE, command, XdrvMailbox.data);
}
}
else if ((CMND_DISP_ADDRESS == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 255)) {
Settings.display_address[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_address[XdrvMailbox.index -1]);
}
else serviced = false; // Unknown command
}
else serviced = false; // Unknown command
return serviced;
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
#define XDRV_98
boolean Xdrv98(byte function)
{
boolean result = false;
if ((i2c_flg || spi_flg) && XdspPresent()) {
switch (function) {
case FUNC_PRE_INIT:
DisplayInitDriver();
break;
case FUNC_EVERY_50_MSECOND:
if (Settings.display_model && Settings.display_mode) { XdspCall(FUNC_DISPLAY_EVERY_50_MSECOND); }
break;
case FUNC_EVERY_SECOND:
if (Settings.display_model && Settings.display_mode) { XdspCall(FUNC_DISPLAY_EVERY_SECOND); }
break;
case FUNC_COMMAND:
result = DisplayCommand();
break;
case FUNC_MQTT_SUBSCRIBE:
DisplayMqttSubscribe();
break;
case FUNC_MQTT_DATA:
result = DisplayMqttData();
break;
case FUNC_SET_POWER:
DisplaySetPower();
break;
case FUNC_SHOW_SENSOR:
DisplayLocalSensor();
break;
}
}
return result;
}
#endif // USE_DISPLAY
#endif // USE_I2C or USE_SPI

259
sonoff/xdsp_01_lcd.ino Normal file
View File

@ -0,0 +1,259 @@
/*
xdsp_01_lcd.ino - Display LCD support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_I2C
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_LCD
#define XDSP_01 1
#define LCD_ADDRESS1 0x27 // LCD I2C address option 1
#define LCD_ADDRESS2 0x3F // LCD I2C address option 2
#define LCD_BUFFER_COLS 40 // Max number of columns in display shadow buffer
#define LCD_BUFFER_ROWS 8 // Max number of lines in display shadow buffer
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C *lcd;
char lcd_screen_buffer[LCD_BUFFER_ROWS][LCD_BUFFER_COLS +1];
void LcdInitFull()
{
lcd->init();
lcd->clear();
memset(lcd_screen_buffer[Settings.display_rows -1], 0x20, Settings.display_cols[0]);
lcd_screen_buffer[Settings.display_rows -1][Settings.display_cols[0]] = 0;
}
void LcdDrawStringAt()
{
lcd->setCursor(dsp_x, dsp_y);
lcd->print(dsp_str);
}
void LcdDisplayOnOff(uint8_t on)
{
if (on) {
lcd->backlight();
} else {
lcd->noBacklight();
}
}
/*********************************************************************************************/
void LcdCenter(byte row, char* txt)
{
int offset;
int len;
char line[Settings.display_cols[0] +2];
memset(line, 0x20, Settings.display_cols[0]);
line[Settings.display_cols[0]] = 0;
len = strlen(txt);
offset = (len < Settings.display_cols[0]) ? offset = (Settings.display_cols[0] - len) / 2 : 0;
strncpy(line +offset, txt, len);
lcd->setCursor(0, row);
lcd->print(line);
}
/*********************************************************************************************/
void LcdInitMode()
{
lcd->init();
lcd->clear();
memset(lcd_screen_buffer[Settings.display_rows -1], 0x20, Settings.display_cols[0]);
lcd_screen_buffer[Settings.display_rows -1][Settings.display_cols[0]] = 0;
}
void LcdInit(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
LcdInitMode();
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void LcdInitDriver()
{
if (!Settings.display_model) {
if (I2cDevice(LCD_ADDRESS1)) {
Settings.display_address[0] = LCD_ADDRESS1;
Settings.display_model = XDSP_01;
}
else if (I2cDevice(LCD_ADDRESS2)) {
Settings.display_address[0] = LCD_ADDRESS2;
Settings.display_model = XDSP_01;
}
}
if (XDSP_01 == Settings.display_model) {
lcd = new LiquidCrystal_I2C(Settings.display_address[0], Settings.display_cols[0], Settings.display_rows);
LcdInitMode();
}
}
void LcdPrintLogLine()
{
uint8_t last_row = Settings.display_rows -1;
for (byte i = 0; i < last_row; i++) {
strlcpy(lcd_screen_buffer[i], lcd_screen_buffer[i +1], sizeof(lcd_screen_buffer[i]));
lcd->setCursor(0, i); // Col 0, Row i
lcd->print(lcd_screen_buffer[i +1]);
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\337'; // = 0xDF
}
strlcpy(lcd_screen_buffer[last_row], disp_log_buffer[disp_log_buffer_ptr], sizeof(lcd_screen_buffer[last_row]));
// Fill with spaces
byte len = sizeof(lcd_screen_buffer[last_row]) - strlen(lcd_screen_buffer[last_row]);
if (len) {
memset(lcd_screen_buffer[last_row] + strlen(lcd_screen_buffer[last_row]), 0x20, len);
lcd_screen_buffer[last_row][sizeof(lcd_screen_buffer[last_row])-1] = 0;
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), lcd_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
lcd->setCursor(0, last_row);
lcd->print(lcd_screen_buffer[last_row]);
}
void LcdPrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
LcdPrintLogLine();
DisplayLogBufferPtrInc();
}
}
}
void LcdTime()
{
char line[Settings.display_cols[0] +1];
snprintf_P(line, sizeof(line), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
LcdCenter(0, line);
snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year);
LcdCenter(1, line);
}
void LcdRefresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
switch (Settings.display_mode) {
case 1: // Time
LcdTime();
break;
case 2: // Local
case 4: // Mqtt
LcdPrintLog();
break;
case 3: // Local
case 5: { // Mqtt
LcdPrintLog();
if (!disp_log_buffer_active) {
LcdTime();
}
break;
}
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp01(byte function)
{
boolean result = false;
if (i2c_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
LcdInitDriver();
}
else if (XDSP_01 == Settings.display_model) {
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
LcdInit(dsp_init);
break;
case FUNC_DISPLAY_EVERY_SECOND:
LcdRefresh();
break;
case FUNC_DISPLAY_POWER:
LcdDisplayOnOff(disp_power);
break;
case FUNC_DISPLAY_CLEAR:
lcd->clear();
break;
// case FUNC_DISPLAY_DRAW_HLINE:
// break;
// case FUNC_DISPLAY_DRAW_VLINE:
// break;
// case FUNC_DISPLAY_DRAW_CIRCLE:
// break;
// case FUNC_DISPLAY_FILL_CIRCLE:
// break;
// case FUNC_DISPLAY_DRAW_RECTANGLE:
// break;
// case FUNC_DISPLAY_FILL_RECTANGLE:
// break;
// case FUNC_DISPLAY_DRAW_FRAME:
// break;
// case FUNC_DISPLAY_FONT_SIZE:
// break;
case FUNC_DISPLAY_DRAW_STRING:
LcdDrawStringAt();
break;
case FUNC_DISPLAY_ONOFF:
LcdDisplayOnOff(dsp_on);
break;
// case FUNC_DISPLAY_ROTATION:
// break;
}
}
}
return result;
}
#endif // USE_DISPLAY_LCD
#endif // USE_DISPLAY
#endif // USE_I2C

291
sonoff/xdsp_02_ssd1306.ino Normal file
View File

@ -0,0 +1,291 @@
/*
xdsp_02_ssd1306.ino - Display Oled ssd1306 support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_I2C
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_SSD1306
#define XDSP_02 2
#define OLED_ADDRESS1 0x3C // Oled 128x32 I2C address
#define OLED_ADDRESS2 0x3D // Oled 128x64 I2C address
#define OLED_BUFFER_COLS 40 // Max number of columns in display shadow buffer
#define OLED_BUFFER_ROWS 8 // Max number of lines in display shadow buffer
#define OLED_FONT_WIDTH 6
#define OLED_FONT_HEIGTH 8
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
Adafruit_SSD1306 *oled;
char oled_screen_buffer[OLED_BUFFER_ROWS][OLED_BUFFER_COLS +1];
uint8_t ssd1306_font_x = OLED_FONT_WIDTH;
uint8_t ssd1306_font_y = OLED_FONT_HEIGTH;
void Ssd1306InitFull()
{
oled->invertDisplay(false);
oled->clearDisplay();
oled->setTextWrap(false); // Allow text to run off edges
oled->cp437(true);
oled->setTextSize(Settings.display_size);
oled->setTextColor(WHITE);
oled->setCursor(0,0);
oled->display();
}
void Ssd1306Clear()
{
oled->clearDisplay();
oled->setCursor(0, 0);
oled->display();
}
void Ssd1306DrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
{
if (!flag) {
oled->setCursor(x, y);
} else {
oled->setCursor((x-1) * ssd1306_font_x * Settings.display_size, (y-1) * ssd1306_font_y * Settings.display_size);
}
oled->println(str);
}
void Ssd1306DisplayOnOff(uint8_t on)
{
if (on) {
oled->ssd1306_command(SSD1306_DISPLAYON);
} else {
oled->ssd1306_command(SSD1306_DISPLAYOFF);
}
}
/*********************************************************************************************/
void Ssd1306InitMode()
{
oled->invertDisplay(false);
oled->clearDisplay();
oled->setTextWrap(false); // Allow text to run off edges
oled->cp437(true);
oled->setTextSize(Settings.display_size);
oled->setTextColor(WHITE);
oled->setCursor(0,0);
oled->display();
}
void Ssd1306Init(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
Ssd1306InitMode();
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void Ssd1306InitDriver()
{
if (!Settings.display_model) {
if (I2cDevice(OLED_ADDRESS1)) {
Settings.display_address[0] = OLED_ADDRESS1;
Settings.display_model = XDSP_02;
}
else if (I2cDevice(OLED_ADDRESS2)) {
Settings.display_address[0] = OLED_ADDRESS2;
Settings.display_model = XDSP_02;
}
}
if (XDSP_02 == Settings.display_model) {
oled = new Adafruit_SSD1306();
oled->begin(SSD1306_SWITCHCAPVCC, Settings.display_address[0]);
Ssd1306InitMode();
}
}
void Ssd1306PrintLogLine()
{
uint8_t last_row = Settings.display_rows -1;
oled->clearDisplay();
oled->setTextSize(Settings.display_size);
oled->setCursor(0,0);
for (byte i = 0; i < last_row; i++) {
strlcpy(oled_screen_buffer[i], oled_screen_buffer[i +1], sizeof(oled_screen_buffer[i]));
oled->println(oled_screen_buffer[i]);
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
strlcpy(oled_screen_buffer[last_row], disp_log_buffer[disp_log_buffer_ptr], sizeof(oled_screen_buffer[last_row]));
// Fill with spaces
byte len = sizeof(oled_screen_buffer[last_row]) - strlen(oled_screen_buffer[last_row]);
if (len) {
memset(oled_screen_buffer[last_row] + strlen(oled_screen_buffer[last_row]), 0x20, len);
oled_screen_buffer[last_row][sizeof(oled_screen_buffer[last_row])-1] = 0;
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), oled_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
oled->println(oled_screen_buffer[last_row]);
oled->display();
}
void Ssd1306PrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
Ssd1306PrintLogLine();
DisplayLogBufferPtrInc();
}
}
}
void Ssd1306OnOff()
{
Ssd1306DisplayOnOff(disp_power);
oled->display();
}
void Ssd1306Time()
{
char line[12];
oled->clearDisplay();
oled->setTextSize(2);
oled->setCursor(0, 0);
snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); // [ 12:34:56 ]
oled->println(line);
snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [01-02-2018]
oled->println(line);
oled->display();
}
void Ssd1306Refresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
switch (Settings.display_mode) {
case 1: // Time
Ssd1306Time();
break;
case 2: // Local
case 3: // Local
case 4: // Mqtt
case 5: // Mqtt
Ssd1306PrintLog();
break;
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp02(byte function)
{
boolean result = false;
if (i2c_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
Ssd1306InitDriver();
}
else if (XDSP_02 == Settings.display_model) {
if (!dsp_color) { dsp_color = WHITE; }
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
Ssd1306Init(dsp_init);
break;
case FUNC_DISPLAY_EVERY_SECOND:
Ssd1306Refresh();
break;
case FUNC_DISPLAY_POWER:
Ssd1306OnOff();
break;
case FUNC_DISPLAY_CLEAR:
Ssd1306Clear();
break;
case FUNC_DISPLAY_DRAW_HLINE:
oled->writeFastHLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_VLINE:
oled->writeFastVLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_LINE:
oled->writeLine(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_CIRCLE:
oled->drawCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_FILL_CIRCLE:
oled->fillCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_DRAW_RECTANGLE:
oled->drawRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_FILL_RECTANGLE:
oled->fillRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_FRAME:
oled->display();
break;
case FUNC_DISPLAY_FONT_SIZE:
oled->setTextSize(Settings.display_size);
break;
case FUNC_DISPLAY_DRAW_STRING:
Ssd1306DrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag);
break;
case FUNC_DISPLAY_ONOFF:
Ssd1306DisplayOnOff(dsp_on);
break;
case FUNC_DISPLAY_ROTATION:
oled->setRotation(dsp_rotation);
break;
}
}
}
return result;
}
#endif // USE_DISPLAY_SSD1306
#endif // USE_DISPLAY
#endif // USE_I2C

344
sonoff/xdsp_03_matrix.ino Normal file
View File

@ -0,0 +1,344 @@
/*
xdsp_03_matrix.ino - Display 8x8 matrix support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_I2C
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_MATRIX
#define XDSP_03 3
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h> // 8x8 Matrix
Adafruit_8x8matrix *matrix[8];
uint8_t mtx_matrices = 0;
uint8_t mtx_state = 0;
uint8_t mtx_counter = 0;
int16_t mtx_x = 0;
int16_t mtx_y = 0;
/*********************************************************************************************/
void MatrixWrite()
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->writeDisplay();
}
}
void MatrixClear()
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
}
MatrixWrite();
}
/*
void MatrixAll() // On based on Text value (1 - 6)
{
int value = atoi(Settings.text);
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
if (i < value) {
matrix[i]->fillRect(0,0, 8,8, LED_ON);
}
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
}
void MatrixAllOn()
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
matrix[i]->fillRect(0,0, 8,8, LED_ON);
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
}
*/
void MatrixFixed(char* txt)
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
matrix[i]->setCursor(-i *8, 0);
matrix[i]->print(txt);
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
}
void MatrixCenter(char* txt)
{
int offset;
int len = strlen(txt);
offset = (len < 8) ? offset = ((mtx_matrices *8) - (len *6)) / 2 : 0;
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
matrix[i]->setCursor(-(i *8)+offset, 0);
matrix[i]->print(txt);
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
}
void MatrixScrollLeft(char* txt, int loop)
{
switch (mtx_state) {
case 1:
mtx_state = 2;
// Horiz. position of text -- starts off right edge
mtx_x = 8 * mtx_matrices;
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), txt);
AddLog(LOG_LEVEL_DEBUG);
disp_refresh = Settings.display_refresh;
case 2:
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
matrix[i]->setCursor(mtx_x - i *8, 0);
matrix[i]->print(txt);
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
// Move text position left by 1 pixel.
mtx_x--;
int16_t len = strlen(txt);
if (mtx_x < -(len *6)) {
mtx_state = loop;
}
}
break;
}
}
void MatrixScrollUp(char* txt, int loop)
{
int wordcounter = 0;
char tmpbuf[200];
char *words[100];
// char separators[] = " ,.;:!?";
// char separators[] = " ";
// char separators[] = " /|";
char separators[] = " /";
switch (mtx_state) {
case 1:
mtx_state = 2;
// Vertical position of text -- starts off left bottom edge
mtx_y = 8;
mtx_counter = 0;
disp_refresh = Settings.display_refresh;
case 2:
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
strlcpy(tmpbuf, txt, sizeof(tmpbuf));
char *p = strtok(tmpbuf, separators);
while (p != NULL && wordcounter < 40) {
words[wordcounter++] = p;
p = strtok(NULL, separators);
}
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->clear();
for (byte j = 0; j < wordcounter; j++) {
matrix[i]->setCursor(-i *8, mtx_y + (j *8));
matrix[i]->println(words[j]);
}
matrix[i]->setBrightness(Settings.display_dimmer);
}
MatrixWrite();
if (((mtx_y %8) == 0) && mtx_counter) {
mtx_counter--;
} else {
mtx_y--; // Move text position up by 1 pixel.
mtx_counter = STATES * 1; // Hold text for 1 seconds
}
if (mtx_y < -(wordcounter *8)) {
mtx_state = loop;
}
}
break;
}
}
void MatrixBufferScroll(uint8_t direction)
{
if (disp_log_buffer_idx != disp_log_buffer_ptr) {
if (!mtx_state) {
mtx_state = 1;
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
if (direction) {
MatrixScrollUp(disp_log_buffer[disp_log_buffer_ptr], 0);
} else {
MatrixScrollLeft(disp_log_buffer[disp_log_buffer_ptr], 0);
}
if (!mtx_state) {
DisplayLogBufferPtrInc();
}
} else {
char disp_time[9]; // 13:45:43
snprintf_P(disp_time, sizeof(disp_time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
MatrixFixed(disp_time);
}
}
/*********************************************************************************************/
void MatrixInitMode()
{
for (byte i = 0; i < mtx_matrices; i++) {
matrix[i]->setRotation(1);
matrix[i]->setBrightness(Settings.display_dimmer);
matrix[i]->blinkRate(0); // 0 - 3
matrix[i]->setTextWrap(false); // Allow text to run off edges
// matrix[i]->setTextSize(Settings.display_size);
// matrix[i]->setTextColor(LED_RED);
matrix[i]->cp437(true);
}
MatrixClear();
}
void MatrixInit(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
MatrixInitMode();
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void MatrixInitDriver()
{
if (!Settings.display_model) {
if (I2cDevice(Settings.display_address[1])) {
Settings.display_model = XDSP_03;
}
}
if (XDSP_03 == Settings.display_model) {
mtx_state = 1;
for (mtx_matrices = 0; mtx_matrices < 8; mtx_matrices++) {
if (Settings.display_address[mtx_matrices]) {
matrix[mtx_matrices] = new Adafruit_8x8matrix();
matrix[mtx_matrices]->begin(Settings.display_address[mtx_matrices]);
} else {
break;
}
}
MatrixInitMode();
}
}
void MatrixOnOff()
{
if (!disp_power) {
MatrixClear();
}
}
void MatrixRefresh() // Every second
{
if (disp_power) {
switch (Settings.display_mode) {
case 0:
// MatrixScrollLeft(Settings.text, Settings.loop);
case 2: {
char disp_date[9]; // 24-04-17
snprintf_P(disp_date, sizeof(disp_date), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%02d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year -2000);
MatrixFixed(disp_date);
break;
}
case 3: {
char disp_day[10]; // Mon
snprintf_P(disp_day, sizeof(disp_day), PSTR("%d %s"), RtcTime.day_of_month, RtcTime.name_of_month);
MatrixCenter(disp_day);
break;
}
case 4:
MatrixBufferScroll(0);
break;
case 1: // Time and user text
case 5: // Time, user text and MQTT
MatrixBufferScroll(1);
break;
// case 8:
// MatrixAllOn();
// break;
// case 9:
// MatrixAll();
// break;
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp03(byte function)
{
boolean result = false;
if (i2c_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
MatrixInitDriver();
}
else if (XDSP_03 == Settings.display_model) {
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
MatrixInit(dsp_init);
break;
case FUNC_DISPLAY_EVERY_50_MSECOND:
MatrixRefresh();
break;
case FUNC_DISPLAY_POWER:
MatrixOnOff();
break;
}
}
}
return result;
}
#endif // USE_DISPLAY_MATRIX
#endif // USE_DISPLAY
#endif // USE_I2C

290
sonoff/xdsp_04_ili9341.ino Normal file
View File

@ -0,0 +1,290 @@
/*
xdsp_04_ili9341.ino - Display Tft Ili9341 support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends and Adafruit
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/>.
*/
#ifdef USE_SPI
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_ILI9341
#define XDSP_04 4
#define TFT_TOP 16
#define TFT_BOTTOM 16
#define TFT_FONT_WIDTH 6
#define TFT_FONT_HEIGTH 8 // Adafruit minimal font heigth pixels
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h> // TFT 320x240 and 480x320
Adafruit_ILI9341 *tft;
uint16_t tft_scroll;
/*********************************************************************************************/
void Ili9341Clear()
{
tft->fillScreen(ILI9341_BLACK);
tft->setCursor(0, 0);
}
void Ili9341DrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
{
uint16_t active_color = ILI9341_WHITE;
tft->setTextSize(Settings.display_size);
if (!flag) {
tft->setCursor(x, y);
} else {
tft->setCursor((x-1) * TFT_FONT_WIDTH * Settings.display_size, (y-1) * TFT_FONT_HEIGTH * Settings.display_size);
}
if (color) { active_color = color; }
tft->setTextColor(active_color, ILI9341_BLACK);
tft->println(str);
}
void Ili9341DisplayOnOff(uint8_t on)
{
// tft->showDisplay(on);
// tft->invertDisplay(on);
if (pin[GPIO_BACKLIGHT] < 99) {
pinMode(pin[GPIO_BACKLIGHT], OUTPUT);
digitalWrite(pin[GPIO_BACKLIGHT], on);
}
}
/*********************************************************************************************/
void DisplayTftPrint(byte size, char *txt)
{
uint16_t theight;
tft->setCursor(0, tft_scroll);
tft->setTextSize(size);
theight = size * TFT_FONT_HEIGTH;
tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), txt);
AddLog(LOG_LEVEL_DEBUG);
tft->print(txt);
tft_scroll += theight;
if (tft_scroll >= (tft->height() - TFT_BOTTOM)) {
tft_scroll = TFT_TOP;
}
tft->setScrollStart(tft_scroll);
}
/*********************************************************************************************/
void Ili9341InitMode()
{
tft->setRotation(0);
tft->invertDisplay(0);
tft->fillScreen(ILI9341_BLACK);
tft->setTextWrap(false); // Allow text to run off edges
tft->cp437(true);
if (!Settings.display_mode) {
tft->setCursor(0, 0);
tft->setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft->setTextSize(1);
} else {
tft->setScrollMargins(TFT_TOP, TFT_BOTTOM);
tft->setCursor(0, 0);
tft->setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft->setTextSize(2);
tft->println("HEADER");
tft_scroll = TFT_TOP;
}
}
void Ili9341Init(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
Ili9341InitMode();
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
break;
}
}
void Ili9341InitDriver()
{
if (!Settings.display_model) {
Settings.display_model = XDSP_04;
}
if (XDSP_04 == Settings.display_model) {
tft = new Adafruit_ILI9341(pin[GPIO_SPI_CS], pin[GPIO_SPI_DC]);
tft->begin();
Ili9341InitMode();
}
}
void Ili9341PrintLogLine()
{
tft->setTextColor(ILI9341_CYAN, ILI9341_BLACK); // Add background color to solve flicker
tft->setCursor(0, tft_scroll);
byte size = Settings.display_size;
tft->setTextSize(size);
uint16_t theight = size * TFT_FONT_HEIGTH;
tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK);
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), disp_log_buffer[disp_log_buffer_ptr]);
AddLog(LOG_LEVEL_DEBUG);
tft->print(disp_log_buffer[disp_log_buffer_ptr]);
tft_scroll += theight;
if (tft_scroll >= (tft->height() - TFT_BOTTOM)) {
tft_scroll = TFT_TOP;
}
tft->setScrollStart(tft_scroll);
}
void Ili9341PrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
Ili9341PrintLogLine();
DisplayLogBufferPtrInc();
}
}
}
void Ili9341OnOff()
{
Ili9341DisplayOnOff(disp_power);
}
void Ili9341Refresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
char tftdt[21];
char disp_time[9]; // 13:45:43
char disp_date4[11]; // 24-04-2017
snprintf_P(disp_time, sizeof(disp_time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
snprintf_P(disp_date4, sizeof(disp_date4), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year);
tft->setTextSize(2);
tft->setTextColor(ILI9341_YELLOW, ILI9341_BLACK); // Add background color to solve flicker
tft->setCursor(0, 0);
snprintf_P(tftdt, sizeof(tftdt), PSTR("%s %s"), disp_date4, disp_time);
tft->print(tftdt);
switch (Settings.display_mode) {
case 2: // Local
case 3: // Local
case 4: // Mqtt
case 5: // Mqtt
Ili9341PrintLog();
break;
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp04(byte function)
{
boolean result = false;
if (spi_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
Ili9341InitDriver();
}
else if (XDSP_04 == Settings.display_model) {
if (!dsp_color) { dsp_color = ILI9341_WHITE; }
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
Ili9341Init(dsp_init);
break;
case FUNC_DISPLAY_EVERY_SECOND:
Ili9341Refresh();
break;
case FUNC_DISPLAY_POWER:
Ili9341OnOff();
break;
case FUNC_DISPLAY_CLEAR:
Ili9341Clear();
break;
case FUNC_DISPLAY_DRAW_HLINE:
tft->writeFastHLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_VLINE:
tft->writeFastVLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_LINE:
tft->writeLine(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_CIRCLE:
tft->drawCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_FILL_CIRCLE:
tft->fillCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_DRAW_RECTANGLE:
tft->drawRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_FILL_RECTANGLE:
tft->fillRect(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
// case FUNC_DISPLAY_DRAW_FRAME:
// oled->display();
// break;
case FUNC_DISPLAY_FONT_SIZE:
tft->setTextSize(Settings.display_size);
break;
case FUNC_DISPLAY_DRAW_STRING:
Ili9341DrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag);
break;
case FUNC_DISPLAY_ONOFF:
Ili9341DisplayOnOff(dsp_on);
break;
case FUNC_DISPLAY_ROTATION:
tft->setRotation(dsp_rotation);
break;
}
}
}
return result;
}
#endif // USE_DISPLAY_ILI9341
#endif // USE_DISPLAY
#endif // USE_SPI

250
sonoff/xdsp_05_epaper.ino Normal file
View File

@ -0,0 +1,250 @@
/*
xdsp_05_epaper.ino - Display e-paper support for Sonoff-Tasmota
Copyright (C) 2018 Theo Arends, Gerhard Mutz and Waveshare
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/>.
*/
#ifdef USE_SPI
#ifdef USE_DISPLAY
#ifdef USE_DISPLAY_EPAPER
#define XDSP_05 5
#define COLORED 0
#define UNCOLORED 1
// using font 8 is opional (num=3)
// very badly readable, but may be useful for graphs
#define USE_TINY_FONT
#include <epd2in9.h>
#include <epdpaint.h>
unsigned char image[(EPD_HEIGHT * EPD_WIDTH) / 8];
Paint paint(image, EPD_WIDTH, EPD_HEIGHT); // width should be the multiple of 8
Epd epd;
sFONT *selected_font;
/*********************************************************************************************/
void EpdInitMode()
{
// whiten display with full update
epd.Init(lut_full_update);
epd.ClearFrameMemory(0xFF); // bit set = white, bit reset = black
epd.DisplayFrame();
delay(3000);
// switch to partial update
epd.Init(lut_partial_update);
// Clear image memory
epd.ClearFrameMemory(0xFF); // bit set = white, bit reset = black
epd.DisplayFrame();
delay(500);
selected_font = &Font12;
/*
// Welcome text
paint.SetRotate(ROTATE_90);
paint.Clear(UNCOLORED);
paint.DrawStringAt(50, 50, "Waveshare E-Paper Display!", selected_font, COLORED);
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
epd.DisplayFrame();
delay(1000);
*/
paint.Clear(UNCOLORED);
}
void EpdInitPartial()
{
epd.Init(lut_partial_update);
//paint.Clear(UNCOLORED);
epd.DisplayFrame();
delay(500);
}
void EpdInitFull()
{
epd.Init(lut_full_update);
//paint.Clear(UNCOLORED);
//epd.ClearFrameMemory(0xFF);
epd.DisplayFrame();
delay(3000);
}
void EpdInit(uint8_t mode)
{
switch(mode) {
case DISPLAY_INIT_MODE:
EpdInitMode();
break;
case DISPLAY_INIT_PARTIAL:
EpdInitPartial();
break;
case DISPLAY_INIT_FULL:
EpdInitFull();
break;
}
}
void EpdInitDriver()
{
if (!Settings.display_model) {
Settings.display_model = XDSP_05;
}
if (XDSP_05 == Settings.display_model) {
epd.cs_pin = pin[GPIO_SPI_CS];
epd.mosi_pin = pin[GPIO_SPI_MOSI]; // 13
epd.sclk_pin = pin[GPIO_SPI_CLK]; // 14
EpdInitMode();
}
}
/*********************************************************************************************/
void EpdClear()
{
paint.Clear(UNCOLORED);
}
void EpdSetFontorSize(uint8_t font)
{
if (1 == font) {
selected_font = &Font12;
} else {
#ifdef USE_TINY_FONT
if (2 == font) {
selected_font = &Font24;
} else {
selected_font = &Font8;
}
#else
selected_font = &Font24;
#endif
}
}
void EpdDrawStringAt(uint16_t x, uint16_t y, char *str, uint8_t color, uint8_t flag)
{
if (!flag) {
paint.DrawStringAt(x, y, str, selected_font, color);
} else {
paint.DrawStringAt((x-1) * selected_font->Width, (y-1) * selected_font->Height, str, selected_font, color);
}
}
// not needed
void EpdDisplayOnOff(uint8_t on)
{
}
void EpdOnOff()
{
EpdDisplayOnOff(disp_power);
}
void EpdRefresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
boolean Xdsp05(byte function)
{
boolean result = false;
if (spi_flg) {
if (FUNC_DISPLAY_INIT_DRIVER == function) {
EpdInitDriver();
}
else if (XDSP_04 == Settings.display_model) {
if (!dsp_color) { dsp_color = COLORED; }
switch (function) {
case FUNC_DISPLAY_MODEL:
result = true;
break;
case FUNC_DISPLAY_INIT:
EpdInit(dsp_init);
break;
case FUNC_DISPLAY_EVERY_SECOND:
EpdRefresh();
break;
case FUNC_DISPLAY_POWER:
EpdOnOff();
break;
case FUNC_DISPLAY_CLEAR:
EpdClear();
break;
case FUNC_DISPLAY_DRAW_HLINE:
paint.DrawHorizontalLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_VLINE:
paint.DrawVerticalLine(dsp_x, dsp_y, dsp_len, dsp_color);
break;
case FUNC_DISPLAY_DRAW_LINE:
paint.DrawLine(dsp_x, dsp_y, dsp_x2, dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_CIRCLE:
paint.DrawCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_FILL_CIRCLE:
paint.DrawFilledCircle(dsp_x, dsp_y, dsp_rad, dsp_color);
break;
case FUNC_DISPLAY_DRAW_RECTANGLE:
paint.DrawRectangle(dsp_x, dsp_y, dsp_x + dsp_x2, dsp_y + dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_FILL_RECTANGLE:
paint.DrawFilledRectangle(dsp_x, dsp_y, dsp_x + dsp_x2, dsp_y + dsp_y2, dsp_color);
break;
case FUNC_DISPLAY_DRAW_FRAME:
epd.SetFrameMemory(paint.GetImage(), 0, 0, paint.GetWidth(), paint.GetHeight());
epd.DisplayFrame();
break;
case FUNC_DISPLAY_FONT_SIZE:
EpdSetFontorSize(Settings.display_size);
break;
case FUNC_DISPLAY_DRAW_STRING:
EpdDrawStringAt(dsp_x, dsp_y, dsp_str, dsp_color, dsp_flag);
break;
case FUNC_DISPLAY_ONOFF:
EpdDisplayOnOff(dsp_on);
break;
case FUNC_DISPLAY_ROTATION:
paint.SetRotate(dsp_rotation);
break;
}
}
}
return result;
}
#endif // USE_DISPLAY_EPAPER
#endif // USE_DISPLAY
#endif // USE_SPI

125
sonoff/xdsp_interface.ino Normal file
View File

@ -0,0 +1,125 @@
/*
xdsp_interface.ino - Display interface support for Sonoff-Tasmota
Copyright (C) 2018 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/>.
*/
boolean (* const xdsp_func_ptr[])(byte) PROGMEM = { // Display Function Pointers
#ifdef XDSP_01
&Xdsp01,
#endif
#ifdef XDSP_02
&Xdsp02,
#endif
#ifdef XDSP_03
&Xdsp03,
#endif
#ifdef XDSP_04
&Xdsp04,
#endif
#ifdef XDSP_05
&Xdsp05,
#endif
#ifdef XDSP_06
&Xdsp06,
#endif
#ifdef XDSP_07
&Xdsp07,
#endif
#ifdef XDSP_08
&Xdsp08,
#endif
#ifdef XDSP_09
&Xdsp09,
#endif
#ifdef XDSP_10
&Xdsp10,
#endif
#ifdef XDSP_11
&Xdsp11,
#endif
#ifdef XDSP_12
&Xdsp12,
#endif
#ifdef XDSP_13
&Xdsp13,
#endif
#ifdef XDSP_14
&Xdsp14,
#endif
#ifdef XDSP_15
&Xdsp15,
#endif
#ifdef XDSP_16
&Xdsp16
#endif
};
const uint8_t xdsp_present = sizeof(xdsp_func_ptr) / sizeof(xdsp_func_ptr[0]); // Number of drivers found
/*********************************************************************************************\
* Function call to all xdsp
*
* FUNC_DISPLAY_INIT_DRIVER
* FUNC_DISPLAY_INIT
* FUNC_DISPLAY_EVERY_50_MSECOND
* FUNC_DISPLAY_EVERY_SECOND
* FUNC_DISPLAY_POWER
* FUNC_DISPLAY_CLEAR
* FUNC_DISPLAY_DRAW_FRAME
* FUNC_DISPLAY_DRAW_HLINE
* FUNC_DISPLAY_DRAW_VLINE
* FUNC_DISPLAY_DRAW_CIRCLE
* FUNC_DISPLAY_FILL_CIRCLE
* FUNC_DISPLAY_DRAW_RECTANGLE
* FUNC_DISPLAY_FILL_RECTANGLE
* FUNC_DISPLAY_FONT_SIZE
* FUNC_DISPLAY_ROTATION
* FUNC_DISPLAY_DRAW_STRING
* FUNC_DISPLAY_ONOFF
\*********************************************************************************************/
uint8_t XdspPresent()
{
return xdsp_present;
}
boolean XdspCall(byte Function)
{
boolean result = false;
for (byte x = 0; x < xdsp_present; x++) {
result = xdsp_func_ptr[x](Function);
if (result) break;
}
return result;
}