PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7373 lines
230KB

  1. /*
  2. Part of RA8875 library from https://github.com/sumotoy/RA8875
  3. License:GNU General Public License v3.0
  4. RA8875 fast SPI library for RAiO SPI RA8875 drived TFT
  5. Copyright (C) 2014 egidio massimo costa sumotoy (a t) gmail.com
  6. This program is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #if !defined(SPARK)//SPI already included in applications.h
  18. #include <SPI.h>
  19. #endif
  20. #include "RA8875.h"
  21. #if defined (USE_FT5206_TOUCH)
  22. #if !defined(SPARK)//wire it's already included in applications.h
  23. #include <Wire.h>
  24. #if defined(___DUESTUFF) && defined(USE_DUE_WIRE1_INTERFACE)
  25. #define Wire Wire1
  26. #endif
  27. #endif
  28. const uint8_t _ctpAdrs = 0x38;
  29. const uint8_t coordRegStart[5] = {0x03,0x09,0x0F,0x15,0x1B};
  30. static volatile bool _FT5206_INT = false;
  31. #endif
  32. //static volatile uint8_t _RA8875_INTS = 0b00000000;//container for INT states
  33. RA8875 *RA8875::_active_touch_objects[3] = {nullptr, nullptr, nullptr};
  34. /*------------------------------
  35. Bit: Called by: In use:
  36. --------------------------------
  37. 0: isr triggered [*]
  38. 1: Resistive TS [*]
  39. 2: KeyScan [*]
  40. 3: DMA
  41. 4: BTE
  42. 5: FT5206 TS [*]
  43. 6: -na-
  44. 7: -na-
  45. --------------------------------*/
  46. /**************************************************************************/
  47. /*!
  48. Contructors
  49. CSp: SPI SS pin
  50. RSTp: Reset pin
  51. INTp: INT pin
  52. //Teensy 3.0 , 3.1 , LC
  53. mosi_pin
  54. sclk_pin
  55. miso_pin
  56. Note:
  57. Teensy CS SPI1:[MOSI1(0) MISO1(1) CLK1(20) CS1(6)]
  58. */
  59. /**************************************************************************/
  60. //------------------------------TEENSY 3/3.1 ---------------------------------------
  61. #if defined(__MK20DX128__) || defined(__MK20DX256__)
  62. RA8875::RA8875(const uint8_t CSp,const uint8_t RSTp,const uint8_t mosi_pin,const uint8_t sclk_pin,const uint8_t miso_pin)
  63. {
  64. _mosi = mosi_pin;
  65. _miso = miso_pin;
  66. _sclk = sclk_pin;
  67. _cs = CSp;
  68. _rst = RSTp;
  69. _RA8875_INTS = 0b00000000;
  70. //------------------------------Teensy LC-------------------------------------------
  71. #elif defined(__MKL26Z64__)
  72. RA8875::RA8875(const uint8_t CSp,const uint8_t RSTp,const uint8_t mosi_pin,const uint8_t sclk_pin,const uint8_t miso_pin)
  73. {
  74. _mosi = mosi_pin;
  75. _miso = miso_pin;
  76. _sclk = sclk_pin;
  77. _cs = CSp;
  78. _rst = RSTp;
  79. _pspi = nullptr;
  80. _RA8875_INTS = 0b00000000;
  81. //------------------------------Teensy of the future -------------------------------------------
  82. #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)
  83. RA8875::RA8875(const uint8_t CSp,const uint8_t RSTp,const uint8_t mosi_pin,const uint8_t sclk_pin,const uint8_t miso_pin)
  84. {
  85. _mosi = mosi_pin;
  86. _miso = miso_pin;
  87. _sclk = sclk_pin;
  88. _cs = CSp;
  89. _rst = RSTp;
  90. _pspi = nullptr;
  91. _RA8875_INTS = 0b00000000;
  92. //---------------------------------DUE--------------------------------------------
  93. #elif defined(___DUESTUFF)//DUE
  94. RA8875::RA8875(const uint8_t CSp, const uint8_t RSTp)
  95. {
  96. _cs = CSp;
  97. _rst = RSTp;
  98. _RA8875_INTS = 0b00000000;
  99. //---------------------------------SPARK----------------------------------------
  100. #elif defined(SPARK)//SPARK
  101. RA8875::RA8875(const uint8_t CSp, const uint8_t RSTp)
  102. {
  103. _cs = CSp;
  104. _rst = RSTp;
  105. _RA8875_INTS = 0b00000000;
  106. //------------------------------ENERGIA-------------------------------------------
  107. #elif defined(NEEDS_SET_MODULE)
  108. RA8875::RA8875(const uint8_t module, const uint8_t RSTp)
  109. {
  110. selectCS(module);
  111. _rst = RSTp;
  112. _cs = 255;
  113. _RA8875_INTS = 0b00000000;
  114. //----------------------------8 BIT ARDUINO's---------------------------------------
  115. #else
  116. RA8875::RA8875(const uint8_t CSp, const uint8_t RSTp)
  117. {
  118. _cs = CSp;
  119. _rst = RSTp;
  120. _RA8875_INTS = 0b00000000;
  121. #endif
  122. }
  123. /**************************************************************************/
  124. /*!
  125. Helper for Energia, it will set CS pin accordly module selected
  126. module: 0...3
  127. [private]
  128. */
  129. /**************************************************************************/
  130. #if defined(NEEDS_SET_MODULE)
  131. void RA8875::selectCS(uint8_t module)
  132. {
  133. if (module > 3) module = 3;
  134. switch(module){
  135. case 0:
  136. _cs = PA_3;
  137. break;
  138. case 1:
  139. _cs = PF_3;
  140. break;
  141. case 2:
  142. _cs = PB_5;
  143. break;
  144. case 3:
  145. _cs = PD_1;
  146. break;
  147. }
  148. SPImodule = module;
  149. }
  150. #endif
  151. /**************************************************************************/
  152. /*!
  153. Initialize library and SPI
  154. Parameter:
  155. (display type)
  156. RA8875_480x272 (4.3" displays)
  157. RA8875_800x480 (5" and 7" displays)
  158. Adafruit_480x272 (4.3" Adafruit displays)
  159. Adafruit_800x480 (5" and 7" Adafruit displays)
  160. (colors) - The color depth (default 16) 8 or 16 (bit)
  161. -------------------------------------------------------------
  162. UPDATE! in Energia IDE some devices needs an extra parameter!
  163. module: sets the SPI interface (it depends from MCU). Default:0
  164. */
  165. /**************************************************************************/
  166. void RA8875::begin(const enum RA8875sizes s,uint8_t colors, uint32_t SPIMaxSpeed, uint32_t SPIMaxReadSpeed )
  167. {
  168. _errorCode = 0;
  169. _displaySize = s;
  170. _rotation = 0;
  171. _portrait = false;
  172. _inited = false;
  173. _sleep = false;
  174. _hasLayerLimits = false;
  175. _intPin = 255;
  176. _intNum = 0;
  177. _useISR = false;
  178. _enabledInterrups = 0b00000000;
  179. #if defined(SPI_HAS_TRANSACTION)
  180. _SPIMaxSpeed = SPIMaxSpeed;
  181. _SPIMaxReadSpeed = SPIMaxReadSpeed;
  182. #endif
  183. /* used to understand wat causes an INT
  184. bit
  185. 0:
  186. 1:
  187. 2: Touch (resistive)
  188. 3:
  189. 4:
  190. 5:
  191. 6:
  192. 7:
  193. 8:
  194. */
  195. #if defined(USE_FT5206_TOUCH)
  196. _intCTSPin = 255;
  197. _intCTSNum = 0;
  198. #endif
  199. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  200. _TXTForeColor = _RA8875_DEFAULTTXTFRGRND;
  201. #if defined(_RA8875_DEFAULTTXTBKGRND)
  202. _TXTBackColor = _RA8875_DEFAULTTXTBKGRND;
  203. #else
  204. _TXTBackColor = 0x0000;
  205. #endif
  206. _TXTrecoverColor = false;
  207. #endif
  208. _maxLayers = 2;
  209. _currentLayer = 0;
  210. _useMultiLayers = false;//starts with one layer only
  211. _textMode = false;
  212. _brightness = 255;
  213. _cursorX = 0; _cursorY = 0; _scrollXL = 0; _scrollXR = 0; _scrollYT = 0; _scrollYB = 0;
  214. _scaleX = 1; _scaleY = 1;
  215. _scaling = false;
  216. _EXTFNTsize = X16;
  217. _FNTspacing = 0;
  218. //_FNTrender = false;
  219. /* set--> _TXTparameters <--
  220. 0:_extFontRom = false;
  221. 1:_autoAdvance = true;
  222. 2:_textWrap = user defined
  223. 3:_fontFullAlig = false;
  224. 4:_fontRotation = false;//not used
  225. 5:_alignXToCenter = false;
  226. 6:_alignYToCenter = false;
  227. 7: render = false;
  228. */
  229. _TXTparameters = 0b00000010;
  230. bitWrite(_TXTparameters,2,_DFT_RA8875_TEXTWRAP);//set _textWrap
  231. _relativeCenter = false;
  232. _absoluteCenter = false;
  233. _EXTFNTrom = _DFT_RA8875_EXTFONTROMTYPE;
  234. _EXTFNTcoding = _DFT_RA8875_EXTFONTROMCODING;
  235. _FNTinterline = 0;
  236. _EXTFNTfamily = STANDARD;
  237. _FNTcursorType = NOCURSOR;
  238. _FNTgrandient = false;
  239. _arcAngle_max = ARC_ANGLE_MAX;
  240. _arcAngle_offset = ARC_ANGLE_OFFSET;
  241. _angle_offset = ANGLE_OFFSET;
  242. _color_bpp = 16;
  243. _colorIndex = 0;
  244. if (colors != 16) {
  245. _color_bpp = 8;
  246. _colorIndex = 3;
  247. }
  248. switch (_displaySize){
  249. case RA8875_480x272:
  250. case Adafruit_480x272:
  251. _width = 480;
  252. _height = 272;
  253. _initIndex = 0;
  254. break;
  255. case RA8875_800x480:
  256. case Adafruit_800x480:
  257. case RA8875_800x480ALT:
  258. _width = 800;
  259. _height = 480;
  260. _hasLayerLimits = true;
  261. _maxLayers = 1;
  262. if (_color_bpp < 16) _maxLayers = 2;
  263. _initIndex = 1;
  264. if (_displaySize == RA8875_800x480ALT) _initIndex = 2;
  265. break;
  266. default:
  267. _errorCode |= (1 << 0);//set
  268. return;
  269. }
  270. RA8875_WIDTH = _width;
  271. RA8875_HEIGHT = _height;
  272. _activeWindowXL = 0;
  273. _activeWindowXR = RA8875_WIDTH;
  274. _activeWindowYT = 0;
  275. _activeWindowYB = RA8875_HEIGHT;
  276. //hack
  277. _cursorY = 0;
  278. _cursorY = 0;
  279. textsize = 1;
  280. setTextSize(1);
  281. wrap = true;
  282. font = NULL;
  283. setClipRect();
  284. setOrigin();
  285. #if !defined(_AVOID_TOUCHSCREEN)//common to all touch
  286. _clearTInt = false;
  287. _touchEnabled = false;
  288. #if defined(USE_RA8875_TOUCH)//resistive touch
  289. _touchrcal_xlow = TOUCSRCAL_XLOW; _touchrcal_ylow = TOUCSRCAL_YLOW; _touchrcal_xhigh = TOUCSRCAL_XHIGH; _touchrcal_yhigh = TOUCSRCAL_YHIGH;
  290. _calibrated = _isCalibrated();//check calibration at startup
  291. if (!_calibrated) {
  292. _tsAdcMinX = 0; _tsAdcMinY = 0; _tsAdcMaxX = 1023; _tsAdcMaxY = 1023;
  293. } else {
  294. _tsAdcMinX = TOUCSRCAL_XLOW; _tsAdcMinY = TOUCSRCAL_YLOW; _tsAdcMaxX = TOUCSRCAL_XHIGH; _tsAdcMaxY = TOUCSRCAL_YHIGH;
  295. }
  296. #endif
  297. #endif
  298. #if defined(USE_RA8875_KEYMATRIX)
  299. _keyMatrixEnabled = false;
  300. #endif
  301. /* Display Configuration Register [0x20]
  302. 7: (Layer Setting Control) 0:one Layer, 1:two Layers
  303. 6,5,4: (na)
  304. 3: (Horizontal Scan Direction) 0: SEG0 to SEG(n-1), 1: SEG(n-1) to SEG0
  305. 2: (Vertical Scan direction) 0: COM0 to COM(n-1), 1: COM(n-1) to COM0
  306. 1,0: (na) */
  307. _DPCR_Reg = 0b00000000;
  308. /* Memory Write Control Register 0 [0x40]
  309. 7: 0(graphic mode), 1(textx mode)
  310. 6: 0(font-memory cursor not visible), 1(visible)
  311. 5: 0(normal), 1(blinking)
  312. 4: na
  313. 3-2: 00(LR,TB), 01(RL,TB), 10(TB,LR), 11(BT,LR)
  314. 1: 0(Auto Increase in write), 1(no)
  315. 0: 0(Auto Increase in read), 1(no) */
  316. _MWCR0_Reg = 0b00000000;
  317. /* Font Control Register 0 [0x21]
  318. 7: 0(CGROM font is selected), 1(CGRAM font is selected)
  319. 6: na
  320. 5: 0(Internal CGROM [reg 0x2F to 00]), 1(External CGROM [0x2E reg, bit6,7 to 0)
  321. 4-2: na
  322. 1-0: 00(ISO/IEC 8859-1), 01(ISO/IEC 8859-2), 10(ISO/IEC 8859-3), 11(ISO/IEC 8859-4)*/
  323. _FNCR0_Reg = 0b00000000;
  324. /* Font Control Register 1 [0x22]
  325. 7: 0(Full Alignment off), 1(Full Alignment on)
  326. 6: 0(no-trasparent), 1(trasparent)
  327. 5: na
  328. 4: 0(normal), 1(90degrees)
  329. 3-2: 00(x1), 01(x2), 10(x3), 11(x3) Horizontal font scale
  330. 1-0: 00(x1), 01(x2), 10(x3), 11(x3) Vertical font scale */
  331. _FNCR1_Reg = 0b00000000;
  332. /* Font Write Type Setting Register [0x2E]
  333. 7-6: 00(16x16,8x16,nx16), 01(24x24,12x24,nx24), 1x(32x32,16x32, nx32)
  334. 5-0: 00...3F (font width off to 63 pixels)*/
  335. _FWTSET_Reg = 0b00000000;
  336. /* Serial Font ROM Setting [0x2F]
  337. GT Serial Font ROM Select
  338. 7-5: 000(GT21L16TW/GT21H16T1W),001(GT30L16U2W),010(GT30L24T3Y/GT30H24T3Y),011(GT30L24M1Z),111(GT30L32S4W/GT30H32S4W)
  339. FONT ROM Coding Setting
  340. 4-2: 000(GB2312),001(GB12345/GB18030),010(BIG5),011(UNICODE),100(ASCII),101(UNI-Japanese),110(JIS0208),111(Latin/Greek/Cyrillic/Arabic)
  341. 1-0: 00...11
  342. bits ASCII Lat/Gr/Cyr Arabic
  343. 00 normal normal na
  344. 01 Arial var Wdth Pres Forms A
  345. 10 Roman na Pres Forms B
  346. 11 Bold na na */
  347. _SFRSET_Reg = 0b00000000;
  348. /* Interrupt Control Register1 [0xF0]
  349. 7,6,5: (na)
  350. 4: KEYSCAN Interrupt Enable Bit
  351. 3: DMA Interrupt Enable Bit
  352. 2: TOUCH Panel Interrupt Enable Bit
  353. 1: BTE Process Complete Interrupt Enable Bit
  354. 0:
  355. When MCU-relative BTE operation is selected(*1) and BTE
  356. Function is Enabled(REG[50h] Bit7 = 1), this bit is used to
  357. Enable the BTE Interrupt for MCU R/W:
  358. 0 : Disable BTE interrupt for MCU R/W.
  359. 1 : Enable BTE interrupt for MCU R/W.
  360. When the BTE Function is Disabled, this bit is used to
  361. Enable the Interrupt of Font Write Function:
  362. 0 : Disable font write interrupt.
  363. 1 : Enable font write interrupt.
  364. */
  365. _INTC1_Reg = 0b00000000;
  366. //------------------------------- Start SPI initialization ------------------------------------------
  367. #if defined(__MK20DX128__) || defined(__MK20DX256__)
  368. //always uses SPI transaction
  369. if ((_mosi == 11 || _mosi == 7) && (_miso == 12 || _miso == 8) && (_sclk == 13 || _sclk == 14)) {//valid SPI pins?
  370. if (_mosi != 11) SPI.setMOSI(_mosi);
  371. if (_miso != 12) SPI.setMISO(_miso);
  372. if (_sclk != 13) SPI.setSCK(_sclk);
  373. } else {
  374. _errorCode |= (1 << 1);//set
  375. return;
  376. }
  377. pinMode(_cs, OUTPUT);
  378. SPI.begin();
  379. digitalWrite(_cs, HIGH);
  380. #elif defined(__MK64FX512__) || defined(__MK66FX1M0__)//future teensys
  381. //always uses SPI transaction
  382. //always uses SPI transaction
  383. if (SPI.pinIsMISO(_miso) && SPI.pinIsMOSI(_mosi) && SPI.pinIsSCK(_sclk)) {
  384. _pspi = &SPI;
  385. if (_mosi != 11) SPI.setMOSI(_mosi);
  386. if (_miso != 12) SPI.setMISO(_miso);
  387. if (_sclk != 13) SPI.setSCK(_sclk);
  388. //Serial.println("Use SPI");
  389. } else if (SPI1.pinIsMISO(_miso) && SPI1.pinIsMOSI(_mosi) && SPI1.pinIsSCK(_sclk)) {
  390. _pspi = &SPI1;
  391. if (_mosi != 0) SPI1.setMOSI(_mosi);
  392. if (_miso != 1) SPI1.setMISO(_miso);
  393. if (_sclk != 32) SPI1.setSCK(_sclk);
  394. //Serial.println("Use SPI1");
  395. } else if (SPI2.pinIsMISO(_miso) && SPI2.pinIsMOSI(_mosi) && SPI2.pinIsSCK(_sclk)) {
  396. _pspi = &SPI2;
  397. if (_mosi != 44) SPI2.setMOSI(_mosi);
  398. if (_miso != 45) SPI2.setMISO(_miso);
  399. if (_sclk != 46) SPI2.setSCK(_sclk);
  400. //Serial.println("Use SPI2");
  401. } else {
  402. _errorCode |= (1 << 1);//set
  403. return;
  404. }
  405. pinMode(_cs, OUTPUT);
  406. _pspi->begin();
  407. digitalWrite(_cs, HIGH);
  408. #elif defined(__IMXRT1062__)
  409. //always uses SPI transaction
  410. if (SPI.pinIsMISO(_miso) && SPI.pinIsMOSI(_mosi) && SPI.pinIsSCK(_sclk)) {
  411. _pspi = &SPI;
  412. } else if (SPI1.pinIsMISO(_miso) && SPI1.pinIsMOSI(_mosi) && SPI1.pinIsSCK(_sclk)) {
  413. _pspi = &SPI1;
  414. } else if (SPI2.pinIsMISO(_miso) && SPI2.pinIsMOSI(_mosi) && SPI2.pinIsSCK(_sclk)) {
  415. _pspi = &SPI2;
  416. } else {
  417. _errorCode |= (1 << 1);//set
  418. return;
  419. }
  420. // Make sure we select the right pins.
  421. // On T4 does nothing, and on T4.1 only miso matters, but just in case.
  422. _pspi->setMISO(_miso);
  423. _pspi->setMOSI(_mosi);
  424. _pspi->setSCK(_sclk);
  425. pinMode(_cs, OUTPUT);
  426. _pspi->begin();
  427. digitalWrite(_cs, HIGH);
  428. #elif defined(__MKL26Z64__)//TeensyLC
  429. //always uses SPI ransaction
  430. #if TEENSYDUINO > 121//not supported prior 1.22!
  431. if (SPI.pinIsMISO(_miso) && SPI.pinIsMOSI(_mosi) && SPI.pinIsSCK(_sclk)) {
  432. _pspi = &SPI;
  433. if (_mosi != 11) SPI.setMOSI(_mosi);
  434. if (_miso != 12) SPI.setMISO(_miso);
  435. if (_sclk != 13) SPI.setSCK(_sclk);
  436. //Serial.println("Use SPI");
  437. } else if (SPI1.pinIsMISO(_miso) && SPI1.pinIsMOSI(_mosi) && SPI1.pinIsSCK(_sclk)) {
  438. _pspi = &SPI1;
  439. if (_mosi != 0) SPI1.setMOSI(_mosi);
  440. if (_miso != 1) SPI1.setMISO(_miso);
  441. if (_sclk != 20) SPI1.setSCK(_sclk);
  442. //Serial.println("Use SPI1");
  443. } else {
  444. _errorCode |= (1 << 1);//set
  445. return;
  446. }
  447. pinMode(_cs, OUTPUT);
  448. _pspi->begin();
  449. digitalWrite(_cs, HIGH);
  450. #else
  451. _pspi = &SPI;
  452. pinMode(_cs, OUTPUT);
  453. SPI.begin();
  454. digitalWrite(_cs, HIGH);
  455. _errorCode |= (1 << 3);//set
  456. #endif
  457. #elif !defined(ENERGIA)//everithing but ENERGIA
  458. #if defined(___DUESTUFF)// DUE
  459. #if defined(SPI_DUE_MODE_EXTENDED)
  460. //DUE SPI mode extended you can use only follow pins
  461. if (_cs == 4 || _cs == 10 || _cs == 52) {
  462. SPI.begin(_cs);
  463. } else {
  464. _errorCode |= (1 << 2);//error! wrong cs pin
  465. return;
  466. }
  467. #else
  468. //DUE in normal SPI mode
  469. pinMode(_cs, OUTPUT);
  470. SPI.begin();
  471. #if defined(_FASTSSPORT)
  472. csport = portOutputRegister(digitalPinToPort(_cs));
  473. cspinmask = digitalPinToBitMask(_cs);
  474. *csport |= cspinmask;//hi
  475. #else
  476. digitalWrite(_cs, HIGH);
  477. #endif
  478. #endif
  479. #elif defined(ESP8266)
  480. pinMode(_cs, OUTPUT);
  481. SPI.begin();
  482. #if defined(_FASTSSPORT)
  483. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, _pinRegister(_cs));//H
  484. #else
  485. digitalWrite(_cs, HIGH);//for now
  486. #endif
  487. #elif defined(SPARK)
  488. pinMode(_cs, OUTPUT);
  489. SPI.begin();
  490. pinSetFast(_cs);//for now
  491. #else
  492. //UNO,MEGA,Yun,nano,duemilanove and other 8 bit arduino's
  493. pinMode(_cs, OUTPUT);
  494. SPI.begin();
  495. csport = portOutputRegister(digitalPinToPort(_cs));//pinMode(_cs, OUTPUT);
  496. cspinmask = digitalPinToBitMask(_cs);
  497. *csport |= cspinmask;//hi
  498. #endif
  499. #endif
  500. if (_rst < 255){//time for hardware reset RA8875
  501. pinMode(_rst, OUTPUT);
  502. digitalWrite(_rst, HIGH);
  503. delay(10);
  504. digitalWrite(_rst, LOW);
  505. delay(220);//120
  506. digitalWrite(_rst, HIGH);
  507. delay(300);//200
  508. }
  509. #if defined(ENERGIA) && defined(NEEDS_SET_MODULE)//energia specific
  510. SPI.setModule(SPImodule);
  511. #endif
  512. //set SPI SPEED, starting at low speed, after init will raise up!
  513. #if defined(SPI_HAS_TRANSACTION)
  514. _SPITransactionSpeed = 4000000UL;//we start in low speed here!
  515. #else//do not use SPItransactons
  516. #if defined (__AVR__)//8 bit arduino's
  517. pinMode(_cs, OUTPUT);
  518. SPI.begin();
  519. SPI.setClockDivider(SPI_SPEED_SAFE);
  520. delay(1);
  521. SPI.setDataMode(SPI_MODE3);
  522. #else
  523. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  524. SPI.setClockDivider(_cs,SPI_SPEED_SAFE);
  525. delay(1);
  526. SPI.setDataMode(_cs,SPI_MODE3);
  527. #elif defined (ESP8266)
  528. SPI.setClockDivider(SPI_SPEED_SAFE);
  529. delay(1);
  530. SPI.setDataMode(SPI_MODE0);
  531. #elif defined(SPARK)
  532. SPI.setClockDivider(SPI_SPEED_SAFE);
  533. delay(1);
  534. SPI.setDataMode(SPI_MODE0);
  535. #else
  536. SPI.setClockDivider(SPI_SPEED_SAFE);
  537. delay(1);
  538. SPI.setDataMode(SPI_MODE3);
  539. #endif
  540. #endif
  541. #endif
  542. #if defined(ENERGIA)//dunno why but energia wants this here or not work!
  543. pinMode(_cs, OUTPUT);
  544. digitalWrite(_cs, HIGH);
  545. #endif
  546. //SPI initialization done
  547. if (_errorCode != 0) return;//ouch, error/s.Better stop here!
  548. _initialize();//----->Time to Initialize the RA8875!
  549. //------- time for capacitive touch stuff -----------------
  550. #if defined(USE_FT5206_TOUCH)
  551. _wire->begin();
  552. #if defined(___DUESTUFF)
  553. _wire->setClock(400000UL); // Set I2C frequency to 400kHz
  554. /*
  555. #if !defined(USE_DUE_WIRE1_INTERFACE)//sorry but I do not own a DUE, have to learn about Wire1
  556. // Force 400 KHz I2C, rawr! (Uses pins 20, 21 for SDA, SCL)
  557. TWI1->TWI_CWGR = 0;
  558. TWI1->TWI_CWGR = ((VARIANT_MCK / (2 * 400000)) - 4) * 0x101;
  559. #endif
  560. */
  561. #else
  562. //TODO, Dunno what to do here with SPARK
  563. #if ARDUINO >= 157
  564. _wire->setClock(400000UL); // Set I2C frequency to 400kHz
  565. #else
  566. TWBR = ((F_CPU / 400000UL) - 16) / 2; // Set I2C frequency to 400kHz
  567. #endif
  568. #endif
  569. delay(10);
  570. _initializeFT5206();//initialize FT5206 controller
  571. _maxTouch = 5;
  572. _gesture = 0;
  573. _currentTouches = 0;
  574. _currentTouchState = 0;
  575. _needISRrearm = false;
  576. //TO DO
  577. //Modify RA8875 registers and disconnect internal Touch Screen totally
  578. #endif
  579. if(_displaySize == Adafruit_480x272 || _displaySize == Adafruit_800x480 ) GPIOX(true);
  580. }
  581. /************************* Initialization *********************************/
  582. /**************************************************************************/
  583. /*!
  584. Hardware initialization of RA8875 and turn on
  585. [private]
  586. */
  587. /**************************************************************************/
  588. void RA8875::_initialize()
  589. {
  590. _inited = false;
  591. // HACK to setup SPI MODE 3
  592. /* SPI.beginTransaction(SPISettings(_SPIMaxSpeed, MSBFIRST, SPI_MODE3));
  593. SPI.transfer(0);
  594. SPI.endTransaction();
  595. delay(1);
  596. */
  597. if (_rst == 255) {// soft reset time ?
  598. writeCommand(RA8875_PWRR);
  599. _writeData(RA8875_PWRR_SOFTRESET);
  600. delay(20);
  601. _writeData(RA8875_PWRR_NORMAL);
  602. delay(200);
  603. }
  604. //set the sysClock
  605. _setSysClock(initStrings[_initIndex][0],initStrings[_initIndex][1],initStrings[_initIndex][2]);
  606. //color space setup
  607. if (_color_bpp < 16){//256
  608. _writeRegister(RA8875_SYSR,0x00);//256
  609. _colorIndex = 3;
  610. } else {
  611. _writeRegister(RA8875_SYSR,0x0C);//65K
  612. _colorIndex = 0;
  613. }
  614. _writeRegister(RA8875_HDWR,initStrings[_initIndex][3]); //LCD Horizontal Display Width Register
  615. _writeRegister(RA8875_HNDFTR,initStrings[_initIndex][4]); //Horizontal Non-Display Period Fine Tuning Option Register
  616. _writeRegister(RA8875_HNDR,initStrings[_initIndex][5]); //LCD Horizontal Non-Display Period Register
  617. _writeRegister(RA8875_HSTR,initStrings[_initIndex][6]); //HSYNC Start Position Register
  618. _writeRegister(RA8875_HPWR,initStrings[_initIndex][7]); //HSYNC Pulse Width Register
  619. _writeRegister(RA8875_VDHR0,initStrings[_initIndex][8]); //LCD Vertical Display Height Register0
  620. _writeRegister(RA8875_VDHR0+1,initStrings[_initIndex][9]); //LCD Vertical Display Height Register1
  621. _writeRegister(RA8875_VNDR0,initStrings[_initIndex][10]); //LCD Vertical Non-Display Period Register 0
  622. _writeRegister(RA8875_VNDR0+1,initStrings[_initIndex][11]); //LCD Vertical Non-Display Period Register 1
  623. _writeRegister(RA8875_VSTR0,initStrings[_initIndex][12]); //VSYNC Start Position Register 0
  624. _writeRegister(RA8875_VSTR0+1,initStrings[_initIndex][13]); //VSYNC Start Position Register 1
  625. _writeRegister(RA8875_VPWR,initStrings[_initIndex][14]); //VSYNC Pulse Width Register
  626. _updateActiveWindow(true); //set the whole screen as active
  627. //clearActiveWindow();
  628. delay(10); //100
  629. setCursorBlinkRate(DEFAULTCURSORBLINKRATE);//set default blink rate
  630. setIntFontCoding(DEFAULTINTENCODING);//set default internal font encoding
  631. setFont(INTFONT); //set internal font use
  632. //postburner PLL!
  633. _setSysClock(sysClockPar[_initIndex][0],sysClockPar[_initIndex][1],initStrings[_initIndex][2]);
  634. _inited = true;
  635. //from here we will go at high speed!
  636. #if defined(SPI_HAS_TRANSACTION)
  637. if (_SPIMaxSpeed == (uint32_t)-1) {
  638. #if defined(__MKL26Z64__)
  639. _SPIMaxSpeed = (_pspi != &SPI)? MAXSPISPEED2 : MAXSPISPEED;
  640. #else
  641. _SPIMaxSpeed = MAXSPISPEED;
  642. #endif
  643. }
  644. if (_SPIMaxReadSpeed == (uint32_t)-1) {
  645. _SPIMaxReadSpeed = MAXSPIREADSPEED;
  646. }
  647. _SPITransactionSpeed = _SPIMaxSpeed;
  648. //Serial.printf("SPI Transaction speed: %d Max Speed:%d\n", _SPITransactionSpeed, _SPIMaxSpeed);
  649. #endif
  650. #if defined(_FASTCPU)
  651. _slowDownSPI(false);
  652. #else
  653. #if defined(SPI_HAS_TRANSACTION)
  654. #else
  655. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  656. SPI.setClockDivider(_cs,SPI_SPEED_WRITE);
  657. #else
  658. SPI.setClockDivider(SPI_SPEED_WRITE);
  659. #endif
  660. #endif
  661. #endif
  662. delay(1);
  663. clearMemory();//clearMemory(true);
  664. delay(1);
  665. displayOn(true);//turn On Display
  666. delay(1);
  667. fillWindow(_RA8875_DEFAULTBACKLIGHT);//set screen black
  668. backlight(true);
  669. setRotation(_RA8875_DEFAULTSCRROT);
  670. _setTextMode(false);
  671. setActiveWindow();
  672. #if defined(_RA8875_DEFAULTTXTBKGRND)
  673. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  674. setForegroundColor(_TXTForeColor);
  675. setBackgroundColor(_TXTBackColor);
  676. #else
  677. setForegroundColor(_RA8875_DEFAULTTXTFRGRND);
  678. setBackgroundColor(_RA8875_DEFAULTTXTBKGRND);
  679. #endif
  680. _backTransparent = false;
  681. _FNCR1_Reg &= ~(1 << 6);//clear
  682. #else
  683. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  684. setForegroundColor(_TXTForeColor);
  685. #else
  686. setForegroundColor(_RA8875_DEFAULTTXTFRGRND);
  687. #endif
  688. _backTransparent = true;
  689. _FNCR1_Reg |= (1 << 6);//set
  690. #endif
  691. _writeRegister(RA8875_FNCR1,_FNCR1_Reg);
  692. setCursor(0,0);
  693. }
  694. /**************************************************************************/
  695. /*!
  696. This function set the sysClock accordly datasheet
  697. Parameters:
  698. pll1: PLL Control Register 1
  699. pll2: PLL Control Register 2
  700. pixclk: Pixel Clock Setting Register
  701. [private]
  702. */
  703. /**************************************************************************/
  704. void RA8875::_setSysClock(uint8_t pll1,uint8_t pll2,uint8_t pixclk)
  705. {
  706. _writeRegister(RA8875_PLLC1,pll1);////PLL Control Register 1
  707. delay(1);
  708. _writeRegister(RA8875_PLLC1+1,pll2);////PLL Control Register 2
  709. delay(1);
  710. _writeRegister(RA8875_PCSR,pixclk);//Pixel Clock Setting Register
  711. delay(1);
  712. }
  713. /**************************************************************************/
  714. /*!
  715. This return a byte with the error code/s:
  716. bit--------------------------------------------------------------------
  717. 0: The display it's not supported!
  718. 1: The MOSI or MISO or SCLK choosed for Teensy it's out permitted range!
  719. 2: The CS pin you selected it's out permitted range!
  720. 3: You have to upgrade to Teensyduino 1.22 or better to use this feature!
  721. 4:
  722. 5:
  723. 6:
  724. 7:
  725. 0b00000000 = no error
  726. */
  727. /**************************************************************************/
  728. uint8_t RA8875::errorCode(void)
  729. {
  730. return _errorCode;
  731. }
  732. /**************************************************************************/
  733. /*!
  734. return true when register has done the job, otherwise false.
  735. */
  736. /**************************************************************************/
  737. boolean RA8875::_waitPoll(uint8_t regname, uint8_t waitflag, uint8_t timeout)
  738. {
  739. uint8_t temp;
  740. unsigned long start_time = millis();
  741. while (1) {
  742. temp = _readRegister(regname);
  743. if (!(temp & waitflag)) {
  744. //unsigned long delta_time = millis() - timeout;
  745. //if ((delta_time > 10) || (waitflag == RA8875_DCR_CIRCLE_STATUS)) Serial.printf("+_waitPoll %x %x %d\n", temp, waitflag, delta_time);
  746. return true;
  747. }
  748. if ((millis() - start_time) > timeout) {
  749. //Serial.printf("TO _waitPoll %x %x\n", temp, waitflag);
  750. return false;//emergency exit!
  751. }
  752. }
  753. return false;
  754. }
  755. /**************************************************************************/
  756. /*!
  757. Just another specified wait routine until job it's done
  758. Parameters:
  759. res:
  760. 0x80(for most operations),
  761. 0x40(BTE wait),
  762. 0x01(DMA wait)
  763. */
  764. /**************************************************************************/
  765. void RA8875::_waitBusy(uint8_t res)
  766. {
  767. uint8_t temp;
  768. unsigned long start = millis();//M.Sandercock
  769. do {
  770. if (res == 0x01) writeCommand(RA8875_DMACR);//dma
  771. temp = readStatus();
  772. if ((millis() - start) > 10) return;
  773. } while ((temp & res) == res);
  774. }
  775. /**************************************************************************/
  776. /*!
  777. Clear memory (different from fillWindow!)
  778. Parameters:
  779. full: true(clear all memory), false(clear active window only)
  780. When in multilayer it automatically clear L1 & L1 and switch back to current layer
  781. */
  782. /**************************************************************************/
  783. /*
  784. void RA8875::clearMemory(boolean full)
  785. {
  786. uint8_t temp = 0b10000000;
  787. if (!full && !_useMultiLayers) temp |= (1 << 6);//set 6
  788. _writeRegister(RA8875_MCLR,temp);
  789. _waitBusy(0x80);
  790. if (full && _useMultiLayers){
  791. temp = 0b10000000;
  792. uint8_t templ = _currentLayer;//remember current layer
  793. if (templ > 0){//we are in L2
  794. writeTo(L1);//switch to L1
  795. } else {
  796. writeTo(L2);//switch to L2
  797. }
  798. _writeRegister(RA8875_MCLR,temp);
  799. _waitBusy(0x80);
  800. if (templ > 0){//we was in L2
  801. writeTo(L2);//switch back to L2
  802. } else {
  803. writeTo(L1);//switch back to L1
  804. }
  805. }
  806. }
  807. */
  808. /**************************************************************************/
  809. /*!
  810. Clear memory (different from fillWindow!)
  811. Parameters:
  812. stop: stop clear memory operation
  813. */
  814. /**************************************************************************/
  815. void RA8875::clearMemory(bool stop)
  816. {
  817. uint8_t temp;
  818. temp = _readRegister(RA8875_MCLR);
  819. stop == true ? temp &= ~(1 << 7) : temp |= (1 << 7);
  820. _writeData(temp);
  821. if (!stop) _waitBusy(0x80);
  822. }
  823. /**************************************************************************/
  824. /*!
  825. Clear the active window
  826. Parameters:
  827. full: false(clear current window), true clear full window
  828. */
  829. /**************************************************************************/
  830. void RA8875::clearActiveWindow(bool full)
  831. {
  832. uint8_t temp;
  833. temp = _readRegister(RA8875_MCLR);
  834. full == true ? temp &= ~(1 << 6) : temp |= (1 << 6);
  835. _writeData(temp);
  836. //_waitBusy(0x80);
  837. }
  838. /**************************************************************************/
  839. /*!
  840. Clear width BG color
  841. Parameters:
  842. bte: false(clear width BTE BG color), true(clear width font BG color)
  843. */
  844. /**************************************************************************/
  845. void RA8875::clearWidthColor(bool bte)
  846. {
  847. uint8_t temp;
  848. temp = _readRegister(RA8875_MCLR);
  849. bte == true ? temp &= ~(1 << 0) : temp |= (1 << 0);
  850. _writeData(temp);
  851. //_waitBusy(0x80);
  852. }
  853. /**************************************************************************/
  854. /*!
  855. turn display on/off
  856. */
  857. /**************************************************************************/
  858. void RA8875::displayOn(boolean on)
  859. {
  860. on == true ? _writeRegister(RA8875_PWRR, RA8875_PWRR_NORMAL | RA8875_PWRR_DISPON) : _writeRegister(RA8875_PWRR, RA8875_PWRR_NORMAL | RA8875_PWRR_DISPOFF);
  861. }
  862. /**************************************************************************/
  863. /*!
  864. Set the Active Window
  865. Parameters:
  866. XL: Horizontal Left
  867. XR: Horizontal Right
  868. YT: Vertical TOP
  869. YB: Vertical Bottom
  870. */
  871. /**************************************************************************/
  872. void RA8875::setActiveWindow(int16_t XL,int16_t XR ,int16_t YT ,int16_t YB)
  873. {
  874. if (_portrait){ swapvals(XL,YT); swapvals(XR,YB);}
  875. if (XR >= RA8875_WIDTH) XR = RA8875_WIDTH;
  876. if (YB >= RA8875_HEIGHT) YB = RA8875_HEIGHT;
  877. _activeWindowXL = XL; _activeWindowXR = XR;
  878. _activeWindowYT = YT; _activeWindowYB = YB;
  879. _updateActiveWindow(false);
  880. }
  881. /**************************************************************************/
  882. /*!
  883. Set the Active Window as FULL SCREEN
  884. */
  885. /**************************************************************************/
  886. void RA8875::setActiveWindow(void)
  887. {
  888. _activeWindowXL = 0; _activeWindowXR = RA8875_WIDTH;
  889. _activeWindowYT = 0; _activeWindowYB = RA8875_HEIGHT;
  890. if (_portrait){swapvals(_activeWindowXL,_activeWindowYT); swapvals(_activeWindowXR,_activeWindowYB);}
  891. _updateActiveWindow(true);
  892. }
  893. /**************************************************************************/
  894. /*!
  895. Set the Active Window
  896. Parameters:
  897. XL: Horizontal Left
  898. XR: Horizontal Right
  899. YT: Vertical TOP
  900. YB: Vertical Bottom
  901. */
  902. /**************************************************************************/
  903. void RA8875::getActiveWindow(int16_t &XL,int16_t &XR ,int16_t &YT ,int16_t &YB)//0.69b24
  904. {
  905. XL = _activeWindowXL; XR = _activeWindowXR;
  906. YT = _activeWindowYT; YB = _activeWindowYB;
  907. }
  908. /**************************************************************************/
  909. /*!
  910. Return the max tft width.
  911. Parameters:
  912. absolute: if true will return the phisical width
  913. */
  914. /**************************************************************************/
  915. uint16_t RA8875::width(bool absolute) const
  916. {
  917. if (absolute) return RA8875_WIDTH;
  918. return _width;
  919. }
  920. /**************************************************************************/
  921. /*!
  922. Return the max tft height.
  923. Parameters:
  924. absolute: if true will return the phisical height
  925. */
  926. /**************************************************************************/
  927. uint16_t RA8875::height(bool absolute) const
  928. {
  929. if (absolute) return RA8875_HEIGHT;
  930. return _height;
  931. }
  932. /**************************************************************************/
  933. /*!
  934. Change the mode between graphic and text
  935. Parameters:
  936. m: can be GRAPHIC or TEXT
  937. [private]
  938. */
  939. /**************************************************************************/
  940. void RA8875::_setTextMode(bool m)
  941. {
  942. if (m == _textMode) return;
  943. writeCommand(RA8875_MWCR0);
  944. //if (m != 0){//text
  945. if (m){//text
  946. _MWCR0_Reg |= (1 << 7);
  947. _textMode = true;
  948. } else {//graph
  949. _MWCR0_Reg &= ~(1 << 7);
  950. _textMode = false;
  951. }
  952. _writeData(_MWCR0_Reg);
  953. }
  954. /**************************************************************************/
  955. /*!
  956. Change the beam scan direction on display
  957. Parameters:
  958. invertH: true(inverted),false(normal) horizontal
  959. invertV: true(inverted),false(normal) vertical
  960. */
  961. /**************************************************************************/
  962. void RA8875::_scanDirection(boolean invertH,boolean invertV)
  963. {
  964. invertH == true ? _DPCR_Reg |= (1 << 3) : _DPCR_Reg &= ~(1 << 3);
  965. invertV == true ? _DPCR_Reg |= (1 << 2) : _DPCR_Reg &= ~(1 << 2);
  966. _writeRegister(RA8875_DPCR,_DPCR_Reg);
  967. }
  968. /**************************************************************************/
  969. /*!
  970. Change the rotation of the screen
  971. Parameters:
  972. rotation:
  973. 0 = default
  974. 1 = 90
  975. 2 = 180
  976. 3 = 270
  977. */
  978. /**************************************************************************/
  979. void RA8875::setRotation(uint8_t rotation)//0.69b32 - less code
  980. {
  981. _rotation = rotation % 4; //limit to the range 0-3
  982. switch (_rotation) {
  983. case 0:
  984. //default, connector to bottom
  985. _portrait = false;
  986. _scanDirection(0,0);
  987. #if defined(USE_RA8875_TOUCH)
  988. if (!_calibrated) {
  989. _tsAdcMinX = 0; _tsAdcMinY = 0; _tsAdcMaxX = 1023; _tsAdcMaxY = 1023;
  990. } else {
  991. _tsAdcMinX = _touchrcal_xlow; _tsAdcMinY = _touchrcal_ylow; _tsAdcMaxX = _touchrcal_xhigh; _tsAdcMaxY = _touchrcal_yhigh;
  992. }
  993. #endif
  994. break;
  995. case 1:
  996. //90
  997. _portrait = true;
  998. _scanDirection(1,0);
  999. #if defined(USE_RA8875_TOUCH)
  1000. if (!_calibrated) {
  1001. _tsAdcMinX = 1023; _tsAdcMinY = 0; _tsAdcMaxX = 0; _tsAdcMaxY = 1023;
  1002. } else {
  1003. _tsAdcMinX = _touchrcal_yhigh; _tsAdcMinY = _touchrcal_xlow; _tsAdcMaxX = _touchrcal_ylow; _tsAdcMaxY = _touchrcal_xhigh;
  1004. }
  1005. #endif
  1006. break;
  1007. case 2:
  1008. //180
  1009. _portrait = false;
  1010. _scanDirection(1,1);
  1011. #if defined(USE_RA8875_TOUCH)
  1012. if (!_calibrated) {
  1013. _tsAdcMinX = 1023; _tsAdcMinY = 1023; _tsAdcMaxX = 0; _tsAdcMaxY = 0;
  1014. } else {
  1015. _tsAdcMinX = _touchrcal_xhigh; _tsAdcMinY = _touchrcal_yhigh; _tsAdcMaxX = _touchrcal_xlow; _tsAdcMaxY = _touchrcal_ylow;
  1016. }
  1017. #endif
  1018. break;
  1019. case 3:
  1020. //270
  1021. _portrait = true;
  1022. _scanDirection(0,1);
  1023. #if defined(USE_RA8875_TOUCH)
  1024. if (!_calibrated) {
  1025. _tsAdcMinX = 0; _tsAdcMinY = 1023; _tsAdcMaxX = 1023; _tsAdcMaxY = 0;
  1026. } else {
  1027. _tsAdcMinX = _touchrcal_ylow; _tsAdcMinY = _touchrcal_xhigh; _tsAdcMaxX = _touchrcal_yhigh; _tsAdcMaxY = _touchrcal_xlow;
  1028. }
  1029. #endif
  1030. break;
  1031. }
  1032. if (_portrait){
  1033. _width = RA8875_HEIGHT;
  1034. _height = RA8875_WIDTH;
  1035. _FNCR1_Reg |= (1 << 4);
  1036. } else {
  1037. _width = RA8875_WIDTH;
  1038. _height = RA8875_HEIGHT;
  1039. _FNCR1_Reg &= ~(1 << 4);
  1040. }
  1041. _writeRegister(RA8875_FNCR1,_FNCR1_Reg);//0.69b21
  1042. setClipRect();
  1043. }
  1044. /**************************************************************************/
  1045. /*!
  1046. Get rotation setting
  1047. */
  1048. /**************************************************************************/
  1049. uint8_t RA8875::getRotation()
  1050. {
  1051. return _rotation;
  1052. }
  1053. /**************************************************************************/
  1054. /*!
  1055. true if rotation 1 or 3
  1056. */
  1057. /**************************************************************************/
  1058. boolean RA8875::isPortrait(void)
  1059. {
  1060. return _portrait;
  1061. }
  1062. /*
  1063. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1064. + TEXT STUFF +
  1065. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1066. */
  1067. /**************************************************************************/
  1068. /*! Upload user custom char or symbol to CGRAM, max 255
  1069. Parameters:
  1070. symbol[]: an 8bit x 16 char in an array. Must be exact 16 bytes
  1071. address: 0...255 the address of the CGRAM where to store the char
  1072. */
  1073. /**************************************************************************/
  1074. void RA8875::uploadUserChar(const uint8_t symbol[],uint8_t address)
  1075. {
  1076. uint8_t tempMWCR1 = _readRegister(RA8875_MWCR1);//thanks MorganSandercock
  1077. uint8_t i;
  1078. if (_textMode) _setTextMode(false);//we are in text mode?
  1079. _writeRegister(RA8875_CGSR,address);
  1080. writeTo(CGRAM);
  1081. writeCommand(RA8875_MRWC);
  1082. for (i=0;i<16;i++){
  1083. _writeData(symbol[i]);
  1084. }
  1085. _writeRegister(RA8875_MWCR1, tempMWCR1);//restore register
  1086. }
  1087. /**************************************************************************/
  1088. /*! Retrieve and print to screen the user custom char or symbol
  1089. User have to store a custom char before use this function
  1090. Parameters:
  1091. address: 0...255 the address of the CGRAM where char it's stored
  1092. wide:0 for single 8x16 char, if you have wider chars that use
  1093. more than a char slot they can be showed combined (see examples)
  1094. */
  1095. /**************************************************************************/
  1096. void RA8875::showUserChar(uint8_t symbolAddrs,uint8_t wide)
  1097. {
  1098. if (!_textMode) _setTextMode(true);//we are in graph mode?
  1099. uint8_t oldReg1State = _FNCR0_Reg;
  1100. uint8_t oldReg2State = 0;
  1101. uint8_t i;
  1102. oldReg1State |= (1 << 7);//set to CGRAM
  1103. oldReg1State |= (1 << 5);//TODO:check this (page 19)
  1104. _writeRegister(RA8875_FNCR0,oldReg1State);
  1105. if (_scaling){//reset scale (not compatible with this!)
  1106. oldReg2State = _FNCR1_Reg;
  1107. oldReg2State &= ~(0xF); // clear bits from 0 to 3
  1108. _writeRegister(RA8875_FNCR1,oldReg2State);
  1109. }
  1110. //layers?
  1111. if (_useMultiLayers){
  1112. if (_currentLayer == 0){
  1113. writeTo(L1);
  1114. } else {
  1115. writeTo(L2);
  1116. }
  1117. } else {
  1118. //writeTo(L1);
  1119. }
  1120. writeCommand(RA8875_MRWC);
  1121. _writeData(symbolAddrs);
  1122. if (wide > 0){
  1123. for (i=1;i<=wide;i++){
  1124. _writeData(symbolAddrs+i);
  1125. }
  1126. }
  1127. if (oldReg2State != 0) _writeRegister(RA8875_FNCR1,_FNCR1_Reg);//put back scale as it was
  1128. if (oldReg1State != _FNCR0_Reg) _writeRegister(RA8875_FNCR0,_FNCR0_Reg);//put back state
  1129. }
  1130. /**************************************************************************/
  1131. /*!
  1132. Set internal Font Encoding
  1133. Parameters:
  1134. f: ISO_IEC_8859_1, ISO_IEC_8859_2, ISO_IEC_8859_3, ISO_IEC_8859_4
  1135. default: ISO_IEC_8859_1
  1136. */
  1137. /**************************************************************************/
  1138. void RA8875::setIntFontCoding(enum RA8875fontCoding f)
  1139. {
  1140. uint8_t temp = _FNCR0_Reg;
  1141. temp &= ~((1<<1) | (1<<0));// Clear bits 1 and 0
  1142. switch (f){
  1143. case ISO_IEC_8859_1:
  1144. //do nothing
  1145. break;
  1146. case ISO_IEC_8859_2:
  1147. temp |= (1 << 0);
  1148. break;
  1149. case ISO_IEC_8859_3:
  1150. temp |= (1 << 1);
  1151. break;
  1152. case ISO_IEC_8859_4:
  1153. temp |= ((1<<1) | (1<<0));// Set bits 1 and 0
  1154. break;
  1155. default:
  1156. return;
  1157. }
  1158. _FNCR0_Reg = temp;
  1159. _writeRegister(RA8875_FNCR0,_FNCR0_Reg);
  1160. }
  1161. /**************************************************************************/
  1162. /*!
  1163. External Font Rom setup
  1164. This will not phisically change the register but should be called before setFont(EXTFONT)!
  1165. You should use this values accordly Font ROM datasheet!
  1166. Parameters:
  1167. ert: ROM Type (GT21L16T1W, GT21H16T1W, GT23L16U2W, GT30H24T3Y, GT23L24T3Y, GT23L24M1Z, GT23L32S4W, GT30H32S4W)
  1168. erc: ROM Font Encoding (GB2312, GB12345, BIG5, UNICODE, ASCII, UNIJIS, JIS0208, LATIN)
  1169. erf: ROM Font Family (STANDARD, ARIAL, ROMAN, BOLD)
  1170. */
  1171. /**************************************************************************/
  1172. void RA8875::setExternalFontRom(enum RA8875extRomType ert, enum RA8875extRomCoding erc, enum RA8875extRomFamily erf)
  1173. {
  1174. if (!_textMode) _setTextMode(true);
  1175. _SFRSET_Reg = _readRegister(RA8875_FNCR0);;//just to preserve the reg in case something wrong
  1176. uint8_t temp = 0b00000000;
  1177. switch(ert){ //type of rom
  1178. case GT21L16T1W:
  1179. case GT21H16T1W:
  1180. temp &= 0x1F;
  1181. break;
  1182. case GT23L16U2W:
  1183. case GT30L16U2W:
  1184. case ER3301_1:
  1185. temp &= 0x1F; temp |= 0x20;
  1186. break;
  1187. case GT23L24T3Y:
  1188. case GT30H24T3Y:
  1189. case ER3303_1://encoding GB12345
  1190. temp &= 0x1F; temp |= 0x40;
  1191. break;
  1192. case GT23L24M1Z:
  1193. temp &= 0x1F; temp |= 0x60;
  1194. break;
  1195. case GT23L32S4W:
  1196. case GT30H32S4W:
  1197. case GT30L32S4W:
  1198. case ER3304_1://encoding GB2312
  1199. temp &= 0x1F; temp |= 0x80;
  1200. break;
  1201. default:
  1202. _TXTparameters &= ~(1 << 0);//wrong type, better avoid for future
  1203. return;//cannot continue, exit
  1204. }
  1205. _EXTFNTrom = ert;
  1206. switch(erc){ //check rom font coding
  1207. case GB2312:
  1208. temp &= 0xE3;
  1209. break;
  1210. case GB12345:
  1211. temp &= 0xE3; temp |= 0x04;
  1212. break;
  1213. case BIG5:
  1214. temp &= 0xE3; temp |= 0x08;
  1215. break;
  1216. case UNICODE:
  1217. temp &= 0xE3; temp |= 0x0C;
  1218. break;
  1219. case ASCII:
  1220. temp &= 0xE3; temp |= 0x10;
  1221. break;
  1222. case UNIJIS:
  1223. temp &= 0xE3; temp |= 0x14;
  1224. break;
  1225. case JIS0208:
  1226. temp &= 0xE3; temp |= 0x18;
  1227. break;
  1228. case LATIN:
  1229. temp &= 0xE3; temp |= 0x1C;
  1230. break;
  1231. default:
  1232. _TXTparameters &= ~(1 << 0);//wrong coding, better avoid for future
  1233. return;//cannot continue, exit
  1234. }
  1235. _EXTFNTcoding = erc;
  1236. _SFRSET_Reg = temp;
  1237. setExtFontFamily(erf,false);
  1238. _TXTparameters |= (1 << 0); //bit set 0
  1239. //_writeRegister(RA8875_SFRSET,_SFRSET_Reg);//0x2F
  1240. //delay(4);
  1241. }
  1242. void RA8875::fontRomSpeed(uint8_t sp)
  1243. {
  1244. _writeRegister(0x28,sp);
  1245. }
  1246. /**************************************************************************/
  1247. /*!
  1248. select the font family for the external Font Rom Chip
  1249. Parameters:
  1250. erf: STANDARD, ARIAL, ROMAN, BOLD
  1251. setReg:
  1252. true(send phisically the register, useful when you change
  1253. family after set setExternalFontRom)
  1254. false:(change only the register container, useful during config)
  1255. NOTE: works only when external font rom it's active
  1256. */
  1257. /**************************************************************************/
  1258. void RA8875::setExtFontFamily(enum RA8875extRomFamily erf,boolean setReg)
  1259. {
  1260. if (_FNTsource == EXTFONT) {//only on EXTFONT ROM fonts!
  1261. _EXTFNTfamily = erf;
  1262. _SFRSET_Reg &= ~(0x03); // clear bits from 0 to 1
  1263. switch(erf){ //check rom font family
  1264. case STANDARD:
  1265. _SFRSET_Reg &= 0xFC;
  1266. break;
  1267. case ARIAL:
  1268. _SFRSET_Reg &= 0xFC; _SFRSET_Reg |= 0x01;
  1269. break;
  1270. case ROMAN:
  1271. _SFRSET_Reg &= 0xFC; _SFRSET_Reg |= 0x02;
  1272. break;
  1273. case BOLD:
  1274. _SFRSET_Reg |= ((1<<1) | (1<<0)); // set bits 1 and 0
  1275. break;
  1276. default:
  1277. _EXTFNTfamily = STANDARD; _SFRSET_Reg &= 0xFC;
  1278. return;
  1279. }
  1280. if (setReg) _writeRegister(RA8875_SFRSET,_SFRSET_Reg);
  1281. }
  1282. }
  1283. /**************************************************************************/
  1284. /*!
  1285. choose from internal/external (if exist) Font Rom
  1286. Parameters:
  1287. s: Font source (INTFONT,EXTFONT)
  1288. */
  1289. /**************************************************************************/
  1290. void RA8875::setFont(enum RA8875fontSource s)
  1291. {
  1292. _use_int_font = 1;
  1293. _use_tfont = 0;
  1294. _use_ili_font = 0;
  1295. _use_gfx_font = 0;
  1296. if (!_textMode) _setTextMode(true);//we are in graph mode?
  1297. _TXTparameters &= ~(1 << 7);//render OFF
  1298. if (s == INTFONT){
  1299. _setFNTdimensions(0);
  1300. //check the font coding
  1301. if (bitRead(_TXTparameters,0) == 1) {//0.96b22 _extFontRom = true
  1302. setFontSize(X16);
  1303. _writeRegister(RA8875_SFRSET,0b00000000);//_SFRSET_Reg
  1304. }
  1305. _FNCR0_Reg &= ~((1<<7) | (1<<5));// Clear bits 7 and 5 (set internal CGROM)
  1306. _writeRegister(RA8875_FNCR0,_FNCR0_Reg);
  1307. _FNTsource = s;
  1308. delay(1);
  1309. } else if (s == EXTFONT){
  1310. if (bitRead(_TXTparameters,0) == 1) {//0.96b22 _extFontRom = true
  1311. _FNTsource = s;
  1312. //now switch
  1313. _FNCR0_Reg &= ~(1 << 7);//clearBit 7
  1314. _FNCR0_Reg |= (1 << 5);//setBit 5
  1315. _writeRegister(RA8875_FNCR0,_FNCR0_Reg);//0x21
  1316. delay(1);
  1317. _writeRegister(RA8875_SFCLR,0x03);//0x02 Serial Flash/ROM CLK frequency/2
  1318. setFontSize(X16);
  1319. _writeRegister(RA8875_SFRSET,_SFRSET_Reg);//at this point should be already set
  1320. delay(4);
  1321. _writeRegister(RA8875_SROC,0x28);// 0x28 rom 0,24bit adrs,wave 3,1 byte dummy,font mode, single mode 00101000
  1322. delay(4);
  1323. } else {
  1324. setFont(INTFONT);
  1325. _setFNTdimensions(0);
  1326. }
  1327. } else {
  1328. return;
  1329. }
  1330. _spaceCharWidth = _FNTwidth;
  1331. //setFontScale(0);
  1332. _scaleX = 1; _scaleY = 1;//reset font scale
  1333. }
  1334. void RA8875::_setFNTdimensions(uint8_t index)
  1335. {
  1336. _FNTwidth = fontDimPar[index][0];
  1337. _FNTheight = fontDimPar[index][1];
  1338. _FNTbaselineLow = fontDimPar[index][2];
  1339. _FNTbaselineTop = fontDimPar[index][3];
  1340. }
  1341. /**************************************************************************/
  1342. /*!
  1343. choose an external font that will be rendered
  1344. Of course slower that internal fonts!
  1345. Parameters:
  1346. *font: &myfont
  1347. */
  1348. /**************************************************************************/
  1349. void RA8875::setFont(const tFont *font)
  1350. {
  1351. _use_tfont = 1;
  1352. _use_int_font = 0;
  1353. _use_ili_font = 0;
  1354. _use_gfx_font = 0;
  1355. _currentFont = font;
  1356. _FNTheight = _currentFont->font_height;
  1357. _FNTwidth = _currentFont->font_width;//if 0 it's variable width font
  1358. _FNTcompression = _currentFont->rle;
  1359. //get all needed infos
  1360. if (_FNTwidth > 0){
  1361. _spaceCharWidth = _FNTwidth;
  1362. } else {
  1363. //_FNTwidth will be 0 to inform other functions that this it's a variable w font
  1364. // We just get the space width now...
  1365. int temp = _getCharCode(0x20);
  1366. if (temp > -1){
  1367. #if defined(_FORCE_PROGMEM__)
  1368. #if defined(ESP8266)
  1369. _spaceCharWidth = FPSTR(&_currentFont->chars[temp].image->image_width);
  1370. #else
  1371. _spaceCharWidth = PROGMEM_read(&_currentFont->chars[temp].image->image_width);
  1372. #endif
  1373. #else
  1374. _spaceCharWidth = (_currentFont->chars[temp].image->image_width);
  1375. #endif
  1376. } else {
  1377. //font malformed, doesn't have needed space parameter
  1378. //will return to system font
  1379. setFont(INTFONT);
  1380. return;
  1381. }
  1382. }
  1383. _scaleX = 1; _scaleY = 1;//reset font scale
  1384. //setFontScale(0);
  1385. _TXTparameters |= (1 << 7);//render ON
  1386. }
  1387. /**************************************************************************/
  1388. /*!
  1389. Enable/Disable the Font Full Alignemet feature (default off)
  1390. Parameters:
  1391. align: true,false
  1392. Note: not active with rendered fonts
  1393. */
  1394. /**************************************************************************/
  1395. void RA8875::setFontFullAlign(boolean align)
  1396. {
  1397. if (bitRead(_TXTparameters,7) == 0){
  1398. align == true ? _FNCR1_Reg |= (1 << 7) : _FNCR1_Reg &= ~(1 << 7);
  1399. _writeRegister(RA8875_FNCR1,_FNCR1_Reg);
  1400. }
  1401. }
  1402. /**************************************************************************/
  1403. /*!
  1404. Set distance between text lines (default off)
  1405. Parameters:
  1406. pix: 0...63 pixels
  1407. Note: active with rendered fonts
  1408. */
  1409. /**************************************************************************/
  1410. void RA8875::setFontInterline(uint8_t pix)
  1411. {
  1412. if (bitRead(_TXTparameters,7) == 1){
  1413. _FNTinterline = pix;
  1414. } else {
  1415. if (pix > 0x3F) pix = 0x3F;
  1416. _FNTinterline = pix;
  1417. //_FWTSET_Reg &= 0xC0;
  1418. //_FWTSET_Reg |= spc & 0x3F;
  1419. _writeRegister(RA8875_FLDR,_FNTinterline);
  1420. }
  1421. }
  1422. /**************************************************************************/
  1423. /*!
  1424. Set the Text position for write Text only.
  1425. Parameters:
  1426. x:horizontal in pixels or CENTER(of the screen)
  1427. y:vertical in pixels or CENTER(of the screen)
  1428. autocenter:center text to choosed x,y regardless text lenght
  1429. false: |ABCD
  1430. true: AB|CD
  1431. NOTE: works with any font
  1432. */
  1433. /**************************************************************************/
  1434. void RA8875::setCursor(int16_t x, int16_t y,bool autocenter)
  1435. {
  1436. if (x < 0) x = 0;
  1437. if (y < 0) y = 0;
  1438. _absoluteCenter = autocenter;
  1439. if (_portrait) {//rotation 1,3
  1440. if (_use_default) swapvals(x,y);
  1441. if (y == CENTER) {//swapped OK
  1442. y = _width/2;
  1443. if (!autocenter) {
  1444. _relativeCenter = true;
  1445. _TXTparameters |= (1 << 6);//set x flag
  1446. }
  1447. }
  1448. if (x == CENTER) {//swapped
  1449. x = _height/2;
  1450. if (!autocenter) {
  1451. _relativeCenter = true;
  1452. _TXTparameters |= (1 << 5);//set y flag
  1453. }
  1454. }
  1455. } else {//rotation 0,2
  1456. if (x == CENTER) {
  1457. x = _width/2;
  1458. if (!autocenter) {
  1459. _relativeCenter = true;
  1460. _TXTparameters |= (1 << 5);
  1461. }
  1462. }
  1463. if (y == CENTER) {
  1464. y = _height/2;
  1465. if (!autocenter) {
  1466. _relativeCenter = true;
  1467. _TXTparameters |= (1 << 6);
  1468. }
  1469. }
  1470. }
  1471. //TODO: This one? Useless?
  1472. if (bitRead(_TXTparameters,2) == 0){//textWrap
  1473. if (x >= _width) x = _width-1;
  1474. if (y >= _height) y = _height-1;
  1475. }
  1476. _cursorX = x;
  1477. _cursorY = y;
  1478. //if _relativeCenter or _absoluteCenter do not apply to registers yet!
  1479. // Have to go to _textWrite first to calculate the lenght of the entire string and recalculate the correct x,y
  1480. if (_relativeCenter || _absoluteCenter) return;
  1481. if (bitRead(_TXTparameters,7) == 0) _textPosition(x,y,false);
  1482. }
  1483. /**************************************************************************/
  1484. /*!
  1485. Set the x,y position for text only
  1486. Parameters:
  1487. x: horizontal pos in pixels
  1488. y: vertical pos in pixels
  1489. update: true track the actual text position internally
  1490. note: not active with rendered fonts, just set x,y internal tracked param
  1491. [private]
  1492. */
  1493. /**************************************************************************/
  1494. void RA8875::_textPosition(int16_t x, int16_t y,bool update)
  1495. {
  1496. #if defined(FORCE_RA8875_TXTREND_FOLLOW_CURS)
  1497. _writeRegister(RA8875_F_CURXL,(x & 0xFF));
  1498. _writeRegister(RA8875_F_CURXH,(x >> 8));
  1499. _writeRegister(RA8875_F_CURYL,(y & 0xFF));
  1500. _writeRegister(RA8875_F_CURYH,(y >> 8));
  1501. #else
  1502. if (bitRead(_TXTparameters,7) == 0){
  1503. _writeRegister(RA8875_F_CURXL,(x & 0xFF));
  1504. _writeRegister(RA8875_F_CURXH,(x >> 8));
  1505. _writeRegister(RA8875_F_CURYL,(y & 0xFF));
  1506. _writeRegister(RA8875_F_CURYH,(y >> 8));
  1507. }
  1508. #endif
  1509. if (update){ _cursorX = x; _cursorY = y;}
  1510. }
  1511. /**************************************************************************/
  1512. /*!
  1513. Give you back the current text cursor position by reading inside RA8875
  1514. Parameters:
  1515. x: horizontal pos in pixels
  1516. y: vertical pos in pixels
  1517. note: works also with rendered fonts
  1518. USE: xxx.getCursor(myX,myY);
  1519. */
  1520. /**************************************************************************/
  1521. void RA8875::getCursor(int16_t &x, int16_t &y)
  1522. {
  1523. if (bitRead(_TXTparameters,7) == 1) {
  1524. getCursorFast(x,y);
  1525. } else {
  1526. uint8_t t1,t2,t3,t4;
  1527. t1 = _readRegister(RA8875_F_CURXL);
  1528. t2 = _readRegister(RA8875_F_CURXH);
  1529. t3 = _readRegister(RA8875_F_CURYL);
  1530. t4 = _readRegister(RA8875_F_CURYH);
  1531. x = (t2 << 8) | (t1 & 0xFF);
  1532. y = (t4 << 8) | (t3 & 0xFF);
  1533. if (_portrait && _use_default) swapvals(x,y);
  1534. }
  1535. }
  1536. /**************************************************************************/
  1537. /*!
  1538. Give you back the current text cursor position as tracked by library (fast)
  1539. Parameters:
  1540. x: horizontal pos in pixels
  1541. y: vertical pos in pixels
  1542. note: works also with rendered fonts
  1543. USE: xxx.getCursor(myX,myY);
  1544. */
  1545. /**************************************************************************/
  1546. void RA8875::getCursorFast(int16_t &x, int16_t &y)
  1547. {
  1548. x = _cursorX;
  1549. y = _cursorY;
  1550. if (_portrait && _use_default) swapvals(x,y);
  1551. }
  1552. int16_t RA8875::getCursorX(void)
  1553. {
  1554. if (_portrait && _use_default) return _cursorY;
  1555. return _cursorX;
  1556. }
  1557. int16_t RA8875::getCursorY(void)
  1558. {
  1559. if (_portrait && _use_default) return _cursorX;
  1560. return _cursorY;
  1561. }
  1562. /**************************************************************************/
  1563. /*! Show/Hide text cursor
  1564. Parameters:
  1565. c: cursor type (NOCURSOR,IBEAM,UNDER,BLOCK)
  1566. note: not active with rendered fonts
  1567. blink: true=blink cursor
  1568. */
  1569. /**************************************************************************/
  1570. void RA8875::showCursor(enum RA8875tcursor c,bool blink)
  1571. {
  1572. //uint8_t MWCR1Reg = _readRegister(RA8875_MWCR1) & 0x01;(needed?)
  1573. uint8_t cW = 0;
  1574. uint8_t cH = 0;
  1575. _FNTcursorType = c;
  1576. c == NOCURSOR ? _MWCR0_Reg &= ~(1 << 6) : _MWCR0_Reg |= (1 << 6);
  1577. if (blink) _MWCR0_Reg |= 0x20;//blink or not?
  1578. _writeRegister(RA8875_MWCR0, _MWCR0_Reg);//set cursor
  1579. //_writeRegister(RA8875_MWCR1, MWCR1Reg);//close graphic cursor(needed?)
  1580. switch (c) {
  1581. case IBEAM:
  1582. cW = 0x01;
  1583. cH = 0x1F;
  1584. break;
  1585. case UNDER:
  1586. cW = 0x07;
  1587. cH = 0x01;
  1588. break;
  1589. case BLOCK:
  1590. cW = 0x07;
  1591. cH = 0x1F;
  1592. break;
  1593. case NOCURSOR:
  1594. default:
  1595. break;
  1596. }
  1597. //set cursor size
  1598. _writeRegister(RA8875_CURHS, cW);
  1599. _writeRegister(RA8875_CURVS, cH);
  1600. }
  1601. /**************************************************************************/
  1602. /*! Set cursor property blink and his rate
  1603. Parameters:
  1604. rate: blink speed (fast 0...255 slow)
  1605. note: not active with rendered fonts
  1606. */
  1607. /**************************************************************************/
  1608. void RA8875::setCursorBlinkRate(uint8_t rate)
  1609. {
  1610. _writeRegister(RA8875_BTCR,rate);//set blink rate
  1611. }
  1612. /**************************************************************************/
  1613. /*!
  1614. set the text color and his background
  1615. Parameters:
  1616. fcolor: 16bit foreground color (text) RGB565
  1617. bcolor: 16bit background color RGB565
  1618. NOTE: will set background trasparent OFF
  1619. It also works with rendered fonts.
  1620. */
  1621. /**************************************************************************/
  1622. void RA8875::setTextColor(uint16_t fcolor, uint16_t bcolor)//0.69b30
  1623. {
  1624. if(_use_ili_font){
  1625. //for anti-alias font only
  1626. // pre-expand colors for fast alpha-blending later
  1627. textcolorPrexpanded = (fcolor | (fcolor << 16)) & 0b00000111111000001111100000011111;
  1628. textbgcolorPrexpanded = (bcolor | (bcolor << 16)) & 0b00000111111000001111100000011111;
  1629. }
  1630. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  1631. if (fcolor != _TXTForeColor) {
  1632. _TXTForeColor = fcolor;
  1633. setForegroundColor(fcolor);
  1634. }
  1635. if (bcolor != _TXTBackColor) {
  1636. _TXTBackColor = bcolor;
  1637. setBackgroundColor(bcolor);
  1638. }
  1639. _backTransparent = false;
  1640. #else
  1641. _backTransparent = false;
  1642. if (fcolor != _foreColor) setForegroundColor(fcolor);
  1643. if (bcolor != _backColor) setBackgroundColor(bcolor);
  1644. #endif
  1645. if (bitRead(_TXTparameters,7) == 0) {
  1646. _FNCR1_Reg &= ~(1 << 6);//clear
  1647. _writeRegister(RA8875_FNCR1,_FNCR1_Reg);
  1648. }
  1649. }
  1650. /**************************************************************************/
  1651. /*!
  1652. set the text color w transparent background
  1653. Parameters:
  1654. fColor: 16bit foreground color (text) RGB565
  1655. NOTE: will set background trasparent ON
  1656. It also works with rendered fonts.
  1657. */
  1658. /**************************************************************************/
  1659. void RA8875::setTextColor(uint16_t fcolor)
  1660. {
  1661. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  1662. if (fcolor != _TXTForeColor) {
  1663. _TXTForeColor = fcolor;
  1664. setForegroundColor(fcolor);
  1665. }
  1666. _backTransparent = true;
  1667. #else
  1668. _backTransparent = true;
  1669. if (fcolor != _foreColor) setForegroundColor(fcolor);
  1670. #endif
  1671. if (bitRead(_TXTparameters,7) == 0) {
  1672. _FNCR1_Reg |= (1 << 6);//set
  1673. _writeRegister(RA8875_FNCR1,_FNCR1_Reg);
  1674. }
  1675. }
  1676. void RA8875::setTextGrandient(uint16_t fcolor1,uint16_t fcolor2)
  1677. {
  1678. _FNTgrandient = true;
  1679. _FNTgrandientColor1 = fcolor1;
  1680. _FNTgrandientColor2 = fcolor2;
  1681. }
  1682. /**************************************************************************/
  1683. /*!
  1684. Set the Text size by it's multiple. normal should=0, max is 3 (x4) for internal fonts
  1685. With Rendered fonts the max scale it's not limited
  1686. Parameters:
  1687. scale: 0..3 -> 0:normal, 1:x2, 2:x3, 3:x4
  1688. */
  1689. /**************************************************************************/
  1690. void RA8875::setFontScale(uint8_t scale)
  1691. {
  1692. setFontScale(scale,scale);
  1693. }
  1694. /**************************************************************************/
  1695. /*!
  1696. Set the Text size by it's multiple. normal should=0, max is 3 (x4) for internal fonts
  1697. With Rendered fonts the max scale it's not limited
  1698. This time you can specify different values for vertical and horizontal
  1699. Parameters:
  1700. xscale: 0..3 -> 0:normal, 1:x2, 2:x3, 3:x4 for internal fonts - 0...xxx for Rendered Fonts
  1701. yscale: 0..3 -> 0:normal, 1:x2, 2:x3, 3:x4 for internal fonts - 0...xxx for Rendered Fonts
  1702. */
  1703. /**************************************************************************/
  1704. void RA8875::setFontScale(uint8_t xscale,uint8_t yscale)
  1705. {
  1706. _scaling = false;
  1707. if (bitRead(_TXTparameters,7) == 0){
  1708. xscale = xscale % 4; //limit to the range 0-3
  1709. yscale = yscale % 4; //limit to the range 0-3
  1710. _FNCR1_Reg &= ~(0xF); // clear bits from 0 to 3
  1711. _FNCR1_Reg |= xscale << 2;
  1712. _FNCR1_Reg |= yscale;
  1713. _writeRegister(RA8875_FNCR1,_FNCR1_Reg);
  1714. }
  1715. _scaleX = xscale + 1;
  1716. _scaleY = yscale + 1;
  1717. if (_scaleX > 1 || _scaleY > 1) _scaling = true;
  1718. }
  1719. /**************************************************************************/
  1720. /*!
  1721. Normally at every char the cursor advance by one
  1722. You can stop/enable this by using this function
  1723. Parameters:
  1724. on: true(auto advance - default), false:(stop auto advance)
  1725. Note: Inactive with rendered fonts
  1726. */
  1727. /**************************************************************************/
  1728. void RA8875::cursorIncrement(bool on)
  1729. {
  1730. if (bitRead(_TXTparameters,7) == 0){
  1731. on == true ? _MWCR0_Reg &= ~(1 << 1) : _MWCR0_Reg |= (1 << 1);
  1732. bitWrite(_TXTparameters,1,on);
  1733. _writeRegister(RA8875_MWCR0,_MWCR0_Reg);
  1734. }
  1735. }
  1736. /**************************************************************************/
  1737. /*!
  1738. Choose between 16x16(8x16) - 24x24(12x24) - 32x32(16x32)
  1739. for External Font ROM
  1740. Parameters:
  1741. ts: X16,X24,X32
  1742. Note: Inactive with rendered fonts
  1743. TODO: Modify font size variables accordly font size!
  1744. */
  1745. /**************************************************************************/
  1746. void RA8875::setFontSize(enum RA8875tsize ts)
  1747. {
  1748. if (_FNTsource == EXTFONT && bitRead(_TXTparameters,7) == 0) {
  1749. switch(ts){
  1750. case X16:
  1751. _FWTSET_Reg &= 0x3F;
  1752. _setFNTdimensions(1);
  1753. break;
  1754. case X24:
  1755. _FWTSET_Reg &= 0x3F; _FWTSET_Reg |= 0x40;
  1756. _setFNTdimensions(2);
  1757. break;
  1758. case X32:
  1759. _FWTSET_Reg &= 0x3F; _FWTSET_Reg |= 0x80;
  1760. _setFNTdimensions(3);
  1761. break;
  1762. default:
  1763. return;
  1764. }
  1765. _EXTFNTsize = ts;
  1766. _writeRegister(RA8875_FWTSET,_FWTSET_Reg);
  1767. }
  1768. }
  1769. /**************************************************************************/
  1770. /*!
  1771. return the current width of the font in pixel
  1772. If font it's scaled, it will multiply.
  1773. It's a fast business since the register it's internally tracked
  1774. It can also return the usable rows based on the actual fontWidth
  1775. Parameters: inColums (true:returns max colums)
  1776. TODO: modded for Rendered Fonts
  1777. */
  1778. /**************************************************************************/
  1779. uint8_t RA8875::getFontWidth(boolean inColums)
  1780. {
  1781. uint8_t temp;
  1782. if (bitRead(_TXTparameters,7) == 1){
  1783. temp = _FNTwidth;
  1784. if (temp < 1) return 0; //variable with
  1785. } else {
  1786. temp = (((_FNCR0_Reg >> 2) & 0x3) + 1) * _FNTwidth;
  1787. }
  1788. if (inColums){
  1789. if (_scaleX < 2) return (_width / temp);
  1790. temp = temp * _scaleX;
  1791. return (_width / temp);
  1792. } else {
  1793. if (_scaleX < 2) return temp;
  1794. temp = temp * _scaleX;
  1795. return temp;
  1796. }
  1797. }
  1798. /**************************************************************************/
  1799. /*!
  1800. return the current heigh of the font in pixel
  1801. If font it's scaled, it will multiply.
  1802. It's a fast business since the register it's internally tracked
  1803. It can also return the usable rows based on the actual fontHeight
  1804. Parameters: inRows (true:returns max rows)
  1805. TODO: modded for Rendered Fonts
  1806. */
  1807. /**************************************************************************/
  1808. uint8_t RA8875::getFontHeight(boolean inRows)
  1809. {
  1810. uint8_t temp;
  1811. if (bitRead(_TXTparameters,7) == 1){
  1812. temp = _FNTheight;
  1813. } else {
  1814. temp = (((_FNCR0_Reg >> 0) & 0x3) + 1) * _FNTheight;
  1815. }
  1816. if (inRows){
  1817. if (_scaleY < 2) return (_height / temp);
  1818. temp = temp * _scaleY;
  1819. return (_height / temp);
  1820. } else {
  1821. if (_scaleY < 2) return temp;
  1822. temp = temp * _scaleY;
  1823. return temp;
  1824. }
  1825. }
  1826. /**************************************************************************/
  1827. /*!
  1828. Choose space in pixels between chars
  1829. Parameters:
  1830. spc: 0...63pix (default 0=off)
  1831. TODO: modded for Rendered Fonts
  1832. */
  1833. /**************************************************************************/
  1834. void RA8875::setFontSpacing(uint8_t spc)
  1835. {
  1836. if (spc > 0x3F) spc = 0x3F;
  1837. _FNTspacing = spc;
  1838. if (bitRead(_TXTparameters,7) == 0){
  1839. _FWTSET_Reg &= 0xC0;
  1840. _FWTSET_Reg |= spc & 0x3F;
  1841. _writeRegister(RA8875_FWTSET,_FWTSET_Reg);
  1842. }
  1843. }
  1844. /**************************************************************************/
  1845. /*! PRIVATE
  1846. draw a string
  1847. Works for all fonts, internal, ROM, external (render)
  1848. */
  1849. /**************************************************************************/
  1850. void RA8875::_textWrite(const char* buffer, uint16_t len)
  1851. {
  1852. uint16_t i;
  1853. if (len == 0) len = strlen(buffer);//try get the info from the buffer
  1854. if (len == 0) return;//better stop here, the string it's really empty!
  1855. bool renderOn = bitRead(_TXTparameters,7);//detect if render fonts active
  1856. uint8_t loVOffset = 0;
  1857. uint8_t hiVOffset = 0;
  1858. uint8_t interlineOffset = 0;
  1859. uint16_t fcolor = _foreColor;
  1860. uint16_t bcolor = _backColor;
  1861. uint16_t strngWidth = 0;
  1862. uint16_t strngHeight = 0;
  1863. if (!renderOn){
  1864. loVOffset = _FNTbaselineLow * _scaleY;//calculate lower baseline
  1865. hiVOffset = _FNTbaselineTop * _scaleY;//calculate topline
  1866. //now check for offset if using an external fonts rom (RA8875 bug)
  1867. if (bitRead(_TXTparameters,0) == 1) interlineOffset = 3 * _scaleY;
  1868. }
  1869. //_absoluteCenter or _relativeCenter cases...................
  1870. //plus calculate the real width & height of the entire text in render mode (not trasparent)
  1871. if (_absoluteCenter || _relativeCenter || (renderOn && !_backTransparent)){
  1872. strngWidth = _STRlen_helper(buffer,len) * _scaleX;//this calculates the width of the entire text
  1873. strngHeight = (_FNTheight * _scaleY) - (loVOffset + hiVOffset);//the REAL heigh
  1874. if (_absoluteCenter && strngWidth > 0){//Avoid operations for strngWidth = 0
  1875. _absoluteCenter = false;
  1876. _cursorX = _cursorX - (strngWidth / 2);
  1877. _cursorY = _cursorY - (strngHeight / 2) - hiVOffset;
  1878. if (_portrait) swapvals(_cursorX,_cursorY);
  1879. } else if (_relativeCenter && strngWidth > 0){//Avoid operations for strngWidth = 0
  1880. _relativeCenter = false;
  1881. if (bitRead(_TXTparameters,5)) {//X = center
  1882. if (!_portrait){
  1883. _cursorX = (_width / 2) - (strngWidth / 2);
  1884. } else {
  1885. _cursorX = (_height / 2) - (strngHeight / 2) - hiVOffset;
  1886. }
  1887. _TXTparameters &= ~(1 << 5);//reset
  1888. }
  1889. if (bitRead(_TXTparameters,6)) {//Y = center
  1890. if (!_portrait){
  1891. _cursorY = (_height / 2) - (strngHeight / 2) - hiVOffset;
  1892. } else {
  1893. _cursorY = (_width / 2) - (strngWidth / 2);
  1894. }
  1895. _TXTparameters &= ~(1 << 6);//reset
  1896. }
  1897. }
  1898. //if ((_absoluteCenter || _relativeCenter) && strngWidth > 0){//Avoid operations for strngWidth = 0
  1899. if (strngWidth > 0){//Avoid operations for strngWidth = 0
  1900. #if defined(FORCE_RA8875_TXTREND_FOLLOW_CURS)
  1901. _textPosition(_cursorX,_cursorY,false);
  1902. #else
  1903. if (!renderOn) _textPosition(_cursorX,_cursorY,false);
  1904. #endif
  1905. }
  1906. }//_absoluteCenter,_relativeCenter,(renderOn && !_backTransparent)
  1907. //-----------------------------------------------------------------------------------------------
  1908. if (!_textMode && !renderOn) _setTextMode(true);// go to text
  1909. if (_textMode && renderOn) _setTextMode(false);// go to graphic
  1910. //colored text vars
  1911. uint16_t grandientLen = 0;
  1912. uint16_t grandientIndex = 0;
  1913. uint16_t recoverColor = fcolor;
  1914. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  1915. if (_textMode && _TXTrecoverColor){
  1916. if (_foreColor != _TXTForeColor) {_TXTrecoverColor = false;setForegroundColor(_TXTForeColor);}
  1917. if (_backColor != _TXTBackColor) {_TXTrecoverColor = false;setBackgroundColor(_TXTBackColor);}
  1918. } else {
  1919. fcolor = _TXTForeColor;
  1920. bcolor = _TXTBackColor;
  1921. }
  1922. #endif
  1923. if (_FNTgrandient){//coloring text
  1924. recoverColor = _TXTForeColor;
  1925. for (i=0;i<len;i++){//avoid non char in color index
  1926. if (buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32) grandientLen++;//lenght of the interpolation
  1927. }
  1928. }
  1929. #if defined(RA8875_TXTBENCH) && !defined(RA8875_VISPIXDEBUG)//for testing purposes
  1930. unsigned long start = micros();
  1931. #endif
  1932. #if defined(_RA8875_TXTRNDOPTIMIZER)
  1933. //instead write the background by using pixels (trough text rendering) better this trick
  1934. if (renderOn && !_backTransparent && strngWidth > 0) fillRect(_cursorX,_cursorY,strngWidth,strngHeight,_backColor);//bColor
  1935. #endif
  1936. //Loop trough every char and write them one by one...
  1937. for (i=0;i<len;i++){
  1938. if (_FNTgrandient){
  1939. if (buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32){
  1940. if (!renderOn){
  1941. setTextColor(colorInterpolation(_FNTgrandientColor1,_FNTgrandientColor2,grandientIndex++,grandientLen));
  1942. } else {
  1943. fcolor = colorInterpolation(_FNTgrandientColor1,_FNTgrandientColor2,grandientIndex++,grandientLen);
  1944. }
  1945. }
  1946. }
  1947. if (!renderOn){
  1948. _charWrite(buffer[i], interlineOffset); // internal,ROM fonts
  1949. } else {
  1950. _charWriteR(buffer[i], interlineOffset, fcolor, bcolor); // user fonts
  1951. }
  1952. }//end loop
  1953. if (_FNTgrandient){//recover text color after colored text
  1954. _FNTgrandient = false;
  1955. //recover original text color
  1956. if (!renderOn){
  1957. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  1958. setTextColor(recoverColor,_backColor);
  1959. #else
  1960. setTextColor(recoverColor,_backColor);
  1961. #endif
  1962. } else {
  1963. fcolor = recoverColor;
  1964. }
  1965. }
  1966. #if defined(RA8875_TXTBENCH) && !defined(RA8875_VISPIXDEBUG)
  1967. unsigned long result = micros() - start;
  1968. Serial.print("Text Rendered in:");
  1969. Serial.print(result);
  1970. Serial.print(" ms");
  1971. Serial.print("\n");
  1972. #endif
  1973. }
  1974. /**************************************************************************/
  1975. /*! PRIVATE
  1976. Main routine that write a single char in render mode, this actually call another subroutine that do the paint job
  1977. but this one take care of all the calculations...
  1978. NOTE: It identify correctly println and /n & /r
  1979. */
  1980. /**************************************************************************/
  1981. void RA8875::_charWriteR(const char c,uint8_t offset,uint16_t fcolor,uint16_t bcolor)
  1982. {
  1983. if (c == 13){//------------------------------- CARRIAGE ----------------------------------
  1984. //ignore
  1985. } else if (c == 10){//------------------------- NEW LINE ---------------------------------
  1986. if (!_portrait){
  1987. _cursorX = 0;
  1988. _cursorY += (_FNTheight * _scaleY) + _FNTinterline + offset;
  1989. } else {
  1990. _cursorX += (_FNTheight * _scaleY) + _FNTinterline + offset;
  1991. _cursorY = 0;
  1992. }
  1993. #if defined(FORCE_RA8875_TXTREND_FOLLOW_CURS)
  1994. _textPosition(_cursorX,_cursorY,false);
  1995. #endif
  1996. } else if (c == 32){//--------------------------- SPACE ---------------------------------
  1997. if (!_portrait){
  1998. fillRect(_cursorX,_cursorY,(_spaceCharWidth * _scaleX),(_FNTheight * _scaleY),bcolor);//bColor
  1999. _cursorX += (_spaceCharWidth * _scaleX) + _FNTspacing;
  2000. } else {
  2001. fillRect(_cursorY,_cursorX,(_spaceCharWidth * _scaleX),(_FNTheight * _scaleY),bcolor);//bColor
  2002. _cursorY += (_spaceCharWidth * _scaleX) + _FNTspacing;
  2003. }
  2004. // #if defined(FORCE_RA8875_TXTREND_FOLLOW_CURS)
  2005. // _textPosition(_cursorX,_cursorY,false);
  2006. // #endif
  2007. } else {//-------------------------------------- CHAR ------------------------------------
  2008. int charIndex = _getCharCode(c);//get char code
  2009. if (charIndex > -1){//valid?
  2010. int charW = 0;
  2011. //get charW and glyph
  2012. #if defined(_FORCE_PROGMEM__)
  2013. #if defined(ESP8266)
  2014. charW = FPSTR(&_currentFont->chars[charIndex].image->image_width);
  2015. #if !defined(_RA8875_TXTRNDOPTIMIZER)
  2016. const uint8_t * charGlyp = FPSTR(&_currentFont->chars[charIndex].image->data);
  2017. #endif
  2018. #else
  2019. charW = PROGMEM_read(&_currentFont->chars[charIndex].image->image_width);
  2020. #if !defined(_RA8875_TXTRNDOPTIMIZER)
  2021. const uint8_t * charGlyp = PROGMEM_read(&_currentFont->chars[charIndex].image->data);
  2022. #endif
  2023. #endif
  2024. #else
  2025. charW = _currentFont->chars[charIndex].image->image_width;
  2026. #if !defined(_RA8875_TXTRNDOPTIMIZER)
  2027. const uint8_t * charGlyp = _currentFont->chars[charIndex].image->data;
  2028. #endif
  2029. #endif
  2030. //check if goes out of screen and goes to a new line (if wrap) or just avoid
  2031. if (bitRead(_TXTparameters,2)){//wrap?
  2032. if (!_portrait && (_cursorX + charW * _scaleX) >= _width){
  2033. _cursorX = 0;
  2034. _cursorY += (_FNTheight * _scaleY) + _FNTinterline + offset;
  2035. } else if (_portrait && (_cursorY + charW * _scaleY) >= _width){
  2036. _cursorX += (_FNTheight * _scaleY) + _FNTinterline + offset;
  2037. _cursorY = 0;
  2038. }
  2039. #if defined(FORCE_RA8875_TXTREND_FOLLOW_CURS)
  2040. //_textPosition(_cursorX,_cursorY,false);
  2041. #endif
  2042. } else {
  2043. if (_portrait){
  2044. if (_cursorY + charW * _scaleY >= _width) return;
  2045. } else {
  2046. if (_cursorX + charW * _scaleX >= _width) return;
  2047. }
  2048. }
  2049. //test purposes ----------------------------------------------------------------
  2050. /*
  2051. if (!_portrait){
  2052. fillRect(_cursorX,_cursorY,(charW * _scaleX),(_FNTheight * _scaleY),RA8875_YELLOW);//bColor
  2053. } else {
  2054. fillRect(_cursorY,_cursorX,(charW * _scaleX),(_FNTheight * _scaleY),RA8875_YELLOW);//bColor
  2055. }
  2056. */
  2057. //-------------------------Actual single char drawing here -----------------------------------
  2058. if (!_FNTcompression){
  2059. #if defined(_RA8875_TXTRNDOPTIMIZER)
  2060. if (!_portrait){
  2061. _drawChar_unc(_cursorX,_cursorY,charW,charIndex,fcolor);
  2062. } else {
  2063. _drawChar_unc(_cursorY,_cursorX,charW,charIndex,fcolor);
  2064. }
  2065. #else
  2066. if (!_portrait){
  2067. _drawChar_unc(_cursorX,_cursorY,charW,charGlyp,fcolor,bcolor);
  2068. } else {
  2069. _drawChar_unc(_cursorY,_cursorX,charW,charGlyp,fcolor,bcolor);
  2070. }
  2071. #endif
  2072. } else {
  2073. //TODO
  2074. //RLE compressed fonts
  2075. }
  2076. //add charW to total -----------------------------------------------------
  2077. if (!_portrait){
  2078. _cursorX += (charW * _scaleX) + _FNTspacing;
  2079. } else {
  2080. _cursorY += (charW * _scaleX) + _FNTspacing;
  2081. }
  2082. // #if defined(FORCE_RA8875_TXTREND_FOLLOW_CURS)
  2083. // _textPosition(_cursorX,_cursorY,false);
  2084. // #endif
  2085. }//end valid
  2086. }//end char
  2087. }
  2088. /**************************************************************************/
  2089. /*! PRIVATE
  2090. Write a single char, only INT and FONT ROM char (internal RA9975 render)
  2091. NOTE: It identify correctly println and /n & /r
  2092. */
  2093. /**************************************************************************/
  2094. void RA8875::_charWrite(const char c,uint8_t offset)
  2095. {
  2096. bool dtacmd = false;
  2097. if (c == 13){//'\r'
  2098. //Ignore carriage-return
  2099. } else if (c == 10){//'\n'
  2100. if (!_portrait){
  2101. _cursorX = 0;
  2102. _cursorY += (_FNTheight + (_FNTheight * (_scaleY - 1))) + _FNTinterline + offset;
  2103. } else {
  2104. _cursorX += (_FNTheight + (_FNTheight * (_scaleY - 1))) + _FNTinterline + offset;
  2105. _cursorY = 0;
  2106. }
  2107. _textPosition(_cursorX,_cursorY, false);
  2108. dtacmd = false;
  2109. } else {
  2110. if (!dtacmd){
  2111. dtacmd = true;
  2112. if (!_textMode) _setTextMode(true);//we are in graph mode?
  2113. writeCommand(RA8875_MRWC);
  2114. }
  2115. _writeData(c);
  2116. _waitBusy(0x80);
  2117. //update cursor
  2118. if (!_portrait){
  2119. _cursorX += _FNTwidth;
  2120. } else {
  2121. _cursorY += _FNTwidth;
  2122. }
  2123. }
  2124. }
  2125. /**************************************************************************/
  2126. /*! PRIVATE
  2127. Search for glyph char code in font array
  2128. It return font index or -1 if not found.
  2129. */
  2130. /**************************************************************************/
  2131. int RA8875::_getCharCode(uint8_t ch)
  2132. {
  2133. int i;
  2134. for (i=0;i<_currentFont->length;i++){//search for char code
  2135. #if defined(_FORCE_PROGMEM__)
  2136. uint8_t ccode = _currentFont->chars[i].char_code;
  2137. if (ccode == ch) return i;
  2138. #else
  2139. if (_currentFont->chars[i].char_code == ch) return i;
  2140. #endif
  2141. }//i
  2142. return -1;
  2143. }
  2144. /**************************************************************************/
  2145. /*! PRIVATE
  2146. This helper loop trough a text string and return how long is (in pixel)
  2147. NOTE: It identify correctly println and /n & /r and forget non present chars
  2148. */
  2149. /**************************************************************************/
  2150. int16_t RA8875::_STRlen_helper(const char* buffer,uint16_t len)
  2151. {
  2152. if (bitRead(_TXTparameters,7) == 0){ //_renderFont not active
  2153. return (len * _FNTwidth);
  2154. } else { //_renderFont active
  2155. int charIndex = -1;
  2156. uint16_t i;
  2157. if (len == 0) len = strlen(buffer); //try to get data from string
  2158. if (len == 0) return 0; //better stop here
  2159. if (_FNTwidth > 0){ // fixed width font
  2160. return ((len * _spaceCharWidth));
  2161. } else { // variable width, need to loop trough entire string!
  2162. uint16_t totW = 0;
  2163. for (i = 0;i < len;i++){ //loop trough buffer
  2164. if (buffer[i] == 32){ //a space
  2165. totW += _spaceCharWidth;
  2166. } else if (buffer[i] != 13 && buffer[i] != 10 && buffer[i] != 32){//avoid special char
  2167. charIndex = _getCharCode(buffer[i]);
  2168. if (charIndex > -1) { //found!
  2169. #if defined(_FORCE_PROGMEM__)
  2170. #if defined(ESP8266)
  2171. totW += (FPSTR(&_currentFont->chars[charIndex].image->image_width));
  2172. #else
  2173. totW += (PROGMEM_read(&_currentFont->chars[charIndex].image->image_width));
  2174. #endif
  2175. #else
  2176. totW += (_currentFont->chars[charIndex].image->image_width);
  2177. #endif
  2178. }
  2179. }//inside permitted chars
  2180. }//buffer loop
  2181. return totW; //return data
  2182. }//end variable w font
  2183. }
  2184. }
  2185. #if defined(_RA8875_TXTRNDOPTIMIZER)
  2186. /**************************************************************************/
  2187. /*! PRIVATE
  2188. Here's the char render engine for uncompressed fonts, it actually render a single char.
  2189. It's actually 2 functions, this one take care of every glyph line
  2190. and perform some optimization second one paint concurrent pixels in chunks.
  2191. To show how optimizations works try uncomment RA8875_VISPIXDEBUG in settings.
  2192. Please do not steal this part of code!
  2193. */
  2194. /**************************************************************************/
  2195. void RA8875::_drawChar_unc(int16_t x,int16_t y,int charW,int index,uint16_t fcolor)
  2196. {
  2197. //start by getting some glyph data...
  2198. #if defined(_FORCE_PROGMEM__)
  2199. #if defined(ESP8266)
  2200. const uint8_t * charGlyp = FPSTR(&_currentFont->chars[index].image->data);//char data
  2201. int totalBytes = FPSTR(&_currentFont->chars[index].image->image_datalen);
  2202. #else
  2203. const uint8_t * charGlyp = PROGMEM_read(&_currentFont->chars[index].image->data);//char data
  2204. int totalBytes = PROGMEM_read(&_currentFont->chars[index].image->image_datalen);
  2205. #endif
  2206. #else
  2207. const uint8_t * charGlyp = _currentFont->chars[index].image->data;
  2208. int totalBytes = _currentFont->chars[index].image->image_datalen;
  2209. #endif
  2210. int i;
  2211. uint8_t temp = 0;
  2212. //some basic variable...
  2213. uint8_t currentXposition = 0;//the current position of the writing cursor in the x axis, from 0 to charW
  2214. uint8_t currentYposition = 1;//the current position of the writing cursor in the y axis, from 1 to _FNTheight
  2215. int currentByte = 0;//the current byte in reading (from 0 to totalBytes)
  2216. bool lineBuffer[charW];//the temporary line buffer (will be _FNTheight each char)
  2217. int lineChecksum = 0;//part of the optimizer
  2218. /*
  2219. uint8_t bytesInLine = 0;
  2220. //try to understand how many bytes in a line
  2221. if (charW % 8 == 0) { // divisible by 8
  2222. bytesInLine = charW / 8;
  2223. } else { // when it's divisible by 8?
  2224. bytesInLine = charW;
  2225. while (bytesInLine % 8) { bytesInLine--;}
  2226. bytesInLine = bytesInLine / 8;
  2227. }
  2228. */
  2229. //the main loop that will read all bytes of the glyph
  2230. while (currentByte < totalBytes){
  2231. //read n byte
  2232. #if defined(_FORCE_PROGMEM__)
  2233. #if defined(ESP8266)
  2234. temp = FPSTR(&charGlyp[currentByte]);
  2235. #else
  2236. temp = PROGMEM_read(&charGlyp[currentByte]);
  2237. #endif
  2238. #else
  2239. temp = charGlyp[currentByte];
  2240. #endif
  2241. for (i=7; i>=0; i--){
  2242. //----------------------------------- exception
  2243. if (currentXposition >= charW){
  2244. //line buffer has been filled!
  2245. currentXposition = 0;//reset the line x position
  2246. if (lineChecksum < 1){//empty line
  2247. #if defined(RA8875_VISPIXDEBUG)
  2248. drawRect(x,y + (currentYposition * _scaleY),charW * _scaleX,_scaleY,RA8875_BLUE);
  2249. #endif
  2250. } else if (lineChecksum == charW){//full line
  2251. #if !defined(RA8875_VISPIXDEBUG)
  2252. fillRect(
  2253. #else
  2254. drawRect(
  2255. #endif
  2256. x,y + (currentYposition * _scaleY),charW * _scaleX,_scaleY,fcolor);
  2257. } else { //line render
  2258. _charLineRender(lineBuffer,charW,x,y,currentYposition,fcolor);
  2259. }
  2260. currentYposition++;//next line
  2261. lineChecksum = 0;//reset checksum
  2262. }//end exception
  2263. //-------------------------------------------------------
  2264. lineBuffer[currentXposition] = bitRead(temp,i);//continue fill line buffer
  2265. lineChecksum += lineBuffer[currentXposition];
  2266. currentXposition++;
  2267. }
  2268. currentByte++;
  2269. }
  2270. }
  2271. /**************************************************************************/
  2272. /*! PRIVATE
  2273. Font Line render optimized routine
  2274. This will render ONLY a single font line by grouping chunks of same pixels
  2275. Version 3.0 (fixed a bug that cause xlinePos to jump of 1 pixel
  2276. */
  2277. /**************************************************************************/
  2278. void RA8875::_charLineRender(bool lineBuffer[],int charW,int16_t x,int16_t y,int16_t currentYposition,uint16_t fcolor)
  2279. {
  2280. int xlinePos = 0;
  2281. int px;
  2282. uint8_t endPix = 0;
  2283. bool refPixel = false;
  2284. while (xlinePos < charW){
  2285. refPixel = lineBuffer[xlinePos];//xlinePos pix as reference value for next pixels
  2286. //detect and render concurrent pixels
  2287. for (px = xlinePos;px <= charW;px++){
  2288. if (lineBuffer[px] == lineBuffer[xlinePos] && px < charW){//grouping pixels with same val
  2289. endPix++;
  2290. } else {
  2291. if (refPixel){
  2292. #if defined(RA8875_VISPIXDEBUG)
  2293. drawRect(
  2294. #else
  2295. fillRect(
  2296. #endif
  2297. x,y + (currentYposition * _scaleY),endPix * _scaleX,_scaleY,fcolor);
  2298. } else {
  2299. #if defined(RA8875_VISPIXDEBUG)
  2300. drawRect(x,y + (currentYposition * _scaleY),endPix * _scaleX,_scaleY,RA8875_BLUE);
  2301. #endif
  2302. }
  2303. //reset and update some vals
  2304. xlinePos += endPix;
  2305. x += endPix * _scaleX;
  2306. endPix = 0;
  2307. break;//exit cycle for...
  2308. }
  2309. }
  2310. }
  2311. }
  2312. #else
  2313. /**************************************************************************/
  2314. /*!
  2315. This is the old rendering engine, pretty basic but slow, here for an alternative.
  2316. Note that this can be enabled only by commenting
  2317. #define _RA8875_TXTRNDOPTIMIZER
  2318. in RA8875UserSettings.h file!
  2319. Parameters:
  2320. x:
  2321. Y:
  2322. w: the width of the font
  2323. data: the data glyph
  2324. fcolor: foreground color
  2325. bcolor: background color
  2326. */
  2327. /**************************************************************************/
  2328. void RA8875::_drawChar_unc(int16_t x,int16_t y,int16_t w,const uint8_t *data,uint16_t fcolor,uint16_t bcolor)
  2329. {
  2330. // if ((x >= _width) || // Clip right
  2331. // (y >= _height) || // Clip bottom
  2332. // ((x + w * _FNTscaleX - 1) < 0) || // Clip left
  2333. // ((y + _FNTheight * _FNTscaleY - 1) < 0)) // Clip top
  2334. // return;
  2335. uint16_t color;
  2336. uint16_t bitCount = 0;
  2337. uint8_t line = 0;
  2338. int j;
  2339. uint16_t i;//,idx;
  2340. for (i=0; i<_FNTheight; i++) { //Y
  2341. for (j = 0; j<w; j++) { //X
  2342. if (bitCount++%8 == 0) {
  2343. #if defined(_FORCE_PROGMEM__)
  2344. #if defined(ESP8266)
  2345. line = FPSTR(&*data++);
  2346. #else
  2347. line = PROGMEM_read(&*data++);
  2348. #endif
  2349. #else
  2350. line = *data++;
  2351. #endif
  2352. }
  2353. #if defined(RA8875_VISPIXDEBUG)
  2354. color = RA8875_BLUE;
  2355. #else
  2356. color = bcolor;
  2357. #endif
  2358. if (line & 0x80) color = fcolor;
  2359. if (_scaling) {// big
  2360. #if defined(RA8875_VISPIXDEBUG)
  2361. drawRect(
  2362. #else
  2363. fillRect(
  2364. #endif
  2365. x + (j * _scaleX),
  2366. y + (i * _scaleY),
  2367. _scaleX,
  2368. _scaleY,
  2369. color
  2370. );
  2371. } else { // def size
  2372. drawPixel(x + j, y + i, color);
  2373. }
  2374. line <<= 1;
  2375. }
  2376. }
  2377. }
  2378. #endif
  2379. /*
  2380. void RA8875::_drawChar_com(int16_t x,int16_t y,int16_t w,const uint8_t *data)
  2381. {
  2382. }
  2383. */
  2384. /*
  2385. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2386. + COLOR STUFF +
  2387. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2388. */
  2389. /**************************************************************************/
  2390. /*!
  2391. Set the display 'Color Space'
  2392. Parameters:
  2393. Bit per Pixel color (colors): 8 or 16 bit
  2394. NOTE:
  2395. For display over 272*480 give the ability to use
  2396. Layers since at 16 bit it's not possible.
  2397. */
  2398. /**************************************************************************/
  2399. void RA8875::setColorBpp(uint8_t colors)
  2400. {
  2401. if (colors != _color_bpp){//only if necessary
  2402. if (colors < 16) {
  2403. _color_bpp = 8;
  2404. _colorIndex = 3;
  2405. _writeRegister(RA8875_SYSR,0x00);
  2406. if (_hasLayerLimits) _maxLayers = 2;
  2407. } else if (colors > 8) {//65K
  2408. _color_bpp = 16;
  2409. _colorIndex = 0;
  2410. _writeRegister(RA8875_SYSR,0x0C);
  2411. if (_hasLayerLimits) _maxLayers = 1;
  2412. _currentLayer = 0;
  2413. }
  2414. }
  2415. }
  2416. /**************************************************************************/
  2417. /*!
  2418. Return current Color Space (8 or 16)
  2419. */
  2420. /**************************************************************************/
  2421. uint8_t RA8875::getColorBpp(void)
  2422. {
  2423. return _color_bpp;
  2424. }
  2425. /**************************************************************************/
  2426. /*!
  2427. Sets set the foreground color using 16bit RGB565 color
  2428. It handles automatically color conversion when in 8 bit!
  2429. Parameters:
  2430. color: 16bit color RGB565
  2431. */
  2432. /**************************************************************************/
  2433. void RA8875::setForegroundColor(uint16_t color)
  2434. {
  2435. _foreColor = color;//keep track
  2436. _writeRegister(RA8875_FGCR0,((color & 0xF800) >> _RA8875colorMask[_colorIndex]));
  2437. _writeRegister(RA8875_FGCR0+1,((color & 0x07E0) >> _RA8875colorMask[_colorIndex+1]));
  2438. _writeRegister(RA8875_FGCR0+2,((color & 0x001F) >> _RA8875colorMask[_colorIndex+2]));
  2439. }
  2440. /**************************************************************************/
  2441. /*!
  2442. Sets set the foreground color using 8bit R,G,B
  2443. Parameters:
  2444. R: 8bit RED
  2445. G: 8bit GREEN
  2446. B: 8bit BLUE
  2447. */
  2448. /**************************************************************************/
  2449. void RA8875::setForegroundColor(uint8_t R,uint8_t G,uint8_t B)
  2450. {
  2451. _foreColor = Color565(R,G,B);//keep track
  2452. _writeRegister(RA8875_FGCR0,R);
  2453. _writeRegister(RA8875_FGCR0+1,G);
  2454. _writeRegister(RA8875_FGCR0+2,B);
  2455. }
  2456. /**************************************************************************/
  2457. /*!
  2458. Sets set the background color using 16bit RGB565 color
  2459. It handles automatically color conversion when in 8 bit!
  2460. Parameters:
  2461. color: 16bit color RGB565
  2462. Note: will set background Trasparency OFF
  2463. */
  2464. /**************************************************************************/
  2465. void RA8875::setBackgroundColor(uint16_t color)
  2466. {
  2467. _backColor = color;//keep track
  2468. _writeRegister(RA8875_BGCR0,((color & 0xF800) >> _RA8875colorMask[_colorIndex]));//11
  2469. _writeRegister(RA8875_BGCR0+1,((color & 0x07E0) >> _RA8875colorMask[_colorIndex+1]));//5
  2470. _writeRegister(RA8875_BGCR0+2,((color & 0x001F) >> _RA8875colorMask[_colorIndex+2]));//0
  2471. }
  2472. /**************************************************************************/
  2473. /*!
  2474. Sets set the background color using 8bit R,G,B
  2475. Parameters:
  2476. R: 8bit RED
  2477. G: 8bit GREEN
  2478. B: 8bit BLUE
  2479. Note: will set background Trasparency OFF
  2480. */
  2481. /**************************************************************************/
  2482. void RA8875::setBackgroundColor(uint8_t R,uint8_t G,uint8_t B)
  2483. {
  2484. _backColor = Color565(R,G,B);//keep track
  2485. _writeRegister(RA8875_BGCR0,R);
  2486. _writeRegister(RA8875_BGCR0+1,G);
  2487. _writeRegister(RA8875_BGCR0+2,B);
  2488. }
  2489. /**************************************************************************/
  2490. /*!
  2491. Sets set the trasparent background color using 16bit RGB565 color
  2492. It handles automatically color conversion when in 8 bit!
  2493. Parameters:
  2494. color: 16bit color RGB565
  2495. Note: will set background Trasparency ON
  2496. */
  2497. /**************************************************************************/
  2498. void RA8875::setTransparentColor(uint16_t color)
  2499. {
  2500. _backColor = color;
  2501. _writeRegister(RA8875_BGTR0,((color & 0xF800) >> _RA8875colorMask[_colorIndex]));
  2502. _writeRegister(RA8875_BGTR0+1,((color & 0x07E0) >> _RA8875colorMask[_colorIndex+1]));
  2503. _writeRegister(RA8875_BGTR0+2,((color & 0x001F) >> _RA8875colorMask[_colorIndex+2]));
  2504. }
  2505. /**************************************************************************/
  2506. /*!
  2507. Sets set the Trasparent background color using 8bit R,G,B
  2508. Parameters:
  2509. R: 8bit RED
  2510. G: 8bit GREEN
  2511. B: 8bit BLUE
  2512. Note: will set background Trasparency ON
  2513. */
  2514. /**************************************************************************/
  2515. void RA8875::setTransparentColor(uint8_t R,uint8_t G,uint8_t B)
  2516. {
  2517. _backColor = Color565(R,G,B);//keep track
  2518. _writeRegister(RA8875_BGTR0,R);
  2519. _writeRegister(RA8875_BGTR0+1,G);
  2520. _writeRegister(RA8875_BGTR0+2,B);
  2521. }
  2522. /**************************************************************************/
  2523. /*!
  2524. set foreground,background color (plus transparent background)
  2525. Parameters:
  2526. fColor: 16bit foreground color (text) RGB565
  2527. bColor: 16bit background color RGB565
  2528. backTransp:if true the bColor will be transparent
  2529. */
  2530. /**************************************************************************/
  2531. void RA8875::setColor(uint16_t fcolor,uint16_t bcolor,bool bcolorTraspFlag)//0.69b30
  2532. {
  2533. if (fcolor != _foreColor) setForegroundColor(fcolor);
  2534. if (bcolorTraspFlag){
  2535. setTransparentColor(bcolor);
  2536. } else {
  2537. if (bcolor != _backColor) setBackgroundColor(bcolor);
  2538. }
  2539. }
  2540. /*
  2541. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2542. + DRAW STUFF +
  2543. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2544. */
  2545. /**************************************************************************/
  2546. /*! Set graphic cursor beween 8 different ones.
  2547. Graphic cursors has to be inserted before use!
  2548. Parameters:
  2549. cur: 0...7
  2550. */
  2551. /**************************************************************************/
  2552. void RA8875::setGraphicCursor(uint8_t cur)
  2553. {
  2554. if (cur > 7) cur = 7;
  2555. uint8_t temp = _readRegister(RA8875_MWCR1);
  2556. temp &= ~(0x70);//clear bit 6,5,4
  2557. temp |= cur << 4;
  2558. temp |= cur;
  2559. if (_useMultiLayers){
  2560. _currentLayer == 1 ? temp |= (1 << 0) : temp &= ~(1 << 0);
  2561. } else {
  2562. temp &= ~(1 << 0);
  2563. }
  2564. _writeData(temp);
  2565. }
  2566. /**************************************************************************/
  2567. /*! Show the graphic cursor
  2568. Graphic cursors has to be inserted before use!
  2569. Parameters:
  2570. cur: true,false
  2571. */
  2572. /**************************************************************************/
  2573. void RA8875::showGraphicCursor(boolean cur)
  2574. {
  2575. uint8_t temp = _readRegister(RA8875_MWCR1);
  2576. cur == true ? temp |= (1 << 7) : temp &= ~(1 << 7);
  2577. if (_useMultiLayers){
  2578. _currentLayer == 1 ? temp |= (1 << 0) : temp &= ~(1 << 0);
  2579. } else {
  2580. temp &= ~(1 << 0);
  2581. }
  2582. _writeData(temp);
  2583. }
  2584. /**************************************************************************/
  2585. /*!
  2586. Set the position for Graphic Write
  2587. Parameters:
  2588. x: horizontal position
  2589. y: vertical position
  2590. */
  2591. /**************************************************************************/
  2592. void RA8875::setXY(int16_t x, int16_t y)
  2593. {
  2594. setX(x);
  2595. setY(y);
  2596. }
  2597. /**************************************************************************/
  2598. /*!
  2599. Set the x position for Graphic Write
  2600. Parameters:
  2601. x: horizontal position
  2602. */
  2603. /**************************************************************************/
  2604. void RA8875::setX(int16_t x)
  2605. {
  2606. if (x < 0) x = 0;
  2607. if (_portrait){//fix 0.69b21
  2608. if (x >= RA8875_HEIGHT) x = RA8875_HEIGHT-1;
  2609. _writeRegister(RA8875_CURV0, x & 0xFF);
  2610. _writeRegister(RA8875_CURV0+1, x >> 8);
  2611. } else {
  2612. if (x >= RA8875_WIDTH) x = RA8875_WIDTH-1;
  2613. _writeRegister(RA8875_CURH0, x & 0xFF);
  2614. _writeRegister(RA8875_CURH0+1, (x >> 8));
  2615. }
  2616. }
  2617. /**************************************************************************/
  2618. /*!
  2619. Set the y position for Graphic Write
  2620. Parameters:
  2621. y: vertical position
  2622. */
  2623. /**************************************************************************/
  2624. void RA8875::setY(int16_t y)
  2625. {
  2626. if (y < 0) y = 0;
  2627. if (_portrait){//fix 0.69b21
  2628. if (y >= RA8875_WIDTH) y = RA8875_WIDTH-1;
  2629. _writeRegister(RA8875_CURH0, y & 0xFF);
  2630. _writeRegister(RA8875_CURH0+1, (y >> 8));
  2631. } else {
  2632. if (y >= RA8875_HEIGHT) y = RA8875_HEIGHT-1;
  2633. _writeRegister(RA8875_CURV0, y & 0xFF);
  2634. _writeRegister(RA8875_CURV0+1, y >> 8);
  2635. }
  2636. }
  2637. /*
  2638. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2639. + SCROLL STUFF +
  2640. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2641. */
  2642. /**************************************************************************/
  2643. /*!
  2644. Sets the scroll mode. This is controlled by bits 6 and 7 of
  2645. REG[52h] Layer Transparency Register0 (LTPR0)
  2646. Author: The Experimentalist
  2647. */
  2648. /**************************************************************************/
  2649. void RA8875::setScrollMode(enum RA8875scrollMode mode)
  2650. {
  2651. uint8_t temp = _readRegister(RA8875_LTPR0);
  2652. temp &= 0x3F; // Clear bits 6 and 7 to zero
  2653. switch(mode){ // bit 7,6 of LTPR0
  2654. case SIMULTANEOUS: // 00b : Layer 1/2 scroll simultaneously.
  2655. // Do nothing
  2656. break;
  2657. case LAYER1ONLY: // 01b : Only Layer 1 scroll.
  2658. temp |= 0x40;
  2659. break;
  2660. case LAYER2ONLY: // 10b : Only Layer 2 scroll.
  2661. temp |= 0x80;
  2662. break;
  2663. case BUFFERED: // 11b: Buffer scroll (using Layer 2 as scroll buffer)
  2664. temp |= 0xC0;
  2665. break;
  2666. default:
  2667. return; //do nothing
  2668. }
  2669. //TODO: Should this be conditional on multi layer?
  2670. //if (_useMultiLayers) _writeRegister(RA8875_LTPR0,temp);
  2671. //_writeRegister(RA8875_LTPR0,temp);
  2672. _writeData(temp);
  2673. }
  2674. /**************************************************************************/
  2675. /*!
  2676. Define a window for perform scroll
  2677. Parameters:
  2678. XL: x window start left
  2679. XR: x window end right
  2680. YT: y window start top
  2681. YB: y window end bottom
  2682. */
  2683. /**************************************************************************/
  2684. void RA8875::setScrollWindow(int16_t XL,int16_t XR ,int16_t YT ,int16_t YB)
  2685. {
  2686. if (_portrait){//0.69b22 (fixed)
  2687. swapvals(XL,YT);
  2688. swapvals(XR,YB);
  2689. }
  2690. _checkLimits_helper(XL,YT);
  2691. _checkLimits_helper(XR,YB);
  2692. _scrollXL = XL; _scrollXR = XR; _scrollYT = YT; _scrollYB = YB;
  2693. _writeRegister(RA8875_HSSW0,(_scrollXL & 0xFF));
  2694. _writeRegister(RA8875_HSSW0+1,(_scrollXL >> 8));
  2695. _writeRegister(RA8875_HESW0,(_scrollXR & 0xFF));
  2696. _writeRegister(RA8875_HESW0+1,(_scrollXR >> 8));
  2697. _writeRegister(RA8875_VSSW0,(_scrollYT & 0xFF));
  2698. _writeRegister(RA8875_VSSW0+1,(_scrollYT >> 8));
  2699. _writeRegister(RA8875_VESW0,(_scrollYB & 0xFF));
  2700. _writeRegister(RA8875_VESW0+1,(_scrollYB >> 8));
  2701. delay(1);
  2702. }
  2703. /**************************************************************************/
  2704. /*!
  2705. Perform the scroll
  2706. */
  2707. /**************************************************************************/
  2708. void RA8875::scroll(int16_t x,int16_t y)
  2709. {
  2710. if (_portrait) swapvals(x,y);
  2711. //if (y > _scrollYB) y = _scrollYB;//??? mmmm... not sure
  2712. if (_scrollXL == 0 && _scrollXR == 0 && _scrollYT == 0 && _scrollYB == 0){
  2713. //do nothing, scroll window inactive
  2714. } else {
  2715. _writeRegister(RA8875_HOFS0,(x & 0xFF));
  2716. _writeRegister(RA8875_HOFS1,(x >> 8));
  2717. _writeRegister(RA8875_VOFS0,(y & 0xFF));
  2718. _writeRegister(RA8875_VOFS1,(y >> 8));
  2719. }
  2720. }
  2721. /*
  2722. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2723. + DMA STUFF +
  2724. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2725. */
  2726. /**************************************************************************/
  2727. /*!
  2728. */
  2729. /**************************************************************************/
  2730. void RA8875::DMA_blockModeSize(int16_t BWR,int16_t BHR,int16_t SPWR)
  2731. {
  2732. _writeRegister(RA8875_DTNR0,BWR & 0xFF);
  2733. _writeRegister(RA8875_BWR1,BWR >> 8);
  2734. _writeRegister(RA8875_DTNR1,BHR & 0xFF);
  2735. _writeRegister(RA8875_BHR1,BHR >> 8);
  2736. _writeRegister(RA8875_DTNR2,SPWR & 0xFF);
  2737. _writeRegister(RA8875_SPWR1,SPWR >> 8);
  2738. }
  2739. /**************************************************************************/
  2740. /*!
  2741. */
  2742. /**************************************************************************/
  2743. void RA8875::DMA_startAddress(unsigned long adrs)
  2744. {
  2745. _writeRegister(RA8875_SSAR0,adrs & 0xFF);
  2746. _writeRegister(RA8875_SSAR0+1,adrs >> 8);
  2747. _writeRegister(RA8875_SSAR0+2,adrs >> 16);
  2748. //_writeRegister(0xB3,adrs >> 24);// not more in datasheet!
  2749. }
  2750. /**************************************************************************/
  2751. /*!
  2752. */
  2753. /**************************************************************************/
  2754. void RA8875::DMA_enable(void)
  2755. {
  2756. uint8_t temp = _readRegister(RA8875_DMACR);
  2757. temp |= 0x01;
  2758. _writeData(temp);
  2759. _waitBusy(0x01);
  2760. }
  2761. /**************************************************************************/
  2762. /*! (STILL IN DEVELOP, please do not complain)
  2763. Display an image stored in Flash RAM
  2764. Note: you should have the optional FLASH Chip connected to RA8875!
  2765. Note: You should store some image in that chip!
  2766. Note: Never tried!!!!!!!
  2767. */
  2768. /**************************************************************************/
  2769. void RA8875::drawFlashImage(int16_t x,int16_t y,int16_t w,int16_t h,uint8_t picnum)
  2770. {
  2771. if (_portrait){swapvals(x,y); swapvals(w,h);}//0.69b21 -have to check this, not verified
  2772. if (_textMode) _setTextMode(false);//we are in text mode?
  2773. _writeRegister(RA8875_SFCLR,0x00);
  2774. _writeRegister(RA8875_SROC,0x87);
  2775. _writeRegister(RA8875_DMACR,0x02);
  2776. //setActiveWindow(0,_width-1,0,_height-1);
  2777. _checkLimits_helper(x,y);
  2778. _checkLimits_helper(w,h);
  2779. _portrait == true ? setXY(y,x) : setXY(x,y);
  2780. DMA_startAddress(261120 * (picnum-1));
  2781. DMA_blockModeSize(w,h,w);
  2782. _writeRegister(RA8875_DMACR,0x03);
  2783. _waitBusy(0x01);
  2784. }
  2785. /*
  2786. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2787. + BTE STUFF +
  2788. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2789. */
  2790. /**************************************************************************/
  2791. /*
  2792. Block Transfer Move
  2793. Can move a rectangular block from any area of memory (eg. layer 1) to any other (eg layer 2)
  2794. Can move with transparency - note THE TRANSPARENT COLOUR IS THE TEXT FOREGROUND COLOUR
  2795. ReverseDir is for moving overlapping areas - may need to use reverse to prevent it double-copying the overlapping area (this option not available with transparency or monochrome)
  2796. ROP is Raster Operation. Usually use RA8875_ROP_SOURCE but a few others are defined
  2797. Defaults to current layer if not given or layer is zero.
  2798. Monochrome uses the colour-expansion mode: the input is a bit map which is then converted to the current foreground and background colours, transparent background is optional
  2799. Monochrome data is assumed to be linear, originally written to the screen memory in 16-bit chunks with drawPixels().
  2800. Monochrome mode uses the ROP to define the offset of the first image bit within the first byte. This also depends on the width of the block you are trying to display.
  2801. Monochrome skips 16-bit words in the input pattern - see the example for more explanation and a trick to interleave 2 characters in the space of one.
  2802. This function returns immediately but the actual transfer can take some time
  2803. Caller should check the busy status before issuing any more RS8875 commands.
  2804. Basic usage:
  2805. BTE_Move(SourceX, SourceY, Width, Height, DestX, DestY) = copy something visible on the current layer
  2806. BTE_Move(SourceX, SourceY, Width, Height, DestX, DestY, 2) = copy something from layer 2 to the current layer
  2807. BTE_Move(SourceX, SourceY, Width, Height, DestX, DestY, 2, 1, true) = copy from layer 2 to layer 1, with the transparency option
  2808. BTE_Move(SourceX, SourceY, Width, Height, DestX, DestY, 0, 0, true, RA8875_BTEROP_ADD) = copy on the current layer, using transparency and the ADD/brighter operation
  2809. BTE_Move(SourceX, SourceY, Width, Height, DestX, DestY, 0, 0, false, RA8875_BTEROP_SOURCE, false, true) = copy on the current layer using the reverse direction option for overlapping areas
  2810. */
  2811. void RA8875::BTE_move(int16_t SourceX, int16_t SourceY, int16_t Width, int16_t Height, int16_t DestX, int16_t DestY, uint8_t SourceLayer, uint8_t DestLayer,bool Transparent, uint8_t ROP, bool Monochrome, bool ReverseDir)
  2812. {
  2813. if (SourceLayer == 0) SourceLayer = _currentLayer;
  2814. if (DestLayer == 0) DestLayer = _currentLayer;
  2815. if (SourceLayer == 2) SourceY |= 0x8000; //set the high bit of the vertical coordinate to indicate layer 2
  2816. if (DestLayer == 2) DestY |= 0x8000; //set the high bit of the vertical coordinate to indicate layer 2
  2817. ROP &= 0xF0; //Ensure the lower bits of ROP are zero
  2818. if (Transparent) {
  2819. if (Monochrome) {
  2820. ROP |= 0x0A; //colour-expand transparent
  2821. } else {
  2822. ROP |= 0x05; //set the transparency option
  2823. }
  2824. } else {
  2825. if (Monochrome) {
  2826. ROP |= 0x0B; //colour-expand normal
  2827. } else {
  2828. if (ReverseDir) {
  2829. ROP |= 0x03; //set the reverse option
  2830. } else {
  2831. ROP |= 0x02; //standard block-move operation
  2832. }
  2833. }
  2834. }
  2835. _waitBusy(0x40); //Check that another BTE operation is not still in progress
  2836. if (_textMode) _setTextMode(false);//we are in text mode?
  2837. BTE_moveFrom(SourceX,SourceY);
  2838. BTE_size(Width,Height);
  2839. BTE_moveTo(DestX,DestY);
  2840. BTE_ropcode(ROP);
  2841. //Execute BTE! (This selects linear addressing mode for the monochrome source data)
  2842. if (Monochrome) _writeRegister(RA8875_BECR0, 0xC0); else _writeRegister(RA8875_BECR0, 0x80);
  2843. _waitBusy(0x40);
  2844. //we are supposed to wait for the thing to become unbusy
  2845. //caller can call _waitBusy(0x40) to check the BTE busy status (except it's private)
  2846. }
  2847. /**************************************************************************/
  2848. /*! TESTING
  2849. */
  2850. /**************************************************************************/
  2851. void RA8875::BTE_size(int16_t w, int16_t h)
  2852. {
  2853. //0.69b21 -have to check this, not verified
  2854. if (_portrait) swapvals(w,h);
  2855. _writeRegister(RA8875_BEWR0,w & 0xFF);//BET area width literacy
  2856. _writeRegister(RA8875_BEWR0+1,w >> 8);//BET area width literacy
  2857. _writeRegister(RA8875_BEHR0,h & 0xFF);//BET area height literacy
  2858. _writeRegister(RA8875_BEHR0+1,h >> 8);//BET area height literacy
  2859. }
  2860. /**************************************************************************/
  2861. /*!
  2862. */
  2863. /**************************************************************************/
  2864. void RA8875::BTE_moveFrom(int16_t SX,int16_t SY)
  2865. {
  2866. if (_portrait) swapvals(SX,SY);
  2867. _writeRegister(RA8875_HSBE0,SX & 0xFF);
  2868. _writeRegister(RA8875_HSBE0+1,SX >> 8);
  2869. _writeRegister(RA8875_VSBE0,SY & 0xFF);
  2870. _writeRegister(RA8875_VSBE0+1,SY >> 8);
  2871. }
  2872. /**************************************************************************/
  2873. /*!
  2874. */
  2875. /**************************************************************************/
  2876. void RA8875::BTE_moveTo(int16_t DX,int16_t DY)
  2877. {
  2878. if (_portrait) swapvals(DX,DY);
  2879. _writeRegister(RA8875_HDBE0,DX & 0xFF);
  2880. _writeRegister(RA8875_HDBE0+1,DX >> 8);
  2881. _writeRegister(RA8875_VDBE0,DY & 0xFF);
  2882. _writeRegister(RA8875_VDBE0+1,DY >> 8);
  2883. }
  2884. /**************************************************************************/
  2885. /*! TESTING
  2886. Use a ROP code EFX
  2887. */
  2888. /**************************************************************************/
  2889. void RA8875::BTE_ropcode(unsigned char setx)
  2890. {
  2891. _writeRegister(RA8875_BECR1,setx);//BECR1
  2892. }
  2893. /**************************************************************************/
  2894. /*! TESTING
  2895. Enable BTE transfer
  2896. */
  2897. /**************************************************************************/
  2898. void RA8875::BTE_enable(bool on)
  2899. {
  2900. uint8_t temp = _readRegister(RA8875_BECR0);
  2901. on == true ? temp &= ~(1 << 7) : temp |= (1 << 7);
  2902. _writeData(temp);
  2903. //_writeRegister(RA8875_BECR0,temp);
  2904. _waitBusy(0x40);
  2905. }
  2906. /**************************************************************************/
  2907. /*! TESTING
  2908. Select BTE mode (CONT (continuous) or RECT)
  2909. */
  2910. /**************************************************************************/
  2911. void RA8875::BTE_dataMode(enum RA8875btedatam m)
  2912. {
  2913. uint8_t temp = _readRegister(RA8875_BECR0);
  2914. m == CONT ? temp &= ~(1 << 6) : temp |= (1 << 6);
  2915. _writeData(temp);
  2916. //_writeRegister(RA8875_BECR0,temp);
  2917. }
  2918. /**************************************************************************/
  2919. /*! TESTING
  2920. Select the BTE SOURCE or DEST layer (1 or 2)
  2921. */
  2922. /**************************************************************************/
  2923. void RA8875::BTE_layer(enum RA8875btelayer sd,uint8_t l)
  2924. {
  2925. uint8_t temp;
  2926. sd == SOURCE ? temp = _readRegister(RA8875_VSBE0+1) : temp = _readRegister(RA8875_VDBE0+1);
  2927. l == 1 ? temp &= ~(1 << 7) : temp |= (1 << 7);
  2928. _writeData(temp);
  2929. //_writeRegister(RA8875_VSBE1,temp);
  2930. }
  2931. /*
  2932. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2933. + LAYER STUFF +
  2934. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2935. */
  2936. /**************************************************************************/
  2937. /*!
  2938. Instruct the RA8875 chip to use 2 layers
  2939. If resolution bring to restrictions it will switch to 8 bit
  2940. so you can always use layers.
  2941. Parameters:
  2942. on: true (enable multiple layers), false (disable)
  2943. */
  2944. /**************************************************************************/
  2945. void RA8875::useLayers(boolean on)
  2946. {
  2947. if (_useMultiLayers == on) return; //no reason to do change that it's already as desidered.
  2948. //bool clearBuffer = false;
  2949. if (_hasLayerLimits && _color_bpp > 8) { //try to set up 8bit color space
  2950. setColorBpp(8);
  2951. _waitBusy();
  2952. _maxLayers = 2;
  2953. }
  2954. if (on){
  2955. _useMultiLayers = true;
  2956. _DPCR_Reg |= (1 << 7);
  2957. //clearBuffer = true;
  2958. clearActiveWindow(true);
  2959. } else {
  2960. _useMultiLayers = false;
  2961. _DPCR_Reg &= ~(1 << 7);
  2962. clearActiveWindow(false);
  2963. }
  2964. _writeRegister(RA8875_DPCR,_DPCR_Reg);
  2965. if (!_useMultiLayers && _color_bpp < 16) setColorBpp(16);//bring color back to 16
  2966. /*
  2967. if (clearBuffer) {
  2968. clearWindow(true);
  2969. //for some reason if you switch to multilayer the layer 2 has garbage better clear
  2970. //writeTo(L2);//switch to layer 2
  2971. //clearMemory(false);//clear memory of layer 2
  2972. //clearWindow(false);
  2973. //writeTo(L1);//switch to layer 1
  2974. }
  2975. */
  2976. }
  2977. /**************************************************************************/
  2978. /*!
  2979. */
  2980. /**************************************************************************/
  2981. void RA8875::layerEffect(enum RA8875boolean efx)
  2982. {
  2983. uint8_t reg = 0b00000000;
  2984. //reg &= ~(0x07);//clear bit 2,1,0
  2985. if (!_useMultiLayers) useLayers(true);//turn on multiple layers if it's off
  2986. switch(efx){// bit 2,1,0 of LTPR0
  2987. case LAYER1: //only layer 1 visible [000]
  2988. //do nothing
  2989. break;
  2990. case LAYER2: //only layer 2 visible [001]
  2991. reg |= (1 << 0);
  2992. break;
  2993. case TRANSPARENT: //transparent mode [011]
  2994. reg |= (1 << 0); reg |= (1 << 1);
  2995. break;
  2996. case LIGHTEN: //lighten-overlay mode [010]
  2997. reg |= (1 << 1);
  2998. break;
  2999. case OR: //boolean OR mode [100]
  3000. reg |= (1 << 2);
  3001. break;
  3002. case AND: //boolean AND mode [101]
  3003. reg |= (1 << 0); reg |= (1 << 2);
  3004. break;
  3005. case FLOATING: //floating windows [110]
  3006. reg |= (1 << 1); reg |= (1 << 2);
  3007. break;
  3008. default:
  3009. //do nothing
  3010. break;
  3011. }
  3012. _writeRegister(RA8875_LTPR0,reg);
  3013. }
  3014. /**************************************************************************/
  3015. /*!
  3016. */
  3017. /**************************************************************************/
  3018. void RA8875::layerTransparency(uint8_t layer1,uint8_t layer2)
  3019. {
  3020. if (layer1 > 8) layer1 = 8;
  3021. if (layer2 > 8) layer2 = 8;
  3022. if (!_useMultiLayers) useLayers(true);//turn on multiple layers if it's off
  3023. //if (_useMultiLayers) _writeRegister(RA8875_LTPR1, ((layer2 & 0x0F) << 4) | (layer1 & 0x0F));
  3024. //uint8_t res = 0b00000000;//RA8875_LTPR1
  3025. //reg &= ~(0x07);//clear bit 2,1,0
  3026. _writeRegister(RA8875_LTPR1, ((layer2 & 0xF) << 4) | (layer1 & 0xF));
  3027. }
  3028. /**************************************************************************/
  3029. /*! return the current drawing layer. If layers are OFF, return 255
  3030. */
  3031. /**************************************************************************/
  3032. uint8_t RA8875::getCurrentLayer(void)
  3033. {
  3034. if (!_useMultiLayers) return 255;
  3035. return _currentLayer;
  3036. }
  3037. /**************************************************************************/
  3038. /*! select pattern
  3039. */
  3040. /**************************************************************************/
  3041. void RA8875::setPattern(uint8_t num, enum RA8875pattern p)
  3042. {
  3043. uint8_t maxLoc;
  3044. uint8_t temp = 0b00000000;
  3045. if (p != P16X16) {
  3046. maxLoc = 16;//at 8x8 max 16 locations
  3047. } else {
  3048. maxLoc = 4;//at 16x16 max 4 locations
  3049. temp |= (1 << 7);
  3050. }
  3051. if (num > (maxLoc - 1)) num = maxLoc - 1;
  3052. temp = temp | num;
  3053. writeTo(PATTERN);
  3054. _writeRegister(RA8875_PTNO,temp);
  3055. }
  3056. /**************************************************************************/
  3057. /*! write pattern
  3058. */
  3059. /**************************************************************************/
  3060. void RA8875::writePattern(int16_t x,int16_t y,const uint8_t *data,uint8_t size,bool setAW)
  3061. {
  3062. int16_t i;
  3063. int16_t a,b,c,d;
  3064. if (size < 8 || size > 16) return;
  3065. if (setAW) getActiveWindow(a,b,c,d);
  3066. setActiveWindow(x,x+size-1,y,y+size-1);
  3067. setXY(x,y);
  3068. if (_textMode) _setTextMode(false);//we are in text mode?
  3069. writeCommand(RA8875_MRWC);
  3070. for (i=0;i<(size*size);i++) {
  3071. _writeData(data[i*2]);
  3072. _writeData(data[i*2+1]);
  3073. _waitBusy(0x80);
  3074. }
  3075. if (setAW) setActiveWindow(a,b,c,d);//set as it was before
  3076. }
  3077. /**************************************************************************/
  3078. /*! This is the most important function to write on:
  3079. LAYERS
  3080. CGRAM
  3081. PATTERN
  3082. CURSOR
  3083. Parameter:
  3084. d (L1, L2, CGRAM, PATTERN, CURSOR)
  3085. When writing on layers 0 or 1, if the layers are not enable it will enable automatically
  3086. If the display doesn't support layers, it will automatically switch to 8bit color
  3087. Remember that when layers are ON you need to disable manually, once that only Layer 1 will be visible
  3088. */
  3089. /**************************************************************************/
  3090. void RA8875::writeTo(enum RA8875writes d)
  3091. {
  3092. uint8_t temp = _readRegister(RA8875_MWCR1);
  3093. //bool trigMultilayer = false;
  3094. switch(d){
  3095. case L1:
  3096. temp &= ~((1<<3) | (1<<2));// Clear bits 3 and 2
  3097. temp &= ~(1 << 0); //clear bit 0
  3098. _currentLayer = 0;
  3099. //trigMultilayer = true;
  3100. _writeData(temp);
  3101. if (!_useMultiLayers) useLayers(true);
  3102. break;
  3103. case L2:
  3104. temp &= ~((1<<3) | (1<<2));// Clear bits 3 and 2
  3105. temp |= (1 << 0); //bit set 0
  3106. _currentLayer = 1;
  3107. //trigMultilayer = true;
  3108. _writeData(temp);
  3109. if (!_useMultiLayers) useLayers(true);
  3110. break;
  3111. case CGRAM:
  3112. temp &= ~(1 << 3); //clear bit 3
  3113. temp |= (1 << 2); //bit set 2
  3114. if (bitRead(_FNCR0_Reg,7)){//REG[0x21] bit7 must be 0
  3115. _FNCR0_Reg &= ~(1 << 7); //clear bit 7
  3116. _writeRegister(RA8875_FNCR0,_FNCR0_Reg);
  3117. _writeRegister(RA8875_MWCR1,temp);
  3118. } else {
  3119. _writeData(temp);
  3120. }
  3121. break;
  3122. case PATTERN:
  3123. temp |= (1 << 3); //bit set 3
  3124. temp |= (1 << 2); //bit set 2
  3125. _writeData(temp);
  3126. break;
  3127. case CURSOR:
  3128. temp |= (1 << 3); //bit set 3
  3129. temp &= ~(1 << 2); //clear bit 2
  3130. _writeData(temp);
  3131. break;
  3132. default:
  3133. //break;
  3134. return;
  3135. }
  3136. //if (trigMultilayer && !_useMultiLayers) useLayers(true);//turn on multiple layers if it's off
  3137. //_writeRegister(RA8875_MWCR1,temp);
  3138. }
  3139. /*
  3140. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  3141. + GEOMETRIC PRIMITIVE STUFF +
  3142. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  3143. */
  3144. /**************************************************************************/
  3145. /*!
  3146. */
  3147. /**************************************************************************/
  3148. /* void RA8875::fillRect(void) {
  3149. writeCommand(RA8875_DCR);
  3150. _writeData(RA8875_DCR_LINESQUTRI_STOP | RA8875_DCR_DRAWSQUARE);
  3151. _writeData(RA8875_DCR_LINESQUTRI_START | RA8875_DCR_FILL | RA8875_DCR_DRAWSQUARE);
  3152. }
  3153. */
  3154. /**************************************************************************/
  3155. /*!
  3156. Write a single pixel
  3157. Parameters:
  3158. x: horizontal pos
  3159. y: vertical pos
  3160. color: RGB565 color
  3161. NOTE:
  3162. In 8bit bpp RA8875 needs a 8bit color(332) and NOT a 16bit(565),
  3163. the routine deal with this...
  3164. */
  3165. /**************************************************************************/
  3166. void RA8875::drawPixel(int16_t x, int16_t y, uint16_t color)
  3167. {
  3168. //setXY(x,y);
  3169. if (_textMode) _setTextMode(false);//we are in text mode?
  3170. setXY(x,y);
  3171. writeCommand(RA8875_MRWC);
  3172. if (_color_bpp > 8){
  3173. writeData16(color);
  3174. } else {//TOTEST:layer bug workaround for 8bit color!
  3175. _writeData(_color16To8bpp(color));
  3176. }
  3177. }
  3178. /**************************************************************************/
  3179. /*!
  3180. Draw a series of pixels
  3181. Parameters:
  3182. p: an array of 16bit colors (pixels)
  3183. count: how many pixels
  3184. x: horizontal pos
  3185. y: vertical pos
  3186. NOTE:
  3187. In 8bit bpp RA8875 needs a 8bit color(332) and NOT a 16bit(565),
  3188. the routine deal with this...
  3189. */
  3190. /**************************************************************************/
  3191. void RA8875::drawPixels(uint16_t p[], uint16_t count, int16_t x, int16_t y)
  3192. {
  3193. //setXY(x,y);
  3194. uint16_t temp = 0;
  3195. uint16_t i;
  3196. if (_textMode) _setTextMode(false);//we are in text mode?
  3197. setXY(x,y);
  3198. writeCommand(RA8875_MRWC);
  3199. _startSend();
  3200. //set data
  3201. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  3202. _spiwrite(RA8875_DATAWRITE);
  3203. #else
  3204. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  3205. _pspi->transfer(RA8875_DATAWRITE);
  3206. #else
  3207. SPI.transfer(RA8875_DATAWRITE);
  3208. #endif
  3209. #endif
  3210. //the loop
  3211. for (i=0;i<count;i++){
  3212. if (_color_bpp < 16) {
  3213. temp = _color16To8bpp(p[i]);//TOTEST:layer bug workaround for 8bit color!
  3214. } else {
  3215. temp = p[i];
  3216. }
  3217. #if !defined(ENERGIA) && !defined(___DUESTUFF) && ((ARDUINO >= 160) || (TEENSYDUINO > 121))
  3218. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  3219. if (_color_bpp > 8){
  3220. _pspi->transfer16(temp);
  3221. } else {//TOTEST:layer bug workaround for 8bit color!
  3222. _pspi->transfer(temp & 0xFF);
  3223. }
  3224. #else
  3225. if (_color_bpp > 8){
  3226. SPI.transfer16(temp);
  3227. } else {//TOTEST:layer bug workaround for 8bit color!
  3228. SPI.transfer(temp & 0xFF);
  3229. }
  3230. #endif
  3231. #else
  3232. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  3233. if (_color_bpp > 8){
  3234. SPI.transfer(_cs, temp >> 8, SPI_CONTINUE);
  3235. SPI.transfer(_cs, temp & 0xFF, SPI_LAST);
  3236. } else {//TOTEST:layer bug workaround for 8bit color!
  3237. SPI.transfer(_cs, temp & 0xFF, SPI_LAST);
  3238. }
  3239. #else
  3240. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  3241. if (_color_bpp > 8){
  3242. _spiwrite16(temp);
  3243. } else {//TOTEST:layer bug workaround for 8bit color!
  3244. _spiwrite(temp >> 8);
  3245. }
  3246. #else
  3247. if (_color_bpp > 8){
  3248. SPI.transfer(temp >> 8);
  3249. SPI.transfer(temp & 0xFF);
  3250. } else {//TOTEST:layer bug workaround for 8bit color!
  3251. SPI.transfer(temp & 0xFF);
  3252. }
  3253. #endif
  3254. #endif
  3255. #endif
  3256. }
  3257. _endSend();
  3258. }
  3259. /**************************************************************************/
  3260. /*!
  3261. Get a pixel color from screen
  3262. Parameters:
  3263. x: horizontal pos
  3264. y: vertical pos
  3265. */
  3266. /**************************************************************************/
  3267. uint16_t RA8875::getPixel(int16_t x, int16_t y)
  3268. {
  3269. uint16_t color;
  3270. setXY(x,y);
  3271. if (_textMode) _setTextMode(false);//we are in text mode?
  3272. writeCommand(RA8875_MRWC);
  3273. #if defined(_FASTCPU)
  3274. _slowDownSPI(true);
  3275. #endif
  3276. _startSend();
  3277. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  3278. _spiwrite(RA8875_DATAREAD);
  3279. _spiwrite(0x00);
  3280. #else
  3281. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  3282. _pspi->transfer(RA8875_DATAREAD);
  3283. _pspi->transfer(0x00);//first byte it's dummy
  3284. #else
  3285. SPI.transfer(RA8875_DATAREAD);
  3286. SPI.transfer(0x00);//first byte it's dummy
  3287. #endif
  3288. #endif
  3289. #if !defined(___DUESTUFF) && ((ARDUINO >= 160) || (TEENSYDUINO > 121))
  3290. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  3291. color = _pspi->transfer16(0x0);
  3292. #else
  3293. color = SPI.transfer16(0x0);
  3294. #endif
  3295. #else
  3296. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  3297. color = SPI.transfer(_cs, 0x0, SPI_CONTINUE);
  3298. color |= (SPI.transfer(_cs, 0x0, SPI_LAST) << 8);
  3299. #else
  3300. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  3301. color = _spiread();
  3302. color |= (_spiread() << 8);
  3303. #else
  3304. color = SPI.transfer(0x0);
  3305. color |= (SPI.transfer(0x0) << 8);
  3306. #endif
  3307. #endif
  3308. #endif
  3309. #if defined(_FASTCPU)
  3310. _slowDownSPI(false);
  3311. #endif
  3312. _endSend();
  3313. return color;
  3314. }
  3315. /*
  3316. void RA8875::getPixels(uint16_t * p, uint32_t count, int16_t x, int16_t y)
  3317. {
  3318. uint16_t color;
  3319. if (_textMode) _setTextMode(false);//we are in text mode?
  3320. setXY(x,y);
  3321. writeCommand(RA8875_MRWC);
  3322. #if defined(_FASTCPU)
  3323. _slowDownSPI(true);
  3324. #endif
  3325. _startSend();
  3326. SPI.transfer(RA8875_DATAREAD);
  3327. #if !defined(ENERGIA) && !defined(__SAM3X8E__) && ((ARDUINO >= 160) || (TEENSYDUINO > 121))
  3328. SPI.transfer16(0x0);//dummy
  3329. #else
  3330. SPI.transfer(0x0);//dummy
  3331. SPI.transfer(0x0);//dummy
  3332. #endif
  3333. while (count--) {
  3334. #if !defined(__SAM3X8E__) && ((ARDUINO >= 160) || (TEENSYDUINO > 121))
  3335. color = SPI.transfer16(0x0);
  3336. #else
  3337. color = SPI.transfer(0x0);
  3338. color |= (SPI.transfer(0x0) << 8);
  3339. #endif
  3340. *p++ = color;
  3341. }
  3342. #if defined(_FASTCPU)
  3343. _slowDownSPI(false);
  3344. #endif
  3345. _endSend();
  3346. }
  3347. */
  3348. /**************************************************************************/
  3349. /*!
  3350. Basic line draw
  3351. Parameters:
  3352. x0: horizontal start pos
  3353. y0: vertical start
  3354. x1: horizontal end pos
  3355. y1: vertical end pos
  3356. color: RGB565 color
  3357. NOTE:
  3358. Remember that this write from->to so: drawLine(0,0,2,0,RA8875_RED);
  3359. result a 3 pixel long! (0..1..2)
  3360. */
  3361. /**************************************************************************/
  3362. void RA8875::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
  3363. {
  3364. //if ((x0 == x1 && y0 == y1) || ((x1 - x0 == 1) && (y1 - y0 == 1))) {//NEW
  3365. if ((x0 == x1 && y0 == y1)) {//Thanks MrTOM
  3366. drawPixel(x0,y0,color);
  3367. return;
  3368. }
  3369. //if ((x1 - x0 == 1) && (y1 - y0 == 1)) drawPixel(x0,y0,color);
  3370. if (_portrait) { swapvals(x0,y0); swapvals(x1,y1);}
  3371. if (_textMode) _setTextMode(false);//we are in text mode?
  3372. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  3373. _TXTrecoverColor = true;
  3374. #endif
  3375. if (color != _foreColor) setForegroundColor(color);//0.69b30 avoid 3 useless SPI calls
  3376. _line_addressing(x0,y0,x1,y1);
  3377. _writeRegister(RA8875_DCR,0x80);
  3378. _waitPoll(RA8875_DCR, RA8875_DCR_LINESQUTRI_STATUS, _RA8875_WAITPOLL_TIMEOUT_DCR_LINESQUTRI_STATUS);
  3379. }
  3380. /**************************************************************************/
  3381. /*!
  3382. Basic line by using Angle as parameter
  3383. Parameters:
  3384. x: horizontal start pos
  3385. y: vertical start
  3386. angle: the angle of the line
  3387. length: lenght of the line
  3388. color: RGB565 color
  3389. */
  3390. /**************************************************************************/
  3391. void RA8875::drawLineAngle(int16_t x, int16_t y, int16_t angle, uint16_t length, uint16_t color,int offset)
  3392. {
  3393. if (length < 2) {
  3394. drawPixel(x,y,color);
  3395. } else {
  3396. length--;//n
  3397. drawLine(
  3398. x,
  3399. y,
  3400. //x + (length * _cosDeg_helper(angle + offset)),//_angle_offset
  3401. x + round((length) * _cosDeg_helper(angle + offset)),//Thanks MrTom
  3402. //y + (length * _sinDeg_helper(angle + offset)),
  3403. y + round((length) * _sinDeg_helper(angle + offset)),//Thanks MrTom
  3404. color);
  3405. }
  3406. }
  3407. /**************************************************************************/
  3408. /*!
  3409. Basic line by using Angle as parameter
  3410. Parameters:
  3411. x: horizontal start pos
  3412. y: vertical start
  3413. angle: the angle of the line
  3414. start: where line start
  3415. length: lenght of the line
  3416. color: RGB565 color
  3417. */
  3418. /**************************************************************************/
  3419. void RA8875::drawLineAngle(int16_t x, int16_t y, int16_t angle, uint16_t start, uint16_t length, uint16_t color,int offset)
  3420. {
  3421. if (length < 2) {
  3422. drawPixel(
  3423. x + round(start * _cosDeg_helper(angle + offset)),
  3424. y + round(start * _sinDeg_helper(angle + offset)),
  3425. color);
  3426. } else {
  3427. length--;//n
  3428. drawLine(
  3429. //x + start * _cosDeg_helper(angle + offset),//_angle_offset
  3430. x + round(start * _cosDeg_helper(angle + offset)),//Thanks MrTom
  3431. //y + start * _sinDeg_helper(angle + offset),
  3432. y + round(start * _sinDeg_helper(angle + offset)),//Thanks MrTom
  3433. //x + (start + length) * _cosDeg_helper(angle + offset),
  3434. x + round((start + length) * _cosDeg_helper(angle + offset)),//Thanks MrTom
  3435. //y + (start + length) * _sinDeg_helper(angle + offset),
  3436. y + round((start + length) * _sinDeg_helper(angle + offset)), //Thanks MrTom
  3437. color);
  3438. }
  3439. }
  3440. void RA8875::roundGaugeTicker(uint16_t x, uint16_t y, uint16_t r, int from, int to, float dev,uint16_t color)
  3441. {
  3442. float dsec;
  3443. int i;
  3444. for (i = from; i <= to; i += 30) {
  3445. dsec = i * (PI / 180);
  3446. drawLine(
  3447. x + (cos(dsec) * (r / dev)) + 1,
  3448. y + (sin(dsec) * (r / dev)) + 1,
  3449. x + (cos(dsec) * r) + 1,
  3450. y + (sin(dsec) * r) + 1,
  3451. color);
  3452. }
  3453. }
  3454. /**************************************************************************/
  3455. /*!
  3456. for compatibility with popular Adafruit_GFX
  3457. draws a single vertical line
  3458. Parameters:
  3459. x: horizontal start
  3460. y: vertical start
  3461. h: height
  3462. color: RGB565 color
  3463. */
  3464. /**************************************************************************/
  3465. void RA8875::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
  3466. {
  3467. if (h < 1) h = 1;
  3468. h < 2 ? drawPixel(x,y,color) : drawLine(x, y, x, (y+h)-1, color);
  3469. }
  3470. /**************************************************************************/
  3471. /*!
  3472. for compatibility with popular Adafruit_GFX
  3473. draws a single orizontal line
  3474. Parameters:
  3475. x: horizontal start
  3476. y: vertical start
  3477. w: width
  3478. color: RGB565 color
  3479. */
  3480. /**************************************************************************/
  3481. void RA8875::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
  3482. {
  3483. if (w < 1) w = 1;
  3484. w < 2 ? drawPixel(x,y,color) : drawLine(x, y, (w+x)-1, y, color);
  3485. }
  3486. /**************************************************************************/
  3487. /*!
  3488. draws a rectangle
  3489. Parameters:
  3490. x: horizontal start
  3491. y: vertical start
  3492. w: width
  3493. h: height
  3494. color: RGB565 color
  3495. */
  3496. /**************************************************************************/
  3497. void RA8875::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
  3498. {
  3499. //RA8875 it's not out-of-range tolerant so this is a workaround
  3500. if (w < 1 || h < 1) return;//it cannot be!
  3501. if (w < 2 && h < 2){ //render as pixel
  3502. drawPixel(x,y,color);
  3503. } else { //render as rect
  3504. _rect_helper(x,y,(w+x)-1,(h+y)-1,color,false);//thanks the experimentalist
  3505. }
  3506. }
  3507. /**************************************************************************/
  3508. /*!
  3509. draws a FILLED rectangle
  3510. Parameters:
  3511. x: horizontal start
  3512. y: vertical start
  3513. w: width
  3514. h: height
  3515. color: RGB565 color
  3516. */
  3517. /**************************************************************************/
  3518. void RA8875::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
  3519. {
  3520. //RA8875 it's not out-of-range tolerant so this is a workaround
  3521. if (w < 1 || h < 1) return;//it cannot be!
  3522. if (w < 2 && h < 2){ //render as pixel
  3523. drawPixel(x,y,color);
  3524. } else { //render as rect
  3525. //Serial.printf(" fillRect: %d %d %d %d %x\n", x, y, w, h, color);
  3526. _rect_helper(x,y,(x+w)-1,(y+h)-1,color,true);//thanks the experimentalist
  3527. }
  3528. }
  3529. /**************************************************************************/
  3530. /*!
  3531. write a filled rectangle wither user colors array
  3532. Parameters:
  3533. x: horizontal start
  3534. y: vertical start
  3535. w: width
  3536. h: height
  3537. pcolors: Array of RGB565 color of size w*h
  3538. */
  3539. /**************************************************************************/
  3540. void RA8875::writeRect(int16_t x, int16_t y, int16_t w, int16_t h, const uint16_t *pcolors)
  3541. {
  3542. uint16_t start_x = (x != CENTER) ? x : (_width - w) / 2;
  3543. uint16_t start_y = (y != CENTER) ? y : (_height - h) / 2;
  3544. static uint16_t rotated_row[800]; // max size.
  3545. bool portrait_mode = isPortrait();
  3546. if (portrait_mode) {
  3547. pcolors += (w - 1);
  3548. for (uint16_t x = start_x + w - 1; x >= start_x; x--) {
  3549. const uint16_t *pimage = pcolors;
  3550. for (uint16_t i = 0; i < h; i++) {
  3551. rotated_row[i] = *pimage;
  3552. pimage += w;
  3553. }
  3554. //Serial.printf("DP %x, %d, %d %d\n", rotated_row, h, start_x, y);
  3555. drawPixels(rotated_row, h, x, start_y);
  3556. pcolors--;
  3557. }
  3558. } else {
  3559. // now lets draw out each of the lines of the image...
  3560. for (uint16_t y = start_y; y < (start_y + h); y++) {
  3561. // tft.setY(y); // Not needed drawPixels calls setXY which will set y...
  3562. drawPixels((uint16_t*)pcolors, w, start_x, y);
  3563. pcolors += w;
  3564. }
  3565. }
  3566. }
  3567. /**************************************************************************/
  3568. /*!
  3569. calculate a grandient color
  3570. return a spectrum starting at blue to red (0...127)
  3571. */
  3572. /**************************************************************************/
  3573. uint16_t RA8875::grandient(uint8_t val)
  3574. {
  3575. uint8_t r = 0;
  3576. uint8_t g = 0;
  3577. uint8_t b = 0;
  3578. uint8_t q = val / 32;
  3579. switch(q){
  3580. case 0:
  3581. r = 0; g = 2 * (val % 32); b = 31;
  3582. break;
  3583. case 1:
  3584. r = 0; g = 63; b = 31 - (val % 32);
  3585. break;
  3586. case 2:
  3587. r = val % 32; g = 63; b = 0;
  3588. break;
  3589. case 3:
  3590. r = 31; g = 63 - 2 * (val % 32); b = 0;
  3591. break;
  3592. }
  3593. return (r << 11) + (g << 5) + b;
  3594. }
  3595. /**************************************************************************/
  3596. /*!
  3597. interpolate 2 16bit colors
  3598. return a 16bit mixed color between the two
  3599. Parameters:
  3600. color1:
  3601. color2:
  3602. pos:0...div (mix percentage) (0:color1, div:color2)
  3603. div:divisions between color1 and color 2
  3604. */
  3605. /**************************************************************************/
  3606. uint16_t RA8875::colorInterpolation(uint16_t color1,uint16_t color2,uint16_t pos,uint16_t div)
  3607. {
  3608. if (pos == 0) return color1;
  3609. if (pos >= div) return color2;
  3610. uint8_t r1,g1,b1;
  3611. Color565ToRGB(color1,r1,g1,b1);//split in r,g,b
  3612. uint8_t r2,g2,b2;
  3613. Color565ToRGB(color2,r2,g2,b2);//split in r,g,b
  3614. return colorInterpolation(r1,g1,b1,r2,g2,b2,pos,div);
  3615. }
  3616. /**************************************************************************/
  3617. /*!
  3618. interpolate 2 r,g,b colors
  3619. return a 16bit mixed color between the two
  3620. Parameters:
  3621. r1.
  3622. g1:
  3623. b1:
  3624. r2:
  3625. g2:
  3626. b2:
  3627. pos:0...div (mix percentage) (0:color1, div:color2)
  3628. div:divisions between color1 and color 2
  3629. */
  3630. /**************************************************************************/
  3631. uint16_t RA8875::colorInterpolation(uint8_t r1,uint8_t g1,uint8_t b1,uint8_t r2,uint8_t g2,uint8_t b2,uint16_t pos,uint16_t div)
  3632. {
  3633. if (pos == 0) return Color565(r1,g1,b1);
  3634. if (pos >= div) return Color565(r2,g2,b2);
  3635. float pos2 = (float)pos/div;
  3636. return Color565(
  3637. (uint8_t)(((1.0 - pos2) * r1) + (pos2 * r2)),
  3638. (uint8_t)((1.0 - pos2) * g1 + (pos2 * g2)),
  3639. (uint8_t)(((1.0 - pos2) * b1) + (pos2 * b2))
  3640. );
  3641. }
  3642. /**************************************************************************/
  3643. /*!
  3644. draws a dots filled area
  3645. Parameters:
  3646. x: horizontal origin
  3647. y: vertical origin
  3648. w: width
  3649. h: height
  3650. spacing: space between dots in pixels (min 2pix)
  3651. color: RGB565 color
  3652. */
  3653. /**************************************************************************/
  3654. void RA8875::drawMesh(int16_t x, int16_t y, int16_t w, int16_t h, uint8_t spacing, uint16_t color)
  3655. {
  3656. if (spacing < 2) spacing = 2;
  3657. if (((x + w) - 1) >= _width) w = _width - x;
  3658. if (((y + h) - 1) >= _height) h = _height - y;
  3659. int16_t n, m;
  3660. if (w < x) {n = w; w = x; x = n;}
  3661. if (h < y) {n = h; h = y; y = n;}
  3662. for (m = y; m <= h; m += spacing) {
  3663. for (n = x; n <= w; n += spacing) {
  3664. drawPixel(n, m, color);
  3665. }
  3666. }
  3667. }
  3668. /**************************************************************************/
  3669. /*!
  3670. Fill the ActiveWindow by using a specified RGB565 color
  3671. Parameters:
  3672. color: RGB565 color (default=BLACK)
  3673. */
  3674. /**************************************************************************/
  3675. void RA8875::fillWindow(uint16_t color)
  3676. {
  3677. _line_addressing(0,0,RA8875_WIDTH-1, RA8875_HEIGHT-1);
  3678. setForegroundColor(color);
  3679. writeCommand(RA8875_DCR);
  3680. _writeData(0xB0);
  3681. _waitPoll(RA8875_DCR, RA8875_DCR_LINESQUTRI_STATUS, _RA8875_WAITPOLL_TIMEOUT_DCR_LINESQUTRI_STATUS);
  3682. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  3683. _TXTrecoverColor = true;
  3684. #endif
  3685. }
  3686. /**************************************************************************/
  3687. /*!
  3688. clearScreen it's different from fillWindow because it doesn't depends
  3689. from the active window settings so it will clear all the screen.
  3690. It should be used only when needed since it's slower than fillWindow.
  3691. parameter:
  3692. color: 16bit color (default=BLACK)
  3693. */
  3694. /**************************************************************************/
  3695. void RA8875::clearScreen(uint16_t color)//0.69b24
  3696. {
  3697. setActiveWindow();
  3698. fillWindow(color);
  3699. }
  3700. /**************************************************************************/
  3701. /*!
  3702. Draw circle
  3703. Parameters:
  3704. x0: The 0-based x location of the center of the circle
  3705. y0: The 0-based y location of the center of the circle
  3706. r: radius
  3707. color: RGB565 color
  3708. */
  3709. /**************************************************************************/
  3710. void RA8875::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
  3711. {
  3712. _center_helper(x0,y0);
  3713. if (r < 1) return;
  3714. if (r < 2) {
  3715. drawPixel(x0,y0,color);
  3716. return;
  3717. }
  3718. _circle_helper(x0, y0, r, color, false);
  3719. }
  3720. /**************************************************************************/
  3721. /*!
  3722. Draw filled circle
  3723. Parameters:
  3724. x0: The 0-based x location of the center of the circle
  3725. y0: The 0-based y location of the center of the circle
  3726. r: radius
  3727. color: RGB565 color
  3728. */
  3729. /**************************************************************************/
  3730. /*
  3731. void RA8875::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
  3732. {
  3733. _center_helper(x0,y0);
  3734. if (r <= 0) return;
  3735. _circle_helper(x0, y0, r, color, true);
  3736. }
  3737. */
  3738. void RA8875::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
  3739. {
  3740. _center_helper(x0,y0);
  3741. if (r < 1) return;
  3742. if (r == 1) {
  3743. drawPixel(x0,y0,color);
  3744. return;
  3745. }
  3746. _circle_helper(x0, y0, r, color, true);
  3747. }
  3748. /**************************************************************************/
  3749. /*!
  3750. Draw a quadrilater by connecting 4 points
  3751. Parameters:
  3752. x0:
  3753. y0:
  3754. x1:
  3755. y1:
  3756. x2:
  3757. y2:
  3758. x3:
  3759. y3:
  3760. color: RGB565 color
  3761. */
  3762. /**************************************************************************/
  3763. void RA8875::drawQuad(int16_t x0, int16_t y0,int16_t x1, int16_t y1,int16_t x2, int16_t y2,int16_t x3, int16_t y3, uint16_t color)
  3764. {
  3765. drawLine(x0, y0, x1, y1, color);//low 1
  3766. drawLine(x1, y1, x2, y2, color);//high 1
  3767. drawLine(x2, y2, x3, y3, color);//high 2
  3768. drawLine(x3, y3, x0, y0, color);//low 2
  3769. }
  3770. /**************************************************************************/
  3771. /*!
  3772. Draw a filled quadrilater by connecting 4 points
  3773. Parameters:
  3774. x0:
  3775. y0:
  3776. x1:
  3777. y1:
  3778. x2:
  3779. y2:
  3780. x3:
  3781. y3:
  3782. color: RGB565 color
  3783. triangled: if true a full quad will be generated, false generate a low res quad (faster)
  3784. *NOTE: a bug in _triangle_helper create some problem, still fixing....
  3785. */
  3786. /**************************************************************************/
  3787. void RA8875::fillQuad(int16_t x0, int16_t y0,int16_t x1, int16_t y1,int16_t x2, int16_t y2, int16_t x3, int16_t y3, uint16_t color, bool triangled)
  3788. {
  3789. _triangle_helper(x0, y0, x1, y1, x2, y2, color,true);
  3790. if (triangled) _triangle_helper(x2, y2, x3, y3, x0, y0, color,true);
  3791. _triangle_helper(x1, y1, x2, y2, x3, y3, color,true);
  3792. }
  3793. /**************************************************************************/
  3794. /*!
  3795. Draw a polygon from a center
  3796. Parameters:
  3797. cx: x center of the polygon
  3798. cy: y center of the polygon
  3799. sides: how many sides (min 3)
  3800. diameter: diameter of the polygon
  3801. rot: angle rotation of the polygon
  3802. color: RGB565 color
  3803. */
  3804. /**************************************************************************/
  3805. void RA8875::drawPolygon(int16_t cx, int16_t cy, uint8_t sides, int16_t diameter, float rot, uint16_t color)
  3806. {
  3807. _center_helper(cx,cy);
  3808. sides = (sides > 2? sides : 3);
  3809. float dtr = (PI / 180.0) + PI;
  3810. float rads = 360.0 / sides;//points spacd equally
  3811. uint8_t i;
  3812. for (i = 0; i < sides; i++) {
  3813. drawLine(
  3814. cx + (sin((i*rads + rot) * dtr) * diameter),
  3815. cy + (cos((i*rads + rot) * dtr) * diameter),
  3816. cx + (sin(((i+1)*rads + rot) * dtr) * diameter),
  3817. cy + (cos(((i+1)*rads + rot) * dtr) * diameter),
  3818. color);
  3819. }
  3820. }
  3821. /**************************************************************************/
  3822. /*!
  3823. ringMeter
  3824. (adapted from Alan Senior (thanks man!))
  3825. it create a ring meter with a lot of personalizations,
  3826. it return the width of the gauge so you can use this value
  3827. for positioning other gauges near the one just created easily
  3828. Parameters:
  3829. val: your value
  3830. minV: the minimum value possible
  3831. maxV: the max value possible
  3832. x: the position on x axis
  3833. y: the position on y axis
  3834. r: the radius of the gauge (minimum 50)
  3835. units: a text that shows the units, if "none" all text will be avoided
  3836. scheme:0...7 or 16 bit color (not BLACK or WHITE)
  3837. 0:red
  3838. 1:green
  3839. 2:blue
  3840. 3:blue->red
  3841. 4:green->red
  3842. 5:red->green
  3843. 6:red->green->blue
  3844. 7:cyan->green->red
  3845. 8:black->white linear interpolation
  3846. 9:violet->yellow linear interpolation
  3847. or
  3848. RGB565 color (not BLACK or WHITE)
  3849. backSegColor: the color of the segments not active (default BLACK)
  3850. angle: 90 -> 180 (the shape of the meter, 90:halfway, 180:full round, 150:default)
  3851. inc: 5...20 (5:solid, 20:sparse divisions, default:10)
  3852. */
  3853. /**************************************************************************/
  3854. void RA8875::ringMeter(int val, int minV, int maxV, int16_t x, int16_t y, uint16_t r, const char* units, uint16_t colorScheme,uint16_t backSegColor,int16_t angle,uint8_t inc)
  3855. {
  3856. if (inc < 5) inc = 5;
  3857. if (inc > 20) inc = 20;
  3858. if (r < 50) r = 50;
  3859. if (angle < 90) angle = 90;
  3860. if (angle > 180) angle = 180;
  3861. int curAngle = map(val, minV, maxV, -angle, angle);
  3862. uint16_t colour;
  3863. x += r;
  3864. y += r; // Calculate coords of centre of ring
  3865. uint16_t w = r / 4; // Width of outer ring is 1/4 of radius
  3866. const uint8_t seg = 5; // Segments are 5 degrees wide = 60 segments for 300 degrees
  3867. // Draw colour blocks every inc degrees
  3868. for (int16_t i = -angle; i < angle; i += inc) {
  3869. colour = RA8875_BLACK;
  3870. switch (colorScheme) {
  3871. case 0:
  3872. colour = RA8875_RED;
  3873. break; // Fixed colour
  3874. case 1:
  3875. colour = RA8875_GREEN;
  3876. break; // Fixed colour
  3877. case 2:
  3878. colour = RA8875_BLUE;
  3879. break; // Fixed colour
  3880. case 3:
  3881. colour = grandient(map(i, -angle, angle, 0, 127));
  3882. break; // Full spectrum blue to red
  3883. case 4:
  3884. colour = grandient(map(i, -angle, angle, 63, 127));
  3885. break; // Green to red (high temperature etc)
  3886. case 5:
  3887. colour = grandient(map(i, -angle, angle, 127, 63));
  3888. break; // Red to green (low battery etc)
  3889. case 6:
  3890. colour = grandient(map(i, -angle, angle, 127, 0));
  3891. break; // Red to blue (air cond reverse)
  3892. case 7:
  3893. colour = grandient(map(i, -angle, angle, 35, 127));
  3894. break; // cyan to red
  3895. case 8:
  3896. colour = colorInterpolation(0,0,0,255,255,255,map(i,-angle,angle,0,w),w);
  3897. break; // black to white
  3898. case 9:
  3899. colour = colorInterpolation(0x80,0,0xC0,0xFF,0xFF,0,map(i,-angle,angle,0,w),w);
  3900. break; // violet to yellow
  3901. default:
  3902. if (colorScheme > 9){
  3903. colour = colorScheme;
  3904. } else {
  3905. colour = RA8875_BLUE;
  3906. }
  3907. break; // Fixed colour
  3908. }
  3909. // Calculate pair of coordinates for segment start
  3910. float xStart = cos((i - 90) * 0.0174532925);
  3911. float yStart = sin((i - 90) * 0.0174532925);
  3912. uint16_t x0 = xStart * (r - w) + x;
  3913. uint16_t y0 = yStart * (r - w) + y;
  3914. uint16_t x1 = xStart * r + x;
  3915. uint16_t y1 = yStart * r + y;
  3916. // Calculate pair of coordinates for segment end
  3917. float xEnd = cos((i + seg - 90) * 0.0174532925);
  3918. float yEnd = sin((i + seg - 90) * 0.0174532925);
  3919. int16_t x2 = xEnd * (r - w) + x;
  3920. int16_t y2 = yEnd * (r - w) + y;
  3921. int16_t x3 = xEnd * r + x;
  3922. int16_t y3 = yEnd * r + y;
  3923. if (i < curAngle) { // Fill in coloured segments with 2 triangles
  3924. fillQuad(x0, y0, x1, y1, x2, y2, x3, y3, colour, false);
  3925. } else {// Fill in blank segments
  3926. fillQuad(x0, y0, x1, y1, x2, y2, x3, y3, backSegColor, false);
  3927. }
  3928. }
  3929. // text
  3930. if (strcmp(units, "none") != 0){
  3931. //erase internal background
  3932. if (angle > 90) {
  3933. fillCircle(x, y, r - w, _backColor);
  3934. } else {
  3935. fillCurve(x, y + getFontHeight() / 2, r - w, r - w, 1, _backColor);
  3936. fillCurve(x, y + getFontHeight() / 2, r - w, r - w, 2, _backColor);
  3937. }
  3938. //prepare for write text
  3939. if (r > 84) {
  3940. setFontScale(1);
  3941. } else {
  3942. setFontScale(0);
  3943. }
  3944. if (_portrait){
  3945. setCursor(y, x - 15, true);
  3946. } else {
  3947. setCursor(x - 15, y, true);
  3948. }
  3949. print(val);
  3950. print(" ");
  3951. print(units);
  3952. }
  3953. // Calculate and return right hand side x coordinate
  3954. //return x + r;
  3955. }
  3956. /**************************************************************************/
  3957. /*!
  3958. Draw Triangle
  3959. Parameters:
  3960. x0: The 0-based x location of the point 0 of the triangle bottom LEFT
  3961. y0: The 0-based y location of the point 0 of the triangle bottom LEFT
  3962. x1: The 0-based x location of the point 1 of the triangle middle TOP
  3963. y1: The 0-based y location of the point 1 of the triangle middle TOP
  3964. x2: The 0-based x location of the point 2 of the triangle bottom RIGHT
  3965. y2: The 0-based y location of the point 2 of the triangle bottom RIGHT
  3966. color: RGB565 color
  3967. */
  3968. /**************************************************************************/
  3969. void RA8875::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
  3970. {
  3971. _triangle_helper(x0, y0, x1, y1, x2, y2, color, false);
  3972. }
  3973. /**************************************************************************/
  3974. /*!
  3975. Draw filled Triangle
  3976. Parameters:
  3977. x0: The 0-based x location of the point 0 of the triangle
  3978. y0: The 0-based y location of the point 0 of the triangle
  3979. x1: The 0-based x location of the point 1 of the triangle
  3980. y1: The 0-based y location of the point 1 of the triangle
  3981. x2: The 0-based x location of the point 2 of the triangle
  3982. y2: The 0-based y location of the point 2 of the triangle
  3983. color: RGB565 color
  3984. */
  3985. /**************************************************************************/
  3986. void RA8875::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
  3987. {
  3988. _triangle_helper(x0, y0, x1, y1, x2, y2, color, true);
  3989. }
  3990. /**************************************************************************/
  3991. /*!
  3992. Draw an ellipse
  3993. Parameters:
  3994. xCenter: x location of the center of the ellipse
  3995. yCenter: y location of the center of the ellipse
  3996. longAxis: Size in pixels of the long axis
  3997. shortAxis: Size in pixels of the short axis
  3998. color: RGB565 color
  3999. */
  4000. /**************************************************************************/
  4001. void RA8875::drawEllipse(int16_t xCenter, int16_t yCenter, int16_t longAxis, int16_t shortAxis, uint16_t color)
  4002. {
  4003. _ellipseCurve_helper(xCenter, yCenter, longAxis, shortAxis, 255, color, false);
  4004. }
  4005. /**************************************************************************/
  4006. /*!
  4007. Draw a filled ellipse
  4008. Parameters:
  4009. xCenter: x location of the center of the ellipse
  4010. yCenter: y location of the center of the ellipse
  4011. longAxis: Size in pixels of the long axis
  4012. shortAxis: Size in pixels of the short axis
  4013. color: RGB565 color
  4014. */
  4015. /**************************************************************************/
  4016. void RA8875::fillEllipse(int16_t xCenter, int16_t yCenter, int16_t longAxis, int16_t shortAxis, uint16_t color)
  4017. {
  4018. _ellipseCurve_helper(xCenter, yCenter, longAxis, shortAxis, 255, color, true);
  4019. }
  4020. /**************************************************************************/
  4021. /*!
  4022. Draw a curve
  4023. Parameters:
  4024. xCenter:] x location of the ellipse center
  4025. yCenter: y location of the ellipse center
  4026. longAxis: Size in pixels of the long axis
  4027. shortAxis: Size in pixels of the short axis
  4028. curvePart: Curve to draw in clock-wise dir: 0[180-270°],1[270-0°],2[0-90°],3[90-180°]
  4029. color: RGB565 color
  4030. */
  4031. /**************************************************************************/
  4032. void RA8875::drawCurve(int16_t xCenter, int16_t yCenter, int16_t longAxis, int16_t shortAxis, uint8_t curvePart, uint16_t color)
  4033. {
  4034. curvePart = curvePart % 4; //limit to the range 0-3
  4035. if (_portrait) {//fix a problem with rotation
  4036. if (curvePart == 0) {
  4037. curvePart = 2;
  4038. } else if (curvePart == 2) {
  4039. curvePart = 0;
  4040. }
  4041. }
  4042. _ellipseCurve_helper(xCenter, yCenter, longAxis, shortAxis, curvePart, color, false);
  4043. }
  4044. /**************************************************************************/
  4045. /*!
  4046. Draw a filled curve
  4047. Parameters:
  4048. xCenter:] x location of the ellipse center
  4049. yCenter: y location of the ellipse center
  4050. longAxis: Size in pixels of the long axis
  4051. shortAxis: Size in pixels of the short axis
  4052. curvePart: Curve to draw in clock-wise dir: 0[180-270°],1[270-0°],2[0-90°],3[90-180°]
  4053. color: RGB565 color
  4054. */
  4055. /**************************************************************************/
  4056. void RA8875::fillCurve(int16_t xCenter, int16_t yCenter, int16_t longAxis, int16_t shortAxis, uint8_t curvePart, uint16_t color)
  4057. {
  4058. curvePart = curvePart % 4; //limit to the range 0-3
  4059. if (_portrait) {//fix a problem with rotation
  4060. if (curvePart == 0) {
  4061. curvePart = 2;
  4062. } else if (curvePart == 2) {
  4063. curvePart = 0;
  4064. }
  4065. }
  4066. _ellipseCurve_helper(xCenter, yCenter, longAxis, shortAxis, curvePart, color, true);
  4067. }
  4068. /**************************************************************************/
  4069. /*!
  4070. Draw a rounded rectangle
  4071. Parameters:
  4072. x: x location of the rectangle
  4073. y: y location of the rectangle
  4074. w: the width in pix
  4075. h: the height in pix
  4076. r: the radius of the rounded corner
  4077. color: RGB565 color
  4078. _roundRect_helper it's not tolerant to improper values
  4079. so there's some value check here
  4080. */
  4081. /**************************************************************************/
  4082. void RA8875::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
  4083. {
  4084. if (r == 0) drawRect(x,y,w,h,color);
  4085. if (w < 1 || h < 1) return;//it cannot be!
  4086. if (w < 2 && h < 2){ //render as pixel
  4087. drawPixel(x,y,color);
  4088. } else { //render as rect
  4089. if (w < h && (r * 2) >= w) r = (w / 2) - 1;
  4090. if (w > h && (r * 2) >= h) r = (h / 2) - 1;
  4091. if (r == w || r == h) drawRect(x,y,w,h,color);
  4092. _roundRect_helper(x, y, (x + w) - 1, (y + h) - 1, r, color, false);
  4093. }
  4094. }
  4095. /**************************************************************************/
  4096. /*!
  4097. Draw a filled rounded rectangle
  4098. Parameters:
  4099. x: x location of the rectangle
  4100. y: y location of the rectangle
  4101. w: the width in pix
  4102. h: the height in pix
  4103. r: the radius of the rounded corner
  4104. color: RGB565 color
  4105. */
  4106. /**************************************************************************/
  4107. void RA8875::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
  4108. {
  4109. if (r == 0) fillRect(x,y,w,h,color);
  4110. if (w < 1 || h < 1) return;//it cannot be!
  4111. if (w < 2 && h < 2){ //render as pixel
  4112. drawPixel(x,y,color);
  4113. } else { //render as rect
  4114. if (w < h && (r * 2) >= w) r = (w / 2) - 1;
  4115. if (w > h && (r *2) >= h) r = (h / 2) - 1;
  4116. if (r == w || r == h) drawRect(x,y,w,h,color);
  4117. _roundRect_helper(x, y, (x + w) - 1, (y + h) - 1, r, color, true);
  4118. }
  4119. }
  4120. /**************************************************************************/
  4121. /*!
  4122. check area of a triangle
  4123. [private]
  4124. Thanks MrTom
  4125. */
  4126. /**************************************************************************/
  4127. float RA8875::_check_area(int16_t Ax, int16_t Ay, int16_t Bx, int16_t By, int16_t Cx, int16_t Cy) {
  4128. float area = abs(Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By)); // Calc area
  4129. float mag1 = sqrt((Bx - Ax) * (Bx - Ax) + (By - Ay) * (By - Ay)); // Calc side lengths
  4130. float mag2 = sqrt((Cx - Ax) * (Cx - Ax) + (Cy - Ay) * (Cy - Ay));
  4131. float mag3 = sqrt((Cx - Bx) * (Cx - Bx) + (Cy - By) * (Cy - By));
  4132. float magmax = (mag1>mag2?mag1:mag2)>mag3?(mag1>mag2?mag1:mag2):mag3; // Find largest length
  4133. return area/magmax; // Return area
  4134. }
  4135. /*
  4136. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4137. + GEOMETRIC PRIMITIVE HELPERS STUFF +
  4138. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4139. */
  4140. /**************************************************************************/
  4141. /*!
  4142. helper function for circles
  4143. [private]
  4144. */
  4145. /**************************************************************************/
  4146. void RA8875::_circle_helper(int16_t x0, int16_t y0, int16_t r, uint16_t color, bool filled)//0.69b32 fixed an undocumented hardware limit
  4147. {
  4148. if (_portrait) swapvals(x0,y0);//0.69b21
  4149. if (r < 1) r = 1;
  4150. if (r < 2) {//NEW
  4151. drawPixel(x0,y0,color);
  4152. return;
  4153. }
  4154. if (r > RA8875_HEIGHT / 2) r = (RA8875_HEIGHT / 2) - 1;//this is the (undocumented) hardware limit of RA8875
  4155. if (_textMode) _setTextMode(false);//we are in text mode?
  4156. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  4157. _TXTrecoverColor = true;
  4158. #endif
  4159. if (color != _foreColor) setForegroundColor(color);//0.69b30 avoid several SPI calls
  4160. _writeRegister(RA8875_DCHR0, x0 & 0xFF);
  4161. _writeRegister(RA8875_DCHR0 + 1,x0 >> 8);
  4162. _writeRegister(RA8875_DCVR0, y0 & 0xFF);
  4163. _writeRegister(RA8875_DCVR0 + 1,y0 >> 8);
  4164. _writeRegister(RA8875_DCRR,r);
  4165. writeCommand(RA8875_DCR);
  4166. #if defined(_FASTCPU)
  4167. _slowDownSPI(true);
  4168. #endif
  4169. filled == true ? _writeData(RA8875_DCR_CIRCLE_START | RA8875_DCR_FILL) : _writeData(RA8875_DCR_CIRCLE_START | RA8875_DCR_NOFILL);
  4170. _waitPoll(RA8875_DCR, RA8875_DCR_CIRCLE_STATUS, _RA8875_WAITPOLL_TIMEOUT_DCR_CIRCLE_STATUS);//ZzZzz
  4171. #if defined(_FASTCPU)
  4172. _slowDownSPI(false);
  4173. #endif
  4174. }
  4175. /**************************************************************************/
  4176. /*!
  4177. helper function for rects (filled or not)
  4178. [private]
  4179. */
  4180. /**************************************************************************/
  4181. /*
  4182. void RA8875::_rect_helper(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color, bool filled)
  4183. {
  4184. if (w < 0 || h < 0) return;//why draw invisible rects?(MrTOM temp fix)
  4185. if (w >= _width) return;
  4186. if (h >= _height) return;
  4187. if (_portrait) {swapvals(x,y); swapvals(w,h);}
  4188. _checkLimits_helper(x,y);
  4189. if (_textMode) _setTextMode(false);//we are in text mode?
  4190. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  4191. _TXTrecoverColor = true;
  4192. #endif
  4193. if (color != _foreColor) setForegroundColor(color);
  4194. _line_addressing(x,y,w,h);
  4195. writeCommand(RA8875_DCR);
  4196. filled == true ? _writeData(0xB0) : _writeData(0x90);
  4197. _waitPoll(RA8875_DCR, RA8875_DCR_LINESQUTRI_STATUS);
  4198. }
  4199. */
  4200. void RA8875::_rect_helper(int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color, bool filled)
  4201. {
  4202. if (_portrait) {swapvals(x1,y1); swapvals(x2,y2);}
  4203. if ((x1 < 0 && x2 < 0) || (x1 >= RA8875_WIDTH && x2 >= RA8875_WIDTH) ||
  4204. (y1 < 0 && y2 < 0) || (y1 >= RA8875_HEIGHT && y2 >= RA8875_HEIGHT))
  4205. return; // All points are out of bounds, don't draw anything
  4206. _checkLimits_helper(x1,y1); // Truncate rectangle that is off screen, still draw remaining rectangle
  4207. _checkLimits_helper(x2,y2);
  4208. if (_textMode) _setTextMode(false); //we are in text mode?
  4209. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  4210. _TXTrecoverColor = true;
  4211. #endif
  4212. if (color != _foreColor) setForegroundColor(color);
  4213. if (x1==x2 && y1==y2) // Width & height can still be 1 pixel, so render as a pixel
  4214. drawPixel(x1,y1,color);
  4215. else {
  4216. _line_addressing(x1,y1,x2,y2);
  4217. writeCommand(RA8875_DCR);
  4218. filled == true ? _writeData(0xB0) : _writeData(0x90);
  4219. _waitPoll(RA8875_DCR, RA8875_DCR_LINESQUTRI_STATUS, _RA8875_WAITPOLL_TIMEOUT_DCR_LINESQUTRI_STATUS);
  4220. }
  4221. }
  4222. /**************************************************************************/
  4223. /*!
  4224. helper function for triangles
  4225. [private]
  4226. */
  4227. /**************************************************************************/
  4228. void RA8875::_triangle_helper(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color, bool filled)
  4229. {
  4230. if (x0 >= _width || x1 >= _width || x2 >= _width) return;
  4231. if (y0 >= _height || y1 >= _height || y2 >= _height) return;
  4232. if (_portrait) {swapvals(x0,y0); swapvals(x1,y1); swapvals(x2,y2);}
  4233. /*
  4234. if (x0 == x1 && y0 == y1){
  4235. drawLine(x0, y0, x2, y2,color);
  4236. return;
  4237. } else if (x0 == x2 && y0 == y2){
  4238. drawLine(x0, y0, x1, y1,color);
  4239. return;
  4240. } else if (x0 == x1 && y0 == y1 && x0 == x2 && y0 == y2) {//new
  4241. drawPixel(x0, y0, color);
  4242. return;
  4243. }
  4244. */
  4245. /*
  4246. if (y0 > y1) {swapvals(y0, y1); swapvals(x0, x1);} // Sort points from Y < to >
  4247. if (y1 > y2) {swapvals(y2, y1); swapvals(x2, x1);}
  4248. if (y0 > y1) {swapvals(y0, y1); swapvals(x0, x1);}
  4249. */
  4250. /*
  4251. if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
  4252. int16_t a, b;
  4253. a = b = x0;
  4254. if (x1 < a) {
  4255. a = x1;
  4256. } else if (x1 > b) {
  4257. b = x1;
  4258. }
  4259. if (x2 < a) {
  4260. a = x2;
  4261. } else if (x2 > b) {
  4262. b = x2;
  4263. }
  4264. drawFastHLine(a, y0, b-a+1, color);
  4265. return;
  4266. }
  4267. */
  4268. // Avoid drawing lines here due to hardware bug in certain circumstances when a
  4269. // specific shape triangle is drawn after a line. This bug can still happen, but
  4270. // at least the user has control over fixing it.
  4271. // Not drawing a line here is slower, but drawing a non-filled "triangle" is
  4272. // slightly faster than a filled "triangle".
  4273. //
  4274. // bug example: tft.drawLine(799,479, 750,50, RA8875_BLUE)
  4275. // tft.fillTriangle(480,152, 456,212, 215,410, RA8875_GREEN)
  4276. // MrTom
  4277. //
  4278. if (x0 == x1 && y0 == y1 && x0 == x2 && y0 == y2) { // All points are same
  4279. drawPixel(x0,y0, color);
  4280. return;
  4281. } else if ((x0 == x1 && y0 == y1) || (x0 == x2 && y0 == y2) || (x1 == x2 && y1 == y2)){
  4282. filled = false; // Two points are same
  4283. } else if (x0 == x1 && x0 == x2){
  4284. filled = false; // Vertical line
  4285. } else if (y0 == y1 && y0 == y2){
  4286. filled = false; // Horizontal line
  4287. }
  4288. if (filled){
  4289. if (_check_area(x0,y0, x1,y1, x2,y2) < 0.9) {
  4290. filled = false; // Draw non-filled triangle to avoid filled triangle bug when two vertices are close together.
  4291. }
  4292. }
  4293. if (_textMode) _setTextMode(false);//we are in text mode?
  4294. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  4295. _TXTrecoverColor = true;
  4296. #endif
  4297. if (color != _foreColor) setForegroundColor(color);//0.69b30 avoid several SPI calls
  4298. //_checkLimits_helper(x0,y0);
  4299. //_checkLimits_helper(x1,y1);
  4300. _line_addressing(x0,y0,x1,y1);
  4301. //p2
  4302. _writeRegister(RA8875_DTPH0, x2 & 0xFF);
  4303. _writeRegister(RA8875_DTPH0 + 1,x2 >> 8);
  4304. _writeRegister(RA8875_DTPV0, y2 & 0xFF);
  4305. _writeRegister(RA8875_DTPV0 + 1,y2 >> 8);
  4306. writeCommand(RA8875_DCR);
  4307. filled == true ? _writeData(0xA1) : _writeData(0x81);
  4308. _waitPoll(RA8875_DCR, RA8875_DCR_LINESQUTRI_STATUS, _RA8875_WAITPOLL_TIMEOUT_DCR_LINESQUTRI_STATUS);
  4309. }
  4310. /**************************************************************************/
  4311. /*!
  4312. helper function for ellipse and curve
  4313. [private]
  4314. */
  4315. /**************************************************************************/
  4316. void RA8875::_ellipseCurve_helper(int16_t xCenter, int16_t yCenter, int16_t longAxis, int16_t shortAxis, uint8_t curvePart,uint16_t color, bool filled)
  4317. {
  4318. _center_helper(xCenter,yCenter);//use CENTER?
  4319. if (_portrait) {
  4320. swapvals(xCenter,yCenter);
  4321. swapvals(longAxis,shortAxis);
  4322. if (longAxis > _height/2) longAxis = (_height / 2) - 1;
  4323. if (shortAxis > _width/2) shortAxis = (_width / 2) - 1;
  4324. } else {
  4325. if (longAxis > _width/2) longAxis = (_width / 2) - 1;
  4326. if (shortAxis > _height/2) shortAxis = (_height / 2) - 1;
  4327. }
  4328. if (longAxis == 1 && shortAxis == 1) {
  4329. drawPixel(xCenter,yCenter,color);
  4330. return;
  4331. }
  4332. _checkLimits_helper(xCenter,yCenter);
  4333. if (_textMode) _setTextMode(false);//we are in text mode?
  4334. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  4335. _TXTrecoverColor = true;
  4336. #endif
  4337. if (color != _foreColor) setForegroundColor(color);
  4338. _curve_addressing(xCenter,yCenter,longAxis,shortAxis);
  4339. writeCommand(RA8875_ELLIPSE);
  4340. if (curvePart != 255){
  4341. curvePart = curvePart % 4; //limit to the range 0-3
  4342. filled == true ? _writeData(0xD0 | (curvePart & 0x03)) : _writeData(0x90 | (curvePart & 0x03));
  4343. } else {
  4344. filled == true ? _writeData(0xC0) : _writeData(0x80);
  4345. }
  4346. _waitPoll(RA8875_ELLIPSE, RA8875_ELLIPSE_STATUS, _RA8875_WAITPOLL_TIMEOUT_ELLIPSE_STATUS);
  4347. }
  4348. /**************************************************************************/
  4349. /*!
  4350. helper function for rounded Rects
  4351. PARAMETERS
  4352. x:
  4353. y:
  4354. w:
  4355. h:
  4356. r:
  4357. color:
  4358. filled:
  4359. [private]
  4360. */
  4361. /**************************************************************************/
  4362. void RA8875::_roundRect_helper(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color, bool filled)
  4363. {
  4364. if (_portrait) {swapvals(x,y); swapvals(w,h);}
  4365. if (_textMode) _setTextMode(false);//we are in text mode?
  4366. #if defined(USE_RA8875_SEPARATE_TEXT_COLOR)
  4367. _TXTrecoverColor = true;
  4368. #endif
  4369. if (color != _foreColor) setForegroundColor(color);//0.69b30 avoid several SPI calls
  4370. _line_addressing(x,y,w,h);
  4371. _writeRegister(RA8875_ELL_A0, r & 0xFF);
  4372. _writeRegister(RA8875_ELL_A0 + 1,r >> 8);
  4373. _writeRegister(RA8875_ELL_B0, r & 0xFF);
  4374. _writeRegister(RA8875_ELL_B0 + 1,r >> 8);
  4375. writeCommand(RA8875_ELLIPSE);
  4376. filled == true ? _writeData(0xE0) : _writeData(0xA0);
  4377. _waitPoll(RA8875_ELLIPSE, RA8875_DCR_LINESQUTRI_STATUS, _RA8875_WAITPOLL_TIMEOUT_DCR_LINESQUTRI_STATUS);
  4378. }
  4379. /**************************************************************************/
  4380. /*!
  4381. helper function for draw arcs in degrees
  4382. DrawArc function thanks to Jnmattern and his Arc_2.0 (https://github.com/Jnmattern)
  4383. Adapted for DUE by Marek Buriak https://github.com/marekburiak/ILI9341_Due
  4384. Re-Adapted for this library by sumotoy
  4385. PARAMETERS
  4386. cx: center x
  4387. cy: center y
  4388. radius: the radius of the arc
  4389. thickness:
  4390. start: where arc start in degrees
  4391. end: where arc end in degrees
  4392. color:
  4393. [private]
  4394. */
  4395. /**************************************************************************/
  4396. void RA8875::_drawArc_helper(uint16_t cx, uint16_t cy, uint16_t radius, uint16_t thickness, float start, float end, uint16_t color) {
  4397. //_center_helper(cx,cy);//use CENTER?
  4398. int16_t xmin = 65535, xmax = -32767, ymin = 32767, ymax = -32767;
  4399. float cosStart, sinStart, cosEnd, sinEnd;
  4400. float r, t;
  4401. float startAngle, endAngle;
  4402. startAngle = (start / _arcAngle_max) * 360; // 252
  4403. endAngle = (end / _arcAngle_max) * 360; // 807
  4404. while (startAngle < 0) startAngle += 360;
  4405. while (endAngle < 0) endAngle += 360;
  4406. while (startAngle > 360) startAngle -= 360;
  4407. while (endAngle > 360) endAngle -= 360;
  4408. if (startAngle > endAngle) {
  4409. _drawArc_helper(cx, cy, radius, thickness, ((startAngle) / (float)360) * _arcAngle_max, _arcAngle_max, color);
  4410. _drawArc_helper(cx, cy, radius, thickness, 0, ((endAngle) / (float)360) * _arcAngle_max, color);
  4411. } else {
  4412. //if (_textMode) _setTextMode(false);//we are in text mode?
  4413. // Calculate bounding box for the arc to be drawn
  4414. cosStart = _cosDeg_helper(startAngle);
  4415. sinStart = _sinDeg_helper(startAngle);
  4416. cosEnd = _cosDeg_helper(endAngle);
  4417. sinEnd = _sinDeg_helper(endAngle);
  4418. r = radius;
  4419. // Point 1: radius & startAngle
  4420. t = r * cosStart;
  4421. if (t < xmin) xmin = t;
  4422. if (t > xmax) xmax = t;
  4423. t = r * sinStart;
  4424. if (t < ymin) ymin = t;
  4425. if (t > ymax) ymax = t;
  4426. // Point 2: radius & endAngle
  4427. t = r * cosEnd;
  4428. if (t < xmin) xmin = t;
  4429. if (t > xmax) xmax = t;
  4430. t = r * sinEnd;
  4431. if (t < ymin) ymin = t;
  4432. if (t > ymax) ymax = t;
  4433. r = radius - thickness;
  4434. // Point 3: radius-thickness & startAngle
  4435. t = r * cosStart;
  4436. if (t < xmin) xmin = t;
  4437. if (t > xmax) xmax = t;
  4438. t = r * sinStart;
  4439. if (t < ymin) ymin = t;
  4440. if (t > ymax) ymax = t;
  4441. // Point 4: radius-thickness & endAngle
  4442. t = r * cosEnd;
  4443. if (t < xmin) xmin = t;
  4444. if (t > xmax) xmax = t;
  4445. t = r * sinEnd;
  4446. if (t < ymin) ymin = t;
  4447. if (t > ymax) ymax = t;
  4448. // Corrections if arc crosses X or Y axis
  4449. if ((startAngle < 90) && (endAngle > 90)) ymax = radius;
  4450. if ((startAngle < 180) && (endAngle > 180)) xmin = -radius;
  4451. if ((startAngle < 270) && (endAngle > 270)) ymin = -radius;
  4452. // Slopes for the two sides of the arc
  4453. float sslope = (float)cosStart / (float)sinStart;
  4454. float eslope = (float)cosEnd / (float)sinEnd;
  4455. if (endAngle == 360) eslope = -1000000;
  4456. int ir2 = (radius - thickness) * (radius - thickness);
  4457. int or2 = radius * radius;
  4458. for (int x = xmin; x <= xmax; x++) {
  4459. bool y1StartFound = false, y2StartFound = false;
  4460. bool y1EndFound = false, y2EndSearching = false;
  4461. int y1s = 0, y1e = 0, y2s = 0;//, y2e = 0;
  4462. for (int y = ymin; y <= ymax; y++) {
  4463. int x2 = x * x;
  4464. int y2 = y * y;
  4465. if (
  4466. (x2 + y2 < or2 && x2 + y2 >= ir2) && (
  4467. (y > 0 && startAngle < 180 && x <= y * sslope) ||
  4468. (y < 0 && startAngle > 180 && x >= y * sslope) ||
  4469. (y < 0 && startAngle <= 180) ||
  4470. (y == 0 && startAngle <= 180 && x < 0) ||
  4471. (y == 0 && startAngle == 0 && x > 0)
  4472. ) && (
  4473. (y > 0 && endAngle < 180 && x >= y * eslope) ||
  4474. (y < 0 && endAngle > 180 && x <= y * eslope) ||
  4475. (y > 0 && endAngle >= 180) ||
  4476. (y == 0 && endAngle >= 180 && x < 0) ||
  4477. (y == 0 && startAngle == 0 && x > 0)))
  4478. {
  4479. if (!y1StartFound) { //start of the higher line found
  4480. y1StartFound = true;
  4481. y1s = y;
  4482. } else if (y1EndFound && !y2StartFound) {//start of the lower line found
  4483. y2StartFound = true;
  4484. y2s = y;
  4485. y += y1e - y1s - 1; // calculate the most probable end of the lower line (in most cases the length of lower line is equal to length of upper line), in the next loop we will validate if the end of line is really there
  4486. if (y > ymax - 1) {// the most probable end of line 2 is beyond ymax so line 2 must be shorter, thus continue with pixel by pixel search
  4487. y = y2s; // reset y and continue with pixel by pixel search
  4488. y2EndSearching = true;
  4489. }
  4490. } else if (y2StartFound && !y2EndSearching) {
  4491. // we validated that the probable end of the lower line has a pixel, continue with pixel by pixel search, in most cases next loop with confirm the end of lower line as it will not find a valid pixel
  4492. y2EndSearching = true;
  4493. }
  4494. } else {
  4495. if (y1StartFound && !y1EndFound) {//higher line end found
  4496. y1EndFound = true;
  4497. y1e = y - 1;
  4498. drawFastVLine(cx + x, cy + y1s, y - y1s, color);
  4499. if (y < 0) {
  4500. y = abs(y); // skip the empty middle
  4501. }
  4502. else
  4503. break;
  4504. } else if (y2StartFound) {
  4505. if (y2EndSearching) {
  4506. // we found the end of the lower line after pixel by pixel search
  4507. drawFastVLine(cx + x, cy + y2s, y - y2s, color);
  4508. y2EndSearching = false;
  4509. break;
  4510. } else {
  4511. // the expected end of the lower line is not there so the lower line must be shorter
  4512. y = y2s; // put the y back to the lower line start and go pixel by pixel to find the end
  4513. y2EndSearching = true;
  4514. }
  4515. }
  4516. }
  4517. }
  4518. if (y1StartFound && !y1EndFound){
  4519. y1e = ymax;
  4520. drawFastVLine(cx + x, cy + y1s, y1e - y1s + 1, color);
  4521. } else if (y2StartFound && y2EndSearching) {// we found start of lower line but we are still searching for the end
  4522. // which we haven't found in the loop so the last pixel in a column must be the end
  4523. drawFastVLine(cx + x, cy + y2s, ymax - y2s + 1, color);
  4524. }
  4525. }
  4526. }
  4527. }
  4528. /**************************************************************************/
  4529. /*!
  4530. this update the RA8875 Active Window registers
  4531. [private]
  4532. */
  4533. /**************************************************************************/
  4534. void RA8875::_updateActiveWindow(bool full)
  4535. {
  4536. if (full){
  4537. // X
  4538. _writeRegister(RA8875_HSAW0, 0x00);
  4539. _writeRegister(RA8875_HSAW0 + 1,0x00);
  4540. _writeRegister(RA8875_HEAW0, (RA8875_WIDTH) & 0xFF);
  4541. _writeRegister(RA8875_HEAW0 + 1,(RA8875_WIDTH) >> 8);
  4542. // Y
  4543. _writeRegister(RA8875_VSAW0, 0x00);
  4544. _writeRegister(RA8875_VSAW0 + 1,0x00);
  4545. _writeRegister(RA8875_VEAW0, (RA8875_HEIGHT) & 0xFF);
  4546. _writeRegister(RA8875_VEAW0 + 1,(RA8875_HEIGHT) >> 8);
  4547. } else {
  4548. // X
  4549. _writeRegister(RA8875_HSAW0, _activeWindowXL & 0xFF);
  4550. _writeRegister(RA8875_HSAW0 + 1,_activeWindowXL >> 8);
  4551. _writeRegister(RA8875_HEAW0, _activeWindowXR & 0xFF);
  4552. _writeRegister(RA8875_HEAW0 + 1,_activeWindowXR >> 8);
  4553. // Y
  4554. _writeRegister(RA8875_VSAW0, _activeWindowYT & 0xFF);
  4555. _writeRegister(RA8875_VSAW0 + 1,_activeWindowYT >> 8);
  4556. _writeRegister(RA8875_VEAW0, _activeWindowYB & 0xFF);
  4557. _writeRegister(RA8875_VEAW0 + 1,_activeWindowYB >> 8);
  4558. }
  4559. }
  4560. /**************************************************************************/
  4561. /*!
  4562. Graphic line addressing helper
  4563. [private]
  4564. */
  4565. /**************************************************************************/
  4566. void RA8875::_line_addressing(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
  4567. {
  4568. //X0
  4569. _writeRegister(RA8875_DLHSR0, x0 & 0xFF);
  4570. _writeRegister(RA8875_DLHSR0 + 1,x0 >> 8);
  4571. //Y0
  4572. _writeRegister(RA8875_DLVSR0, y0 & 0xFF);
  4573. _writeRegister(RA8875_DLVSR0 + 1,y0 >> 8);
  4574. //X1
  4575. _writeRegister(RA8875_DLHER0, x1 & 0xFF);
  4576. _writeRegister(RA8875_DLHER0 + 1,x1 >> 8);
  4577. //Y1
  4578. _writeRegister(RA8875_DLVER0, y1 & 0xFF);
  4579. _writeRegister(RA8875_DLVER0 + 1,y1 >> 8);
  4580. }
  4581. /**************************************************************************/
  4582. /*!
  4583. curve addressing helper
  4584. [private]
  4585. */
  4586. /**************************************************************************/
  4587. void RA8875::_curve_addressing(int16_t x0, int16_t y0, int16_t x1, int16_t y1)
  4588. {
  4589. //center
  4590. _writeRegister(RA8875_DEHR0, x0 & 0xFF);
  4591. _writeRegister(RA8875_DEHR0 + 1,x0 >> 8);
  4592. _writeRegister(RA8875_DEVR0, y0 & 0xFF);
  4593. _writeRegister(RA8875_DEVR0 + 1,y0 >> 8);
  4594. //long,short ax
  4595. _writeRegister(RA8875_ELL_A0, x1 & 0xFF);
  4596. _writeRegister(RA8875_ELL_A0 + 1,x1 >> 8);
  4597. _writeRegister(RA8875_ELL_B0, y1 & 0xFF);
  4598. _writeRegister(RA8875_ELL_B0 + 1,y1 >> 8);
  4599. }
  4600. /**************************************************************************/
  4601. /*!
  4602. sin e cos helpers
  4603. [private]
  4604. */
  4605. /**************************************************************************/
  4606. float RA8875::_cosDeg_helper(float angle)
  4607. {
  4608. float radians = angle / (float)360 * 2 * PI;
  4609. return cos(radians);
  4610. }
  4611. float RA8875::_sinDeg_helper(float angle)
  4612. {
  4613. float radians = angle / (float)360 * 2 * PI;
  4614. return sin(radians);
  4615. }
  4616. /**************************************************************************/
  4617. /*!
  4618. change the arc default parameters
  4619. */
  4620. /**************************************************************************/
  4621. void RA8875::setArcParams(float arcAngleMax, int arcAngleOffset)
  4622. {
  4623. _arcAngle_max = arcAngleMax;
  4624. _arcAngle_offset = arcAngleOffset;
  4625. }
  4626. /**************************************************************************/
  4627. /*!
  4628. change the angle offset parameter from default one
  4629. */
  4630. /**************************************************************************/
  4631. void RA8875::setAngleOffset(int16_t angleOffset)
  4632. {
  4633. _angle_offset = ANGLE_OFFSET + angleOffset;
  4634. }
  4635. /*
  4636. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4637. + PWM STUFF +
  4638. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4639. */
  4640. /**************************************************************************/
  4641. /*!
  4642. on/off GPIO (basic for Adafruit module
  4643. */
  4644. /**************************************************************************/
  4645. void RA8875::GPIOX(boolean on)
  4646. {
  4647. _writeRegister(RA8875_GPIOX, on);
  4648. }
  4649. /**************************************************************************/
  4650. /*!
  4651. PWM out
  4652. Parameters:
  4653. pw: pwm selection (1,2)
  4654. p: 0...255 rate
  4655. */
  4656. /**************************************************************************/
  4657. void RA8875::PWMout(uint8_t pw,uint8_t p)
  4658. {
  4659. uint8_t reg;
  4660. pw > 1 ? reg = RA8875_P2DCR : reg = RA8875_P1DCR;
  4661. _writeRegister(reg, p);
  4662. }
  4663. /**************************************************************************/
  4664. /*!
  4665. Set the brightness of the backlight (if connected to pwm)
  4666. (basic controls pwm 1)
  4667. Parameters:
  4668. val: 0...255
  4669. */
  4670. /**************************************************************************/
  4671. void RA8875::brightness(uint8_t val)
  4672. {
  4673. _brightness = val;
  4674. PWMout(1,_brightness);
  4675. }
  4676. /**************************************************************************/
  4677. /*!
  4678. controls the backligh by using PWM engine.
  4679. It handles adafruit board separately
  4680. Parameters:
  4681. on: true(backlight on), false(backlight off)
  4682. */
  4683. /**************************************************************************/
  4684. void RA8875::backlight(boolean on) //0.69b31 (fixed an issue with adafruit backlight)
  4685. {
  4686. if (_displaySize == Adafruit_480x272 || _displaySize == Adafruit_800x480) GPIOX(on);
  4687. if (on == true){
  4688. PWMsetup(1,true, RA8875_PWM_CLK_DIV1024);//setup PWM ch 1 for backlight
  4689. PWMout(1,_brightness);//turn on PWM1
  4690. } else {
  4691. PWMsetup(1,false, RA8875_PWM_CLK_DIV1024);//setup PWM ch 1 for backlight
  4692. }
  4693. }
  4694. /**************************************************************************/
  4695. /*!
  4696. Setup PWM engine
  4697. Parameters:
  4698. pw: pwm selection (1,2)
  4699. on: turn on/off
  4700. clock: the clock setting
  4701. [private]
  4702. */
  4703. /**************************************************************************/
  4704. void RA8875::PWMsetup(uint8_t pw,boolean on, uint8_t clock)
  4705. {
  4706. uint8_t reg;
  4707. uint8_t set;
  4708. if (pw > 1){
  4709. reg = RA8875_P2CR;
  4710. on == true ? set = RA8875_PxCR_ENABLE : set = RA8875_PxCR_DISABLE;
  4711. } else {
  4712. reg = RA8875_P1CR;
  4713. on == true ? set = RA8875_PxCR_ENABLE : set = RA8875_PxCR_DISABLE;
  4714. }
  4715. _writeRegister(reg,(set | (clock & 0xF)));
  4716. }
  4717. /*
  4718. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4719. + ISR +
  4720. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4721. */
  4722. void RA8875::setInternalInt(enum RA8875intlist b)
  4723. {
  4724. _enabledInterrups |= (1 << b);//set
  4725. }
  4726. void RA8875::clearInternalInt(enum RA8875intlist b)
  4727. {
  4728. _enabledInterrups &= ~(1 << b);//clear
  4729. }
  4730. /**************************************************************************/
  4731. /*!
  4732. RA8875 can use the INT pin for many purposes.
  4733. This function just tell the CPU to use a pin for listen to RA8875 pin,
  4734. no matter if we will use ISR or DigitalRead
  4735. ------------------------------
  4736. Bit: Called by: In use:
  4737. --------------------------------
  4738. 0: isr triggered [*]
  4739. 1: Resistive TS [*]
  4740. 2: KeyScan [*]
  4741. 3: DMA
  4742. 4: BTE
  4743. 5: -na-
  4744. 6: -na-
  4745. 7: -na-
  4746. --------------------------------
  4747. Parameters:
  4748. INTpin: it's the pin where we listen to ISR
  4749. INTnum: it's the INT related to pin. On some processor it's not needed
  4750. This last parameter it's used only when decide to use an ISR.
  4751. */
  4752. /**************************************************************************/
  4753. void RA8875::useINT(const uint8_t INTpin,const uint8_t INTnum)
  4754. {
  4755. _intPin = INTpin;
  4756. _intNum = INTnum;
  4757. #if defined(___TEENSYES)//all of them (32 bit only)
  4758. pinMode(_intPin ,INPUT_PULLUP);
  4759. #else
  4760. pinMode(_intPin ,INPUT);
  4761. #endif
  4762. }
  4763. /**************************************************************************/
  4764. /*!
  4765. the generic ISR routine, will set to 1 bit 0 of _RA8875_INTS
  4766. [private]
  4767. */
  4768. /**************************************************************************/
  4769. void RA8875::_isr(void)
  4770. {
  4771. if(_active_touch_objects[0]) _active_touch_objects[0]->_RA8875_INTS |= (1 << 0);//set
  4772. }
  4773. void RA8875::_isr1(void)
  4774. {
  4775. if(_active_touch_objects[1]) _active_touch_objects[1]->_RA8875_INTS |= (1 << 0);//set
  4776. }
  4777. void RA8875::_isr2(void)
  4778. {
  4779. if(_active_touch_objects[2]) _active_touch_objects[2]->_RA8875_INTS |= (1 << 0);//set
  4780. }
  4781. /**************************************************************************/
  4782. /*!
  4783. Enable the ISR, after this any falling edge on
  4784. _intPin pin will trigger ISR
  4785. Parameters:
  4786. force: if true will force attach interrupt
  4787. NOTE:
  4788. if parameter _needISRrearm = true will rearm interrupt
  4789. */
  4790. /**************************************************************************/
  4791. #define COUNT_TOUCH_OBJECTS (sizeof(_active_touch_objects)/sizeof(_active_touch_objects[0]))
  4792. void RA8875::enableISR(bool force)
  4793. {
  4794. static void (*touch_object_isr_ptrs[])(void) = {&_isr, &_isr1, &_isr2};
  4795. if (force || _needISRrearm){
  4796. uint8_t index_touch_object = 0;
  4797. for (; index_touch_object < COUNT_TOUCH_OBJECTS; index_touch_object++) {
  4798. if ((_active_touch_objects[index_touch_object] == nullptr) || (_active_touch_objects[index_touch_object] == this)) break;
  4799. }
  4800. if (index_touch_object == COUNT_TOUCH_OBJECTS) return; // failed to find a free index...
  4801. _active_touch_objects[index_touch_object] = this; // claim this spot.
  4802. _needISRrearm = false;
  4803. #ifdef digitalPinToInterrupt
  4804. attachInterrupt(digitalPinToInterrupt(_intPin),touch_object_isr_ptrs[index_touch_object],FALLING);
  4805. #else
  4806. attachInterrupt(_intNum,touch_object_isr_ptrs[index_touch_object],FALLING);
  4807. #endif
  4808. _RA8875_INTS = 0b00000000;//reset all INT bits flags
  4809. _useISR = true;
  4810. }
  4811. #if defined(USE_RA8875_TOUCH)
  4812. if (_touchEnabled) _checkInterrupt(2);//clear internal RA int to engage
  4813. #endif
  4814. }
  4815. /**************************************************************************/
  4816. /*!
  4817. Disable ISR
  4818. Works only if previously enabled or do nothing.
  4819. */
  4820. /**************************************************************************/
  4821. void RA8875::_disableISR(void)
  4822. {
  4823. if (_useISR){
  4824. #if defined(USE_RA8875_TOUCH)
  4825. if (_touchEnabled) _checkInterrupt(2);//clear internal RA int to engage
  4826. #endif
  4827. #ifdef digitalPinToInterrupt
  4828. detachInterrupt(digitalPinToInterrupt(_intPin));
  4829. #else
  4830. detachInterrupt(_intNum);
  4831. #endif
  4832. _RA8875_INTS = 0b00000000;//reset all bits
  4833. _useISR = false;
  4834. }
  4835. }
  4836. /**************************************************************************/
  4837. /*!
  4838. Check the [interrupt register] for an interrupt,
  4839. if found it will reset it.
  4840. bit
  4841. 0: complicated....
  4842. 1: BTE INT
  4843. 2: TOUCH INT
  4844. 3: DMA INT
  4845. 4: Keyscan INT
  4846. */
  4847. /**************************************************************************/
  4848. bool RA8875::_checkInterrupt(uint8_t _bit,bool _clear)
  4849. {
  4850. if (_bit > 4) _bit = 4;
  4851. uint8_t temp = _readRegister(RA8875_INTC2);
  4852. if (bitRead(temp,_bit) == 1){
  4853. if (_clear){
  4854. temp |= (1 << _bit);//bitSet(temp,_bit);
  4855. //if (bitRead(temp,0)) bitSet(temp,0);//Mmmmm...
  4856. _writeRegister(RA8875_INTC2, temp);//clear int
  4857. }
  4858. return true;
  4859. }
  4860. return false;
  4861. }
  4862. #if defined(USE_FT5206_TOUCH)
  4863. /**************************************************************************/
  4864. /*!
  4865. The FT5206 Capacitive Touch driver uses a different INT pin than RA8875
  4866. and it's not controlled by RA chip of course, so we need a separate code
  4867. for that purpose, no matter we decide to use an ISR or digitalRead.
  4868. no matter if we will use ISR or DigitalRead
  4869. Parameters:
  4870. INTpin: it's the pin where we listen to ISR
  4871. INTnum: it's the INT related to pin. On some processor it's not needed
  4872. This last parameter it's used only when decide to use an ISR.
  4873. */
  4874. /**************************************************************************/
  4875. void RA8875::useCapINT(const uint8_t INTpin,const uint8_t INTnum)
  4876. {
  4877. _intCTSPin = INTpin;
  4878. _intCTSNum = INTnum;
  4879. #if defined(___TEENSYES)//all of them (32 bit only)
  4880. pinMode(_intCTSPin ,INPUT_PULLUP);
  4881. #else
  4882. pinMode(_intCTSPin ,INPUT);
  4883. #endif
  4884. }
  4885. /**************************************************************************/
  4886. /*!
  4887. Since FT5206 uses a different INT pin, we need a separate isr routine.
  4888. [private]
  4889. */
  4890. /**************************************************************************/
  4891. void RA8875::cts_isr(void)
  4892. {
  4893. _FT5206_INT = true;
  4894. }
  4895. /**************************************************************************/
  4896. /*!
  4897. Enable the ISR, after this any falling edge on
  4898. _intCTSPin pin will trigger ISR
  4899. Parameters:
  4900. force: if true will force attach interrup
  4901. NOTE:
  4902. if parameter _needCTS_ISRrearm = true will rearm interrupt
  4903. */
  4904. /**************************************************************************/
  4905. void RA8875::enableCapISR(bool force)
  4906. {
  4907. if (force || _needCTS_ISRrearm){
  4908. _needCTS_ISRrearm = false;
  4909. #ifdef digitalPinToInterrupt
  4910. attachInterrupt(digitalPinToInterrupt(_intCTSPin),cts_isr,FALLING);
  4911. #else
  4912. attachInterrupt(_intCTSNum,cts_isr,FALLING);
  4913. #endif
  4914. _FT5206_INT = false;
  4915. _useISR = true;
  4916. }
  4917. }
  4918. /**************************************************************************/
  4919. /*!
  4920. Disable ISR [FT5206 version]
  4921. Works only if previously enabled or do nothing.
  4922. */
  4923. /**************************************************************************/
  4924. void RA8875::_disableCapISR(void)
  4925. {
  4926. if (_useISR){
  4927. #ifdef digitalPinToInterrupt
  4928. detachInterrupt(digitalPinToInterrupt(_intCTSPin));
  4929. #else
  4930. detachInterrupt(_intCTSNum);
  4931. #endif
  4932. _FT5206_INT = false;
  4933. _useISR = false;
  4934. }
  4935. }
  4936. #endif
  4937. /*
  4938. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4939. + TOUCH SCREEN COMMONS +
  4940. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4941. */
  4942. #if !defined(_AVOID_TOUCHSCREEN)//Common touch screend methods (for capacitive and resistive)
  4943. /**************************************************************************/
  4944. /*!
  4945. Checks an interrupt has occurred. return true if yes.
  4946. Designed to run in loop.
  4947. It works with ISR or DigitalRead methods
  4948. Parameters:
  4949. safe: true (detach interrupt routine, has to be re-engaged manually!)
  4950. false (
  4951. */
  4952. /**************************************************************************/
  4953. bool RA8875::touched(bool safe)
  4954. {
  4955. if (_useISR){//using interrupts
  4956. #if defined(USE_FT5206_TOUCH)
  4957. _needCTS_ISRrearm = safe;
  4958. if (_FT5206_INT) {
  4959. #elif defined(USE_RA8875_TOUCH)
  4960. _needISRrearm = safe;
  4961. if (bitRead(_RA8875_INTS,0)){
  4962. #endif
  4963. //there was an interrupt
  4964. #if defined(USE_FT5206_TOUCH)
  4965. if (_needCTS_ISRrearm){//safe was true, detach int
  4966. _disableCapISR();
  4967. #else
  4968. if (_needISRrearm){//safe was true, detach int
  4969. _disableISR();
  4970. #endif
  4971. } else {//safe was false, do not detatch int and clear INT flag
  4972. #if defined(USE_FT5206_TOUCH)
  4973. _FT5206_INT = false;
  4974. #elif defined(USE_RA8875_TOUCH)
  4975. _RA8875_INTS &= ~(1 << 0);//clear
  4976. //_checkInterrupt(2);//clear internal RA int to re-engage
  4977. #endif
  4978. }
  4979. return true;
  4980. }
  4981. return false;
  4982. } else {//not use ISR, digitalRead method
  4983. #if defined(USE_FT5206_TOUCH)
  4984. //TODO
  4985. #elif defined(USE_RA8875_TOUCH)
  4986. if (_touchEnabled){
  4987. #if defined(___TEENSYES)
  4988. if (!digitalReadFast(_intPin)) {
  4989. #else
  4990. if (!digitalRead(_intPin)) {
  4991. #endif
  4992. _clearTInt = true;
  4993. if (_checkInterrupt(2)){
  4994. return true;
  4995. } else {
  4996. return false;
  4997. }
  4998. }//digitalRead
  4999. if (_clearTInt){
  5000. _clearTInt = false;
  5001. _checkInterrupt(2);//clear internal RA int
  5002. delay(1);
  5003. }
  5004. return false;
  5005. } else {//_touchEnabled
  5006. return false;
  5007. }
  5008. #endif
  5009. return false;
  5010. }
  5011. }
  5012. void RA8875::setTouchLimit(uint8_t limit)
  5013. {
  5014. #if defined(USE_FT5206_TOUCH)
  5015. if (limit > 5) limit = 5;//max 5 allowed
  5016. #else
  5017. limit = 1;//always 1
  5018. #endif
  5019. _maxTouch = limit;
  5020. }
  5021. uint8_t RA8875::getTouchLimit(void)
  5022. {
  5023. return _maxTouch;
  5024. }
  5025. /*
  5026. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5027. + CAPACITIVE TOUCH SCREEN CONTROLLER FT5206 +
  5028. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5029. */
  5030. #if defined(USE_FT5206_TOUCH)
  5031. /**************************************************************************/
  5032. /*!
  5033. Initialization sequence of the FT5206
  5034. */
  5035. /**************************************************************************/
  5036. void RA8875::_initializeFT5206(void)
  5037. {
  5038. uint8_t i;
  5039. for (i=0x80;i<0x89;i++){
  5040. _sendRegFT5206(i,_FT5206REgisters[i-0x80]);
  5041. }
  5042. _sendRegFT5206(0x00,0x00);//Device Mode
  5043. }
  5044. /**************************************************************************/
  5045. /*!
  5046. Communicate with FT5206
  5047. */
  5048. /**************************************************************************/
  5049. void RA8875::_sendRegFT5206(uint8_t reg,const uint8_t val)
  5050. {
  5051. // save I2C bitrate
  5052. #if !defined(___DUESTUFF)
  5053. uint8_t twbrbackup = TWBR;
  5054. TWBR = 12; // upgrade to 400KHz!
  5055. #endif
  5056. _wire->beginTransmission(_ctpAdrs);
  5057. _wire->write(reg);
  5058. _wire->write(val);
  5059. _wire->endTransmission(_ctpAdrs);
  5060. #if !defined(___DUESTUFF)
  5061. TWBR = twbrbackup;
  5062. #endif
  5063. }
  5064. /**************************************************************************/
  5065. /*!
  5066. This is the function that update the current state of the Touch Screen
  5067. It's developed for use in loop
  5068. */
  5069. /**************************************************************************/
  5070. void RA8875::updateTS(void)
  5071. {
  5072. _wire->requestFrom((uint8_t)_ctpAdrs,(uint8_t)31); //get 31 registers
  5073. uint8_t index = 0;
  5074. while(_wire->available()) {
  5075. _cptRegisters[index++] = _wire->read();//fill registers
  5076. }
  5077. _currentTouches = _cptRegisters[0x02] & 0xF;
  5078. if (_currentTouches > _maxTouch) _currentTouches = _maxTouch;
  5079. _gesture = _cptRegisters[0x01];
  5080. if (_maxTouch < 2) _gesture = 0;
  5081. uint8_t temp = _cptRegisters[0x03];
  5082. _currentTouchState = 0;
  5083. if (!bitRead(temp,7) && bitRead(temp,6)) _currentTouchState = 1;//finger up
  5084. if (bitRead(temp,7) && !bitRead(temp,6)) _currentTouchState = 2;//finger down
  5085. }
  5086. /**************************************************************************/
  5087. /*!
  5088. It gets coordinates out from data collected by updateTS function
  5089. Actually it will not communicate with FT5206, just reorder collected data
  5090. so it MUST be used after updateTS!
  5091. */
  5092. /**************************************************************************/
  5093. uint8_t RA8875::getTScoordinates(uint16_t (*touch_coordinates)[2])
  5094. {
  5095. uint8_t i;
  5096. if (_currentTouches < 1) return 0;
  5097. for (i=1;i<=_currentTouches;i++){
  5098. switch(_rotation){
  5099. case 0://ok
  5100. //touch_coordinates[i-1][0] = _width - (((_cptRegisters[coordRegStart[i-1]] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 1]) / (4096/_width);
  5101. //touch_coordinates[i-1][1] = (((_cptRegisters[coordRegStart[i-1]] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 1]) / (4096/_height);
  5102. touch_coordinates[i-1][0] = ((_cptRegisters[coordRegStart[i-1]] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 1];
  5103. touch_coordinates[i-1][1] = ((_cptRegisters[coordRegStart[i-1] + 2] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 3];
  5104. break;
  5105. case 1://ok
  5106. touch_coordinates[i-1][0] = (((_cptRegisters[coordRegStart[i-1] + 2] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 3]);
  5107. touch_coordinates[i-1][1] = (RA8875_WIDTH - 1) - (((_cptRegisters[coordRegStart[i-1]] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 1]);
  5108. break;
  5109. case 2://ok
  5110. touch_coordinates[i-1][0] = (RA8875_WIDTH - 1) - (((_cptRegisters[coordRegStart[i-1]] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 1]);
  5111. touch_coordinates[i-1][1] = (RA8875_HEIGHT - 1) -(((_cptRegisters[coordRegStart[i-1] + 2] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 3]);
  5112. break;
  5113. case 3://ok
  5114. touch_coordinates[i-1][0] = (RA8875_HEIGHT - 1) - (((_cptRegisters[coordRegStart[i-1] + 2] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 3]);
  5115. touch_coordinates[i-1][1] = (((_cptRegisters[coordRegStart[i-1]] & 0x0f) << 8) | _cptRegisters[coordRegStart[i-1] + 1]);
  5116. break;
  5117. }
  5118. if (i == _maxTouch) return i;
  5119. }
  5120. return _currentTouches;
  5121. }
  5122. /**************************************************************************/
  5123. /*!
  5124. Gets the current Touch State, must be used AFTER updateTS!
  5125. */
  5126. /**************************************************************************/
  5127. uint8_t RA8875::getTouchState(void)
  5128. {
  5129. return _currentTouchState;
  5130. }
  5131. /**************************************************************************/
  5132. /*!
  5133. Gets the number of touches, must be used AFTER updateTS!
  5134. Return 0..5
  5135. 0: no touch
  5136. */
  5137. /**************************************************************************/
  5138. uint8_t RA8875::getTouches(void)
  5139. {
  5140. return _currentTouches;
  5141. }
  5142. /**************************************************************************/
  5143. /*!
  5144. Gets the gesture, if identified, must be used AFTER updateTS!
  5145. */
  5146. /**************************************************************************/
  5147. uint8_t RA8875::getGesture(void)
  5148. {
  5149. //if gesture is up, down, left or right, juggle with bit2 & bit3 to match rotation
  5150. if((_gesture >> 4) & 1){
  5151. switch(_rotation){
  5152. case 0:
  5153. _gesture ^= 1 << 2;
  5154. if(!((_gesture >> 2) & 1)) _gesture ^= 1 << 3;
  5155. break;
  5156. case 1:
  5157. _gesture ^= 1 << 3;
  5158. break;
  5159. case 2:
  5160. _gesture ^= 1 << 2;
  5161. if((_gesture >> 2) & 1) _gesture ^= 1 << 3;
  5162. break;
  5163. }
  5164. }
  5165. return _gesture;
  5166. }
  5167. #elif defined(USE_RA8875_TOUCH)
  5168. /*
  5169. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5170. + RESISTIVE TOUCH STUFF +
  5171. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5172. */
  5173. /**************************************************************************/
  5174. /*!
  5175. Initialize support for on-chip resistive Touch Screen controller
  5176. It also enable the Touch Screen
  5177. NOTE:
  5178. You need to use useINT(pin) [before] to define an INT pin!
  5179. You need to use enableISR() [after] to enable ISR on MCU and RA8875!
  5180. */
  5181. /**************************************************************************/
  5182. void RA8875::touchBegin(void)
  5183. {
  5184. if (_intPin < 255){
  5185. /* Touch Panel Control Register 0 TPCR0 [0x70]
  5186. 7: 0(disable, 1:(enable)
  5187. 6,5,4:TP Sample Time Adjusting (000...111)
  5188. 3:Touch Panel Wakeup Enable 0(disable),1(enable)
  5189. 2,1,0:ADC Clock Setting (000...111) set fixed to 010: (System CLK) / 4, 10Mhz Max! */
  5190. #if defined(___TEENSYES) || defined(___DUESTUFF)//fast 32 bit processors
  5191. _writeRegister(RA8875_TPCR0, TP_ENABLE | TP_ADC_SAMPLE_16384_CLKS | TP_ADC_CLKDIV_32);
  5192. #else
  5193. _writeRegister(RA8875_TPCR0, TP_ENABLE | TP_ADC_SAMPLE_4096_CLKS | TP_ADC_CLKDIV_16);
  5194. #endif
  5195. _writeRegister(RA8875_TPCR1, TP_MODE_AUTO | TP_DEBOUNCE_ON);
  5196. setInternalInt(TOUCH);
  5197. _INTC1_Reg |= (1 << 2);//set
  5198. _writeRegister(RA8875_INTC1, _INTC1_Reg);
  5199. _touchEnabled = true;
  5200. } else {
  5201. _touchEnabled = false;
  5202. }
  5203. }
  5204. /**************************************************************************/
  5205. /*!
  5206. Enables or disables the on-chip touch screen controller
  5207. You must use touchBegin at list once to instruct the RA8875
  5208. Parameters:
  5209. enabled: true(enable),false(disable)
  5210. */
  5211. /**************************************************************************/
  5212. void RA8875::touchEnable(boolean enabled) {
  5213. if (_intPin < 255){
  5214. /* another grrrr bug of the RA8875!
  5215. if we are in text mode the RA chip cannot get back the
  5216. INT mode!
  5217. */
  5218. if (_textMode) _setTextMode(false);
  5219. if (!_touchEnabled && enabled) {//Enable
  5220. //enableISR(true);
  5221. // bitSet(_INTC1_Reg,2);
  5222. // _writeRegister(RA8875_INTC1, _INTC1_Reg);
  5223. _touchEnabled = true;
  5224. _checkInterrupt(2);
  5225. } else if (_touchEnabled && !enabled) {//disable
  5226. //_disableISR();
  5227. // bitClear(_INTC1_Reg,2);
  5228. // _writeRegister(RA8875_INTC1, _INTC1_Reg);
  5229. _checkInterrupt(2);
  5230. _touchEnabled = false;
  5231. }
  5232. } else {
  5233. _touchEnabled = false;
  5234. }
  5235. }
  5236. /**************************************************************************/
  5237. /*!
  5238. Read 10bit internal ADC of RA8875 registers and perform corrections
  5239. It will return always RAW data
  5240. Parameters:
  5241. x: out 0...1023
  5242. Y: out 0...1023
  5243. */
  5244. /**************************************************************************/
  5245. void RA8875::readTouchADC(uint16_t *x, uint16_t *y)
  5246. {
  5247. #if defined(_FASTCPU)
  5248. _slowDownSPI(true);
  5249. #endif
  5250. uint16_t tx = _readRegister(RA8875_TPXH);
  5251. uint16_t ty = _readRegister(RA8875_TPYH);
  5252. uint8_t remain = _readRegister(RA8875_TPXYL);
  5253. #if defined(_FASTCPU)
  5254. _slowDownSPI(false);
  5255. #endif
  5256. tx <<= 2;
  5257. ty <<= 2;
  5258. tx |= remain & 0x03; // get the bottom x bits
  5259. ty |= (remain >> 2) & 0x03; // get the bottom y bits
  5260. if (_portrait){
  5261. *x = ty;
  5262. *y = tx;
  5263. } else {
  5264. tx = 1024 - tx;
  5265. ty = 1024 - ty;
  5266. *x = tx;
  5267. *y = ty;
  5268. }
  5269. }
  5270. /**************************************************************************/
  5271. /*!
  5272. Returns 10bit x,y data with TRUE scale (0...1023)
  5273. Parameters:
  5274. x: out 0...1023
  5275. Y: out 0...1023
  5276. */
  5277. /**************************************************************************/
  5278. void RA8875::touchReadAdc(uint16_t *x, uint16_t *y)
  5279. {
  5280. uint16_t tx,ty;
  5281. readTouchADC(&tx,&ty);
  5282. if (_calibrated) {
  5283. *x = map(tx,_tsAdcMinX,_tsAdcMaxX,0,1024);
  5284. *y = map(ty,_tsAdcMinY,_tsAdcMaxY,0,1024);
  5285. } else {
  5286. *x = tx;
  5287. *y = ty;
  5288. }
  5289. _checkInterrupt(2);
  5290. }
  5291. /**************************************************************************/
  5292. /*!
  5293. Returns pixel x,y data with SCREEN scale (screen width, screen Height)
  5294. Parameters:
  5295. x: out 0...screen width (pixels)
  5296. Y: out 0...screen Height (pixels)
  5297. Check for out-of-bounds here as touches near the edge of the screen
  5298. can be safely mapped to the nearest point of the screen.
  5299. If the screen is rotated, then the min and max will be modified elsewhere
  5300. so that this always corresponds to screen pixel coordinates.
  5301. /M.SANDERSCROCK added constrain
  5302. */
  5303. /**************************************************************************/
  5304. void RA8875::touchReadPixel(uint16_t *x, uint16_t *y)
  5305. {
  5306. uint16_t tx,ty;
  5307. readTouchADC(&tx,&ty);
  5308. //*x = map(tx,_tsAdcMinX,_tsAdcMaxX,0,_width-1);
  5309. *x = constrain(map(tx,_tsAdcMinX,_tsAdcMaxX,0,_width-1),0,_width-1);
  5310. //*y = map(ty,_tsAdcMinY,_tsAdcMaxY,0,_height-1);
  5311. *y = constrain(map(ty,_tsAdcMinY,_tsAdcMaxY,0,_height-1),0,_height-1);
  5312. _checkInterrupt(2);
  5313. }
  5314. boolean RA8875::touchCalibrated(void)
  5315. {
  5316. return _calibrated;
  5317. }
  5318. /**************************************************************************/
  5319. /*! A service utility that detects if system has been calibrated in the past
  5320. Return true if an old calibration exists
  5321. [private]
  5322. */
  5323. /**************************************************************************/
  5324. boolean RA8875::_isCalibrated(void)
  5325. {
  5326. uint8_t uncaltetection = 4;
  5327. #if defined(TOUCSRCAL_XLOW) && (TOUCSRCAL_XLOW != 0)
  5328. uncaltetection--;
  5329. #endif
  5330. #if defined(TOUCSRCAL_YLOW) && (TOUCSRCAL_YLOW != 0)
  5331. uncaltetection--;
  5332. #endif
  5333. #if defined(TOUCSRCAL_XHIGH) && (TOUCSRCAL_XHIGH != 0)
  5334. uncaltetection--;
  5335. #endif
  5336. #if defined(TOUCSRCAL_YHIGH) && (TOUCSRCAL_YHIGH != 0)
  5337. uncaltetection--;
  5338. #endif
  5339. if (uncaltetection < 4) return true;
  5340. return false;
  5341. }
  5342. /**************************************************************************/
  5343. /*! A way to have different calibrations for different displays and
  5344. a way to force the system to act like uncalibrated, so you don't have
  5345. to edit header file, rebuild, edit header again ...
  5346. */
  5347. /**************************************************************************/
  5348. void RA8875::setTouchCalibrationData(uint16_t minX, uint16_t maxX, uint16_t minY, uint16_t maxY)
  5349. {
  5350. _touchrcal_xlow = minX;
  5351. _touchrcal_xhigh = maxX;
  5352. _touchrcal_ylow = minY;
  5353. _touchrcal_yhigh = maxY;
  5354. // Lets guess at setting is calibrated.
  5355. _calibrated = (minX || maxX) && (minY || maxY);
  5356. setRotation(_rotation); // make sure it is updated to what ever the rotation is now.
  5357. }
  5358. #endif
  5359. #endif
  5360. /*
  5361. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5362. + SLEEP STUFF +
  5363. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5364. */
  5365. /**************************************************************************/
  5366. /*!
  5367. Sleep mode on/off (complete sequence)
  5368. The sleep on/off sequence it's quite tricky on RA8875 when in SPI mode!
  5369. */
  5370. /**************************************************************************/
  5371. void RA8875::sleep(boolean sleep)
  5372. {
  5373. if (_sleep != sleep){//only if it's needed
  5374. _sleep = sleep;
  5375. if (_sleep == true){
  5376. //1)turn off backlight
  5377. if (_displaySize == Adafruit_480x272 || _displaySize == Adafruit_800x480/* || _displaySize == Adafruit_640x480*/) GPIOX(false);
  5378. //2)decelerate SPI clock
  5379. #if defined(_FASTCPU)
  5380. _slowDownSPI(true);
  5381. #else
  5382. #if defined(SPI_HAS_TRANSACTION)
  5383. _SPITransactionSpeed = 4000000UL;
  5384. #else
  5385. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5386. SPI.setClockDivider(_cs,SPI_SPEED_READ);
  5387. #else
  5388. SPI.setClockDivider(SPI_SPEED_READ);
  5389. #endif
  5390. #endif
  5391. #endif
  5392. //3)set PLL to default
  5393. _setSysClock(0x07,0x03,0x02);
  5394. //4)display off & sleep
  5395. _writeRegister(RA8875_PWRR, RA8875_PWRR_DISPOFF | RA8875_PWRR_SLEEP);
  5396. delay(100);
  5397. } else {
  5398. //1)wake up with display off(100ms)
  5399. _writeRegister(RA8875_PWRR, RA8875_PWRR_DISPOFF);
  5400. delay(100);
  5401. //2)bring back the pll
  5402. _setSysClock(initStrings[_initIndex][0],initStrings[_initIndex][1],initStrings[_initIndex][2]);
  5403. //_writeRegister(RA8875_PCSR,initStrings[_initIndex][2]);//Pixel Clock Setting Register
  5404. delay(20);
  5405. _writeRegister(RA8875_PWRR, RA8875_PWRR_NORMAL | RA8875_PWRR_DISPON);//disp on
  5406. delay(20);
  5407. //4)resume SPI speed
  5408. #if defined(_FASTCPU)
  5409. _slowDownSPI(false);
  5410. #else
  5411. #if defined(SPI_HAS_TRANSACTION)
  5412. _SPITransactionSpeed = _SPIMaxSpeed;
  5413. #else
  5414. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5415. SPI.setClockDivider(_cs,SPI_SPEED_WRITE);
  5416. #else
  5417. SPI.setClockDivider(SPI_SPEED_WRITE);
  5418. #endif
  5419. #endif
  5420. #endif
  5421. //5)PLL afterburn!
  5422. _setSysClock(sysClockPar[_initIndex][0],sysClockPar[_initIndex][1],initStrings[_initIndex][2]);
  5423. //5)turn on backlight
  5424. if (_displaySize == Adafruit_480x272 || _displaySize == Adafruit_800x480/* || _displaySize == Adafruit_640x480*/) GPIOX(true);
  5425. //_writeRegister(RA8875_PWRR, RA8875_PWRR_NORMAL);
  5426. }
  5427. }
  5428. }
  5429. /*
  5430. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5431. + SPI & LOW LEVEL STUFF +
  5432. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5433. */
  5434. /**************************************************************************/
  5435. /*! PRIVATE
  5436. Write in a register
  5437. Parameters:
  5438. reg: the register
  5439. val: the data
  5440. */
  5441. /**************************************************************************/
  5442. void RA8875::_writeRegister(const uint8_t reg, uint8_t val)
  5443. {
  5444. writeCommand(reg);
  5445. _writeData(val);
  5446. }
  5447. /**************************************************************************/
  5448. /*! PRIVATE
  5449. Returns the value inside register
  5450. Parameters:
  5451. reg: the register
  5452. */
  5453. /**************************************************************************/
  5454. uint8_t RA8875::_readRegister(const uint8_t reg)
  5455. {
  5456. writeCommand(reg);
  5457. return _readData(false);
  5458. }
  5459. /**************************************************************************/
  5460. /*!
  5461. Write data
  5462. Parameters:
  5463. d: the data
  5464. */
  5465. /**************************************************************************/
  5466. void RA8875::_writeData(uint8_t data)
  5467. {
  5468. _startSend();
  5469. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5470. SPI.transfer(_cs, RA8875_DATAWRITE, SPI_CONTINUE);
  5471. SPI.transfer(_cs, data, SPI_LAST);
  5472. #else
  5473. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  5474. _spiwrite(RA8875_DATAWRITE);
  5475. _spiwrite(data);
  5476. #else
  5477. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  5478. _pspi->transfer(RA8875_DATAWRITE);
  5479. _pspi->transfer(data);
  5480. #else
  5481. SPI.transfer(RA8875_DATAWRITE);
  5482. SPI.transfer(data);
  5483. #endif
  5484. #endif
  5485. #endif
  5486. _endSend();
  5487. }
  5488. /**************************************************************************/
  5489. /*!
  5490. Write 16 bit data
  5491. Parameters:
  5492. d: the data (16 bit)
  5493. */
  5494. /**************************************************************************/
  5495. void RA8875::writeData16(uint16_t data)
  5496. {
  5497. _startSend();
  5498. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  5499. _spiwrite(RA8875_DATAWRITE);
  5500. #else
  5501. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  5502. _pspi->transfer(RA8875_DATAWRITE);
  5503. #else
  5504. SPI.transfer(RA8875_DATAWRITE);
  5505. #endif
  5506. #endif
  5507. #if !defined(ENERGIA) && !defined(___DUESTUFF) && ((ARDUINO >= 160) || (TEENSYDUINO > 121))
  5508. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  5509. _pspi->transfer16(data);
  5510. #else
  5511. SPI.transfer16(data);
  5512. #endif
  5513. #else
  5514. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5515. SPI.transfer(_cs, highByte(data), SPI_CONTINUE);
  5516. SPI.transfer(_cs, lowByte(data), SPI_LAST);
  5517. #else
  5518. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  5519. _spiwrite16(data);
  5520. #else
  5521. SPI.transfer(data >> 8);
  5522. SPI.transfer(data & 0xFF);
  5523. #endif
  5524. #endif
  5525. #endif
  5526. _endSend();
  5527. }
  5528. /**************************************************************************/
  5529. /*! PRIVATE
  5530. */
  5531. /**************************************************************************/
  5532. uint8_t RA8875::_readData(bool stat)
  5533. {
  5534. #if defined(SPI_HAS_TRANSACTION)
  5535. //Serial.printf("RA8875::_readData _SPIMaxSpeed: %d\n", _SPIMaxSpeed);
  5536. if (_inited) _SPITransactionSpeed = _SPIMaxReadSpeed;
  5537. #else
  5538. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5539. if (_inited) SPI.setClockDivider(_cs,SPI_SPEED_READ);
  5540. #else
  5541. if (_inited) SPI.setClockDivider(SPI_SPEED_READ);
  5542. #endif
  5543. #endif
  5544. _startSend();
  5545. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5546. stat == true ? SPI.transfer(_cs, RA8875_CMDREAD, SPI_CONTINUE) : SPI.transfer(_cs, RA8875_DATAREAD, SPI_CONTINUE);
  5547. uint8_t x = SPI.transfer(_cs, 0x0, SPI_LAST);
  5548. #else
  5549. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  5550. stat == true ? _spiwrite(RA8875_CMDREAD) : _spiwrite(RA8875_DATAREAD);
  5551. uint8_t x = _spiread();
  5552. #else
  5553. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  5554. stat == true ? _pspi->transfer(RA8875_CMDREAD) : _pspi->transfer(RA8875_DATAREAD);
  5555. uint8_t x = _pspi->transfer(0x0);
  5556. #else
  5557. stat == true ? SPI.transfer(RA8875_CMDREAD) : SPI.transfer(RA8875_DATAREAD);
  5558. uint8_t x = SPI.transfer(0x0);
  5559. #endif
  5560. #endif
  5561. #endif
  5562. _endSend();
  5563. #if defined(SPI_HAS_TRANSACTION)
  5564. if (_inited) _SPITransactionSpeed = _SPIMaxSpeed;
  5565. #else
  5566. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5567. if (_inited) SPI.setClockDivider(_cs,SPI_SPEED_WRITE);
  5568. #else
  5569. if (_inited) SPI.setClockDivider(SPI_SPEED_WRITE);
  5570. #endif
  5571. #endif
  5572. return x;
  5573. }
  5574. /**************************************************************************/
  5575. /*!
  5576. */
  5577. /**************************************************************************/
  5578. uint8_t RA8875::readStatus(void)
  5579. {
  5580. return _readData(true);
  5581. }
  5582. /**************************************************************************/
  5583. /*! PRIVATE
  5584. Write a command
  5585. Parameters:
  5586. d: the command
  5587. */
  5588. /**************************************************************************/
  5589. void RA8875::writeCommand(const uint8_t d)
  5590. {
  5591. _startSend();
  5592. #if defined(___DUESTUFF) && defined(SPI_DUE_MODE_EXTENDED)
  5593. SPI.transfer(_cs, RA8875_CMDWRITE, SPI_CONTINUE);
  5594. SPI.transfer(_cs, d, SPI_LAST);
  5595. #else
  5596. #if (defined(__AVR__) && defined(_FASTSSPORT)) || defined(SPARK)
  5597. _spiwrite(RA8875_CMDWRITE);
  5598. _spiwrite(d);
  5599. #else
  5600. #if defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__) || defined(__MKL26Z64__)
  5601. _pspi->transfer(RA8875_CMDWRITE);
  5602. _pspi->transfer(d);
  5603. #else
  5604. SPI.transfer(RA8875_CMDWRITE);
  5605. SPI.transfer(d);
  5606. #endif
  5607. #endif
  5608. #endif
  5609. _endSend();
  5610. }
  5611. void RA8875::_fontWrite(const uint8_t* buffer, uint16_t len)
  5612. {
  5613. if(_use_default) {
  5614. if (_FNTgrandient) _FNTgrandient = false;//cannot use this with write
  5615. _textWrite((const char *)buffer, len);
  5616. //Serial.printf("Default: %c, %d, %d\n", c, _cursorX, _cursorY);
  5617. return;
  5618. }
  5619. // Lets try to handle some of the special font centering code that was done for default fonts.
  5620. if (_absoluteCenter || _relativeCenter ) {
  5621. int16_t x, y;
  5622. uint16_t strngWidth, strngHeight;
  5623. getTextBounds(buffer, len, 0, 0, &x, &y, &strngWidth, &strngHeight);
  5624. //Serial.printf("_fontwrite bounds: %d %d %u %u\n", x, y, strngWidth, strngHeight);
  5625. // Note we may want to play with the x ane y returned if they offset some
  5626. if (_absoluteCenter && strngWidth > 0){//Avoid operations for strngWidth = 0
  5627. _absoluteCenter = false;
  5628. _cursorX = _cursorX - ((x + strngWidth) / 2);
  5629. _cursorY = _cursorY - ((y + strngHeight) / 2);
  5630. } else if (_relativeCenter && strngWidth > 0){//Avoid operations for strngWidth = 0
  5631. _relativeCenter = false;
  5632. if (bitRead(_TXTparameters,5)) {//X = center
  5633. _cursorX = (_width / 2) - ((x + strngWidth) / 2);
  5634. _TXTparameters &= ~(1 << 5);//reset
  5635. }
  5636. if (bitRead(_TXTparameters,6)) {//Y = center
  5637. _cursorY = (_height / 2) - ((y + strngHeight) / 2) ;
  5638. _TXTparameters &= ~(1 << 6);//reset
  5639. }
  5640. }
  5641. }
  5642. while(len) {
  5643. uint8_t c = *buffer++;
  5644. if (font) {
  5645. //Serial.printf("ILI: %c, %d, %d\n", c, _cursorX, _cursorY);
  5646. if (c == '\n') {
  5647. //_cursorY += font->line_space;
  5648. //_cursorX = 0;
  5649. } else {
  5650. if (c == 13) {
  5651. _cursorY += font->line_space;
  5652. _cursorX = 0;
  5653. } else {
  5654. drawFontChar(c);
  5655. }
  5656. }
  5657. } else if (gfxFont) {
  5658. //Serial.printf("GFX: %c, %d, %d\n", c, _cursorX, _cursorY);
  5659. if (c == '\n') {
  5660. _cursorY += (int16_t)textsize_y * gfxFont->yAdvance;
  5661. _cursorX = 0;
  5662. } else {
  5663. drawGFXFontChar(c);
  5664. }
  5665. } else {
  5666. if (c == '\n') {
  5667. _cursorY += textsize_y*8;
  5668. _cursorX = 0;
  5669. } else if (c == '\r') {
  5670. // skip em
  5671. } else {
  5672. drawChar(_cursorX, _cursorY, c, textcolor, textbgcolor, textsize_x, textsize_y);
  5673. _cursorX += textsize_x*6;
  5674. if (wrap && (_cursorX > (_width - textsize_x*6))) {
  5675. _cursorY += textsize_y*6;
  5676. _cursorX = 0;
  5677. }
  5678. }
  5679. }
  5680. len--;
  5681. }
  5682. }
  5683. //#include "glcdfont.c"
  5684. extern "C" const unsigned char glcdfont[];
  5685. // Draw a character
  5686. void RA8875::drawChar(int16_t x, int16_t y, unsigned char c,
  5687. uint16_t fgcolor, uint16_t bgcolor, uint8_t size_x, uint8_t size_y)
  5688. {
  5689. if((x >= _width) || // Clip right
  5690. (y >= _height) || // Clip bottom
  5691. ((x + 6 * size_x - 1) < 0) || // Clip left TODO: is this correct?
  5692. ((y + 8 * size_y - 1) < 0)) // Clip top TODO: is this correct?
  5693. return;
  5694. //Serial.printf("drawchar %d %d %c %x %x %d %d\n", x, y, c, fgcolor, bgcolor, size_x, size_y);
  5695. if (fgcolor == bgcolor) {
  5696. // This transparent approach is only about 20% faster
  5697. if ((size_x == 1) && (size_y == 1)) {
  5698. uint8_t mask = 0x01;
  5699. int16_t xoff, yoff;
  5700. for (yoff=0; yoff < 8; yoff++) {
  5701. uint8_t line = 0;
  5702. for (xoff=0; xoff < 5; xoff++) {
  5703. if (glcdfont[c * 5 + xoff] & mask) line |= 1;
  5704. line <<= 1;
  5705. }
  5706. line >>= 1;
  5707. xoff = 0;
  5708. while (line) {
  5709. if (line == 0x1F) {
  5710. drawFastHLine(x + xoff, y + yoff, 5, fgcolor);
  5711. break;
  5712. } else if (line == 0x1E) {
  5713. drawFastHLine(x + xoff, y + yoff, 4, fgcolor);
  5714. break;
  5715. } else if ((line & 0x1C) == 0x1C) {
  5716. drawFastHLine(x + xoff, y + yoff, 3, fgcolor);
  5717. line <<= 4;
  5718. xoff += 4;
  5719. } else if ((line & 0x18) == 0x18) {
  5720. drawFastHLine(x + xoff, y + yoff, 2, fgcolor);
  5721. line <<= 3;
  5722. xoff += 3;
  5723. } else if ((line & 0x10) == 0x10) {
  5724. drawPixel(x + xoff, y + yoff, fgcolor);
  5725. line <<= 2;
  5726. xoff += 2;
  5727. } else {
  5728. line <<= 1;
  5729. xoff += 1;
  5730. }
  5731. }
  5732. mask = mask << 1;
  5733. }
  5734. } else {
  5735. uint8_t mask = 0x01;
  5736. int16_t xoff, yoff;
  5737. for (yoff=0; yoff < 8; yoff++) {
  5738. uint8_t line = 0;
  5739. for (xoff=0; xoff < 5; xoff++) {
  5740. if (glcdfont[c * 5 + xoff] & mask) line |= 1;
  5741. line <<= 1;
  5742. }
  5743. line >>= 1;
  5744. xoff = 0;
  5745. while (line) {
  5746. if (line == 0x1F) {
  5747. fillRect(x + xoff * size_x, y + yoff * size_y,
  5748. 5 * size_x, size_y, fgcolor);
  5749. break;
  5750. } else if (line == 0x1E) {
  5751. fillRect(x + xoff * size_x, y + yoff * size_y,
  5752. 4 * size_x, size_y, fgcolor);
  5753. break;
  5754. } else if ((line & 0x1C) == 0x1C) {
  5755. fillRect(x + xoff * size_x, y + yoff * size_y,
  5756. 3 * size_x, size_y, fgcolor);
  5757. line <<= 4;
  5758. xoff += 4;
  5759. } else if ((line & 0x18) == 0x18) {
  5760. fillRect(x + xoff * size_x, y + yoff * size_y,
  5761. 2 * size_x, size_y, fgcolor);
  5762. line <<= 3;
  5763. xoff += 3;
  5764. } else if ((line & 0x10) == 0x10) {
  5765. fillRect(x + xoff * size_x, y + yoff * size_y,
  5766. size_x, size_y, fgcolor);
  5767. line <<= 2;
  5768. xoff += 2;
  5769. } else {
  5770. line <<= 1;
  5771. xoff += 1;
  5772. }
  5773. }
  5774. mask = mask << 1;
  5775. }
  5776. }
  5777. } else {
  5778. // This solid background approach is about 5 time faster
  5779. uint8_t xc, yc;
  5780. uint8_t xr, yr;
  5781. uint8_t mask = 0x01;
  5782. // We need to offset by the origin.
  5783. x+=_originx;
  5784. y+=_originy;
  5785. int16_t x_char_start = x; // remember our X where we start outputting...
  5786. if((x >= _displayclipx2) || // Clip right
  5787. (y >= _displayclipy2) || // Clip bottom
  5788. ((x + 6 * size_x - 1) < _displayclipx1) || // Clip left TODO: this is not correct
  5789. ((y + 8 * size_y - 1) < _displayclipy1)) // Clip top TODO: this is not correct
  5790. return;
  5791. // need to build actual pixel rectangle we will output into.
  5792. int16_t y_char_top = y; // remember the y
  5793. int16_t w = 6 * size_x;
  5794. int16_t h = 8 * size_y;
  5795. if(x < _displayclipx1) { w -= (_displayclipx1-x); x = _displayclipx1; }
  5796. if((x + w - 1) >= _displayclipx2) w = _displayclipx2 - x;
  5797. if(y < _displayclipy1) { h -= (_displayclipy1 - y); y = _displayclipy1; }
  5798. if((y + h - 1) >= _displayclipy2) h = _displayclipy2 - y;
  5799. //Serial.printf("%d, %d, %d, %d\n", x, y, x + w -1, y + h - 1);
  5800. setActiveWindow(x, y, x + w -1, y + h - 1);
  5801. _startSend();
  5802. y = y_char_top; // restore the actual y.
  5803. writeCommand(RA8875_MRWC);
  5804. for (yc=0; (yc < 8) && (y < _displayclipy2); yc++) {
  5805. for (yr=0; (yr < size_y) && (y < _displayclipy2); yr++) {
  5806. x = x_char_start; // get our first x position...
  5807. if (y >= _displayclipy1) {
  5808. for (xc=0; xc < 5; xc++) {
  5809. for (xr=0; xr < size_x; xr++) {
  5810. if ((x >= _displayclipx1) && (x < _displayclipx2)) {
  5811. //write16BitColor(fgcolor);
  5812. drawPixel(xr+x,yc+y,fgcolor);
  5813. }
  5814. x++;
  5815. }
  5816. }
  5817. for (xr=0; xr < size_x; xr++) {
  5818. if ((x >= _displayclipx1) && (x < _displayclipx2)) {
  5819. //write16BitColor(bgcolor);
  5820. drawPixel(xr+x,yc+y,bgcolor);
  5821. }
  5822. x++;
  5823. }
  5824. }
  5825. y++;
  5826. }
  5827. mask = mask << 1;
  5828. }
  5829. //writecommand_last(ILI9488_NOP);
  5830. _endSend();
  5831. }
  5832. }
  5833. void RA8875::setFont(const ILI9341_t3_font_t &f) {
  5834. _use_default = 0;
  5835. if(_portrait && !_use_gfx_font) {
  5836. _cursorY += _cursorX;
  5837. _cursorX -= _cursorY;
  5838. }
  5839. _use_ili_font = 1;
  5840. _use_gfx_font = 0;
  5841. _use_int_font = 1;
  5842. _use_tfont = 0;
  5843. _gfx_last_char_x_write = 0; // Don't use cached data here
  5844. font = &f;
  5845. if (gfxFont) {
  5846. _cursorY -= 6;
  5847. gfxFont = NULL;
  5848. }
  5849. fontbpp = 1;
  5850. // Calculate additional metrics for Anti-Aliased font support (BDF extn v2.3)
  5851. if (font && font->version==23){
  5852. fontbpp = (font->reserved & 0b000011)+1;
  5853. fontbppindex = (fontbpp >> 2)+1;
  5854. fontbppmask = (1 << (fontbppindex+1))-1;
  5855. fontppb = 8/fontbpp;
  5856. fontalphamx = 31/((1<<fontbpp)-1);
  5857. // Ensure text and bg color are different. Note: use setTextColor to set actual bg color
  5858. if (_TXTForeColor == _TXTBackColor) _TXTBackColor = (_TXTForeColor==0x0000)?0xFFFF:0x0000; }
  5859. }
  5860. // Maybe support GFX Fonts as well?
  5861. void RA8875::setFont(const GFXfont *f) {
  5862. _use_default = 0;
  5863. if(_portrait && !_use_ili_font) {
  5864. _cursorY += _cursorX;
  5865. _cursorX -= _cursorY;
  5866. }
  5867. _use_gfx_font = 1;
  5868. _use_ili_font = 0;
  5869. _use_int_font = 0;
  5870. _use_tfont = 0;
  5871. font = NULL; // turn off the other font...
  5872. _gfx_last_char_x_write = 0; // Don't use cached data here
  5873. if (f == gfxFont) return; // same font or lack of so can bail.
  5874. if(f) { // Font struct pointer passed in?
  5875. if(!gfxFont) { // And no current font struct?
  5876. // Switching from classic to new font behavior.
  5877. // Move cursor pos down 6 pixels so it's on baseline.
  5878. _cursorY += 6;
  5879. }
  5880. // Test wondering high and low of Ys here...
  5881. int8_t miny_offset = 0;
  5882. #if 1
  5883. for (uint8_t i=0; i <= (f->last - f->first); i++) {
  5884. if (f->glyph[i].yOffset < miny_offset) {
  5885. miny_offset = f->glyph[i].yOffset;
  5886. }
  5887. }
  5888. #else
  5889. int max_delta = 0;
  5890. uint8_t index_min = 0;
  5891. uint8_t index_max = 0;
  5892. int8_t minx_offset = 127;
  5893. int8_t maxx_overlap = 0;
  5894. uint8_t indexx_min = 0;
  5895. uint8_t indexx_max = 0;
  5896. for (uint8_t i=0; i <= (f->last - f->first); i++) {
  5897. if (f->glyph[i].yOffset < miny_offset) {
  5898. miny_offset = f->glyph[i].yOffset;
  5899. index_min = i;
  5900. }
  5901. if (f->glyph[i].xOffset < minx_offset) {
  5902. minx_offset = f->glyph[i].xOffset;
  5903. indexx_min = i;
  5904. }
  5905. if ( (f->glyph[i].yOffset + f->glyph[i].height) > max_delta) {
  5906. max_delta = (f->glyph[i].yOffset + f->glyph[i].height);
  5907. index_max = i;
  5908. }
  5909. int8_t x_overlap = f->glyph[i].xOffset + f->glyph[i].width - f->glyph[i].xAdvance;
  5910. if (x_overlap > maxx_overlap) {
  5911. maxx_overlap = x_overlap;
  5912. indexx_max = i;
  5913. }
  5914. }
  5915. Serial.printf("Set GFX Font(%x): Y: %d %d(%c) %d(%c) X: %d(%c) %d(%c)\n", (uint32_t)f, f->yAdvance,
  5916. miny_offset, index_min + f->first, max_delta, index_max + f->first,
  5917. minx_offset, indexx_min + f->first, maxx_overlap, indexx_max + f->first);
  5918. #endif
  5919. _gfxFont_min_yOffset = miny_offset; // Probably only thing we need... May cache?
  5920. } else if(gfxFont) { // NULL passed. Current font struct defined?
  5921. // Switching from new to classic font behavior.
  5922. // Move cursor pos up 6 pixels so it's at top-left of char.
  5923. _cursorY -= 6;
  5924. }
  5925. gfxFont = f;
  5926. }
  5927. void RA8875::drawFontChar(unsigned int c)
  5928. {
  5929. uint32_t bitoffset = 0;
  5930. const uint8_t *data;
  5931. //Serial.printf("drawFontChar(%c) %d (%d, %d) %x %x %x\n", c, c, _cursorX, _cursorY, _TXTBackColor, _TXTForeColor, _backTransparent);
  5932. if (c >= font->index1_first && c <= font->index1_last) {
  5933. bitoffset = c - font->index1_first;
  5934. bitoffset *= font->bits_index;
  5935. } else if (c >= font->index2_first && c <= font->index2_last) {
  5936. bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
  5937. bitoffset *= font->bits_index;
  5938. }
  5939. // TODO: implement sparse unicode
  5940. //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
  5941. data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
  5942. uint32_t encoding = fetchbits_unsigned(data, 0, 3);
  5943. if (encoding != 0) return;
  5944. uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
  5945. bitoffset = font->bits_width + 3;
  5946. uint32_t height = fetchbits_unsigned(data, bitoffset, font->bits_height);
  5947. bitoffset += font->bits_height;
  5948. //Serial.printf(" size = %d,%d\n", width, height);
  5949. //Serial.printf(" line space = %d\n", font->line_space);
  5950. //Serial.printf(" cap height = %d\n", font->cap_height);
  5951. int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
  5952. bitoffset += font->bits_xoffset;
  5953. int32_t yoffset = fetchbits_signed(data, bitoffset, font->bits_yoffset);
  5954. bitoffset += font->bits_yoffset;
  5955. //Serial.printf(" offset = %d,%d\n", xoffset, yoffset);
  5956. uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
  5957. bitoffset += font->bits_delta;
  5958. //Serial.printf(" delta = %d\n", delta);
  5959. //horizontally, we draw every pixel, or none at all
  5960. if (_cursorX < 0) _cursorX = 0;
  5961. int32_t origin_x = _cursorX + xoffset;
  5962. if (origin_x < 0) {
  5963. _cursorX -= xoffset;
  5964. origin_x = 0;
  5965. }
  5966. if (origin_x + (int)width > _width) {
  5967. if (!wrap) return;
  5968. origin_x = 0;
  5969. if (xoffset >= 0) {
  5970. _cursorX = 0;
  5971. } else {
  5972. _cursorX = -xoffset;
  5973. }
  5974. _cursorY += font->line_space;
  5975. }
  5976. if (_cursorY >= _height) return;
  5977. // vertically, the top and/or bottom can be clipped
  5978. int32_t origin_y = _cursorY + font->cap_height - height - yoffset;
  5979. // TODO: compute top skip and number of lines
  5980. int32_t linecount = height;
  5981. //uint32_t loopcount = 0;
  5982. int32_t y = origin_y;
  5983. bool opaque = !_backTransparent; //(_TXTBackColor != _TXTForeColor);
  5984. // Going to try a fast Opaque method which works similar to drawChar, which is near the speed of writerect
  5985. if (!opaque) {
  5986. // Anti-alias support
  5987. if (fontbpp>1){
  5988. // This branch should, in most cases, never happen. This is because if an
  5989. // anti-aliased font is being used, textcolor and textbgcolor should always
  5990. // be different. Even though an anti-alised font is being used, pixels in this
  5991. // case will all be solid because pixels are rendered on same colour as themselves!
  5992. // This won't look very good.
  5993. bitoffset = ((bitoffset + 7) & (-8)); // byte-boundary
  5994. uint32_t xp = 0;
  5995. uint8_t halfalpha = 1<<(fontbpp-1);
  5996. while (linecount) {
  5997. uint32_t x = 0;
  5998. while(x<width) {
  5999. // One pixel at a time, either on (if alpha > 0.5) or off
  6000. if (fetchpixel(data, bitoffset, xp)>=halfalpha){
  6001. Pixel(origin_x + x,y, _TXTForeColor);
  6002. }
  6003. bitoffset += fontbpp;
  6004. x++;
  6005. xp++;
  6006. }
  6007. y++;
  6008. linecount--;
  6009. }
  6010. }
  6011. // Soild pixels
  6012. else {
  6013. while (linecount > 0) {
  6014. //Serial.printf(" linecount = %d\n", linecount);
  6015. uint32_t n = 1;
  6016. if (fetchbit(data, bitoffset++) != 0) {
  6017. n = fetchbits_unsigned(data, bitoffset, 3) + 2;
  6018. bitoffset += 3;
  6019. }
  6020. uint32_t x = 0;
  6021. do {
  6022. int32_t xsize = width - x;
  6023. if (xsize > 32) xsize = 32;
  6024. uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
  6025. //Serial.printf(" multi line %d %d %x\n", n, x, bits);
  6026. drawFontBits(opaque, bits, xsize, origin_x + x, y, n);
  6027. bitoffset += xsize;
  6028. x += xsize;
  6029. } while (x < width);
  6030. y += n;
  6031. linecount -= n;
  6032. //if (++loopcount > 100) {
  6033. //Serial.println(" abort draw loop");
  6034. //break;
  6035. //}
  6036. }
  6037. }
  6038. } else { //Opaque
  6039. if (fontbpp>1){
  6040. // Now opaque mode...
  6041. // Now write out background color for the number of rows above the above the character
  6042. // figure out bounding rectangle...
  6043. // In this mode we need to update to use the offset and bounding rectangles as we are doing it it direct.
  6044. // also update the Origin
  6045. int cursor_x_origin = _cursorX + _originx;
  6046. int cursor_y_origin = _cursorY + _originy;
  6047. _cursorX += _originx;
  6048. _cursorY += _originy;
  6049. int start_x = (origin_x < cursor_x_origin) ? origin_x : cursor_x_origin;
  6050. if (start_x < 0) start_x = 0;
  6051. int start_y = (origin_y < cursor_y_origin) ? origin_y : cursor_y_origin;
  6052. if (start_y < 0) start_y = 0;
  6053. int end_x = cursor_x_origin + delta;
  6054. if ((origin_x + (int)width) > end_x)
  6055. end_x = origin_x + (int)width;
  6056. if (end_x >= _displayclipx2) end_x = _displayclipx2;
  6057. int end_y = cursor_y_origin + font->line_space;
  6058. if ((origin_y + (int)height) > end_y)
  6059. end_y = origin_y + (int)height;
  6060. if (end_y >= _displayclipy2) end_y = _displayclipy2;
  6061. end_x--; // setup to last one we draw
  6062. end_y--;
  6063. int start_x_min = (start_x >= _displayclipx1) ? start_x : _displayclipx1;
  6064. int start_y_min = (start_y >= _displayclipy1) ? start_y : _displayclipy1;
  6065. // See if anything is in the display area.
  6066. if((end_x < _displayclipx1) ||(start_x >= _displayclipx2) || (end_y < _displayclipy1) || (start_y >= _displayclipy2)) {
  6067. _cursorX += delta; // could use goto or another indent level...
  6068. return;
  6069. }
  6070. /*
  6071. Serial.printf("drawFontChar(%c) %d\n", c, c);
  6072. Serial.printf(" size = %d,%d\n", width, height);
  6073. Serial.printf(" line space = %d\n", font->line_space);
  6074. Serial.printf(" offset = %d,%d\n", xoffset, yoffset);
  6075. Serial.printf(" delta = %d\n", delta);
  6076. Serial.printf(" cursor = %d,%d\n", _cursorX, _cursorY);
  6077. Serial.printf(" origin = %d,%d\n", origin_x, origin_y);
  6078. Serial.printf(" Bounding: (%d, %d)-(%d, %d)\n", start_x, start_y, end_x, end_y);
  6079. Serial.printf(" mins (%d %d),\n", start_x_min, start_y_min);
  6080. */
  6081. //}
  6082. // Anti-aliased font
  6083. //Serial.printf("SetAddr %d %d %d %d\n", start_x_min, start_y_min, end_x, end_y);
  6084. // output rectangle we are updating... We have already clipped end_x/y, but not yet start_x/y
  6085. setActiveWindow( start_x, start_y_min, end_x, end_y);
  6086. int screen_y = start_y_min;
  6087. int screen_x;
  6088. // Clear above character
  6089. while (screen_y < origin_y) {
  6090. for (screen_x = start_x_min; screen_x <= end_x; screen_x++) {
  6091. drawPixel(screen_x, screen_y, _TXTBackColor);
  6092. }
  6093. screen_y++;
  6094. }
  6095. screen_y = origin_y;
  6096. bitoffset = ((bitoffset + 7) & (-8)); // byte-boundary
  6097. int glyphend_x = origin_x + width;
  6098. uint32_t xp = 0;
  6099. while (linecount) {
  6100. screen_x = start_x;
  6101. while(screen_x<=end_x) {
  6102. // XXX: I'm sure clipping could be done way more efficiently than just chekcing every single pixel, but let's just get this going
  6103. if ((screen_x >= _displayclipx1) && (screen_x < _displayclipx2) && (screen_y >= _displayclipy1) && (screen_y < _displayclipy2)) {
  6104. // Clear before or after pixel
  6105. if ((screen_x<origin_x) || (screen_x>=glyphend_x)){
  6106. drawPixel(screen_x, screen_y, _TXTBackColor);
  6107. }
  6108. // Draw alpha-blended character
  6109. else{
  6110. uint8_t alpha = fetchpixel(data, bitoffset, xp);
  6111. drawPixel(screen_x, screen_y, alphaBlendRGB565Premultiplied( textcolorPrexpanded, textbgcolorPrexpanded, (uint8_t)(alpha * fontalphamx) ) );
  6112. bitoffset += fontbpp;
  6113. xp++;
  6114. }
  6115. } // clip
  6116. screen_x++;
  6117. }
  6118. screen_y++;
  6119. linecount--;
  6120. }
  6121. // clear below character
  6122. setActiveWindow(); //have to do this otherwise it gets clipped
  6123. fillRect(_cursorX, screen_y, delta, _cursorY + font->line_space - screen_y, _TXTBackColor);
  6124. } // anti-aliased
  6125. // 1bpp
  6126. else {
  6127. // Now opaque mode...
  6128. // Now write out background color for the number of rows above the above the character
  6129. // figure out bounding rectangle...
  6130. // In this mode we need to update to use the offset and bounding rectangles as we are doing it it direct.
  6131. // also update the Origin
  6132. fillRect(_cursorX, _cursorY, delta, y - _cursorY, _TXTBackColor);
  6133. while (linecount > 0) {
  6134. //Serial.printf(" linecount = %d\n", linecount);
  6135. uint32_t n = 1;
  6136. if (fetchbit(data, bitoffset++) != 0) {
  6137. n = fetchbits_unsigned(data, bitoffset, 3) + 2;
  6138. bitoffset += 3;
  6139. }
  6140. uint32_t x = 0;
  6141. fillRect(_cursorX, y, origin_x - _cursorX, n, _TXTBackColor);
  6142. do {
  6143. int32_t xsize = width - x;
  6144. if (xsize > 32) xsize = 32;
  6145. uint32_t bits = fetchbits_unsigned(data, bitoffset, xsize);
  6146. //Serial.printf(" multi line %d %d %x\n", n, x, bits);
  6147. drawFontBits(opaque, bits, xsize, origin_x + x, y, n);
  6148. bitoffset += xsize;
  6149. x += xsize;
  6150. } while (x < width);
  6151. if ((width+xoffset) < delta) {
  6152. fillRect(origin_x + x, y, delta - (width+xoffset), n, _TXTBackColor);
  6153. }
  6154. y += n;
  6155. linecount -= n;
  6156. //if (++loopcount > 100) {
  6157. //Serial.println(" abort draw loop");
  6158. //break;
  6159. //}
  6160. }
  6161. fillRect(_cursorX, y, delta, _cursorY + font->line_space - y, _TXTBackColor);
  6162. }
  6163. }
  6164. // Increment to setup for the next character.
  6165. _cursorX += delta;
  6166. }
  6167. //strPixelLen - gets pixel length of given ASCII string
  6168. int16_t RA8875::strPixelLen(const char * str)
  6169. {
  6170. // Serial.printf("strPixelLen %s\n", str);
  6171. if (!str) return(0);
  6172. if (gfxFont)
  6173. {
  6174. // BUGBUG:: just use the other function for now... May do this for all of them...
  6175. int16_t x, y;
  6176. uint16_t w, h;
  6177. getTextBounds(str, _cursorX, _cursorY, &x, &y, &w, &h);
  6178. return w;
  6179. }
  6180. uint16_t len=0, maxlen=0;
  6181. while (*str)
  6182. {
  6183. if (*str=='\n')
  6184. {
  6185. if ( len > maxlen )
  6186. {
  6187. maxlen=len;
  6188. len=0;
  6189. }
  6190. }
  6191. else
  6192. {
  6193. if (!font)
  6194. {
  6195. len+=textsize_x*6;
  6196. }
  6197. else
  6198. {
  6199. uint32_t bitoffset;
  6200. const uint8_t *data;
  6201. uint16_t c = *str;
  6202. // Serial.printf("char %c(%d)\n", c,c);
  6203. if (c >= font->index1_first && c <= font->index1_last) {
  6204. bitoffset = c - font->index1_first;
  6205. bitoffset *= font->bits_index;
  6206. } else if (c >= font->index2_first && c <= font->index2_last) {
  6207. bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
  6208. bitoffset *= font->bits_index;
  6209. } else if (font->unicode) {
  6210. continue;
  6211. } else {
  6212. continue;
  6213. }
  6214. //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
  6215. data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
  6216. uint32_t encoding = fetchbits_unsigned(data, 0, 3);
  6217. if (encoding != 0) continue;
  6218. // uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
  6219. // Serial.printf(" width = %d\n", width);
  6220. bitoffset = font->bits_width + 3;
  6221. bitoffset += font->bits_height;
  6222. // int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
  6223. // Serial.printf(" xoffset = %d\n", xoffset);
  6224. bitoffset += font->bits_xoffset;
  6225. bitoffset += font->bits_yoffset;
  6226. uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
  6227. bitoffset += font->bits_delta;
  6228. // Serial.printf(" delta = %d\n", delta);
  6229. len += delta;//+width-xoffset;
  6230. // Serial.printf(" len = %d\n", len);
  6231. if ( len > maxlen )
  6232. {
  6233. maxlen=len;
  6234. // Serial.printf(" maxlen = %d\n", maxlen);
  6235. }
  6236. }
  6237. }
  6238. str++;
  6239. }
  6240. // Serial.printf("Return maxlen = %d\n", maxlen);
  6241. return( maxlen );
  6242. }
  6243. void RA8875::charBounds(char c, int16_t *x, int16_t *y,
  6244. int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) {
  6245. uint8_t offset=0, _x, _y;
  6246. int charW = 0;
  6247. // BUGBUG:: Not handling offset/clip
  6248. if (font) {
  6249. if(c == '\n') { // Newline?
  6250. *x = 0; // Reset x to zero, advance y by one line
  6251. *y += font->line_space;
  6252. } else if(c != '\r') { // Not a carriage return; is normal char
  6253. uint32_t bitoffset;
  6254. const uint8_t *data;
  6255. if (c >= font->index1_first && c <= font->index1_last) {
  6256. bitoffset = c - font->index1_first;
  6257. bitoffset *= font->bits_index;
  6258. } else if (c >= font->index2_first && c <= font->index2_last) {
  6259. bitoffset = c - font->index2_first + font->index1_last - font->index1_first + 1;
  6260. bitoffset *= font->bits_index;
  6261. } else if (font->unicode) {
  6262. return; // TODO: implement sparse unicode
  6263. } else {
  6264. return;
  6265. }
  6266. //Serial.printf(" index = %d\n", fetchbits_unsigned(font->index, bitoffset, font->bits_index));
  6267. data = font->data + fetchbits_unsigned(font->index, bitoffset, font->bits_index);
  6268. uint32_t encoding = fetchbits_unsigned(data, 0, 3);
  6269. if (encoding != 0) return;
  6270. uint32_t width = fetchbits_unsigned(data, 3, font->bits_width);
  6271. bitoffset = font->bits_width + 3;
  6272. uint32_t height = fetchbits_unsigned(data, bitoffset, font->bits_height);
  6273. bitoffset += font->bits_height;
  6274. //Serial.printf(" size = %d,%d\n", width, height);
  6275. //Serial.printf(" line space = %d\n", font->line_space);
  6276. int32_t xoffset = fetchbits_signed(data, bitoffset, font->bits_xoffset);
  6277. bitoffset += font->bits_xoffset;
  6278. int32_t yoffset = fetchbits_signed(data, bitoffset, font->bits_yoffset);
  6279. bitoffset += font->bits_yoffset;
  6280. uint32_t delta = fetchbits_unsigned(data, bitoffset, font->bits_delta);
  6281. bitoffset += font->bits_delta;
  6282. int16_t
  6283. x1 = *x + xoffset,
  6284. y1 = *y + yoffset,
  6285. x2 = x1 + width,
  6286. y2 = y1 + height;
  6287. if(wrap && (x2 > _width)) {
  6288. *x = 0; // Reset x to zero, advance y by one line
  6289. *y += font->line_space;
  6290. x1 = *x + xoffset,
  6291. y1 = *y + yoffset,
  6292. x2 = x1 + width,
  6293. y2 = y1 + height;
  6294. }
  6295. if(x1 < *minx) *minx = x1;
  6296. if(y1 < *miny) *miny = y1;
  6297. if(x2 > *maxx) *maxx = x2;
  6298. if(y2 > *maxy) *maxy = y2;
  6299. *x += delta; // ? guessing here...
  6300. }
  6301. }
  6302. else if(gfxFont) {
  6303. if(c == '\n') { // Newline?
  6304. *x = 0; // Reset x to zero, advance y by one line
  6305. *y += textsize_y * gfxFont->yAdvance;
  6306. } else if(c != '\r') { // Not a carriage return; is normal char
  6307. uint8_t first = gfxFont->first,
  6308. last = gfxFont->last;
  6309. if((c >= first) && (c <= last)) { // Char present in this font?
  6310. GFXglyph *glyph = gfxFont->glyph + (c - first);
  6311. uint8_t gw = glyph->width,
  6312. gh = glyph->height,
  6313. xa = glyph->xAdvance;
  6314. int8_t xo = glyph->xOffset,
  6315. yo = glyph->yOffset + gfxFont->yAdvance/2;
  6316. if(wrap && ((*x+(((int16_t)xo+gw)*textsize_x)) > _width)) {
  6317. *x = 0; // Reset x to zero, advance y by one line
  6318. *y += textsize_y * gfxFont->yAdvance;
  6319. }
  6320. int16_t tsx = (int16_t)textsize_x,
  6321. tsy = (int16_t)textsize_y,
  6322. x1 = *x + xo * tsx,
  6323. y1 = *y + yo * tsy,
  6324. x2 = x1 + gw * tsx - 1,
  6325. y2 = y1 + gh * tsy - 1;
  6326. if(x1 < *minx) *minx = x1;
  6327. if(y1 < *miny) *miny = y1;
  6328. if(x2 > *maxx) *maxx = x2;
  6329. if(y2 > *maxy) *maxy = y2;
  6330. *x += xa * tsx;
  6331. }
  6332. }
  6333. } else { // font test int, tfont default
  6334. if(_use_tfont == 1){
  6335. if (bitRead(_TXTparameters,0) == 1) offset = 3 * _scaleY;
  6336. _x = 0; _y = 0;
  6337. if (c == 13){//------------------------------- CARRIAGE ----------------------------------
  6338. //ignore
  6339. } else if (c == 10){//------------------------- NEW LINE ---------------------------------
  6340. _y += (_FNTheight * _scaleY) + _FNTinterline + offset;
  6341. } else if (c == 32){//--------------------------- SPACE ---------------------------------
  6342. _x += (_spaceCharWidth * _scaleX) + _FNTspacing;
  6343. }
  6344. else {//-------------------------------------- CHAR ------------------------------------
  6345. int charIndex = _getCharCode(c);//get char code
  6346. if (charIndex > -1){//valid?
  6347. charW = 0;
  6348. //get charW and glyph
  6349. #if defined(_FORCE_PROGMEM__)
  6350. #if defined(ESP8266)
  6351. charW = FPSTR(&_currentFont->chars[charIndex].image->image_width);
  6352. #if !defined(_RA8875_TXTRNDOPTIMIZER)
  6353. const uint8_t * charGlyp = FPSTR(&_currentFont->chars[charIndex].image->data);
  6354. #endif
  6355. #else
  6356. charW = PROGMEM_read(&_currentFont->chars[charIndex].image->image_width);
  6357. #if !defined(_RA8875_TXTRNDOPTIMIZER)
  6358. const uint8_t * charGlyp = PROGMEM_read(&_currentFont->chars[charIndex].image->data);
  6359. #endif
  6360. #endif
  6361. #else
  6362. charW = _currentFont->chars[charIndex].image->image_width;
  6363. #if !defined(_RA8875_TXTRNDOPTIMIZER)
  6364. const uint8_t * charGlyp = _currentFont->chars[charIndex].image->data;
  6365. #endif
  6366. #endif
  6367. }
  6368. }
  6369. *x += _x + charW * _scaleX;
  6370. *y = _y + (_FNTheight) * _scaleY;
  6371. int x2 = *x + charW * _scaleX - 1, // Lower-right pixel of char
  6372. y2 = *y + (_FNTheight+3) * _scaleY - 1;
  6373. if(x2 > *maxx) *maxx = x2; // Track max x, y
  6374. if(y2 > *maxy) *maxy = y2;
  6375. if(*x < *minx) *minx = *x; // Track min x, y
  6376. if(*y < *miny) *miny = *y;
  6377. } else if(_use_int_font == 1){
  6378. if(c == '\n') { // Newline?
  6379. *x = 0; // Reset x to zero,
  6380. *y += _FNTheight * _scaleY; // advance y one line
  6381. // min/max x/y unchaged -- that waits for next 'normal' character
  6382. } else if(c != '\r') { // Normal char; ignore carriage returns
  6383. if(wrap && ((*x + _FNTheight * _scaleY) > _width)) { // Off right?
  6384. *x = 0; // Reset x to zero,
  6385. *y += _FNTheight * _scaleY; // advance y one line
  6386. }
  6387. int x2 = *x + _FNTwidth * _scaleX - 1, // Lower-right pixel of char
  6388. y2 = *y + _FNTheight * _scaleY - 1;
  6389. if(x2 > *maxx) *maxx = x2; // Track max x, y
  6390. if(y2 > *maxy) *maxy = y2;
  6391. if(*x < *minx) *minx = *x; // Track min x, y
  6392. if(*y < *miny) *miny = *y;
  6393. *x += _FNTwidth * _scaleX ; // Advance x one char
  6394. }
  6395. } else {
  6396. if(c == '\n') { // Newline?
  6397. *x = 0; // Reset x to zero,
  6398. *y += textsize_y * 8; // advance y one line
  6399. // min/max x/y unchaged -- that waits for next 'normal' character
  6400. } else if(c != '\r') { // Normal char; ignore carriage returns
  6401. if(wrap && ((*x + textsize_x * 6) > _width)) { // Off right?
  6402. *x = 0; // Reset x to zero,
  6403. *y += textsize_y * 8; // advance y one line
  6404. }
  6405. int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char
  6406. y2 = *y + textsize_y * 8 - 1;
  6407. if(x2 > *maxx) *maxx = x2; // Track max x, y
  6408. if(y2 > *maxy) *maxy = y2;
  6409. if(*x < *minx) *minx = *x; // Track min x, y
  6410. if(*y < *miny) *miny = *y;
  6411. *x += textsize_x * 6; // Advance x one char
  6412. }
  6413. }
  6414. }
  6415. }
  6416. // Add in Adafruit versions of text bounds calculations.
  6417. void RA8875::getTextBounds(const uint8_t *buffer, uint16_t len, int16_t x, int16_t y,
  6418. int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
  6419. *x1 = x;
  6420. *y1 = y;
  6421. *w = *h = 0;
  6422. int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
  6423. while(len--)
  6424. charBounds(*buffer++, &x, &y, &minx, &miny, &maxx, &maxy);
  6425. if(maxx >= minx) {
  6426. *x1 = minx;
  6427. *w = maxx - minx + 1;
  6428. }
  6429. if(maxy >= miny) {
  6430. *y1 = miny;
  6431. *h = maxy - miny + 1;
  6432. }
  6433. }
  6434. void RA8875::getTextBounds(const char *str, int16_t x, int16_t y,
  6435. int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
  6436. uint8_t c; // Current character
  6437. *x1 = x;
  6438. *y1 = y;
  6439. *w = *h = 0;
  6440. int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
  6441. while((c = *str++))
  6442. charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
  6443. if(maxx >= minx) {
  6444. *x1 = minx;
  6445. *w = maxx - minx + 1;
  6446. }
  6447. if(maxy >= miny) {
  6448. *y1 = miny;
  6449. *h = maxy - miny + 1;
  6450. }
  6451. }
  6452. void RA8875::getTextBounds(const String &str, int16_t x, int16_t y,
  6453. int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
  6454. if (str.length() != 0) {
  6455. getTextBounds(const_cast<char*>(str.c_str()), x, y, x1, y1, w, h);
  6456. }
  6457. }
  6458. void RA8875::drawFontBits(bool opaque, uint32_t bits, uint32_t numbits, int32_t x, int32_t y, uint32_t repeat)
  6459. {
  6460. //Serial.printf(" drawFontBits: %d %x %x (%d %d) %u\n", opaque, bits, numbits, x, y, repeat);
  6461. if (bits == 0) {
  6462. if (opaque) {
  6463. fillRect(x, y, numbits, repeat, _TXTBackColor);
  6464. }
  6465. } else {
  6466. int32_t x1 = x;
  6467. uint32_t n = numbits;
  6468. int w;
  6469. int bgw;
  6470. w = 0;
  6471. bgw = 0;
  6472. do {
  6473. n--;
  6474. if (bits & (1 << n)) {
  6475. if (bgw>0) {
  6476. if (opaque) {
  6477. fillRect(x1 - bgw, y, bgw, repeat, _TXTBackColor);
  6478. //Serial.printf(" BG fillrect: %d %d %d %d %x\n", x1 - bgw, y, bgw, repeat, _TXTBackColor);
  6479. }
  6480. bgw=0;
  6481. }
  6482. w++;
  6483. } else {
  6484. if (w>0) {
  6485. fillRect(x1 - w, y, w, repeat, _TXTForeColor);
  6486. //Serial.printf(" FG fillrect: %d %d %d %d %x\n", x1 - w, y, w, repeat, _TXTForeColor);
  6487. w = 0;
  6488. }
  6489. bgw++;
  6490. }
  6491. x1++;
  6492. } while (n > 0);
  6493. if (w > 0) {
  6494. fillRect(x1 - w, y, w, repeat, _TXTForeColor);
  6495. //Serial.printf(" FG fillrect: %d %d %d %d %x\n", x1 - w, y, w, repeat, _TXTForeColor);
  6496. }
  6497. if (bgw > 0) {
  6498. if (opaque) {
  6499. fillRect(x1 - bgw, y, bgw, repeat, _TXTBackColor);
  6500. //Serial.printf(" BG fillrect: %d %d %d %d %x\n", x1 - bgw, y, bgw, repeat, _TXTBackColor);
  6501. }
  6502. }
  6503. }
  6504. }
  6505. void RA8875::drawGFXFontChar(unsigned int c) {
  6506. // Lets do Adafruit GFX character output here as well
  6507. if(c == '\r') return;
  6508. // Some quick and dirty tests to see if we can
  6509. uint8_t first = gfxFont->first;
  6510. if((c < first) || (c > gfxFont->last)) return;
  6511. GFXglyph *glyph = gfxFont->glyph + (c - first);
  6512. uint8_t w = glyph->width,
  6513. h = glyph->height;
  6514. //Serial.printf("w = %d, h = %d\n", w, h);
  6515. //if((w == 0) || (h == 0)) return; // Is there an associated bitmap?
  6516. int16_t xo = glyph->xOffset; // sic
  6517. int16_t yo = glyph->yOffset + gfxFont->yAdvance/2;
  6518. if(wrap && ((_cursorX + textsize_x * (xo + w)) > _width)) {
  6519. _cursorX = 0;
  6520. _cursorY += (int16_t)textsize_y * gfxFont->yAdvance;
  6521. }
  6522. // Lets do the work to output the font character
  6523. uint8_t *bitmap = gfxFont->bitmap;
  6524. uint16_t bo = glyph->bitmapOffset;
  6525. uint8_t xx, yy, bits = 0, bit = 0;
  6526. //Serial.printf("DGFX_char: %c (%d,%d) : %u %u %u %u %d %d %x %x %d\n", c, _cursorX, _cursorY, w, h,
  6527. // glyph->xAdvance, gfxFont->yAdvance, xo, yo, _TXTForeColor, _TXTBackColor, 0); Serial.flush();
  6528. if (_backTransparent) {
  6529. //Serial.printf("DGFXChar: %c %u, %u, wh:%d %d o:%d %d\n", c, _cursorX, _cursorY, w, h, xo, yo);
  6530. // Todo: Add character clipping here
  6531. // NOTE: Adafruit GFX does not support Opaque font output as there
  6532. // are issues with proportionally spaced characters that may overlap
  6533. // So the below is not perfect as we may overwrite a small portion
  6534. // of a letter with the next one, when we blank out...
  6535. // But: I prefer to let each of us decide if the limitations are
  6536. // worth it or not. If Not you still have the option to not
  6537. // Do transparent mode and instead blank out and blink...
  6538. for(yy=0; yy<h; yy++) {
  6539. uint8_t w_left = w;
  6540. xx = 0;
  6541. while (w_left) {
  6542. if(!(bit & 7)) {
  6543. bits = bitmap[bo++];
  6544. }
  6545. // Could try up to 8 bits at time, but start off trying up to 4
  6546. uint8_t xCount;
  6547. if ((w_left >= 8) && ((bits & 0xff) == 0xff)) {
  6548. xCount = 8;
  6549. //Serial.print("8");
  6550. fillRect(_cursorX+(xo+xx)*textsize_x, _cursorY+(yo+yy)*textsize_y,
  6551. xCount * textsize_x, textsize_y, _TXTForeColor);
  6552. } else if ((w_left >= 4) && ((bits & 0xf0) == 0xf0)) {
  6553. xCount = 4;
  6554. //Serial.print("4");
  6555. fillRect(_cursorX+(xo+xx)*textsize_x, _cursorY+(yo+yy)*textsize_y,
  6556. xCount * textsize_x, textsize_y, _TXTForeColor);
  6557. } else if ((w_left >= 3) && ((bits & 0xe0) == 0xe0)) {
  6558. //Serial.print("3");
  6559. xCount = 3;
  6560. fillRect(_cursorX+(xo+xx)*textsize_x, _cursorY+(yo+yy)*textsize_y,
  6561. xCount * textsize_x, textsize_y, _TXTForeColor);
  6562. } else if ((w_left >= 2) && ((bits & 0xc0) == 0xc0)) {
  6563. //Serial.print("2");
  6564. xCount = 2;
  6565. fillRect(_cursorX+(xo+xx)*textsize_x, _cursorY+(yo+yy)*textsize_y,
  6566. xCount * textsize_x, textsize_y, _TXTForeColor);
  6567. } else {
  6568. xCount = 1;
  6569. if(bits & 0x80) {
  6570. if((textsize_x == 1) && (textsize_y == 1)){
  6571. drawPixel(_cursorX+xo+xx, _cursorY+yo+yy, _TXTForeColor);
  6572. } else {
  6573. fillRect(_cursorX+(xo+xx)*textsize_x, _cursorY+(yo+yy)*textsize_y,textsize_x, textsize_y, _TXTForeColor);
  6574. }
  6575. }
  6576. }
  6577. xx += xCount;
  6578. w_left -= xCount;
  6579. bit += xCount;
  6580. bits <<= xCount;
  6581. }
  6582. }
  6583. _gfx_last_char_x_write = 0;
  6584. } else {
  6585. // To Do, properly clipping and offsetting...
  6586. // This solid background approach is about 5 time faster
  6587. // Lets calculate bounding rectangle that we will update
  6588. // We need to offset by the origin.
  6589. // We are going direct so do some offsets and clipping
  6590. int16_t x_offset_cursor = _cursorX + _originx; // This is where the offseted cursor is.
  6591. int16_t x_start = x_offset_cursor; // I am assuming no negative x offsets.
  6592. int16_t x_end = x_offset_cursor + (glyph->xAdvance * textsize_x);
  6593. if (glyph->xAdvance < (xo + w)) x_end = x_offset_cursor + ((xo + w)* textsize_x); // BUGBUG Overlflows into next char position.
  6594. int16_t x_left_fill = x_offset_cursor + xo * textsize_x;
  6595. int16_t x;
  6596. if (xo < 0) {
  6597. // Unusual character that goes back into previous character
  6598. //Serial.printf("GFX Font char XO < 0: %c %d %d %u %u %u\n", c, xo, yo, w, h, glyph->xAdvance );
  6599. x_start += xo * textsize_x;
  6600. x_left_fill = 0; // Don't need to fill anything here...
  6601. }
  6602. int16_t y_start = _cursorY + _originy + (_gfxFont_min_yOffset * textsize_y)+ gfxFont->yAdvance*textsize_y/2; // UP to most negative value.
  6603. int16_t y_end = y_start + gfxFont->yAdvance * textsize_y; // how far we will update
  6604. int16_t y = y_start;
  6605. //int8_t y_top_fill = (yo - _gfxFont_min_yOffset) * textsize_y; // both negative like -10 - -16 = 6...
  6606. int8_t y_top_fill = (yo - gfxFont->yAdvance/2 - _gfxFont_min_yOffset) * textsize_y;
  6607. // See if anything is within clip rectangle, if not bail
  6608. if((x_start >= _displayclipx2) || // Clip right
  6609. (y_start >= _displayclipy2) || // Clip bottom
  6610. (x_end < _displayclipx1) || // Clip left
  6611. (y_end < _displayclipy1)) // Clip top
  6612. {
  6613. // But remember to first update the cursor position
  6614. _cursorX += glyph->xAdvance * (int16_t)textsize_x;
  6615. return;
  6616. }
  6617. // If our y_end > _displayclipy2 set it to _displayclipy2 as to not have to test both Likewise X
  6618. if (y_end > _displayclipy2) y_end = _displayclipy2;
  6619. if (x_end > _displayclipx2) x_end = _displayclipx2;
  6620. // If we get here and
  6621. if (_gfx_last__cursorY != (_cursorY + _originy)) _gfx_last_char_x_write = 0;
  6622. // lets try to output text in one output rectangle
  6623. //Serial.printf(" SPI (%d %d) (%d %d)\n", x_start, y_start, x_end, y_end);Serial.flush();
  6624. // compute the actual region we will output given
  6625. _startSend();
  6626. //setActiveWindow((x_start >= _displayclipx1) ? x_start : _displayclipx1,
  6627. // (y_start >= _displayclipy1) ? y_start : _displayclipy1,
  6628. // x_end - 1, y_end - 1);
  6629. //writeCommand(RA8875_MRWC);
  6630. //Serial.printf("SetAddr: %u %u %u %u\n", (x_start >= _displayclipx1) ? x_start : _displayclipx1,
  6631. // (y_start >= _displayclipy1) ? y_start : _displayclipy1,
  6632. // x_end - 1, y_end - 1);
  6633. // First lets fill in the top parts above the actual rectangle...
  6634. //Serial.printf(" y_top_fill %d x_left_fill %d\n", y_top_fill, x_left_fill);
  6635. while (y_top_fill--) {
  6636. if ( (y >= _displayclipy1) && (y < _displayclipy2)) {
  6637. for (int16_t xx = x_start; xx < x_end; xx++) {
  6638. if (xx >= _displayclipx1) {
  6639. combineAndDrawPixel(xx, y, gfxFontLastCharPosFG(xx,y)? _gfx_last_char_textcolor : (xx < x_offset_cursor)? _gfx_last_char_textbgcolor : _TXTBackColor);
  6640. }
  6641. }
  6642. }
  6643. forceCombinedPixelsOut();
  6644. y++;
  6645. }
  6646. //Serial.println(" After top fill"); Serial.flush();
  6647. // Now lets output all of the pixels for each of the rows..
  6648. for(yy=0; (yy<h) && (y < _displayclipy2); yy++) {
  6649. uint16_t bo_save = bo;
  6650. uint8_t bit_save = bit;
  6651. uint8_t bits_save = bits;
  6652. for (uint8_t yts = 0; (yts < textsize_y) && (y < _displayclipy2); yts++) {
  6653. // need to repeat the stuff for each row...
  6654. bo = bo_save;
  6655. bit = bit_save;
  6656. bits = bits_save;
  6657. x = x_start;
  6658. if (y >= _displayclipy1) {
  6659. while (x < x_left_fill) {
  6660. if ( (x >= _displayclipx1) && (x < _displayclipx2)) {
  6661. // Don't need to check if we are in previous char as in this case x_left_fill is set to 0...
  6662. combineAndDrawPixel(x, y, gfxFontLastCharPosFG(x,y)? _gfx_last_char_textcolor : _TXTBackColor);
  6663. }
  6664. x++;
  6665. }
  6666. for(xx=0; xx<w; xx++) {
  6667. if(!(bit++ & 7)) {
  6668. bits = bitmap[bo++];
  6669. }
  6670. for (uint8_t xts = 0; xts < textsize_x; xts++) {
  6671. if ( (x >= _displayclipx1) && (x < _displayclipx2)) {
  6672. if (bits & 0x80)
  6673. combineAndDrawPixel(x, y, _TXTForeColor);
  6674. else
  6675. combineAndDrawPixel(x, y,gfxFontLastCharPosFG(x,y)? _gfx_last_char_textcolor : (x < x_offset_cursor)? _gfx_last_char_textbgcolor : _TXTBackColor);
  6676. }
  6677. x++; // remember our logical position...
  6678. }
  6679. bits <<= 1;
  6680. }
  6681. // Fill in any additional bg colors to right of our output
  6682. while (x < x_end) {
  6683. if (x >= _displayclipx1) {
  6684. combineAndDrawPixel(x, y, gfxFontLastCharPosFG(x,y)? _gfx_last_char_textcolor : (x < x_offset_cursor)? _gfx_last_char_textbgcolor : _TXTBackColor);
  6685. }
  6686. x++;
  6687. }
  6688. }
  6689. forceCombinedPixelsOut();
  6690. y++; // remember which row we just output
  6691. }
  6692. }
  6693. // And output any more rows below us...
  6694. //Serial.println(" Bottom fill"); Serial.flush();
  6695. while (y < y_end) {
  6696. if (y >= _displayclipy1) {
  6697. for (int16_t xx = x_start; xx < x_end; xx++) {
  6698. if (xx >= _displayclipx1) {
  6699. combineAndDrawPixel(xx ,y, gfxFontLastCharPosFG(xx,y)? _gfx_last_char_textcolor : (xx < x_offset_cursor)? _gfx_last_char_textbgcolor : _TXTBackColor);
  6700. }
  6701. }
  6702. }
  6703. forceCombinedPixelsOut();
  6704. y++;
  6705. }
  6706. //writecommand_last(ILI9488_NOP);
  6707. //_endSend();
  6708. //setActiveWindow();
  6709. _gfx_c_last = c;
  6710. _gfx_last__cursorX = _cursorX + _originx;
  6711. _gfx_last__cursorY = _cursorY + _originy;
  6712. _gfx_last_char_x_write = x_end;
  6713. _gfx_last_char_textcolor = _TXTForeColor;
  6714. _gfx_last_char_textbgcolor = _TXTBackColor;
  6715. }
  6716. _cursorX += glyph->xAdvance * (int16_t)textsize_x;
  6717. }
  6718. // Some fonts overlap characters if we detect that the previous
  6719. // character wrote out more width than they advanced in X direction
  6720. // we may want to know if the last character output a FG or BG at a position.
  6721. // Opaque font chracter overlap?
  6722. // unsigned int _gfx_c_last;
  6723. // int16_t _gfx_last__cursorX, _gfx_last__cursorY;
  6724. // int16_t _gfx_last_x_overlap = 0;
  6725. bool RA8875::gfxFontLastCharPosFG(int16_t x, int16_t y) {
  6726. GFXglyph *glyph = gfxFont->glyph + (_gfx_c_last - gfxFont->first);
  6727. uint8_t w = glyph->width,
  6728. h = glyph->height;
  6729. int16_t xo = glyph->xOffset; // sic
  6730. int16_t yo = glyph->yOffset + gfxFont->yAdvance/2;
  6731. if (x >= _gfx_last_char_x_write) return false; // we did not update here...
  6732. if (y < (_gfx_last__cursorY + (yo*textsize_y))) return false; // above
  6733. if (y >= (_gfx_last__cursorY + (yo+h)*textsize_y)) return false; // below
  6734. // Lets compute which Row this y is in the bitmap
  6735. int16_t y_bitmap = (y - ((_gfx_last__cursorY + (yo*textsize_y))) + textsize_y - 1) / textsize_y;
  6736. int16_t x_bitmap = (x - ((_gfx_last__cursorX + (xo*textsize_x))) + textsize_x - 1) / textsize_x;
  6737. uint16_t pixel_bit_offset = y_bitmap * w + x_bitmap;
  6738. return ((gfxFont->bitmap[glyph->bitmapOffset + (pixel_bit_offset >> 3)]) & (0x80 >> (pixel_bit_offset & 0x7)));
  6739. }
  6740. void RA8875::setTextSize(uint8_t s_x, uint8_t s_y) {
  6741. textsize_x = (s_x > 0) ? s_x : 1;
  6742. textsize_y = (s_y > 0) ? s_y : 1;
  6743. _gfx_last_char_x_write = 0; // Don't use cached data here
  6744. }
  6745. void RA8875::drawFontPixel( uint8_t alpha, uint32_t x, uint32_t y ){
  6746. // Adjust alpha based on the number of alpha levels supported by the font (based on bpp)
  6747. // Note: Implemented look-up table for alpha, but made absolutely no difference in speed (T3.6)
  6748. alpha = (uint8_t)(alpha * fontalphamx);
  6749. uint32_t result = ((((textcolorPrexpanded - textbgcolorPrexpanded) * alpha) >> 5) + textbgcolorPrexpanded) & 0b00000111111000001111100000011111;
  6750. Pixel(x,y,(uint16_t)((result >> 16) | result));
  6751. }
  6752. void RA8875::Pixel(int16_t x, int16_t y, uint16_t color)
  6753. {
  6754. x+=_originx;
  6755. y+=_originy;
  6756. if((x < _displayclipx1) ||(x >= _displayclipx2) || (y < _displayclipy1) || (y >= _displayclipy2)) return;
  6757. setActiveWindow(x, y, x, y);
  6758. writeCommand(RA8875_MRWC);
  6759. drawPixel(x, y, color);
  6760. }
  6761. uint32_t RA8875::fetchbit(const uint8_t *p, uint32_t index)
  6762. {
  6763. if (p[index >> 3] & (1 << (7 - (index & 7)))) return 1;
  6764. return 0;
  6765. }
  6766. uint32_t RA8875::fetchbits_unsigned(const uint8_t *p, uint32_t index, uint32_t required)
  6767. {
  6768. uint32_t val = 0;
  6769. do {
  6770. uint8_t b = p[index >> 3];
  6771. uint32_t avail = 8 - (index & 7);
  6772. if (avail <= required) {
  6773. val <<= avail;
  6774. val |= b & ((1 << avail) - 1);
  6775. index += avail;
  6776. required -= avail;
  6777. } else {
  6778. b >>= avail - required;
  6779. val <<= required;
  6780. val |= b & ((1 << required) - 1);
  6781. break;
  6782. }
  6783. } while (required);
  6784. return val;
  6785. }
  6786. uint32_t RA8875::fetchbits_signed(const uint8_t *p, uint32_t index, uint32_t required)
  6787. {
  6788. uint32_t val = fetchbits_unsigned(p, index, required);
  6789. if (val & (1 << (required - 1))) {
  6790. return (int32_t)val - (1 << required);
  6791. }
  6792. return (int32_t)val;
  6793. }
  6794. uint32_t RA8875::fetchpixel(const uint8_t *p, uint32_t index, uint32_t x)
  6795. {
  6796. // The byte
  6797. uint8_t b = p[index >> 3];
  6798. // Shift to LSB position and mask to get value
  6799. uint8_t s = ((fontppb-(x % fontppb)-1)*fontbpp);
  6800. // Mask and return
  6801. return (b >> s) & fontbppmask;
  6802. }
  6803. void RA8875::write16BitColor(uint16_t color, bool last_pixel){
  6804. writeData16(color);
  6805. }
  6806. /*
  6807. void RA8875::debugData(uint16_t data,uint8_t len)
  6808. {
  6809. int i;
  6810. for (i=len-1; i>=0; i--){
  6811. if (bitRead(data,i)==1){
  6812. Serial.print("1");
  6813. } else {
  6814. Serial.print("0");
  6815. }
  6816. }
  6817. Serial.print(" -> 0x");
  6818. Serial.print(data,HEX);
  6819. Serial.print("\n");
  6820. }
  6821. */
  6822. /*
  6823. void RA8875::showLineBuffer(uint8_t data[],int len)
  6824. {
  6825. int i;
  6826. for (i=0; i<len; i++){
  6827. if (data[i] == 1){
  6828. Serial.print("1");
  6829. } else {
  6830. Serial.print("0");
  6831. }
  6832. }
  6833. Serial.print("\n");
  6834. }
  6835. */