Add STM32 and generic processor support

This commit is contained in:
Bodmer
2020-01-11 23:32:10 +00:00
parent 8342507233
commit 7f53a571f4
21 changed files with 4846 additions and 48 deletions

View File

@@ -35,7 +35,7 @@ void TFT_eSPI_Button::initButtonUL(
strncpy(_label, label, 9);
}
void TFT_eSPI_Button::drawButton(boolean inverted) {
void TFT_eSPI_Button::drawButton(bool inverted) {
uint16_t fill, outline, text;
if(!inverted) {
@@ -57,20 +57,20 @@ void TFT_eSPI_Button::drawButton(boolean inverted) {
uint8_t tempdatum = _gfx->getTextDatum();
_gfx->setTextDatum(MC_DATUM);
_gfx->drawString(_label, _x1 + (_w/2), _y1 + (_h/2));
_gfx->drawString(_label, _x1 + (_w/2), _y1 + (_h/2) -4);
_gfx->setTextDatum(tempdatum);
}
boolean TFT_eSPI_Button::contains(int16_t x, int16_t y) {
bool TFT_eSPI_Button::contains(int16_t x, int16_t y) {
return ((x >= _x1) && (x < (_x1 + _w)) &&
(y >= _y1) && (y < (_y1 + _h)));
}
void TFT_eSPI_Button::press(boolean p) {
void TFT_eSPI_Button::press(bool p) {
laststate = currstate;
currstate = p;
}
boolean TFT_eSPI_Button::isPressed() { return currstate; }
boolean TFT_eSPI_Button::justPressed() { return (currstate && !laststate); }
boolean TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }
bool TFT_eSPI_Button::isPressed() { return currstate; }
bool TFT_eSPI_Button::justPressed() { return (currstate && !laststate); }
bool TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }

View File

@@ -18,13 +18,13 @@ class TFT_eSPI_Button {
void initButtonUL(TFT_eSPI *gfx, int16_t x1, int16_t y1,
uint16_t w, uint16_t h, uint16_t outline, uint16_t fill,
uint16_t textcolor, char *label, uint8_t textsize);
void drawButton(boolean inverted = false);
boolean contains(int16_t x, int16_t y);
void drawButton(bool inverted = false);
bool contains(int16_t x, int16_t y);
void press(boolean p);
boolean isPressed();
boolean justPressed();
boolean justReleased();
void press(bool p);
bool isPressed();
bool justPressed();
bool justReleased();
private:
TFT_eSPI *_gfx;
@@ -34,5 +34,5 @@ class TFT_eSPI_Button {
uint16_t _outlinecolor, _fillcolor, _textcolor;
char _label[10];
boolean currstate, laststate;
bool currstate, laststate;
};

View File

@@ -0,0 +1,259 @@
////////////////////////////////////////////////////
// TFT_eSPI generic driver functions //
////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Global variables
////////////////////////////////////////////////////////////////////////////////////////
// Select the SPI port to use
SPIClass& spi = SPI;
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: tft_Read_8
** Description: Bit bashed SPI to read bidirectional SDA line
***************************************************************************************/
uint8_t TFT_eSPI::tft_Read_8(void)
{
uint8_t ret = 0;
for (uint8_t i = 0; i < 8; i++) { // read results
ret <<= 1;
SCLK_L;
if (digitalRead(TFT_MOSI)) ret |= 1;
SCLK_H;
}
return ret;
}
/***************************************************************************************
** Function name: beginSDA
** Description: Detach SPI from pin to permit software SPI
***************************************************************************************/
void TFT_eSPI::begin_SDA_Read(void)
{
// Release configured SPI port for SDA read
spi.end();
}
/***************************************************************************************
** Function name: endSDA
** Description: Attach SPI pins after software SPI
***************************************************************************************/
void TFT_eSPI::end_SDA_Read(void)
{
// Configure SPI port ready for next TFT access
spi.begin();
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // #if defined (TFT_SDA_READ)
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_PARALLEL_8_BIT) // Code for generic (i.e. any) processor
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for generic processor and parallel display
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
while (len>1) {tft_Write_32D(color); len-=2;}
if (len) {tft_Write_16(color);}
}
/***************************************************************************************
** Function name: pushPixels - for gereric processor and parallel display
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in;
if(_swapBytes) {
while (len>1) {tft_Write_16(*data); data++; tft_Write_16(*data); data++; len -=2;}
if (len) {tft_Write_16(*data);}
return;
}
while (len>1) {tft_Write_16S(*data); data++; tft_Write_16S(*data); data++; len -=2;}
if (len) {tft_Write_16S(*data);}
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Set parallel bus to INPUT or OUTPUT
***************************************************************************************/
void TFT_eSPI::busDir(uint32_t mask, uint8_t mode)
{
// mask is unused for generic processor
// Arduino native functions suited well to a generic driver
pinMode(TFT_D0, mode);
pinMode(TFT_D1, mode);
pinMode(TFT_D2, mode);
pinMode(TFT_D3, mode);
pinMode(TFT_D4, mode);
pinMode(TFT_D5, mode);
pinMode(TFT_D6, mode);
pinMode(TFT_D7, mode);
return;
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Faster GPIO pin input/output switch
***************************************************************************************/
void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode)
{
// No fast port based generic approach available
}
/***************************************************************************************
** Function name: read byte - supports class functions
** Description: Read a byte - parallel bus only
***************************************************************************************/
uint8_t TFT_eSPI::readByte(void)
{
uint8_t b = 0;
busDir(0, INPUT);
digitalWrite(TFT_RD, LOW);
b |= digitalRead(TFT_D0) << 0;
b |= digitalRead(TFT_D1) << 1;
b |= digitalRead(TFT_D2) << 2;
b |= digitalRead(TFT_D3) << 3;
b |= digitalRead(TFT_D4) << 4;
b |= digitalRead(TFT_D5) << 5;
b |= digitalRead(TFT_D6) << 6;
b |= digitalRead(TFT_D7) << 7;
digitalWrite(TFT_RD, HIGH);
busDir(0, OUTPUT);
return b;
}
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe ############# UNTESTED ###################
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32 or STM32 RPi TFT
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
if(len) { tft_Write_16(color); len--; }
while(len--) {WR_L; WR_H;}
}
/***************************************************************************************
** Function name: pushPixels - for ESP32 or STM32 RPi TFT
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
{
uint16_t *data = (uint16_t*)data_in;
if (_swapBytes) while ( len-- ) {tft_Write_16S(*data); data++;}
else while ( len-- ) {tft_Write_16(*data); data++;}
}
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (ILI9488_DRIVER) // For 24 bit SPI colour TFT ############# UNTESTED ###################
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for STM32 and 3 byte RGB display
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
{
// Split out the colours
uint8_t r = (color & 0xF800)>>8;
uint8_t g = (color & 0x07E0)>>3;
uint8_t b = (color & 0x001F)<<3;
while ( len-- ) {tft_Write_8(r); tft_Write_8(g); tft_Write_8(b);}
}
/***************************************************************************************
** Function name: pushPixels - for STM32 and 3 byte RGB display
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in;
if (_swapBytes) {
while ( len-- ) {
uint16_t color = *data >> 8 | *data << 8;
tft_Write_8((color & 0xF800)>>8);
tft_Write_8((color & 0x07E0)>>3);
tft_Write_8((color & 0x001F)<<3);
data++;
}
}
else {
while ( len-- ) {
tft_Write_8((*data & 0xF800)>>8);
tft_Write_8((*data & 0x07E0)>>3);
tft_Write_8((*data & 0x001F)<<3);
data++;
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
#else // Standard SPI 16 bit colour TFT All Tested
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for STM32
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
while ( len-- ) {tft_Write_16(color);}
}
/***************************************************************************************
** Function name: pushPixels - for STM32
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in;
if (_swapBytes) while ( len-- ) {tft_Write_16(*data); data++;}
else while ( len-- ) {tft_Write_16S(*data); data++;}
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // End of display interface specific functions
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// DMA FUNCTIONS All tested on STM32F767
////////////////////////////////////////////////////////////////////////////////////////
// Placeholder for DMA functions
/*
Minimal function set to support DMA:
bool TFT_eSPI::initDMA(void)
void TFT_eSPI::deInitDMA(void)
bool TFT_eSPI::dmaBusy(void)
void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image)
*/

View File

@@ -0,0 +1,155 @@
////////////////////////////////////////////////////
// TFT_eSPI generic driver functions //
////////////////////////////////////////////////////
#ifndef _TFT_eSPI_GENERICH_
#define _TFT_eSPI_GENERICH_
// Processor ID reported by getSetup()
#define PROCESSOR_ID 0x0000
// Include processor specific header
// None
// Processor specific code used by SPI bus transaction startWrite and endWrite functions
#define SET_SPI_WRITE_MODE // Not used
#define SET_SPI_READ_MODE // Not used
// Code to check if DMA is busy, used by SPI bus transaction startWrite and endWrite functions
#define DMA_BUSY_CHECK // Not used so leave blank
// To be safe, SUPPORT_TRANSACTIONS is assumed mandatory
#if !defined (SUPPORT_TRANSACTIONS)
#define SUPPORT_TRANSACTIONS
#endif
// Initialise processor specific SPI functions, used by init()
#define INIT_TFT_DATA_BUS
// If smooth fonts are enabled the filing system may need to be loaded
#ifdef SMOOTH_FONT
// Call up the filing system for the anti-aliased fonts
//#define FS_NO_GLOBALS
//#include <FS.h>
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the DC (TFT Data/Command or Register Select (RS))pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifndef TFT_DC
#define DC_C // No macro allocated so it generates no code
#define DC_D // No macro allocated so it generates no code
#else
#define DC_C digitalWrite(TFT_DC, LOW)
#define DC_D digitalWrite(TFT_DC, HIGH)
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the CS (TFT chip select) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifndef TFT_CS
#define CS_L // No macro allocated so it generates no code
#define CS_H // No macro allocated so it generates no code
#else
#define CS_L digitalWrite(TFT_CS, LOW)
#define CS_H digitalWrite(TFT_CS, HIGH)
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the WR (TFT Write) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TFT_WR
#define WR_L digitalWrite(TFT_WR, LOW)
#define WR_H digitalWrite(TFT_WR, HIGH)
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the touch screen chip select pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if !defined TOUCH_CS || (TOUCH_CS < 0)
#define T_CS_L // No macro allocated so it generates no code
#define T_CS_H // No macro allocated so it generates no code
#else
#define T_CS_L digitalWrite(TOUCH_CS, LOW)
#define T_CS_H digitalWrite(TOUCH_CS, HIGH)
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Make sure TFT_MISO is defined if not used to avoid an error message
////////////////////////////////////////////////////////////////////////////////////////
#ifndef TFT_MISO
#define TFT_MISO -1
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to an ILI9488 TFT
////////////////////////////////////////////////////////////////////////////////////////
#if defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB
// Write 8 bits to TFT
#define tft_Write_8(C) spi.transfer(C)
// Convert 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16(C) spi.transfer(((C) & 0xF800)>>8); \
spi.transfer(((C) & 0x07E0)>>3); \
spi.transfer(((C) & 0x001F)<<3)
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16S(C) spi.transfer((C) & 0xF8); \
spi.transfer(((C) & 0xE000)>>11 | ((C) & 0x07)<<5); \
spi.transfer(((C) & 0x1F00)>>5)
// Write 32 bits to TFT
#define tft_Write_32(C) spi.transfer16((C)>>16); spi.transfer16((uint16_t)(C))
// Write two address coordinates
#define tft_Write_32C(C,D) spi.transfer16(C); spi.transfer16(D)
// Write same value twice
#define tft_Write_32D(C) spi.transfer16(C); spi.transfer16(C)
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to other displays
////////////////////////////////////////////////////////////////////////////////////////
#else
#if defined (RPI_ILI9486_DRIVER) // RPi TFT always needs 16 bit transfers
#define tft_Write_8(C) spi.transfer(0); spi.transfer(C)
#else
#ifdef __AVR__ // AVR processors do not have 16 bit transfer
#define tft_Write_8(C) {SPDR=(C); while (!(SPSR&_BV(SPIF)));}
#define tft_Write_16(C) tft_Write_8((uint8_t)((C)>>8));tft_Write_8((uint8_t)((C)>>0))
#define tft_Write_16S(C) tft_Write_8((uint8_t)((C)>>0));tft_Write_8((uint8_t)((C)>>8))
#else
#define tft_Write_8(C) spi.transfer(C)
#define tft_Write_16(C) spi.transfer16(C)
#define tft_Write_16S(C) spi.transfer16(((C)>>8) | ((C)<<8))
#endif // AVR
#endif // RPI_ILI9486_DRIVER
#define tft_Write_32(C) \
tft_Write_16((uint16_t) ((C)>>16)); \
tft_Write_16((uint16_t) ((C)>>0))
#define tft_Write_32C(C,D) \
tft_Write_16((uint16_t) (C)); \
tft_Write_16((uint16_t) (D))
#define tft_Write_32D(C) \
tft_Write_16((uint16_t) (C)); \
tft_Write_16((uint16_t) (C))
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to read from display using SPI or software SPI
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_SDA_READ)
// Use a bit banged function call for STM32 and bi-directional SDA pin
#define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8(void);
#define SCLK_L digitalWrite(TFT_SCLK, LOW)
#define SCLK_H digitalWrite(TFT_SCLK, LOW)
#else
// Use a SPI read transfer
#define tft_Read_8() spi.transfer(0)
#endif
#endif // Header end

542
Processors/TFT_eSPI_STM32.c Normal file
View File

@@ -0,0 +1,542 @@
////////////////////////////////////////////////////
// TFT_eSPI Driver functions for STM32 processors //
////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Global variables
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_PARALLEL_8_BIT)
// No globals
#else
// Use STM32 default SPI port
SPIClass& spi = SPI;
// SPI HAL peripheral handle
SPI_HandleTypeDef spiHal;
#endif
#ifdef STM32_DMA
// DMA HAL handle
DMA_HandleTypeDef dmaHal;
#endif
// Buffer for SPI transmit byte padding and byte order manipulation
uint8_t spiBuffer[8];
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_SDA_READ) && !defined (TFT_PARALLEL_8_BIT)
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************############# UNTESTED ###################
** Function name: tft_Read_8
** Description: STM32 software SPI to read bidirectional SDA line
***************************************************************************************/
uint8_t TFT_eSPI::tft_Read_8(void)
{
uint8_t ret = 0;
uint32_t reg = 0;
for (uint8_t i = 0; i < 8; i++) { // read results
ret <<= 1;
SCLK_L;
if (digitalRead(TFT_MOSI)) ret |= 1;
SCLK_H;
}
return ret;
}
/***************************************************************************************############# UNTESTED ###################
** Function name: beginSDA
** Description: Detach SPI from pin to permit software SPI
***************************************************************************************/
void TFT_eSPI::begin_SDA_Read(void)
{
// Release configured SPI port for SDA read
spi.end();// Code missing here! <<<<<<<<<<<<<<Missing code<<<<<<<<<<<<<<<<<
}
/***************************************************************************************############# UNTESTED ###################
** Function name: endSDA
** Description: Attach SPI pins after software SPI
***************************************************************************************/
void TFT_eSPI::end_SDA_Read(void)
{
// Configure SPI port ready for next TFT access
spi.begin();// Code missing here! <<<<<<<<<<<<<<Missing code<<<<<<<<<<<<<<<<<
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // #if defined (TFT_SDA_READ)
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_PARALLEL_8_BIT) // Code for STM32 8 bit parallel
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32 and parallel display
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len){
// Loop unrolling improves speed dramtically graphics test 0.634s => 0.374s
while (len>31) {
// 32D macro writes 16 bits twice
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
len-=32;
}
while (len>7) {
tft_Write_32D(color); tft_Write_32D(color);
tft_Write_32D(color); tft_Write_32D(color);
len-=8;
}
while (len--) {tft_Write_16(color);}
}
/***************************************************************************************
** Function name: pushPixels - for ESP32 and parallel display
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len){
uint16_t *data = (uint16_t*)data_in;
if(_swapBytes) {
while (len>1) {tft_Write_16(*data); data++; tft_Write_16(*data); data++; len -=2;}
if (len) {tft_Write_16(*data);}
return;
}
while (len>1) {tft_Write_16S(*data); data++; tft_Write_16S(*data); data++; len -=2;}
if (len) {tft_Write_16S(*data);}
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Set parallel bus to INPUT or OUTPUT
***************************************************************************************/
void TFT_eSPI::busDir(uint32_t mask, uint8_t mode)
{
// Use pinMode() for each pin at least one first to enable clocks etc
// Now we can use a minimal set of register changes
if (mode == OUTPUT) {
LL_GPIO_SetPinMode(D0_PIN_PORT, D0_PIN_BIT, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(D1_PIN_PORT, D1_PIN_BIT, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(D2_PIN_PORT, D2_PIN_BIT, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(D3_PIN_PORT, D3_PIN_BIT, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(D4_PIN_PORT, D4_PIN_BIT, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(D5_PIN_PORT, D5_PIN_BIT, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(D6_PIN_PORT, D6_PIN_BIT, LL_GPIO_MODE_OUTPUT);
LL_GPIO_SetPinMode(D7_PIN_PORT, D7_PIN_BIT, LL_GPIO_MODE_OUTPUT);
}
else {
LL_GPIO_SetPinMode(D0_PIN_PORT, D0_PIN_BIT, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinMode(D1_PIN_PORT, D1_PIN_BIT, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinMode(D2_PIN_PORT, D2_PIN_BIT, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinMode(D3_PIN_PORT, D3_PIN_BIT, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinMode(D4_PIN_PORT, D4_PIN_BIT, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinMode(D5_PIN_PORT, D5_PIN_BIT, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinMode(D6_PIN_PORT, D6_PIN_BIT, LL_GPIO_MODE_INPUT);
LL_GPIO_SetPinMode(D7_PIN_PORT, D7_PIN_BIT, LL_GPIO_MODE_INPUT);
}
}
/***************************************************************************************
** Function name: GPIO direction control - supports class functions
** Description: Set STM32 GPIO pin to input or output (set high) ASAP
***************************************************************************************/
void TFT_eSPI::gpioMode(uint8_t gpio, uint8_t mode)
{
PinName pn = digitalPinToPinName(gpio);
// Push-pull output with no pullup
if (mode == OUTPUT) pin_function(pn, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0));
// Input with pullup
else pin_function(pn, STM_PIN_DATA(STM_MODE_INPUT, GPIO_PULLUP, 0));
}
/***************************************************************************************############# UNTESTED ###################
** Function name: read byte - supports class functions
** Description: Read a byte - parallel bus only
***************************************************************************************/
uint8_t TFT_eSPI::readByte(void)
{
uint8_t b = 0;
RD_L;
b = RD_TFT_D0 | RD_TFT_D0 | RD_TFT_D0 | RD_TFT_D0; //Delay for bits to settle
b = RD_TFT_D0 | RD_TFT_D1 | RD_TFT_D2 | RD_TFT_D3;
b |= RD_TFT_D4 | RD_TFT_D5 | RD_TFT_D6 | RD_TFT_D7;
RD_H;
return b;
}
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (RPI_WRITE_STROBE) // For RPi TFT with write strobe ############# UNTESTED ###################
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for ESP32 or STM32 RPi TFT
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
{
if(len) { tft_Write_16(color); len--; }
while(len--) {WR_L; WR_H;}
}
/***************************************************************************************
** Function name: pushPixels - for ESP32 or STM32 RPi TFT
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
{
uint16_t *data = (uint16_t*)data_in;
if (_swapBytes) while ( len-- ) { tft_Write_16S(*data); data++;}
else while ( len-- ) {tft_Write_16(*data); data++;}
}
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (ILI9488_DRIVER) // For 24 bit colour TFT ############# UNTESTED ###################
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for STM32 and 3 byte RGB display
** Description: Write a block of pixels of the same colour
***************************************************************************************/
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
{
// Split out the colours
spiBuffer[0] = (color & 0xF800)>>8; // Red
spiBuffer[1] = (color & 0x07E0)>>3; // Green
spiBuffer[2] = (color & 0x001F)<<3; // Blue
while (len--) HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY);
}
/***************************************************************************************
** Function name: pushPixels - for STM32 and 3 byte RGB display
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
{
uint16_t *data = (uint16_t*)data_in;
if(_swapBytes) {
while ( len-- ) {
// Split out the colours
spiBuffer[0] = (*data & 0xF8); // Red
spiBuffer[1] = (*data & 0xE000)>>11 | (*data & 0x07)<<5; // Green
spiBuffer[2] = (*data & 0x1F00)>>5; // Blue
data++;
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY);
}
}
else {
while ( len-- ) {
// Split out the colours
spiBuffer[0] = (*data & 0xF800)>>8; // Red
spiBuffer[1] = (*data & 0x07E0)>>3; // Green
spiBuffer[2] = (*data & 0x001F)<<3; // Blue
data++;
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, HAL_MAX_DELAY);
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
#else // Standard SPI 16 bit colour TFT All Tested
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: pushBlock - for STM32
** Description: Write a block of pixels of the same colour
***************************************************************************************/
#define BUF_SIZE 480
void TFT_eSPI::pushBlock(uint16_t color, uint32_t len)
{
uint16_t col[BUF_SIZE];
// Always using swapped bytes is a peculiarity of this function...
uint16_t swapColor = color>>8 | color<<8;
if (len<BUF_SIZE) {
for (uint32_t i = 0; i < len; i++) col[i] = swapColor;
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY);
return;
}
for (uint32_t i = 0; i < BUF_SIZE; i++) col[i] = swapColor;
do {
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, BUF_SIZE<<1, HAL_MAX_DELAY);
len -= BUF_SIZE;
} while ( len>=BUF_SIZE ) ;
// Send remaining pixels
if (len) HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY); //*/
}
/***************************************************************************************
** Function name: pushPixels - for STM32
** Description: Write a sequence of pixels
***************************************************************************************/
void TFT_eSPI::pushPixels(const void* data_in, uint32_t len)
{
uint16_t *data = (uint16_t*)data_in;
if(_swapBytes) {
uint16_t col[BUF_SIZE]; // Buffer for swapped bytes
while ( len>=BUF_SIZE ) {
for (uint32_t i = 0; i < BUF_SIZE; i++) { col[i] = (*data>>8) | (*data<<8); data++; }
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, BUF_SIZE<<1, HAL_MAX_DELAY);
len -= BUF_SIZE;
}
for (uint32_t i = 0; i < len; i++) { col[i] = (*data>>8) | (*data<<8); data++; }
HAL_SPI_Transmit(&spiHal, (uint8_t*)col, len<<1, HAL_MAX_DELAY);
}
else {
// HAL byte count for transmit is only 16 bits maximum so to avoid this constraint
// transfers of small blocks are performed until HAL capacity is reached.
while(len>0x7FFF) { // Transfer 16 bit pixels in blocks if len*2 over 65534 bytes
HAL_SPI_Transmit(&spiHal, (uint8_t*)data, 0x800<<1, HAL_MAX_DELAY);
len -= 0x800; data+= 0x800; // Arbitrarily use 2KByte blocks
}
// Send remaining pixels (max 65534 bytes)
HAL_SPI_Transmit(&spiHal, (uint8_t*)data, len<<1, HAL_MAX_DELAY);
}
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // End of display interface specific functions
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
#if defined STM32_DMA && !defined (TFT_PARALLEL_8_BIT) // DMA FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************************
** Function name: dmaBusy
** Description: Check if DMA is busy (usefully non-blocking!)
***************************************************************************************/
// Use "while(tft.dmaBusy());" in sketch for a blocking wait for DMA to complete
// or "while( tft.dmaBusy() ) {Do-something-useful;}"
bool TFT_eSPI::dmaBusy(void)
{
//return (dmaHal.State == HAL_DMA_STATE_BUSY); // Do not use, SPI may still be busy
return (spiHal.State == HAL_SPI_STATE_BUSY_TX); // Check if SPI Tx is busy
}
/***************************************************************************************
** Function name: pushImageDMA
** Description: Push pixels to TFT (len must be less than 32767)
***************************************************************************************/
// This will byte swap the original image if setSwapBytes(true) was called by sketch.
void TFT_eSPI::pushPixelsDMA(uint16_t* image, uint32_t len)
{
if (len == 0) return;
// Wait for any current DMA transaction to end
while (dmaHal.State == HAL_DMA_STATE_BUSY);
if(_swapBytes) {
for (uint32_t i = 0; i < len; i++) (image[i] = image[i] << 8 | image[i] >> 8);
}
HAL_SPI_Transmit_DMA(&spiHal, (uint8_t*)image, len << 1);
}
/***************************************************************************************
** Function name: pushImageDMA
** Description: Push image to a window (w*h must be less than 65536)
***************************************************************************************/
// This will clip and also swap bytes if setSwapBytes(true) was called by sketch
void TFT_eSPI::pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* image, uint16_t* buffer)
{
if ((x >= _width) || (y >= _height)) return;
int32_t dx = 0;
int32_t dy = 0;
int32_t dw = w;
int32_t dh = h;
if (x < 0) { dw += x; dx = -x; x = 0; }
if (y < 0) { dh += y; dy = -y; y = 0; }
if ((x + dw) > _width ) dw = _width - x;
if ((y + dh) > _height) dh = _height - y;
if (dw < 1 || dh < 1) return;
if (buffer == nullptr) buffer = image;
uint32_t len = dw*dh;
// Wait for any current DMA transaction to end
while (dmaHal.State == HAL_DMA_STATE_BUSY);
// If image is clipped, copy pixels into a contiguous block
if ( (dw != w) || (dh != h) ) {
if(_swapBytes) {
for (uint32_t yb = 0; yb < dh; yb++) {
for (uint32_t xb = 0; xb < dw; xb++) {
uint32_t src = xb + dx + w * (yb + dy);
(buffer[xb + yb * dw] = image[src] << 8 | image[src] >> 8);
}
}
}
else {
for (uint32_t yb = 0; yb < dh; yb++) {
memcpy((uint8_t*) (buffer + yb * dw), (uint8_t*) (image + dx + w * (yb + dy)), dw << 1);
}
}
}
// else, if a buffer pointer has been provided copy whole image to the buffer
else if (buffer != image || _swapBytes) {
if(_swapBytes) {
for (uint32_t i = 0; i < len; i++) (buffer[i] = image[i] << 8 | image[i] >> 8);
}
else {
memcpy(buffer, image, len*2);
}
}
// Wait for any current SPI transaction to end
while (spiHal.State == HAL_SPI_STATE_BUSY_TX);
setWindow(x, y, x + dw - 1, y + dh - 1);
// DMA byte count for transmit is only 16 bits maximum, so to avoid this constraint
// small transfers are performed using a blocking call until DMA capacity is reached.
// User sketch can prevent blocking by managing pixel count and splitting into blocks
// of 32767 pixels maximum. (equivalent to an area of ~320 x 100 pixels)
while(len>0x7FFF) { // Transfer 16 bit pixels in blocks if len*2 over 65534 bytes
HAL_SPI_Transmit(&spiHal, (uint8_t*)buffer, 0x800<<1, HAL_MAX_DELAY);
len -= 0x800; buffer+= 0x800; // Arbitrarily send 1K pixel blocks (2Kbytes)
}
// Send remaining pixels using DMA (max 65534 bytes)
HAL_SPI_Transmit_DMA(&spiHal, (uint8_t*)buffer, len << 1);
}
////////////////////////////////////////////////////////////////////////////////////////
// Processor specific DMA initialisation
////////////////////////////////////////////////////////////////////////////////////////
// The DMA functions here work with SPI only (not parallel)
#if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx)
/***************************************************************************************
** Function name: DMA2_StreamX_IRQHandler
** Description: Override the default HAL stream 3 interrupt handler
***************************************************************************************/
extern "C" void DMA2_Stream3_IRQHandler();
void DMA2_Stream3_IRQHandler()
{
// Call the default end of buffer handler
HAL_DMA_IRQHandler(&dmaHal);
}
/***************************************************************************************
** Function name: initDMA
** Description: Initialise the DMA engine - returns true if init OK
***************************************************************************************/
// This initialisation is for STM32F2xx/4xx/7xx processors and may not work on others
// Dual core H7xx series not supported yet, they are different and have a DMA MUX:
// https://electronics.stackexchange.com/questions/379813/configuring-the-dma-request-multiplexer-on-a-stm32h7-mcu
bool TFT_eSPI::initDMA(void)
{
__HAL_RCC_DMA2_CLK_ENABLE(); // Enable DMA2 clock
dmaHal.Init.Channel = DMA_CHANNEL_3; // DMA channel 3 is for SPI1 TX
dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once
dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral
dmaHal.Init.PeriphInc = DMA_PINC_DISABLE; // Don't increment peripheral address
dmaHal.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // Peripheral is byte aligned
dmaHal.Init.MemInc = DMA_MINC_ENABLE; // Increment memory address
dmaHal.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // Memory is byte aligned
if (HAL_DMA_Init(&dmaHal) != HAL_OK){ // Init DMA with settings
// Insert error message here?
return DMA_Enabled = false;
};
HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); // Enable DMA end interrupt handler
__HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral
return DMA_Enabled = true;
}
#elif defined (STM32F1xx) // Supports "Blue Pill" boards
/***************************************************************************************
** Function name: DMA1_ChannelX_IRQHandler
** Description: Override the default HAL stream 3 interrupt handler
***************************************************************************************/
extern "C" void DMA1_Channel3_IRQHandler();
void DMA1_Channel3_IRQHandler()
{
// Call the default end of buffer handler
HAL_DMA_IRQHandler(&dmaHal);
}
//*/
/***************************************************************************************
** Function name: initDMA
** Description: Initialise the DMA engine - returns true if init OK
***************************************************************************************/
bool TFT_eSPI::initDMA(void)
{
__HAL_RCC_DMA1_CLK_ENABLE(); // Enable DMA2 clock
dmaHal.Init.Mode = DMA_NORMAL; //DMA_CIRCULAR; // // Normal = send buffer once
dmaHal.Init.Direction = DMA_MEMORY_TO_PERIPH; // Copy memory to the peripheral
dmaHal.Init.PeriphInc = DMA_PINC_DISABLE; // Don't increment peripheral address
dmaHal.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // Peripheral is byte aligned
dmaHal.Init.MemInc = DMA_MINC_ENABLE; // Increment memory address
dmaHal.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // Memory is byte aligned
dmaHal.Init.Priority = DMA_PRIORITY_LOW; // Added this line - needed ?
__HAL_LINKDMA(&spiHal, hdmatx, dmaHal); // Attach DMA engine to SPI peripheral
if (HAL_DMA_Init(&dmaHal) != HAL_OK){ // Init DMA with settings
// Insert error message here?
return DMA_Enabled = false;
};
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn); // Enable DMA end interrupt handler
return DMA_Enabled = true;
}
#endif // End of STM32F1/2/4/7xx
/***************************************************************************************
** Function name: deInitDMA
** Description: Disconnect the DMA engine from SPI
***************************************************************************************/
void TFT_eSPI::deInitDMA(void)
{
HAL_DMA_DeInit(&dmaHal);
DMA_Enabled = false;
}
////////////////////////////////////////////////////////////////////////////////////////
#endif // End of DMA FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////

804
Processors/TFT_eSPI_STM32.h Normal file
View File

@@ -0,0 +1,804 @@
////////////////////////////////////////////////////
// TFT_eSPI driver functions for STM32 processors //
////////////////////////////////////////////////////
#ifndef _TFT_eSPI_STM32H_
#define _TFT_eSPI_STM32H_
// Processor ID reported by getSetup()
#define PROCESSOR_ID 0x32F
// Include processor specific header
// None
// Processor specific code used by SPI bus transaction startWrite and endWrite functions
#define SET_SPI_WRITE_MODE // Not used
#define SET_SPI_READ_MODE // Not used
// SUPPORT_TRANSACTIONS is mandatory for STM32
#if !defined (SUPPORT_TRANSACTIONS)
#define SUPPORT_TRANSACTIONS
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the parallel bus interface chip pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if defined(TFT_PARALLEL_8_BIT)
// The STM32 processors can toggle pins fast, TFTs need setup and hold times
// for writes so here twc can be extended with delays:
//
// 0 1 2 3 4 5 Extra high periods
// TFT_WR ¯|_ _ _ _ _ _ |¯ ¯ ¯ ¯ ¯ ¯ ¯|
// 5 4 3 2 1 0 Extra low periods
// xxxx=======================xxxx
// |<---------- twc --------->|
// |<- tdst ->|<-- tdht -->|
//
// Data is placed bit by bit on bus during period xxxx and TFT_WR driven low
// Period xxxx depends on D0-D7 pin allocations and bit manipulation needed
// Data stable during period ===
// Most TFTs can be "overclocked" and run >2x faster than data sheet figures
////////////////////////////////////////////////////////////////////////////////////////
// Write strobe timing setup
////////////////////////////////////////////////////////////////////////////////////////
#if defined (ILI9341_DRIVER) // WRX twc spec is 66ns = 15.15MHz
// Extra write pulse low time (delay for data setup)
#if defined (STM32F2xx) || defined (STM32F4xx)
#define WR_TWRL_0 // Tested with STM32F446 - 27.6MHz when WR_TWRH_1 defined
//#define WR_TWRL_3 // STM32F446 - 15.6MHz when WR_TWRH_3 defined
#elif defined (STM32F7xx)
#define WR_TWRL_1 //Tested with STM32F767
#else
#define WR_TWRL_5
#endif
// Extra write pulse high time (data hold time, delays next write cycle start)
#if defined (STM32F2xx) || defined (STM32F4xx)
#define WR_TWRH_1 // Tested with STM32F446
//#define WR_TWRL_3
#elif defined (STM32F7xx)
#define WR_TWRH_1 //Tested with STM32F767
#else
#define WR_TWRH_5
#endif
#elif defined (ILI9481_DRIVER) // WRX twc spec is 100ns = 10MHz
// Extra write pulse low time (delay for data setup)
#if defined (STM32F2xx) || defined (STM32F4xx)
//#define WR_TWRL_0 // STM32F446 - ~30MHz when WR_TWRH_0 defined
//#define WR_TWRL_1 // STM32F446 - ~25MHz when WR_TWRH_0 defined
#define WR_TWRL_2 // STM32F446 - ~20MHz when WR_TWRH_2 defined
//#define WR_TWRL_3 // STM32F446 - ~16MHz when WR_TWRH_3 defined
//#define WR_TWRL_4
//#define WR_TWRL_5 // STM32F446 - ~12MHz when WR_TWRH_5 defined
#elif defined (STM32F7xx)
//#define WR_TWRL_0
//#define WR_TWRL_1
//#define WR_TWRL_2
#define WR_TWRL_3
#else
//#define WR_TWRH_0 // Fastest
//#define WR_TWRH_1
//#define WR_TWRH_2
#define WR_TWRH_3 // Slowest
#endif
// Extra write pulse high time (data hold time, delays next write cycle start)
#if defined (STM32F2xx) || defined (STM32F4xx)
//#define WR_TWRH_0
//#define WR_TWRH_1
#define WR_TWRH_2
//#define WR_TWRH_3
#elif defined (STM32F7xx)
//#define WR_TWRH_0
//#define WR_TWRH_1
//#define WR_TWRH_2
#define WR_TWRH_3
//#define WR_TWRH_4
//#define WR_TWRH_5
#else
//#define WR_TWRH_0 // Fastest
//#define WR_TWRH_1
//#define WR_TWRH_2
#define WR_TWRH_3 // Slowest
#endif
#else // Default display slow settings
// Extra write pulse low time (delay for data setup)
//#define WR_TWRL_0
//#define WR_TWRL_1
//#define WR_TWRL_2
//#define WR_TWRL_3
//#define WR_TWRL_4
#define WR_TWRL_5
// Extra write pulse high time (data hold time, delays next write cycle start)
//#define WR_TWRH_0
//#define WR_TWRH_1
//#define WR_TWRH_2
//#define WR_TWRH_3
//#define WR_TWRH_4
#define WR_TWRH_5
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros for all other SPI displays
////////////////////////////////////////////////////////////////////////////////////////
#else
// Global define is _VARIANT_ARDUINO_STM32_, see board package stm32_def.h for specific variants
#if defined (STM32F2xx) || defined (STM32F4xx) || defined (STM32F7xx)
#define STM32_DMA // DMA is available with these processors
// Initialise processor specific SPI and DMA instances - used by init()
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \
dmaHal.Instance = DMA2_Stream3
// The DMA hard-coding for SPI1 is in TFT_eSPI_STM32.c as follows:
// DMA_CHANNEL_3
// DMA2_Stream3_IRQn and DMA2_Stream3_IRQHandler()
#elif defined (STM32F1xx)
// For Blue Pill and STM32F1xx processors with DMA support
#define STM32_DMA // DMA is available with these processors
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI1; \
dmaHal.Instance = DMA1_Channel3
#else
// For STM32 processor with no implemented DMA support (yet)
#define INIT_TFT_DATA_BUS spiHal.Instance = SPI1
#endif
#endif
#ifdef STM32_DMA
// Code to check if DMA is busy, used by SPI DMA + transaction + endWrite functions
#define DMA_BUSY_CHECK { if (DMA_Enabled) while(dmaBusy()); }
#else
#define DMA_BUSY_CHECK
#endif
// If smooth fonts are enabled the filing system may need to be loaded
#ifdef SMOOTH_FONT
// Call up the filing system for the anti-aliased fonts <<<==== TODO
//#define FS_NO_GLOBALS
//#include <FS.h>
#endif // end of parallel/SPI selection
////////////////////////////////////////////////////////////////////////////////////////
// Define the DC (TFT Data/Command or Register Select (RS))pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_DC) || (TFT_DC < 0)
#define DC_C // No macro allocated so it generates no code
#define DC_D // No macro allocated so it generates no code
#else
// Convert Arduino pin reference Dn or STM pin reference PXn to hardware port and mask
#define DC_PIN_NAME digitalPinToPinName(TFT_DC)
#define DC_PORT get_GPIO_Port(STM_PORT(DC_PIN_NAME))
#define DC_PIN_MASK STM_LL_GPIO_PIN(DC_PIN_NAME)
// Use bit set reset register
#define DC_C DC_PORT->BSRR = DC_PIN_MASK<<16
#define DC_D DC_PORT->BSRR = DC_PIN_MASK
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the CS (TFT chip select) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_CS) || (TFT_CS < 0)
#define CS_L // No macro allocated so it generates no code
#define CS_H // No macro allocated so it generates no code
#else
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define CS_PIN_NAME digitalPinToPinName(TFT_CS)
#define CS_PORT get_GPIO_Port(STM_PORT(CS_PIN_NAME))
#define CS_PIN_MASK STM_LL_GPIO_PIN(CS_PIN_NAME)
// Use bit set reset register
#define CS_L CS_PORT->BSRR = CS_PIN_MASK<<16
#define CS_H CS_PORT->BSRR = CS_PIN_MASK
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the RD (TFT Read) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TFT_RD
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define RD_PIN_NAME digitalPinToPinName(TFT_RD)
#define RD_PORT get_GPIO_Port(STM_PORT(RD_PIN_NAME))
#define RD_PIN_MASK STM_LL_GPIO_PIN(RD_PIN_NAME)
// Use bit set reset register
#define RD_L RD_PORT->BSRR = RD_PIN_MASK<<16
#define RD_H RD_PORT->BSRR = RD_PIN_MASK
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the WR (TFT Write) pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#ifdef TFT_WR
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define WR_PIN_NAME digitalPinToPinName(TFT_WR)
#define WR_PORT get_GPIO_Port(STM_PORT(WR_PIN_NAME))
#define WR_PIN_MASK STM_LL_GPIO_PIN(WR_PIN_NAME)
// Use bit set reset register
#define WR_L WR_PORT->BSRR = WR_PIN_MASK<<16
#ifdef ILI9341_DRIVER
#define WR_H WR_PORT->BSRR = WR_PIN_MASK
#else
#define WR_H WR_PORT->BSRR = WR_PIN_MASK
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the touch screen chip select pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TOUCH_CS) || (TOUCH_CS < 0)
#define T_CS_L // No macro allocated so it generates no code
#define T_CS_H // No macro allocated so it generates no code
#else
// Speed is not important for this signal
#define T_CS_L digitalWrite(TOUCH_CS, LOW)
#define T_CS_H digitalWrite(TOUCH_CS, HIGH)
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Make sure TFT_MISO is defined if not used to avoid an error message
////////////////////////////////////////////////////////////////////////////////////////
#if !defined (TFT_PARALLEL_8_BIT)
#ifndef TFT_MISO
#define TFT_MISO -1
#endif
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Define the parallel bus interface chip pin drive code
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_PARALLEL_8_BIT)
// Mask for the 8 data bits to set pin directions (not used)
#define dir_mask 0
#define CONSTRUCTOR_INIT_TFT_DATA_BUS // None
#define INIT_TFT_DATA_BUS // Setup built into TFT_eSPI.cpp
////////////////////////////////////////////////////////////////////////////////////////
// Define the TFT_WR drive cycle timing
////////////////////////////////////////////////////////////////////////////////////////
// Write low extra setup time
#if defined WR_TWRL_0
#define WR_TWRL
#elif defined WR_TWRL_1 // 1 extra low period
#define WR_TWRL WR_L
#elif defined WR_TWRL_2 // 2 extra low periods
#define WR_TWRL WR_L; WR_L
#elif defined WR_TWRL_3 // 3 extra low periods
#define WR_TWRL WR_L; WR_L; WR_L
#elif defined WR_TWRL_4 // 4 extra low periods
#define WR_TWRL WR_L; WR_L; WR_L; WR_L
#elif defined WR_TWRL_5 // 5 extra low periods
#define WR_TWRL WR_L; WR_L; WR_L; WR_L; WR_L
#endif
// Write high extra hold time
#if defined WR_TWRH_0
#define WR_TWRH WR_H
#elif defined WR_TWRH_1 // 1 extra high period
#define WR_TWRH WR_H; WR_H
#elif defined WR_TWRH_2 // 2 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H
#elif defined WR_TWRH_3 // 3 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H; WR_H
#elif defined WR_TWRH_4 // 4 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H; WR_H; WR_H
#elif defined WR_TWRH_5 // 5 extra high periods
#define WR_TWRH WR_H; WR_H; WR_H; WR_H; WR_H; WR_H
#endif
#define WR_STB WR_TWRL; WR_TWRH // Rising edge write strobe
////////////////////////////////////////////////////////////////////////////////////////
// Nucleo 64: hard-coded pins
////////////////////////////////////////////////////////////////////////////////////////
#ifdef NUCLEO_64_TFT
// Nucleo 64 boards use the same ports/pins
#define D0_PIN_BIT LL_GPIO_PIN_9
#define D1_PIN_BIT LL_GPIO_PIN_7
#define D2_PIN_BIT LL_GPIO_PIN_10
#define D3_PIN_BIT LL_GPIO_PIN_3
#define D4_PIN_BIT LL_GPIO_PIN_5
#define D5_PIN_BIT LL_GPIO_PIN_4
#define D6_PIN_BIT LL_GPIO_PIN_10
#define D7_PIN_BIT LL_GPIO_PIN_8
// Ports associated with pins - better than get_GPIO_Port() which seems to be slow...
#define D0_PIN_PORT GPIOA
#define D1_PIN_PORT GPIOC
#define D2_PIN_PORT GPIOA
#define D3_PIN_PORT GPIOB
#define D4_PIN_PORT GPIOB
#define D5_PIN_PORT GPIOB
#define D6_PIN_PORT GPIOB
#define D7_PIN_PORT GPIOA
// Pin masks for set/clear
#define D0_PIN_MASK (1UL<< 9) // Set/clear mask for PA9
#define D1_PIN_MASK (1UL<< 7) // Set/clear mask for PC7
#define D2_PIN_MASK (1UL<<10) // Set/clear mask for PA10
#define D3_PIN_MASK (1UL<< 3) // Set/clear mask for PB3
#define D4_PIN_MASK (1UL<< 5) // Set/clear mask for PB5
#define D5_PIN_MASK (1UL<< 4) // Set/clear mask for PB4
#define D6_PIN_MASK (1UL<<10) // Set/clear mask for PB10
#define D7_PIN_MASK (1UL<< 8) // Set/clear mask for PA8
// Create bit set/reset mask based on LS byte of value B
#define D0_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)<< 4)&0x10))
#define D1_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)<< 3)&0x10))
#define D2_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)<< 2)&0x10))
#define D3_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)<< 1)&0x10))
#define D4_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)<< 0)&0x10))
#define D5_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 1)&0x10))
#define D6_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>> 2)&0x10))
#define D7_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>> 3)&0x10))
// Create bit set/reset mask for top byte of 16 bit value B
#define D8_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)>> 4)&0x10))
#define D9_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)>> 5)&0x10))
#define D10_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)>> 6)&0x10))
#define D11_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)>> 7)&0x10))
#define D12_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)>> 8)&0x10))
#define D13_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 9)&0x10))
#define D14_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>>10)&0x10))
#define D15_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>>11)&0x10))
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOA->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D1_BSR_MASK(C); \
GPIOB->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB // Need to slow down strobe
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOA->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D9_BSR_MASK(C); \
GPIOB->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB; \
GPIOA->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D1_BSR_MASK(C); \
GPIOB->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB // Need to slow down strobe
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOA->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D1_BSR_MASK(C); \
GPIOB->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB; \
GPIOA->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOC->BSRR = D9_BSR_MASK(C); \
GPIOB->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB
// Read a data bit
#define RD_TFT_D0 (((GPIOA->IDR)&(D0_PIN_MASK))>>( 9-0)) // Read pin PA9
#define RD_TFT_D1 (((GPIOC->IDR)&(D1_PIN_MASK))>>( 7-1)) // Read pin PC7
#define RD_TFT_D2 (((GPIOA->IDR)&(D2_PIN_MASK))>>(10-2)) // Read pin PA10
#define RD_TFT_D3 (((GPIOB->IDR)&(D3_PIN_MASK))>>( 3-3)) // Read pin PB3
#define RD_TFT_D4 (((GPIOB->IDR)&(D4_PIN_MASK))>>( 5-4)) // Read pin PB5
#define RD_TFT_D5 (((GPIOB->IDR)&(D5_PIN_MASK))<<(-4+5)) // Read pin PB4
#define RD_TFT_D6 (((GPIOB->IDR)&(D6_PIN_MASK))>>(10-6)) // Read pin PB10
#define RD_TFT_D7 (((GPIOA->IDR)&(D7_PIN_MASK))>>( 8-7)) // Read pin PA8
////////////////////////////////////////////////////////////////////////////////////////
// Nucleo 144: hard-coded pins
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (NUCLEO_144_TFT)
#if !defined (STM32H7xx)
// Nucleo 144 boards use the same ports/pins
#define D0_PIN_BIT LL_GPIO_PIN_12
#define D1_PIN_BIT LL_GPIO_PIN_15
#define D2_PIN_BIT LL_GPIO_PIN_15
#define D3_PIN_BIT LL_GPIO_PIN_13
#define D4_PIN_BIT LL_GPIO_PIN_14
#define D5_PIN_BIT LL_GPIO_PIN_11
#define D6_PIN_BIT LL_GPIO_PIN_9
#define D7_PIN_BIT LL_GPIO_PIN_13
// Ports associated with pins - get_GPIO_Port() seems to be slow...
#define D0_PIN_PORT GPIOF
#define D1_PIN_PORT GPIOD
#define D2_PIN_PORT GPIOF
#define D3_PIN_PORT GPIOE
#define D4_PIN_PORT GPIOF
#define D5_PIN_PORT GPIOE
#define D6_PIN_PORT GPIOE
#define D7_PIN_PORT GPIOF
// Pin masks for set/clear
#define D0_PIN_MASK (1UL<<12) // Set/clear mask for PF12 PF3
#define D1_PIN_MASK (1UL<<15) // Set/clear mask for PD15
#define D2_PIN_MASK (1UL<<15) // Set/clear mask for PF15 PG14
#define D3_PIN_MASK (1UL<<13) // Set/clear mask for PE13
#define D4_PIN_MASK (1UL<<14) // Set/clear mask for PF14
#define D5_PIN_MASK (1UL<<11) // Set/clear mask for PE11
#define D6_PIN_MASK (1UL<< 9) // Set/clear mask for PE9
#define D7_PIN_MASK (1UL<<13) // Set/clear mask for PF13 PG12
// Create bit set/reset mask based on LS byte of value B
#define D0_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)<< 4)&0x10))
#define D1_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)<< 3)&0x10))
#define D2_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)<< 2)&0x10))
#define D3_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)<< 1)&0x10))
#define D4_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)<< 0)&0x10))
#define D5_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 1)&0x10))
#define D6_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>> 2)&0x10))
#define D7_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>> 3)&0x10))
// Create bit set/reset mask for top byte of 16 bit value B
#define D8_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)>> 4)&0x10))
#define D9_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)>> 5)&0x10))
#define D10_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)>> 6)&0x10))
#define D11_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)>> 7)&0x10))
#define D12_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)>> 8)&0x10))
#define D13_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 9)&0x10))
#define D14_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>>10)&0x10))
#define D15_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>>11)&0x10))
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOF->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D4_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOF->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D12_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB;\
GPIOF->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D4_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOF->BSRR = D0_BSR_MASK(C) | D2_BSR_MASK(C) | D4_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB; \
GPIOF->BSRR = D8_BSR_MASK(C) | D10_BSR_MASK(C) | D12_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB
// Read a data bit
#define RD_TFT_D0 (((GPIOF->IDR)&(D0_PIN_MASK))>>(12-0)) // Read pin PF12
#define RD_TFT_D1 (((GPIOD->IDR)&(D1_PIN_MASK))>>(15-1)) // Read pin PD15
#define RD_TFT_D2 (((GPIOF->IDR)&(D2_PIN_MASK))>>(15-2)) // Read pin PF15
#define RD_TFT_D3 (((GPIOE->IDR)&(D3_PIN_MASK))>>(13-3)) // Read pin PE13
#define RD_TFT_D4 (((GPIOF->IDR)&(D4_PIN_MASK))>>(14-4)) // Read pin PF14
#define RD_TFT_D5 (((GPIOE->IDR)&(D5_PIN_MASK))>>(11-5)) // Read pin PE11
#define RD_TFT_D6 (((GPIOE->IDR)&(D6_PIN_MASK))>>( 9-6)) // Read pin PE9
#define RD_TFT_D7 (((GPIOF->IDR)&(D7_PIN_MASK))>>(13-7)) // Read pin PF13
#else
// Test setup for STM32H743 - starts to run, slow and then crashes! Board support bug?
// Nucleo 144 boards use the same ports/pins
#define D0_PIN_BIT LL_GPIO_PIN_3
#define D1_PIN_BIT LL_GPIO_PIN_15
#define D2_PIN_BIT LL_GPIO_PIN_14
#define D3_PIN_BIT LL_GPIO_PIN_13
#define D4_PIN_BIT LL_GPIO_PIN_14
#define D5_PIN_BIT LL_GPIO_PIN_11
#define D6_PIN_BIT LL_GPIO_PIN_9
#define D7_PIN_BIT LL_GPIO_PIN_12
// Ports associated with pins - get_GPIO_Port() seems to be slow...
#define D0_PIN_PORT GPIOF
#define D1_PIN_PORT GPIOD
#define D2_PIN_PORT GPIOG
#define D3_PIN_PORT GPIOE
#define D4_PIN_PORT GPIOE
#define D5_PIN_PORT GPIOE
#define D6_PIN_PORT GPIOE
#define D7_PIN_PORT GPIOG
// Pin masks for set/clear
#define D0_PIN_MASK (1UL<< 3) // Set/clear mask for PF3
#define D1_PIN_MASK (1UL<<15) // Set/clear mask for PD15
#define D2_PIN_MASK (1UL<<14) // Set/clear mask for PG14
#define D3_PIN_MASK (1UL<<13) // Set/clear mask for PE13
#define D4_PIN_MASK (1UL<<14) // Set/clear mask for PE14
#define D5_PIN_MASK (1UL<<11) // Set/clear mask for PE11
#define D6_PIN_MASK (1UL<< 9) // Set/clear mask for PE9
#define D7_PIN_MASK (1UL<<12) // Set/clear mask for PG12
// Create bit set/reset mask based on LS byte of value B
#define D0_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)<< 4)&0x10))
#define D1_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)<< 3)&0x10))
#define D2_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)<< 2)&0x10))
#define D3_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)<< 1)&0x10))
#define D4_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)<< 0)&0x10))
#define D5_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 1)&0x10))
#define D6_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>> 2)&0x10))
#define D7_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>> 3)&0x10))
// Create bit set/reset mask for top byte of 16 bit value B
#define D8_BSR_MASK(B) ((D0_PIN_MASK<<16)>>(((B)>> 4)&0x10))
#define D9_BSR_MASK(B) ((D1_PIN_MASK<<16)>>(((B)>> 5)&0x10))
#define D10_BSR_MASK(B) ((D2_PIN_MASK<<16)>>(((B)>> 6)&0x10))
#define D11_BSR_MASK(B) ((D3_PIN_MASK<<16)>>(((B)>> 7)&0x10))
#define D12_BSR_MASK(B) ((D4_PIN_MASK<<16)>>(((B)>> 8)&0x10))
#define D13_BSR_MASK(B) ((D5_PIN_MASK<<16)>>(((B)>> 9)&0x10))
#define D14_BSR_MASK(B) ((D6_PIN_MASK<<16)>>(((B)>>10)&0x10))
#define D15_BSR_MASK(B) ((D7_PIN_MASK<<16)>>(((B)>>11)&0x10))
// Write 8 bits to TFT
#define tft_Write_8(C) GPIOF->BSRR = D0_BSR_MASK(C); \
GPIOG->BSRR = D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// Write 16 bits to TFT
#define tft_Write_16(C) GPIOF->BSRR = D8_BSR_MASK(C); \
GPIOG->BSRR = D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB;\
GPIOF->BSRR = D0_BSR_MASK(C); \
GPIOG->BSRR = D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB
// 16 bit write with swapped bytes
#define tft_Write_16S(C) GPIOF->BSRR = D0_BSR_MASK(C); \
GPIOG->BSRR = D2_BSR_MASK(C) | D7_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D1_BSR_MASK(C); \
GPIOE->BSRR = D3_BSR_MASK(C) | D4_BSR_MASK(C) | D5_BSR_MASK(C) | D6_BSR_MASK(C); \
WR_STB; \
GPIOF->BSRR = D8_BSR_MASK(C); \
GPIOG->BSRR = D10_BSR_MASK(C) | D15_BSR_MASK(C); \
WR_L; \
GPIOD->BSRR = D9_BSR_MASK(C); \
GPIOE->BSRR = D11_BSR_MASK(C) | D12_BSR_MASK(C) | D13_BSR_MASK(C) | D14_BSR_MASK(C); \
WR_STB
// Read a data bit
#define RD_TFT_D0 (((GPIOF->IDR)&(D0_PIN_MASK))>>( 3-0)) // Read pin PF3
#define RD_TFT_D1 (((GPIOD->IDR)&(D1_PIN_MASK))>>(15-1)) // Read pin PD15
#define RD_TFT_D2 (((GPIOG->IDR)&(D2_PIN_MASK))>>(14-2)) // Read pin PG14
#define RD_TFT_D3 (((GPIOE->IDR)&(D3_PIN_MASK))>>(13-3)) // Read pin PE13
#define RD_TFT_D4 (((GPIOE->IDR)&(D4_PIN_MASK))>>(14-4)) // Read pin PE14
#define RD_TFT_D5 (((GPIOE->IDR)&(D5_PIN_MASK))>>(11-5)) // Read pin PE11
#define RD_TFT_D6 (((GPIOE->IDR)&(D6_PIN_MASK))>>( 9-6)) // Read pin PE9
#define RD_TFT_D7 (((GPIOG->IDR)&(D7_PIN_MASK))>>(12-7)) // Read pin PG12
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Support for other STM32 boards (not optimised!)
////////////////////////////////////////////////////////////////////////////////////////
#else
// This will work with any STM32 to parallel TFT pin mapping but will be slower
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D0_PIN_NAME digitalPinToPinName(TFT_D0)
#ifndef D0_PORT
#define D0_PORT get_GPIO_Port(STM_PORT(D0_PIN_NAME))
#endif
#define D0_PIN_MASK (const uint16_t)STM_LL_GPIO_PIN(D0_PIN_NAME)<<16
// Use bit set reset register
#define D0_BSR(B) D0_PORT->BSRR = (D0_PIN_MASK)>>(B)
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D1_PIN_NAME digitalPinToPinName(TFT_D1)
#ifndef D1_PORT
#define D1_PORT get_GPIO_Port(STM_PORT(D1_PIN_NAME))
#endif
#define D1_PIN_MASK STM_LL_GPIO_PIN(D1_PIN_NAME)<<16
// Use bit set reset register
#define D1_BSR(B) D1_PORT->BSRR = D1_PIN_MASK>>(B)
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D2_PIN_NAME digitalPinToPinName(TFT_D2)
#ifndef D2_PORT
#define D2_PORT get_GPIO_Port(STM_PORT(D2_PIN_NAME))
#endif
#define D2_PIN_MASK (const uint16_t)STM_LL_GPIO_PIN(D2_PIN_NAME)<<16
// Use bit set reset register
#define D2_BSR(B) D2_PORT->BSRR = D2_PIN_MASK>>(B)
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D3_PIN_NAME digitalPinToPinName(TFT_D3)
#ifndef D3_PORT
#define D3_PORT get_GPIO_Port(STM_PORT(D3_PIN_NAME))
#endif
#define D3_PIN_MASK (const uint16_t)STM_LL_GPIO_PIN(D3_PIN_NAME)<<16
// Use bit set reset register
#define D3_BSR(B) D3_PORT->BSRR = D3_PIN_MASK>>(B)
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D4_PIN_NAME digitalPinToPinName(TFT_D4)
#ifndef D4_PORT
#define D4_PORT get_GPIO_Port(STM_PORT(D4_PIN_NAME))
#endif
#define D4_PIN_MASK (const uint16_t)STM_LL_GPIO_PIN(D4_PIN_NAME)<<16
// Use bit set reset register
#define D4_BSR(B) D4_PORT->BSRR = D4_PIN_MASK>>(B)
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D5_PIN_NAME digitalPinToPinName(TFT_D5)
#ifndef D5_PORT
#define D5_PORT get_GPIO_Port(STM_PORT(D5_PIN_NAME))
#endif
#define D5_PIN_MASK (const uint16_t)STM_LL_GPIO_PIN(D5_PIN_NAME)<<16
// Use bit set reset register
#define D5_BSR(B) D5_PORT->BSRR = D5_PIN_MASK>>(B)
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D6_PIN_NAME digitalPinToPinName(TFT_D6)
#ifndef D6_PORT
#define D6_PORT get_GPIO_Port(STM_PORT(D6_PIN_NAME))
#endif
#define D6_PIN_MASK (const uint16_t)STM_LL_GPIO_PIN(D6_PIN_NAME)<<16
// Use bit set reset register
#define D6_BSR(B) D6_PORT->BSRR = D6_PIN_MASK>>(B)
// Convert Arduino pin reference Dx or STM pin reference PXn to hardware port and mask
#define D7_PIN_NAME digitalPinToPinName(TFT_D7)
#ifndef D7_PORT
#define D7_PORT get_GPIO_Port(STM_PORT(D7_PIN_NAME))
#endif
#define D7_PIN_MASK (const uint16_t)STM_LL_GPIO_PIN(D7_PIN_NAME)<<16
// Use bit set reset register
#define D7_BSR(B) D7_PORT->BSRR = D7_PIN_MASK>>(B)
// Write 8 bits to TFT for any Nucleo
#define tft_Write_8(C) D7_BSR(((C)>>3)&0x10); D6_BSR(((C)>>2)&0x10); \
D5_BSR(((C)>>1)&0x10); D4_BSR(((C)>>0)&0x10); \
WR_L; \
D3_BSR(((C)<<1)&0x10); D2_BSR(((C)<<2)&0x10); \
D1_BSR(((C)<<3)&0x10); D0_BSR(((C)<<4)&0x10); \
WR_H
// Write 16 bits to TFT
#define tft_Write_16(C) tft_Write_8((C)>>8); tft_Write_8(C)
// 16 bit write with swapped bytes
#define tft_Write_16S(C) tft_Write_8(C); tft_Write_8((C)>>8)
#endif // End of parallel/Nucleo 64/144 selections
// Write 32 bits to TFT
#define tft_Write_32(C) tft_Write_16((C)>>16); tft_Write_16(C)
// Write two concatenated 16 bit values to TFT
#define tft_Write_32C(C,D) tft_Write_16(C); tft_Write_16(D)
// Write 16 bit value twice to TFT
#define tft_Write_32D(C) tft_Write_16(C); tft_Write_16(C)
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to a SPI ILI9488 TFT
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (ILI9488_DRIVER) // 16 bit colour converted to 3 bytes for 18 bit RGB
// Write 8 bits to TFT
#define tft_Write_8(C) \
{ spiBuffer[0] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 1, 10); }
// Convert 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16(C) \
{ spiBuffer[0] = ((C) & 0xF800)>>8; spiBuffer[1] = ((C) & 0x07E0)>>3; spiBuffer[2] = ((C) & 0x001F)<<3; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, 10); }
// Convert swapped byte 16 bit colour to 18 bit and write in 3 bytes
#define tft_Write_16S(C) \
{ spiBuffer[0] = (C) & 0xF8; spiBuffer[1] = ((C) & 0xE000)>>11 | ((C) & 0x07)<<5; spiBuffer[2] = ((C) & 0x1F00)>>5; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 3, 10); }
// Write 32 bits to TFT
#define tft_Write_32(C) \
{ spiBuffer[0] = (C)>>24; spiBuffer[1] = (C)>>16; spiBuffer[2] = (C)>>8; spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
// Write two address coordinates
#define tft_Write_32C(C,D) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; spiBuffer[2] = (D)>>8; spiBuffer[3] = D; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
// Write same value twice
#define tft_Write_32D(C) \
{ spiBuffer[0] = spiBuffer[2] = (C)>>8; spiBuffer[1] = spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
////////////////////////////////////////////////////////////////////////////////////////
// Macros to write commands/pixel colour data to a SPI Raspberry Pi TFT
////////////////////////////////////////////////////////////////////////////////////////
#elif defined (RPI_ILI9486_DRIVER)
#define tft_Write_8(C) \
{ spiBuffer[0] = 0; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16(C) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16S(C) \
{ spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_32(C) \
{ spiBuffer[1] = ((C)>>24); spiBuffer[3] = ((C)>>16); spiBuffer[5] = ((C)>>8); spiBuffer[7] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 8, 10); }
#define tft_Write_32C(C,D) \
{ spiBuffer[1] = ((C)>>8); spiBuffer[3] = (C); spiBuffer[5] = ((D)>>8); spiBuffer[7] = D; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 8, 10); }
#define tft_Write_32D(C) \
{ spiBuffer[1] = ((C)>>8); spiBuffer[3] = (C); spiBuffer[5] = ((C)>>8); spiBuffer[7] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 8, 10); }
////////////////////////////////////////////////////////////////////////////////////////
// Macros for all other SPI displays
////////////////////////////////////////////////////////////////////////////////////////
#else
#define tft_Write_8(C) \
{ spiBuffer[0] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 1, 10); }
#define tft_Write_16(C) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_16S(C) \
{ spiBuffer[0] = C; spiBuffer[1] = (C)>>8; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 2, 10); }
#define tft_Write_32(C) \
{ spiBuffer[0] = (C)>>24; spiBuffer[1] = (C)>>16; spiBuffer[2] = (C)>>8; spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
#define tft_Write_32C(C,D) \
{ spiBuffer[0] = (C)>>8; spiBuffer[1] = C; spiBuffer[2] = (D)>>8; spiBuffer[3] = D; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
#define tft_Write_32D(C) \
{ spiBuffer[0] = spiBuffer[2] = (C)>>8; spiBuffer[1] = spiBuffer[3] = C; \
HAL_SPI_Transmit(&spiHal, spiBuffer, 4, 10); }
#endif
////////////////////////////////////////////////////////////////////////////////////////
// Macros to read from display using SPI or software SPI
////////////////////////////////////////////////////////////////////////////////////////
#if defined (TFT_SDA_READ)
// Macros to support a bit banged function call for STM32 and bi-directional SDA pin
#define TFT_eSPI_ENABLE_8_BIT_READ // Enable tft_Read_8();
#define SCLK_L digitalWrite(TFT_SCLK, LOW)
#define SCLK_H digitalWrite(TFT_SCLK, HIGH)
#elif !defined (TFT_PARALLEL_8_BIT)
// Use a SPI read transfer
#define tft_Read_8() spi.transfer(0)
#endif
#endif // Header end

View File

@@ -12,12 +12,14 @@ You can take this one step further and have your own setup select file and then
To select a new setup you then edit your own my_setup_select.h file (which will not get over-written during an upgrade).
# News
1. The ST7796 display controller has been added. The ST7796 RPi MHS-4.0 inch Display-B type display is supported (this is fast for a SPI display as an ESP32 can clock it at 80MHz (ESP8266 at 40MHz)), see setups 27 and 28.
1. The library has been upgraded to support STM32 processors when used with SPI or 8 bit parallel displays. DMA capability for SPI displays has been added for STM32F103 (e.g. "Blue Pill") and STM32F2xx/4xx/7xx (e.g. 32/64/144 Nucleo boards). New DMA demo examples have been added (for STM32 only). Smooth (anti-aliased) fonts are not yet supported for STM32 processors due to the lack of SPIFFS, support for smooth fonts using SD cards will be added at a future date.
2. A new beta test branch has been added to support other processors, in particular STM32:
2. The ST7796 display controller has been added. The ST7796 RPi MHS-4.0 inch Display-B type display is supported (this is fast for a SPI display as an ESP32 can clock it at 80MHz (ESP8266 at 40MHz)), see setups 27 and 28.
3. A new beta test branch has been added to support other processors, in particular STM32:
https://github.com/Bodmer/TFT_eSPI/tree/STM32
3. A callback function has been added, this allows antialiased fonts to be rendered over colour gradients or images. Two new examples have been added to illustrate this new capability:
4. A callback function has been added, this allows antialiased fonts to be rendered over colour gradients or images. Two new examples have been added to illustrate this new capability:
"Smooth_font_reading_TFT"
@@ -25,14 +27,11 @@ To select a new setup you then edit your own my_setup_select.h file (which will
![AA_gradien](https://i.imgur.com/YMBcPHp.png)
4. Sprites can now by pushed to the screen (or another Sprite) with a rotation angle. The new function is pushRotated(). Three new examples (Rotate_Sprite_1/2/3) have been added to show how the functions can be used to rotate text, images and to draw animated dials with moving needles.
5. Sprites can now by pushed to the screen (or another Sprite) with a rotation angle. The new function is pushRotated(). Three new examples (Rotate_Sprite_1/2/3) have been added to show how the functions can be used to rotate text, images and to draw animated dials with moving needles.
5. A new TFT_eFEX support library has been created which includes extra functions such as drawing a BMP or Jpeg to the screen. This library will simplify the examples. It will be expanded at a future date to include meters, dials and GUI elements like progress bars, graphs and animated buttons:
6. A new TFT_eFEX support library has been created which includes extra functions such as drawing a BMP or Jpeg to the screen. This library will simplify the examples. It will be expanded at a future date to include meters, dials and GUI elements like progress bars, graphs and animated buttons:
https://github.com/Bodmer/TFT_eFEX
6. I have created a user updateable graphics extension library template that can be used to create your own graphics extensions. The Library contains examples and is commented so it should be clear what you need to do to add functions. You can find it here:
https://github.com/Bodmer/TFT_eFX
# TFT_eSPI

View File

@@ -10,9 +10,7 @@
#define TFT_CASET 0x2A
#define TFT_PASET 0x2B
#define TFT_RAMWR 0x2C
#define TFT_RAMRD 0x2E
#define TFT_IDXRD 0xDD // ILI9341 only, indexed control register read
#define TFT_MADCTL 0x36
#define TFT_MAD_MY 0x80
@@ -37,7 +35,7 @@
#define TFT_INVON 0x21
// All ST7796 specific commands some are used by init()
// ST7796 specific commands
#define ST7796_NOP 0x00
#define ST7796_SWRESET 0x01
#define ST7796_RDDID 0x04
@@ -56,7 +54,7 @@
#define ST7796_INVOFF 0x20
#define ST7796_INVON 0x21
#define ST7796_GAMMASET 0x26
#define ST7796_DISPOFF 0x28
#define ST7796_DISPON 0x29
@@ -84,17 +82,11 @@
#define ST7796_PWCTR1 0xC0
#define ST7796_PWCTR2 0xC1
#define ST7796_PWCTR3 0xC2
#define ST7796_PWCTR4 0xC3
#define ST7796_PWCTR5 0xC4
#define ST7796_VMCTR1 0xC5
#define ST7796_VMCTR2 0xC7
#define ST7796_VMCOFF 0xC6
#define ST7796_RDID4 0xD3
#define ST7796_RDINDEX 0xD9
#define ST7796_RDID1 0xDA
#define ST7796_RDID2 0xDB
#define ST7796_RDID3 0xDC
#define ST7796_RDIDX 0xDD // TBC
#define ST7796_GMCTRP1 0xE0
#define ST7796_GMCTRN1 0xE1

View File

@@ -15,7 +15,7 @@
#ifndef _TFT_eSPIH_
#define _TFT_eSPIH_
#define TFT_ESPI_VERSION "1.4.30"
#define TFT_ESPI_VERSION "1.5.0"
// Include header file that defines the fonts loaded, the TFT drivers
// available and the pins to be used, etc, etc
@@ -40,9 +40,9 @@
#elif defined (ESP8266)
#include "Processors/TFT_eSPI_ESP8266.h"
#elif defined (STM32)
//#include "Processors/TFT_eSPI_STM32.h"
#include "Processors/TFT_eSPI_STM32.h"
#else
//#include "Processors/TFT_eSPI_Generic.h"
#include "Processors/TFT_eSPI_Generic.h"
#endif
#ifndef TAB_COLOUR
@@ -487,6 +487,15 @@ class TFT_eSPI : public Print {
void getSetup(setup_t& tft_settings); // Sketch provides the instance to populate
// DMA support functions
bool initDMA(void);
void deInitDMA(void);
void pushImageDMA(int32_t x, int32_t y, int32_t w, int32_t h, uint16_t* data, uint16_t* buffer = nullptr);
//void pushBlockDMA(uint16_t color, uint32_t len);
void pushPixelsDMA(uint16_t* image, uint32_t len);
bool dmaBusy(void);
bool DMA_Enabled = false;
static SPIClass& getSPIinstance(void);
int32_t cursor_x, cursor_y, padX;

View File

@@ -253,14 +253,13 @@
// With an ILI9341 display 40MHz works OK, 80MHz sometimes fails
// With a ST7735 display more than 27MHz may not work (spurious pixels and lines)
// With an ILI9163 display 27 MHz works OK.
// The RPi typically only works at 20MHz maximum.
// #define SPI_FREQUENCY 1000000
// #define SPI_FREQUENCY 5000000
// #define SPI_FREQUENCY 10000000
// #define SPI_FREQUENCY 20000000
#define SPI_FREQUENCY 27000000 // Actually sets it to 26.67MHz = 80/3
// #define SPI_FREQUENCY 40000000 // Maximum to use SPIFFS
// #define SPI_FREQUENCY 40000000
// #define SPI_FREQUENCY 80000000
// Optional reduced SPI frequency for reading TFT

View File

@@ -1,3 +1,36 @@
// My specials below
///#include <User_Setups/Setup24_ST7789.h> // Setup file for ESP32 and TTGO TM ST7789 SPI bus TFT
// // //#include <User_Setups/Setup135_ST7789.h> // Setup file for ESP32 and TTGO TM ST7789 SPI bus TFT
// #include <User_Setups/zSetup42_ST7735.hpp> // Setup file configured for my ST7735S
//#include <User_Setups/zSetup123_ILI9xxx.hpp> // Setup file for ESP32 and ILI9341 SPI bus TFT
// #include <User_Setups/zHSPI_Setup123_ILI9xxx.hpp> // Setup file for ESP32 and ILI9341 SPI bus TFT
//#include <../TFT_eSPI_Setup/zHSPI_Setup123_ILI9xxx.hpp>
//#include <zHSPI_Setup123_ILI9xxx.hpp>
//#include <User_Setups/zSetup124_R61581.hpp> //Compile error test only I do not have one of these
// #include <User_Setups/zSetup111_RPi_touch_ILI9486.hpp> // SD ESP32
//#include <User_Setups/zSetup111_RPi_ST7796.hpp> // ESP32 RPi
//#include <User_Setups/zSetup111_RPi_ST7796_ESP8266.hpp> // ESP8266 RPi
//#include <User_Setups/zSetup99_ILI9xxx_Overlap.hpp> // Setup file configured for my ILI9xxx
//#include <User_Setups/Setup77_ePaper.h> // Setup file for 2.9" Waveshare ePaper display
//#include <User_Setups/Setup43_ST7735_2.h> // Setup file configured for my ST7735S 80x160
//#include <../TFT_eSPI_Setup/zHSPI_Setup123_ILI9xxx.hpp>
//#include <User_Setups/zSetup1b_ILI9341.hpp> // Setup file configured for my ESP8266 and ILI9341
#include <User_Setups/Setup29_ILI9341_STM32.h> // Setup for Nucleo board
//#include <../TFT_eSPI_Setup/Setup_STM32F103_ILI9341.h> // Setup for Blue Pill
//#include <../TFT_eSPI_Setup/Setup_Due_ILI9341.h> // Setup for Blue Pill
//#include <User_Setups/Setup30_ILI9341_Parallel_STM32.h> // Setup for Nucleo board and parallel display
// This header file contains a list of user setup files and defines which one the
// compiler uses when the IDE performs a Verify/Compile or Upload.
//
@@ -19,7 +52,7 @@
// Only ONE line below should be uncommented. Add extra lines and files as needed.
#include <User_Setup.h> // Default setup is root library folder
//#include <User_Setup.h> // Default setup is root library folder
//#include <User_Setups/Setup1_ILI9341.h> // Setup file configured for my ILI9341
//#include <User_Setups/Setup2_ST7735.h> // Setup file configured for my ST7735
@@ -57,7 +90,7 @@
//#include <User_Setups/Setup43_ST7735.h> // Setup file configured for my ST7735S 80x160
//#include <User_Setups/Setup135_ST7789.h> // Setup file for ESP8266 and ST7789 125 x 240 TFT
//#include <User_Setups/Setup135_ST7789.h> // Setup file for ESP8266 and ST7789 135 x 240 TFT
//#include <User_Setups/SetupX_Template.h>

View File

@@ -0,0 +1,68 @@
///////////////////////////////////////////////////
// Setup for STM32 Nucleo and ILI9341 display //
///////////////////////////////////////////////////
// Last update by Bodmer: 28/11/19
// STM32 optimised functions are not yet compatible with STM32H743 processor.
// The STM32H743 does work with the slower generic processor drivers
//
// REMINDER - Nucleo-F743ZI and Nucleo-F743ZI2 have different pin port allocations
// and require appropriate selection in IDE. ^---- Note the extra 2 in part number!
// Define STM32 to invoke STM32 optimised driver (optimised fns only tested on STM32F767 so far)
// so you may need to comment this out
#define STM32
// Define the TFT display driver
#define ILI9341_DRIVER
//#define ILI9481_DRIVER
// MOSI and SCK do not need to be defined, connect:
// - Arduino SCK to TFT SCK
// - Arduino MOSI to TFT SDI(may be marked SDA or MOSI)
// Standard Arduino SPI pins are(SCK=D13, MOSI=D11) this is port pins PA5 and PA7 on Nucleo-F767ZI
// Can use Ardiuno pin references, arbitrary allocation, TFT_eSPI controls chip select
#define TFT_CS D5 // Chip select control pin to TFT CS
#define TFT_DC D6 // Data Command control pin to TFT DC (may be labelled RS = Register Select)
#define TFT_RST D7 // Reset pin to TFT RST (or RESET)
// Alternatively, we can use STM32 port reference names PXnn
//#define TFT_CS PE11 // Nucleo-F767ZI equivalent of D5
//#define TFT_DC PE9 // Nucleo-F767ZI equivalent of D6
//#define TFT_RST PF13 // Nucleo-F767ZI equivalent of D7
//#define TFT_RST -1 // Set TFT_RST to -1 if the display RESET is connected to processor reset
// Use an Arduino pin for initial testing as connecting to processor reset
// may not work (pulse too short at power up?)
// Chip select for XPT2046 touch controller
#define TOUCH_CS D4
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:-.
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
// At the moment SMOOTH fonts must be disabled for STM32 processors (due to lack of SPIFFS)
// Support for smooth fonts via SD cards is planned.
//#define SMOOTH_FONT // Must be commented out for STM32
// Nucleo-F767ZI has a ~216MHZ CPU clock, this is divided by 4, 8, 16 etc
#define SPI_FREQUENCY 27000000 // 27MHz SPI clock
//#define SPI_FREQUENCY 55000000 // 55MHz is over-clocking ILI9341 but seems to work reliably!
//#define SPI_READ_FREQUENCY 15000000 // Reads need a slower SPI clock, probably ends up at 13.75MHz (CPU clock/16)
//#define SPI_TOUCH_FREQUENCY 2500000 // Must be very slow
// This has no effect, transactions for STM32 are automatically enabled
#define SUPPORT_TRANSACTIONS

View File

@@ -0,0 +1,52 @@
///////////////////////////////////////////////////
// Setup for Nucleo-F446/767 and ILI9341 display //
///////////////////////////////////////////////////
// See SetupX_Template.h for all options available
// Define STM32 to invoke optimised processor support
#define STM32
// Defining the board allows the library to optimise the performance
// for UNO compatible "MCUfriend" style shields
#define NUCLEO_64_TFT
//#define NUCLEO_144_TFT
// Tell the library to use 8 bit parallel mode(otherwise SPI is assumed)
#define TFT_PARALLEL_8_BIT
// Define the display driver chip type
#define ILI9341_DRIVER
//#define ILI9481_DRIVER
// Define the Nucleo 64/144 pins used for the parallel interface TFT
// The pins can be changed here but these are the ones used by the
// common "MCUfriend" shields
#define TFT_CS A3 // Chip select control pin
#define TFT_DC A2 // Data Command control pin
#define TFT_RST A4 // Reset pin
#define TFT_WR A1 // Write strobe control pin
#define TFT_RD A0 // Read pin
#define TFT_D0 D8 // 8 bit parallel bus to TFT
#define TFT_D1 D9
#define TFT_D2 D2
#define TFT_D3 D3
#define TFT_D4 D4
#define TFT_D5 D5
#define TFT_D6 D6
#define TFT_D7 D7
// Fonts to be available
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:.
#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
// At the moment SMOOTH fonts must be disabled for STM32 processors (due to lack of SPIFFS)
// Support for smooth fonts via SD cards is planned.
//#define SMOOTH_FONT

View File

@@ -0,0 +1,111 @@
// Example for library:
// https://github.com/Bodmer/TJpg_Decoder
// This example renders a Jpeg file that is stored in an array within Flash (program) memory
// see panda.h tab. The panda image file being ~13Kbytes.
#define USE_DMA
// Include the array
#include "panda.h"
// Include the jpeg decoder library
#include <TJpg_Decoder.h>
#ifdef USE_DMA
uint16_t dmaBuffer1[16*16]; // Toggle buffer for 16*16 MCU block, 512bytes
uint16_t dmaBuffer2[16*16]; // Toggle buffer for 16*16 MCU block, 512bytes
uint16_t* dmaBufferPtr = dmaBuffer1;
bool dmaBufferSel = 0;
#endif
// Include the TFT library https://github.com/Bodmer/TFT_eSPI
#include "SPI.h"
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
// This next function will be called during decoding of the jpeg file to render each
// 16x16 or 8x8 image tile (Minimum Coding Unit) to the TFT.
bool tft_output(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t* bitmap)
{
// Stop further decoding as image is running off bottom of screen
if ( y >= tft.height() ) return 0;
// STM32F767 processor takes 43ms just to decode (and not draw) jpeg (-Os compile option)
// Total time to decode and also draw to TFT:
// SPI 54MHz=71ms, with DMA 50ms, 71-43 = 28ms spent drawing, so DMA is complete before next MCU block is ready
// Apparent performance benefit of DMA = 71/50 = 42%, 50 - 43 = 7ms lost elsewhere
// SPI 27MHz=95ms, with DMA 52ms. 95-43 = 52ms spent drawing, so DMA is *just* complete before next MCU block is ready!
// Apparent performance benefit of DMA = 95/52 = 83%, 52 - 43 = 9ms lost elsewhere
#ifdef USE_DMA
// Double buffering is used, the bitmap is copied to the buffer by pushImageDMA() the
// bitmap can then be updated by the jpeg decoder while DMA is in progress
if (dmaBufferSel) dmaBufferPtr = dmaBuffer2;
else dmaBufferPtr = dmaBuffer1;
dmaBufferSel != dmaBufferSel; // Toggle buffer selection
// pushImageDMA() will clip the image block at screen boundaries before initiating DMA
tft.pushImageDMA(x, y, w, h, bitmap, dmaBufferPtr); // Initiate DMA - blocking only if last DMA is not complete
// The DMA transfer of image block to the TFT is now in progress...
#else
// Non-DMA blocking alternative
tft.pushImage(x, y, w, h, bitmap); // Blocking, so only returns when image block is drawn
#endif
// Return 1 to decode next block.
return 1;
}
void setup()
{
Serial.begin(115200);
Serial.println("\n\n Testing TJpg_Decoder library");
// Initialise the TFT
tft.begin();
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.fillScreen(TFT_BLACK);
#ifdef USE_DMA
tft.initDMA(); // To use SPI DMA you must call initDMA() to setup the DMA engine
#endif
// The jpeg image can be scaled down by a factor of 1, 2, 4, or 8
TJpgDec.setJpgScale(1);
// The colour byte order can be swapped by the decoder
// using TJpgDec.setSwapBytes(true); or by the TFT_eSPI library:
tft.setSwapBytes(true);
// The decoder must be given the exact name of the rendering function above
TJpgDec.setCallback(tft_output);
}
void loop()
{
// Show a contrasting colour for demo of draw speed
tft.fillScreen(TFT_RED);
// Get the width and height in pixels of the jpeg if you wish:
uint16_t w = 0, h = 0;
TJpgDec.getJpgSize(&w, &h, panda, sizeof(panda));
Serial.print("Width = "); Serial.print(w); Serial.print(", height = "); Serial.println(h);
// Time recorded for test purposes
uint32_t dt = millis();
// Must use startWrite first so TFT chip select stays low during DMA and SPI channel settings remain configured
tft.startWrite();
// Draw the image, top left at 0,0 - DMA request is handled in the call-back tft_output() in this sketch
TJpgDec.drawJpg(0, 0, panda, sizeof(panda));
// Must use endWrite to release the TFT chip select and release the SPI channel
tft.endWrite();
// How much time did rendering take (ESP8266 80MHz 262ms, 160MHz 149ms, ESP32 SPI 111ms, 8bit parallel 90ms
dt = millis() - dt;
Serial.print(dt); Serial.println(" ms");
// Wait before drawing again
delay(2000);
}

View File

@@ -0,0 +1,818 @@
/* Create C arrays from jpeg images using this online tool:
http://tomeko.net/online_tools/file_to_hex.php?lang=en
If needed, first resize and crop to an appropriate width and height
to suit your display with an image editting program such as IrfanView.
You can also change the image "guality" to reduce the file size.
Paste the array into a new tabe, top and tail the array from the
tool to look like the one below with:
#include <pgmspace.h>
const uint8_t name[] PROGMEM = {
to start and and end with:
};
Change the name of the array. Make sure the original jpeg is less than 32Kbyes
as there is an array size limit imposed by the Arduino IDE!
*/
#include <pgmspace.h>
const uint8_t panda[] PROGMEM = {
0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0xB4,
0x00, 0xB4, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08,
0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0A, 0x0C, 0x14, 0x0D, 0x0C, 0x0B, 0x0B, 0x0C, 0x19, 0x12,
0x13, 0x0F, 0x14, 0x1D, 0x1A, 0x1F, 0x1E, 0x1D, 0x1A, 0x1C, 0x1C, 0x20, 0x24, 0x2E, 0x27, 0x20,
0x22, 0x2C, 0x23, 0x1C, 0x1C, 0x28, 0x37, 0x29, 0x2C, 0x30, 0x31, 0x34, 0x34, 0x34, 0x1F, 0x27,
0x39, 0x3D, 0x38, 0x32, 0x3C, 0x2E, 0x33, 0x34, 0x32, 0xFF, 0xDB, 0x00, 0x43, 0x01, 0x09, 0x09,
0x09, 0x0C, 0x0B, 0x0C, 0x18, 0x0D, 0x0D, 0x18, 0x32, 0x21, 0x1C, 0x21, 0x32, 0x32, 0x32, 0x32,
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32,
0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0xFF, 0xC0,
0x00, 0x11, 0x08, 0x01, 0x40, 0x00, 0xF0, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11,
0x01, 0xFF, 0xC4, 0x00, 0x1C, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x02, 0x03, 0x05, 0x06, 0x07, 0x00, 0x08, 0xFF,
0xC4, 0x00, 0x3A, 0x10, 0x00, 0x02, 0x01, 0x03, 0x02, 0x04, 0x05, 0x02, 0x03, 0x07, 0x05, 0x00,
0x02, 0x03, 0x00, 0x00, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x12, 0x21, 0x05, 0x31, 0x41, 0x51,
0x06, 0x13, 0x22, 0x61, 0x71, 0x32, 0x81, 0x07, 0x91, 0xA1, 0x14, 0x23, 0x42, 0xB1, 0xC1, 0xD1,
0xF0, 0x15, 0x52, 0x62, 0xE1, 0xF1, 0x16, 0x33, 0x24, 0x72, 0x82, 0xFF, 0xC4, 0x00, 0x19, 0x01,
0x00, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x02, 0x03, 0x00, 0x04, 0x05, 0xFF, 0xC4, 0x00, 0x21, 0x11, 0x01, 0x01, 0x00, 0x02, 0x03,
0x01, 0x01, 0x01, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x11, 0x03,
0x21, 0x31, 0x12, 0x41, 0x13, 0x04, 0x32, 0x51, 0x22, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00,
0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0x8E, 0xC2, 0x24, 0x44, 0xCB, 0x0C, 0x7B, 0x0A, 0x9A,
0x5B, 0x80, 0xA7, 0x03, 0x95, 0x0E, 0x9A, 0xCA, 0x00, 0xA7, 0x48, 0xA7, 0x88, 0x40, 0xDC, 0x9C,
0x9F, 0x7A, 0xE4, 0x9D, 0x4E, 0x91, 0xCD, 0x28, 0x9C, 0xB2, 0xF2, 0xAF, 0x5B, 0x03, 0xE7, 0x64,
0xF7, 0xA8, 0xB2, 0x06, 0xC2, 0x8A, 0x81, 0x7D, 0x3A, 0xA9, 0x6C, 0xED, 0x3D, 0x0C, 0x9E, 0x55,
0x11, 0xE9, 0xE7, 0x55, 0x37, 0x0A, 0x0E, 0xEB, 0xCE, 0xA7, 0x95, 0x8B, 0x3E, 0xF5, 0x13, 0xAE,
0xD9, 0xCD, 0x3D, 0x34, 0x0F, 0x1A, 0xA8, 0xE9, 0xBF, 0x73, 0x49, 0x28, 0x27, 0x91, 0x38, 0xA5,
0x32, 0xA2, 0x1D, 0xDB, 0x1F, 0x35, 0x13, 0x5C, 0x07, 0x07, 0x1F, 0x4D, 0x2C, 0x19, 0x8E, 0xCD,
0x1B, 0x1C, 0x0F, 0xCA, 0x89, 0x8A, 0x15, 0x2A, 0x4B, 0x0A, 0xAE, 0x33, 0x16, 0x98, 0x20, 0xDB,
0x3D, 0x2A, 0xD0, 0x4A, 0x20, 0x83, 0x51, 0xFA, 0x71, 0x46, 0x4E, 0xD3, 0xBD, 0x29, 0xF8, 0xAD,
0xB6, 0x01, 0x68, 0xDB, 0x2B, 0xD5, 0x6B, 0x38, 0x6C, 0x99, 0x24, 0x2E, 0xA7, 0xD2, 0x4F, 0x2A,
0xBC, 0xBD, 0xBE, 0x02, 0x63, 0x83, 0xB1, 0xE9, 0x41, 0x99, 0x91, 0xB9, 0x0E, 0x74, 0x32, 0xCA,
0x1B, 0x18, 0x82, 0x14, 0xD2, 0x37, 0xA9, 0x83, 0x6F, 0x5E, 0xCE, 0xD8, 0x14, 0xE6, 0x09, 0x14,
0x45, 0x89, 0x1A, 0xB1, 0xB0, 0x26, 0x96, 0x6F, 0x2E, 0xA2, 0xB0, 0xF3, 0x2A, 0xC0, 0x35, 0x36,
0x0F, 0xB5, 0x45, 0x35, 0xF2, 0x36, 0x90, 0xA0, 0x26, 0x30, 0x79, 0xF3, 0xAA, 0xAB, 0xAB, 0xC2,
0x58, 0x86, 0xDB, 0x3C, 0x86, 0x28, 0x2F, 0xDA, 0x0E, 0x82, 0xA0, 0x9F, 0x62, 0x6B, 0xAB, 0x0E,
0x29, 0x27, 0x62, 0xB4, 0x9E, 0xF1, 0xF3, 0x8D, 0x5B, 0x67, 0x63, 0xDC, 0x52, 0x8E, 0x24, 0xD1,
0x85, 0x24, 0xEA, 0xD8, 0x9F, 0xBD, 0x53, 0x19, 0x89, 0xC0, 0x63, 0xF1, 0x4E, 0x2C, 0x74, 0x1C,
0x1D, 0xBA, 0x55, 0xA7, 0x40, 0xD9, 0x59, 0xF1, 0x94, 0x31, 0x69, 0x91, 0x71, 0x9D, 0x8B, 0x55,
0x90, 0x91, 0x65, 0x42, 0x63, 0x6D, 0xF3, 0x80, 0x33, 0x5C, 0xFB, 0xF6, 0x93, 0x18, 0x0D, 0x9E,
0x46, 0xAD, 0x6C, 0xB8, 0xA3, 0xAB, 0x8C, 0xB1, 0xC7, 0x53, 0xDF, 0xDA, 0x97, 0x2C, 0x66, 0x53,
0x46, 0x68, 0xA4, 0x8C, 0xAE, 0xA2, 0xC3, 0xAE, 0xF5, 0x5B, 0x72, 0x4E, 0xAC, 0x8A, 0xB1, 0xF3,
0xC5, 0xC5, 0xA0, 0x60, 0xDA, 0x54, 0x77, 0x34, 0x1C, 0x88, 0x08, 0xDE, 0xBC, 0xFC, 0xF8, 0xBE,
0x6B, 0x2B, 0x1E, 0x42, 0x49, 0x19, 0xA6, 0xE3, 0x23, 0x73, 0x52, 0x4E, 0xA1, 0x4E, 0xD5, 0x08,
0x26, 0xA5, 0xAD, 0x52, 0x58, 0xF1, 0x38, 0x3B, 0x57, 0x88, 0x2D, 0x4A, 0x14, 0xBB, 0x60, 0x0D,
0xCF, 0x41, 0x5A, 0x8F, 0x0D, 0xF8, 0x1F, 0x8B, 0xF8, 0x89, 0xD1, 0xA0, 0x80, 0xC5, 0x6A, 0xDC,
0xE7, 0x93, 0x61, 0xF6, 0xA6, 0x98, 0x77, 0xD0, 0x49, 0x6D, 0x66, 0xE0, 0xB5, 0x7B, 0x89, 0x16,
0x28, 0x91, 0x9E, 0x57, 0x38, 0x55, 0x51, 0xB9, 0x35, 0xD2, 0xBC, 0x2D, 0xF8, 0x4B, 0x3D, 0xE7,
0x97, 0x75, 0xC5, 0xDC, 0xC3, 0x09, 0x01, 0x95, 0x23, 0x23, 0x57, 0xDF, 0x20, 0x8A, 0xE8, 0x1E,
0x18, 0xF0, 0x0F, 0x0A, 0xF0, 0xE4, 0x6A, 0xFA, 0x45, 0xCD, 0xD6, 0x06, 0xA9, 0xA4, 0x51, 0xCF,
0xDB, 0xB5, 0x6B, 0x2B, 0xAB, 0x0E, 0x29, 0xFA, 0xAC, 0xC6, 0x40, 0xB6, 0x1C, 0x36, 0xD3, 0x85,
0xDA, 0xA5, 0xBD, 0x9D, 0xBC, 0x70, 0xC6, 0x83, 0x00, 0x22, 0x01, 0xFC, 0xA8, 0x93, 0x9A, 0xF1,
0xDF, 0xAD, 0x26, 0xE3, 0xAD, 0x5B, 0xC1, 0x7C, 0xFF, 0x00, 0x1B, 0x90, 0x06, 0x06, 0xD4, 0xC7,
0x96, 0x42, 0x7A, 0x28, 0xAF, 0x34, 0xCA, 0x87, 0x4F, 0x5A, 0x66, 0x0B, 0x1C, 0x85, 0x3F, 0x26,
0xB9, 0x25, 0x43, 0x2A, 0x91, 0x0E, 0xA3, 0x8C, 0xD1, 0xAB, 0x26, 0x84, 0x03, 0x34, 0x24, 0x2A,
0x14, 0xE4, 0x8A, 0x9C, 0xE1, 0x8E, 0x28, 0xCB, 0x76, 0x13, 0xC3, 0x48, 0x24, 0x96, 0xE9, 0x55,
0xD7, 0xF7, 0x86, 0x10, 0x71, 0x56, 0xED, 0x84, 0x8B, 0xFA, 0x55, 0x15, 0xE5, 0xB9, 0xBA, 0x62,
0x50, 0x64, 0x75, 0x14, 0xF4, 0xF8, 0xC0, 0x91, 0x4A, 0x67, 0xF5, 0x31, 0xA4, 0xB9, 0xBE, 0x48,
0x06, 0x90, 0x72, 0xDD, 0x85, 0x0B, 0x22, 0x4B, 0x6E, 0xC5, 0x08, 0xF8, 0xA8, 0x56, 0x06, 0x91,
0xC6, 0xA1, 0xB9, 0xA5, 0x5F, 0x1C, 0x3A, 0xEC, 0x77, 0x0C, 0x0F, 0x3C, 0xAD, 0x3B, 0xF2, 0xE9,
0x4F, 0xBF, 0xE2, 0x45, 0x25, 0x16, 0xDB, 0x90, 0x68, 0xB5, 0x8D, 0x6D, 0x6D, 0x34, 0xF2, 0x0A,
0x2A, 0x81, 0x95, 0xA7, 0xB8, 0x32, 0x13, 0xD7, 0x6A, 0xD7, 0xA9, 0xD3, 0x9A, 0xCF, 0xAC, 0x8F,
0x9A, 0x23, 0x26, 0x58, 0x1D, 0xFB, 0xD4, 0x21, 0x4A, 0x9E, 0x75, 0x64, 0xB0, 0x13, 0x1E, 0x4D,
0x09, 0xE5, 0xE6, 0x5C, 0x01, 0x49, 0x67, 0xE9, 0xA4, 0x49, 0x0A, 0x6A, 0x3B, 0xD0, 0x1C, 0x56,
0x66, 0x0F, 0xA1, 0x3A, 0x0E, 0xB5, 0x73, 0x14, 0x41, 0x53, 0x56, 0x2B, 0x39, 0xC6, 0x4E, 0x6E,
0x5D, 0x54, 0xE0, 0xA9, 0xDF, 0x03, 0x19, 0x1D, 0xEA, 0xBF, 0xE3, 0xE3, 0xDE, 0xCC, 0xAD, 0x92,
0x46, 0xCF, 0xA8, 0x9F, 0x83, 0x50, 0x16, 0xDF, 0x06, 0x9C, 0xDA, 0xCE, 0xC4, 0x93, 0xF3, 0x4D,
0x08, 0x71, 0x91, 0xBD, 0x75, 0x6C, 0x74, 0x70, 0x25, 0x97, 0x15, 0x2C, 0x59, 0xD5, 0xA0, 0x73,
0xDF, 0x9D, 0x24, 0x71, 0xEB, 0x2B, 0x83, 0xB9, 0xE6, 0x0D, 0x11, 0x14, 0x41, 0x89, 0x19, 0xDC,
0x75, 0x34, 0x40, 0xAB, 0x6C, 0xC6, 0x1C, 0x91, 0x91, 0xBE, 0x71, 0x4E, 0x11, 0xB4, 0x44, 0x10,
0x30, 0xB8, 0xAB, 0x0B, 0x22, 0x46, 0x53, 0x48, 0x21, 0x8E, 0x08, 0xCF, 0x4A, 0x36, 0xE7, 0x86,
0xBB, 0xDA, 0x1B, 0x91, 0x19, 0x0A, 0x5B, 0x48, 0x04, 0x1C, 0x93, 0xD6, 0x8F, 0x42, 0x83, 0x86,
0xDF, 0x3A, 0x90, 0xAC, 0xDB, 0x0F, 0xA7, 0x6A, 0xB4, 0x98, 0x16, 0x4F, 0x33, 0xCC, 0xD5, 0x9D,
0xCE, 0x45, 0x67, 0xED, 0xE2, 0x29, 0x74, 0x55, 0xC3, 0x0D, 0x39, 0xDB, 0xAF, 0xB7, 0xF3, 0x15,
0xBE, 0xF0, 0xEF, 0x84, 0xB8, 0x8F, 0x1E, 0x78, 0xE3, 0x48, 0xB1, 0x0E, 0xC5, 0xA4, 0xD5, 0xE9,
0x03, 0xE6, 0xB9, 0xF9, 0xB1, 0xDC, 0x6D, 0x31, 0x92, 0xEA, 0x62, 0x3A, 0xE4, 0xE0, 0x62, 0xB4,
0x1C, 0x1B, 0xC1, 0x1C, 0x6F, 0x8D, 0x2E, 0xAB, 0x6B, 0x37, 0x09, 0xD1, 0xDC, 0x69, 0x1F, 0x99,
0xE7, 0x5D, 0xC7, 0x81, 0x78, 0x23, 0x83, 0xF0, 0x58, 0xC6, 0x8B, 0x64, 0x92, 0x4E, 0x7A, 0xE4,
0x1A, 0x88, 0xAD, 0x2A, 0x22, 0xA2, 0xE9, 0x45, 0x0A, 0x3B, 0x01, 0x51, 0x9C, 0x1B, 0xF4, 0x7E,
0x63, 0x9E, 0xF8, 0x5F, 0xF0, 0xB7, 0x87, 0xF0, 0x93, 0x1D, 0xD7, 0x10, 0x63, 0x73, 0x74, 0x37,
0x03, 0x92, 0xA9, 0xF8, 0xEB, 0x5D, 0x09, 0x23, 0x48, 0x90, 0x2C, 0x68, 0x15, 0x7B, 0x01, 0x5E,
0x24, 0x83, 0x5E, 0xD5, 0x9A, 0xBE, 0x32, 0x63, 0xE0, 0xE8, 0xA6, 0x92, 0xBD, 0x9D, 0xEB, 0xC7,
0x14, 0xCC, 0xF1, 0x3D, 0x40, 0xA6, 0x12, 0x4E, 0x7F, 0x4A, 0x79, 0xC6, 0x29, 0x09, 0xC0, 0xE5,
0x4B, 0x46, 0x3E, 0x78, 0x84, 0x17, 0x3A, 0xF4, 0xEF, 0xDC, 0xD4, 0xE6, 0x37, 0x73, 0x92, 0x4D,
0x5E, 0x37, 0x0C, 0x88, 0xA6, 0x42, 0xE9, 0x3D, 0x85, 0x57, 0x5C, 0x29, 0x85, 0xB4, 0x91, 0x5C,
0xD8, 0xCD, 0x23, 0x70, 0x0A, 0x13, 0x4E, 0xDF, 0x9D, 0x39, 0xA4, 0x11, 0x8C, 0x9E, 0x54, 0x9A,
0xC9, 0x39, 0x3C, 0xAA, 0x19, 0x49, 0xE6, 0x0E, 0xDD, 0xA9, 0xFE, 0x42, 0xE3, 0xA2, 0xCB, 0x73,
0x95, 0xC6, 0x76, 0x34, 0x7D, 0x85, 0xB4, 0x6F, 0x06, 0xA3, 0xD4, 0x6E, 0x6B, 0x3D, 0x70, 0x59,
0x5B, 0x63, 0xB5, 0x1D, 0xC3, 0x6F, 0x5C, 0x42, 0x51, 0x8F, 0x2E, 0x54, 0x2F, 0x55, 0x6E, 0x3C,
0x76, 0x03, 0x8B, 0x85, 0x4B, 0x96, 0x02, 0x82, 0xB0, 0xFD, 0xED, 0xD8, 0x1D, 0x13, 0x7A, 0xB3,
0xBA, 0x87, 0xF6, 0x89, 0xDD, 0xC8, 0xF8, 0xCD, 0x09, 0x0E, 0x88, 0x26, 0x6C, 0x11, 0xAB, 0xAD,
0x6F, 0x27, 0x66, 0xE6, 0xBA, 0x9A, 0x89, 0x78, 0xA3, 0xE9, 0x83, 0x48, 0xE6, 0x6A, 0xBE, 0xD6,
0x22, 0x58, 0x60, 0x66, 0xA7, 0xBB, 0xB8, 0x12, 0x4C, 0x01, 0xED, 0x45, 0xD9, 0x22, 0x02, 0x01,
0x1B, 0x53, 0xD9, 0x2B, 0x9F, 0x19, 0xD2, 0x53, 0x09, 0x58, 0xB9, 0x74, 0xDE, 0xAB, 0xCC, 0x00,
0x31, 0x61, 0xB5, 0x5C, 0x5D, 0x48, 0xA9, 0x09, 0x20, 0xD5, 0x54, 0x72, 0x79, 0xB2, 0x60, 0xF2,
0xA9, 0xE5, 0xA9, 0xD1, 0xCC, 0xD4, 0x4B, 0x05, 0xD5, 0x81, 0xEE, 0x71, 0x54, 0x1C, 0x6E, 0xDC,
0xA5, 0xCF, 0x98, 0xAD, 0xF5, 0x0E, 0x43, 0xA5, 0x68, 0xEE, 0xA3, 0xD3, 0x18, 0x20, 0x61, 0xAA,
0xBF, 0x8B, 0xC6, 0x93, 0x70, 0xD5, 0x60, 0xA3, 0x5A, 0xF3, 0x23, 0x6A, 0xA7, 0x0F, 0x55, 0x99,
0x48, 0xF2, 0x5C, 0xAE, 0x74, 0xEA, 0xDB, 0x7D, 0xBF, 0xCE, 0x55, 0x24, 0x70, 0x33, 0x0C, 0x83,
0x8C, 0xF4, 0xC5, 0x79, 0x55, 0x9A, 0x40, 0xA0, 0x86, 0x3D, 0xB3, 0xFD, 0xEB, 0x49, 0xE1, 0xFF,
0x00, 0x0F, 0x4D, 0xC5, 0x6F, 0x22, 0x81, 0x11, 0xFD, 0x60, 0x91, 0x85, 0xC8, 0xFB, 0xE3, 0x95,
0x74, 0x8A, 0xA2, 0xDE, 0xC9, 0xE7, 0xD6, 0xAB, 0x1B, 0x33, 0xAA, 0xE7, 0x09, 0xCF, 0xFC, 0xDF,
0x35, 0xAD, 0xF0, 0x87, 0x81, 0x9F, 0x8D, 0xDC, 0x69, 0xB9, 0x72, 0x91, 0xE3, 0x07, 0x03, 0x07,
0x71, 0xB1, 0x1F, 0x15, 0xD5, 0x78, 0x2F, 0xE1, 0xE5, 0xB4, 0x10, 0xDB, 0xBB, 0xC0, 0x9E, 0x6C,
0x7C, 0x98, 0xAE, 0xE4, 0x76, 0x3D, 0x3B, 0xD6, 0xCA, 0xD3, 0x83, 0xDA, 0x58, 0xA0, 0x10, 0xC2,
0xA9, 0x83, 0x9C, 0x28, 0xC5, 0x2D, 0xCB, 0xFE, 0x1A, 0x46, 0x3F, 0x83, 0x7E, 0x1E, 0xF0, 0xFB,
0x28, 0x11, 0x24, 0x85, 0x24, 0xC0, 0xC3, 0x9C, 0x6C, 0xD8, 0xE4, 0x77, 0xAD, 0x0A, 0xF8, 0x5F,
0x86, 0x98, 0x7C, 0xA7, 0xB6, 0x8D, 0xA3, 0xE8, 0xA5, 0x79, 0x0F, 0xFC, 0xAB, 0xD0, 0xA0, 0x6C,
0x06, 0x29, 0x84, 0xE3, 0xAF, 0xCD, 0x4E, 0xD3, 0xC8, 0xCF, 0xAF, 0x81, 0x7C, 0x38, 0xB2, 0xBC,
0xDF, 0xE9, 0x50, 0x34, 0x8E, 0x49, 0x2E, 0x46, 0xF9, 0x35, 0x7B, 0x6F, 0x0C, 0x36, 0x70, 0xAC,
0x50, 0x44, 0xB1, 0xC6, 0xBC, 0x82, 0x8C, 0x52, 0x89, 0x29, 0x0C, 0x83, 0x34, 0xBB, 0x37, 0xCA,
0x7F, 0x34, 0xD7, 0xBC, 0xDE, 0xF4, 0x31, 0x71, 0xB9, 0xDA, 0xA9, 0x3C, 0x45, 0xE2, 0x5B, 0x4E,
0x05, 0xC3, 0xA6, 0x9E, 0x69, 0x54, 0x3A, 0x21, 0x60, 0xA4, 0xEE, 0x6B, 0x7D, 0xD6, 0xF8, 0x68,
0x24, 0xBA, 0x8A, 0x35, 0x2C, 0xCE, 0x00, 0x03, 0x27, 0x7A, 0x1F, 0xFD, 0x56, 0xD1, 0x94, 0xB0,
0x9D, 0x0A, 0x8D, 0xC9, 0xD5, 0xD2, 0xBE, 0x72, 0xE3, 0x5F, 0x8A, 0x97, 0xF3, 0x71, 0x1B, 0xD7,
0xB6, 0x25, 0x22, 0x9B, 0xD0, 0xAB, 0x9E, 0x4B, 0x8F, 0x6F, 0xBD, 0x67, 0x7F, 0xF9, 0xBF, 0x11,
0x8C, 0x3A, 0xC3, 0x33, 0x28, 0x92, 0x01, 0x13, 0x82, 0x7B, 0x0C, 0x6D, 0xDB, 0x6A, 0x7D, 0x52,
0xEF, 0x18, 0xFA, 0x9C, 0x78, 0x8F, 0x87, 0x00, 0x75, 0x5C, 0x46, 0xA4, 0x30, 0x4C, 0x67, 0xA9,
0xA2, 0xA2, 0xE2, 0x96, 0x93, 0x2E, 0xA4, 0x99, 0x19, 0x71, 0xA8, 0x90, 0x7A, 0x77, 0xAF, 0x8F,
0xA3, 0xF1, 0x57, 0x10, 0x8E, 0xE2, 0x39, 0x4C, 0xEC, 0xDE, 0x5B, 0x33, 0x2A, 0x9D, 0xC0, 0x26,
0xAD, 0xF8, 0x4F, 0x8E, 0xAF, 0xEC, 0xE3, 0x58, 0x9E, 0xE5, 0xBC, 0xA2, 0xC1, 0x9B, 0xDF, 0x1F,
0x4E, 0x7E, 0x39, 0xE2, 0x8F, 0xCD, 0x81, 0xBC, 0x6B, 0xEB, 0x05, 0xB8, 0x46, 0x50, 0xCA, 0x41,
0x06, 0xBC, 0x64, 0x07, 0x91, 0xFB, 0x57, 0x09, 0xE0, 0x9F, 0x89, 0xF2, 0xC3, 0x13, 0x3D, 0xC9,
0x24, 0x31, 0x0B, 0x1C, 0x61, 0xB7, 0xC7, 0xFC, 0x89, 0xEA, 0x7F, 0x95, 0x74, 0xBE, 0x13, 0xE2,
0x9B, 0x7B, 0xD8, 0x22, 0x46, 0x95, 0x1A, 0xE5, 0xFE, 0xA8, 0x94, 0xFD, 0x34, 0x97, 0x70, 0xF2,
0x4B, 0xE3, 0x01, 0x65, 0xC6, 0x92, 0x67, 0xF2, 0xE4, 0x6F, 0x51, 0x34, 0xCE, 0x2D, 0x75, 0x11,
0x00, 0x9C, 0x0C, 0x56, 0x22, 0xDD, 0xA5, 0x17, 0x0A, 0xC1, 0x8E, 0x47, 0xE9, 0x57, 0xF1, 0xDB,
0x49, 0x77, 0x6E, 0x1A, 0x52, 0x73, 0x8A, 0x9C, 0x97, 0x7A, 0x47, 0x7D, 0x68, 0xF5, 0xB8, 0x1E,
0x59, 0x20, 0xE7, 0x3C, 0xA9, 0xC9, 0x26, 0x41, 0x27, 0xEF, 0x50, 0x45, 0x1E, 0x8C, 0xA3, 0x74,
0x34, 0xDB, 0x86, 0x01, 0x59, 0x41, 0xC1, 0xA6, 0xAD, 0x87, 0xFE, 0xA9, 0x92, 0x62, 0x42, 0x71,
0x4E, 0xB5, 0xC4, 0x6E, 0x72, 0x6A, 0x38, 0xBE, 0x9D, 0xEA, 0x1B, 0x89, 0xCC, 0x3B, 0x81, 0x49,
0x7D, 0x74, 0x61, 0x35, 0x05, 0x5E, 0x4A, 0x16, 0x33, 0xA4, 0xF5, 0xDA, 0xAB, 0x2D, 0x89, 0xD4,
0xCC, 0x77, 0x2D, 0xCC, 0x9A, 0x69, 0xBA, 0x69, 0x07, 0xA8, 0x6D, 0x43, 0x06, 0x61, 0x2E, 0xD9,
0xC7, 0xB5, 0x3D, 0xC7, 0x71, 0x1E, 0x5E, 0xC4, 0xCB, 0x09, 0x69, 0x4B, 0x03, 0xE9, 0xCD, 0x19,
0x03, 0x68, 0x50, 0x33, 0xD2, 0x82, 0x32, 0x04, 0x5C, 0x62, 0xA4, 0x8F, 0x5B, 0x28, 0x6C, 0x6D,
0x4B, 0x75, 0x12, 0x94, 0xFB, 0x9B, 0x87, 0x76, 0xD2, 0x06, 0xD4, 0x96, 0xB1, 0x92, 0xEA, 0xD9,
0xC1, 0xA9, 0xFF, 0x00, 0x66, 0xFD, 0xD9, 0x24, 0xEF, 0xCE, 0xA3, 0x8D, 0xB4, 0xE4, 0x11, 0xCA,
0xA7, 0x7B, 0xA3, 0xB4, 0x97, 0x4F, 0x88, 0xF4, 0x31, 0xCB, 0x50, 0xF0, 0x05, 0x74, 0x78, 0xDC,
0x02, 0xAC, 0x39, 0x1A, 0x90, 0x8F, 0x35, 0x89, 0x22, 0xB4, 0x7E, 0x18, 0xF0, 0x95, 0xD7, 0x1E,
0x94, 0x88, 0x57, 0x44, 0x4B, 0xF5, 0x4A, 0xC3, 0x6A, 0xA7, 0x7B, 0xE8, 0x64, 0x67, 0xFC, 0x37,
0xE0, 0xFB, 0x8E, 0x2D, 0xC4, 0x9A, 0xDA, 0x05, 0x18, 0xCE, 0xE4, 0xAE, 0xCA, 0x33, 0xD4, 0xE3,
0xB5, 0x77, 0xEF, 0x0F, 0x78, 0x53, 0x86, 0xF8, 0x7E, 0x12, 0x2D, 0xA0, 0x55, 0x91, 0xB1, 0xAD,
0xBB, 0x9F, 0xE9, 0x46, 0x70, 0x4E, 0x07, 0x69, 0xC0, 0xEC, 0x92, 0xDE, 0xDD, 0x72, 0x40, 0xC1,
0x91, 0x80, 0xD4, 0x7E, 0xF5, 0x66, 0x6B, 0xA7, 0xBD, 0x76, 0x62, 0x6C, 0x06, 0xC2, 0x9A, 0xCF,
0x81, 0xCA, 0x98, 0xF2, 0x63, 0x6F, 0xEB, 0x50, 0xBC, 0x8C, 0x06, 0xD8, 0xF6, 0xC1, 0xA4, 0xB9,
0x1A, 0x63, 0xB3, 0x9D, 0xCE, 0xE4, 0x9C, 0x0F, 0x6A, 0x84, 0xB9, 0x3C, 0x85, 0x46, 0x72, 0x4E,
0x5F, 0x3F, 0x63, 0x51, 0xBB, 0x80, 0x32, 0x07, 0xC6, 0x6A, 0x37, 0x25, 0xA6, 0x29, 0x0B, 0xEE,
0x49, 0x3F, 0x6A, 0x4F, 0x30, 0xE7, 0x6A, 0x80, 0x16, 0x7C, 0x90, 0x30, 0x6B, 0xC4, 0x1D, 0x89,
0x3F, 0x71, 0x4B, 0x69, 0xF4, 0x74, 0xF2, 0xAC, 0x10, 0xB4, 0xB2, 0x36, 0x14, 0x0C, 0x93, 0x5F,
0x36, 0xFE, 0x27, 0x78, 0xB5, 0xB8, 0xD7, 0x1A, 0x30, 0xC2, 0xDF, 0xB9, 0x83, 0x29, 0x91, 0xD6,
0xBA, 0xAF, 0xE2, 0x8F, 0x19, 0x97, 0x85, 0xF8, 0x5D, 0xFC, 0xA9, 0x5A, 0x39, 0x24, 0x6D, 0x2A,
0xC3, 0xB7, 0x51, 0xEF, 0x5F, 0x35, 0x4C, 0xEC, 0xEE, 0x58, 0xEE, 0x49, 0xAB, 0x71, 0x63, 0xD6,
0xD1, 0xE5, 0xBA, 0xE8, 0x85, 0x8B, 0x01, 0xBD, 0x33, 0x3B, 0xF3, 0xA5, 0xCE, 0x57, 0x7A, 0x63,
0x1A, 0xBA, 0x05, 0x27, 0x34, 0xAA, 0xC4, 0x0D, 0xB9, 0xD4, 0x62, 0x9E, 0xA3, 0x3C, 0xCD, 0x60,
0x15, 0x14, 0xCD, 0x18, 0x04, 0x1C, 0x56, 0xCF, 0xC2, 0x3C, 0x7A, 0xF6, 0x1B, 0xD4, 0x44, 0x9D,
0x60, 0x88, 0x80, 0x65, 0x94, 0xF4, 0x51, 0xFC, 0xBF, 0x95, 0x61, 0x54, 0xE4, 0xE0, 0x55, 0x95,
0xA7, 0x9B, 0x03, 0x06, 0x52, 0x06, 0x39, 0x12, 0x73, 0xF9, 0x0A, 0x16, 0x6E, 0x1B, 0x1B, 0xAA,
0xDA, 0xEC, 0xB2, 0x7A, 0x70, 0x37, 0xAB, 0xFB, 0x2B, 0xA5, 0x36, 0xAA, 0xA4, 0xEE, 0x2B, 0x37,
0x00, 0x33, 0x39, 0x24, 0x11, 0xBF, 0x3A, 0xB7, 0x88, 0x84, 0x50, 0x0D, 0x46, 0xCB, 0xB4, 0xF7,
0xA1, 0xA6, 0x3D, 0x99, 0x87, 0xBD, 0x00, 0xC0, 0x92, 0x4B, 0x6F, 0xBD, 0x14, 0xD7, 0x20, 0x45,
0xBF, 0x2A, 0x08, 0x6B, 0x76, 0x62, 0xA7, 0x6A, 0x4C, 0xAE, 0x95, 0xE3, 0x85, 0x12, 0x22, 0x1C,
0x11, 0xB5, 0x47, 0x2A, 0x87, 0x19, 0xE9, 0x50, 0x4E, 0x92, 0x2B, 0xE3, 0x34, 0xE2, 0xC7, 0xCB,
0xC1, 0x04, 0x1A, 0x58, 0xE9, 0xF2, 0x68, 0x23, 0x60, 0x31, 0x51, 0x52, 0x45, 0x16, 0x58, 0x77,
0xA6, 0x88, 0xC8, 0x60, 0x4D, 0x11, 0x18, 0x23, 0xD5, 0xA7, 0x6A, 0xAD, 0xEA, 0x38, 0xF3, 0xF5,
0x14, 0xB0, 0x92, 0x41, 0x07, 0x6E, 0xB4, 0x42, 0xC9, 0x1A, 0x26, 0x41, 0xDF, 0x1C, 0xA9, 0x85,
0xF5, 0x36, 0x00, 0xA6, 0xBC, 0x2E, 0xD8, 0x2A, 0xA5, 0xBB, 0xE2, 0xA1, 0x74, 0x5D, 0x27, 0x5B,
0x90, 0xF8, 0x18, 0xC5, 0x3C, 0xE8, 0x2A, 0x4A, 0x8C, 0x1A, 0x1E, 0x3B, 0x79, 0x1C, 0x65, 0x46,
0x31, 0xDE, 0xB6, 0xDE, 0x03, 0xF0, 0x63, 0x71, 0xBB, 0x81, 0x7B, 0x7C, 0x24, 0x16, 0x91, 0xB6,
0xC0, 0xAE, 0x04, 0x87, 0xB6, 0x68, 0x49, 0x6D, 0xD4, 0x34, 0xEC, 0x0F, 0x85, 0xBC, 0x1D, 0x77,
0xC7, 0xAF, 0x90, 0x37, 0xEE, 0xED, 0x06, 0x19, 0xE5, 0x5C, 0x30, 0x23, 0xB6, 0x46, 0xD9, 0xAE,
0xDD, 0xC3, 0x38, 0x55, 0x97, 0x07, 0xB4, 0x16, 0xD6, 0x50, 0xAC, 0x51, 0xF3, 0x38, 0xEA, 0x7B,
0x9A, 0x9E, 0xDE, 0xD6, 0x0B, 0x38, 0x16, 0x1B, 0x78, 0x92, 0x28, 0x97, 0x92, 0xA2, 0x80, 0x07,
0xE5, 0x4E, 0x79, 0x02, 0xF5, 0xFC, 0xAB, 0xAB, 0x1C, 0x66, 0x3E, 0x9E, 0x43, 0xD9, 0x82, 0x8C,
0x93, 0x50, 0x3C, 0xA0, 0xE4, 0x6F, 0x9E, 0x82, 0xA2, 0x69, 0x59, 0x9B, 0x39, 0xDB, 0xE2, 0x93,
0x49, 0xC7, 0xD4, 0x77, 0xEB, 0x8A, 0x17, 0x2D, 0xA9, 0x31, 0x79, 0x99, 0xB2, 0x39, 0x63, 0xE6,
0xA2, 0x25, 0x8E, 0x70, 0x70, 0x29, 0x5D, 0x8A, 0x0F, 0x49, 0x03, 0xDA, 0xA3, 0x0C, 0xCE, 0x76,
0xFA, 0x73, 0xCA, 0xA7, 0x54, 0x91, 0xED, 0x05, 0xB9, 0xB6, 0x3D, 0xC5, 0x23, 0x2E, 0x8C, 0x65,
0xFF, 0x00, 0x31, 0x52, 0xEA, 0x25, 0x88, 0xC6, 0x3E, 0x69, 0xB8, 0x08, 0x0B, 0x36, 0xE7, 0xDE,
0x97, 0x43, 0xB3, 0x4E, 0x92, 0x06, 0x91, 0x8A, 0x67, 0xD2, 0xDA, 0x98, 0x02, 0x31, 0xF3, 0x4C,
0x92, 0x56, 0x3C, 0x86, 0x7B, 0x76, 0xA6, 0x23, 0x82, 0xE0, 0x36, 0xD8, 0x3C, 0xC1, 0xEB, 0x40,
0x5C, 0xA3, 0xF1, 0xBE, 0x60, 0xDC, 0x26, 0xCE, 0x35, 0x1B, 0x79, 0x99, 0xDC, 0x63, 0x15, 0xC1,
0xCE, 0x79, 0x57, 0xD0, 0x3F, 0x8E, 0x48, 0xCF, 0xE1, 0xFB, 0x47, 0x0C, 0x34, 0xA4, 0xBB, 0x02,
0x37, 0xCE, 0x3F, 0x4A, 0xF9, 0xF8, 0x83, 0x5D, 0x3C, 0x7F, 0xEA, 0xE7, 0xE4, 0xF5, 0x1B, 0x11,
0x8E, 0x54, 0xCD, 0xCF, 0x2A, 0x7B, 0x0C, 0x1A, 0x67, 0x4C, 0xF5, 0xAA, 0x24, 0x5D, 0xC6, 0x29,
0xEA, 0xB9, 0x14, 0xD5, 0xED, 0x8D, 0xFB, 0xD3, 0x84, 0x4D, 0xCC, 0x7E, 0x95, 0x98, 0xF5, 0x61,
0x19, 0xC6, 0x37, 0xF7, 0xA9, 0x83, 0x16, 0x23, 0x0C, 0x40, 0xA8, 0xE3, 0x94, 0xA8, 0x28, 0xE0,
0x32, 0x37, 0x3C, 0x8D, 0xFE, 0xC7, 0xA5, 0x49, 0xE4, 0xA1, 0xDD, 0x18, 0x9F, 0x93, 0x58, 0x5D,
0x36, 0xDF, 0x4A, 0xA0, 0x3C, 0xF6, 0xAF, 0x45, 0x28, 0x92, 0xE0, 0x29, 0xF7, 0xE5, 0x40, 0xDB,
0x89, 0x4C, 0x63, 0x9E, 0x33, 0x46, 0xD9, 0xDB, 0x32, 0xCC, 0x5C, 0xF4, 0x15, 0x1B, 0xC9, 0xAD,
0x42, 0x49, 0xDF, 0x62, 0x27, 0x88, 0xB6, 0x02, 0xF2, 0xA9, 0x60, 0x88, 0x2E, 0x7A, 0x1A, 0x46,
0x90, 0x2E, 0x32, 0x3A, 0xFE, 0x94, 0x89, 0x30, 0x66, 0x23, 0x18, 0xDB, 0x9D, 0x4F, 0x3D, 0x55,
0xF8, 0xFD, 0x7A, 0xE2, 0x35, 0x63, 0x8C, 0x55, 0x7C, 0xCA, 0xDD, 0x0E, 0xC2, 0x8E, 0x77, 0xEF,
0x4E, 0x31, 0x2B, 0xC0, 0x49, 0x14, 0x22, 0xD9, 0xDD, 0x45, 0x40, 0x72, 0x76, 0x23, 0x14, 0x50,
0x65, 0x09, 0xB1, 0xE9, 0xCA, 0xAB, 0xE7, 0x98, 0xAC, 0x8D, 0x8F, 0x8A, 0x9A, 0xDC, 0xB3, 0x26,
0x48, 0xDA, 0x9B, 0xEE, 0x5E, 0x9C, 0x79, 0x1C, 0xAC, 0xCA, 0xE5, 0xB1, 0xB5, 0x5D, 0x58, 0x94,
0x6B, 0x41, 0x87, 0x50, 0xD9, 0xC9, 0x06, 0xA9, 0x18, 0x86, 0x6D, 0x2A, 0x77, 0xED, 0x45, 0x5A,
0x5B, 0x4D, 0x73, 0x32, 0x5B, 0xC1, 0x1B, 0xBC, 0xAE, 0x42, 0x85, 0x5E, 0xB5, 0x1D, 0x6B, 0x2E,
0x83, 0xB6, 0x9B, 0x81, 0xF0, 0x57, 0xE3, 0xF7, 0xC2, 0x0B, 0x46, 0x8C, 0x04, 0x23, 0x59, 0x2D,
0xB8, 0x1D, 0xF1, 0xFF, 0x00, 0x95, 0xDA, 0xF8, 0x77, 0x0F, 0x83, 0x85, 0x58, 0x47, 0x6B, 0x6E,
0x08, 0x44, 0x1D, 0x4E, 0x49, 0xAA, 0xFF, 0x00, 0x0A, 0xF0, 0x7F, 0xF4, 0x4E, 0x01, 0x6F, 0x6E,
0xD1, 0xA2, 0x4D, 0xA7, 0x54, 0x9A, 0x7F, 0xDC, 0x7D, 0xF0, 0x3F, 0x95, 0x59, 0xC8, 0x4E, 0x09,
0xC9, 0xFB, 0x0A, 0xE8, 0xC6, 0x7C, 0xC5, 0x71, 0xC4, 0xB2, 0x33, 0x32, 0xEC, 0xDA, 0x7D, 0xE8,
0x72, 0x54, 0xB6, 0x47, 0xE7, 0x4C, 0x91, 0xB5, 0x1D, 0x23, 0xD5, 0xDF, 0x3B, 0x62, 0xA3, 0x2D,
0xA4, 0x85, 0x09, 0xB7, 0xCF, 0x5F, 0x9A, 0x16, 0xED, 0x69, 0x34, 0x94, 0xCB, 0x86, 0xC0, 0x27,
0x6E, 0x78, 0x15, 0x17, 0xED, 0x4A, 0x4E, 0xC5, 0x88, 0x1D, 0x01, 0xDE, 0x87, 0x96, 0x64, 0xC6,
0x92, 0xF8, 0x24, 0xEE, 0x46, 0xF4, 0x33, 0x0C, 0x1C, 0x89, 0x14, 0x47, 0x9E, 0x6C, 0x2A, 0x77,
0x23, 0xC8, 0x37, 0xCC, 0xF3, 0xA4, 0x5D, 0x27, 0x4F, 0x32, 0x41, 0x18, 0xCD, 0x4B, 0xF4, 0x26,
0xED, 0xF1, 0x8A, 0x0D, 0x14, 0x64, 0xB3, 0x13, 0x9C, 0x73, 0xC7, 0x4A, 0x35, 0x40, 0x05, 0x71,
0xBE, 0x79, 0x91, 0x46, 0x01, 0x00, 0xC3, 0x6B, 0x23, 0x1F, 0x1F, 0xD4, 0xD4, 0x1A, 0xD9, 0xC3,
0x1D, 0xB1, 0xD1, 0xBD, 0xEA, 0x77, 0x3A, 0xC1, 0xDC, 0x00, 0x7A, 0x50, 0x73, 0xB3, 0xE0, 0x29,
0x24, 0x2F, 0x6E, 0x54, 0x28, 0xC4, 0x37, 0x17, 0x21, 0x48, 0x45, 0x66, 0x20, 0x0D, 0xDF, 0x1B,
0x0A, 0x9A, 0x29, 0x0B, 0x05, 0x03, 0x73, 0xD8, 0x74, 0x1D, 0xEA, 0xBE, 0x40, 0x24, 0xB9, 0x50,
0x5F, 0x4A, 0x83, 0xF4, 0xAA, 0xFF, 0x00, 0x99, 0xA2, 0x6D, 0xB2, 0xCC, 0xC5, 0xCE, 0x09, 0x63,
0xA4, 0x73, 0xA1, 0x0C, 0xE6, 0x7F, 0x8D, 0x33, 0xC4, 0xFC, 0x32, 0xDE, 0x12, 0x8A, 0x59, 0x5C,
0xE1, 0x89, 0xDC, 0x1E, 0xD8, 0xAE, 0x0E, 0xED, 0x83, 0xB0, 0xAE, 0xC5, 0xF8, 0xB9, 0x03, 0x9B,
0xF8, 0x9B, 0x04, 0x8C, 0x1C, 0x03, 0xFE, 0x7C, 0xD7, 0x1E, 0x9D, 0x40, 0x6C, 0x81, 0x81, 0x5D,
0x58, 0x75, 0x1C, 0xB9, 0xFA, 0x89, 0xB9, 0xE4, 0x53, 0x47, 0x3D, 0xCD, 0x2A, 0x82, 0x4F, 0x61,
0x4A, 0x42, 0x86, 0xF4, 0xB6, 0x69, 0xC9, 0xA3, 0x40, 0x3A, 0xAA, 0x51, 0x23, 0x63, 0x03, 0x6C,
0x53, 0x30, 0x4F, 0x5C, 0x0A, 0x5C, 0xFA, 0x80, 0x1C, 0xAB, 0x6D, 0x92, 0x89, 0x86, 0xEA, 0xC0,
0x6F, 0x5E, 0x00, 0x83, 0x95, 0xCE, 0x2A, 0x3F, 0x2C, 0x9C, 0xED, 0x91, 0x52, 0x21, 0x65, 0x5D,
0x38, 0xCF, 0xBD, 0x10, 0x74, 0xE5, 0x2B, 0x10, 0x51, 0x9F, 0xB5, 0x1F, 0x14, 0x8B, 0xE5, 0x9C,
0x01, 0xB8, 0xAA, 0xC7, 0x8C, 0xBB, 0x02, 0x79, 0x54, 0xB6, 0xAD, 0xA0, 0x15, 0x07, 0x3B, 0xEF,
0x5C, 0x39, 0x72, 0x4F, 0xAD, 0x16, 0x16, 0x46, 0x26, 0x4D, 0x23, 0x9F, 0x2A, 0x2A, 0x35, 0x54,
0x4C, 0xB7, 0x3E, 0xB4, 0x3C, 0x63, 0xCC, 0xB9, 0xC1, 0x3B, 0x0A, 0x9A, 0xE1, 0x8A, 0xC3, 0x80,
0x29, 0xFA, 0xD6, 0xD6, 0xE3, 0xEC, 0x8D, 0x89, 0x36, 0xC8, 0xDA, 0xA7, 0x62, 0xA9, 0x68, 0x01,
0xE7, 0x8A, 0xA9, 0x8E, 0x42, 0x1C, 0xF7, 0x35, 0x34, 0xF2, 0xB0, 0x88, 0x83, 0x42, 0x7F, 0xD0,
0xCB, 0x2E, 0xF4, 0x12, 0x3B, 0x51, 0x3D, 0xC1, 0xD5, 0x9C, 0x67, 0x35, 0x6B, 0x25, 0xB2, 0xC3,
0x6F, 0x95, 0xDC, 0x11, 0x55, 0x96, 0xD7, 0x05, 0x64, 0xDB, 0x7E, 0x9B, 0xD1, 0x73, 0x4C, 0x64,
0x8F, 0x49, 0xC8, 0x15, 0x39, 0x3A, 0x4A, 0xFA, 0xAD, 0x89, 0x80, 0x95, 0xF5, 0x1F, 0xBD, 0x74,
0xBF, 0xC2, 0xCE, 0x18, 0xB7, 0xBC, 0x4E, 0x6B, 0xF7, 0x0D, 0xA2, 0x01, 0x84, 0x3B, 0x60, 0x93,
0xF6, 0xAE, 0x6E, 0xB1, 0xE6, 0x50, 0x07, 0x22, 0x77, 0xAF, 0xA3, 0xBC, 0x2F, 0xC3, 0xA3, 0xE1,
0x7C, 0x02, 0xDA, 0x24, 0x04, 0x12, 0x80, 0xB6, 0x40, 0xC8, 0x3D, 0xB6, 0x02, 0x9F, 0x87, 0x1D,
0xF6, 0x7C, 0x62, 0xD6, 0x49, 0x37, 0xC6, 0x32, 0x05, 0x07, 0x34, 0xD9, 0x3A, 0x22, 0x19, 0x6C,
0xF5, 0x3B, 0x0A, 0x9E, 0x57, 0x24, 0x9D, 0x8F, 0xB5, 0x09, 0x29, 0x55, 0x42, 0x09, 0x6E, 0xC3,
0x49, 0xFE, 0xB5, 0x5C, 0x96, 0xC6, 0x3C, 0xCE, 0xCA, 0xA0, 0x6A, 0x8F, 0x27, 0x99, 0x19, 0xFD,
0x31, 0x43, 0x5C, 0x92, 0x23, 0xC6, 0xE4, 0x91, 0xB6, 0x4E, 0x3F, 0x31, 0x48, 0xD3, 0x84, 0x01,
0x4B, 0x9C, 0x7B, 0x7F, 0x53, 0x41, 0xCF, 0x24, 0xF2, 0x49, 0xFB, 0xB3, 0xE9, 0xD5, 0xBE, 0x79,
0xE3, 0xB8, 0xFE, 0xD5, 0x3B, 0x54, 0x91, 0xE4, 0x09, 0x8C, 0x33, 0x61, 0x80, 0xF5, 0x22, 0xE7,
0x4D, 0x38, 0xBA, 0x2B, 0x0C, 0x28, 0x19, 0x18, 0x18, 0x4F, 0xEF, 0xCA, 0xA1, 0x88, 0x1C, 0xE4,
0xBB, 0x15, 0x1C, 0x97, 0x3B, 0xB7, 0xDE, 0xA4, 0x8D, 0x65, 0x42, 0x5D, 0x8F, 0xEF, 0x09, 0x2B,
0x91, 0xCB, 0xE3, 0xDE, 0x90, 0xE3, 0x61, 0x96, 0x34, 0x0C, 0x08, 0x3D, 0xC9, 0x61, 0xB7, 0xFD,
0xD4, 0xAB, 0x22, 0xB8, 0x62, 0x49, 0x04, 0xE3, 0x07, 0x1C, 0xFE, 0x05, 0x04, 0xDE, 0x76, 0x02,
0xAE, 0x08, 0xD8, 0x6A, 0x6D, 0x87, 0xBE, 0x28, 0xB0, 0x88, 0xD8, 0x38, 0xD5, 0xE9, 0xCE, 0x7D,
0xA9, 0xE1, 0x0A, 0xF2, 0x12, 0x30, 0xA3, 0x56, 0x39, 0xE3, 0x60, 0x28, 0x4B, 0x87, 0x12, 0xA2,
0x07, 0xC2, 0x93, 0x8C, 0x62, 0x88, 0x08, 0x06, 0x95, 0x1A, 0x98, 0x6E, 0x4E, 0xFB, 0x50, 0x8E,
0x52, 0x59, 0x18, 0x63, 0x51, 0x53, 0xB6, 0x3A, 0xD6, 0xA2, 0x45, 0x44, 0xD4, 0xD2, 0xB7, 0x25,
0x3B, 0xEA, 0xDC, 0x93, 0xDA, 0x9F, 0x13, 0x16, 0x0A, 0xE3, 0x2B, 0x83, 0x8C, 0x7F, 0x9F, 0x6A,
0x53, 0x6E, 0x02, 0x3E, 0xB7, 0xDB, 0x3B, 0x8F, 0x9A, 0x86, 0x45, 0x67, 0x68, 0x53, 0x50, 0x53,
0xB9, 0x63, 0x8A, 0x02, 0xE7, 0x1F, 0x8A, 0x96, 0x0E, 0xFC, 0x3A, 0x49, 0x55, 0xB3, 0xA5, 0x43,
0x6C, 0x39, 0x6F, 0x5C, 0x39, 0xE3, 0xD4, 0xA0, 0x81, 0x5F, 0x42, 0xFE, 0x25, 0x26, 0xBE, 0x0C,
0xF0, 0x28, 0x2C, 0xD2, 0x7A, 0x7D, 0x23, 0x24, 0x57, 0x22, 0xFF, 0x00, 0x4D, 0x1F, 0xB3, 0xC7,
0x18, 0x4C, 0x38, 0xF6, 0xDC, 0x0C, 0x55, 0xF1, 0xCA, 0x4C, 0x7B, 0x47, 0x2C, 0x6D, 0xAC, 0xAA,
0xDB, 0x93, 0x92, 0x00, 0xCF, 0x6A, 0x87, 0xC8, 0x65, 0x72, 0x31, 0xB9, 0xE8, 0x0D, 0x68, 0xE4,
0xB3, 0x56, 0x62, 0xA1, 0x88, 0x20, 0xF3, 0x22, 0xA2, 0x82, 0xC4, 0xA9, 0x77, 0xD3, 0xE9, 0x07,
0x72, 0xC3, 0x73, 0xF1, 0x4B, 0xFD, 0x4F, 0x38, 0x55, 0xAD, 0x6C, 0x3C, 0xA0, 0xC1, 0x4E, 0xE3,
0x9F, 0x73, 0x42, 0xB2, 0x3A, 0x1C, 0x2A, 0xFD, 0xC5, 0x5F, 0xDF, 0x46, 0x1F, 0xF7, 0xA8, 0x0E,
0xE7, 0x1A, 0x40, 0xE5, 0x55, 0x72, 0x9C, 0xA6, 0x06, 0x73, 0xD8, 0x56, 0xC3, 0x2B, 0x49, 0x9E,
0x3A, 0x0F, 0x6C, 0x24, 0x9A, 0x41, 0x18, 0x5C, 0xB1, 0xD8, 0x56, 0x92, 0xCB, 0xC1, 0xB7, 0xF7,
0x47, 0x0C, 0xA2, 0x3C, 0xF2, 0xC9, 0xDB, 0x1F, 0x22, 0xAB, 0xF8, 0x05, 0xA8, 0x92, 0xF0, 0x34,
0x83, 0x20, 0x1D, 0xB3, 0xDE, 0xBA, 0xCF, 0x0E, 0x74, 0xF2, 0xA2, 0xC0, 0xDF, 0x96, 0xDD, 0xA8,
0xE5, 0xC9, 0x65, 0xD4, 0x6C, 0x30, 0x96, 0x6E, 0xB3, 0x96, 0xCF, 0xE7, 0x03, 0x81, 0x45, 0xC3,
0x6B, 0xA0, 0x9F, 0x7A, 0xAE, 0xB1, 0x95, 0x61, 0x18, 0x62, 0x7D, 0xEA, 0xDA, 0x1B, 0x94, 0x75,
0xD8, 0xED, 0x5E, 0x6E, 0x5D, 0xE5, 0xB7, 0x21, 0x91, 0x5B, 0x85, 0x66, 0x62, 0x77, 0x34, 0x1F,
0x10, 0x94, 0xAB, 0xE0, 0x1F, 0xB5, 0x5A, 0x3B, 0x00, 0xB9, 0x02, 0xB3, 0xBC, 0x4A, 0x53, 0x93,
0xD4, 0xE6, 0xBA, 0xB8, 0xFF, 0x00, 0xD7, 0xB7, 0x46, 0x1D, 0x63, 0xB3, 0xE1, 0x70, 0xCD, 0x93,
0x53, 0x5C, 0x02, 0xD1, 0xEC, 0x6A, 0xB6, 0x09, 0x58, 0x01, 0x8A, 0x38, 0x3B, 0x31, 0xC9, 0xE5,
0x56, 0x97, 0x1F, 0x94, 0xAD, 0xDD, 0x32, 0xD9, 0x04, 0x72, 0x82, 0xC0, 0x62, 0x8F, 0x67, 0x53,
0x19, 0x3B, 0x54, 0x2F, 0x10, 0xF2, 0xF3, 0x9D, 0xEA, 0x04, 0x38, 0x62, 0x33, 0xD3, 0x15, 0x2D,
0xC2, 0xFA, 0xD5, 0xF8, 0x0B, 0x86, 0x37, 0x15, 0xF1, 0x2C, 0x63, 0x4C, 0x6F, 0x04, 0x23, 0x53,
0xAB, 0x28, 0xDF, 0xF4, 0xDA, 0xBB, 0x9C, 0xA4, 0x22, 0x04, 0x5C, 0x0C, 0x6D, 0x82, 0x6B, 0x0D,
0xF8, 0x59, 0xC2, 0x5A, 0xD3, 0x82, 0x3D, 0xF4, 0xB1, 0xC7, 0xAA, 0x66, 0x3A, 0x18, 0x2E, 0xF8,
0xF9, 0xAD, 0xAC, 0xC7, 0xA8, 0x3B, 0xD5, 0xB1, 0xEB, 0x15, 0xB1, 0x88, 0x1E, 0x62, 0xDC, 0x97,
0xE4, 0xFF, 0x00, 0x6A, 0x06, 0x49, 0x59, 0x09, 0x28, 0x32, 0xCD, 0xB6, 0xA1, 0xFF, 0x00, 0xB4,
0x4C, 0x8C, 0x75, 0x69, 0x50, 0x07, 0x7C, 0x9C, 0x50, 0x53, 0x4F, 0x2A, 0xC8, 0x0B, 0x3A, 0x15,
0xCE, 0x15, 0x7B, 0xFD, 0xF1, 0xB5, 0x25, 0xAB, 0xC8, 0x16, 0x58, 0xFC, 0xD6, 0xD0, 0x59, 0x25,
0x62, 0x70, 0xD8, 0xE4, 0xA3, 0xDE, 0xA2, 0x8F, 0x44, 0x4E, 0x51, 0x40, 0x5D, 0x07, 0x19, 0xEF,
0xF0, 0x3B, 0x74, 0xA7, 0x04, 0x26, 0x40, 0x9A, 0xC2, 0xA6, 0xE5, 0x97, 0xF8, 0xB3, 0xDF, 0x34,
0x44, 0x65, 0x62, 0x8B, 0x41, 0x8D, 0x70, 0x4E, 0x73, 0xED, 0xF1, 0x49, 0xE9, 0xDE, 0x0B, 0xE5,
0xA2, 0x28, 0x0E, 0x19, 0xB7, 0x55, 0x0B, 0xFF, 0x00, 0x7B, 0x51, 0x4B, 0xA9, 0x18, 0x05, 0x46,
0x6D, 0x23, 0x25, 0xFD, 0xEB, 0xC9, 0x16, 0x25, 0xD7, 0xA8, 0x1E, 0xF9, 0x14, 0xF4, 0xD6, 0xA0,
0x02, 0x08, 0xD5, 0xD4, 0x9A, 0x6D, 0x14, 0xDC, 0x6A, 0x65, 0x00, 0x93, 0xDB, 0x18, 0xA2, 0x63,
0x55, 0xDC, 0x32, 0xE7, 0x48, 0xE5, 0xDE, 0x98, 0x8C, 0x04, 0x8D, 0x82, 0x0A, 0x93, 0xCF, 0xA5,
0x7A, 0x35, 0x5F, 0xAB, 0x25, 0x89, 0xC8, 0xCF, 0xBD, 0x34, 0x02, 0xCC, 0x9A, 0x88, 0x00, 0x13,
0x9D, 0xF6, 0xA8, 0x52, 0xDC, 0x2A, 0xE4, 0x26, 0xF8, 0xC9, 0x22, 0x89, 0x92, 0x40, 0xB2, 0x00,
0xA7, 0x90, 0xC0, 0xA7, 0x30, 0xC4, 0x61, 0x31, 0x96, 0x23, 0xD5, 0x47, 0x41, 0xB0, 0x9A, 0x75,
0x62, 0x3C, 0xFA, 0xB9, 0x9C, 0xF2, 0xA8, 0x9A, 0xD4, 0x4B, 0x70, 0x5D, 0x72, 0x34, 0x73, 0x20,
0xF4, 0xFF, 0x00, 0x05, 0x14, 0x55, 0x63, 0x88, 0xB6, 0x7A, 0x13, 0xB9, 0xA8, 0x96, 0x5F, 0x2E,
0xD6, 0x59, 0x9B, 0xD2, 0x4A, 0xE3, 0x3E, 0xD4, 0x34, 0x6D, 0xB3, 0x1E, 0x25, 0xB7, 0x69, 0x6C,
0x32, 0xA0, 0x67, 0x58, 0x24, 0x9E, 0xD9, 0xE4, 0x2B, 0x01, 0xC4, 0x78, 0x42, 0x5B, 0x28, 0x78,
0x64, 0x46, 0x76, 0xDF, 0x4A, 0x37, 0x2F, 0x8A, 0xE9, 0x1C, 0x66, 0x45, 0x2B, 0x1E, 0xB6, 0x1E,
0x5E, 0xD9, 0xAC, 0x97, 0x16, 0xE1, 0x12, 0x5D, 0x5F, 0x48, 0xD1, 0x49, 0x98, 0xB6, 0xC1, 0x38,
0xC8, 0xEF, 0x8A, 0x96, 0x5B, 0x57, 0x0D, 0x39, 0xDD, 0xC4, 0x4D, 0x24, 0xE0, 0x13, 0x90, 0xC7,
0x1E, 0x91, 0xCE, 0xA4, 0x9F, 0x86, 0xBC, 0x71, 0x10, 0xAB, 0x81, 0x8D, 0xC7, 0x52, 0x6B, 0x43,
0x2F, 0x0B, 0x0B, 0x74, 0x89, 0x19, 0xCA, 0x46, 0x77, 0x27, 0x6D, 0x46, 0xA7, 0xBE, 0x80, 0x18,
0x55, 0x11, 0x46, 0x43, 0x05, 0x27, 0xF9, 0xD2, 0x9F, 0x6C, 0x9A, 0x70, 0xD3, 0x22, 0xE5, 0x93,
0xD0, 0xCB, 0x8D, 0x27, 0xA1, 0xAC, 0xCF, 0x19, 0xB5, 0x36, 0xEE, 0x85, 0x0E, 0xC3, 0xB1, 0xEB,
0x5D, 0x2E, 0x32, 0x21, 0xD1, 0x09, 0x40, 0x3A, 0xF2, 0xAC, 0x97, 0x1B, 0xE1, 0x53, 0x99, 0xE5,
0x66, 0x41, 0xE5, 0x39, 0xCA, 0xB0, 0xD8, 0x7E, 0xB5, 0xD1, 0xC5, 0xD3, 0x9B, 0x9B, 0xBA, 0xA5,
0xF0, 0xFC, 0xC1, 0x26, 0xD2, 0xC3, 0x99, 0xDF, 0x3D, 0x2B, 0xA4, 0xF0, 0xD7, 0xD1, 0x10, 0x25,
0xF9, 0xE3, 0x6A, 0xE6, 0x96, 0x56, 0xB3, 0x41, 0x7A, 0x10, 0x29, 0xCE, 0x79, 0x56, 0xF6, 0x09,
0x2E, 0x63, 0x31, 0x2E, 0x13, 0x43, 0x73, 0xCF, 0x31, 0x43, 0x39, 0x3E, 0xB6, 0x18, 0x5E, 0x98,
0xF9, 0x38, 0xB0, 0x40, 0x72, 0x77, 0xF6, 0x35, 0x04, 0x7C, 0x7C, 0xA4, 0x98, 0x04, 0xE2, 0xB3,
0xA5, 0xD8, 0xF3, 0xA4, 0x04, 0xD1, 0x9C, 0x18, 0xB9, 0x75, 0x1D, 0x16, 0xD3, 0x8D, 0x24, 0xB0,
0x90, 0xC7, 0x27, 0x14, 0x25, 0xF5, 0xCC, 0x67, 0x0C, 0xA7, 0x07, 0x1C, 0xAB, 0x19, 0x1D, 0xD4,
0xB1, 0x1C, 0xAB, 0x10, 0x6A, 0xD1, 0xA5, 0x92, 0x5B, 0x60, 0x5C, 0xEF, 0x8C, 0xE6, 0xB7, 0xF3,
0xD5, 0x5A, 0x65, 0xD6, 0x96, 0x51, 0x71, 0x04, 0x4D, 0xF0, 0x0F, 0xB5, 0x12, 0x78, 0xBC, 0x7F,
0xC2, 0x3E, 0x77, 0xAC, 0x88, 0x9A, 0x52, 0xFA, 0x40, 0xD6, 0x49, 0xD8, 0x60, 0xE4, 0x9F, 0xB7,
0x3A, 0x9B, 0xCE, 0x8E, 0x11, 0x87, 0x8C, 0x49, 0x27, 0xFB, 0x55, 0xCE, 0x07, 0xC9, 0xFE, 0xDF,
0x9D, 0x69, 0xC2, 0x8F, 0xCB, 0x4F, 0x27, 0x1B, 0x1E, 0x51, 0xC6, 0x3E, 0x68, 0x4B, 0x5E, 0x28,
0x65, 0xBC, 0x8E, 0x20, 0x59, 0x8C, 0x8C, 0x17, 0xD2, 0x35, 0x11, 0xF0, 0x33, 0x54, 0x1F, 0xEA,
0x33, 0x0F, 0x4C, 0x4B, 0x0C, 0x63, 0xFE, 0x31, 0x82, 0x7F, 0x33, 0x93, 0xFA, 0xD5, 0xEF, 0x83,
0x1E, 0xF2, 0xF3, 0xC5, 0xDC, 0x2E, 0xDB, 0xCE, 0x0C, 0x1A, 0xE1, 0x49, 0x59, 0x5D, 0x70, 0x46,
0x7A, 0x6A, 0xEB, 0x5A, 0x70, 0x4F, 0xD1, 0xF9, 0x7D, 0x59, 0xE1, 0xDB, 0x11, 0xC2, 0xFC, 0x39,
0x65, 0x68, 0x1B, 0x25, 0x63, 0x1A, 0x98, 0xE7, 0x73, 0xDE, 0x88, 0x96, 0x4D, 0xC1, 0x07, 0x38,
0xFD, 0x69, 0x67, 0x94, 0x22, 0xAA, 0xEC, 0x30, 0x00, 0x18, 0xA0, 0xA6, 0x90, 0xA2, 0x00, 0xBB,
0xC8, 0x4F, 0x22, 0x79, 0x51, 0xCA, 0xFE, 0x2F, 0x8C, 0x43, 0x72, 0xEC, 0xE1, 0x80, 0x19, 0x03,
0x63, 0xF3, 0x41, 0xC8, 0x51, 0x14, 0x8D, 0x4A, 0x30, 0xC3, 0x1A, 0x58, 0x80, 0x07, 0x6C, 0xD2,
0xCB, 0x30, 0x4C, 0x99, 0x25, 0x21, 0xB6, 0xD2, 0x49, 0xF4, 0xE4, 0xF6, 0xAA, 0xEB, 0xAB, 0xC7,
0x9A, 0x54, 0x45, 0x05, 0xB5, 0x1C, 0x61, 0x5B, 0x50, 0xC6, 0x77, 0xC9, 0x07, 0x35, 0x1C, 0xAA,
0xB2, 0x0E, 0x81, 0xCB, 0xCA, 0x5D, 0x53, 0x4A, 0x11, 0x90, 0x41, 0x1C, 0xBB, 0x62, 0xA6, 0x57,
0x88, 0xA7, 0x94, 0x43, 0x28, 0x24, 0x8C, 0x81, 0xFD, 0x7A, 0x55, 0x6B, 0xDC, 0x22, 0x12, 0x4C,
0xA0, 0x69, 0x19, 0x23, 0x5F, 0x21, 0xEF, 0x8A, 0x64, 0x1C, 0x5A, 0xDA, 0x79, 0x62, 0x89, 0x1B,
0x2E, 0x70, 0x35, 0x6A, 0xD8, 0x67, 0xBF, 0xF3, 0xA1, 0x0C, 0xD0, 0xC5, 0xA1, 0x10, 0x20, 0x93,
0xF8, 0xB0, 0x35, 0x1C, 0xE0, 0x75, 0xA9, 0x24, 0x72, 0x1C, 0x12, 0x47, 0xD4, 0x42, 0xFB, 0x0A,
0x07, 0xF6, 0x80, 0xC0, 0x95, 0x45, 0x60, 0x37, 0x53, 0xF7, 0xA5, 0x50, 0xC6, 0x41, 0x9D, 0xDB,
0x5E, 0xFD, 0x75, 0x53, 0xEC, 0x82, 0xC6, 0x7C, 0xDD, 0x21, 0x81, 0x5C, 0x8E, 0x5C, 0xCD, 0x17,
0x1E, 0x82, 0x70, 0xAB, 0x85, 0x53, 0xCC, 0xF5, 0xA0, 0xA0, 0x54, 0xCA, 0x9C, 0xB2, 0xFA, 0xC9,
0x6C, 0xF3, 0xA2, 0x1A, 0x70, 0x8E, 0xEA, 0x06, 0xDC, 0xF7, 0xEE, 0x69, 0xA0, 0x52, 0xC4, 0x4C,
0x8F, 0xAD, 0xB0, 0xBC, 0xD8, 0x8E, 0xC3, 0xA5, 0x34, 0x4A, 0x64, 0x98, 0xA8, 0xD5, 0xB8, 0xCF,
0x2E, 0x95, 0x3A, 0xE3, 0xCB, 0xDC, 0x7D, 0x58, 0x04, 0x52, 0x3E, 0x22, 0x84, 0x94, 0x1E, 0xB6,
0xF4, 0xD3, 0x17, 0x61, 0x66, 0xD5, 0x21, 0x7F, 0x57, 0xA0, 0x1A, 0x5B, 0x84, 0x56, 0xB3, 0xD0,
0x4E, 0x43, 0xF3, 0x3E, 0xD9, 0xA7, 0xAC, 0x40, 0xB2, 0xC7, 0x90, 0x11, 0x71, 0xA8, 0x53, 0x2E,
0x5D, 0x1C, 0x0C, 0x01, 0x85, 0xDC, 0x7D, 0xAB, 0x69, 0xB6, 0xAD, 0xBD, 0xB4, 0x46, 0x90, 0x45,
0xA1, 0x64, 0x45, 0x50, 0xDA, 0x4F, 0x7E, 0x54, 0x15, 0xDF, 0x0E, 0x48, 0xED, 0x58, 0x2E, 0x00,
0x00, 0x90, 0xCA, 0x77, 0x1D, 0xC5, 0x58, 0xCB, 0x21, 0x64, 0x25, 0x86, 0x72, 0x08, 0x26, 0x9A,
0xA3, 0xFF, 0x00, 0xC4, 0x80, 0xCA, 0x33, 0xE8, 0xDF, 0x3D, 0x69, 0x72, 0x92, 0x9E, 0x5D, 0x31,
0x3F, 0xE9, 0xCC, 0x59, 0x1D, 0x86, 0x96, 0x57, 0x27, 0x9F, 0x41, 0xCA, 0xAB, 0xEF, 0x62, 0x2A,
0x49, 0x05, 0x72, 0x72, 0x4E, 0x9E, 0x59, 0xAD, 0x2D, 0xE3, 0x68, 0x84, 0xB7, 0x96, 0x08, 0xD7,
0xBE, 0x17, 0xE9, 0x5A, 0xA9, 0x9A, 0x15, 0x08, 0xA5, 0xB6, 0x2C, 0xC4, 0xEC, 0x7A, 0x54, 0xBF,
0x55, 0xDF, 0x4A, 0x47, 0x55, 0x32, 0x63, 0x1E, 0xA5, 0x01, 0x88, 0xA8, 0xE6, 0x85, 0x6E, 0x94,
0xA1, 0x51, 0xA4, 0xF4, 0xAB, 0x29, 0xED, 0x8F, 0x99, 0x26, 0x93, 0x87, 0x4C, 0x6D, 0x9E, 0x62,
0xBD, 0x0F, 0x96, 0x14, 0x93, 0x19, 0x0C, 0x7F, 0x89, 0x79, 0x7E, 0x54, 0xF3, 0xA2, 0x5E, 0xE3,
0x21, 0x37, 0x0A, 0x7B, 0x7B, 0xF0, 0xC6, 0x30, 0xA1, 0x87, 0x3C, 0x72, 0xFB, 0xD1, 0xC6, 0xCD,
0x44, 0x82, 0x51, 0x96, 0x65, 0x1B, 0x11, 0xD3, 0xED, 0x57, 0xB7, 0xC8, 0x8D, 0x67, 0x23, 0x32,
0xB6, 0x42, 0x9D, 0xC0, 0xAC, 0xAD, 0xA5, 0xF3, 0x3D, 0xCB, 0x45, 0x36, 0x40, 0x0D, 0xE9, 0x0D,
0xD4, 0x63, 0xB5, 0x1B, 0xBF, 0x49, 0x3F, 0xE3, 0x03, 0x73, 0xC3, 0x5A, 0x37, 0x38, 0x07, 0x02,
0x84, 0x68, 0x08, 0xE6, 0x0D, 0x6E, 0xE7, 0xB1, 0x57, 0x6C, 0x11, 0x55, 0x77, 0x9C, 0x2C, 0x28,
0x24, 0x0A, 0xA7, 0xF4, 0x9A, 0x73, 0x32, 0xBE, 0x59, 0xD5, 0x8C, 0x55, 0xA3, 0x92, 0x96, 0xD8,
0xF6, 0xA2, 0xA3, 0xE1, 0x44, 0xB6, 0x71, 0x53, 0xDC, 0xD8, 0x9F, 0x24, 0x80, 0x29, 0x7F, 0xAE,
0x36, 0xE8, 0x71, 0x66, 0xF5, 0xB6, 0x18, 0x2F, 0xA4, 0x1E, 0x78, 0xEB, 0x51, 0x90, 0x6A, 0xCF,
0xF6, 0x13, 0x92, 0x31, 0x51, 0xCB, 0x66, 0xC8, 0x33, 0x8A, 0xA7, 0xF4, 0x85, 0x00, 0xA8, 0x6B,
0x79, 0xF8, 0x53, 0xC2, 0x66, 0xE2, 0x3E, 0x3B, 0xE1, 0xD2, 0x21, 0x5F, 0x2E, 0xDE, 0x41, 0x24,
0x9A, 0x87, 0x31, 0xDB, 0x60, 0x70, 0x79, 0x9F, 0xB5, 0x63, 0x56, 0x13, 0xCB, 0x1B, 0xD7, 0x78,
0xFC, 0x0C, 0xF0, 0xED, 0xCD, 0xBD, 0xA5, 0xC7, 0x1A, 0x96, 0x38, 0xD2, 0x19, 0x03, 0x24, 0x4F,
0xFC, 0x6E, 0x76, 0x1F, 0x60, 0x30, 0x7E, 0x73, 0xED, 0x47, 0x7D, 0x0C, 0xF5, 0xD4, 0xAE, 0x17,
0xF7, 0x8C, 0x58, 0x64, 0x03, 0xB1, 0xAA, 0x2B, 0xAB, 0x84, 0x67, 0x90, 0x11, 0xA5, 0x57, 0x91,
0x27, 0x3F, 0xF9, 0x57, 0x57, 0x5B, 0xB1, 0xDF, 0x6E, 0xE6, 0xA8, 0x6E, 0x1D, 0x23, 0x49, 0x1A,
0x17, 0x57, 0x73, 0x9D, 0x87, 0x33, 0xEF, 0xBF, 0x3F, 0x9A, 0x86, 0x73, 0x6E, 0x9C, 0x7A, 0x54,
0xDF, 0xF1, 0x45, 0x89, 0x50, 0x17, 0x8D, 0x57, 0xE9, 0x2A, 0xC3, 0x3B, 0x7B, 0x56, 0x23, 0x8E,
0x78, 0xBE, 0x2E, 0x1F, 0x13, 0xB6, 0x86, 0xCA, 0xEC, 0xBA, 0x46, 0xC7, 0xE0, 0x8E, 0x5F, 0x7A,
0xB4, 0xE3, 0xB7, 0x11, 0xBC, 0x13, 0x03, 0x11, 0x8B, 0x4E, 0x4E, 0xA5, 0x03, 0x5E, 0xAE, 0x7B,
0xFF, 0x00, 0x6A, 0xE3, 0x3C, 0x56, 0xF9, 0x6E, 0xF7, 0x33, 0x3B, 0x37, 0x3D, 0x2D, 0xD0, 0xF5,
0xE9, 0x5B, 0x8F, 0x8F, 0x7E, 0x86, 0x79, 0xEB, 0xC1, 0x97, 0x7E, 0x23, 0xE2, 0xB7, 0x57, 0x32,
0x4E, 0x2E, 0x5A, 0x1D, 0x7F, 0xC0, 0x87, 0x60, 0x3E, 0xF5, 0x7D, 0xE1, 0x7F, 0x13, 0x5D, 0xC3,
0x77, 0x65, 0x03, 0x7A, 0xF4, 0xB1, 0x02, 0x2F, 0x51, 0xF3, 0x09, 0xEB, 0xD8, 0x7E, 0x75, 0x8D,
0x86, 0xD6, 0x7B, 0x88, 0xE5, 0x99, 0x32, 0xEB, 0x18, 0x05, 0xC8, 0x42, 0x42, 0xFC, 0x90, 0x30,
0x29, 0xC9, 0x31, 0x0E, 0xBA, 0x58, 0xAB, 0xA9, 0xCE, 0x7B, 0x63, 0xB5, 0x5E, 0xE1, 0x34, 0x94,
0xCE, 0xED, 0xF4, 0xAF, 0x0C, 0xE2, 0xAA, 0xD0, 0x09, 0x5E, 0x4D, 0x50, 0xB7, 0x2C, 0x1C, 0xE3,
0xDB, 0x6E, 0xB9, 0xCE, 0xF5, 0x7F, 0x04, 0xDB, 0x19, 0x08, 0x1A, 0x94, 0x6F, 0xA7, 0xBF, 0x6A,
0xC1, 0xF8, 0x26, 0x74, 0xBA, 0xE1, 0x36, 0x3A, 0x62, 0x69, 0x32, 0x8A, 0xCC, 0xCB, 0xB9, 0xD5,
0xDC, 0x9C, 0x7D, 0xFE, 0xF5, 0xBE, 0xB7, 0x81, 0xED, 0x60, 0x91, 0xCB, 0x65, 0xB5, 0x0C, 0x00,
0x33, 0x8F, 0x61, 0xDE, 0xB9, 0xA4, 0xBB, 0xD3, 0xA3, 0x73, 0x42, 0xA3, 0xCA, 0x46, 0x19, 0x95,
0xB3, 0x8C, 0x82, 0x4F, 0x23, 0x4D, 0xD2, 0xA4, 0xBA, 0x83, 0xF4, 0x6E, 0x72, 0x76, 0xCD, 0x4B,
0x29, 0x21, 0x14, 0x9F, 0x40, 0x1B, 0xB0, 0x03, 0x24, 0xFB, 0x54, 0x41, 0x02, 0x29, 0xCF, 0xA5,
0x71, 0xA9, 0x8D, 0x52, 0x15, 0x31, 0xCA, 0x44, 0x8C, 0xDC, 0xFE, 0xA6, 0xCF, 0x42, 0x79, 0x53,
0xCC, 0xA4, 0x4C, 0x10, 0x6F, 0xE9, 0xFD, 0x68, 0x28, 0xEF, 0x92, 0x57, 0x11, 0xB2, 0x13, 0x1B,
0x36, 0x41, 0x3D, 0x87, 0xB5, 0x4B, 0x2D, 0xC2, 0xC5, 0x29, 0xDB, 0x0A, 0xC4, 0x10, 0x7D, 0xA8,
0x94, 0x51, 0x75, 0x52, 0x72, 0x3D, 0x4C, 0x72, 0x05, 0x56, 0xBB, 0xB4, 0xB7, 0x4F, 0x11, 0x03,
0x48, 0x4C, 0x80, 0x3F, 0xCF, 0x6A, 0x9A, 0x59, 0x10, 0xCD, 0xAC, 0xB6, 0x02, 0xAE, 0x17, 0x26,
0x80, 0xB7, 0x9D, 0x4D, 0xEC, 0xA7, 0x49, 0x62, 0xC4, 0x28, 0xC9, 0xED, 0xCE, 0x88, 0x09, 0x8E,
0x3D, 0x16, 0xA1, 0x4E, 0x49, 0x61, 0x90, 0x49, 0xE6, 0x68, 0x5B, 0xE7, 0xFD, 0xC3, 0x29, 0x60,
0xBA, 0x0E, 0x90, 0x49, 0xEC, 0x33, 0xB5, 0x17, 0x2C, 0xA0, 0x90, 0x0F, 0xA7, 0x0D, 0x85, 0x15,
0x9A, 0xE3, 0x33, 0x39, 0x92, 0x48, 0x14, 0xF2, 0x1A, 0x72, 0x3F, 0xE5, 0xD6, 0x85, 0x19, 0xEA,
0x19, 0xA7, 0x6C, 0xCC, 0x22, 0xDE, 0x33, 0x94, 0x03, 0x3C, 0xD8, 0x8E, 0x74, 0x3D, 0xD5, 0xB8,
0x2A, 0xE5, 0x89, 0xD5, 0x17, 0x22, 0x39, 0x11, 0xCB, 0x6A, 0x96, 0x10, 0x85, 0x98, 0x01, 0xB0,
0x8C, 0xE3, 0x7E, 0x6D, 0xEF, 0x50, 0xD8, 0x81, 0x24, 0x28, 0x2E, 0x1B, 0xF8, 0x89, 0xFC, 0xEA,
0x7A, 0x53, 0x61, 0x64, 0x41, 0x2A, 0xA4, 0x98, 0xD3, 0x2E, 0x31, 0xB9, 0xE7, 0x51, 0xA4, 0x4B,
0xA7, 0x20, 0xEF, 0xD9, 0x85, 0x3E, 0x46, 0x55, 0x99, 0x82, 0x8D, 0x2B, 0xBE, 0x9C, 0x9F, 0xA4,
0xF6, 0xA9, 0x62, 0x70, 0xD1, 0x90, 0xC1, 0x4B, 0x01, 0xBE, 0xD5, 0xB4, 0x1B, 0x35, 0x2D, 0x56,
0x44, 0x29, 0x21, 0x3E, 0xA1, 0x8C, 0x1A, 0xA1, 0x9B, 0x85, 0x44, 0xD6, 0xE7, 0x5A, 0x0F, 0x31,
0x18, 0x8D, 0x59, 0xFC, 0xBF, 0x4A, 0xD2, 0x06, 0x08, 0x41, 0x62, 0x00, 0xC6, 0x01, 0xA0, 0xCA,
0x23, 0x43, 0x2A, 0xBF, 0x42, 0x58, 0x1A, 0xA7, 0xE1, 0x3F, 0x58, 0xD9, 0x97, 0x12, 0x6D, 0x50,
0xCB, 0x17, 0x9C, 0x30, 0x39, 0x54, 0xD7, 0x2D, 0xEA, 0xC8, 0x14, 0xB6, 0xCD, 0x95, 0x15, 0xCF,
0x95, 0xDD, 0xD3, 0x9E, 0xFA, 0x86, 0x3B, 0x70, 0xA0, 0xEC, 0x2A, 0x39, 0xE1, 0x56, 0x18, 0xC0,
0xAB, 0x09, 0x63, 0x5C, 0x61, 0x4E, 0xF8, 0xA0, 0x01, 0x3E, 0x66, 0xFD, 0xEA, 0x37, 0x86, 0xCC,
0xB6, 0x1B, 0xD0, 0x35, 0xE1, 0xF8, 0x6C, 0x95, 0xE7, 0xDE, 0xA1, 0xBA, 0xB1, 0x0C, 0x39, 0x0A,
0xBC, 0x77, 0x40, 0xB9, 0x06, 0x9B, 0x69, 0x65, 0x27, 0x11, 0xBD, 0x82, 0xD2, 0x00, 0x0C, 0xB3,
0x48, 0xB1, 0xA6, 0x4E, 0xD9, 0x27, 0x1B, 0xD5, 0x7F, 0x9D, 0xB9, 0x4A, 0x1D, 0xDA, 0x27, 0xF0,
0xEF, 0xC0, 0x63, 0xC4, 0x7C, 0x7D, 0x64, 0xB9, 0x8C, 0x1E, 0x1F, 0x6A, 0x43, 0xCF, 0xAB, 0x38,
0x7E, 0xCA, 0x2B, 0xE8, 0xB5, 0xB7, 0x86, 0xD6, 0xD9, 0x61, 0xB7, 0x89, 0x63, 0x89, 0x46, 0x15,
0x23, 0x18, 0x03, 0xED, 0x41, 0x78, 0x73, 0x81, 0xC5, 0xE1, 0xEE, 0x07, 0x6F, 0xC3, 0xA2, 0x21,
0x8A, 0x0C, 0xC8, 0xE0, 0x63, 0x5B, 0x9E, 0x66, 0xAC, 0x26, 0x39, 0x1A, 0x06, 0xAC, 0x9D, 0xB6,
0x07, 0x6A, 0xEE, 0x98, 0xF4, 0xAC, 0xE9, 0x57, 0x77, 0xA0, 0x12, 0xAC, 0x32, 0x4F, 0x4C, 0x8D,
0xFF, 0x00, 0x3A, 0xAE, 0xBD, 0xE1, 0xD2, 0x4D, 0x13, 0x0F, 0x33, 0xF7, 0x7B, 0x80, 0x0B, 0x1D,
0x43, 0xE0, 0x8A, 0xB3, 0x68, 0x19, 0xA7, 0x5D, 0xB2, 0xBC, 0x88, 0x6C, 0xE7, 0xEE, 0x6A, 0x41,
0x67, 0xAC, 0xEE, 0xC7, 0x1D, 0x32, 0x73, 0x49, 0xF2, 0x7D, 0xB9, 0x37, 0x8A, 0x38, 0x58, 0xE1,
0xB6, 0x72, 0xCF, 0x1D, 0xE3, 0x2C, 0x86, 0x32, 0xAA, 0xA8, 0xA3, 0x51, 0x3F, 0xF2, 0x1F, 0x1D,
0x6B, 0x87, 0x3F, 0x0A, 0x9A, 0x6F, 0xDA, 0x27, 0x08, 0x55, 0x14, 0x93, 0x80, 0x39, 0xFC, 0x57,
0xD4, 0xBE, 0x30, 0xF0, 0xDC, 0x3C, 0x42, 0xC6, 0x40, 0x10, 0xE4, 0x0F, 0x4B, 0xF3, 0xC1, 0xFB,
0xD7, 0x09, 0xE3, 0x36, 0x77, 0x16, 0xB3, 0x1B, 0x70, 0x34, 0xB2, 0x39, 0x53, 0x8E, 0x95, 0x4C,
0x71, 0xD4, 0x25, 0x54, 0x0E, 0x2F, 0xC4, 0x97, 0x84, 0x2F, 0x02, 0x4B, 0xA9, 0xA1, 0xB0, 0x2C,
0x0B, 0xDB, 0xA9, 0xD0, 0xB9, 0x3C, 0xF5, 0x01, 0xF5, 0x72, 0xEB, 0x55, 0xB2, 0xD9, 0xC6, 0x2F,
0x9C, 0x40, 0xD9, 0x41, 0xB0, 0xCF, 0x7A, 0xB0, 0xBA, 0x17, 0x8D, 0xFF, 0x00, 0xDA, 0x15, 0xF4,
0x8C, 0x07, 0x70, 0x35, 0x7E, 0x75, 0x04, 0x11, 0x98, 0xD4, 0x96, 0xFA, 0xB9, 0xE6, 0x8F, 0x6D,
0x6B, 0xB9, 0xFE, 0x15, 0xDB, 0xE3, 0xC3, 0x48, 0x23, 0x04, 0xC7, 0x1B, 0x30, 0x59, 0x18, 0x63,
0x59, 0xEA, 0x7E, 0x39, 0x8E, 0x7D, 0x2B, 0x7C, 0xB8, 0xC0, 0x5C, 0x7A, 0x14, 0x8C, 0x1F, 0xF7,
0x1A, 0xE6, 0x9F, 0x86, 0x7C, 0x62, 0xD5, 0xEC, 0xA3, 0xE1, 0xB0, 0x92, 0x59, 0x21, 0x0D, 0x34,
0x9C, 0x86, 0xEE, 0x40, 0xE5, 0xD7, 0x7C, 0x7F, 0xEE, 0xDD, 0x16, 0xE6, 0xE2, 0x38, 0xE3, 0x80,
0x29, 0x18, 0xF3, 0x00, 0x19, 0xE7, 0x8A, 0x86, 0x53, 0x55, 0x4C, 0x6E, 0xE0, 0x97, 0x72, 0xCD,
0x32, 0x82, 0x35, 0x81, 0xE9, 0x02, 0x85, 0x9E, 0x37, 0x40, 0xCA, 0xD9, 0x21, 0xC1, 0x6F, 0x81,
0x8A, 0x1F, 0xF6, 0xA4, 0x5B, 0xC2, 0xC5, 0xB7, 0x1F, 0x58, 0x03, 0x71, 0xEC, 0x6B, 0xD7, 0x97,
0x03, 0xCB, 0x62, 0xEC, 0x01, 0xD3, 0xA4, 0xFC, 0x74, 0xA1, 0xB3, 0x22, 0xE1, 0xC5, 0x9E, 0x25,
0x2E, 0x43, 0x13, 0xAB, 0x63, 0xD3, 0xEF, 0xD7, 0xAD, 0x49, 0x71, 0x32, 0x34, 0xA9, 0x8C, 0x1D,
0x3C, 0xD7, 0xDB, 0x1F, 0xF9, 0x51, 0x24, 0xC2, 0x0B, 0x55, 0x90, 0xB6, 0xDB, 0xF2, 0xDF, 0xED,
0x55, 0xB0, 0xBC, 0x87, 0x8A, 0xC0, 0x58, 0x6A, 0x12, 0xA6, 0x90, 0x4F, 0x43, 0xFE, 0x1A, 0xCC,
0x9E, 0xEE, 0xE4, 0x08, 0xA2, 0xF3, 0x09, 0x0C, 0x65, 0x23, 0x03, 0xD8, 0x6D, 0xFA, 0xD3, 0xA1,
0x12, 0x41, 0x22, 0xB8, 0x3A, 0x86, 0xA3, 0xD2, 0x80, 0xBD, 0x94, 0x24, 0xD1, 0xA4, 0x87, 0x57,
0x96, 0xDA, 0xB2, 0x7B, 0x8C, 0x9A, 0x2E, 0xCA, 0xED, 0x25, 0x8E, 0xD9, 0x0B, 0x0C, 0x3B, 0x9C,
0x64, 0xF4, 0xDF, 0x9F, 0xE6, 0x28, 0x80, 0x8B, 0xBB, 0x8F, 0xDE, 0x32, 0x82, 0x17, 0x4F, 0xA8,
0x92, 0x79, 0x8C, 0x56, 0x7A, 0xE1, 0xB5, 0x1C, 0xB6, 0xDB, 0x60, 0x91, 0xDA, 0x8C, 0xE2, 0xB7,
0x8A, 0xB2, 0x98, 0xD0, 0x6A, 0xD6, 0x31, 0xBD, 0x57, 0x33, 0x34, 0x8A, 0xA0, 0x8D, 0xCE, 0x0F,
0xC8, 0x1F, 0xFB, 0x8A, 0xC0, 0x8E, 0x08, 0x5A, 0x39, 0x95, 0x75, 0xEC, 0xEA, 0x15, 0x46, 0x79,
0x0E, 0xB4, 0x44, 0xDA, 0x52, 0x38, 0x80, 0x03, 0x50, 0x38, 0xDB, 0xAD, 0x2D, 0xD9, 0x10, 0xC7,
0x91, 0xBB, 0x36, 0xC0, 0x8A, 0xF4, 0x69, 0xBB, 0x07, 0x23, 0x44, 0x7A, 0xBA, 0x6F, 0xBE, 0x29,
0x4F, 0x28, 0x49, 0x90, 0x10, 0x18, 0x0F, 0x4E, 0x76, 0xA8, 0x8B, 0x28, 0x72, 0x40, 0xF4, 0x92,
0x32, 0x2A, 0x65, 0xD6, 0x64, 0x7C, 0x26, 0x50, 0xE4, 0x0E, 0xB4, 0x34, 0xD9, 0x59, 0x34, 0x13,
0x91, 0x9C, 0x6F, 0x41, 0x85, 0x91, 0xFB, 0x82, 0xD8, 0xD5, 0x1B, 0x73, 0xA0, 0xD9, 0x44, 0x90,
0x93, 0x11, 0x19, 0x07, 0x7D, 0xF9, 0x8A, 0x94, 0x6B, 0x5D, 0xF3, 0xB0, 0x1A, 0x88, 0xAA, 0x6B,
0x99, 0x65, 0x85, 0xF5, 0xC4, 0x7E, 0x94, 0x20, 0x81, 0xC8, 0xFC, 0x8A, 0x6F, 0x49, 0x54, 0xF3,
0xC4, 0x49, 0xE5, 0x51, 0x2C, 0x45, 0x06, 0x73, 0x53, 0xDC, 0xCA, 0x17, 0x07, 0xF3, 0xA1, 0xFC,
0xDD, 0x4B, 0xE9, 0x18, 0xF9, 0xA9, 0x4D, 0x4B, 0xDA, 0x15, 0x33, 0xCA, 0xDE, 0x5E, 0x36, 0xCF,
0x7A, 0x81, 0x23, 0xD4, 0x4E, 0xF4, 0x85, 0x89, 0x14, 0xF8, 0x58, 0x0C, 0xE7, 0x9D, 0x57, 0x5B,
0x80, 0x8E, 0x48, 0xCF, 0x5E, 0x42, 0xBA, 0x17, 0xE1, 0x2F, 0x07, 0x5B, 0x8E, 0x27, 0x75, 0xC5,
0x64, 0x00, 0x8B, 0x65, 0x11, 0xC6, 0x08, 0xFE, 0x26, 0xE6, 0x7F, 0x2F, 0xE7, 0x58, 0x50, 0x8D,
0x3C, 0xAA, 0x91, 0xAB, 0x3B, 0xB1, 0xC0, 0x55, 0x19, 0x24, 0xFB, 0x57, 0x73, 0xF0, 0x37, 0x00,
0x97, 0xC3, 0xFE, 0x1D, 0x48, 0x6E, 0x36, 0xB9, 0x99, 0xCC, 0xD2, 0x2F, 0xFB, 0x49, 0x00, 0x05,
0xFB, 0x01, 0x47, 0x8E, 0x76, 0x38, 0xB4, 0xC4, 0xF4, 0x14, 0x99, 0xC0, 0xC9, 0xA8, 0xE4, 0x0C,
0x5B, 0x23, 0x6C, 0x75, 0xEF, 0x48, 0xA5, 0x9B, 0x20, 0xE3, 0x3B, 0x66, 0xAC, 0x73, 0xB4, 0xA9,
0x3A, 0xBB, 0x8A, 0x42, 0xE0, 0x6D, 0x8E, 0x54, 0x8F, 0x80, 0x33, 0x9C, 0x9A, 0x16, 0x50, 0xCC,
0x40, 0x27, 0x3B, 0x9D, 0xEB, 0x31, 0x2F, 0x1D, 0x64, 0x5D, 0x00, 0xEC, 0x46, 0xE6, 0xBE, 0x7E,
0xF1, 0xAC, 0x6D, 0x65, 0xE2, 0x7B, 0x9B, 0xA6, 0x81, 0x85, 0xAE, 0xBD, 0x0A, 0x4B, 0x0C, 0x33,
0x75, 0xE5, 0x5D, 0xE2, 0x52, 0xA0, 0x60, 0x92, 0x2B, 0x94, 0x7E, 0x28, 0x70, 0xD1, 0x3F, 0x96,
0x6D, 0x21, 0xCB, 0xBE, 0x0B, 0x60, 0xF6, 0x24, 0x93, 0xF3, 0xCA, 0x8E, 0x35, 0xAB, 0x10, 0x8B,
0x05, 0xCA, 0x8F, 0x37, 0x00, 0x97, 0x23, 0x4F, 0x6E, 0xDF, 0xD6, 0xAA, 0x78, 0x95, 0xB9, 0x59,
0x26, 0x44, 0x0B, 0xFB, 0xBD, 0xC0, 0x5E, 0x44, 0x63, 0x7D, 0xE9, 0x96, 0x53, 0x34, 0x65, 0xC8,
0x39, 0x56, 0xD8, 0x13, 0xFD, 0x7B, 0xD2, 0x48, 0x0A, 0xAB, 0x69, 0x62, 0x58, 0x73, 0x03, 0xF8,
0x81, 0xDA, 0x98, 0x8B, 0x0F, 0x07, 0xCD, 0x3C, 0x1C, 0x72, 0xCD, 0x6D, 0xE4, 0x68, 0xF5, 0x16,
0xF3, 0x18, 0x1E, 0xCA, 0x48, 0xFE, 0xDF, 0x7A, 0xED, 0x92, 0x5C, 0x3C, 0xAB, 0x68, 0x58, 0xB6,
0xA6, 0x44, 0x24, 0xF3, 0xC9, 0x06, 0xB8, 0xB7, 0x86, 0x66, 0x11, 0xF1, 0xEB, 0x6D, 0x63, 0x4A,
0x23, 0x2A, 0x8D, 0xB6, 0xF7, 0xCF, 0x7E, 0x55, 0xD9, 0x5A, 0x54, 0x40, 0x64, 0x66, 0xC2, 0x2C,
0x6B, 0x13, 0x20, 0xD8, 0xAE, 0xFB, 0x1D, 0xFD, 0xAA, 0x3C, 0x93, 0xB5, 0x70, 0xA2, 0xD1, 0x54,
0xDA, 0xDC, 0x5E, 0x13, 0xAF, 0x2F, 0x9D, 0x8F, 0x41, 0x53, 0xCE, 0xF1, 0xBC, 0x20, 0xB9, 0x00,
0x3A, 0x8C, 0x83, 0xD4, 0x74, 0xC5, 0x53, 0xAF, 0x10, 0x05, 0xA4, 0xB7, 0x3E, 0x9F, 0xA9, 0x40,
0x1C, 0x8E, 0x7F, 0xF3, 0xF5, 0xA2, 0x2E, 0x26, 0xCB, 0xC7, 0x14, 0xEA, 0x4A, 0x91, 0xA8, 0x01,
0xCC, 0x7F, 0x62, 0x0D, 0x43, 0xC5, 0x85, 0x5D, 0x49, 0x19, 0xB7, 0xF2, 0x35, 0x8C, 0x11, 0x94,
0x23, 0xAE, 0xDB, 0xD4, 0x16, 0x2E, 0x53, 0xF6, 0x5C, 0x9C, 0xB1, 0xC9, 0x19, 0xDE, 0xB3, 0xF7,
0x7C, 0x5F, 0x55, 0xCB, 0x5B, 0x31, 0x66, 0x08, 0xE4, 0xAB, 0x37, 0x31, 0xF1, 0xDB, 0xAD, 0x2D,
0xAD, 0xD4, 0xB1, 0xCD, 0x01, 0x2D, 0x90, 0xAF, 0xB3, 0x0E, 0x83, 0x99, 0xA6, 0x20, 0xCE, 0x29,
0x78, 0x4C, 0xD3, 0x46, 0x48, 0xF3, 0x1C, 0x60, 0x77, 0xC6, 0x33, 0x53, 0x46, 0xF1, 0x42, 0x91,
0x3A, 0x82, 0x16, 0x11, 0xBA, 0x81, 0xCD, 0x89, 0xE5, 0xFD, 0x7E, 0xD5, 0x4D, 0x77, 0x34, 0x37,
0xD7, 0xA6, 0xE9, 0x0B, 0x28, 0xD6, 0x72, 0xA7, 0xB7, 0x2C, 0xD4, 0xB2, 0x5E, 0x6B, 0xF2, 0x62,
0x53, 0x92, 0x84, 0xB8, 0xF7, 0xDB, 0x19, 0xFE, 0x74, 0x76, 0x09, 0x64, 0x6D, 0x52, 0xCE, 0xCE,
0x49, 0x2A, 0x39, 0x9F, 0x9D, 0xE9, 0xD1, 0x30, 0x96, 0x70, 0xB8, 0x23, 0x07, 0x3F, 0x03, 0x35,
0x5A, 0xF3, 0xB4, 0x97, 0x8C, 0xE3, 0x65, 0x67, 0xDC, 0x55, 0xA5, 0xB1, 0x1E, 0x50, 0x23, 0x79,
0x03, 0x0D, 0x59, 0xEA, 0x3F, 0xC3, 0x59, 0x8B, 0x3B, 0x97, 0x91, 0x1C, 0x01, 0xA2, 0x36, 0xD8,
0x7D, 0xF1, 0x44, 0x48, 0x35, 0x15, 0x45, 0x3A, 0x41, 0x5D, 0x4F, 0xF3, 0xEF, 0x4C, 0x94, 0xC4,
0xAC, 0x34, 0x8F, 0xDD, 0xB3, 0x6A, 0x07, 0xEF, 0xCA, 0x85, 0x49, 0x24, 0x5B, 0xC2, 0x49, 0xE7,
0x91, 0xF3, 0x8A, 0xD4, 0x63, 0xCB, 0x23, 0x46, 0x76, 0x19, 0xED, 0x93, 0xD6, 0xA0, 0x55, 0x32,
0x30, 0x0F, 0xB9, 0x23, 0x39, 0xA3, 0x65, 0x55, 0x8E, 0x74, 0x1A, 0x4E, 0xFC, 0xF3, 0xEF, 0x42,
0xAA, 0x95, 0x9D, 0xF7, 0xFA, 0x06, 0x73, 0x4A, 0x27, 0xAE, 0xA5, 0x91, 0x49, 0x1C, 0xC6, 0x01,
0x15, 0x4B, 0xC5, 0x7F, 0x77, 0x1C, 0xB2, 0xA8, 0xC1, 0x0D, 0xEA, 0x07, 0xEF, 0xFD, 0x4D, 0x5C,
0x89, 0x01, 0x20, 0xE7, 0x7C, 0x9C, 0x6F, 0xD6, 0xB2, 0xDC, 0x73, 0x89, 0x69, 0x46, 0x85, 0x88,
0x0C, 0x5B, 0x0D, 0xFC, 0xFF, 0x00, 0xA1, 0xAA, 0x63, 0x13, 0xCA, 0x85, 0x36, 0xC6, 0x62, 0x76,
0xDA, 0x98, 0xF0, 0x79, 0x7B, 0x74, 0xAB, 0xA5, 0x88, 0x44, 0x98, 0xC5, 0x03, 0x70, 0x15, 0x9B,
0x9E, 0xF4, 0x9F, 0x08, 0xAB, 0x8C, 0x79, 0xD8, 0x57, 0x92, 0x33, 0x9D, 0xAA, 0x59, 0x3D, 0x19,
0xC8, 0xA7, 0x41, 0xEA, 0x20, 0x77, 0xA6, 0x8C, 0xE9, 0xDF, 0x86, 0x5E, 0x19, 0x45, 0x83, 0xFD,
0x72, 0xE9, 0x55, 0xD9, 0xF2, 0xB6, 0xE1, 0x97, 0xE9, 0xC1, 0xC1, 0x6F, 0xE6, 0x2B, 0xA5, 0x50,
0xBC, 0x3A, 0xD9, 0x2C, 0xB8, 0x6D, 0xAD, 0xAC, 0x60, 0x04, 0x8A, 0x25, 0x41, 0x8F, 0x61, 0x44,
0x96, 0x02, 0xAD, 0x26, 0x8E, 0x42, 0x0E, 0x6A, 0x27, 0x04, 0x64, 0x80, 0x3B, 0xD2, 0xF9, 0xAB,
0x81, 0x93, 0x8C, 0xD4, 0x12, 0x5C, 0xAF, 0xA9, 0x49, 0x19, 0xCE, 0x05, 0x11, 0xD9, 0x92, 0x12,
0x4E, 0xED, 0x81, 0xB6, 0xF5, 0x0C, 0x92, 0xE8, 0x00, 0x96, 0x51, 0xB1, 0x03, 0xDC, 0xD3, 0x65,
0x94, 0x16, 0x20, 0xE0, 0x91, 0xD0, 0xD0, 0x57, 0x33, 0x2F, 0x31, 0xCC, 0x0D, 0xC1, 0x14, 0x18,
0x2D, 0xF7, 0x10, 0x0A, 0xD8, 0x62, 0xD8, 0xE8, 0x55, 0x73, 0x9E, 0x5F, 0xDA, 0xB3, 0xBE, 0x20,
0x96, 0x2B, 0xB8, 0xC0, 0x2A, 0x59, 0x31, 0x80, 0x71, 0xCF, 0x27, 0x07, 0xEF, 0xCA, 0x8E, 0xBB,
0xB9, 0x56, 0x95, 0x01, 0x25, 0x4E, 0xC0, 0x02, 0x71, 0xBE, 0x3D, 0xEA, 0x9E, 0xEA, 0xF6, 0x21,
0x23, 0x96, 0x46, 0x65, 0xC1, 0x00, 0x03, 0xD7, 0xDC, 0x74, 0xA4, 0xDE, 0x99, 0xC8, 0x7C, 0x41,
0x64, 0x9C, 0x2D, 0x83, 0x47, 0x29, 0x7D, 0x52, 0x10, 0x70, 0x36, 0xF7, 0xAA, 0x15, 0xE2, 0x06,
0x29, 0x09, 0x24, 0xE4, 0xAE, 0xD9, 0x3D, 0x6B, 0xA4, 0xF1, 0xBB, 0x3B, 0x6B, 0xBB, 0x56, 0x8A,
0x21, 0x86, 0x39, 0x62, 0xAC, 0x40, 0x3F, 0x03, 0xBD, 0x73, 0xEE, 0x21, 0xC2, 0x99, 0x34, 0x9D,
0x18, 0xD3, 0xB6, 0xC3, 0x9D, 0x1F, 0xE9, 0x3F, 0x5B, 0xE4, 0xFB, 0x5B, 0xE6, 0x8E, 0xE8, 0xBC,
0x4C, 0x36, 0x60, 0x41, 0x07, 0x38, 0x23, 0x96, 0x3F, 0x3A, 0xEA, 0x7C, 0x1F, 0x8D, 0x9E, 0x25,
0xC3, 0xA6, 0x69, 0xD3, 0xCC, 0xF2, 0x88, 0x42, 0x7A, 0xB0, 0x39, 0x19, 0xFE, 0x55, 0xC8, 0x56,
0x21, 0x0A, 0xFA, 0x49, 0xD4, 0x4D, 0x68, 0x6C, 0x3C, 0x44, 0xD6, 0x56, 0x9F, 0xB3, 0x63, 0x29,
0xE4, 0x34, 0x5B, 0x75, 0x2C, 0x72, 0x73, 0xF1, 0x49, 0x9E, 0x52, 0x8E, 0x3D, 0x3A, 0x65, 0xBD,
0xCF, 0x95, 0xC5, 0xE3, 0xB3, 0x91, 0x14, 0xA9, 0x64, 0x64, 0x90, 0x1C, 0x13, 0x9E, 0x87, 0xBF,
0x23, 0x57, 0x5C, 0x65, 0xDA, 0x39, 0x4E, 0x91, 0x91, 0xA7, 0x03, 0x49, 0xE5, 0xBF, 0xFD, 0xD6,
0x3A, 0xC3, 0x8C, 0x41, 0x78, 0xF6, 0x97, 0x11, 0x31, 0x73, 0x1C, 0x71, 0x64, 0xB0, 0xF5, 0x06,
0xFA, 0x4E, 0x47, 0xBE, 0x92, 0x6B, 0x41, 0xC6, 0x2F, 0xD1, 0xAD, 0x25, 0x99, 0x86, 0x18, 0x80,
0x32, 0x4F, 0xE7, 0x51, 0xBD, 0x29, 0xBD, 0xA8, 0x15, 0xDE, 0xE3, 0x8A, 0x30, 0x21, 0x48, 0x07,
0x4E, 0x4F, 0x6E, 0x7F, 0xDE, 0x88, 0x82, 0x42, 0x8A, 0xD1, 0x39, 0x38, 0xC1, 0x20, 0x83, 0xDA,
0xA9, 0xAD, 0x6E, 0xD8, 0xD9, 0xB4, 0x98, 0xC4, 0xCF, 0x20, 0x23, 0xDD, 0x7A, 0x54, 0xB6, 0xFC,
0x47, 0xCF, 0xBA, 0x62, 0xA4, 0xF9, 0x5B, 0xE8, 0xF7, 0x3D, 0x6B, 0x4A, 0x5E, 0xD6, 0x96, 0xAC,
0x10, 0xC8, 0x01, 0x3E, 0x86, 0x38, 0xCF, 0x6A, 0x59, 0xF2, 0x91, 0xC8, 0x54, 0x60, 0xB2, 0xE9,
0x56, 0xEE, 0x33, 0x51, 0x47, 0x22, 0xE4, 0x95, 0xD9, 0x86, 0xF8, 0x1D, 0x6B, 0xCC, 0x09, 0x8D,
0xB5, 0x6C, 0xD9, 0xCF, 0xF3, 0x34, 0xCC, 0x7A, 0xFE, 0xE8, 0x2E, 0xD9, 0xDC, 0x01, 0x56, 0x88,
0xEB, 0x1E, 0x4C, 0x7B, 0x9D, 0xF2, 0x7E, 0xDD, 0x3E, 0xF5, 0x57, 0x1C, 0x85, 0xA1, 0x8D, 0xF1,
0x91, 0x9D, 0x80, 0xE6, 0x6A, 0x48, 0xAE, 0x8C, 0x70, 0x98, 0xF1, 0x9D, 0x27, 0x4E, 0x73, 0xB9,
0xA1, 0xB1, 0x58, 0xAB, 0x03, 0x1C, 0x2C, 0x7D, 0x87, 0xB7, 0x3D, 0xE9, 0x58, 0x03, 0x7D, 0x9F,
0xE1, 0x04, 0xB0, 0xFB, 0xD4, 0x36, 0x92, 0x8F, 0x25, 0xCE, 0x30, 0xA8, 0xDE, 0x92, 0x7E, 0xF5,
0x3C, 0x6C, 0xA1, 0x7C, 0xD9, 0x06, 0xDA, 0x74, 0xD1, 0xF4, 0x52, 0xB4, 0x9A, 0x8E, 0x58, 0xEE,
0xAD, 0x95, 0xF8, 0xA1, 0x59, 0xCC, 0x72, 0x36, 0x40, 0xC9, 0x00, 0x1A, 0xF4, 0x92, 0x90, 0x23,
0x70, 0x01, 0x43, 0xCD, 0x47, 0x6E, 0x95, 0x1B, 0x48, 0xA1, 0xC9, 0x04, 0xB0, 0x65, 0xD8, 0x1A,
0x21, 0xB4, 0x17, 0x73, 0x8B, 0x78, 0xDE, 0x4E, 0x63, 0x19, 0xC7, 0xCD, 0x73, 0x1F, 0x10, 0x71,
0x63, 0x34, 0xF2, 0xEA, 0x6D, 0x6C, 0xC0, 0x1C, 0x8E, 0xBB, 0x7F, 0xE5, 0x6B, 0x3C, 0x5F, 0xC4,
0x85, 0xAF, 0x0B, 0x97, 0xCB, 0x24, 0x36, 0xD9, 0x03, 0xF2, 0x15, 0xCB, 0x6E, 0x2E, 0x0C, 0xA5,
0x58, 0x9C, 0xB1, 0x50, 0x0F, 0xB1, 0xAB, 0x61, 0x12, 0xB7, 0x6E, 0xC7, 0x79, 0x73, 0xA8, 0x90,
0x9C, 0xA8, 0x38, 0x61, 0x92, 0x52, 0x49, 0x53, 0x56, 0x76, 0xB6, 0x8B, 0x2C, 0x9A, 0x71, 0x93,
0x57, 0x70, 0x70, 0xF5, 0x8D, 0x75, 0x10, 0x06, 0xD4, 0x35, 0xB2, 0x31, 0xD7, 0xB6, 0xCC, 0x98,
0x24, 0x72, 0xA6, 0xDB, 0xAA, 0x8C, 0x33, 0xBE, 0x92, 0x37, 0x18, 0x5C, 0xD5, 0xF7, 0x14, 0x85,
0x4E, 0xE0, 0x56, 0x76, 0x6C, 0xC6, 0xC4, 0x50, 0xB8, 0xEA, 0xB7, 0x8E, 0x9D, 0xC3, 0xBF, 0x12,
0xF8, 0x75, 0xBF, 0x0F, 0x48, 0xF8, 0xA5, 0xDA, 0xC7, 0x2A, 0xAE, 0x03, 0x95, 0x20, 0x31, 0x1D,
0xBD, 0xEA, 0xE7, 0x86, 0xF8, 0xBB, 0x87, 0x71, 0x48, 0xC3, 0x5A, 0x5F, 0x24, 0x99, 0xFA, 0x57,
0x38, 0x38, 0xEE, 0x41, 0xDC, 0x57, 0x03, 0xE2, 0x56, 0xA6, 0xFE, 0xD9, 0x91, 0x5B, 0x4B, 0x83,
0x95, 0x27, 0xBD, 0x67, 0xAE, 0x38, 0xB7, 0x13, 0xE1, 0x57, 0x48, 0xD0, 0x48, 0xF6, 0xF3, 0x2A,
0xE3, 0x52, 0xEC, 0x69, 0xB1, 0xCE, 0x5E, 0xA1, 0xA5, 0x7D, 0x5A, 0x2F, 0xC4, 0xC1, 0x54, 0x65,
0x5B, 0xCC, 0xD0, 0x37, 0xE7, 0xCE, 0x87, 0xBD, 0x37, 0x31, 0x8D, 0x6A, 0xC0, 0xAE, 0x76, 0xC1,
0xCE, 0xDD, 0x73, 0x5F, 0x3A, 0x3F, 0xE2, 0xD7, 0x88, 0xFF, 0x00, 0x63, 0x8E, 0xDE, 0x26, 0x85,
0x19, 0x14, 0x2F, 0x9A, 0x13, 0xD4, 0x7B, 0x9F, 0x6E, 0xDE, 0xD5, 0xB3, 0xF0, 0x3F, 0x8D, 0x6F,
0x78, 0xDD, 0xB4, 0xF1, 0x5F, 0xC8, 0x45, 0xC0, 0x23, 0x33, 0xE7, 0x00, 0xE7, 0x27, 0xFA, 0x1A,
0x76, 0x74, 0x9F, 0xDB, 0xCC, 0x8E, 0xA8, 0x48, 0x27, 0x27, 0x99, 0xC7, 0xE5, 0x4F, 0x95, 0xF2,
0x0F, 0xA8, 0xEF, 0x8D, 0x81, 0xDC, 0xFC, 0xF4, 0xAA, 0x1E, 0x08, 0xE2, 0xE4, 0xE6, 0x62, 0xAC,
0xA0, 0x90, 0xBE, 0xC3, 0x7C, 0xE6, 0xAF, 0xBC, 0xE8, 0x1E, 0xD5, 0x5D, 0x25, 0x0A, 0xAC, 0x32,
0x18, 0x8D, 0xFA, 0x63, 0x7A, 0x14, 0x60, 0x33, 0x64, 0xC3, 0xD4, 0x49, 0x63, 0xC9, 0x89, 0xC6,
0x09, 0xAA, 0x1E, 0x2A, 0x91, 0xA2, 0xF9, 0x41, 0x00, 0x6F, 0xF8, 0x1E, 0x9F, 0x19, 0xCF, 0xDE,
0xAF, 0x2E, 0xEF, 0x92, 0x26, 0x93, 0x49, 0x76, 0x2B, 0x8D, 0x44, 0x83, 0x91, 0xF2, 0x07, 0x3A,
0xC5, 0xF1, 0x19, 0x1F, 0xCC, 0x69, 0xA5, 0x47, 0x95, 0x25, 0x6F, 0x4C, 0x84, 0xE3, 0x6E, 0xDB,
0x8A, 0x96, 0x47, 0x80, 0x2E, 0x2C, 0x56, 0x76, 0xF3, 0x1A, 0x45, 0x2A, 0x09, 0xF4, 0xC8, 0xC3,
0xD4, 0x3D, 0x89, 0xDC, 0x55, 0x6F, 0x11, 0x86, 0xDA, 0x3B, 0x26, 0x79, 0x0E, 0x83, 0xB8, 0x52,
0xE0, 0x80, 0x41, 0xEA, 0x3B, 0xD1, 0x17, 0x57, 0xBE, 0x54, 0x4A, 0x8F, 0x34, 0xBA, 0x41, 0xC2,
0x39, 0x5D, 0x46, 0x3F, 0x90, 0x46, 0x3F, 0x5A, 0xA7, 0xB9, 0xBC, 0x12, 0xB2, 0xAC, 0xAE, 0x5E,
0x3D, 0x3B, 0x80, 0x9B, 0x03, 0xFE, 0xE1, 0xDA, 0xA3, 0x65, 0x52, 0x59, 0x14, 0xB7, 0x10, 0x00,
0x04, 0xA6, 0x44, 0x70, 0x36, 0xCA, 0xED, 0x8A, 0x09, 0xC6, 0x06, 0xD8, 0x3E, 0xFD, 0xE8, 0xF6,
0x77, 0x49, 0x7C, 0xB4, 0x7C, 0xEB, 0x00, 0x8D, 0x51, 0xE9, 0x2D, 0xF0, 0x45, 0x0F, 0x34, 0x45,
0x17, 0x53, 0x2E, 0xDD, 0xFB, 0x56, 0xF0, 0xB6, 0x0E, 0xE1, 0x77, 0xEF, 0x65, 0x73, 0x14, 0xB1,
0x10, 0xCA, 0x30, 0x0A, 0x1E, 0xA7, 0x98, 0x1F, 0x99, 0xAD, 0x69, 0xE2, 0x22, 0xF3, 0x85, 0xCA,
0xB2, 0x6A, 0xF3, 0x5C, 0xE9, 0xD0, 0x3A, 0x0E, 0x98, 0xFD, 0x4D, 0x60, 0xED, 0xE3, 0x2E, 0x48,
0x43, 0xB7, 0xD4, 0x73, 0x5A, 0x2B, 0x49, 0xA3, 0x48, 0x94, 0xB4, 0x84, 0xCA, 0x72, 0x48, 0x07,
0x7C, 0x9F, 0xFD, 0xA4, 0xCE, 0xE9, 0xB1, 0x86, 0x49, 0x76, 0x50, 0x91, 0xA8, 0x99, 0x00, 0xD3,
0x91, 0xC8, 0x1C, 0x76, 0xF9, 0xA3, 0xE1, 0x54, 0x8E, 0xD2, 0x29, 0x0B, 0x10, 0x7C, 0xCC, 0x0F,
0x82, 0x2A, 0xB1, 0x54, 0x20, 0x91, 0x88, 0xC6, 0xAC, 0x9C, 0x9E, 0xA6, 0x9F, 0x1D, 0xC3, 0x79,
0x0C, 0x8A, 0x72, 0xA7, 0x04, 0xE7, 0xFA, 0x52, 0x4C, 0x9A, 0xC6, 0x99, 0x88, 0x5F, 0x26, 0x6C,
0xE1, 0x58, 0x10, 0x4F, 0xBF, 0x6A, 0x58, 0xE5, 0x2E, 0x15, 0x5C, 0x82, 0xA7, 0x2C, 0xA7, 0xFB,
0xFE, 0x75, 0x57, 0x15, 0xE3, 0x34, 0x08, 0xAD, 0xF4, 0xAB, 0x6B, 0x2B, 0x8E, 0xB9, 0xFF, 0x00,
0x05, 0x22, 0x5D, 0xBB, 0x4A, 0xC7, 0x38, 0x0D, 0xBF, 0xC5, 0x53, 0xFA, 0x48, 0x5D, 0x2C, 0xFC,
0xC6, 0x59, 0xC3, 0x30, 0xF4, 0xAE, 0xCA, 0x3B, 0x6D, 0xFF, 0x00, 0x74, 0xA8, 0xCC, 0xF7, 0x41,
0x40, 0xD8, 0x1C, 0xD0, 0x30, 0xCC, 0x75, 0x90, 0xDF, 0xC4, 0x7F, 0xF2, 0x8D, 0x82, 0x41, 0x1E,
0x87, 0x03, 0x53, 0xE0, 0xE6, 0x97, 0xEB, 0x67, 0xF1, 0x60, 0x24, 0x20, 0x98, 0xC1, 0xFA, 0x5B,
0x38, 0x1D, 0x69, 0xF7, 0x17, 0x47, 0xCB, 0x08, 0x0E, 0xC5, 0x77, 0x35, 0x5D, 0xE6, 0x14, 0x00,
0x03, 0xEA, 0xF6, 0xA9, 0x89, 0xC2, 0x82, 0xC7, 0xE9, 0x03, 0x7A, 0x79, 0x43, 0xA1, 0x29, 0x21,
0x6B, 0x67, 0x24, 0xE3, 0x6C, 0xFC, 0x50, 0xB7, 0x17, 0xC2, 0x18, 0x24, 0x70, 0x46, 0xB4, 0x43,
0x80, 0x7A, 0xD5, 0x37, 0x18, 0xE2, 0xEF, 0x69, 0x67, 0x2F, 0x92, 0x09, 0x64, 0x52, 0x70, 0x7F,
0xCF, 0xBF, 0xDA, 0xB1, 0xD7, 0xDE, 0x20, 0x96, 0xEB, 0x53, 0xEA, 0x20, 0x33, 0x2A, 0x90, 0x3E,
0x3F, 0xEF, 0x15, 0x6C, 0x26, 0xFB, 0x4E, 0xD4, 0x9E, 0x25, 0xE2, 0xAF, 0x78, 0xF3, 0x20, 0x24,
0x69, 0x70, 0x08, 0xEE, 0x37, 0xFE, 0xF5, 0x96, 0x38, 0x26, 0xA6, 0x92, 0x76, 0x72, 0xCF, 0xD5,
0x86, 0x08, 0xA8, 0x33, 0xD6, 0xAD, 0x0A, 0xFA, 0x47, 0x86, 0x5A, 0x47, 0x14, 0x61, 0x98, 0xFD,
0xEA, 0x79, 0xE7, 0x43, 0x9C, 0x72, 0xE9, 0x59, 0xBB, 0x5E, 0x2D, 0x24, 0x8A, 0x41, 0xE4, 0x39,
0x52, 0xDC, 0x71, 0x35, 0x8D, 0x72, 0x5B, 0x7E, 0xD5, 0x3C, 0x73, 0x9A, 0x29, 0x78, 0xA5, 0xDA,
0x45, 0x92, 0xC7, 0x3D, 0x80, 0xAC, 0xC4, 0xF7, 0x42, 0x42, 0x77, 0xA6, 0x71, 0x0E, 0x23, 0xE7,
0xC8, 0x40, 0x39, 0x3E, 0xD4, 0x06, 0xA6, 0xD4, 0x2B, 0x9F, 0x96, 0xE5, 0x9D, 0xD4, 0x01, 0xE9,
0x26, 0x83, 0x90, 0x81, 0xC9, 0x18, 0x00, 0xF4, 0x3D, 0xEA, 0xC1, 0xB8, 0x6F, 0x0C, 0xE2, 0x16,
0xFE, 0x5D, 0xF0, 0xFD, 0xA9, 0xE4, 0x01, 0x43, 0x2E, 0x57, 0xCB, 0x3F, 0xF0, 0x3C, 0xC9, 0x1C,
0xB3, 0xCB, 0xB6, 0x79, 0xD0, 0x11, 0x85, 0x68, 0xF3, 0x9D, 0xEA, 0xC2, 0xD6, 0xFE, 0x2B, 0x50,
0x02, 0x2E, 0x66, 0xFA, 0x43, 0xF4, 0x41, 0xED, 0xFA, 0xEF, 0x5B, 0x8F, 0x8F, 0xE7, 0xB6, 0x66,
0xB8, 0xA7, 0x80, 0xA5, 0xE1, 0xF7, 0x8A, 0xB1, 0xCB, 0x9B, 0x79, 0x06, 0x56, 0x49, 0x76, 0xD3,
0xF3, 0x8A, 0xB3, 0xB2, 0xB7, 0x87, 0x85, 0x58, 0x0B, 0x5E, 0x1A, 0x3F, 0x68, 0x76, 0x61, 0xE7,
0x48, 0x47, 0xD4, 0xC7, 0xE7, 0xA6, 0xD8, 0xAD, 0x21, 0xE2, 0x50, 0x5C, 0xDA, 0x98, 0xA6, 0x7F,
0x38, 0x6A, 0xC0, 0x1A, 0x7E, 0x9F, 0xF3, 0x9D, 0x55, 0x8E, 0x1F, 0x1A, 0x79, 0x8B, 0x68, 0xDB,
0xCD, 0x1E, 0x90, 0xA4, 0xEE, 0x3A, 0xFD, 0xB9, 0xD7, 0x47, 0xD5, 0x15, 0x97, 0x0C, 0xE3, 0x52,
0x59, 0x32, 0xB6, 0x57, 0xFF, 0x00, 0xAC, 0xAB, 0x63, 0xE9, 0x3B, 0xD5, 0xAC, 0x9C, 0x6D, 0xD2,
0xCF, 0x31, 0xCA, 0xA0, 0xB7, 0xA9, 0x43, 0x7C, 0x7E, 0x86, 0xB1, 0xAF, 0x17, 0x90, 0xA8, 0xB3,
0xC6, 0x43, 0x92, 0x40, 0x60, 0xB9, 0x5C, 0x64, 0x60, 0x0C, 0x6F, 0xB9, 0xCD, 0x11, 0x75, 0x1D,
0xDC, 0x30, 0xA6, 0x19, 0x7D, 0x08, 0x5B, 0x2B, 0xEA, 0x04, 0x8E, 0x5B, 0xFE, 0x7F, 0x6A, 0xDB,
0x3C, 0x1D, 0x79, 0xC6, 0x4D, 0xBB, 0x97, 0x79, 0x48, 0x95, 0x97, 0xD2, 0x4E, 0x76, 0x3F, 0xFB,
0xBD, 0x54, 0xB7, 0x12, 0x9A, 0xF2, 0x16, 0x95, 0x73, 0xE5, 0xAB, 0x1D, 0x71, 0xA9, 0x23, 0x7E,
0xBB, 0x54, 0x3C, 0x42, 0xDF, 0xF6, 0xDB, 0x51, 0x31, 0xCC, 0x60, 0xFA, 0x99, 0x47, 0x35, 0xC7,
0xF4, 0xDC, 0x7E, 0x55, 0x54, 0x78, 0xAC, 0x10, 0xC6, 0x77, 0xD4, 0xC1, 0x18, 0xC8, 0x41, 0x00,
0x9C, 0x03, 0xA4, 0x8C, 0xFD, 0x59, 0x38, 0x1D, 0xE8, 0x6B, 0x63, 0xBD, 0x2D, 0x7F, 0x6A, 0x89,
0x92, 0x41, 0xE7, 0xE8, 0x8B, 0x3B, 0x99, 0x4E, 0xC0, 0x7B, 0xF6, 0xF9, 0xA0, 0xAF, 0x42, 0xD9,
0x35, 0x9D, 0xDC, 0x25, 0xA5, 0x89, 0x9C, 0xAB, 0xA9, 0x3C, 0x88, 0xFF, 0x00, 0xA3, 0x9A, 0xCA,
0xDC, 0x71, 0x57, 0xD6, 0xF8, 0x97, 0xCE, 0x89, 0xF9, 0xC6, 0xE0, 0xAB, 0x29, 0xEF, 0x91, 0xB0,
0xFD, 0x47, 0xB5, 0x36, 0xDA, 0xF6, 0xE4, 0x44, 0x11, 0x0E, 0xFA, 0x71, 0x93, 0xBE, 0x07, 0xB7,
0xEB, 0x5A, 0xE2, 0x32, 0xAF, 0x2F, 0x78, 0x84, 0x2D, 0x6F, 0x8B, 0x75, 0x29, 0x01, 0x2D, 0x85,
0x65, 0xCE, 0x5B, 0xFE, 0x3D, 0xBA, 0xD0, 0xB6, 0xF2, 0x49, 0x32, 0x11, 0x2F, 0xAB, 0x0B, 0xF5,
0x1E, 0x74, 0xED, 0x46, 0xE8, 0x42, 0x98, 0xC4, 0x71, 0xAE, 0x3E, 0x9D, 0x8B, 0x75, 0x35, 0x30,
0x8C, 0x22, 0xE0, 0x73, 0x1D, 0xAA, 0x16, 0x9E, 0x92, 0xCD, 0x22, 0xB7, 0x5C, 0xB3, 0x1D, 0x52,
0x82, 0x14, 0x76, 0x5F, 0x71, 0xEE, 0x47, 0xF9, 0x9A, 0x26, 0xC3, 0xF7, 0x6E, 0x73, 0xC9, 0xB7,
0x26, 0x85, 0xC1, 0x66, 0x07, 0x19, 0x3D, 0xE8, 0xD8, 0x2D, 0x98, 0xAE, 0xA2, 0x77, 0x03, 0x00,
0x7B, 0x54, 0xF3, 0xF1, 0xB1, 0xA2, 0xA7, 0x93, 0x51, 0x00, 0x6E, 0x07, 0x6A, 0x7C, 0x51, 0xE9,
0x56, 0xC0, 0xE4, 0x69, 0x11, 0x42, 0x8C, 0x6D, 0xCA, 0x9E, 0x1D, 0x89, 0x03, 0xA0, 0xDF, 0x02,
0xA5, 0x1B, 0x7B, 0x4F, 0x0C, 0x2C, 0xE9, 0x93, 0xF4, 0x75, 0xA9, 0x95, 0x42, 0x92, 0x4E, 0x30,
0x36, 0x03, 0xDE, 0x99, 0xE7, 0x0D, 0x90, 0x73, 0xED, 0x51, 0xBC, 0xA3, 0x5E, 0xED, 0x8C, 0x77,
0xA3, 0xAB, 0x5B, 0x62, 0x41, 0x1A, 0x89, 0xC6, 0xC3, 0xAD, 0x13, 0xE6, 0x02, 0xAA, 0x8A, 0x76,
0x03, 0x24, 0x8A, 0xAD, 0x79, 0x82, 0x85, 0x50, 0x77, 0x63, 0x93, 0xF1, 0xBF, 0xF6, 0xA0, 0xAF,
0x78, 0xA2, 0x47, 0x6B, 0x22, 0x07, 0xC3, 0x4A, 0x8C, 0x43, 0x0E, 0x9D, 0xAA, 0x98, 0x71, 0xD0,
0xB9, 0x34, 0x16, 0xD7, 0x09, 0x34, 0xAC, 0x43, 0x75, 0xFD, 0x06, 0xD4, 0x3F, 0x1A, 0xE2, 0x49,
0x0D, 0xA6, 0x92, 0x4A, 0xB3, 0x30, 0x3C, 0xF1, 0xB5, 0x64, 0xE0, 0xE3, 0x1A, 0x23, 0xB8, 0x11,
0x3E, 0x1D, 0xC6, 0x01, 0xFF, 0x00, 0x68, 0xD4, 0xBF, 0xF7, 0x55, 0xBC, 0x4F, 0x8C, 0x4D, 0x77,
0xAD, 0x59, 0xB5, 0x6B, 0x0A, 0x48, 0xC7, 0xD3, 0xB0, 0xE5, 0xFA, 0xD7, 0x4E, 0x3C, 0x44, 0xB4,
0xBC, 0x47, 0x8C, 0xC9, 0x73, 0x74, 0xDA, 0x0E, 0x23, 0x62, 0xC0, 0x81, 0xD7, 0x24, 0xEF, 0xFA,
0xD5, 0x41, 0x73, 0xA4, 0xA9, 0xCF, 0x32, 0x7E, 0xF4, 0xDE, 0xB9, 0xE5, 0x4A, 0x40, 0xE7, 0xD0,
0x8A, 0xBC, 0x92, 0x14, 0xCC, 0x9A, 0x5E, 0x74, 0x9F, 0x7A, 0x51, 0x45, 0x9D, 0x42, 0x0E, 0x22,
0xC8, 0x31, 0x8F, 0x8A, 0x1E, 0x77, 0x96, 0x76, 0x24, 0x9D, 0xBB, 0x54, 0x28, 0x30, 0xF9, 0x39,
0xC5, 0x10, 0x1C, 0x27, 0x3A, 0xE2, 0xC4, 0x81, 0x61, 0x8B, 0x17, 0x1E, 0xA1, 0xBD, 0x11, 0x3A,
0x05, 0x03, 0x4F, 0xDE, 0x86, 0x9D, 0xF5, 0x3F, 0xA4, 0x52, 0x87, 0x24, 0x60, 0xF3, 0xEA, 0x6A,
0x9A, 0xD0, 0x2C, 0x22, 0x03, 0xC9, 0xDA, 0x84, 0x27, 0x2E, 0x74, 0x9A, 0x61, 0x99, 0xB4, 0x94,
0x0D, 0xB7, 0xB5, 0x4B, 0x02, 0x8C, 0x82, 0x79, 0xD3, 0x69, 0x8E, 0x8A, 0x43, 0x11, 0x05, 0xB3,
0xA7, 0xDB, 0x9D, 0x0F, 0x73, 0xC4, 0xE3, 0x89, 0x48, 0x89, 0xE4, 0xF3, 0x9C, 0xE1, 0x9B, 0x1B,
0x81, 0xD9, 0x7B, 0x51, 0x17, 0x5A, 0x52, 0x22, 0x73, 0x55, 0x76, 0xF2, 0x24, 0x7C, 0x42, 0x19,
0x0A, 0xB3, 0xE8, 0x70, 0xC0, 0x05, 0xCE, 0x7E, 0xD4, 0xD8, 0x8B, 0x5D, 0x0F, 0xFA, 0x85, 0xBF,
0x09, 0xB8, 0xBE, 0x9A, 0x24, 0x2C, 0x1C, 0x24, 0x66, 0x47, 0xFA, 0x70, 0x30, 0x5B, 0x00, 0x6F,
0xBE, 0x7F, 0x4A, 0xA6, 0x7F, 0x14, 0xC7, 0xA2, 0xEB, 0x11, 0x30, 0x58, 0x5D, 0x62, 0x0E, 0x7F,
0x8D, 0x89, 0x23, 0xF9, 0x02, 0x6B, 0x5B, 0x6B, 0xC4, 0x20, 0x9E, 0xD5, 0x2D, 0xA5, 0x65, 0xF3,
0x08, 0xD9, 0x00, 0xD9, 0x71, 0xDC, 0xF5, 0xF9, 0xAC, 0x6F, 0x1E, 0xF0, 0xE4, 0xAF, 0x91, 0x0E,
0x34, 0x06, 0x2E, 0x54, 0x00, 0x37, 0x3E, 0xD5, 0xAF, 0xCF, 0xE9, 0xA2, 0xA2, 0xFF, 0x00, 0x8A,
0xB5, 0xD4, 0xEF, 0x6E, 0x0F, 0x97, 0x0C, 0x61, 0x55, 0x98, 0x7F, 0x03, 0x9E, 0xA3, 0xE1, 0x8E,
0x3E, 0x33, 0x54, 0x32, 0xB3, 0x2C, 0x6E, 0x93, 0x12, 0x66, 0x8D, 0xBD, 0x27, 0xB7, 0x71, 0x47,
0xCB, 0xC1, 0x6E, 0xA3, 0x00, 0x79, 0x47, 0x7F, 0x6D, 0xFE, 0xF5, 0xE1, 0xC0, 0xAE, 0x88, 0xCE,
0x31, 0x91, 0xB6, 0x6B, 0x4C, 0xB1, 0x86, 0xF5, 0x46, 0xAA, 0xD2, 0xCA, 0x00, 0x19, 0x24, 0xF6,
0xAB, 0x7B, 0x2B, 0x47, 0xD4, 0xAC, 0xDF, 0x4D, 0x59, 0x5A, 0xF0, 0x47, 0x84, 0x93, 0xA3, 0x73,
0xCC, 0x91, 0x56, 0x0B, 0xC3, 0x9D, 0x70, 0x15, 0x7D, 0x3D, 0xFB, 0x54, 0xB9, 0x39, 0x77, 0xD4,
0x36, 0x3A, 0x43, 0x1C, 0x2B, 0x1A, 0xFA, 0x40, 0xC6, 0x29, 0x7C, 0x87, 0xCE, 0x68, 0x97, 0xF2,
0xE1, 0x52, 0x09, 0xE4, 0x39, 0x55, 0x7C, 0x9C, 0x61, 0x62, 0x7C, 0x08, 0xB6, 0xCF, 0x2C, 0xD4,
0x31, 0xC7, 0x2B, 0xE3, 0x5C, 0xA0, 0xE8, 0xAD, 0x46, 0xBD, 0x44, 0x72, 0x1B, 0xD5, 0x94, 0x36,
0xBA, 0xD3, 0x51, 0x20, 0x2F, 0x22, 0x4D, 0x53, 0x49, 0xC5, 0xA3, 0x60, 0xBE, 0x51, 0x20, 0x6C,
0x33, 0xDF, 0x3F, 0xF9, 0x56, 0xF6, 0x33, 0xBA, 0xDA, 0x81, 0x0B, 0x89, 0x1F, 0x03, 0x76, 0x6D,
0x38, 0xDB, 0x1B, 0x66, 0x9F, 0x0E, 0x1B, 0x95, 0xEC, 0x3E, 0xC6, 0x1B, 0x24, 0x58, 0xF5, 0x05,
0x66, 0xC8, 0xE6, 0x05, 0x08, 0xEA, 0xA9, 0x90, 0x00, 0x1B, 0xD1, 0x6C, 0xEC, 0x90, 0x67, 0x26,
0x49, 0x31, 0x9D, 0x39, 0xD7, 0xA7, 0xEC, 0x07, 0xEB, 0x55, 0x12, 0x4F, 0x3C, 0x93, 0x2C, 0x28,
0xAC, 0x5C, 0x9F, 0x52, 0xA8, 0xE5, 0xF7, 0xCE, 0xD5, 0xD1, 0xFC, 0x71, 0x6D, 0x96, 0x79, 0x04,
0x0C, 0x48, 0x65, 0xD4, 0x77, 0x24, 0x9E, 0x5F, 0xE6, 0x2A, 0xB5, 0xAE, 0x88, 0x69, 0x00, 0xFA,
0x17, 0xD5, 0x9C, 0x6E, 0x4D, 0x4B, 0x7F, 0x11, 0x84, 0xC6, 0x89, 0xEA, 0x92, 0x46, 0x3B, 0x8C,
0xE5, 0x88, 0xF9, 0xE6, 0x3A, 0x0E, 0xB4, 0x23, 0xC6, 0xD0, 0xAC, 0xAB, 0x29, 0xFD, 0xF0, 0x6D,
0x52, 0x36, 0x79, 0x1E, 0xDF, 0x6E, 0x54, 0xD3, 0x8E, 0x46, 0x24, 0xBC, 0x4B, 0x37, 0x48, 0x9B,
0x04, 0x03, 0x0C, 0x3D, 0xB1, 0x54, 0xD7, 0x37, 0x4D, 0x3C, 0xCC, 0xCE, 0x71, 0x94, 0xD3, 0x8F,
0xF6, 0x9A, 0x56, 0x6F, 0xDE, 0x3C, 0xDB, 0xEE, 0x7F, 0x4A, 0x12, 0x46, 0x2C, 0xC7, 0x3C, 0x89,
0xDA, 0x9A, 0x63, 0x20, 0x53, 0x3C, 0xC6, 0x40, 0x46, 0x77, 0x34, 0xCD, 0x58, 0x6C, 0xE2, 0x94,
0xF2, 0xC9, 0xA8, 0xCF, 0x2A, 0x60, 0x2E, 0x4E, 0x73, 0x4E, 0xC9, 0x3B, 0xD2, 0x32, 0x95, 0x62,
0x0F, 0x3C, 0x0A, 0x43, 0xB6, 0x00, 0x34, 0x58, 0x9B, 0xF3, 0xAF, 0x57, 0xB1, 0x5E, 0x34, 0x19,
0xD3, 0xEE, 0x60, 0x10, 0xAE, 0x47, 0x3E, 0xD4, 0x00, 0x66, 0x66, 0xC1, 0x34, 0x5D, 0xD5, 0xDF,
0x98, 0xE4, 0x9E, 0x40, 0xF5, 0xA0, 0xC3, 0x82, 0xFE, 0x9E, 0x79, 0xAE, 0x7E, 0x39, 0xB4, 0xD2,
0x84, 0xC1, 0xDE, 0x9A, 0xCA, 0x09, 0xC0, 0xA7, 0x33, 0x64, 0x67, 0xAD, 0x31, 0x0F, 0x3A, 0xA3,
0x1A, 0x54, 0x86, 0xD8, 0x51, 0x30, 0x7D, 0x43, 0x26, 0xA1, 0x66, 0xDF, 0xDE, 0x9F, 0x1E, 0x73,
0x90, 0x28, 0x5E, 0xC4, 0xFB, 0xF4, 0x3E, 0x49, 0x22, 0xA8, 0x85, 0xCC, 0xA8, 0x55, 0x03, 0x14,
0x8C, 0x7D, 0x46, 0x31, 0x86, 0x6F, 0xFF, 0x00, 0xAA, 0xD0, 0xCE, 0x41, 0x80, 0x93, 0xDA, 0xB3,
0xD2, 0x69, 0xF3, 0x08, 0xC7, 0x5A, 0x31, 0x85, 0x27, 0x14, 0x71, 0x70, 0x86, 0x04, 0x8E, 0x25,
0x5D, 0xC8, 0x39, 0x3B, 0x0E, 0x40, 0x9E, 0xBD, 0xFE, 0x7D, 0xF7, 0xAB, 0x51, 0xC7, 0x7F, 0x66,
0x68, 0x23, 0x95, 0xF5, 0x6A, 0x01, 0xDD, 0x98, 0xEE, 0xC4, 0xFF, 0x00, 0x9F, 0xCA, 0xB3, 0xE8,
0xC9, 0x13, 0x02, 0xD1, 0x2B, 0x8C, 0xEF, 0x9E, 0xD5, 0x11, 0x2D, 0x71, 0x74, 0xD3, 0x4A, 0x75,
0x31, 0x39, 0x3B, 0x51, 0xCA, 0x4B, 0xE8, 0xCE, 0x9A, 0xDB, 0x7E, 0x2A, 0x97, 0x7A, 0x83, 0x44,
0xA0, 0x8C, 0x67, 0xE6, 0x9B, 0x27, 0x13, 0xB7, 0x0A, 0x8C, 0xB1, 0x82, 0x0E, 0xE3, 0xE3, 0x15,
0x4B, 0x6D, 0xAA, 0x02, 0x62, 0x1E, 0x96, 0xE4, 0xF9, 0xEE, 0x79, 0xFF, 0x00, 0x4A, 0x87, 0x58,
0x91, 0x74, 0x0C, 0xF3, 0x04, 0x7E, 0x55, 0x1F, 0xE7, 0x0C, 0xB8, 0x9F, 0x89, 0xEA, 0x5C, 0x46,
0x17, 0x19, 0xC6, 0xC3, 0x71, 0x55, 0x32, 0xDC, 0x4E, 0x49, 0x61, 0x23, 0x03, 0xF3, 0x4F, 0x54,
0x2C, 0xA4, 0x8F, 0xA8, 0x0D, 0xEA, 0x39, 0x1B, 0xD3, 0xCB, 0x7A, 0xD3, 0x19, 0x04, 0x0D, 0xD4,
0xCF, 0x29, 0xD4, 0xC7, 0x2D, 0xD4, 0xD0, 0x24, 0xE4, 0xEE, 0x68, 0xA9, 0xC8, 0xCE, 0x48, 0xA1,
0xD4, 0x0D, 0x60, 0x9E, 0x59, 0xAA, 0x48, 0x5A, 0x9E, 0xD6, 0x17, 0x92, 0x55, 0x53, 0xB2, 0x93,
0xCF, 0x1F, 0xE6, 0x6B, 0x69, 0x02, 0x45, 0x66, 0x88, 0x55, 0x4C, 0x84, 0xAF, 0xA8, 0x10, 0x33,
0x9E, 0xC3, 0xB5, 0x50, 0xF0, 0xAB, 0x11, 0x3C, 0x9E, 0x63, 0x9C, 0x42, 0xBB, 0x92, 0x37, 0xC9,
0xED, 0x8A, 0xD1, 0xDA, 0xDA, 0x19, 0x35, 0x15, 0x90, 0xA1, 0x1B, 0x96, 0x73, 0x84, 0x03, 0xFC,
0xEC, 0x0D, 0x3E, 0x10, 0x21, 0xF3, 0xDF, 0xCE, 0xB1, 0x00, 0xB0, 0x08, 0x62, 0xC0, 0xC8, 0x51,
0x96, 0x63, 0xF2, 0x77, 0x34, 0x04, 0xFE, 0x5D, 0xA5, 0xA6, 0xA4, 0x50, 0x8D, 0x20, 0x1A, 0xB7,
0xF5, 0x11, 0xF3, 0x8A, 0x3E, 0xEE, 0x40, 0x53, 0xCB, 0x66, 0xF3, 0x34, 0x0F, 0x53, 0x3B, 0x1D,
0x87, 0x6F, 0xD6, 0xB3, 0x97, 0x85, 0xDF, 0xD7, 0x82, 0x85, 0xBD, 0x58, 0x3D, 0x07, 0x4F, 0x8E,
0xF4, 0xE7, 0x7A, 0xDE, 0x47, 0xB8, 0xB8, 0xD3, 0x6E, 0x9A, 0x51, 0x46, 0x1D, 0x8E, 0xFB, 0x7C,
0x74, 0xEB, 0x41, 0xF1, 0x2B, 0x85, 0xD1, 0x15, 0xBC, 0x23, 0x04, 0x31, 0xD4, 0xD9, 0xE7, 0x8F,
0xFD, 0x35, 0x67, 0x0B, 0x25, 0x95, 0x8B, 0x22, 0x69, 0x52, 0xED, 0xBB, 0x63, 0xD4, 0xDC, 0x85,
0x54, 0xC6, 0x8B, 0x2B, 0x49, 0x3B, 0x6C, 0xB1, 0x29, 0x25, 0xBA, 0x6F, 0xB5, 0x01, 0x01, 0x7D,
0xA6, 0x27, 0x1A, 0x00, 0xD0, 0xC0, 0x3E, 0x0F, 0xBF, 0x2F, 0xCA, 0x82, 0xC8, 0x53, 0x86, 0x03,
0x60, 0x40, 0xDB, 0x99, 0xA3, 0x78, 0xAE, 0x96, 0xBD, 0xF2, 0x90, 0x9F, 0xA1, 0x41, 0xFF, 0x00,
0x8E, 0x00, 0xCE, 0x7F, 0x5A, 0x07, 0x20, 0xCE, 0xC7, 0x6C, 0x61, 0x9B, 0x03, 0xA6, 0xC6, 0x88,
0x23, 0x70, 0x18, 0x1C, 0x0D, 0xF7, 0x3F, 0x02, 0x87, 0xA9, 0xD9, 0xF0, 0xEC, 0x7A, 0x30, 0x22,
0xA2, 0xEB, 0x40, 0x0A, 0xB9, 0x24, 0xE6, 0xBD, 0xF3, 0x5E, 0x5E, 0x74, 0xE0, 0x06, 0xE4, 0xF3,
0xAC, 0xC6, 0x63, 0xF2, 0xA5, 0xEB, 0x4B, 0x83, 0x9A, 0xF0, 0x15, 0x99, 0xD1, 0x2F, 0x74, 0xF9,
0x47, 0x18, 0xA0, 0x20, 0x7F, 0x51, 0x04, 0x7C, 0x54, 0xC5, 0x3D, 0x18, 0x27, 0x3E, 0xD5, 0xE5,
0x81, 0x73, 0xB0, 0xC1, 0xA8, 0x63, 0xD4, 0x21, 0xCC, 0xC0, 0x52, 0xC4, 0xDB, 0xFA, 0x86, 0x36,
0xAF, 0x3A, 0x69, 0x1C, 0xA9, 0xB8, 0xD8, 0x60, 0xD3, 0x7A, 0xC5, 0x97, 0xEA, 0x04, 0x51, 0x76,
0xCA, 0x0E, 0x36, 0xA0, 0x91, 0x49, 0x71, 0x56, 0x50, 0x00, 0xAC, 0x33, 0xCA, 0xB7, 0x83, 0x10,
0xDE, 0xFA, 0x50, 0x83, 0x54, 0x72, 0x47, 0x96, 0x24, 0x56, 0xA2, 0xEA, 0xDC, 0x4B, 0x0E, 0x73,
0x9A, 0xA1, 0x96, 0x23, 0x1B, 0x91, 0x4D, 0x04, 0x03, 0x29, 0xE4, 0x76, 0xA7, 0x44, 0xCF, 0x0B,
0x87, 0x89, 0xB4, 0xBA, 0x90, 0x55, 0x87, 0x30, 0x7D, 0xA9, 0xD2, 0x0D, 0xF7, 0x14, 0x84, 0x8C,
0x72, 0xAC, 0x06, 0x87, 0x64, 0x56, 0x21, 0xB7, 0xC8, 0xDE, 0xBD, 0x1C, 0x98, 0x3B, 0x73, 0xAF,
0x30, 0xC8, 0xF7, 0xA8, 0xC2, 0x91, 0xC8, 0x50, 0xA2, 0x2D, 0x25, 0x3A, 0x81, 0x1C, 0xB3, 0x5E,
0x70, 0x34, 0x93, 0x9A, 0x81, 0x33, 0xAB, 0x14, 0xE9, 0x58, 0x85, 0xDE, 0xA7, 0xFA, 0x60, 0x33,
0xF3, 0xC0, 0xAF, 0x59, 0xC0, 0xD7, 0x37, 0x0B, 0x0A, 0x80, 0x59, 0xB3, 0x80, 0x4E, 0x07, 0xE7,
0x4B, 0x26, 0xF5, 0x61, 0xC1, 0xAD, 0x07, 0xED, 0x2B, 0x23, 0x49, 0xA1, 0xD4, 0xE5, 0x40, 0xDC,
0xE3, 0xB8, 0xC5, 0x52, 0x13, 0xF5, 0xA0, 0xB1, 0xB3, 0x9A, 0xD2, 0x24, 0x8B, 0xCB, 0x2B, 0x18,
0xDC, 0xE0, 0xFD, 0x4D, 0xED, 0x83, 0xBD, 0x1C, 0x8C, 0xB6, 0xC8, 0xAA, 0xD7, 0x31, 0xC6, 0xA3,
0x7E, 0xB9, 0xC7, 0xE5, 0x45, 0x5B, 0x5B, 0x81, 0x18, 0x94, 0x2E, 0x09, 0x5D, 0x9B, 0xBF, 0xD8,
0x0F, 0xEB, 0x55, 0xD7, 0x83, 0xCC, 0x5D, 0x10, 0x85, 0x04, 0xEC, 0xAD, 0x8D, 0xCE, 0xFC, 0xBE,
0x2A, 0xB2, 0x6A, 0x1A, 0x22, 0xBD, 0xE2, 0x11, 0xDD, 0x01, 0x15, 0xA8, 0x90, 0xE4, 0x92, 0xC5,
0x90, 0x28, 0x0C, 0x7F, 0xDA, 0x07, 0xE5, 0xBF, 0xE5, 0x55, 0x97, 0xB0, 0x47, 0xFB, 0x5C, 0x10,
0x8B, 0x88, 0xE6, 0x0B, 0xA5, 0xE6, 0x11, 0x03, 0xFB, 0xB3, 0xCC, 0xA6, 0x79, 0x36, 0x00, 0xDF,
0x1D, 0xE8, 0xAB, 0x99, 0xA0, 0xB3, 0xB6, 0x01, 0x5C, 0xF9, 0xAD, 0xF5, 0x8C, 0x06, 0x08, 0xBD,
0x77, 0xEA, 0xC4, 0xF6, 0xE5, 0x8E, 0x75, 0x5F, 0x6F, 0x19, 0x16, 0xD2, 0xB9, 0x02, 0x31, 0xA4,
0x48, 0xE7, 0x39, 0x31, 0xA7, 0x21, 0x9E, 0xC4, 0x92, 0x0F, 0xDE, 0xB1, 0x91, 0x5A, 0x46, 0x2E,
0x6F, 0xC2, 0xCC, 0x74, 0x40, 0xAA, 0x49, 0x19, 0x1B, 0x0C, 0x12, 0x06, 0xE7, 0x9E, 0x7A, 0x77,
0xAA, 0xF3, 0x31, 0x11, 0xB5, 0xBC, 0x44, 0x98, 0xF5, 0x21, 0xC6, 0x79, 0xEC, 0x7F, 0xBD, 0x4A,
0x2E, 0x84, 0x90, 0xCF, 0x3A, 0x07, 0xF2, 0xD4, 0x1C, 0x29, 0xE6, 0x73, 0x81, 0x92, 0x7B, 0xEF,
0x40, 0xC0, 0xCA, 0x67, 0x69, 0x59, 0xBE, 0x95, 0x24, 0x90, 0x3E, 0xD4, 0x18, 0x07, 0x9A, 0x03,
0xCA, 0xD8, 0xF5, 0x31, 0xFF, 0x00, 0x3F, 0xA5, 0x0E, 0x5B, 0xD4, 0x48, 0xEB, 0x52, 0x85, 0xD4,
0xE5, 0x77, 0xD8, 0x1E, 0x55, 0x19, 0x0B, 0xB6, 0x01, 0xE7, 0xB8, 0x35, 0x80, 0xD6, 0xDF, 0x71,
0xCA, 0xBD, 0x8A, 0x93, 0x4E, 0xA3, 0x8C, 0xF4, 0xAF, 0x05, 0x20, 0xE2, 0xB0, 0x12, 0x35, 0x2C,
0xC0, 0x54, 0x9A, 0x0E, 0x09, 0xFD, 0x29, 0xF1, 0xAE, 0x14, 0xF7, 0x06, 0x97, 0x48, 0xD3, 0x9C,
0x9C, 0x9A, 0xC2, 0x1D, 0xB7, 0x26, 0x95, 0x46, 0x76, 0xAF, 0x2A, 0x9D, 0xEA, 0x68, 0x90, 0x93,
0x42, 0xD6, 0x6E, 0x9C, 0x0C, 0xE3, 0x1B, 0xD4, 0x69, 0x95, 0x6E, 0xC2, 0x9E, 0xEC, 0x4B, 0x6F,
0x4D, 0x63, 0xB6, 0x47, 0x3A, 0x92, 0x67, 0xCC, 0x3D, 0x02, 0x84, 0xD4, 0x73, 0x81, 0x53, 0x96,
0x2C, 0xBB, 0xD4, 0x0C, 0x42, 0x9D, 0xE8, 0x63, 0xB6, 0x15, 0x1E, 0x00, 0x04, 0xE2, 0xA6, 0x59,
0x37, 0x02, 0x82, 0x47, 0xCB, 0x60, 0x51, 0x8A, 0xBB, 0x03, 0x4C, 0x23, 0x0C, 0xFA, 0x62, 0xC1,
0x38, 0xC5, 0x53, 0x5C, 0x3A, 0xBB, 0x12, 0x79, 0xD1, 0x37, 0x52, 0x11, 0x19, 0x00, 0xF4, 0xAA,
0xD7, 0xCE, 0x9C, 0x93, 0xF6, 0xA6, 0x6D, 0x99, 0x21, 0x53, 0x50, 0x6D, 0xA8, 0xE2, 0xBC, 0x79,
0xE4, 0x52, 0x64, 0x93, 0xCE, 0x85, 0x13, 0xF1, 0x8A, 0xF1, 0x20, 0x53, 0x59, 0xB1, 0xF3, 0x48,
0xBB, 0xEE, 0x4E, 0xD4, 0xA2, 0x99, 0x06, 0xD9, 0x15, 0x05, 0xC3, 0x74, 0x15, 0x29, 0x7C, 0x03,
0xBE, 0xF4, 0x1C, 0xEF, 0x93, 0x41, 0xAF, 0x8F, 0x5B, 0xC2, 0xD7, 0x37, 0x0B, 0x10, 0x56, 0x24,
0x9E, 0x82, 0xB7, 0x56, 0x36, 0xFF, 0x00, 0xB0, 0xC5, 0x1A, 0x24, 0x2E, 0x57, 0x4E, 0x08, 0x00,
0x0C, 0x9F, 0x9F, 0xEB, 0x8A, 0xCF, 0xF8, 0x66, 0xDE, 0x26, 0x95, 0xA7, 0x92, 0x55, 0x42, 0x9D,
0x59, 0x76, 0xFC, 0xFA, 0x74, 0xAB, 0xFB, 0xFB, 0xBF, 0x2A, 0x37, 0x53, 0x72, 0x8E, 0x54, 0x6A,
0xD2, 0xD2, 0x17, 0xFE, 0x9B, 0x7E, 0x62, 0xAB, 0x8B, 0x48, 0x1A, 0xE7, 0x88, 0x2D, 0x9A, 0x17,
0xB9, 0xCC, 0x25, 0xD8, 0x0C, 0x91, 0xAF, 0xF9, 0x55, 0x73, 0x5F, 0xCF, 0x28, 0x6F, 0x21, 0x00,
0x0E, 0x74, 0xF9, 0xAE, 0x9E, 0xB3, 0xBE, 0xD8, 0xE8, 0xB4, 0x0C, 0xF7, 0xCB, 0x31, 0xD4, 0xAA,
0x00, 0x0D, 0x80, 0xC4, 0x8C, 0xE2, 0x83, 0xBA, 0xBB, 0x8A, 0x48, 0x88, 0x88, 0x3C, 0xAE, 0xB8,
0xCB, 0x31, 0xDB, 0xFE, 0xFB, 0x53, 0x6C, 0xDA, 0x11, 0x3C, 0xF1, 0x41, 0x33, 0xA0, 0x65, 0xB9,
0x94, 0x9D, 0x21, 0x94, 0xE5, 0x73, 0xED, 0xB7, 0xAA, 0x87, 0xBF, 0x9E, 0x4F, 0x2E, 0x51, 0x3B,
0xEA, 0x62, 0xC4, 0xB8, 0xEA, 0x1B, 0xFC, 0xDB, 0xF4, 0xA8, 0x0C, 0x73, 0x45, 0x68, 0x97, 0x25,
0x02, 0x34, 0x99, 0x2A, 0x71, 0xD3, 0x3F, 0xC3, 0xDB, 0xE6, 0x99, 0x77, 0x0E, 0x88, 0x22, 0xB7,
0x19, 0x6B, 0x8D, 0x8C, 0xBB, 0xF5, 0x39, 0xC0, 0xCE, 0x6B, 0x31, 0xE6, 0x15, 0x82, 0xDA, 0x18,
0x4C, 0xC1, 0xDE, 0x58, 0x56, 0x4C, 0x20, 0xCE, 0x9D, 0x44, 0x6D, 0xCF, 0x9E, 0x33, 0xFA, 0x52,
0x5A, 0x45, 0x0B, 0x4B, 0x24, 0x12, 0x10, 0xA7, 0xCB, 0x73, 0xEA, 0xE5, 0x90, 0x09, 0xC6, 0xDE,
0xE0, 0x54, 0xB2, 0x2C, 0x2D, 0x0A, 0x4A, 0xB2, 0x66, 0x48, 0xFD, 0x0C, 0xA5, 0x71, 0xA7, 0x00,
0x69, 0x24, 0xF5, 0xCE, 0xE0, 0x0F, 0xF8, 0xD0, 0x31, 0xDC, 0x33, 0x5F, 0xF9, 0x8C, 0xA1, 0xB4,
0x93, 0xE9, 0x27, 0x62, 0x3A, 0x8C, 0xD0, 0x60, 0xB0, 0xC8, 0x23, 0xBB, 0x56, 0x20, 0x15, 0xDC,
0x1F, 0x8E, 0x55, 0xEB, 0x88, 0x56, 0x19, 0xA6, 0x88, 0x38, 0x6D, 0x0D, 0xE9, 0x2B, 0xC9, 0x87,
0x71, 0x9E, 0x9D, 0x6A, 0x36, 0x5D, 0x2E, 0x71, 0x9C, 0x03, 0xB6, 0x6A, 0x70, 0xEB, 0x34, 0x25,
0x1C, 0xE1, 0x90, 0x7A, 0x5B, 0x19, 0xC8, 0xEC, 0x68, 0x82, 0x10, 0x37, 0x19, 0x18, 0xC8, 0xA9,
0x52, 0x32, 0x02, 0x30, 0x20, 0x83, 0xB1, 0x1D, 0x8D, 0x46, 0xDE, 0xA7, 0x07, 0x90, 0x34, 0xF5,
0x91, 0xA3, 0x57, 0x41, 0xC8, 0x1C, 0xFD, 0xEB, 0x31, 0xC0, 0xFA, 0xDA, 0x22, 0x71, 0xBE, 0xC4,
0xD3, 0x19, 0xC8, 0x00, 0x11, 0x5E, 0x67, 0x0D, 0x2F, 0x98, 0x07, 0x30, 0x32, 0x29, 0x0A, 0x9C,
0x81, 0x8A, 0x0C, 0xF2, 0x2F, 0xAA, 0x8A, 0x8A, 0x3C, 0x51, 0x96, 0x7C, 0x25, 0x65, 0x55, 0x91,
0xEE, 0xA0, 0x89, 0x08, 0x07, 0x53, 0x37, 0xF4, 0xAB, 0x62, 0xBE, 0x1D, 0xB4, 0x83, 0x05, 0xAE,
0xEF, 0xAE, 0x31, 0xFC, 0x18, 0x89, 0x17, 0xEE, 0x72, 0x4D, 0x47, 0x2E, 0x59, 0xBD, 0x42, 0xDC,
0xE4, 0x59, 0xDC, 0x2A, 0xA8, 0x24, 0x54, 0x31, 0x30, 0xD5, 0x83, 0x52, 0xCC, 0xC1, 0xD3, 0x6E,
0x54, 0x20, 0xD8, 0xF3, 0xA6, 0x93, 0xA2, 0x89, 0x70, 0xB9, 0xC8, 0xE9, 0x41, 0xC8, 0xBA, 0xB2,
0x3A, 0xD3, 0xCC, 0xB8, 0xD8, 0x9D, 0xA9, 0x81, 0x8B, 0x36, 0xD5, 0xBC, 0x9D, 0xB2, 0x48, 0x17,
0x49, 0xC9, 0xA3, 0xD7, 0x05, 0x40, 0x14, 0x0A, 0x92, 0x36, 0xCD, 0x13, 0x19, 0x23, 0x14, 0x37,
0xB1, 0x9D, 0xA0, 0xBB, 0xC8, 0xEF, 0x8A, 0xAE, 0x69, 0x36, 0xC7, 0x5A, 0xB7, 0xBC, 0x40, 0x62,
0xCD, 0x51, 0x49, 0xB6, 0x70, 0x69, 0xDB, 0x46, 0xB1, 0xA6, 0x6B, 0xC5, 0x35, 0x9F, 0xA6, 0x69,
0x34, 0xEA, 0xEB, 0x42, 0x8A, 0x4D, 0x41, 0xBF, 0xEE, 0x9E, 0x0E, 0x3E, 0x6A, 0x10, 0x98, 0xA9,
0x54, 0x1C, 0xD2, 0x89, 0x49, 0xF4, 0xEF, 0x42, 0x48, 0x35, 0x12, 0x40, 0xAB, 0xCB, 0x1E, 0x09,
0x73, 0xC4, 0x91, 0x8C, 0x05, 0x35, 0x2E, 0x3D, 0x25, 0xB7, 0x3F, 0x6F, 0xB5, 0x5A, 0xF0, 0xFF,
0x00, 0x0D, 0x2D, 0xB4, 0x5E, 0x6D, 0xFC, 0x0D, 0xE6, 0x0C, 0xEC, 0x0E, 0x46, 0xDF, 0x14, 0xD8,
0xE3, 0x6B, 0x50, 0xFC, 0x16, 0xD6, 0x5B, 0x3B, 0x35, 0x69, 0x63, 0x68, 0x96, 0x43, 0x9F, 0x30,
0xAE, 0xAC, 0x8F, 0xFF, 0x00, 0x53, 0x44, 0x5D, 0xDA, 0x35, 0xD6, 0xAD, 0x09, 0x2B, 0xA2, 0x9C,
0x92, 0x55, 0x54, 0x7C, 0xF2, 0x18, 0x1C, 0x85, 0x1F, 0x32, 0x5A, 0xC8, 0xFE, 0x4C, 0x31, 0x30,
0x50, 0x07, 0xD6, 0xDC, 0x8F, 0x5C, 0x63, 0xFA, 0x8A, 0xAA, 0xBB, 0x49, 0xCA, 0x30, 0x91, 0x15,
0xA3, 0x43, 0x92, 0xBB, 0xE9, 0x56, 0xF7, 0xFF, 0x00, 0x71, 0xFE, 0x54, 0xDE, 0x1A, 0x33, 0xD3,
0xCA, 0xB3, 0x33, 0x2B, 0xC6, 0x15, 0x7A, 0x1D, 0x23, 0x03, 0xF2, 0x1B, 0xD4, 0x51, 0xC8, 0x90,
0xC5, 0xBC, 0x5A, 0x54, 0x1C, 0xE4, 0x81, 0xCB, 0xE0, 0xED, 0x47, 0xDD, 0xB3, 0x26, 0xA0, 0x63,
0x0B, 0x9F, 0xE1, 0x23, 0x7C, 0x75, 0xCF, 0xB9, 0xDE, 0xAB, 0x40, 0x55, 0xC8, 0x9D, 0x04, 0x85,
0x77, 0xD0, 0xA4, 0x32, 0x0F, 0x92, 0x3E, 0x6B, 0x41, 0x49, 0x2C, 0xD2, 0x5C, 0xBA, 0xDC, 0xCE,
0x87, 0xCB, 0x24, 0x94, 0x19, 0xD8, 0x8A, 0x10, 0xB8, 0x8F, 0x5B, 0x11, 0xEB, 0x91, 0x83, 0x0C,
0xFD, 0xFF, 0x00, 0x3E, 0x62, 0x9D, 0x3C, 0xED, 0x71, 0x28, 0x5C, 0x92, 0xE3, 0x9E, 0x93, 0xB6,
0x3B, 0x0E, 0xD4, 0x0E, 0x5A, 0x69, 0x49, 0xC7, 0xA7, 0x90, 0x34, 0xC0, 0x9C, 0x4C, 0x11, 0x99,
0x95, 0x41, 0x0D, 0x1E, 0x86, 0x53, 0xC8, 0x9C, 0xE4, 0xFF, 0x00, 0x2F, 0xD2, 0xA3, 0x75, 0xF2,
0x8C, 0x6E, 0x06, 0xAD, 0xF7, 0x39, 0xD8, 0x8F, 0xE9, 0x49, 0x26, 0x72, 0x11, 0x88, 0x21, 0x18,
0xEE, 0xBB, 0xE7, 0x34, 0x44, 0x58, 0x7D, 0xB0, 0xA7, 0x19, 0x21, 0x24, 0x38, 0xC8, 0xF6, 0xAC,
0x01, 0x9B, 0xCA, 0x90, 0x15, 0xD0, 0xF1, 0xC8, 0xB9, 0x27, 0x7C, 0xE7, 0xED, 0xD2, 0x90, 0x11,
0x0C, 0x72, 0x00, 0x41, 0x67, 0x00, 0x1F, 0x61, 0xCF, 0xFA, 0x52, 0xB4, 0x9A, 0x25, 0x8C, 0xE0,
0x86, 0x56, 0xDC, 0x37, 0x3C, 0x76, 0xA8, 0xEE, 0x1F, 0x12, 0xCA, 0xB9, 0xC8, 0x2F, 0xCF, 0xBE,
0x39, 0x56, 0xD3, 0x1B, 0xD4, 0x02, 0x29, 0x85, 0x89, 0x62, 0x49, 0xE6, 0x73, 0x5E, 0x0F, 0xB1,
0xCF, 0x3C, 0x57, 0x80, 0xD4, 0x7B, 0x9A, 0xCC, 0x70, 0xCE, 0x79, 0x6C, 0x28, 0xA8, 0xE3, 0x2C,
0x72, 0x29, 0x61, 0x88, 0x6C, 0x08, 0xFC, 0xA8, 0xC0, 0x81, 0x46, 0x05, 0x27, 0xAD, 0x4C, 0x5C,
0x85, 0x03, 0x34, 0xF5, 0x52, 0x7A, 0x52, 0x69, 0x3D, 0xB6, 0xA9, 0x01, 0xC0, 0xCE, 0x29, 0xB4,
0x47, 0xFF, 0xD9, };

View File

@@ -0,0 +1,391 @@
// TFT_eSPI library demo, principally for STM32F processors with DMA:
// https://en.wikipedia.org/wiki/Direct_memory_access
// Tested with Nucleo 64 STM32F446RE and Nucleo 144 STM32F767ZI
// TFT's with SPI can use DMA, the sketch also works with 8 bit
// parallel TFT's (tested with ILI9341 and ILI9481)
// The sketch will run on processors without DMA and also parallel
// interface TFT's. Comment out line 25 for no DMA.
// Library here:
// https://github.com/Bodmer/TFT_eSPI
// Adapted by Bodmer 18/12/19 from "RotatingCube" by Daniel Eichhorn.
// See MIT License at end of sketch.
// The rotating cube is drawn into a 128 x 128 Sprite and then this is
// rendered to screen. The Sprite need 32Kbytes of RAM and DMA buffer the same
// so processors with at least >64Kbytes RAM free will be required.
// Define to use DMA for Sprite transfer to SPI TFT, comment out to use no DMA
// (Tested with Nucleo 64 STM32F446RE and Nucleo 144 STM32F767ZI)
// STM32F767 27MHz SPI 50% processor load: Non DMA 52 fps, with DMA 101 fps
// STM32F767 27MHz SPI 0% processor load: Non DMA 97 fps, with DMA 102 fps
// NOTE: FOR SPI DISPLAYS ONLY
#define USE_DMA_TO_TFT
// Show a processing load does not impact rendering performance
// Processing load is simple algorithm to calculate prime numbers
//#define PRIME_NUMBER_PROCESSOR_LOAD 491 // 241 = 50% CPU load for 128 * 128 and STM32F466 Nucleo 64
// 491 = 50% CPU load for 128 * 128 and STM32F767 Nucleo 144
// Color depth has to be 16 bits if DMA is used to render image
#define COLOR_DEPTH 16
// 128x128 for a 16 bit colour Sprite (32Kbytes RAM)
// Maximum is 181x181 (64Kbytes) for DMA - restricted by processor design
#define IWIDTH 128
#define IHEIGHT 128
// Size of cube image
// 358 is max for 128x128 sprite, too big and pixel trails are drawn...
#define CUBE_SIZE 358
#include <TFT_eSPI.h>
// Library instance
TFT_eSPI tft = TFT_eSPI(); // Declare object "tft"
// Create two sprites for a DMA toggle buffer
TFT_eSprite spr[2] = {TFT_eSprite(&tft), TFT_eSprite(&tft) };
// Toggle buffer selection
bool sprSel = 0;
// Pointers to start of Sprties in RAM
uint16_t* sprPtr[2];
// Define the cube face colors
uint16_t palette[] = {TFT_WHITE, // 1
TFT_GREENYELLOW, // 2
TFT_YELLOW, // 3
TFT_PINK, // 4
TFT_MAGENTA, // 5
TFT_CYAN // 6
};
// Used for fps measuring
uint16_t counter = 0;
long startMillis = millis();
uint16_t interval = 100;
// size / 2 of cube edge
float d = 15;
float px[] = {
-d, d, d, -d, -d, d, d, -d
};
float py[] = {
-d, -d, d, d, -d, -d, d, d
};
float pz[] = {
-d, -d, -d, -d, d, d, d, d
};
// Define the triangles
// The order of the vertices MUST be CCW or the
// shoelace method won't work to detect visible edges
int faces[12][3] = {
{0, 1, 4},
{1, 5, 4},
{1, 2, 5},
{2, 6, 5},
{5, 7, 4},
{6, 7, 5},
{3, 4, 7},
{4, 3, 0},
{0, 3, 1},
{1, 3, 2},
{2, 3, 6},
{6, 3, 7}
};
// mapped coordinates on screen
float p2x[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
float p2y[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
// rotation angle in radians
float r[] = {
0, 0, 0
};
// Frames per second
String fps = "0fps";
// Sprite draw position
int16_t xpos = 0;
int16_t ypos = 0;
// Prime number initial value
int prime_max = 2;
// 3 axis spin control
bool spinX = true;
bool spinY = true;
bool spinZ = true;
// Min and max of cube edges, "int" type used for compatibility with original sketch min() function
int xmin,ymin,xmax,ymax;
/////////////////////////////////////////////////////////// setup ///////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
tft.init();
tft.fillScreen(TFT_BLACK);
xpos = 0;
ypos = (tft.height() - IHEIGHT) / 2;
// Define cprite colour depth
spr[0].setColorDepth(COLOR_DEPTH);
spr[1].setColorDepth(COLOR_DEPTH);
// Create the 2 sprites
sprPtr[0] = (uint16_t*)spr[0].createSprite(IWIDTH, IHEIGHT);
sprPtr[1] = (uint16_t*)spr[1].createSprite(IWIDTH, IHEIGHT);
// Define text datum and text colour for Sprites
spr[0].setTextColor(TFT_BLACK);
spr[0].setTextDatum(MC_DATUM);
spr[1].setTextColor(TFT_BLACK);
spr[1].setTextDatum(MC_DATUM);
#ifdef USE_DMA_TO_TFT
// DMA - should work with STM32F2xx/F4xx/F7xx processors
// NOTE: >>>>>> DMA IS FOR SPI DISPLAYS ONLY <<<<<<
tft.initDMA(); // Initialise the DMA engine (tested with STM32F446 and STM32F767)
#endif
// Animation control timer
startMillis = millis();
}
/////////////////////////////////////////////////////////// loop ///////////////////////////////////////////////////
void loop() {
uint32_t updateTime = 0; // time for next update
bool bounce = false;
int wait = 0; //random (20);
// Random movement direction
int dx = 1; if (random(2)) dx = -1;
int dy = 1; if (random(2)) dy = -1;
// Grab exclusive use of the SPI bus
tft.startWrite();
// Loop forever
while (1) {
// Pull it back onto screen if it wanders off
if (xpos < -xmin) {
dx = 1;
bounce = true;
}
if (xpos >= tft.width() - xmax) {
dx = -1;
bounce = true;
}
if (ypos < -ymin) {
dy = 1;
bounce = true;
}
if (ypos >= tft.height() - ymax) {
dy = -1;
bounce = true;
}
if (bounce) {
// Randomise spin
if (random(2)) spinX = true;
else spinX = false;
if (random(2)) spinY = true;
else spinY = false;
if (random(2)) spinZ = true;
else spinZ = false;
bounce = false;
//wait = random (20);
}
if (updateTime <= millis())
{
// Use time delay so sprtie does not move fast when not all on screen
updateTime = millis() + wait;
xmin = IWIDTH / 2; xmax = IWIDTH / 2; ymin = IHEIGHT / 2; ymax = IHEIGHT / 2;
drawCube();
#ifdef USE_DMA_TO_TFT
if (tft.dmaBusy()) prime_max++; // Increase processing load until just not busy
tft.pushImageDMA(xpos, ypos, IWIDTH, IHEIGHT, sprPtr[sprSel]);
sprSel = !sprSel;
#else
#ifdef PRIME_NUMBER_PROCESSOR_LOAD
prime_max = PRIME_NUMBER_PROCESSOR_LOAD;
#endif
spr[sprSel].pushSprite(xpos, ypos); // Blocking write (no DMA) 115fps
#endif
counter++;
// only calculate the fps every <interval> iterations.
if (counter % interval == 0) {
long millisSinceUpdate = millis() - startMillis;
fps = String((int)(interval * 1000.0 / (millisSinceUpdate))) + " fps";
Serial.println(fps);
startMillis = millis();
}
#ifdef PRIME_NUMBER_PROCESSOR_LOAD
// Add a processor task
uint32_t pr = computePrimeNumbers(prime_max);
Serial.print("Biggest = "); Serial.println(pr);
#endif
// Change coord for next loop
xpos += dx;
ypos += dy;
}
} // End of forever loop
// Release exclusive use of SPI bus ( here as a reminder... forever loop prevents execution)
tft.endWrite();
}
/**
Detected visible triangles. If calculated area > 0 the triangle
is rendered facing towards the viewer, since the vertices are CCW.
If the area is negative the triangle is CW and thus facing away from us.
*/
int shoelace(int x1, int y1, int x2, int y2, int x3, int y3) {
// (x1y2 - y1x2) + (x2y3 - y2x3)
return x1 * y2 - y1 * x2 + x2 * y3 - y2 * x3 + x3 * y1 - y3 * x1;
}
/**
Rotates and renders the cube.
**/
void drawCube()
{
double speed = 90;
if (spinX) r[0] = r[0] + PI / speed; // Add a degree
if (spinY) r[1] = r[1] + PI / speed; // Add a degree
if (spinZ) r[2] = r[2] + PI / speed; // Add a degree
if (r[0] >= 360.0 * PI / 90.0) r[0] = 0;
if (r[1] >= 360.0 * PI / 90.0) r[1] = 0;
if (r[2] >= 360.0 * PI / 90.0) r[2] = 0;
float ax[8] = {0, 0, 0, 0, 0, 0, 0, 0};
float ay[8] = {0, 0, 0, 0, 0, 0, 0, 0};
float az[8] = {0, 0, 0, 0, 0, 0, 0, 0};
// Calculate all vertices of the cube
for (int i = 0; i < 8; i++)
{
float px2 = px[i];
float py2 = cos(r[0]) * py[i] - sin(r[0]) * pz[i];
float pz2 = sin(r[0]) * py[i] + cos(r[0]) * pz[i];
float px3 = cos(r[1]) * px2 + sin(r[1]) * pz2;
float py3 = py2;
float pz3 = -sin(r[1]) * px2 + cos(r[1]) * pz2;
ax[i] = cos(r[2]) * px3 - sin(r[2]) * py3;
ay[i] = sin(r[2]) * px3 + cos(r[2]) * py3;
az[i] = pz3 - 150;
p2x[i] = IWIDTH / 2 + ax[i] * CUBE_SIZE / az[i];
p2y[i] = IHEIGHT / 2 + ay[i] * CUBE_SIZE / az[i];
}
// Fill the buffer with color 0 (Black)
spr[sprSel].fillSprite(TFT_BLACK);
for (int i = 0; i < 12; i++) {
if (shoelace(p2x[faces[i][0]], p2y[faces[i][0]], p2x[faces[i][1]], p2y[faces[i][1]], p2x[faces[i][2]], p2y[faces[i][2]]) > 0) {
int x0 = p2x[faces[i][0]];
int y0 = p2y[faces[i][0]];
int x1 = p2x[faces[i][1]];
int y1 = p2y[faces[i][1]];
int x2 = p2x[faces[i][2]];
int y2 = p2y[faces[i][2]];
xmin = min(xmin, x0);
ymin = min(ymin, y0);
xmin = min(xmin, x1);
ymin = min(ymin, y1);
xmin = min(xmin, x2);
ymin = min(ymin, y2);
xmax = max(xmax, x0);
ymax = max(ymax, y0);
xmax = max(xmax, x1);
ymax = max(ymax, y1);
xmax = max(xmax, x2);
ymax = max(ymax, y2);
spr[sprSel].fillTriangle(x0, y0, x1, y1, x2, y2, palette[i / 2]);
if (i % 2) {
int avX = 0;
int avY = 0;
for (int v = 0; v < 3; v++) {
avX += p2x[faces[i][v]];
avY += p2y[faces[i][v]];
}
avX = avX / 3;
avY = avY / 3;
}
}
}
//spr[sprSel].drawString(fps, IWIDTH / 2, IHEIGHT / 2, 4);
//delay(100);
}
// This is to provide a processing load to see the improvement DMA gives
uint32_t computePrimeNumbers(int32_t n) {
if (n<2) return 1;
int32_t i, fact, j, p;
//Serial.print("\nPrime Numbers are: \n");
for (i = 1; i <= n; i++)
{
fact = 0;
for (j = 1; j <= n; j++)
{
if (i % j == 0)
fact++;
}
if (fact == 2) {
p = i;//Serial.print(i); Serial.print(", ");
}
}
//Serial.println();
return p; // Biggest
}
/*
Original licence:
The MIT License (MIT)
Copyright (c) 2017 by Daniel Eichhorn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

View File

@@ -0,0 +1,185 @@
// 'Boing' ball demo
// ESP32 110 fps (no DMA)
// STM32F767 55MHz SPI 170 fps without DMA
// STM32F767 55MHz SPI 227 fps with DMA
// STM32F446 55MHz SPI 110 fps without DMA
// STM32F446 55MHz SPI 187 fps with DMA
// STM32F401 55MHz SPI 56 fps without DMA
// STM32F401 55MHz SPI 120 fps with DMA
// STM32F767 27MHz SPI 99 fps without DMA
// STM32F767 27MHz SPI 120 fps with DMA
// STM32F446 27MHz SPI 73 fps without DMA
// STM32F446 27MHz SPI 97 fps with DMA
// STM32F401 27MHz SPI 51 fps without DMA
// STM32F401 27MHz SPI 90 fps with DMA
// Blue Pill - 36MHz SPI *no* DMA 36 fps
// Blue Pill - 36MHz SPI with DMA 67 fps
// Blue Pill overclocked to 128MHz *no* DMA - 32MHz SPI 64 fps
// Blue Pill overclocked to 128MHz with DMA - 32MHz SPI 116 fps
#define SCREENWIDTH 320
#define SCREENHEIGHT 240
#include "graphic.h"
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
#define BGCOLOR 0xAD75
#define GRIDCOLOR 0xA815
#define BGSHADOW 0x5285
#define GRIDSHADOW 0x600C
#define RED 0xF800
#define WHITE 0xFFFF
#define YBOTTOM 123 // Ball Y coord at bottom
#define YBOUNCE -3.5 // Upward velocity on ball bounce
// Ball coordinates are stored floating-point because screen refresh
// is so quick, whole-pixel movements are just too fast!
float ballx = 20.0, bally = YBOTTOM, // Current ball position
ballvx = 0.8, ballvy = YBOUNCE, // Ball velocity
ballframe = 3; // Ball animation frame #
int balloldx = ballx, balloldy = bally; // Prior ball position
// Working buffer for ball rendering...2 scanlines that alternate,
// one is rendered while the other is transferred via DMA.
uint16_t renderbuf[2][SCREENWIDTH];
uint16_t palette[16]; // Color table for ball rotation effect
uint32_t startTime, frame = 0; // For frames-per-second estimate
void setup() {
Serial.begin(115200);
// while(!Serial);
// Turn on backlight (required on PyPortal)
tft.begin();
tft.setRotation(3); // Landscape orientation, USB at bottom right
tft.setSwapBytes(false);
// Draw initial framebuffer contents:
//tft.setBitmapColor(GRIDCOLOR, BGCOLOR);
tft.fillScreen(BGCOLOR);
tft.initDMA();
delay(2000);
tft.drawBitmap(0, 0, (const uint8_t *)background, SCREENWIDTH, SCREENHEIGHT, GRIDCOLOR);
startTime = millis();
}
void loop() {
balloldx = (int16_t)ballx; // Save prior position
balloldy = (int16_t)bally;
ballx += ballvx; // Update position
bally += ballvy;
ballvy += 0.06; // Update Y velocity
if((ballx <= 15) || (ballx >= SCREENWIDTH - BALLWIDTH))
ballvx *= -1; // Left/right bounce
if(bally >= YBOTTOM) { // Hit ground?
bally = YBOTTOM; // Clip and
ballvy = YBOUNCE; // bounce up
}
// Determine screen area to update. This is the bounds of the ball's
// prior and current positions, so the old ball is fully erased and new
// ball is fully drawn.
int16_t minx, miny, maxx, maxy, width, height;
// Determine bounds of prior and new positions
minx = ballx;
if(balloldx < minx) minx = balloldx;
miny = bally;
if(balloldy < miny) miny = balloldy;
maxx = ballx + BALLWIDTH - 1;
if((balloldx + BALLWIDTH - 1) > maxx) maxx = balloldx + BALLWIDTH - 1;
maxy = bally + BALLHEIGHT - 1;
if((balloldy + BALLHEIGHT - 1) > maxy) maxy = balloldy + BALLHEIGHT - 1;
width = maxx - minx + 1;
height = maxy - miny + 1;
// Ball animation frame # is incremented opposite the ball's X velocity
ballframe -= ballvx * 0.5;
if(ballframe < 0) ballframe += 14; // Constrain from 0 to 13
else if(ballframe >= 14) ballframe -= 14;
// Set 7 palette entries to white, 7 to red, based on frame number.
// This makes the ball spin
for(uint8_t i=0; i<14; i++) {
palette[i+2] = ((((int)ballframe + i) % 14) < 7) ? WHITE : RED;
// Palette entries 0 and 1 aren't used (clear and shadow, respectively)
}
// Only the changed rectangle is drawn into the 'renderbuf' array...
uint16_t c, *destPtr;
int16_t bx = minx - (int)ballx, // X relative to ball bitmap (can be negative)
by = miny - (int)bally, // Y relative to ball bitmap (can be negative)
bgx = minx, // X relative to background bitmap (>= 0)
bgy = miny, // Y relative to background bitmap (>= 0)
x, y, bx1, bgx1; // Loop counters and working vars
uint8_t p; // 'packed' value of 2 ball pixels
int8_t bufIdx = 0;
// Start SPI transaction and drop TFT_CS - avoids transaction overhead in loop
tft.startWrite();
// Set window area to pour pixels into
tft.setAddrWindow(minx, miny, width, height);
// Draw line by line loop
for(y=0; y<height; y++) { // For each row...
destPtr = &renderbuf[bufIdx][0];
bx1 = bx; // Need to keep the original bx and bgx values,
bgx1 = bgx; // so copies of them are made here (and changed in loop below)
for(x=0; x<width; x++) {
if((bx1 >= 0) && (bx1 < BALLWIDTH) && // Is current pixel row/column
(by >= 0) && (by < BALLHEIGHT)) { // inside the ball bitmap area?
// Yes, do ball compositing math...
p = ball[by][bx1 / 2]; // Get packed value (2 pixels)
c = (bx1 & 1) ? (p & 0xF) : (p >> 4); // Unpack high or low nybble
if(c == 0) { // Outside ball - just draw grid
c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDCOLOR : BGCOLOR;
} else if(c > 1) { // In ball area...
c = palette[c];
} else { // In shadow area...
c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDSHADOW : BGSHADOW;
}
} else { // Outside ball bitmap, just draw background bitmap...
c = background[bgy][bgx1 / 8] & (0x80 >> (bgx1 & 7)) ? GRIDCOLOR : BGCOLOR;
}
*destPtr++ = c<<8 | c>>8; // Store pixel color
bx1++; // Increment bitmap position counters (X axis)
bgx1++;
}
tft.pushPixelsDMA(&renderbuf[bufIdx][0], width); // Push line to screen
// Push line to screen (swap bytes false for STM/ESP32)
//tft.pushPixels(&renderbuf[bufIdx][0], width);
bufIdx = 1 - bufIdx;
by++; // Increment bitmap position counters (Y axis)
bgy++;
}
//if (random(100) == 1) delay(2000);
tft.endWrite();
//delay(5);
// Show approximate frame rate
if(!(++frame & 255)) { // Every 256 frames...
uint32_t elapsed = (millis() - startTime) / 1000; // Seconds
if(elapsed) {
Serial.print(frame / elapsed);
Serial.println(" fps");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
{
"name": "TFT_eSPI",
"version": "1.4.30",
"keywords": "tft, ePaper, display, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140",
"description": "A TFT and ePaper SPI graphics library for ESP8266 and ESP32",
"version": "1.5.0",
"keywords": "Arduino", "tft, ePaper, display, STM32, ESP8266, NodeMCU, ESP32, M5Stack, ILI9341, ST7735, ILI9163, S6D02A1, ILI9486, ST7789, RM68140",
"description": "A TFT and ePaper SPI graphics library with optimisation for ESP8266, ESP32 and STM32",
"repository":
{
"type": "git",
@@ -17,5 +17,5 @@
}
],
"frameworks": "arduino",
"platforms": "espressif8266, espressif32"
"platforms": "espressif8266, espressif32, stm32"
}

View File

@@ -1,11 +1,11 @@
name=TFT_eSPI
version=1.4.30
version=1.5.0
author=Bodmer
maintainer=Bodmer
sentence=A fast TFT graphics library for ESP8266 and ESP32 processors for the Arduino IDE
sentence=TFT graphics library for Arduino processors with performance optimisation for STM32, ESP8266 and ESP32
paragraph=Supports TFT displays using drivers (ILI9341 etc) that operate with hardware SPI or 8 bit parallel.
category=Display
url=https://github.com/Bodmer/TFT_eSPI
architectures=esp8266,esp32
architectures=*
includes=TFT_eSPI.h

View File

@@ -94,6 +94,10 @@ graphics.
In 2018 anti-aliased fonts were added along with a Processing font conversion
sketch.
In 2019 the library was adapted to be able to use it with any 32 bit Arduino
compatible processor. It will run on 8 bit and 16 bit processors but will be
slow due to extensive use of 32 bit varaibles.
Many of the example sketches are original work, that contain code created
for my own projects. For all the original code the FreeBSD licence applies
and is compatible with the GNU GPL.