diff --git a/PDQ_MinLib/PDQ_FastPin.h b/PDQ_MinLib/PDQ_FastPin.h new file mode 100644 index 0000000..d96af0f --- /dev/null +++ b/PDQ_MinLib/PDQ_FastPin.h @@ -0,0 +1,489 @@ +// +// This excellent template library is from FastLED http://fastled.io +// +// I was considering writing something similar, but FastPin seemed perfect. +// +// Thanks FastLED people! Here is the license from FastLED followed by the +// header +// + +/* + +The MIT License (MIT) + +Copyright (c) 2013 FastLED + +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. + +*/ + +#ifndef __INC_FASTPIN_H +#define __INC_FASTPIN_H + +#include + +// Arduino.h needed for convinience functions digitalPinToPort/BitMask/portOutputRegister and the pinMode methods. +#include + +#define NO_PIN 255 + +// Class to ensure that a minimum amount of time has kicked since the last time run - and delay if not enough time has passed yet +// this should make sure that chipsets that have +template class CMinWait { + long mLastMicros; +public: + CMinWait() { mLastMicros = 0; } + + void wait() { + long diff = micros() - mLastMicros; + while(diff < WAIT) { + diff = micros() - mLastMicros; + } + } + + void mark() { mLastMicros = micros(); } +}; + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Pin access class - needs to tune for various platforms (naive fallback solution?) +// +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define _CYCLES(_PIN) (((_PIN >= 62 ) || (_PIN>=42 && _PIN<=49) || (_PIN>=14 && _PIN <=17) || (_PIN>=6 && _PIN <=9)) ? 2 : 1) +#else +#define _CYCLES(_PIN) ((_PIN >= 24) ? 2 : 1) +#endif + +class Selectable { +public: + virtual void select() = 0; + virtual void release() = 0; + virtual bool isSelected() = 0; +}; + +class Pin : public Selectable { + uint8_t mPinMask; + uint8_t mPin; + volatile uint8_t *mPort; + + void _init() { + mPinMask = digitalPinToBitMask(mPin); + mPort = portOutputRegister(digitalPinToPort(mPin)); + } +public: + Pin(int pin) : mPin(pin) { _init(); } + + typedef volatile uint8_t * port_ptr_t; + typedef uint8_t port_t; + + inline void setOutput() { pinMode(mPin, OUTPUT); } + inline void setInput() { pinMode(mPin, INPUT); } + + inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; } + inline void lo() __attribute__ ((always_inline)) { *mPort &= ~mPinMask; } + + inline void strobe() __attribute__ ((always_inline)) { hi(); lo(); } + + inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; } + inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; } + inline void set(register port_t val) __attribute__ ((always_inline)) { *mPort = val; } + + inline void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + port_t hival() __attribute__ ((always_inline)) { return *mPort | mPinMask; } + port_t loval() __attribute__ ((always_inline)) { return *mPort & ~mPinMask; } + port_ptr_t port() __attribute__ ((always_inline)) { return mPort; } + port_t mask() __attribute__ ((always_inline)) { return mPinMask; } + + virtual void select() { hi(); } + virtual void release() { lo(); } + virtual bool isSelected() { return (*mPort & mPinMask) == mPinMask; } +}; + +class OutputPin : public Pin { +public: + OutputPin(int pin) : Pin(pin) { setOutput(); } +}; + +class InputPin : public Pin { +public: + InputPin(int pin) : Pin(pin) { setInput(); } +}; + +/// The simplest level of Pin class. This relies on runtime functions durinig initialization to get the port/pin mask for the pin. Most +/// of the accesses involve references to these static globals that get set up. This won't be the fastest set of pin operations, but it +/// will provide pin level access on pretty much all arduino environments. In addition, it includes some methods to help optimize access in +/// various ways. Namely, the versions of hi, lo, and fastset that take the port register as a passed in register variable (saving a global +/// dereference), since these functions are aggressively inlined, that can help collapse out a lot of extraneous memory loads/dereferences. +/// +/// In addition, if, while writing a bunch of data to a pin, you know no other pins will be getting written to, you can get/cache a value of +/// the pin's port register and use that to do a full set to the register. This results in one being able to simply do a store to the register, +/// vs. the load, and/or, and store that would be done normally. +/// +/// There are platform specific instantiations of this class that provide direct i/o register access to pins for much higher speed pin twiddling. +/// +/// Note that these classes are all static functions. So the proper usage is Pin<13>::hi(); or such. Instantiating objects is not recommended, +/// as passing Pin objects around will likely -not- have the effect you're expecting. +template class FastPin { + static uint8_t sPinMask; + static volatile uint8_t *sPort; + static void _init() { + sPinMask = digitalPinToBitMask(PIN); + sPort = portOutputRegister(digitalPinToPort(PIN)); + } +public: + typedef volatile uint8_t * port_ptr_t; + typedef uint8_t port_t; + + inline static void setOutput() { _init(); pinMode(PIN, OUTPUT); } + inline static void setInput() { _init(); pinMode(PIN, INPUT); } + + inline static void hi() __attribute__ ((always_inline)) { *sPort |= sPinMask; } + inline static void lo() __attribute__ ((always_inline)) { *sPort &= ~sPinMask; } + + inline static void strobe() __attribute__ ((always_inline)) { hi(); lo(); } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= sPinMask; } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~sPinMask; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { *sPort = val; } + + inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + static port_t hival() __attribute__ ((always_inline)) { return *sPort | sPinMask; } + static port_t loval() __attribute__ ((always_inline)) { return *sPort & ~sPinMask; } + static port_ptr_t port() __attribute__ ((always_inline)) { return sPort; } + static port_t mask() __attribute__ ((always_inline)) { return sPinMask; } +}; + +template uint8_t FastPin::sPinMask; +template volatile uint8_t *FastPin::sPort; + +/// Class definition for a Pin where we know the port registers at compile time for said pin. This allows us to make +/// a lot of optimizations, as the inlined hi/lo methods will devolve to a single io register write/bitset. +template class _AVRPIN { +public: + typedef volatile uint8_t * port_ptr_t; + typedef uint8_t port_t; + + inline static void setOutput() { _DDR::r() |= _MASK; } + inline static void setInput() { _DDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { _PORT::r() |= _MASK; } + inline static void lo() __attribute__ ((always_inline)) { _PORT::r() &= ~_MASK; } + inline static void set(register uint8_t val) __attribute__ ((always_inline)) { _PORT::r() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { hi(); lo(); } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } + inline static void fastset(register port_ptr_t port, register uint8_t val) __attribute__ ((always_inline)) { set(val); } + + inline static port_t hival() __attribute__ ((always_inline)) { return _PORT::r() | _MASK; } + inline static port_t loval() __attribute__ ((always_inline)) { return _PORT::r() & ~_MASK; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PORT::r(); } + inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } +}; + +/// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this +/// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found +/// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. +template class _ARMPIN { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } + inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } + inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { _PTOR::r() = _MASK; } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } + inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } + inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } + inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } +}; + +/// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC +/// does a poor job of optimizing around these accesses so they are not being used just yet. +template class _ARMPIN_BITBAND { +public: + typedef volatile uint32_t * port_ptr_t; + typedef uint32_t port_t; + + inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } + inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } + + inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } + inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } + inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } + + inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } + + inline static void toggle() __attribute__ ((always_inline)) { *_PTOR::template rx<_BIT>() = 1; } + + inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port = 1; } + inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port = 0; } + inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } + + inline static port_t hival() __attribute__ ((always_inline)) { return 1; } + inline static port_t loval() __attribute__ ((always_inline)) { return 0; } + inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } + inline static port_t mask() __attribute__ ((always_inline)) { return 1; } +}; + +/// AVR definitions for pins. Getting around the fact that I can't pass GPIO register addresses in as template arguments by instead creating +/// a custom type for each GPIO register with a single, static, aggressively inlined function that returns that specific GPIO register. A similar +/// trick is used a bit further below for the ARM GPIO registers (of which there are far more than on AVR!) +typedef volatile uint8_t & reg8_t; +#define _R(T) struct __gen_struct_ ## T +#define _RD8(T) struct __gen_struct_ ## T { static inline reg8_t r() { return T; }}; +#define _IO(L) _RD8(DDR ## L); _RD8(PORT ## L); _RD8(PIN ## L); +#define _DEFPIN_AVR(PIN, MASK, L) template<> class FastPin : public _AVRPIN {}; + +// ARM definitions +#define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) +#define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) + +typedef volatile uint32_t & reg32_t; +typedef volatile uint32_t * ptr_reg32_t; + +#define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } \ + template static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } }; +#define _IO32(L) _RD32(GPIO ## L ## _PDOR); _RD32(GPIO ## L ## _PSOR); _RD32(GPIO ## L ## _PCOR); _RD32(GPIO ## L ## _PTOR); _RD32(GPIO ## L ## _PDIR); _RD32(GPIO ## L ## _PDDR); + +#define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin : public _ARMPIN {}; + +// Don't use bit band'd pins for now, the compiler generates far less efficient code around them +// #define _DEFPIN_ARM(PIN, BIT, L) template<> class Pin : public _ARMPIN_BITBAND {}; + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Pin definitions for AVR and ARM. If there are pin definitions supplied below for the platform being +// built on, then much higher speed access will be possible, namely with direct GPIO register accesses. +// +/////////////////////////////////////////////////////////////////////////////////////////////////////////// +#if defined(FORCE_SOFTWARE_PINS) +#warning "Softwrae pin support forced pin access will be slightly slower. See fastpin.h for info." +#define NO_HARDWARE_PIN_SUPPORT + +#elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) +_IO(B); + +_DEFPIN_AVR(0, 0x01, B); _DEFPIN_AVR(1, 0x02, B); _DEFPIN_AVR(2, 0x04, B); _DEFPIN_AVR(3, 0x08, B); +_DEFPIN_AVR(4, 0x10, B); _DEFPIN_AVR(5, 0x20, B); + +#elif(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) +_IO(A); _IO(B); + +_DEFPIN_AVR(0, 0x01, A); _DEFPIN_AVR(1, 0x02, A); _DEFPIN_AVR(2, 0x04, A); _DEFPIN_AVR(3, 0x08, A); +_DEFPIN_AVR(4, 0x10, A); _DEFPIN_AVR(5, 0x20, A); _DEFPIN_AVR(6, 0x40, A); _DEFPIN_AVR(7, 0x80, A); +_DEFPIN_AVR(8, 0x04, B); _DEFPIN_AVR(9, 0x02, B); _DEFPIN_AVR(10, 0x01, B); + +#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) +// Accelerated port definitions for arduino avrs +_IO(D); _IO(B); _IO(C); +_DEFPIN_AVR( 0, 0x01, D); _DEFPIN_AVR( 1, 0x02, D); _DEFPIN_AVR( 2, 0x04, D); _DEFPIN_AVR( 3, 0x08, D); +_DEFPIN_AVR( 4, 0x10, D); _DEFPIN_AVR( 5, 0x20, D); _DEFPIN_AVR( 6, 0x40, D); _DEFPIN_AVR( 7, 0x80, D); +_DEFPIN_AVR( 8, 0x01, B); _DEFPIN_AVR( 9, 0x02, B); _DEFPIN_AVR(10, 0x04, B); _DEFPIN_AVR(11, 0x08, B); +_DEFPIN_AVR(12, 0x10, B); _DEFPIN_AVR(13, 0x20, B); _DEFPIN_AVR(14, 0x01, C); _DEFPIN_AVR(15, 0x02, C); +_DEFPIN_AVR(16, 0x04, C); _DEFPIN_AVR(17, 0x08, C); _DEFPIN_AVR(18, 0x10, C); _DEFPIN_AVR(19, 0x20, C); + +#define SPI_DATA 11 +#define SPI_CLOCK 13 +#define SPI_SELECT 10 +#define AVR_HARDWARE_SPI + +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +// megas + +_IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); _IO(G); _IO(H); _IO(J); _IO(K); _IO(L); + +_DEFPIN_AVR(0, 1, E); _DEFPIN_AVR(1, 2, E); _DEFPIN_AVR(2, 16, E); _DEFPIN_AVR(3, 32, E); +_DEFPIN_AVR(4, 32, G); _DEFPIN_AVR(5, 8, E); _DEFPIN_AVR(6, 8, H); _DEFPIN_AVR(7, 16, H); +_DEFPIN_AVR(8, 32, H); _DEFPIN_AVR(9, 64, H); _DEFPIN_AVR(10, 16, B); _DEFPIN_AVR(11, 32, B); +_DEFPIN_AVR(12, 64, B); _DEFPIN_AVR(13, 128, B); _DEFPIN_AVR(14, 2, J); _DEFPIN_AVR(15, 1, J); +_DEFPIN_AVR(16, 2, H); _DEFPIN_AVR(17, 1, H); _DEFPIN_AVR(18, 8, D); _DEFPIN_AVR(19, 4, D); +_DEFPIN_AVR(20, 2, D); _DEFPIN_AVR(21, 1, D); _DEFPIN_AVR(22, 1, A); _DEFPIN_AVR(23, 2, A); +_DEFPIN_AVR(24, 4, A); _DEFPIN_AVR(25, 8, A); _DEFPIN_AVR(26, 16, A); _DEFPIN_AVR(27, 32, A); +_DEFPIN_AVR(28, 64, A); _DEFPIN_AVR(29, 128, A); _DEFPIN_AVR(30, 128, C); _DEFPIN_AVR(31, 64, C); +_DEFPIN_AVR(32, 32, C); _DEFPIN_AVR(33, 16, C); _DEFPIN_AVR(34, 8, C); _DEFPIN_AVR(35, 4, C); +_DEFPIN_AVR(36, 2, C); _DEFPIN_AVR(37, 1, C); _DEFPIN_AVR(38, 128, D); _DEFPIN_AVR(39, 4, G); +_DEFPIN_AVR(40, 2, G); _DEFPIN_AVR(41, 1, G); _DEFPIN_AVR(42, 128, L); _DEFPIN_AVR(43, 64, L); +_DEFPIN_AVR(44, 32, L); _DEFPIN_AVR(45, 16, L); _DEFPIN_AVR(46, 8, L); _DEFPIN_AVR(47, 4, L); +_DEFPIN_AVR(48, 2, L); _DEFPIN_AVR(49, 1, L); _DEFPIN_AVR(50, 8, B); _DEFPIN_AVR(51, 4, B); +_DEFPIN_AVR(52, 2, B); _DEFPIN_AVR(53, 1, B); _DEFPIN_AVR(54, 1, F); _DEFPIN_AVR(55, 2, F); +_DEFPIN_AVR(56, 4, F); _DEFPIN_AVR(57, 8, F); _DEFPIN_AVR(58, 16, F); _DEFPIN_AVR(59, 32, F); +_DEFPIN_AVR(60, 64, F); _DEFPIN_AVR(61, 128, F); _DEFPIN_AVR(62, 1, K); _DEFPIN_AVR(63, 2, K); +_DEFPIN_AVR(64, 4, K); _DEFPIN_AVR(65, 8, K); _DEFPIN_AVR(66, 16, K); _DEFPIN_AVR(67, 32, K); +_DEFPIN_AVR(68, 64, K); _DEFPIN_AVR(69, 128, K); + +#define SPI_DATA 51 +#define SPI_CLOCK 52 +#define SPI_SELECT 53 +#define AVR_HARDWARE_SPI + +#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) +// Xark: Add ATMega644,644P,1284 and 1284P (using pinout from http://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/) + +_IO(A); _IO(B); _IO(C); _IO(D); + +_DEFPIN_AVR( 0, (1<<0), B); _DEFPIN_AVR( 1, (1<<1), B); _DEFPIN_AVR( 2, (1<<2), B); _DEFPIN_AVR( 3, (1<<3), B); +_DEFPIN_AVR( 4, (1<<4), B); _DEFPIN_AVR( 5, (1<<5), B); _DEFPIN_AVR( 6, (1<<6), B); _DEFPIN_AVR( 7, (1<<7), B); + +_DEFPIN_AVR( 8, (1<<0), D); _DEFPIN_AVR( 9, (1<<1), D); _DEFPIN_AVR(10, (1<<2), D); _DEFPIN_AVR(11, (1<<3), D); +_DEFPIN_AVR(12, (1<<4), D); _DEFPIN_AVR(13, (1<<5), D); _DEFPIN_AVR(14, (1<<6), D); _DEFPIN_AVR(15, (1<<7), D); + +_DEFPIN_AVR(16, (1<<0), C); _DEFPIN_AVR(17, (1<<1), C); _DEFPIN_AVR(18, (1<<2), C); _DEFPIN_AVR(19, (1<<3), C); +_DEFPIN_AVR(20, (1<<4), C); _DEFPIN_AVR(21, (1<<5), C); _DEFPIN_AVR(22, (1<<6), C); _DEFPIN_AVR(23, (1<<7), C); + +_DEFPIN_AVR(24, (1<<0), A); _DEFPIN_AVR(25, (1<<1), A); _DEFPIN_AVR(26, (1<<2), A); _DEFPIN_AVR(27, (1<<3), A); +_DEFPIN_AVR(28, (1<<4), A); _DEFPIN_AVR(29, (1<<5), A); _DEFPIN_AVR(30, (1<<6), A); _DEFPIN_AVR(31, (1<<7), A); + +#define SPI_DATA 5 +#define SPI_CLOCK 7 +#define SPI_SELECT 4 +#define AVR_HARDWARE_SPI + +// Leonardo, teensy, blinkm +#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) +// Leonardo, teensy, blinkm +#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) + +// teensy defs +_IO(B); _IO(C); _IO(D); _IO(E); _IO(F); + +_DEFPIN_AVR(0, 1, B); _DEFPIN_AVR(1, 2, B); _DEFPIN_AVR(2, 4, B); _DEFPIN_AVR(3, 8, B); +_DEFPIN_AVR(4, 128, B); _DEFPIN_AVR(5, 1, D); _DEFPIN_AVR(6, 2, D); _DEFPIN_AVR(7, 4, D); +_DEFPIN_AVR(8, 8, D); _DEFPIN_AVR(9, 64, C); _DEFPIN_AVR(10, 128, C); _DEFPIN_AVR(11, 64, D); +_DEFPIN_AVR(12, 128, D); _DEFPIN_AVR(13, 16, B); _DEFPIN_AVR(14, 32, B); _DEFPIN_AVR(15, 64, B); +_DEFPIN_AVR(16, 128, F); _DEFPIN_AVR(17, 64, F); _DEFPIN_AVR(18, 32, F); _DEFPIN_AVR(19, 16, F); +_DEFPIN_AVR(20, 2, F); _DEFPIN_AVR(21, 1, F); _DEFPIN_AVR(22, 16, D); _DEFPIN_AVR(23, 32, D); + +#define SPI_DATA 2 +#define SPI_CLOCK 1 +#define SPI_SELECT 3 +#define AVR_HARDWARE_SPI + +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +// teensy++ 2 defs + +_IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); + +_DEFPIN_AVR(0, 1, D); _DEFPIN_AVR(1, 2, D); _DEFPIN_AVR(2, 4, D); _DEFPIN_AVR(3, 8, D); +_DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 32, D); _DEFPIN_AVR(6, 64, D); _DEFPIN_AVR(7, 128, D); +_DEFPIN_AVR(8, 1, E); _DEFPIN_AVR(9, 2, E); _DEFPIN_AVR(10, 1, C); _DEFPIN_AVR(11, 2, C); +_DEFPIN_AVR(12, 4, C); _DEFPIN_AVR(13, 8, C); _DEFPIN_AVR(14, 16, C); _DEFPIN_AVR(15, 32, C); +_DEFPIN_AVR(16, 64, C); _DEFPIN_AVR(17, 128, C); _DEFPIN_AVR(18, 64, E); _DEFPIN_AVR(19, 128, E); +_DEFPIN_AVR(20, 1, B); _DEFPIN_AVR(21, 2, B); _DEFPIN_AVR(22, 4, B); _DEFPIN_AVR(23, 8, B); +_DEFPIN_AVR(24, 16, B); _DEFPIN_AVR(25, 32, B); _DEFPIN_AVR(26, 64, B); _DEFPIN_AVR(27, 128, B); +_DEFPIN_AVR(28, 1, A); _DEFPIN_AVR(29, 2, A); _DEFPIN_AVR(30, 4, A); _DEFPIN_AVR(31, 8, A); +_DEFPIN_AVR(32, 16, A); _DEFPIN_AVR(33, 32, A); _DEFPIN_AVR(34, 64, A); _DEFPIN_AVR(35, 128, A); +_DEFPIN_AVR(36, 16, E); _DEFPIN_AVR(37, 32, E); _DEFPIN_AVR(38, 1, F); _DEFPIN_AVR(39, 2, F); +_DEFPIN_AVR(40, 4, F); _DEFPIN_AVR(41, 8, F); _DEFPIN_AVR(42, 16, F); _DEFPIN_AVR(43, 32, F); +_DEFPIN_AVR(44, 64, F); _DEFPIN_AVR(45, 128, F); + +#define SPI_DATA 22 +#define SPI_CLOCK 21 +#define SPI_SELECT 20 +#define AVR_HARDWARE_SPI + +#elif defined(__AVR_ATmega32U4__) + +// leonard defs +_IO(B); _IO(C); _IO(D); _IO(E); _IO(F); + +_DEFPIN_AVR(0, 4, D); _DEFPIN_AVR(1, 8, D); _DEFPIN_AVR(2, 2, D); _DEFPIN_AVR(3, 1, D); +_DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 64, C); _DEFPIN_AVR(6, 128, D); _DEFPIN_AVR(7, 64, E); +_DEFPIN_AVR(8, 16, B); _DEFPIN_AVR(9, 32, B); _DEFPIN_AVR(10, 64, B); _DEFPIN_AVR(11, 128, B); +_DEFPIN_AVR(12, 64, D); _DEFPIN_AVR(13, 128, C); _DEFPIN_AVR(14, 8, B); _DEFPIN_AVR(15, 2, B); +_DEFPIN_AVR(16, 4, B); _DEFPIN_AVR(17, 1, B); _DEFPIN_AVR(18, 128, F); _DEFPIN_AVR(19, 64, F); +_DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_AVR(23, 0, F); + +#define SPI_DATA 16 +#define SPI_CLOCK 15 +#define AVR_HARDWARE_SPI + +#elif defined(__MK20DX128__) && defined(CORE_TEENSY) + +_IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); + +_DEFPIN_ARM(0, 16, B); _DEFPIN_ARM(1, 17, B); _DEFPIN_ARM(2, 0, D); _DEFPIN_ARM(3, 12, A); +_DEFPIN_ARM(4, 13, A); _DEFPIN_ARM(5, 7, D); _DEFPIN_ARM(6, 4, D); _DEFPIN_ARM(7, 2, D); +_DEFPIN_ARM(8, 3, D); _DEFPIN_ARM(9, 3, C); _DEFPIN_ARM(10, 4, C); _DEFPIN_ARM(11, 6, C); +_DEFPIN_ARM(12, 7, C); _DEFPIN_ARM(13, 5, C); _DEFPIN_ARM(14, 1, D); _DEFPIN_ARM(15, 0, C); +_DEFPIN_ARM(16, 0, B); _DEFPIN_ARM(17, 1, B); _DEFPIN_ARM(18, 3, B); _DEFPIN_ARM(19, 2, B); +_DEFPIN_ARM(20, 5, D); _DEFPIN_ARM(21, 6, D); _DEFPIN_ARM(22, 1, C); _DEFPIN_ARM(23, 2, C); +_DEFPIN_ARM(24, 5, A); _DEFPIN_ARM(25, 19, B); _DEFPIN_ARM(26, 1, E); _DEFPIN_ARM(27, 9, C); +_DEFPIN_ARM(28, 8, C); _DEFPIN_ARM(29, 10, C); _DEFPIN_ARM(30, 11, C); _DEFPIN_ARM(31, 0, E); +_DEFPIN_ARM(32, 18, B); _DEFPIN_ARM(33, 4, A); + +#define SPI_DATA 11 +#define SPI_CLOCK 13 +#define ARM_HARDWARE_SPI + +#elif defined(__SAM3X8E__) + +DUE_IO32(A); +DUE_IO32(B); +DUE_IO32(C); +DUE_IO32(D); + +_DEFPIN_DUE(0, 8, A); _DEFPIN_DUE(1, 9, A); _DEFPIN_DUE(2, 25, B); _DEFPIN_DUE(3, 28, C); +_DEFPIN_DUE(4, 26, C); _DEFPIN_DUE(5, 25, C); _DEFPIN_DUE(6, 24, C); _DEFPIN_DUE(7, 23, C); +_DEFPIN_DUE(8, 22, C); _DEFPIN_DUE(9, 21, C); _DEFPIN_DUE(10, 29, C); _DEFPIN_DUE(11, 7, D); +_DEFPIN_DUE(12, 8, D); _DEFPIN_DUE(13, 27, B); _DEFPIN_DUE(14, 4, D); _DEFPIN_DUE(15, 5, D); +_DEFPIN_DUE(16, 13, A); _DEFPIN_DUE(17, 12, A); _DEFPIN_DUE(18, 11, A); _DEFPIN_DUE(19, 10, A); +_DEFPIN_DUE(20, 12, B); _DEFPIN_DUE(21, 13, B); _DEFPIN_DUE(22, 26, B); _DEFPIN_DUE(23, 14, A); +_DEFPIN_DUE(24, 15, A); _DEFPIN_DUE(25, 0, D); _DEFPIN_DUE(26, 1, D); _DEFPIN_DUE(27, 2, D); +_DEFPIN_DUE(28, 3, D); _DEFPIN_DUE(29, 6, D); _DEFPIN_DUE(30, 9, D); _DEFPIN_DUE(31, 7, A); +_DEFPIN_DUE(32, 10, D); _DEFPIN_DUE(33, 1, C); _DEFPIN_DUE(34, 2, C); _DEFPIN_DUE(35, 3, C); +_DEFPIN_DUE(36, 4, C); _DEFPIN_DUE(37, 5, C); _DEFPIN_DUE(38, 6, C); _DEFPIN_DUE(39, 7, C); +_DEFPIN_DUE(40, 8, C); _DEFPIN_DUE(41, 9, C); _DEFPIN_DUE(42, 19, A); _DEFPIN_DUE(43, 20, A); +_DEFPIN_DUE(44, 19, C); _DEFPIN_DUE(45, 18, C); _DEFPIN_DUE(46, 17, C); _DEFPIN_DUE(47, 16, C); +_DEFPIN_DUE(48, 15, C); _DEFPIN_DUE(49, 14, C); _DEFPIN_DUE(50, 13, C); _DEFPIN_DUE(51, 12, C); +_DEFPIN_DUE(52, 21, B); _DEFPIN_DUE(53, 14, B); _DEFPIN_DUE(54, 16, A); _DEFPIN_DUE(55, 24, A); +_DEFPIN_DUE(56, 23, A); _DEFPIN_DUE(57, 22, A); _DEFPIN_DUE(58, 6, A); _DEFPIN_DUE(59, 4, A); +_DEFPIN_DUE(60, 3, A); _DEFPIN_DUE(61, 2, A); _DEFPIN_DUE(62, 17, B); _DEFPIN_DUE(63, 18, B); +_DEFPIN_DUE(64, 19, B); _DEFPIN_DUE(65, 20, B); _DEFPIN_DUE(66, 15, B); _DEFPIN_DUE(67, 16, B); +_DEFPIN_DUE(68, 1, A); _DEFPIN_DUE(69, 0, A); _DEFPIN_DUE(70, 17, A); _DEFPIN_DUE(71, 18, A); +_DEFPIN_DUE(72, 30, C); _DEFPIN_DUE(73, 21, A); _DEFPIN_DUE(74, 25, A); _DEFPIN_DUE(75, 26, A); +_DEFPIN_DUE(76, 27, A); _DEFPIN_DUE(77, 28, A); _DEFPIN_DUE(78, 23, B); + +#else + +#warning "No pin/port mappings found, pin access will be slightly slower. See fastpin.h for info." +#define NO_HARDWARE_PIN_SUPPORT + +#endif + +#endif diff --git a/PDQ_MinLib/PDQ_GFX.h b/PDQ_MinLib/PDQ_GFX.h new file mode 100644 index 0000000..5b225ef --- /dev/null +++ b/PDQ_MinLib/PDQ_GFX.h @@ -0,0 +1,1369 @@ +// This is the PDQ re-mixed version of Adafruit's library from Xark +// here is the original copyright notice and license: + +/* +This is the core graphics library for all our displays, providing a common +set of graphics primitives (points, lines, circles, etc.). It needs to be +paired with a hardware-specific library for each display device we carry +(to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please +support Adafruit & open-source hardware by purchasing products from Adafruit! + +Copyright (c) 2013 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +// This PDQ optimized version is by Xark +// +// Inspiration from Paul Stoffregen and the Teensy 3.1 community. +// +// GOALS: +// 1) Maintain "sketch" compatibility with original Adafruit libraries. +// 2) Be as much faster as is reasonably possible honoring goal 1. :-) +// 3) Be at least as small as Adafruit libraries. +// +// I believe all three of these have largely been achieved: +// 1) Near full compatibility. Only minor initialization changes in original sketch. +// 2) Between ~2.5 and ~12 times faster (fillRect ~2.5x, drawLine ~12x). +// An average of ~4x faster over entire "graphictest.ino" benchmark. +// +// Even if this library is faster, it was based on the Adafruit original. +// Adafruit deserves your support for making their library open-source (and +// for having some nice LCD modules and all kinds of other great parts too). +// Consider giving them your support if possible! + +#ifndef _PDQ_GFX_H +#define _PDQ_GFX_H + +#include "Arduino.h" +#include "Print.h" + +#ifndef pgm_read_byte + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif +#ifndef pgm_read_word + #define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#endif +#ifndef pgm_read_dword + #define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#endif +#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFFL) + #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) +#else + #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) +#endif + +#include "gfxfont.h" + +#define GFX_FONT_PACKED + +typedef int coord_t; // type used for coordinates (signed) for parameters (int16_t used for storage) +typedef uint16_t color_t; // type used for colors (unsigned) + +// swap any type +template +static inline void swapValue(T& x, T& y) +{ + T tmp = x; + x = y; + y = tmp; +} + +// minimum value for any type +template +static inline T minValue(T& x, T& y) +{ + return x < y ? x : y; +} + +// maximum value for any type +template +static inline T maxValue(T& x, T& y) +{ + return x >= y ? x : y; +} + +template +class PDQ_GFX : public Print { + +public: + PDQ_GFX(coord_t w, coord_t h); // Constructor (called by HW driver) + + // Graphic primitives + // drawPixel MUST be defined by the driver subclass (and has no generic fall-back): + + // These are generic versions of routines for drivers that don't provide device-optimized code. + // Drivers are required to have these functions (without "_" postfix), but can fall back to using + // these if needed (they should not be called directly with "_" postfix or it will bypass any + // device-optimized implementations). + static void drawLine_(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); + static void drawFastVLine_(coord_t x, coord_t y, coord_t h, color_t color); + static void drawFastHLine_(coord_t x, coord_t y, coord_t w, color_t color); + static void fillRect_(coord_t x, coord_t y, coord_t w, coord_t h, color_t color); + static void fillScreen_(color_t color); + + // These are usually overridden in the driver subclass to be useful (but not internally referenced) + static void setRotation(uint8_t r); // only swaps width/height if not supported by driver + static void invertDisplay(boolean i); // only if supported by driver + + // These exist in PDQ_GFX (and generally have no subclass override) + static void drawRect(coord_t x, coord_t y, coord_t w, coord_t h, color_t color); + static void drawCircle(coord_t x0, coord_t y0, coord_t r, color_t color); + static void drawCircleHelper(coord_t x0, coord_t y0, coord_t r, uint8_t cornername, color_t color); + static void fillCircle(coord_t x0, coord_t y0, coord_t r, color_t color); + static void fillCircleHelper(coord_t x0, coord_t y0, coord_t r, uint8_t cornername, coord_t delta, color_t color); + static void drawTriangle(coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color); + static void fillTriangle(coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color); + static void drawRoundRect(coord_t x0, coord_t y0, coord_t w, coord_t h, coord_t radius, color_t color); + static void fillRoundRect(coord_t x0, coord_t y0, coord_t w, coord_t h, coord_t radius, color_t color); + static void drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color); + static void drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg); + static void drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color); + static void drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg); + static void drawXBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color); + static void drawChar(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size); + static void drawCharGFX(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size); + static inline void setCursor(coord_t x, coord_t y); + static inline void setTextColor(color_t c); + static inline void setTextColor(color_t c, color_t bg); + static inline void setTextSize(uint8_t s); + static inline void setTextWrap(boolean w); + static inline void cp437(boolean x=true); + static inline void setFont(const GFXfont *f = NULL); + + static inline coord_t width() __attribute__ ((always_inline)) { return _width; } + static inline coord_t height() __attribute__ ((always_inline)) { return _height; } + static inline uint8_t getRotation() __attribute__ ((always_inline)) { return rotation; } + static inline coord_t getCursorX() __attribute__ ((always_inline)) { return cursor_x; } + static inline coord_t getCursorY() __attribute__ ((always_inline)) { return cursor_y; } + static inline void getTextBounds(char *string, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + static inline void getTextBounds(const __FlashStringHelper *s, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + + virtual size_t write(uint8_t); // used by Arduino "Print.h" (and the one required virtual function) + +protected: + static GFXfont* gfxFont; + static coord_t WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes + static coord_t _width, _height; // Display w/h as modified by current rotation + static coord_t cursor_x, cursor_y; + static color_t textcolor, textbgcolor; + static uint8_t textsize; + static uint8_t rotation; + static boolean wrap; // If set, 'wrap' text at right edge of display + static boolean _cp437; // If set, use correct CP437 charset (default is off) +}; + + +template +class PDQ_GFX_Button_ +{ +public: + PDQ_GFX_Button_(); + void initButton(PDQ_GFX *gfx, coord_t x, coord_t y, coord_t w, coord_t h, color_t outline, color_t fill, color_t textcolor, const char *label, uint8_t textsize); + void drawButton(boolean inverted = false); + boolean contains(coord_t x, coord_t y); + + void press(boolean p); + boolean isPressed(); + boolean justPressed(); + boolean justReleased(); + +private: + PDQ_GFX *_gfx; + int16_t _x, _y; + int16_t _w, _h; + uint8_t _textsize; + color_t _outlinecolor, _fillcolor, _textcolor; + char _label[10]; + + boolean currstate, laststate; +}; + +// ----------------------------------------------- +extern const unsigned char glcdfont[] PROGMEM; + +template +int16_t PDQ_GFX::WIDTH; // This is the 'raw' display w/h - never changes +template +int16_t PDQ_GFX::HEIGHT; +template +int16_t PDQ_GFX::_width; // Display w/h as modified by current rotation +template +int16_t PDQ_GFX::_height; +template +int16_t PDQ_GFX::cursor_x; +template +int16_t PDQ_GFX::cursor_y; +template +color_t PDQ_GFX::textcolor; +template +color_t PDQ_GFX::textbgcolor; +template +uint8_t PDQ_GFX::textsize; +template +uint8_t PDQ_GFX::rotation; +template +boolean PDQ_GFX::wrap; // If set, 'wrap' text at right edge of display +template +boolean PDQ_GFX::_cp437; // If set, use correct CP437 charset (default is off) +template +GFXfont *PDQ_GFX::gfxFont; + +template +PDQ_GFX::PDQ_GFX(coord_t w, coord_t h) +{ + WIDTH = (int16_t)w; + HEIGHT = (int16_t)h; + _width = (int16_t)w; + _height = (int16_t)h; + cursor_x = 0; + cursor_y = 0; + rotation = 0; + textsize = 1; + textcolor = 0xffff; + textbgcolor = 0xffff; + wrap = true; + _cp437 = false; + gfxFont = NULL; +} + +// Draw a circle outline +template +void PDQ_GFX::drawCircle(coord_t x0, coord_t y0, coord_t r, color_t color) +{ + coord_t f = 1 - r; + coord_t ddF_x = 1; + coord_t ddF_y = -2 * r; + coord_t x = 0; + coord_t y = r; + + HW::drawPixel(x0 , y0+r, color); + HW::drawPixel(x0 , y0-r, color); + HW::drawPixel(x0+r, y0 , color); + HW::drawPixel(x0-r, y0 , color); + + while (x < y) + { + if (f >= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + HW::drawPixel(x0 + x, y0 + y, color); + HW::drawPixel(x0 - x, y0 + y, color); + HW::drawPixel(x0 + x, y0 - y, color); + HW::drawPixel(x0 - x, y0 - y, color); + HW::drawPixel(x0 + y, y0 + x, color); + HW::drawPixel(x0 - y, y0 + x, color); + HW::drawPixel(x0 + y, y0 - x, color); + HW::drawPixel(x0 - y, y0 - x, color); + } +} + +template +void PDQ_GFX::drawCircleHelper( coord_t x0, coord_t y0, coord_t r, uint8_t cornername, color_t color) +{ + coord_t f = 1 - r; + coord_t ddF_x = 1; + coord_t ddF_y = -2 * r; + coord_t x = 0; + coord_t y = r; + + while (x < y) + { + if (f >= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) + { + HW::drawPixel(x0 + x, y0 + y, color); + HW::drawPixel(x0 + y, y0 + x, color); + } + if (cornername & 0x2) + { + HW::drawPixel(x0 + x, y0 - y, color); + HW::drawPixel(x0 + y, y0 - x, color); + } + if (cornername & 0x8) + { + HW::drawPixel(x0 - y, y0 + x, color); + HW::drawPixel(x0 - x, y0 + y, color); + } + if (cornername & 0x1) + { + HW::drawPixel(x0 - y, y0 - x, color); + HW::drawPixel(x0 - x, y0 - y, color); + } + } +} + +template +void PDQ_GFX::fillCircle(coord_t x0, coord_t y0, coord_t r, color_t color) +{ + HW::drawFastVLine(x0, y0-r, 2*r+1, color); + fillCircleHelper(x0, y0, r, 3, 0, color); +} + +// Used to do circles and roundrects +template +void PDQ_GFX::fillCircleHelper(coord_t x0, coord_t y0, coord_t r, uint8_t cornername, coord_t delta, color_t color) +{ + coord_t f = 1 - r; + coord_t ddF_x = 1; + coord_t ddF_y = -2 * r; + coord_t x = 0; + coord_t y = r; + + while (x < y) + { + if (f >= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + if (cornername & 0x1) + { + HW::drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); + HW::drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); + } + if (cornername & 0x2) + { + HW::drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); + HW::drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); + } + } +} + +// Bresenham's algorithm - thx Wikipedia +template +void PDQ_GFX::drawLine_(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) +{ + int8_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) + { + swapValue(x0, y0); + swapValue(x1, y1); + } + + if (x0 > x1) + { + swapValue(x0, x1); + swapValue(y0, y1); + } + + coord_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + coord_t err = dx / 2; + coord_t ystep; + + if (y0 < y1) + { + ystep = 1; + } + else + { + ystep = -1; + } + + for (; x0<=x1; x0++) + { + if (steep) + { + HW::drawPixel(y0, x0, color); + } + else + { + HW::drawPixel(x0, y0, color); + } + err -= dy; + if (err < 0) + { + y0 += ystep; + err += dx; + } + } +} + +// Draw a rectangle +template +void PDQ_GFX::drawRect(coord_t x, coord_t y, coord_t w, coord_t h, color_t color) +{ + HW::drawFastHLine(x , y , w, color); + HW::drawFastHLine(x , y+h-1, w, color); + HW::drawFastVLine(x , y , h, color); + HW::drawFastVLine(x+w-1, y , h, color); +} + +template +void PDQ_GFX::drawFastVLine_(coord_t x, coord_t y, coord_t h, color_t color) +{ + // Used by driver when it has no special support + HW::drawLine(x, y, x, y+h-1, color); +} + +template +void PDQ_GFX::drawFastHLine_(coord_t x, coord_t y, coord_t w, color_t color) +{ + // Used by driver when it has no special support + HW::drawLine(x, y, x+w-1, y, color); +} + +template +void PDQ_GFX::fillRect_(coord_t x, coord_t y, coord_t w, coord_t h, color_t color) +{ + // Used by driver when it has no special support + for (coord_t i=x; i +void PDQ_GFX::fillScreen_(color_t color) +{ + // Used by driver when it has no special support + HW::fillRect(0, 0, _width, _height, color); +} + +// Draw a rounded rectangle +template +void PDQ_GFX::drawRoundRect(coord_t x, coord_t y, coord_t w, coord_t h, coord_t r, color_t color) +{ + // smarter version + HW::drawFastHLine(x+r , y , w-2*r, color); // Top + HW::drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom + HW::drawFastVLine(x , y+r , h-2*r, color); // Left + HW::drawFastVLine(x+w-1, y+r , h-2*r, color); // Right + // draw four corners + drawCircleHelper(x+r , y+r , r, 1, color); + drawCircleHelper(x+w-r-1, y+r , r, 2, color); + drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color); + drawCircleHelper(x+r , y+h-r-1, r, 8, color); +} + +// Fill a rounded rectangle +template +void PDQ_GFX::fillRoundRect(coord_t x, coord_t y, coord_t w, coord_t h, coord_t r, color_t color) +{ + // smarter version + HW::fillRect(x+r, y, w-2*r, h, color); + + // draw four corners + fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color); + fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color); +} + +// Draw a triangle +template +void PDQ_GFX::drawTriangle(coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color) +{ + HW::drawLine(x0, y0, x1, y1, color); + HW::drawLine(x1, y1, x2, y2, color); + HW::drawLine(x2, y2, x0, y0, color); +} + +// Fill a triangle +template +void PDQ_GFX::fillTriangle( coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color) +{ + coord_t a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) + { + swapValue(y0, y1); + swapValue(x0, x1); + } + if (y1 > y2) + { + swapValue(y2, y1); + swapValue(x2, x1); + } + if (y0 > y1) + { + swapValue(y0, y1); + swapValue(x0, x1); + } + + if (y0 == y2) // Handle awkward all-on-same-line case as its own thing + { + a = b = x0; + if (x1 < a) + a = x1; + else if (x1 > b) + b = x1; + if (x2 < a) + a = x2; + else if (x2 > b) + b = x2; + HW::drawFastHLine(a, y0, b-a+1, color); + return; + } + + coord_t dx01 = x1 - x0; + coord_t dy01 = y1 - y0; + coord_t dx02 = x2 - x0; + coord_t dy02 = y2 - y0; + coord_t dx12 = x2 - x1; + coord_t dy12 = y2 - y1; + int32_t sa = 0; + int32_t sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if (y1 == y2) + last = y1; // Include y1 scanline + else + last = y1-1; // Skip it + + for (y = y0; y <= last; y++) + { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + swapValue(a, b); + HW::drawFastHLine(a, y, b-a+1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = dx12 * (y - y1); + sb = dx02 * (y - y0); + for (; y <= y2; y++) + { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + swapValue(a, b); + HW::drawFastHLine(a, y, b-a+1, color); + } +} + +// Draw a 1-bit image (bitmap) at the specified (x, y) position from the +// provided bitmap buffer (must be PROGMEM memory) using the specified +// foreground color (unset bits are transparent). +template +void PDQ_GFX::drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color) +{ + coord_t i, j, byteWidth = (w + 7) / 8; + uint8_t byte; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + if (i % 8 == 0) + byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); + else + byte <<= 1; + + if (byte & 0x80) + HW::drawPixel(x+i, y+j, color); + } + } +} + +// Draw a 1-bit image (bitmap) at the specified (x, y) position from the +// provided bitmap buffer (must be PROGMEM memory) using the specified +// foreground (for set bits) and background (for clear bits) colors. +template +void PDQ_GFX::drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg) +{ + coord_t i, j, byteWidth = (w + 7) / 8; + uint8_t byte; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + if (i % 8 == 0) + byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); + else + byte <<= 1; + + if (byte & 0x80) + HW::drawPixel(x+i, y+j, color); + else + HW::drawPixel(x+i, y+j, bg); + } + } +} + +// drawBitmap() variant for RAM-resident (not PROGMEM) bitmaps. +template +void PDQ_GFX::drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color) +{ + coord_t i, j, byteWidth = (w + 7) / 8; + uint8_t byte; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + if (i % 8 == 0) + byte = bitmap[j * byteWidth + i / 8]; + else + byte <<= 1; + + if (byte & 0x80) + HW::drawPixel(x+i, y+j, color); + } + } +} + +// drawBitmap() variant w/background for RAM-resident (not PROGMEM) bitmaps. +template +void PDQ_GFX::drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg) +{ + coord_t i, j, byteWidth = (w + 7) / 8; + uint8_t byte; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + if (i % 8 == 0) + byte = bitmap[j * byteWidth + i / 8]; + else + byte <<= 1; + + if (byte & 0x80) + HW::drawPixel(x+i, y+j, color); + else + HW::drawPixel(x+i, y+j, bg); + } + } +} + +// Draw XBitMap Files (*.xbm), exported from GIMP, +// Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. +// C Array can be directly used with this function +template +void PDQ_GFX::drawXBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color) +{ + coord_t i, j, byteWidth = (w + 7) / 8; + uint8_t byte; + + for (j = 0; j < h; j++) + { + for (i = 0; i < w; i++) + { + if (i % 8 == 0) + byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); + else + byte >>= 1; + + if (byte & 0x01) + HW::drawPixel(x+i, y+j, color); + } + } +} + +template +size_t PDQ_GFX::write(uint8_t c) +{ + // 'Classic' built-in font + if (!gfxFont) + { + if (c == '\n') + { + cursor_x = 0; + cursor_y += (coord_t)textsize*8; + } + else if (c != '\r') + { + HW::drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); + cursor_x += textsize*6; + if (wrap && (cursor_x > (_width - textsize*6))) + { + cursor_x = 0; + cursor_y += textsize*8; + } + } + } + else + { + if(c == '\n') + { + cursor_x = 0; + cursor_y += (coord_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + else if (c != '\r') + { + uint8_t first = pgm_read_byte(&gfxFont->first); + if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) + { + uint8_t c2 = c - pgm_read_byte(&gfxFont->first); + GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c2]); + uint8_t w = pgm_read_byte(&glyph->width); + uint8_t h = pgm_read_byte(&glyph->height); + // Is there an associated bitmap? + if ((w > 0) && (h > 0)) + { + coord_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic + if(wrap && ((cursor_x + textsize * (xo + w)) >= _width)) + { + // Drawing character would go off right edge; wrap to new line + cursor_x = 0; + cursor_y += (coord_t)textsize * + (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + HW::drawCharGFX(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); + } + cursor_x += pgm_read_byte(&glyph->xAdvance) * (coord_t)textsize; + } + } + } + return 1; +} + +// Draw a character with built-in font +template +void PDQ_GFX::drawChar(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size) +{ + if ((x >= _width) || + (y >= _height) || + ((x + (6 * size) - 1) < 0) || + ((y + (8 * size) - 1) < 0)) + return; + + uint8_t is_opaque = (bg != color); + + if(!_cp437 && (c >= 176)) // Handle 'classic' charset behavior + c++; + + for (int8_t i=0; i<6; i++) + { + uint8_t line; + + if (i == 5) + line = 0x0; + else + line = pgm_read_byte(glcdfont+(c*5)+i); + + if (size == 1) + { + for (int8_t j = 0; j < 8; j++) + { + if (line & 0x1) + { + HW::drawPixel(x+i, y+j, color); + } + else if (is_opaque) + { + HW::drawPixel(x+i, y+j, bg); + } + line >>= 1; + } + } + else + { + for (int8_t j = 0; j < 8; j++) + { + if (line & 0x1) + { + HW::fillRect(x+(i*size), y+(j*size), size, size, color); + } + else if (is_opaque) + { + HW::fillRect(x+(i*size), y+(j*size), size, size, bg); + } + line >>= 1; + } + } + } +} + +// Draw a character with GFX font +template +void PDQ_GFX::drawCharGFX(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size) +{ + // Character is assumed previously filtered by write() to eliminate + // newlines, returns, non-printable characters, etc. Calling drawChar() + // directly with 'bad' characters of font may cause mayhem! + + c -= pgm_read_byte(&gfxFont->first); + GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); + uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); + + uint16_t bo = pgm_read_word(&glyph->bitmapOffset); + uint8_t w = pgm_read_byte(&glyph->width); + uint8_t h = pgm_read_byte(&glyph->height); + // uint8_t xa = pgm_read_byte(&glyph->xAdvance); + int8_t xo = pgm_read_byte(&glyph->xOffset); + int8_t yo = pgm_read_byte(&glyph->yOffset); + + // Todo: Add character clipping here + + // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS. + // THIS IS ON PURPOSE AND BY DESIGN. The background color feature + // has typically been used with the 'classic' font to overwrite old + // screen contents with new data. This ONLY works because the + // characters are a uniform size; it's not a sensible thing to do with + // proportionally-spaced fonts with glyphs of varying sizes (and that + // may overlap). To replace previously-drawn text when using a custom + // font, use the getTextBounds() function to determine the smallest + // rectangle encompassing a string, erase the area with fillRect(), + // then draw new text. This WILL infortunately 'blink' the text, but + // is unavoidable. Drawing 'background' pixels will NOT fix this, + // only creates a new set of problems. Have an idea to work around + // this (a canvas object type for MCUs that can afford the RAM and + // displays supporting setAddrWindow() and pushColors()), but haven't + // implemented this yet. + + if (bo & 0x8000) { + // packed font + uint8_t bits_cnt = 0; + uint8_t bits; + uint8_t cnt,cnt2; + bo &= 0x7FFF; + coord_t _y = y+yo; + for (coord_t yy=0; yy= w) + { + cnt2 = w-xx; + } else { + cnt2 = cnt; + } + + if (bits & 0x8) + { + if (size == 1) + { + HW::drawFastHLine(_x, _y, cnt2, color); + _x += cnt2; + } + else + { + HW::fillRect(x+xo+xx*size, y+yo+yy*size, cnt2*size, size, color); + // _x not used if size > 1, so not need to increment it + } + } else { + _x += cnt2; + } + + cnt -= cnt2; + if (cnt == 0) { + bits >>= 4; + cnt = (bits & 0x7)+1; + bits_cnt--; + } + } + } + } else { + uint8_t bit = 0; + uint8_t bits = 0; + if (size == 1) + { + coord_t _y = y+yo; + for (coord_t yy=0; yy +void PDQ_GFX::setCursor(coord_t x, coord_t y) +{ + cursor_x = (int16_t)x; + cursor_y = (int16_t)y; +} + +template +void PDQ_GFX::setTextSize(uint8_t s) +{ + textsize = (s > 0) ? s : 1; +} + +template +void PDQ_GFX::setTextColor(color_t c) +{ + // For 'transparent' background, we'll set the bg + // to the same as fg instead of using a flag + textcolor = c; + textbgcolor = c; +} + +template +void PDQ_GFX::setTextColor(color_t c, color_t b) +{ + textcolor = c; + textbgcolor = b; +} + +template +void PDQ_GFX::setTextWrap(boolean w) +{ + wrap = w; +} + +template +void PDQ_GFX::setRotation(uint8_t x) +{ + // Used by driver when it has no special support + rotation = x & 3; + switch(rotation) { + case 0: + case 2: + _width = WIDTH; + _height = HEIGHT; + break; + case 1: + case 3: + _width = HEIGHT; + _height = WIDTH; + break; + } +} + +template +void PDQ_GFX::cp437(boolean x) +{ + _cp437 = x; +} + +template +void PDQ_GFX::setFont(const GFXfont *f) +{ + if (f) // Font struct pointer passed in? + { + if (!gfxFont) // And no current font struct? + { + // Switching from classic to new font behavior. + // Move cursor pos down 6 pixels so it's on baseline. + cursor_y += 6; + } + } + else if (gfxFont) // NULL passed. Current font struct defined? + { + // Switching from new to classic font behavior. + // Move cursor pos up 6 pixels so it's at top-left of char. + cursor_y -= 6; + } + gfxFont = (GFXfont *)f; +} + +// Pass string and a cursor position, returns UL corner and W,H. +template +void PDQ_GFX::getTextBounds(char *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) +{ + uint8_t c; // Current character + + *x1 = x; + *y1 = y; + *w = *h = 0; + + if (gfxFont) + { + GFXglyph *glyph; + uint8_t first = pgm_read_byte(&gfxFont->first); + uint8_t last = pgm_read_byte(&gfxFont->last); + uint8_t gw, gh, xa; + int8_t xo, yo; + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; + coord_t gx1, gy1, gx2, gy2; + coord_t ts = (coord_t)textsize, ya = (coord_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + + while((c = *str++)) + { + if (c != '\n') // Not a newline + { + if (c != '\r') // Not a carriage return, is normal char + { + if ((c >= first) && (c <= last)) // Char present in current font + { + c -= first; + glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); + gw = pgm_read_byte(&glyph->width); + gh = pgm_read_byte(&glyph->height); + xa = pgm_read_byte(&glyph->xAdvance); + xo = pgm_read_byte(&glyph->xOffset); + yo = pgm_read_byte(&glyph->yOffset); + if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) // Line wrap + { + x = 0; // Reset x to 0 + y += ya; // Advance y by 1 line + } + gx1 = x + xo * ts; + gy1 = y + yo * ts; + gx2 = gx1 + gw * ts - 1; + gy2 = gy1 + gh * ts - 1; + if (gx1 < minx) + minx = gx1; + if (gy1 < miny) + miny = gy1; + if (gx2 > maxx) + maxx = gx2; + if (gy2 > maxy) + maxy = gy2; + x += xa * ts; + } + } // Carriage return = do nothing + } + else // Newline + { + x = 0; // Reset x + y += ya; // Advance y by 1 line + } + } + // End of string + *x1 = minx; + *y1 = miny; + if (maxx >= minx) + *w = maxx - minx + 1; + if (maxy >= miny) + *h = maxy - miny + 1; + + } + else // Default font + { + uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines + + while((c = *str++)) + { + if (c != '\n') // Not a newline + { + if (c != '\r') // Not a carriage return, is normal char + { + lineWidth += textsize * 6; // Includes interchar x gap + if (wrap && (cursor_x > (_width - textsize*6))) + { + x = 0; + y += textsize*8; + + if (lineWidth > maxWidth) // Save widest line + maxWidth = lineWidth; + lineWidth = textsize * 6; // First char on new line + } + } // Carriage return = do nothing + } + else // Newline + { + x = 0; // Reset x to 0 + y += textsize * 8; // Advance y by 1 line + if (lineWidth > maxWidth) // Save widest line + maxWidth = lineWidth; + lineWidth = 0; // Reset lineWidth for new line + } + } + // End of string + if (lineWidth) // Add height of last (or only) line + y += textsize * 8; + *w = maxWidth - 1; // Don't include last interchar x gap + *h = y - *y1; + + } // End classic vs custom font +} + +// Same as above, but for PROGMEM strings +template +void PDQ_GFX::getTextBounds(const __FlashStringHelper *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) +{ + uint8_t *s = (uint8_t *)str; + uint8_t c; + + *x1 = x; + *y1 = y; + *w = *h = 0; + + if (gfxFont) + { + GFXglyph *glyph; + uint8_t first = pgm_read_byte(&gfxFont->first); + uint8_t last = pgm_read_byte(&gfxFont->last); + uint8_t gw, gh, xa; + int8_t xo, yo; + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; + coord_t gx1, gy1, gx2, gy2; + coord_t ts = (coord_t)textsize; + coord_t ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + + while((c = pgm_read_byte(s++))) + { + if (c != '\n') // Not a newline + { + if (c != '\r') // Not a carriage return, is normal char + { + if ((c >= first) && (c <= last)) // Char present in current font + { + c -= first; + glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); + gw = pgm_read_byte(&glyph->width); + gh = pgm_read_byte(&glyph->height); + xa = pgm_read_byte(&glyph->xAdvance); + xo = pgm_read_byte(&glyph->xOffset); + yo = pgm_read_byte(&glyph->yOffset); + if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) // Line wrap + { + x = 0; // Reset x to 0 + y += ya; // Advance y by 1 line + } + gx1 = x + xo * ts; + gy1 = y + yo * ts; + gx2 = gx1 + gw * ts - 1; + gy2 = gy1 + gh * ts - 1; + if (gx1 < minx) + minx = gx1; + if (gy1 < miny) + miny = gy1; + if (gx2 > maxx) + maxx = gx2; + if (gy2 > maxy) + maxy = gy2; + x += xa * ts; + } + } // Carriage return = do nothing + } + else // Newline + { + x = 0; // Reset x + y += ya; // Advance y by 1 line + } + } + // End of string + *x1 = minx; + *y1 = miny; + if (maxx >= minx) + *w = maxx - minx + 1; + if (maxy >= miny) + *h = maxy - miny + 1; + + } + else // Default font + { + uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines + + while((c = pgm_read_byte(s++))) + { + if (c != '\n') // Not a newline + { + if (c != '\r') // Not a carriage return, is normal char + { + if (wrap && ((x + textsize * 6) >= _width)) + { + x = 0; // Reset x to 0 + y += textsize * 8; // Advance y by 1 line + if (lineWidth > maxWidth) // Save widest line + maxWidth = lineWidth; + lineWidth = textsize * 6; // First char on new line + } + else // No line wrap, just keep incrementing X + { + lineWidth += textsize * 6; // Includes interchar x gap + } + } // Carriage return = do nothing + } + else // Newline + { + x = 0; // Reset x to 0 + y += textsize * 8; // Advance y by 1 line + if (lineWidth > maxWidth) // Save widest line + maxWidth = lineWidth; + lineWidth = 0; // Reset lineWidth for new line + } + } + // End of string + if (lineWidth) // Add height of last (or only) line + y += textsize * 8; + *w = maxWidth - 1; // Don't include last interchar x gap + *h = y - *y1; + + } // End classic vs custom font +} + +template +void PDQ_GFX::invertDisplay(boolean i) +{ + // Used by driver when it has no special support + // Do nothing, must be supported by driver +} + +/***************************************************************************/ +// code for the GFX button UI element + +template +PDQ_GFX_Button_::PDQ_GFX_Button_() +{ + _gfx = 0; +} + +template +void PDQ_GFX_Button_::initButton(PDQ_GFX *gfx, coord_t x, coord_t y, coord_t w, coord_t h, color_t outline, color_t fill, color_t textcolor, const char *label, uint8_t textsize) +{ + _gfx = gfx; + _x = x; + _y = y; + _w = w; + _h = h; + _outlinecolor = outline; + _fillcolor = fill; + _textcolor = textcolor; + _textsize = textsize; + strncpy(_label, label, 9); + _label[9] = 0; +} + +template +void PDQ_GFX_Button_::drawButton(boolean inverted) +{ + uint16_t fill, outline, text; + + if (!inverted) + { + fill = _fillcolor; + outline = _outlinecolor; + text = _textcolor; + } + else + { + fill = _textcolor; + outline = _outlinecolor; + text = _fillcolor; + } + + _gfx->fillRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, fill); + _gfx->drawRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, outline); + + _gfx->setCursor(_x - strlen(_label)*3*_textsize, _y-4*_textsize); + _gfx->setTextColor(text); + _gfx->setTextSize(_textsize); + _gfx->print(_label); +} + +template +boolean PDQ_GFX_Button_::contains(coord_t x, coord_t y) +{ + if ((x < (_x - _w/2)) || (x > (_x + _w/2))) + return false; + if ((y < (_y - _h/2)) || (y > (_y + _h/2))) + return false; + return true; +} + +template +void PDQ_GFX_Button_::press(boolean p) +{ + laststate = currstate; + currstate = p; +} + +template +boolean PDQ_GFX_Button_::isPressed() +{ + return currstate; +} + +template +boolean PDQ_GFX_Button_::justPressed() +{ + return (currstate && !laststate); +} + +template +boolean PDQ_GFX_Button_::justReleased() +{ + return (!currstate && laststate); +} + +#endif // _PDQ_GFX_H diff --git a/PDQ_MinLib/PDQ_ILI9341.h b/PDQ_MinLib/PDQ_ILI9341.h new file mode 100644 index 0000000..8cc4051 --- /dev/null +++ b/PDQ_MinLib/PDQ_ILI9341.h @@ -0,0 +1,1064 @@ +// This is the PDQ re-mixed version of Adafruit's library +// here is the original copyright notice: + +/*************************************************** + This is an Arduino Library for the Adafruit 2.2" SPI display. + This library works with the Adafruit 2.2" TFT Breakout w/SD card + ----> http://www.adafruit.com/products/1480 + + Check out the links above for our tutorials and wiring diagrams + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional) + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +//=============================================================== +// This PDQ optimized version is by Xark +// +// Inspiration from Paul Stoffregen and the Teensy 3.1 community. +// +// GOALS: +// 1) Maintain "sketch" compatibility with original Adafruit libraries. +// 2) Be as much faster as is reasonably possible honoring goal 1. :-) +// 3) Be at least as small as Adafruit libraries. +// +// I believe all three of these have largely been achieved: +// 1) Near full compatibility. Only minor initialization changes in original sketch. +// 2) Between ~2.5 and ~12 times faster (fillRect ~2.5x, drawLine ~12x). +// An average of ~4x faster over entire "graphictest.ino" benchmark. +// +// Even if this library is faster, it was based on the Adafruit original. +// Adafruit deserves your support for making their library open-source (and +// for having some nice LCD modules and all kinds of other great parts too). +// Consider giving them your support if possible! + +#if !defined(_PDQ_ILI9341H_) +#define _PDQ_ILI9341H_ + +#include "Arduino.h" +#include "Print.h" + +#include "PDQ_GFX.h" + +#include + +#if !defined(ILI9341_CS_PIN) || !defined(ILI9341_DC_PIN) +#error Oops! You need to #include "PDQ_ILI9341_config.h" (modified with your pin configuration and options) from your sketch before #include "PDQ_ILI9341.h". +#endif + +#include "PDQ_FastPin.h" + +#if !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny45__) +#define INLINE inline +#define INLINE_OPT __attribute__((always_inline)) +#else +#define INLINE +#define INLINE_OPT +#endif + +// Color definitions +enum +{ + ILI9341_BLACK = 0x0000, + ILI9341_BLUE = 0x001F, + ILI9341_RED = 0xF800, + ILI9341_GREEN = 0x07E0, + ILI9341_CYAN = 0x07FF, + ILI9341_MAGENTA = 0xF81F, + ILI9341_YELLOW = 0xFFE0, + ILI9341_WHITE = 0xFFFF, +}; + +class PDQ_ILI9341 : public PDQ_GFX +{ + public: + // ILI9341 commands + // For datasheet see https://www.adafruit.com/products/1480 + enum + { + ILI9341_NOP = 0x00, + ILI9341_SWRESET = 0x01, + ILI9341_RDDID = 0x04, + ILI9341_RDDST = 0x09, + + ILI9341_SLPIN = 0x10, + ILI9341_SLPOUT = 0x11, + ILI9341_PTLON = 0x12, + ILI9341_NORON = 0x13, + + ILI9341_RDMODE = 0x0A, + ILI9341_RDMADCTL = 0x0B, + ILI9341_RDPIXFMT = 0x0C, + ILI9341_RDIMGFMT = 0x0A, + ILI9341_RDSELFDIAG = 0x0F, + + ILI9341_INVOFF = 0x20, + ILI9341_INVON = 0x21, + ILI9341_GAMMASET = 0x26, + ILI9341_DISPOFF = 0x28, + ILI9341_DISPON = 0x29, + + ILI9341_CASET = 0x2A, + ILI9341_PASET = 0x2B, + ILI9341_RAMWR = 0x2C, + ILI9341_RAMRD = 0x2E, + + ILI9341_PTLAR = 0x30, + ILI9341_MADCTL = 0x36, + ILI9341_PIXFMT = 0x3A, + + ILI9341_FRMCTR1 = 0xB1, + ILI9341_FRMCTR2 = 0xB2, + ILI9341_FRMCTR3 = 0xB3, + ILI9341_INVCTR = 0xB4, + ILI9341_DFUNCTR = 0xB6, + + ILI9341_PWCTR1 = 0xC0, + ILI9341_PWCTR2 = 0xC1, + ILI9341_PWCTR3 = 0xC2, + ILI9341_PWCTR4 = 0xC3, + ILI9341_PWCTR5 = 0xC4, + ILI9341_VMCTR1 = 0xC5, + ILI9341_VMCTR2 = 0xC7, + + ILI9341_RDID1 = 0xDA, + ILI9341_RDID2 = 0xDB, + ILI9341_RDID3 = 0xDC, + ILI9341_RDID4 = 0xDD, + + ILI9341_GMCTRP1 = 0xE0, + ILI9341_GMCTRN1 = 0xE1, + + // ILI9341_PWCTR6 = 0xFC, + }; + + // some other misc. constants + enum + { + // screen dimensions + ILI9341_TFTWIDTH = 240, + ILI9341_TFTHEIGHT = 320, + + // MADCTL bits + ILI9341_MADCTL_MH = 0x04, // bit 2 = 0 for refresh left -> right, 1 for refresh right -> left + ILI9341_MADCTL_RGB = 0x00, // bit 3 = 0 for RGB color order + ILI9341_MADCTL_BGR = 0x08, // bit 3 = 1 for BGR color order + ILI9341_MADCTL_ML = 0x10, // bit 4 = 0 for refresh top -> bottom, 1 for bottom -> top + ILI9341_MADCTL_MV = 0x20, // bit 5 = 0 for column, row order (portrait), 1 for row, column order (landscape) + ILI9341_MADCTL_MX = 0x40, // bit 6 = 0 for left -> right, 1 for right -> left order + ILI9341_MADCTL_MY = 0x80, // bit 7 = 0 for top -> bottom, 1 for bottom -> top + + // delay indicator bit for commandList() + DELAY = 0x80 + }; + + // higher-level routines + PDQ_ILI9341(); + static void inline begin(void); + static void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); + static void pushColor(uint16_t color); + static void pushColor(uint16_t color, int cnt); + + // Pass 8-bit (each) R,G,B, get back 16-bit packed color + static INLINE uint16_t color565(uint8_t r, uint8_t g, uint8_t b) + { + return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); + } + static INLINE uint16_t Color565(uint8_t r, uint8_t g, uint8_t b) // older inconsistent name for compatibility + { + return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); + } + + // required driver primitive methods (all except drawPixel can call generic version in PDQ_GFX with "_" postfix). + static void drawPixel(int x, int y, uint16_t color); + static void drawFastVLine(int x, int y, int h, uint16_t color); + static void drawFastHLine(int x, int y, int w, uint16_t color); + static void setRotation(uint8_t r); + static void invertDisplay(boolean i); + + static inline void fillScreen(uint16_t color) __attribute__((always_inline)) + { + fillScreen_(color); // call generic version + } + + static void drawLine(int x0, int y0, int x1, int y1, uint16_t color); + static void fillRect(int x, int y, int w, int h, uint16_t color); + + // === lower-level internal routines ========= + static void commandList(const uint8_t *addr); + + // NOTE: Make sure each spi_begin() is matched with a single spi_end() (and don't call either twice) + // set CS back to low (LCD selected) + static inline void spi_begin() __attribute__((always_inline)) + { +#if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) + swapValue(save_SPCR, SPCR); // swap initial/current SPCR settings +#endif + FastPin::lo(); // CS <= LOW (selected) + } + + // NOTE: Make sure each spi_begin() is matched with a single spi_end() (and don't call either twice) + // reset CS back to high (LCD unselected) + static inline void spi_end() __attribute__((always_inline)) + { + FastPin::hi(); // CS <= HIGH (deselected) +#if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) + swapValue(SPCR, save_SPCR); // swap current/initial SPCR settings +#endif + } + +#if defined(AVR_HARDWARE_SPI) + // 10 cycle delay (including "call") + static void delay10() __attribute__((noinline)) __attribute__((naked)) + { + __asm__ __volatile__ + ( + // +4 (call to get here) +#if !defined(__AVR_HAVE_RAMPD__) + " adiw r24,0\n" // +2 (2-cycle NOP) +#else + " nop\n" // +1 (1-cycle NOP) +#endif + " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) + // = 10 cycles + : : : + ); + } + + // 13 cycle delay (including "call") + static void delay13() __attribute__((noinline)) __attribute__((naked)) + { + __asm__ __volatile__ + ( + // +4 (call to get here) + " adiw r24,0\n" // +2 (2-cycle NOP) + " adiw r24,0\n" // +2 (2-cycle NOP) +#if !defined(__AVR_HAVE_RAMPD__) + " nop\n" // +1 (1-cycle NOP) +#endif + " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) + // = 13 cycles + : : : + ); + } + + // 15 cycle delay (including "call") + static void delay15() __attribute__((noinline)) __attribute__((naked)) + { + __asm__ __volatile__ + ( + // +4 (call to get here) + " adiw r24,0\n" // +2 (2-cycle NOP) + " adiw r24,0\n" // +2 (2-cycle NOP) + " adiw r24,0\n" // +2 (2-cycle NOP) +#if !defined(__AVR_HAVE_RAMPD__) + " nop\n" // +1 (1-cycle NOP) +#endif + " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) + // = 15 cycles + : : : + ); + } + + // 17 cycle delay (including "call") + static void delay17() __attribute__((noinline)) __attribute__((naked)) + { + __asm__ __volatile__ + ( + // +4 (call to get here) + " adiw r24,0\n" // +2 (2-cycle NOP) + " adiw r24,0\n" // +2 (2-cycle NOP) + " adiw r24,0\n" // +2 (2-cycle NOP) + " adiw r24,0\n" // +2 (2-cycle NOP) +#if !defined(__AVR_HAVE_RAMPD__) + " nop\n" // +1 (2-cycle NOP) +#endif + " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) + // = 17 cycles + : : : + ); + } + + // normal SPI write with minimal hand-tuned delay (assuming max DIV2 SPI rate) + static INLINE void spiWrite(uint8_t data) INLINE_OPT + { + SPDR = data; + __asm__ __volatile__ + ( + " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) + : : : + ); + } + + // special SPI write with minimal hand-tuned delay (assuming max DIV2 SPI rate) - minus 2 cycles for RS (etc.) change + static INLINE void spiWrite_preCmd(uint8_t data) INLINE_OPT + { + SPDR = data; + + __asm__ __volatile__ + ( + " call _ZN11PDQ_ILI93417delay15Ev\n" // call mangled delay15 (compiler would needlessly save/restore regs) + : : : + ); + } + + // SPI 16-bit write with minimal hand-tuned delay (assuming max DIV2 SPI rate) + static INLINE void spiWrite16(uint16_t data) INLINE_OPT + { + uint8_t temp; + __asm__ __volatile__ + ( + " out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) + " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) + " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) + " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) + + : [temp] "=d" (temp) + : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) + : + ); + } + + // SPI 16-bit write with minimal hand-tuned delay (assuming max DIV2 SPI rate) minus 2 cycles + static INLINE void spiWrite16_preCmd(uint16_t data) INLINE_OPT + { + uint8_t temp; + __asm__ __volatile__ + ( + " out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) + " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) + " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) + " call _ZN11PDQ_ILI93417delay15Ev\n" // call mangled delay15 (compiler would needlessly save/restore regs) + + : [temp] "=d" (temp) + : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) + : + ); + } + + // SPI 16-bit write with minimal hand-tuned delay (assuming max DIV2 SPI rate) minus 4 cycles + static INLINE void spiWrite16_lineDraw(uint16_t data) INLINE_OPT + { + uint8_t temp; + __asm__ __volatile__ + ( + " out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) + " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) + " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) + + : [temp] "=d" (temp) + : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) + : + ); + } + + // normal SPI write with minimal hand-tuned delay (assuming max DIV2 SPI rate) + static INLINE void spiWrite16(uint16_t data, int count) INLINE_OPT + { + uint8_t temp; + __asm__ __volatile__ + ( + " sbiw %[count],0\n" // test count + " brmi 4f\n" // if < 0 then done + " breq 4f\n" // if == 0 then done + "1: out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) + " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) + " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) + " call _ZN11PDQ_ILI93417delay13Ev\n" // call mangled delay13 (compiler would needlessly save/restore regs) + " sbiw %[count],1\n" // +2 decrement count + " brne 1b\n" // +2/1 if != 0 then loop + // = 13 + 2 + 2 (17 cycles) + "4:\n" + + : [temp] "=d" (temp), [count] "+w" (count) + : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) + : + ); + } + +#else // bit-bang +#if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) + // USI hardware assisted + static void spiWrite(uint8_t data) __attribute__((noinline)) + { + USIDR = data; + __asm__ __volatile__ + ( + " out %[spi],%[clkp0]\n" // MSB + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" // LSB + " out %[spi],%[clkp1]\n" + : + : [spi] "i" (_SFR_IO_ADDR(USICR)), [clkp0] "a" ((uint8_t)((1<>8; + __asm__ __volatile__ + ( + " out %[spi],%[clkp0]\n" // MSB + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" + " out %[spi],%[clkp1]\n" + " out %[spi],%[clkp0]\n" // LSB + " out %[spi],%[clkp1]\n" + : + : [spi] "i" (_SFR_IO_ADDR(USICR)), [clkp0] "a" ((uint8_t)((1<>= 1) + { + if (data & bit) + FastPin::hi(); + else + FastPin::lo(); + + FastPin::hi(); + FastPin::lo(); + } + } + static void spiWrite16(uint16_t data) __attribute__((noinline)) + { + spiWrite(data >> 8); + spiWrite(data & 0xff); + } +#endif + static INLINE void spiWrite_preCmd(uint8_t data) INLINE_OPT + { + spiWrite(data); + } + static INLINE void spiWrite16_preCmd(uint16_t data) INLINE_OPT + { + spiWrite16(data); + } + static INLINE void spiWrite16_lineDraw(uint16_t data) INLINE_OPT + { + spiWrite16(data); + } + static INLINE void spiWrite16(uint16_t data, int count) INLINE_OPT + { + while (count-- > 0) + spiWrite16(data); + } + static inline void delay10() { } + static inline void delay13() { } + static inline void delay15() { } + static inline void delay17() { } +#endif + + // write SPI byte with RS (aka D/C) pin set low to indicate a command byte (and then reset back to high when done) + static INLINE void writeCommand(uint8_t data) INLINE_OPT + { + FastPin::lo(); // RS <= LOW indicate command byte + spiWrite_preCmd(data); + FastPin::hi(); // RS <= HIGH indicate data byte (always assumed left in data mode) + } + + // write SPI byte with RS assumed low indicating a data byte + static inline void writeData(uint8_t data) __attribute__((always_inline)) + { + spiWrite(data); + } + + // internal version that does not spi_begin()/spi_end() + static INLINE void setAddrWindow_(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) INLINE_OPT + { + writeCommand(ILI9341_CASET); // column address set + spiWrite16(x0); // XSTART + spiWrite16_preCmd(x1); // XEND + writeCommand(ILI9341_PASET); // row address set + spiWrite16(y0); // YSTART + spiWrite16_preCmd(y1); // YEND + writeCommand(ILI9341_RAMWR); // write to RAM + } + +#if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) + static volatile uint8_t save_SPCR; // initial SPCR value/saved SPCR value (swapped in spi_begin/spi_end) +#endif +}; + +typedef PDQ_GFX_Button_ PDQ_GFX_Button; + +/*************************************************** + This is an Arduino Library for the Adafruit 2.2" SPI display. + This library works with the Adafruit 2.2" TFT Breakout w/SD card + ----> http://www.adafruit.com/products/1480 + + Check out the links above for our tutorials and wiring diagrams + These displays use SPI to communicate, 4 or 5 pins are required to + interface (RST is optional) + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by Limor Fried/Ladyada for Adafruit Industries. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) +// static data needed by base class +volatile uint8_t PDQ_ILI9341::save_SPCR; +#endif + +// Constructor when using hardware SPI. +PDQ_ILI9341::PDQ_ILI9341() : PDQ_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) +{ +#if defined(AVR_HARDWARE_SPI) + // must reference these functions from C++ or they will be stripped by linker (called from inline asm) + delay10(); + delay13(); + delay15(); + delay17(); +#endif +} + +// Companion code to the above tables. Reads and issues +// a series of LCD commands stored in PROGMEM byte array. +void PDQ_ILI9341::commandList(const uint8_t *addr) +{ + uint8_t numCommands, numArgs; + uint16_t ms; + + numCommands = pgm_read_byte(addr++); // Number of commands to follow + while (numCommands--) // For each command... + { + writeCommand(pgm_read_byte(addr++)); // Read, issue command + numArgs = pgm_read_byte(addr++); // Number of args to follow + ms = numArgs & DELAY; // If hibit set, delay follows args + numArgs &= ~DELAY; // Mask out delay bit + while (numArgs--) // For each argument... + { + writeData(pgm_read_byte(addr++)); // Read, issue argument + } + + if (ms) + { + ms = pgm_read_byte(addr++); // Read post-command delay time (ms) + if(ms == 255) + ms = 500; // If 255, delay for 500 ms + delay(ms); + } + } +} + +void PDQ_ILI9341::begin(void) +{ + + // set CS and RS pin directions to output + FastPin::setOutput(); + FastPin::setOutput(); +#if !defined(AVR_HARDWARE_SPI) + #if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + USICR = (0<::setInput(); + #endif + FastPin::setOutput(); + FastPin::setOutput(); + FastPin::lo(); + FastPin::lo(); +#endif + + FastPin::hi(); // CS <= HIGH (deselected, so no spurious data) + FastPin::hi(); // RS <= HIGH (default data byte) + +#if defined(AVR_HARDWARE_SPI) + #if ILI9341_SAVE_SPCR + uint8_t oldSPCR = SPCR; // save initial SPCR settings + #endif + SPI.begin(); + SPI.setBitOrder(MSBFIRST); + SPI.setDataMode(SPI_MODE0); + SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!) [1 byte every 18 cycles] +#endif + +#if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) + save_SPCR = SPCR; // save SPCR settings + SPCR = oldSPCR; // restore previous SPCR settings (spi_begin/spi_end will switch between the two) +#endif + spi_begin(); + + // Initialization commands for ILI9341 screens + static const uint8_t ILI9341_cmds[] PROGMEM = + { + 22, + ILI9341_SWRESET, DELAY, // 1 + 5, + 0xEF, 3, // 2 + 0x03, 0x80, 0x02, + 0xCF, 3, // 3 + 0x00, 0xC1, 0x30, + 0xED, 4, // 4 + 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, // 5 + 0x85, 0x00, 0x78, + 0xCB, 5, // 6 + 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, // 7 + 0x20, + 0xEA, 2, // 8 + 0x00, 0x00, + ILI9341_PWCTR1, 1, // 9 power control + 0x23, // VRH[5:0] + ILI9341_PWCTR2, 1, // 10 power control + 0x10, // SAP[2:0];BT[3:0] + ILI9341_VMCTR1, 2, // 11 VCM control + 0x3e, 0x28, + ILI9341_VMCTR2, 1, // 12 VCM control2 + 0x86, // -- + ILI9341_MADCTL, 1, // 13 + (ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR), + ILI9341_PIXFMT, 1, // 14 + 0x55, + ILI9341_FRMCTR1, 2, // 15 + 0x00, 0x18, + ILI9341_DFUNCTR, 3, // 16 + 0x08, 0x82, 0x27, + 0xF2, 1, // 17 3Gamma Function Disable + 0x00, + ILI9341_GAMMASET, 1, // 18 Gamma curve selected + 0x01, + ILI9341_GMCTRP1, 15, // 19 Set Gamma + 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, + ILI9341_GMCTRN1, 15, // 20 + 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, + ILI9341_SLPOUT, DELAY, // 21 + 120, + ILI9341_DISPON, 0, // 22 + }; + + commandList(ILI9341_cmds); + + spi_end(); +} + +void PDQ_ILI9341::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) +{ + spi_begin(); + + setAddrWindow_(x0, y0, x1, y1); + + spi_end(); +} + +void PDQ_ILI9341::pushColor(uint16_t color) +{ + spi_begin(); + + spiWrite16_preCmd(color); + + spi_end(); +} + +void PDQ_ILI9341::pushColor(uint16_t color, int count) +{ + spi_begin(); + + spiWrite16(color, count); + + spi_end(); +} + +void PDQ_ILI9341::drawPixel(int x, int y, uint16_t color) +{ + if ((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) + return; + + spi_begin(); + + setAddrWindow_(x, y, x, y); + + spiWrite16_preCmd(color); + + spi_end(); +} + +void PDQ_ILI9341::drawFastVLine(int x, int y, int h, uint16_t color) +{ + // clipping + if ((x < 0) || (x >= _width) || (y >= _height)) + return; + + if (y < 0) + { + h += y; + y = 0; + } + + int y1 = y+h; + + if (y1 < 0) + return; + + if (y1 > _height) + h = _height-y; + + spi_begin(); + + setAddrWindow_(x, y, x, _height); + spiWrite16(color, h); + + spi_end(); +} + + +void PDQ_ILI9341::drawFastHLine(int x, int y, int w, uint16_t color) +{ + // clipping + if ((x >= _width) || (y < 0) || (y >= _height)) + return; + + if (x < 0) + { + w += x; + x = 0; + } + + int x1 = x+w; + + if (x1 < 0) + return; + + if (x1 > _width) + w = _width-w; + + spi_begin(); + + setAddrWindow_(x, y, _width, y); + spiWrite16(color, w); + + spi_end(); +} + +void PDQ_ILI9341::fillRect(int x, int y, int w, int h, uint16_t color) +{ + // rudimentary clipping (drawChar w/big text requires this) + if ((x >= _width) || (y >= _height)) + return; + if (x < 0) + { + w += x; + x = 0; + } + if (y < 0) + { + h += y; + y = 0; + } + if ((x + w) > _width) + w = _width - x; + if ((y + h) > _height) + h = _height - y; + + spi_begin(); + + setAddrWindow_(x, y, x+w-1, _height); + + for (; h > 0; h--) + { + spiWrite16(color, w); + } + + spi_end(); +} + +// Bresenham's algorithm - thx Wikipedia +void PDQ_ILI9341::drawLine(int x0, int y0, int x1, int y1, uint16_t color) +{ +#if 0 && defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) + drawLine_(x0, y0, x1, y1, color); +#else + int8_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) + { + swapValue(x0, y0); + swapValue(x1, y1); + } + + if (x0 > x1) + { + swapValue(x0, x1); + swapValue(y0, y1); + } + + if (x1 < 0) + return; + + int dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int err = dx / 2; + int8_t ystep; + + if (y0 < y1) + { + ystep = 1; + } + else + { + ystep = -1; + } + + uint8_t setaddr = 1; + +#if 0 && defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny45__) + int end = steep ? _height-1 : _width-1; + if (x1 > end) + x1 = end; + + for (; x0 <= x1; x0++) + { + if ((x0 >= 0) && (y0 >= 0) && (y0 <= end)) + break; + + err -= dy; + if (err < 0) + { + err += dx; + y0 += ystep; + } + } + + if (x0 > x1) + return; + + spi_begin(); + + for (; x0 <= x1; x0++) + { + if (setaddr) + { + if (steep) + setAddrWindow_(y0, x0, y0, end+1); + else + setAddrWindow_(x0, y0, end+1, y0); + setaddr = 0; + } + spiWrite16_lineDraw(color); + err -= dy; + if (err < 0) + { + y0 += ystep; + if ((y0 < 0) || (y0 > end)) + break; + err += dx; + setaddr = 1; + } + } +#else + if (steep) // y increments every iteration (y0 is x-axis, and x0 is y-axis) + { + if (x1 >= _height) + x1 = _height - 1; + + for (; x0 <= x1; x0++) + { + if ((x0 >= 0) && (y0 >= 0) && (y0 < _width)) + break; + + err -= dy; + if (err < 0) + { + err += dx; + y0 += ystep; + } + } + + if (x0 > x1) + return; + + spi_begin(); + + for (; x0 <= x1; x0++) + { + if (setaddr) + { + setAddrWindow_(y0, x0, y0, _height); + setaddr = 0; + } + spiWrite16_lineDraw(color); + err -= dy; + if (err < 0) + { + y0 += ystep; + if ((y0 < 0) || (y0 >= _width)) + break; + err += dx; + setaddr = 1; + } +#if defined(AVR_HARDWARE_SPI) + else + { + __asm__ __volatile__ + ( + " call _ZN11PDQ_ILI93417delay10Ev\n" + : : : + ); + } +#endif + } + } + else // x increments every iteration (x0 is x-axis, and y0 is y-axis) + { + if (x1 >= _width) + x1 = _width - 1; + + for (; x0 <= x1; x0++) + { + if ((x0 >= 0) && (y0 >= 0) && (y0 < _height)) + break; + + err -= dy; + if (err < 0) + { + err += dx; + y0 += ystep; + } + } + + if (x0 > x1) + return; + + spi_begin(); + + for (; x0 <= x1; x0++) + { + if (setaddr) + { + setAddrWindow_(x0, y0, _width, y0); + setaddr = 0; + } + spiWrite16_lineDraw(color); + err -= dy; + if (err < 0) + { + y0 += ystep; + if ((y0 < 0) || (y0 >= _height)) + break; + err += dx; + setaddr = 1; + } +#if defined(AVR_HARDWARE_SPI) + else + { + __asm__ __volatile__ + ( + " call _ZN11PDQ_ILI93417delay10Ev\n" + : : : + ); + } +#endif + } + } +#endif + + spi_end(); +#endif +} + +void PDQ_ILI9341::setRotation(uint8_t m) +{ + rotation = (m & 3); // can't be higher than 3 + + spi_begin(); + + writeCommand(ILI9341_MADCTL); + + switch (rotation) + { + default: + case 0: + writeData(ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR); + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; + break; + case 1: + writeData(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); + _width = ILI9341_TFTHEIGHT; + _height = ILI9341_TFTWIDTH; + break; + case 2: + writeData(ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR); + _width = ILI9341_TFTWIDTH; + _height = ILI9341_TFTHEIGHT; + break; + case 3: + writeData(ILI9341_MADCTL_MV | ILI9341_MADCTL_MY | ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR); + _width = ILI9341_TFTHEIGHT; + _height = ILI9341_TFTWIDTH; + break; + } + + spi_end(); +} + +void PDQ_ILI9341::invertDisplay(boolean i) +{ + spi_begin(); + + writeCommand(i ? ILI9341_INVON : ILI9341_INVOFF); + + spi_end(); +} + +#endif // !defined(_PDQ_ILI9341H_) diff --git a/PDQ_MinLib/README.md b/PDQ_MinLib/README.md new file mode 100644 index 0000000..48bd2e5 --- /dev/null +++ b/PDQ_MinLib/README.md @@ -0,0 +1,51 @@ +PDQ_GFX_Libs with packed font support +============ +Version with special "packed" font support. Also include TTF2GFX for create custom GFX fonts from TTF. +Speed up improvement for GFX text drawing about 2-3 times. +Allow to create custom fonts with subset of chars (not all ASCII table). +Special "packing" algorithm for GFX font allow to save 20-50% of space + +PDQ_GFX_Libs +============ + +An optimized fork of Adafruit's GFX library (and LCD drivers) for Arduino (AVR). + +This is a replacement "re-mix" of the Adafruit GFX library and associated hardware drivers. + +Currently supported are ILI9340, ILI9341, ST7735 and ST7781 LCD drivers (and compatible chipsets). + +It is between 2.5x and 12x faster than the Adafruit libraries for SPI LCDs, but it aims to be completely "sketch compatible" (so you +can easily speed up your sketches that are using Adafruit's library). You just need to change the name of the #include and "tft" +object. A version of the Adafruit "benchmark" example is included (PDQ_graphicsbest.ino) with each driver library. + +This includes the 1.8", 2.2" and 2.8" SPI TFT LCD boards or "touch shields" that are commonly available from Adafruit and +many other vendors. These are commonly 128x128, 128x160 or 240x320 (but the library supports rotation). + +I would also like to thank the excellent http://fastled.io/ project for creating the "FastPin.h" template header that allows +for full speed GPIO while allowing the use of "friendly" Arduino pin numbering (it is included in the PDQ driver libraries). + +New features in latest commit ("v1.1.5" 2016-04-09) include: + + * Synced core functions with Adafruit_GFX (few changes - I think their clipping is still broken [fixed in PDQ_GFX]) + * Support for new fonts as seen in Adafruit_GFX GitHub + * Minor bugfixes + +New features in latest commit ("v1.0.0" 2015-05-30) include: + + * Arduino IDE 1.6.x support (mainly information in library.properties, but also tested and 100% warning free). + * New ATtiny85 support for IL934x using USI SPI (not quite as fast as 328P - but can run 20MHz PLL to make up). + * New support for parallel ST7781 driver as used in Seeed Studio 2.8" Touch Shield (also sold by Radio Shack). This is the fastest LCD supported currently. + * "Bit-banged" SPI support. Not as fast, but can use (nearly) any pins. + * Added pushColor with a count that can speed up application rendering runs of same color. + * Tidied up files and made sure all drivers were updated with latest tweaks. + +Suggestions, issues, bugs and comments welcome. Via https://hackaday.io/Xark or visit #Arduino channel on Freenode.net IRC. +I have also posted a write-up about the development of this library at http://hackaday.io/Xark (describes most of the optimizations done). + + +Issues +------ + +Currently, the library may only be used from the INO file in your project. You _cannot_ include it in a header file and +use it from other CPP files. The current workaround is to write wrapper functions or classes, declare them in a header +file, and then implement them in the INO file. \ No newline at end of file diff --git a/PDQ_MinLib/gfxfont.h b/PDQ_MinLib/gfxfont.h new file mode 100644 index 0000000..78f3a47 --- /dev/null +++ b/PDQ_MinLib/gfxfont.h @@ -0,0 +1,29 @@ +// This is the PDQ re-mixed version of Adafruit's library from Xark +// here is the original copyright notice and license: + +// Font structures for newer Adafruit_GFX (1.1 and later). +// Example fonts are included in 'Fonts' directory. +// To use a font in your Arduino sketch, #include the corresponding .h +// file and pass address of GFXfont struct to setFont(). Pass NULL to +// revert to 'classic' fixed-space bitmap font. + +#ifndef _GFXFONT_H_ +#define _GFXFONT_H_ + +struct GFXglyph // Data stored PER GLYPH +{ + uint16_t bitmapOffset; // Pointer into GFXfont->bitmap + uint8_t width, height; // Bitmap dimensions in pixels + uint8_t xAdvance; // Distance to advance cursor (x axis) + int8_t xOffset, yOffset; // Dist from cursor pos to UL corner +}; + +struct GFXfont // Data stored for FONT AS A WHOLE: +{ + uint8_t *bitmap; // Glyph bitmaps, concatenated + GFXglyph *glyph; // Glyph array + uint8_t first, last; // ASCII extents + uint8_t yAdvance; // Newline distance (y axis) +}; + +#endif // _GFXFONT_H_ diff --git a/PDQ_MinLib/glcdfont.c b/PDQ_MinLib/glcdfont.c new file mode 100644 index 0000000..7231f92 --- /dev/null +++ b/PDQ_MinLib/glcdfont.c @@ -0,0 +1,278 @@ +// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. +// See gfxfont.h for newer custom bitmap font info. + +#ifndef FONT5X7_H +#define FONT5X7_H + +#ifdef __AVR__ + #include + #include +#elif defined(ESP8266) + #include +#else + #define PROGMEM +#endif + +// Standard ASCII 5x7 font + +const unsigned char glcdfont[] PROGMEM = + { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x22, 0x54, 0x54, 0x78, 0x42, // a-umlaut + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0x7D, 0x12, 0x11, 0x12, 0x7D, // A-umlaut + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x3A, 0x44, 0x44, 0x44, 0x3A, // o-umlaut + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x3D, 0x42, 0x42, 0x42, 0x3D, // O-umlaut + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0x55, 0x00, 0x55, 0x00, 0x55, // #176 (25% block) missing in old code + 0xAA, 0x55, 0xAA, 0x55, 0xAA, // 50% block + 0xFF, 0x55, 0xFF, 0x55, 0xFF, // 75% block + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0xFC, 0x4A, 0x4A, 0x4A, 0x34, // sharp-s or beta + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00 // #255 NBSP +}; + +#endif // FONT5X7_H diff --git a/glcdfont.c b/glcdfont.c new file mode 100644 index 0000000..c2c52ca --- /dev/null +++ b/glcdfont.c @@ -0,0 +1,6 @@ +//Include the font so that it's built by the arduino +//default builder, despite being in a subdirectory +//#include "PDQ_MinLib/glcdfont.c" + +#include +const unsigned char glcdfont[] PROGMEM = {0}; \ No newline at end of file diff --git a/nano_font.cpp b/nano_font.cpp new file mode 100644 index 0000000..9d4803c --- /dev/null +++ b/nano_font.cpp @@ -0,0 +1,337 @@ +#include "nano_font.h" +#include + +const uint8_t ubitxBitmaps[] PROGMEM = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, + 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, + 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, + 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, + 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, + 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, + 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, + 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, + 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, + 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, + 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, + 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, + 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, + 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0x21, 0xFF, 0xE0, 0xF3, 0xF9, 0xFC, 0xFE, 0x7E, + 0x3B, 0x1D, 0x84, 0x0E, 0x70, 0x73, 0x83, 0x9C, 0x18, 0xC7, 0xFF, 0xBF, + 0xFD, 0xFF, 0xE3, 0x9C, 0x18, 0xC0, 0xC6, 0x0E, 0x7D, 0xFF, 0xEF, 0xFF, + 0x18, 0xC0, 0xC6, 0x0E, 0x70, 0x73, 0x83, 0x9C, 0x00, 0x04, 0x01, 0xF8, + 0x7F, 0xCF, 0xDE, 0xE4, 0xEE, 0x4E, 0xE4, 0x0F, 0x40, 0x7E, 0x03, 0xFC, + 0x0F, 0xE0, 0x5E, 0x04, 0xFE, 0x4F, 0xE4, 0xFF, 0x4E, 0x7F, 0xE3, 0xFC, + 0x04, 0x00, 0x40, 0x04, 0x00, 0x3C, 0x06, 0x07, 0xE0, 0x60, 0xFF, 0x0C, + 0x0C, 0x30, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xFF, 0x30, 0x07, 0xE6, + 0x00, 0x3C, 0x60, 0x00, 0x0C, 0x7C, 0x00, 0xCF, 0xE0, 0x19, 0xC6, 0x01, + 0x98, 0x70, 0x31, 0x87, 0x03, 0x1C, 0x60, 0x60, 0xFE, 0x04, 0x07, 0xC0, + 0x0F, 0x80, 0x1F, 0xC0, 0x3D, 0xE0, 0x38, 0xE0, 0x3C, 0xE0, 0x1D, 0xC0, + 0x1F, 0xC0, 0x0F, 0x00, 0x3F, 0x8C, 0x7B, 0xDC, 0x71, 0xDC, 0xF1, 0xFC, + 0xF0, 0xF8, 0xF0, 0x78, 0x79, 0xFC, 0x7F, 0xFC, 0x3F, 0x9E, 0x00, 0x00, + 0xFF, 0xFF, 0xE6, 0x60, 0x0C, 0x71, 0x8E, 0x31, 0xC7, 0x38, 0xE3, 0x8E, + 0x38, 0xE3, 0x8E, 0x38, 0x71, 0xC7, 0x0E, 0x38, 0x70, 0xC0, 0xC3, 0x86, + 0x1C, 0x70, 0xE3, 0x8E, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xCE, 0x38, 0xE7, + 0x1C, 0x63, 0x8C, 0x00, 0x10, 0x10, 0x10, 0xFE, 0x7C, 0x38, 0x6C, 0x44, + 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x60, + 0x06, 0x00, 0x60, 0x06, 0x00, 0xFF, 0xF2, 0xFE, 0xFF, 0xFF, 0xC0, 0xFF, + 0xF0, 0x04, 0x08, 0x30, 0x60, 0x83, 0x06, 0x08, 0x10, 0x60, 0xC1, 0x06, + 0x0C, 0x10, 0x20, 0xC0, 0x3F, 0x8F, 0xF9, 0xEF, 0x78, 0xFE, 0x0F, 0xC1, + 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xE3, 0xDE, + 0xF3, 0xFE, 0x3F, 0x80, 0x80, 0x06, 0x1C, 0x7F, 0xFF, 0xE1, 0xC3, 0x87, + 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x3F, 0x8F, 0xFB, 0xEF, + 0xF8, 0x7E, 0x0F, 0xC1, 0xC0, 0x38, 0x0F, 0x03, 0xC0, 0xF0, 0x7C, 0x1F, + 0x07, 0x80, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0x8F, 0xFB, 0xCF, + 0xF0, 0xFE, 0x1E, 0x03, 0xC0, 0x70, 0x7C, 0x0F, 0xC0, 0xFC, 0x03, 0x80, + 0x7E, 0x0F, 0xC1, 0xFC, 0xFB, 0xFE, 0x3F, 0x80, 0x80, 0x07, 0xC0, 0x7C, + 0x0F, 0xC0, 0xFC, 0x1F, 0xC3, 0xBC, 0x33, 0xC7, 0x3C, 0x63, 0xCE, 0x3C, + 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3F, + 0xEF, 0xFD, 0xFF, 0xB8, 0x06, 0x00, 0xC0, 0x1F, 0xE7, 0xFE, 0xF1, 0xE0, + 0x1C, 0x03, 0x80, 0x70, 0x0F, 0xC1, 0xFC, 0xFB, 0xFE, 0x3F, 0x80, 0x80, + 0x1F, 0x87, 0xF9, 0xE7, 0xB8, 0x7E, 0x01, 0xC0, 0x3B, 0xE7, 0xFE, 0xFB, + 0xFE, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xE1, 0xDE, 0xFB, 0xFE, 0x3F, 0x80, + 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0E, 0x01, 0xC0, 0x3C, 0x03, 0x80, + 0x70, 0x0F, 0x00, 0xE0, 0x0E, 0x01, 0xE0, 0x1C, 0x01, 0xC0, 0x1C, 0x03, + 0xC0, 0x3C, 0x00, 0x3F, 0x87, 0xFC, 0xF9, 0xEE, 0x0E, 0xE0, 0xEE, 0x0E, + 0x71, 0xC3, 0xF8, 0x7F, 0xCF, 0x1E, 0xE0, 0xEE, 0x0F, 0xE0, 0xFE, 0x0E, + 0xF1, 0xE7, 0xFC, 0x3F, 0x80, 0x40, 0x3F, 0x0F, 0xFB, 0xEF, 0x70, 0xFE, + 0x0F, 0xC1, 0xF8, 0x3F, 0x0F, 0xF3, 0xEF, 0xFC, 0xFB, 0x80, 0x70, 0x0F, + 0xC3, 0xFE, 0xF3, 0xFE, 0x3F, 0x80, 0x80, 0xFF, 0x80, 0x00, 0xFF, 0xF0, + 0xFF, 0x80, 0x00, 0xFF, 0xF2, 0xDE, 0x00, 0x70, 0x1F, 0x0F, 0xE7, 0xF0, + 0xF8, 0x0E, 0x00, 0xFC, 0x03, 0xF8, 0x0F, 0xE0, 0x1F, 0x00, 0x30, 0xFF, + 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xC0, 0x0F, 0x80, 0x7F, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0x03, 0xF1, + 0xFC, 0xFE, 0x0F, 0x80, 0xC0, 0x00, 0x1F, 0x0F, 0xF3, 0xFF, 0x78, 0xFE, + 0x0F, 0xC1, 0xC0, 0x38, 0x0F, 0x03, 0xE0, 0xF8, 0x3C, 0x07, 0x00, 0xE0, + 0x00, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xFE, + 0x00, 0xF0, 0x3C, 0x07, 0x00, 0x38, 0x38, 0x00, 0x30, 0xC0, 0x00, 0xE6, + 0x0F, 0xF1, 0x98, 0x73, 0xC7, 0xC3, 0x87, 0x0F, 0x0C, 0x1C, 0x3C, 0x30, + 0x61, 0xF1, 0xC1, 0x86, 0xC7, 0x0E, 0x1B, 0x1C, 0x38, 0xEC, 0x3B, 0xEF, + 0x38, 0xFD, 0xF8, 0x70, 0xC1, 0x80, 0xE0, 0x00, 0x01, 0xC0, 0x10, 0x03, + 0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0xE0, 0x07, + 0xE0, 0x0F, 0xE0, 0x0E, 0xF0, 0x0E, 0xF0, 0x1E, 0x70, 0x1C, 0x78, 0x1C, + 0x78, 0x3C, 0x38, 0x3F, 0xFC, 0x3F, 0xFC, 0x7F, 0xFC, 0x70, 0x1E, 0xF0, + 0x1E, 0xF0, 0x0E, 0xE0, 0x0F, 0xFF, 0x03, 0xFF, 0xCF, 0xFF, 0xBC, 0x7E, + 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBF, 0xFE, 0xFF, 0xE3, 0xFF, 0xCF, 0x0F, + 0xBC, 0x0F, 0xF0, 0x1F, 0xC0, 0xFF, 0x03, 0xFF, 0xFE, 0xFF, 0xFB, 0xFF, + 0x80, 0x03, 0xC0, 0x1F, 0xF0, 0xFF, 0xF1, 0xF1, 0xE7, 0x81, 0xEF, 0x01, + 0xFC, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, + 0x00, 0xEF, 0x01, 0xDE, 0x07, 0x9F, 0xFE, 0x1F, 0xFC, 0x1F, 0xE0, 0x04, + 0x00, 0xFE, 0x03, 0xFF, 0x8F, 0xFF, 0x38, 0x7E, 0xE0, 0x7B, 0x80, 0xFE, + 0x03, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x3F, + 0x80, 0xFE, 0x07, 0xBF, 0xFE, 0xFF, 0xF3, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFE, 0xFF, 0xF7, + 0xFF, 0xBC, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xE0, 0x0E, 0x00, + 0xE0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, + 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x03, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC, + 0x3E, 0x3E, 0x78, 0x0F, 0x70, 0x0F, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, + 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x07, 0x78, 0x0F, 0x7C, 0x1F, + 0x3F, 0xFF, 0x1F, 0xFB, 0x0F, 0xF3, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, + 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, + 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, + 0x80, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xE0, 0x3C, + 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, + 0x80, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0xFE, 0xFF, 0xCF, 0xF0, 0x00, 0x00, + 0xE0, 0x3D, 0xC0, 0xFB, 0x83, 0xE7, 0x07, 0x8E, 0x1E, 0x1C, 0x78, 0x39, + 0xE0, 0x77, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0xFE, 0x07, 0x9E, 0x0E, 0x1E, + 0x1C, 0x1E, 0x38, 0x3C, 0x70, 0x3C, 0xE0, 0x3D, 0xC0, 0x3C, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xF8, 0x1F, 0xFC, 0x0F, 0xFE, 0x07, 0xFF, 0x83, 0xFF, 0xC3, 0xFF, + 0xE1, 0xFF, 0xB0, 0xFF, 0xDC, 0x6F, 0xEE, 0x77, 0xF7, 0x3B, 0xF9, 0x9D, + 0xFC, 0xCC, 0xFE, 0x76, 0x7F, 0x3F, 0x3F, 0x8F, 0x9F, 0xC7, 0xCF, 0xE3, + 0xC7, 0xF1, 0xE3, 0xC0, 0xE0, 0x3F, 0xC0, 0xFF, 0x03, 0xFE, 0x0F, 0xFC, + 0x3F, 0xF0, 0xFE, 0xE3, 0xFB, 0x8F, 0xE7, 0x3F, 0x9E, 0xFE, 0x3B, 0xF8, + 0xFF, 0xE1, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x1F, 0xE0, 0x7F, 0x80, 0xF0, + 0x03, 0xE0, 0x07, 0xFC, 0x07, 0xFF, 0x07, 0xCF, 0xC7, 0x81, 0xF3, 0xC0, + 0x7B, 0xC0, 0x1D, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, + 0x00, 0xFF, 0x00, 0x73, 0xC0, 0x79, 0xF0, 0x7C, 0x7F, 0xFC, 0x1F, 0xFC, + 0x07, 0xFC, 0x00, 0x20, 0x00, 0xFF, 0x07, 0xFF, 0x3F, 0xFD, 0xC3, 0xFE, + 0x07, 0xF0, 0x1F, 0x80, 0xFC, 0x0F, 0xE0, 0xFF, 0xFF, 0xBF, 0xF9, 0xFF, + 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x03, + 0xE0, 0x07, 0xFC, 0x07, 0xFF, 0x07, 0xCF, 0xC7, 0x80, 0xF3, 0xC0, 0x7B, + 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, 0x04, + 0xFF, 0x07, 0x73, 0xC3, 0xF9, 0xF0, 0xFC, 0x7F, 0xFC, 0x1F, 0xFF, 0x07, + 0xFF, 0xC0, 0x20, 0xC0, 0xFF, 0x83, 0xFF, 0xCF, 0xFF, 0xBC, 0x3F, 0xF0, + 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xFF, 0xFB, 0xFF, 0x8F, 0xFF, 0xBC, + 0x1E, 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBC, 0x0E, 0xF0, 0x3F, 0xC0, 0xF0, + 0x0F, 0x80, 0xFF, 0xC7, 0xFF, 0xBE, 0x1E, 0xF0, 0x3B, 0xC0, 0xFF, 0x00, + 0x3F, 0x80, 0x7F, 0xE0, 0xFF, 0xE0, 0x3F, 0xC0, 0x0F, 0x00, 0x1F, 0x80, + 0x7F, 0x03, 0xFF, 0x1F, 0x7F, 0xF8, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, + 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, + 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, + 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFE, + 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0xC0, 0xFF, 0x07, 0x9F, 0xFE, 0x7F, 0xF0, + 0x7F, 0x80, 0x20, 0x00, 0xE0, 0x1F, 0xC0, 0x3B, 0xC0, 0xF3, 0x81, 0xE7, + 0x03, 0x8F, 0x0F, 0x0E, 0x1C, 0x1C, 0x38, 0x3C, 0x70, 0x39, 0xC0, 0x73, + 0x80, 0xE7, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x03, 0xC0, 0x07, 0x80, + 0x0F, 0x00, 0xF0, 0x38, 0x1D, 0xC1, 0xE0, 0xF7, 0x87, 0xC3, 0xDE, 0x1F, + 0x0F, 0x78, 0x7C, 0x38, 0xE3, 0xB0, 0xE3, 0x8E, 0xC7, 0x8F, 0x3B, 0x9C, + 0x1C, 0xEE, 0x70, 0x73, 0x39, 0xC1, 0xDC, 0x67, 0x07, 0x71, 0xB8, 0x0F, + 0xC7, 0xE0, 0x3E, 0x1F, 0x80, 0xF8, 0x3E, 0x01, 0xE0, 0xF0, 0x07, 0x83, + 0xC0, 0x1E, 0x0F, 0x00, 0xF0, 0x3D, 0xF0, 0x79, 0xE1, 0xE1, 0xE3, 0xC3, + 0xCF, 0x03, 0xFC, 0x07, 0xF8, 0x07, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x3F, + 0x00, 0x7F, 0x01, 0xFE, 0x07, 0x9E, 0x0F, 0x3C, 0x3C, 0x3C, 0xF8, 0x3D, + 0xE0, 0x78, 0xF0, 0x1F, 0xE0, 0x79, 0xE0, 0xF3, 0xC3, 0xC3, 0xC7, 0x87, + 0x9E, 0x07, 0x3C, 0x0F, 0x70, 0x0F, 0xE0, 0x1F, 0x80, 0x1F, 0x00, 0x3C, + 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x80, + 0x78, 0x07, 0x80, 0x78, 0x07, 0x80, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, + 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xCE, 0x73, 0x9C, 0xE7, + 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCF, 0xFF, 0xE0, 0xC1, 0x81, 0x02, + 0x06, 0x04, 0x08, 0x18, 0x30, 0x20, 0x60, 0xC0, 0x81, 0x83, 0x02, 0x06, + 0xFF, 0xFF, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, + 0x1C, 0x71, 0xC7, 0xFF, 0xFF, 0xC0, 0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xF8, + 0x1B, 0x83, 0x9C, 0x39, 0xC3, 0x0C, 0x70, 0xE7, 0x0E, 0xE0, 0x70, 0xFF, + 0xFF, 0xFF, 0xFC, 0x71, 0x86, 0x3F, 0x87, 0xFC, 0xFF, 0xEE, 0x1E, 0x01, + 0xE0, 0xFE, 0x7F, 0xEF, 0x8E, 0xE1, 0xEE, 0x1E, 0xF3, 0xEF, 0xFE, 0x7E, + 0xE1, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x7B, 0xE3, + 0xFF, 0x9F, 0xFE, 0xF8, 0xF7, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, + 0x3F, 0xC1, 0xDF, 0x9E, 0xFF, 0xE7, 0xFE, 0x00, 0x40, 0x1F, 0x83, 0xFC, + 0x7F, 0xEF, 0x0E, 0xE0, 0xEE, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0x0E, + 0x79, 0xE7, 0xFC, 0x3F, 0x80, 0x00, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, + 0x00, 0x71, 0xE7, 0x3F, 0xF7, 0xFF, 0xF0, 0xFE, 0x0F, 0xE0, 0x7E, 0x07, + 0xE0, 0x7E, 0x0F, 0xF0, 0xF7, 0x9F, 0x7F, 0xF3, 0xF7, 0x00, 0x00, 0x1F, + 0x07, 0xFC, 0x7B, 0xEE, 0x0E, 0xE0, 0xEF, 0xFE, 0xFF, 0xFF, 0xFF, 0xE0, + 0x0E, 0x0E, 0xF1, 0xE7, 0xFC, 0x3F, 0x80, 0x40, 0x00, 0x1E, 0x3E, 0x3C, + 0x3C, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, + 0x3C, 0x3C, 0x1E, 0x73, 0xF7, 0x7F, 0xFF, 0x0F, 0xF0, 0xFE, 0x07, 0xE0, + 0x7E, 0x07, 0xE0, 0x7F, 0x0F, 0x79, 0xF7, 0xFF, 0x3F, 0x70, 0x07, 0x00, + 0x7F, 0x0F, 0x7F, 0xE3, 0xFC, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, + 0xDF, 0x3F, 0xF7, 0xFF, 0xF1, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, + 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1C, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFC, 0x39, 0xCE, 0x70, 0x1C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, + 0xCE, 0x7F, 0xFF, 0xC0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, + 0x0E, 0xF1, 0xEF, 0x3C, 0xF7, 0x8F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x8F, + 0x3C, 0xF3, 0xCF, 0x1E, 0xF1, 0xEF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFC, 0xF7, 0xCF, 0x9F, 0xFF, 0xFB, 0xFF, 0xFF, 0xF8, 0x78, 0xFF, + 0x0E, 0x1F, 0xE1, 0xC3, 0xFC, 0x38, 0x7F, 0x87, 0x0F, 0xF0, 0xE1, 0xFE, + 0x1C, 0x3F, 0xC3, 0x87, 0xF8, 0x70, 0xFF, 0x0E, 0x1E, 0xEF, 0x9F, 0xFB, + 0xFF, 0xF8, 0xFE, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, + 0xF0, 0x7E, 0x0E, 0x1F, 0x81, 0xFF, 0x1F, 0xFD, 0xE1, 0xEF, 0x07, 0x70, + 0x3F, 0x81, 0xFC, 0x0F, 0xE0, 0x7F, 0x83, 0x9E, 0x3C, 0xFF, 0xC3, 0xFC, + 0x01, 0x00, 0xF7, 0xC7, 0xFF, 0x3F, 0xFD, 0xF1, 0xEF, 0x07, 0xF8, 0x3F, + 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xBE, 0x3D, 0xFF, 0xCF, 0x7C, 0x78, + 0x83, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x00, 0x1E, 0x77, 0xF7, 0x7F, + 0xFF, 0x0F, 0xE0, 0xFE, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0xFF, 0x0F, 0xF9, + 0xF7, 0xFF, 0x3F, 0x70, 0x47, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0xEF, + 0xFF, 0xFF, 0x8E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x00, 0x3F, + 0x8F, 0xFB, 0xEF, 0xF8, 0x7F, 0x01, 0xFE, 0x1F, 0xF0, 0xFF, 0x01, 0xFC, + 0x1F, 0xC3, 0xFF, 0xF7, 0xFC, 0x08, 0x00, 0x38, 0x70, 0xE7, 0xFF, 0xFF, + 0xCE, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0F, 0x8F, 0x04, 0xF0, 0x7F, + 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, + 0x0F, 0x79, 0xF7, 0xFF, 0x3F, 0x70, 0x80, 0xF0, 0x7B, 0x83, 0x9E, 0x1C, + 0x71, 0xE3, 0x8E, 0x1E, 0x70, 0x73, 0x83, 0xB8, 0x1D, 0xC0, 0x7E, 0x03, + 0xE0, 0x1F, 0x00, 0x78, 0x00, 0xF0, 0xE1, 0xDC, 0x78, 0x77, 0x1F, 0x3D, + 0xC7, 0xCE, 0x79, 0xF3, 0x8E, 0xEC, 0xE3, 0xBB, 0x78, 0xEC, 0xFC, 0x1F, + 0x3F, 0x07, 0xCF, 0xC1, 0xF1, 0xE0, 0x7C, 0x78, 0x0E, 0x1E, 0x00, 0x78, + 0xF3, 0xC7, 0x8F, 0x78, 0x3B, 0x81, 0xFC, 0x07, 0xC0, 0x1E, 0x01, 0xF0, + 0x1F, 0xC0, 0xEF, 0x0F, 0x78, 0xF1, 0xE7, 0x87, 0x80, 0xF0, 0x7B, 0x83, + 0x9E, 0x1C, 0xF1, 0xE3, 0x8E, 0x1E, 0x70, 0x73, 0x83, 0xB8, 0x1D, 0xC0, + 0x7E, 0x03, 0xE0, 0x1F, 0x00, 0x78, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x3E, + 0x01, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x1E, 0x0F, 0x83, 0xC1, 0xE0, + 0xF0, 0x78, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0x3C, 0xF9, 0xC3, + 0x87, 0x0E, 0x1C, 0x38, 0x73, 0xC7, 0x0F, 0x07, 0x0E, 0x1C, 0x38, 0x70, + 0xE1, 0xC3, 0xE7, 0xC7, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xC3, + 0xCF, 0x0C, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0xC7, 0x3C, 0xE3, 0x8E, 0x38, + 0xE3, 0x8E, 0xF3, 0xCE, 0x00, 0x10, 0x0F, 0x85, 0xBD, 0xE1, 0xF0, 0x08, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, + 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, + 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0 }; + +const GFXglyph ubitxGlyphs[] PROGMEM = { + { 0, 13, 18, 17, 2, -17 }, // 0x14 + { 30, 13, 18, 17, 2, -17 }, // 0x15 + { 60, 13, 18, 17, 2, -17 }, // 0x16 + { 90, 13, 18, 17, 2, -17 }, // 0x17 + { 120, 13, 18, 17, 2, -17 }, // 0x18 + { 150, 13, 18, 17, 2, -17 }, // 0x19 + { 180, 13, 18, 17, 2, -17 }, // 0x1A + { 210, 13, 18, 17, 2, -17 }, // 0x1B + { 240, 13, 18, 17, 2, -17 }, // 0x1C + { 270, 13, 18, 17, 2, -17 }, // 0x1D + { 300, 13, 18, 17, 2, -17 }, // 0x1E + { 330, 13, 18, 17, 2, -17 }, // 0x1F + { 360, 0, 0, 7, 0, 1 }, // 0x20 ' ' + { 360, 3, 17, 8, 3, -16 }, // 0x21 '!' + { 367, 9, 7, 11, 1, -17 }, // 0x22 '"' + { 375, 13, 18, 13, 0, -16 }, // 0x23 '#' + { 405, 12, 21, 13, 1, -17 }, // 0x24 '$' + { 437, 20, 17, 21, 1, -16 }, // 0x25 '%' + { 480, 16, 18, 17, 1, -16 }, // 0x26 '&' + { 516, 4, 7, 6, 1, -17 }, // 0x27 ''' + { 520, 6, 23, 8, 1, -17 }, // 0x28 '(' + { 538, 6, 23, 8, 1, -17 }, // 0x29 ')' + { 556, 8, 8, 9, 1, -17 }, // 0x2A '*' + { 564, 12, 11, 14, 1, -10 }, // 0x2B '+' + { 581, 3, 8, 7, 2, -3 }, // 0x2C ',' + { 584, 6, 3, 8, 1, -7 }, // 0x2D '-' + { 587, 3, 4, 7, 2, -3 }, // 0x2E '.' + { 589, 7, 17, 7, 0, -16 }, // 0x2F '/' + { 604, 11, 18, 13, 1, -16 }, // 0x30 '0' + { 629, 7, 17, 13, 2, -16 }, // 0x31 '1' + { 644, 11, 17, 13, 1, -16 }, // 0x32 '2' + { 668, 11, 18, 13, 1, -16 }, // 0x33 '3' + { 693, 12, 17, 13, 1, -16 }, // 0x34 '4' + { 719, 11, 18, 13, 1, -16 }, // 0x35 '5' + { 744, 11, 18, 13, 1, -16 }, // 0x36 '6' + { 769, 12, 17, 13, 1, -16 }, // 0x37 '7' + { 795, 12, 18, 13, 1, -16 }, // 0x38 '8' + { 822, 11, 18, 13, 1, -16 }, // 0x39 '9' + { 847, 3, 12, 8, 3, -11 }, // 0x3A ':' + { 852, 3, 16, 8, 3, -11 }, // 0x3B ';' + { 858, 12, 11, 14, 1, -10 }, // 0x3C '<' + { 875, 12, 9, 14, 1, -9 }, // 0x3D '=' + { 889, 12, 11, 14, 1, -10 }, // 0x3E '>' + { 906, 11, 18, 15, 2, -17 }, // 0x3F '?' + { 931, 22, 21, 23, 1, -17 }, // 0x40 '@' + { 989, 16, 18, 17, 1, -17 }, // 0x41 'A' + { 1025, 14, 18, 17, 2, -17 }, // 0x42 'B' + { 1057, 15, 19, 17, 1, -17 }, // 0x43 'C' + { 1093, 14, 18, 17, 2, -17 }, // 0x44 'D' + { 1125, 13, 18, 16, 2, -17 }, // 0x45 'E' + { 1155, 12, 18, 15, 2, -17 }, // 0x46 'F' + { 1182, 16, 18, 19, 1, -17 }, // 0x47 'G' + { 1218, 14, 18, 17, 2, -17 }, // 0x48 'H' + { 1250, 3, 18, 7, 2, -17 }, // 0x49 'I' + { 1257, 11, 19, 13, 1, -17 }, // 0x4A 'J' + { 1284, 15, 18, 17, 2, -17 }, // 0x4B 'K' + { 1318, 12, 18, 15, 2, -17 }, // 0x4C 'L' + { 1345, 17, 18, 20, 2, -17 }, // 0x4D 'M' + { 1384, 14, 18, 17, 2, -17 }, // 0x4E 'N' + { 1416, 17, 19, 19, 1, -17 }, // 0x4F 'O' + { 1457, 13, 18, 16, 2, -17 }, // 0x50 'P' + { 1487, 17, 19, 19, 1, -17 }, // 0x51 'Q' + { 1528, 14, 18, 17, 2, -17 }, // 0x52 'R' + { 1560, 14, 19, 16, 1, -17 }, // 0x53 'S' + { 1594, 14, 18, 15, 0, -17 }, // 0x54 'T' + { 1626, 14, 19, 17, 2, -17 }, // 0x55 'U' + { 1660, 15, 18, 16, 1, -17 }, // 0x56 'V' + { 1694, 22, 18, 23, 0, -17 }, // 0x57 'W' + { 1744, 15, 18, 16, 1, -17 }, // 0x58 'X' + { 1778, 15, 18, 16, 1, -17 }, // 0x59 'Y' + { 1812, 13, 18, 15, 1, -17 }, // 0x5A 'Z' + { 1842, 5, 23, 8, 2, -17 }, // 0x5B '[' + { 1857, 7, 17, 7, 0, -16 }, // 0x5C '\' + { 1872, 6, 23, 8, 0, -17 }, // 0x5D ']' + { 1890, 12, 11, 14, 1, -16 }, // 0x5E '^' + { 1907, 15, 2, 13, -1, 4 }, // 0x5F '_' + { 1911, 5, 3, 8, 0, -17 }, // 0x60 '`' + { 1913, 12, 14, 13, 1, -12 }, // 0x61 'a' + { 1934, 13, 19, 15, 1, -17 }, // 0x62 'b' + { 1965, 12, 14, 13, 1, -12 }, // 0x63 'c' + { 1986, 12, 19, 15, 1, -17 }, // 0x64 'd' + { 2015, 12, 14, 13, 1, -12 }, // 0x65 'e' + { 2036, 8, 18, 8, 0, -17 }, // 0x66 'f' + { 2054, 12, 18, 15, 1, -12 }, // 0x67 'g' + { 2081, 11, 18, 15, 2, -17 }, // 0x68 'h' + { 2106, 3, 18, 7, 2, -17 }, // 0x69 'i' + { 2113, 5, 23, 7, 0, -17 }, // 0x6A 'j' + { 2128, 12, 18, 13, 1, -17 }, // 0x6B 'k' + { 2155, 3, 18, 7, 2, -17 }, // 0x6C 'l' + { 2162, 19, 13, 21, 1, -12 }, // 0x6D 'm' + { 2193, 11, 13, 15, 2, -12 }, // 0x6E 'n' + { 2211, 13, 14, 15, 1, -12 }, // 0x6F 'o' + { 2234, 13, 18, 15, 1, -12 }, // 0x70 'p' + { 2264, 12, 18, 15, 1, -12 }, // 0x71 'q' + { 2291, 7, 13, 9, 2, -12 }, // 0x72 'r' + { 2303, 11, 14, 13, 1, -12 }, // 0x73 's' + { 2323, 7, 17, 8, 0, -15 }, // 0x74 't' + { 2338, 12, 14, 15, 1, -12 }, // 0x75 'u' + { 2359, 13, 13, 13, 0, -12 }, // 0x76 'v' + { 2381, 18, 13, 19, 0, -12 }, // 0x77 'w' + { 2411, 13, 13, 13, 0, -12 }, // 0x78 'x' + { 2433, 13, 18, 13, 0, -12 }, // 0x79 'y' + { 2463, 10, 13, 12, 1, -12 }, // 0x7A 'z' + { 2480, 7, 23, 9, 1, -17 }, // 0x7B '{' + { 2501, 2, 23, 7, 2, -17 }, // 0x7C '|' + { 2507, 6, 23, 9, 2, -17 }, // 0x7D '}' + { 2525, 11, 5, 14, 1, -7 }, // 0x7E '~' + { 2532, 13, 18, 17, 2, -17 } }; // 0x7F + +const GFXfont ubitx_font PROGMEM = { + (uint8_t *)ubitxBitmaps, + (GFXglyph *)ubitxGlyphs, + 0x14, + 0x7F, + 33}; + +// Approx. 3325 bytes diff --git a/nano_font.h b/nano_font.h new file mode 100644 index 0000000..1b56f73 --- /dev/null +++ b/nano_font.h @@ -0,0 +1,9 @@ +#ifndef _NANO_FONT +#define _NANO_FONT + +#include +#include "PDQ_MinLib/gfxfont.h" + +extern const GFXfont ubitx_font; + +#endif //_NANO_FONT \ No newline at end of file diff --git a/nano_gui.cpp b/nano_gui.cpp index 97d7ddb..01dd3be 100644 --- a/nano_gui.cpp +++ b/nano_gui.cpp @@ -3,19 +3,9 @@ #include "ubitx.h" #include "nano_gui.h" -//#include "Adafruit_GFX.h" -//#include #include #include -#define TFT_CS 10 -#define TFT_RS 9 - - -GFXfont *gfxFont = NULL; -//int touch_x, touch_y; -//XPT2046_Touchscreen ts(CS_PIN); -//TS_Point ts_point; struct Point ts_point; //filled from a test run of calibration routine @@ -149,139 +139,16 @@ void scaleTouch(struct Point *p){ // p->y = ((long)(p->y) * 10l)/(long)(slope_y) - offset_y; } +/***************** + * Begin TFT functions + *****************/ +#define ILI9341_CS_PIN TFT_CS +#define ILI9341_DC_PIN TFT_DC +#include "PDQ_MinLib/PDQ_ILI9341.h" +PDQ_ILI9341 tft; -#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF) - #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) -#else - #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) -#endif +#include "nano_font.h" -inline GFXglyph * pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) -{ -#ifdef __AVR__ - return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); -#else - // expression in __AVR__ section may generate "dereferencing type-punned pointer will break strict-aliasing rules" warning - // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way - // So expression may be simplified - return gfxFont->glyph + c; -#endif //__AVR__ -} - -inline uint8_t * pgm_read_bitmap_ptr(const GFXfont *gfxFont){ -#ifdef __AVR__ - return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); -#else - // expression in __AVR__ section generates "dereferencing type-punned pointer will break strict-aliasing rules" warning - // In fact, on other platforms (such as STM32) there is no need to do this pointer magic as program memory may be read in a usual way - // So expression may be simplified - return gfxFont->bitmap; -#endif //__AVR__ -} - -inline static void utft_write(unsigned char d){ - SPI.transfer(d); -} - -inline static void utftCmd(unsigned char VH){ - *(portOutputRegister(digitalPinToPort(TFT_RS))) &= ~digitalPinToBitMask(TFT_RS);//LCD_RS=0; - utft_write(VH); -} - -inline static void utftData(unsigned char VH){ - *(portOutputRegister(digitalPinToPort(TFT_RS)))|= digitalPinToBitMask(TFT_RS);//LCD_RS=1; - utft_write(VH); -} - - -static void utftAddress(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2){ - - utftCmd(0x2a); - utftData(x1>>8); - utftData(x1); - utftData(x2>>8); - utftData(x2); - utftCmd(0x2b); - utftData(y1>>8); - utftData(y1); - utftData(y2>>8); - utftData(y2); - utftCmd(0x2c); -} - -void displayPixel(unsigned int x, unsigned int y, unsigned int c){ - unsigned int i,j; - digitalWrite(TFT_CS,LOW); - - utftCmd(0x02c); //write_memory_start - utftAddress(x,y,x,y); - utftData(c>>8); - utftData(c); - - digitalWrite(TFT_CS,HIGH); -} - -void displayHline(unsigned int x, unsigned int y, unsigned int l, unsigned int c){ - unsigned int i,j; - - digitalWrite(TFT_CS,LOW); - utftCmd(0x02c); //write_memory_start - l=l+x; - utftAddress(x,y,l,y); - j = l; - for(i=1;i<=j;i++) - { - utftData(c>>8); - utftData(c); - } - digitalWrite(TFT_CS,HIGH); - checkCAT(); -} - -void displayVline(unsigned int x, unsigned int y, unsigned int l, unsigned int c){ - unsigned int i,j; - digitalWrite(TFT_CS,LOW); - - utftCmd(0x02c); //write_memory_start - l=l+y; - utftAddress(x,y,x,l); - j = l; - for(i=1;i<=l;i++) - { - utftData(c>>8); - utftData(c); - } - digitalWrite(TFT_CS,HIGH); - checkCAT(); -} - -void displayClear(unsigned int color){ - unsigned int i,m; - - digitalWrite(TFT_CS,LOW); - utftAddress(0,0,320,240); - for(i=0;i<320;i++) - for(m=0;m<240;m++){ - utftData(color>>8); - utftData(color); - } - digitalWrite(TFT_CS,HIGH); -} - -void displayRect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c){ - displayHline(x , y , w, c); - displayHline(x , y+h, w, c); - displayVline(x , y , h, c); - displayVline(x+w, y , h, c); -} - -void displayFillrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c){ - unsigned int i; - - for(i=0;ifirst); - GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c); - uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont); - - uint16_t bo = pgm_read_word(&glyph->bitmapOffset); - uint8_t w = pgm_read_byte(&glyph->width), - h = pgm_read_byte(&glyph->height); - int8_t xo = pgm_read_byte(&glyph->xOffset), - yo = pgm_read_byte(&glyph->yOffset); - uint8_t xx, yy, bits = 0, bit = 0; - int16_t xo16 = 0, yo16 = 0; - - digitalWrite(TFT_CS,LOW); - -#ifdef FAST_TEXT - uint16_t hpc = 0; // Horizontal foreground pixel count - for(yy=0; yy>= 1; - } - // Draw pixels for this line as we are about to increment yy - if (hpc) { - displayHline(x+xo+xx-hpc, y+yo+yy, hpc, color); - hpc=0; - } - checkCAT(); - } -#else - for(yy=0; yyfirst); - if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { - GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); - ext += (uint8_t)pgm_read_byte(&glyph->xAdvance); - } - }//end of the while loop of the characters to be printed - return ext; + tft.drawCharGFX(x,y,c,color,bg,1); } void displayRawText(char *text, int x1, int y1, int color, int background){ - while(*text){ - char c = *text++; - - uint8_t first = pgm_read_byte(&gfxFont->first); - if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { - - GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); - uint8_t w = pgm_read_byte(&glyph->width), - h = pgm_read_byte(&glyph->height); - if((w > 0) && (h > 0)) { // Is there an associated bitmap? - int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic - displayChar(x1, y1+TEXT_LINE_HEIGHT, c, color, background); - checkCAT(); - } - x1 += (uint8_t)pgm_read_byte(&glyph->xAdvance); - } - }//end of the while loop of the characters to be printed + tft.setTextColor(color,background); + tft.setCursor(x1,y1); + tft.print(text); } -// The generic routine to display one line on the LCD void displayText(char *text, int x1, int y1, int w, int h, int color, int background, int border) { - displayFillrect(x1, y1, w ,h, background); displayRect(x1, y1, w ,h, border); - x1 += (w - displayTextExtent(text))/2; - y1 += (h - TEXT_LINE_HEIGHT)/2; - while(*text){ - char c = *text++; - - uint8_t first = pgm_read_byte(&gfxFont->first); - if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { - - GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); - uint8_t w = pgm_read_byte(&glyph->width), - h = pgm_read_byte(&glyph->height); - if((w > 0) && (h > 0)) { // Is there an associated bitmap? - int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic - displayChar(x1, y1+TEXT_LINE_HEIGHT, c, color, background); - checkCAT(); - } - x1 += (uint8_t)pgm_read_byte(&glyph->xAdvance); - } - }//end of the while loop of the characters to be printed + int16_t x1_out; + int16_t y1_out; + uint16_t width_out; + uint16_t height_out; + tft.getTextBounds(text,x1,y1,&x1_out,&y1_out,&width_out,&height_out); + x1_out += (w - width_out)/2; + y1_out += 2*height_out + (h - height_out)/2; + displayRawText(text,x1_out,y1_out,color,background); } void setupTouch(){ diff --git a/nano_gui.h b/nano_gui.h index a66b1b0..efb163b 100644 --- a/nano_gui.h +++ b/nano_gui.h @@ -15,7 +15,6 @@ void displayVline(unsigned int x, unsigned int y, unsigned int l, unsigned int c void displayRect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c); void displayFillrect(unsigned int x,unsigned int y,unsigned int w,unsigned int h,unsigned int c); void displayChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg); -int displayTextExtent(char *text); void displayRawText(char *text, int x1, int y1, int color, int background); void displayText(char *text, int x1, int y1, int w, int h, int color, int background, int border); @@ -53,356 +52,4 @@ void scaleTouch(struct Point *p); #define BUTTON_CHECK #define BUTTON_SPINNER -/// Font data stored PER GLYPH -typedef struct { - uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap - uint8_t width; ///< Bitmap dimensions in pixels - uint8_t height; ///< Bitmap dimensions in pixels - uint8_t xAdvance; ///< Distance to advance cursor (x axis) - int8_t xOffset; ///< X dist from cursor pos to UL corner - int8_t yOffset; ///< Y dist from cursor pos to UL corner -} GFXglyph; - -/// Data stored for FONT AS A WHOLE -typedef struct { - uint8_t *bitmap; ///< Glyph bitmaps, concatenated - GFXglyph *glyph; ///< Glyph array - uint8_t first; ///< ASCII extents (first char) - uint8_t last; ///< ASCII extents (last char) - uint8_t yAdvance; ///< Newline distance (y axis) -} GFXfont; - -const uint8_t ubitxBitmaps[] PROGMEM = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, - 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, - 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, - 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, - 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, - 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, - 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, - 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, - 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, - 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, - 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, - 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, - 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, - 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, - 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, - 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, - 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, - 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, - 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, - 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0, - 0xFF, 0xFF, 0xFF, 0xFF, 0x21, 0xFF, 0xE0, 0xF3, 0xF9, 0xFC, 0xFE, 0x7E, - 0x3B, 0x1D, 0x84, 0x0E, 0x70, 0x73, 0x83, 0x9C, 0x18, 0xC7, 0xFF, 0xBF, - 0xFD, 0xFF, 0xE3, 0x9C, 0x18, 0xC0, 0xC6, 0x0E, 0x7D, 0xFF, 0xEF, 0xFF, - 0x18, 0xC0, 0xC6, 0x0E, 0x70, 0x73, 0x83, 0x9C, 0x00, 0x04, 0x01, 0xF8, - 0x7F, 0xCF, 0xDE, 0xE4, 0xEE, 0x4E, 0xE4, 0x0F, 0x40, 0x7E, 0x03, 0xFC, - 0x0F, 0xE0, 0x5E, 0x04, 0xFE, 0x4F, 0xE4, 0xFF, 0x4E, 0x7F, 0xE3, 0xFC, - 0x04, 0x00, 0x40, 0x04, 0x00, 0x3C, 0x06, 0x07, 0xE0, 0x60, 0xFF, 0x0C, - 0x0C, 0x30, 0x80, 0xC3, 0x18, 0x0C, 0x31, 0x00, 0xFF, 0x30, 0x07, 0xE6, - 0x00, 0x3C, 0x60, 0x00, 0x0C, 0x7C, 0x00, 0xCF, 0xE0, 0x19, 0xC6, 0x01, - 0x98, 0x70, 0x31, 0x87, 0x03, 0x1C, 0x60, 0x60, 0xFE, 0x04, 0x07, 0xC0, - 0x0F, 0x80, 0x1F, 0xC0, 0x3D, 0xE0, 0x38, 0xE0, 0x3C, 0xE0, 0x1D, 0xC0, - 0x1F, 0xC0, 0x0F, 0x00, 0x3F, 0x8C, 0x7B, 0xDC, 0x71, 0xDC, 0xF1, 0xFC, - 0xF0, 0xF8, 0xF0, 0x78, 0x79, 0xFC, 0x7F, 0xFC, 0x3F, 0x9E, 0x00, 0x00, - 0xFF, 0xFF, 0xE6, 0x60, 0x0C, 0x71, 0x8E, 0x31, 0xC7, 0x38, 0xE3, 0x8E, - 0x38, 0xE3, 0x8E, 0x38, 0x71, 0xC7, 0x0E, 0x38, 0x70, 0xC0, 0xC3, 0x86, - 0x1C, 0x70, 0xE3, 0x8E, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xCE, 0x38, 0xE7, - 0x1C, 0x63, 0x8C, 0x00, 0x10, 0x10, 0x10, 0xFE, 0x7C, 0x38, 0x6C, 0x44, - 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x60, - 0x06, 0x00, 0x60, 0x06, 0x00, 0xFF, 0xF2, 0xFE, 0xFF, 0xFF, 0xC0, 0xFF, - 0xF0, 0x04, 0x08, 0x30, 0x60, 0x83, 0x06, 0x08, 0x10, 0x60, 0xC1, 0x06, - 0x0C, 0x10, 0x20, 0xC0, 0x3F, 0x8F, 0xF9, 0xEF, 0x78, 0xFE, 0x0F, 0xC1, - 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xE3, 0xDE, - 0xF3, 0xFE, 0x3F, 0x80, 0x80, 0x06, 0x1C, 0x7F, 0xFF, 0xE1, 0xC3, 0x87, - 0x0E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x3F, 0x8F, 0xFB, 0xEF, - 0xF8, 0x7E, 0x0F, 0xC1, 0xC0, 0x38, 0x0F, 0x03, 0xC0, 0xF0, 0x7C, 0x1F, - 0x07, 0x80, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xE0, 0x3F, 0x8F, 0xFB, 0xCF, - 0xF0, 0xFE, 0x1E, 0x03, 0xC0, 0x70, 0x7C, 0x0F, 0xC0, 0xFC, 0x03, 0x80, - 0x7E, 0x0F, 0xC1, 0xFC, 0xFB, 0xFE, 0x3F, 0x80, 0x80, 0x07, 0xC0, 0x7C, - 0x0F, 0xC0, 0xFC, 0x1F, 0xC3, 0xBC, 0x33, 0xC7, 0x3C, 0x63, 0xCE, 0x3C, - 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3F, - 0xEF, 0xFD, 0xFF, 0xB8, 0x06, 0x00, 0xC0, 0x1F, 0xE7, 0xFE, 0xF1, 0xE0, - 0x1C, 0x03, 0x80, 0x70, 0x0F, 0xC1, 0xFC, 0xFB, 0xFE, 0x3F, 0x80, 0x80, - 0x1F, 0x87, 0xF9, 0xE7, 0xB8, 0x7E, 0x01, 0xC0, 0x3B, 0xE7, 0xFE, 0xFB, - 0xFE, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xE1, 0xDE, 0xFB, 0xFE, 0x3F, 0x80, - 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0E, 0x01, 0xC0, 0x3C, 0x03, 0x80, - 0x70, 0x0F, 0x00, 0xE0, 0x0E, 0x01, 0xE0, 0x1C, 0x01, 0xC0, 0x1C, 0x03, - 0xC0, 0x3C, 0x00, 0x3F, 0x87, 0xFC, 0xF9, 0xEE, 0x0E, 0xE0, 0xEE, 0x0E, - 0x71, 0xC3, 0xF8, 0x7F, 0xCF, 0x1E, 0xE0, 0xEE, 0x0F, 0xE0, 0xFE, 0x0E, - 0xF1, 0xE7, 0xFC, 0x3F, 0x80, 0x40, 0x3F, 0x0F, 0xFB, 0xEF, 0x70, 0xFE, - 0x0F, 0xC1, 0xF8, 0x3F, 0x0F, 0xF3, 0xEF, 0xFC, 0xFB, 0x80, 0x70, 0x0F, - 0xC3, 0xFE, 0xF3, 0xFE, 0x3F, 0x80, 0x80, 0xFF, 0x80, 0x00, 0xFF, 0xF0, - 0xFF, 0x80, 0x00, 0xFF, 0xF2, 0xDE, 0x00, 0x70, 0x1F, 0x0F, 0xE7, 0xF0, - 0xF8, 0x0E, 0x00, 0xFC, 0x03, 0xF8, 0x0F, 0xE0, 0x1F, 0x00, 0x30, 0xFF, - 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0xC0, 0x0F, 0x80, 0x7F, 0x00, 0xFC, 0x03, 0xF0, 0x07, 0x03, 0xF1, - 0xFC, 0xFE, 0x0F, 0x80, 0xC0, 0x00, 0x1F, 0x0F, 0xF3, 0xFF, 0x78, 0xFE, - 0x0F, 0xC1, 0xC0, 0x38, 0x0F, 0x03, 0xE0, 0xF8, 0x3C, 0x07, 0x00, 0xE0, - 0x00, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x00, 0xFC, 0x00, 0x0F, 0xFE, - 0x00, 0xF0, 0x3C, 0x07, 0x00, 0x38, 0x38, 0x00, 0x30, 0xC0, 0x00, 0xE6, - 0x0F, 0xF1, 0x98, 0x73, 0xC7, 0xC3, 0x87, 0x0F, 0x0C, 0x1C, 0x3C, 0x30, - 0x61, 0xF1, 0xC1, 0x86, 0xC7, 0x0E, 0x1B, 0x1C, 0x38, 0xEC, 0x3B, 0xEF, - 0x38, 0xFD, 0xF8, 0x70, 0xC1, 0x80, 0xE0, 0x00, 0x01, 0xC0, 0x10, 0x03, - 0xFF, 0xC0, 0x03, 0xFF, 0x00, 0x03, 0xC0, 0x07, 0xC0, 0x07, 0xE0, 0x07, - 0xE0, 0x0F, 0xE0, 0x0E, 0xF0, 0x0E, 0xF0, 0x1E, 0x70, 0x1C, 0x78, 0x1C, - 0x78, 0x3C, 0x38, 0x3F, 0xFC, 0x3F, 0xFC, 0x7F, 0xFC, 0x70, 0x1E, 0xF0, - 0x1E, 0xF0, 0x0E, 0xE0, 0x0F, 0xFF, 0x03, 0xFF, 0xCF, 0xFF, 0xBC, 0x7E, - 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBF, 0xFE, 0xFF, 0xE3, 0xFF, 0xCF, 0x0F, - 0xBC, 0x0F, 0xF0, 0x1F, 0xC0, 0xFF, 0x03, 0xFF, 0xFE, 0xFF, 0xFB, 0xFF, - 0x80, 0x03, 0xC0, 0x1F, 0xF0, 0xFF, 0xF1, 0xF1, 0xE7, 0x81, 0xEF, 0x01, - 0xFC, 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, - 0x00, 0xEF, 0x01, 0xDE, 0x07, 0x9F, 0xFE, 0x1F, 0xFC, 0x1F, 0xE0, 0x04, - 0x00, 0xFE, 0x03, 0xFF, 0x8F, 0xFF, 0x38, 0x7E, 0xE0, 0x7B, 0x80, 0xFE, - 0x03, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x3F, - 0x80, 0xFE, 0x07, 0xBF, 0xFE, 0xFF, 0xF3, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFE, 0xFF, 0xF7, - 0xFF, 0xBC, 0x01, 0xE0, 0x0F, 0x00, 0x78, 0x03, 0xC0, 0x1F, 0xFF, 0xFF, - 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0xE0, 0x0E, 0x00, - 0xE0, 0x0F, 0xFE, 0xFF, 0xEF, 0xFE, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, - 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x03, 0xE0, 0x0F, 0xF8, 0x1F, 0xFC, - 0x3E, 0x3E, 0x78, 0x0F, 0x70, 0x0F, 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, - 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x7F, 0xF0, 0x07, 0x78, 0x0F, 0x7C, 0x1F, - 0x3F, 0xFF, 0x1F, 0xFB, 0x0F, 0xF3, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, - 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, - 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, - 0x80, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x01, 0xE0, 0x3C, - 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, - 0x80, 0xFE, 0x1F, 0xC3, 0xF8, 0x7F, 0xFE, 0xFF, 0xCF, 0xF0, 0x00, 0x00, - 0xE0, 0x3D, 0xC0, 0xFB, 0x83, 0xE7, 0x07, 0x8E, 0x1E, 0x1C, 0x78, 0x39, - 0xE0, 0x77, 0x80, 0xFF, 0x01, 0xFF, 0x03, 0xFE, 0x07, 0x9E, 0x0E, 0x1E, - 0x1C, 0x1E, 0x38, 0x3C, 0x70, 0x3C, 0xE0, 0x3D, 0xC0, 0x3C, 0xF0, 0x0F, - 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, - 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, - 0xFF, 0xF8, 0x1F, 0xFC, 0x0F, 0xFE, 0x07, 0xFF, 0x83, 0xFF, 0xC3, 0xFF, - 0xE1, 0xFF, 0xB0, 0xFF, 0xDC, 0x6F, 0xEE, 0x77, 0xF7, 0x3B, 0xF9, 0x9D, - 0xFC, 0xCC, 0xFE, 0x76, 0x7F, 0x3F, 0x3F, 0x8F, 0x9F, 0xC7, 0xCF, 0xE3, - 0xC7, 0xF1, 0xE3, 0xC0, 0xE0, 0x3F, 0xC0, 0xFF, 0x03, 0xFE, 0x0F, 0xFC, - 0x3F, 0xF0, 0xFE, 0xE3, 0xFB, 0x8F, 0xE7, 0x3F, 0x9E, 0xFE, 0x3B, 0xF8, - 0xFF, 0xE1, 0xFF, 0x83, 0xFE, 0x0F, 0xF8, 0x1F, 0xE0, 0x7F, 0x80, 0xF0, - 0x03, 0xE0, 0x07, 0xFC, 0x07, 0xFF, 0x07, 0xCF, 0xC7, 0x81, 0xF3, 0xC0, - 0x7B, 0xC0, 0x1D, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, - 0x00, 0xFF, 0x00, 0x73, 0xC0, 0x79, 0xF0, 0x7C, 0x7F, 0xFC, 0x1F, 0xFC, - 0x07, 0xFC, 0x00, 0x20, 0x00, 0xFF, 0x07, 0xFF, 0x3F, 0xFD, 0xC3, 0xFE, - 0x07, 0xF0, 0x1F, 0x80, 0xFC, 0x0F, 0xE0, 0xFF, 0xFF, 0xBF, 0xF9, 0xFF, - 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x03, - 0xE0, 0x07, 0xFC, 0x07, 0xFF, 0x07, 0xCF, 0xC7, 0x80, 0xF3, 0xC0, 0x7B, - 0xC0, 0x1F, 0xE0, 0x0F, 0xF0, 0x07, 0xF8, 0x03, 0xFC, 0x01, 0xFE, 0x04, - 0xFF, 0x07, 0x73, 0xC3, 0xF9, 0xF0, 0xFC, 0x7F, 0xFC, 0x1F, 0xFF, 0x07, - 0xFF, 0xC0, 0x20, 0xC0, 0xFF, 0x83, 0xFF, 0xCF, 0xFF, 0xBC, 0x3F, 0xF0, - 0x3F, 0xC0, 0xFF, 0x03, 0xFC, 0x0F, 0xFF, 0xFB, 0xFF, 0x8F, 0xFF, 0xBC, - 0x1E, 0xF0, 0x3B, 0xC0, 0xEF, 0x03, 0xBC, 0x0E, 0xF0, 0x3F, 0xC0, 0xF0, - 0x0F, 0x80, 0xFF, 0xC7, 0xFF, 0xBE, 0x1E, 0xF0, 0x3B, 0xC0, 0xFF, 0x00, - 0x3F, 0x80, 0x7F, 0xE0, 0xFF, 0xE0, 0x3F, 0xC0, 0x0F, 0x00, 0x1F, 0x80, - 0x7F, 0x03, 0xFF, 0x1F, 0x7F, 0xF8, 0xFF, 0xC0, 0x00, 0x00, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, - 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, - 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, - 0x0F, 0xE0, 0x3F, 0x80, 0xFE, 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0x80, 0xFE, - 0x03, 0xF8, 0x0F, 0xE0, 0x3F, 0xC0, 0xFF, 0x07, 0x9F, 0xFE, 0x7F, 0xF0, - 0x7F, 0x80, 0x20, 0x00, 0xE0, 0x1F, 0xC0, 0x3B, 0xC0, 0xF3, 0x81, 0xE7, - 0x03, 0x8F, 0x0F, 0x0E, 0x1C, 0x1C, 0x38, 0x3C, 0x70, 0x39, 0xC0, 0x73, - 0x80, 0xE7, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x03, 0xC0, 0x07, 0x80, - 0x0F, 0x00, 0xF0, 0x38, 0x1D, 0xC1, 0xE0, 0xF7, 0x87, 0xC3, 0xDE, 0x1F, - 0x0F, 0x78, 0x7C, 0x38, 0xE3, 0xB0, 0xE3, 0x8E, 0xC7, 0x8F, 0x3B, 0x9C, - 0x1C, 0xEE, 0x70, 0x73, 0x39, 0xC1, 0xDC, 0x67, 0x07, 0x71, 0xB8, 0x0F, - 0xC7, 0xE0, 0x3E, 0x1F, 0x80, 0xF8, 0x3E, 0x01, 0xE0, 0xF0, 0x07, 0x83, - 0xC0, 0x1E, 0x0F, 0x00, 0xF0, 0x3D, 0xF0, 0x79, 0xE1, 0xE1, 0xE3, 0xC3, - 0xCF, 0x03, 0xFC, 0x07, 0xF8, 0x07, 0xE0, 0x07, 0x80, 0x0F, 0x00, 0x3F, - 0x00, 0x7F, 0x01, 0xFE, 0x07, 0x9E, 0x0F, 0x3C, 0x3C, 0x3C, 0xF8, 0x3D, - 0xE0, 0x78, 0xF0, 0x1F, 0xE0, 0x79, 0xE0, 0xF3, 0xC3, 0xC3, 0xC7, 0x87, - 0x9E, 0x07, 0x3C, 0x0F, 0x70, 0x0F, 0xE0, 0x1F, 0x80, 0x1F, 0x00, 0x3C, - 0x00, 0x78, 0x00, 0xF0, 0x01, 0xE0, 0x03, 0xC0, 0x07, 0x80, 0x0F, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x80, - 0x78, 0x07, 0x80, 0x78, 0x07, 0x80, 0x7C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, - 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xCE, 0x73, 0x9C, 0xE7, - 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, 0xCF, 0xFF, 0xE0, 0xC1, 0x81, 0x02, - 0x06, 0x04, 0x08, 0x18, 0x30, 0x20, 0x60, 0xC0, 0x81, 0x83, 0x02, 0x06, - 0xFF, 0xFF, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7, - 0x1C, 0x71, 0xC7, 0xFF, 0xFF, 0xC0, 0x0F, 0x00, 0xF0, 0x0F, 0x01, 0xF8, - 0x1B, 0x83, 0x9C, 0x39, 0xC3, 0x0C, 0x70, 0xE7, 0x0E, 0xE0, 0x70, 0xFF, - 0xFF, 0xFF, 0xFC, 0x71, 0x86, 0x3F, 0x87, 0xFC, 0xFF, 0xEE, 0x1E, 0x01, - 0xE0, 0xFE, 0x7F, 0xEF, 0x8E, 0xE1, 0xEE, 0x1E, 0xF3, 0xEF, 0xFE, 0x7E, - 0xE1, 0x00, 0xF0, 0x07, 0x80, 0x3C, 0x01, 0xE0, 0x0F, 0x00, 0x7B, 0xE3, - 0xFF, 0x9F, 0xFE, 0xF8, 0xF7, 0x83, 0xFC, 0x1F, 0xE0, 0xFF, 0x07, 0xF8, - 0x3F, 0xC1, 0xDF, 0x9E, 0xFF, 0xE7, 0xFE, 0x00, 0x40, 0x1F, 0x83, 0xFC, - 0x7F, 0xEF, 0x0E, 0xE0, 0xEE, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0F, 0x0E, - 0x79, 0xE7, 0xFC, 0x3F, 0x80, 0x00, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, - 0x00, 0x71, 0xE7, 0x3F, 0xF7, 0xFF, 0xF0, 0xFE, 0x0F, 0xE0, 0x7E, 0x07, - 0xE0, 0x7E, 0x0F, 0xF0, 0xF7, 0x9F, 0x7F, 0xF3, 0xF7, 0x00, 0x00, 0x1F, - 0x07, 0xFC, 0x7B, 0xEE, 0x0E, 0xE0, 0xEF, 0xFE, 0xFF, 0xFF, 0xFF, 0xE0, - 0x0E, 0x0E, 0xF1, 0xE7, 0xFC, 0x3F, 0x80, 0x40, 0x00, 0x1E, 0x3E, 0x3C, - 0x3C, 0xFF, 0xFF, 0xFF, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, - 0x3C, 0x3C, 0x1E, 0x73, 0xF7, 0x7F, 0xFF, 0x0F, 0xF0, 0xFE, 0x07, 0xE0, - 0x7E, 0x07, 0xE0, 0x7F, 0x0F, 0x79, 0xF7, 0xFF, 0x3F, 0x70, 0x07, 0x00, - 0x7F, 0x0F, 0x7F, 0xE3, 0xFC, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, - 0xDF, 0x3F, 0xF7, 0xFF, 0xF1, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x0F, 0xC1, - 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1C, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFC, 0x39, 0xCE, 0x70, 0x1C, 0xE7, 0x39, 0xCE, 0x73, 0x9C, 0xE7, 0x39, - 0xCE, 0x7F, 0xFF, 0xC0, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, - 0x0E, 0xF1, 0xEF, 0x3C, 0xF7, 0x8F, 0xF0, 0xFF, 0x0F, 0xF0, 0xFF, 0x8F, - 0x3C, 0xF3, 0xCF, 0x1E, 0xF1, 0xEF, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFC, 0xF7, 0xCF, 0x9F, 0xFF, 0xFB, 0xFF, 0xFF, 0xF8, 0x78, 0xFF, - 0x0E, 0x1F, 0xE1, 0xC3, 0xFC, 0x38, 0x7F, 0x87, 0x0F, 0xF0, 0xE1, 0xFE, - 0x1C, 0x3F, 0xC3, 0x87, 0xF8, 0x70, 0xFF, 0x0E, 0x1E, 0xEF, 0x9F, 0xFB, - 0xFF, 0xF8, 0xFE, 0x0F, 0xC1, 0xF8, 0x3F, 0x07, 0xE0, 0xFC, 0x1F, 0x83, - 0xF0, 0x7E, 0x0E, 0x1F, 0x81, 0xFF, 0x1F, 0xFD, 0xE1, 0xEF, 0x07, 0x70, - 0x3F, 0x81, 0xFC, 0x0F, 0xE0, 0x7F, 0x83, 0x9E, 0x3C, 0xFF, 0xC3, 0xFC, - 0x01, 0x00, 0xF7, 0xC7, 0xFF, 0x3F, 0xFD, 0xF1, 0xEF, 0x07, 0xF8, 0x3F, - 0xC1, 0xFE, 0x0F, 0xF0, 0x7F, 0x83, 0xBE, 0x3D, 0xFF, 0xCF, 0x7C, 0x78, - 0x83, 0xC0, 0x1E, 0x00, 0xF0, 0x07, 0x80, 0x00, 0x1E, 0x77, 0xF7, 0x7F, - 0xFF, 0x0F, 0xE0, 0xFE, 0x07, 0xE0, 0x7E, 0x07, 0xE0, 0xFF, 0x0F, 0xF9, - 0xF7, 0xFF, 0x3F, 0x70, 0x47, 0x00, 0x70, 0x07, 0x00, 0x70, 0x07, 0xEF, - 0xFF, 0xFF, 0x8E, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0E, 0x00, 0x3F, - 0x8F, 0xFB, 0xEF, 0xF8, 0x7F, 0x01, 0xFE, 0x1F, 0xF0, 0xFF, 0x01, 0xFC, - 0x1F, 0xC3, 0xFF, 0xF7, 0xFC, 0x08, 0x00, 0x38, 0x70, 0xE7, 0xFF, 0xFF, - 0xCE, 0x1C, 0x38, 0x70, 0xE1, 0xC3, 0x87, 0x0F, 0x8F, 0x04, 0xF0, 0x7F, - 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, 0x07, 0xF0, 0x7F, - 0x0F, 0x79, 0xF7, 0xFF, 0x3F, 0x70, 0x80, 0xF0, 0x7B, 0x83, 0x9E, 0x1C, - 0x71, 0xE3, 0x8E, 0x1E, 0x70, 0x73, 0x83, 0xB8, 0x1D, 0xC0, 0x7E, 0x03, - 0xE0, 0x1F, 0x00, 0x78, 0x00, 0xF0, 0xE1, 0xDC, 0x78, 0x77, 0x1F, 0x3D, - 0xC7, 0xCE, 0x79, 0xF3, 0x8E, 0xEC, 0xE3, 0xBB, 0x78, 0xEC, 0xFC, 0x1F, - 0x3F, 0x07, 0xCF, 0xC1, 0xF1, 0xE0, 0x7C, 0x78, 0x0E, 0x1E, 0x00, 0x78, - 0xF3, 0xC7, 0x8F, 0x78, 0x3B, 0x81, 0xFC, 0x07, 0xC0, 0x1E, 0x01, 0xF0, - 0x1F, 0xC0, 0xEF, 0x0F, 0x78, 0xF1, 0xE7, 0x87, 0x80, 0xF0, 0x7B, 0x83, - 0x9E, 0x1C, 0xF1, 0xE3, 0x8E, 0x1E, 0x70, 0x73, 0x83, 0xB8, 0x1D, 0xC0, - 0x7E, 0x03, 0xE0, 0x1F, 0x00, 0x78, 0x03, 0x80, 0x1C, 0x01, 0xE0, 0x3E, - 0x01, 0xE0, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x1E, 0x0F, 0x83, 0xC1, 0xE0, - 0xF0, 0x78, 0x3C, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0x3C, 0xF9, 0xC3, - 0x87, 0x0E, 0x1C, 0x38, 0x73, 0xC7, 0x0F, 0x07, 0x0E, 0x1C, 0x38, 0x70, - 0xE1, 0xC3, 0xE7, 0xC7, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xC3, - 0xCF, 0x0C, 0x38, 0xE3, 0x8E, 0x38, 0xE3, 0xC7, 0x3C, 0xE3, 0x8E, 0x38, - 0xE3, 0x8E, 0xF3, 0xCE, 0x00, 0x10, 0x0F, 0x85, 0xBD, 0xE1, 0xF0, 0x08, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, 0xFC, - 0x07, 0xE0, 0x3F, 0x01, 0xF8, 0x0F, 0xC0, 0x7E, 0x03, 0xF0, 0x1F, 0x80, - 0xFC, 0x07, 0xFF, 0xFF, 0xFF, 0xC0 }; - -const GFXglyph ubitxGlyphs[] PROGMEM = { - { 0, 13, 18, 17, 2, -17 }, // 0x14 - { 30, 13, 18, 17, 2, -17 }, // 0x15 - { 60, 13, 18, 17, 2, -17 }, // 0x16 - { 90, 13, 18, 17, 2, -17 }, // 0x17 - { 120, 13, 18, 17, 2, -17 }, // 0x18 - { 150, 13, 18, 17, 2, -17 }, // 0x19 - { 180, 13, 18, 17, 2, -17 }, // 0x1A - { 210, 13, 18, 17, 2, -17 }, // 0x1B - { 240, 13, 18, 17, 2, -17 }, // 0x1C - { 270, 13, 18, 17, 2, -17 }, // 0x1D - { 300, 13, 18, 17, 2, -17 }, // 0x1E - { 330, 13, 18, 17, 2, -17 }, // 0x1F - { 360, 0, 0, 7, 0, 1 }, // 0x20 ' ' - { 360, 3, 17, 8, 3, -16 }, // 0x21 '!' - { 367, 9, 7, 11, 1, -17 }, // 0x22 '"' - { 375, 13, 18, 13, 0, -16 }, // 0x23 '#' - { 405, 12, 21, 13, 1, -17 }, // 0x24 '$' - { 437, 20, 17, 21, 1, -16 }, // 0x25 '%' - { 480, 16, 18, 17, 1, -16 }, // 0x26 '&' - { 516, 4, 7, 6, 1, -17 }, // 0x27 ''' - { 520, 6, 23, 8, 1, -17 }, // 0x28 '(' - { 538, 6, 23, 8, 1, -17 }, // 0x29 ')' - { 556, 8, 8, 9, 1, -17 }, // 0x2A '*' - { 564, 12, 11, 14, 1, -10 }, // 0x2B '+' - { 581, 3, 8, 7, 2, -3 }, // 0x2C ',' - { 584, 6, 3, 8, 1, -7 }, // 0x2D '-' - { 587, 3, 4, 7, 2, -3 }, // 0x2E '.' - { 589, 7, 17, 7, 0, -16 }, // 0x2F '/' - { 604, 11, 18, 13, 1, -16 }, // 0x30 '0' - { 629, 7, 17, 13, 2, -16 }, // 0x31 '1' - { 644, 11, 17, 13, 1, -16 }, // 0x32 '2' - { 668, 11, 18, 13, 1, -16 }, // 0x33 '3' - { 693, 12, 17, 13, 1, -16 }, // 0x34 '4' - { 719, 11, 18, 13, 1, -16 }, // 0x35 '5' - { 744, 11, 18, 13, 1, -16 }, // 0x36 '6' - { 769, 12, 17, 13, 1, -16 }, // 0x37 '7' - { 795, 12, 18, 13, 1, -16 }, // 0x38 '8' - { 822, 11, 18, 13, 1, -16 }, // 0x39 '9' - { 847, 3, 12, 8, 3, -11 }, // 0x3A ':' - { 852, 3, 16, 8, 3, -11 }, // 0x3B ';' - { 858, 12, 11, 14, 1, -10 }, // 0x3C '<' - { 875, 12, 9, 14, 1, -9 }, // 0x3D '=' - { 889, 12, 11, 14, 1, -10 }, // 0x3E '>' - { 906, 11, 18, 15, 2, -17 }, // 0x3F '?' - { 931, 22, 21, 23, 1, -17 }, // 0x40 '@' - { 989, 16, 18, 17, 1, -17 }, // 0x41 'A' - { 1025, 14, 18, 17, 2, -17 }, // 0x42 'B' - { 1057, 15, 19, 17, 1, -17 }, // 0x43 'C' - { 1093, 14, 18, 17, 2, -17 }, // 0x44 'D' - { 1125, 13, 18, 16, 2, -17 }, // 0x45 'E' - { 1155, 12, 18, 15, 2, -17 }, // 0x46 'F' - { 1182, 16, 18, 19, 1, -17 }, // 0x47 'G' - { 1218, 14, 18, 17, 2, -17 }, // 0x48 'H' - { 1250, 3, 18, 7, 2, -17 }, // 0x49 'I' - { 1257, 11, 19, 13, 1, -17 }, // 0x4A 'J' - { 1284, 15, 18, 17, 2, -17 }, // 0x4B 'K' - { 1318, 12, 18, 15, 2, -17 }, // 0x4C 'L' - { 1345, 17, 18, 20, 2, -17 }, // 0x4D 'M' - { 1384, 14, 18, 17, 2, -17 }, // 0x4E 'N' - { 1416, 17, 19, 19, 1, -17 }, // 0x4F 'O' - { 1457, 13, 18, 16, 2, -17 }, // 0x50 'P' - { 1487, 17, 19, 19, 1, -17 }, // 0x51 'Q' - { 1528, 14, 18, 17, 2, -17 }, // 0x52 'R' - { 1560, 14, 19, 16, 1, -17 }, // 0x53 'S' - { 1594, 14, 18, 15, 0, -17 }, // 0x54 'T' - { 1626, 14, 19, 17, 2, -17 }, // 0x55 'U' - { 1660, 15, 18, 16, 1, -17 }, // 0x56 'V' - { 1694, 22, 18, 23, 0, -17 }, // 0x57 'W' - { 1744, 15, 18, 16, 1, -17 }, // 0x58 'X' - { 1778, 15, 18, 16, 1, -17 }, // 0x59 'Y' - { 1812, 13, 18, 15, 1, -17 }, // 0x5A 'Z' - { 1842, 5, 23, 8, 2, -17 }, // 0x5B '[' - { 1857, 7, 17, 7, 0, -16 }, // 0x5C '\' - { 1872, 6, 23, 8, 0, -17 }, // 0x5D ']' - { 1890, 12, 11, 14, 1, -16 }, // 0x5E '^' - { 1907, 15, 2, 13, -1, 4 }, // 0x5F '_' - { 1911, 5, 3, 8, 0, -17 }, // 0x60 '`' - { 1913, 12, 14, 13, 1, -12 }, // 0x61 'a' - { 1934, 13, 19, 15, 1, -17 }, // 0x62 'b' - { 1965, 12, 14, 13, 1, -12 }, // 0x63 'c' - { 1986, 12, 19, 15, 1, -17 }, // 0x64 'd' - { 2015, 12, 14, 13, 1, -12 }, // 0x65 'e' - { 2036, 8, 18, 8, 0, -17 }, // 0x66 'f' - { 2054, 12, 18, 15, 1, -12 }, // 0x67 'g' - { 2081, 11, 18, 15, 2, -17 }, // 0x68 'h' - { 2106, 3, 18, 7, 2, -17 }, // 0x69 'i' - { 2113, 5, 23, 7, 0, -17 }, // 0x6A 'j' - { 2128, 12, 18, 13, 1, -17 }, // 0x6B 'k' - { 2155, 3, 18, 7, 2, -17 }, // 0x6C 'l' - { 2162, 19, 13, 21, 1, -12 }, // 0x6D 'm' - { 2193, 11, 13, 15, 2, -12 }, // 0x6E 'n' - { 2211, 13, 14, 15, 1, -12 }, // 0x6F 'o' - { 2234, 13, 18, 15, 1, -12 }, // 0x70 'p' - { 2264, 12, 18, 15, 1, -12 }, // 0x71 'q' - { 2291, 7, 13, 9, 2, -12 }, // 0x72 'r' - { 2303, 11, 14, 13, 1, -12 }, // 0x73 's' - { 2323, 7, 17, 8, 0, -15 }, // 0x74 't' - { 2338, 12, 14, 15, 1, -12 }, // 0x75 'u' - { 2359, 13, 13, 13, 0, -12 }, // 0x76 'v' - { 2381, 18, 13, 19, 0, -12 }, // 0x77 'w' - { 2411, 13, 13, 13, 0, -12 }, // 0x78 'x' - { 2433, 13, 18, 13, 0, -12 }, // 0x79 'y' - { 2463, 10, 13, 12, 1, -12 }, // 0x7A 'z' - { 2480, 7, 23, 9, 1, -17 }, // 0x7B '{' - { 2501, 2, 23, 7, 2, -17 }, // 0x7C '|' - { 2507, 6, 23, 9, 2, -17 }, // 0x7D '}' - { 2525, 11, 5, 14, 1, -7 }, // 0x7E '~' - { 2532, 13, 18, 17, 2, -17 } }; // 0x7F - -const GFXfont ubitx_font PROGMEM = { - (uint8_t *)ubitxBitmaps, - (GFXglyph *)ubitxGlyphs, - 0x14, 0x7F, 33 }; - -// Approx. 3325 bytes - #endif // _NANO_GUI_H_