Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of RA8875 by
RA8875.cpp
00001 /// RA8875 Display Controller Library. 00002 /// 00003 /// This is being created for a Raio RA8875-based display from buydisplay.com, 00004 /// which is 480 x 272 using a 4-wire SPI interface. Support is provided for 00005 /// both a keypad and a resistive touch-screen. 00006 /// 00007 /// This driver has been fully tested with an 800 x 480 variant (also using 00008 /// 4-wire SPI). 00009 /// 00010 /// 20161106: Updated the initialization to set the various registers based on 00011 /// the BuyDisplay.com example code. This altered several registers 00012 /// for the 800x480 display driver. 00013 /// 00014 #include "RA8875.h" 00015 00016 //#include "Utility.h" // private memory manager 00017 #ifndef UTILITY_H 00018 #define swMalloc malloc // use the standard 00019 #define swFree free 00020 #endif 00021 00022 //#define DEBUG "RAIO" 00023 // ... 00024 // INFO("Stuff to show %d", var); // new-line is automatically appended 00025 // 00026 #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) 00027 #define INFO(x, ...) std::printf("[INF %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00028 #define WARN(x, ...) std::printf("[WRN %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00029 #define ERR(x, ...) std::printf("[ERR %s %4d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00030 static void HexDump(const char * title, const uint8_t * p, int count) 00031 { 00032 int i; 00033 char buf[100] = "0000: "; 00034 00035 if (*title) 00036 INFO("%s", title); 00037 for (i=0; i<count; ) { 00038 sprintf(buf + strlen(buf), "%02X ", *(p+i)); 00039 if ((++i & 0x0F) == 0x00) { 00040 INFO("%s", buf); 00041 if (i < count) 00042 sprintf(buf, "%04X: ", i); 00043 else 00044 buf[0] = '\0'; 00045 } 00046 } 00047 if (strlen(buf)) 00048 INFO("%s", buf); 00049 } 00050 #else 00051 #define INFO(x, ...) 00052 #define WARN(x, ...) 00053 #define ERR(x, ...) 00054 #define HexDump(a, b, c) 00055 #endif 00056 00057 // Defaults. Users can override this with the init() method. 00058 #define RA8875_DISPLAY_WIDTH 480 00059 #define RA8875_DISPLAY_HEIGHT 272 00060 #define RA8875_COLORDEPTH_BPP 16 /* Not an API */ 00061 00062 #ifdef PERF_METRICS 00063 #define PERFORMANCE_RESET performance.reset() 00064 #define REGISTERPERFORMANCE(a) RegisterPerformance(a) 00065 #define COUNTIDLETIME(a) CountIdleTime(a) 00066 static const char *metricsName[] = { 00067 "Cls", "Pixel", "Pixel Stream", "Boolean Stream", 00068 "Read Pixel", "Read Pixel Stream", 00069 "Line", 00070 "Rectangle", "Rounded Rectangle", 00071 "Triangle", "Circle", "Ellipse" 00072 }; 00073 uint16_t commandsUsed[256]; // track which commands are used with simple counter of number of hits. 00074 #else 00075 #define PERFORMANCE_RESET 00076 #define REGISTERPERFORMANCE(a) 00077 #define COUNTIDLETIME(a) 00078 #endif 00079 00080 // When it is going to poll a register for completion, how many 00081 // uSec should it wait between each polling activity. 00082 #define POLLWAITuSec 10 00083 00084 // Private RawKeyMap for the Keyboard interface 00085 static const uint8_t DefaultKeyMap[22] = { 00086 0, 00087 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 00088 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 00089 255 00090 }; 00091 00092 static const char * ErrMessages[] = { 00093 "noerror", ///< no errors, command completed successfully 00094 "bad parameter", ///< one or more parameters are invalid 00095 "file not found", ///< specified file could not be found 00096 "not bmp format", ///< file is not a .bmp file 00097 "not ico format", ///< file is not a .ico file 00098 "not supported format", ///< file format is not yet supported 00099 "image too big", ///< image is too large for the screen 00100 "not enough ram", ///< could not allocate ram for scanline 00101 "touch cal. timeout", ///< calibration could not complete in time 00102 "external abort", ///< during an idle callback, the user code initiated an abort 00103 }; 00104 00105 RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 00106 const char *name) 00107 : GraphicsDisplay(name) 00108 , spi(mosi, miso, sclk) 00109 , cs(csel) 00110 , res(reset) 00111 { 00112 useTouchPanel = TP_NONE; 00113 m_irq = NULL; 00114 m_i2c = NULL; 00115 c_callback = NULL; 00116 obj_callback = NULL; 00117 method_callback = NULL; 00118 idle_callback = NULL; 00119 } 00120 00121 00122 RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 00123 PinName sda, PinName scl, PinName irq, const char * name) 00124 : GraphicsDisplay(name) 00125 , spi(mosi, miso, sclk) 00126 , cs(csel) 00127 , res(reset) 00128 { 00129 useTouchPanel = TP_CAP; 00130 m_irq = new InterruptIn(irq); 00131 m_i2c = new I2C(sda, scl); 00132 c_callback = NULL; 00133 obj_callback = NULL; 00134 method_callback = NULL; 00135 idle_callback = NULL; 00136 00137 // Cap touch panel config 00138 m_addr = (FT5206_I2C_ADDRESS << 1); 00139 m_i2c->frequency(FT5206_I2C_FREQUENCY); 00140 00141 // Interrupt 00142 m_irq->mode(PullUp); 00143 m_irq->enable_irq(); 00144 m_irq->fall(callback(this, &RA8875::TouchPanelISR)); 00145 TouchPanelInit(); 00146 } 00147 00148 00149 //RA8875::~RA8875() 00150 //{ 00151 //} 00152 00153 RetCode_t RA8875::init(int width, int height, int color_bpp, uint8_t poweron, bool keypadon, bool touchscreenon) 00154 { 00155 font = NULL; // no external font, use internal. 00156 pKeyMap = DefaultKeyMap; // set default key map 00157 _select(false); // deselect the display 00158 frequency(RA8875_DEFAULT_SPI_FREQ); // data rate 00159 Reset(); 00160 // Set PLL based on display size from buy-display.com sample code 00161 if (width == 800) { 00162 WriteCommand(0x88, 0x0C); // PLLC1 - Phase Lock Loop registers 00163 } else { 00164 WriteCommand(0x88, 0x0B); // PLLC1 - Phase Lock Loop registers 00165 } 00166 wait_ms(1); 00167 WriteCommand(0x89, 0x02); 00168 wait_ms(1); 00169 00170 // System Config Register (SYSR) 00171 screenbpp = color_bpp; 00172 if (color_bpp == 16) { 00173 WriteCommand(0x10, 0x0C); // 16-bpp (65K colors) color depth, 8-bit interface 00174 } else { // color_bpp == 8 00175 WriteCommand(0x10, 0x00); // 8-bpp (256 colors) 00176 } 00177 00178 // Set Pixel Clock Setting Register (PCSR) based on display size from buy-display.com sample code 00179 if (width == 800) { 00180 WriteCommand(0x04, 0x81); // PDAT on PCLK falling edge, PCLK = 4 x System Clock 00181 wait_ms(1); 00182 00183 // Horizontal Settings 00184 screenwidth = width; 00185 WriteCommand(0x14, width/8 - 1); //HDWR//Horizontal Display Width Setting Bit[6:0] 00186 WriteCommand(0x15, 0x00); //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0] 00187 WriteCommand(0x16, 0x03); //HNDR//Horizontal Non-Display Period Bit[4:0] 00188 WriteCommand(0x17, 0x03); //HSTR//HSYNC Start Position[4:0] 00189 WriteCommand(0x18, 0x0B); //HPWR//HSYNC Polarity ,The period width of HSYNC. 00190 00191 // Vertical Settings 00192 screenheight = height; 00193 WriteCommand(0x19, (height-1)&0xFF); //VDHR0 //Vertical Display Height Bit [7:0] 00194 WriteCommand(0x1a, (height-1)>>8); //VDHR1 //Vertical Display Height Bit [8] 00195 WriteCommand(0x1b, 0x20); //VNDR0 //Vertical Non-Display Period Bit [7:0] 00196 WriteCommand(0x1c, 0x00); //VNDR1 //Vertical Non-Display Period Bit [8] 00197 WriteCommand(0x1d, 0x16); //VSTR0 //VSYNC Start Position[7:0] 00198 WriteCommand(0x1e, 0x00); //VSTR1 //VSYNC Start Position[8] 00199 WriteCommand(0x1f, 0x01); //VPWR //VSYNC Polarity ,VSYNC Pulse Width[6:0] 00200 } else { 00201 WriteCommand(0x04, 0x82); // PDAT on PCLK falling edge, PCLK = 4 x System Clock 00202 wait_ms(1); 00203 00204 // Horizontal Settings 00205 screenwidth = width; 00206 WriteCommand(0x14, width/8 - 1); //HDWR//Horizontal Display Width Setting Bit[6:0] 00207 WriteCommand(0x15, 0x02); //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0] 00208 WriteCommand(0x16, 0x03); //HNDR//Horizontal Non-Display Period Bit[4:0] 00209 WriteCommand(0x17, 0x01); //HSTR//HSYNC Start Position[4:0] 00210 WriteCommand(0x18, 0x03); //HPWR//HSYNC Polarity ,The period width of HSYNC. 00211 00212 // Vertical Settings 00213 screenheight = height; 00214 WriteCommand(0x19, (height-1)&0xFF); //VDHR0 //Vertical Display Height Bit [7:0] 00215 WriteCommand(0x1a, (height-1)>>8); //VDHR1 //Vertical Display Height Bit [8] 00216 WriteCommand(0x1b, 0x0F); //VNDR0 //Vertical Non-Display Period Bit [7:0] 00217 WriteCommand(0x1c, 0x00); //VNDR1 //Vertical Non-Display Period Bit [8] 00218 WriteCommand(0x1d, 0x0e); //VSTR0 //VSYNC Start Position[7:0] 00219 WriteCommand(0x1e, 0x06); //VSTR1 //VSYNC Start Position[8] 00220 WriteCommand(0x1f, 0x01); //VPWR //VSYNC Polarity ,VSYNC Pulse Width[6:0] 00221 } 00222 00223 portraitmode = false; 00224 00225 if (width >= 800 && height >= 480 && color_bpp > 8) { 00226 WriteCommand(0x20, 0x00); // DPCR - 1-layer mode when the resolution is too high 00227 } else { 00228 WriteCommand(0x20, 0x80); // DPCR - 2-layer mode 00229 } 00230 00231 // Set display image to Blue on Black as default 00232 window(0,0, width, height); // Initialize to full screen 00233 SetTextCursorControl(); 00234 foreground(Blue); 00235 background(Black); 00236 cls(3); 00237 00238 Power(poweron); 00239 Backlight_u8(poweron); 00240 if (keypadon) 00241 KeypadInit(); 00242 if (touchscreenon) { 00243 if (useTouchPanel == TP_NONE) 00244 useTouchPanel = TP_RES; 00245 TouchPanelInit(); 00246 } 00247 #ifdef PERF_METRICS 00248 performance.start(); 00249 ClearPerformance(); 00250 #endif 00251 return noerror; 00252 } 00253 00254 00255 RetCode_t RA8875::Reset(void) 00256 { 00257 RetCode_t ret; 00258 00259 #if 0 00260 if (res != (PinName)NC) { 00261 res = 0; // Active low - assert reset 00262 wait_ms(2); // must be > 1024 clock periods. (@25 MHz, this is 40.96 usec) 00263 res = 1; // de-assert reset 00264 } 00265 #endif 00266 ret = WriteCommand(0x01, 0x01); // Apply Display Off, Reset 00267 wait_ms(2); // no idea if I need to wait, or how long 00268 if (ret == noerror) { 00269 ret = WriteCommand(0x01, 0x00); // Display off, Remove reset 00270 wait_ms(2); // no idea if I need to wait, or how long 00271 } 00272 return ret; 00273 } 00274 00275 00276 const char * RA8875::GetErrorMessage(RetCode_t code) 00277 { 00278 if (code >= LastErrCode) 00279 code = bad_parameter; 00280 return ErrMessages[code]; 00281 } 00282 00283 00284 uint16_t RA8875::GetDrawingLayer(void) 00285 { 00286 return (ReadCommand(0x41) & 0x01); 00287 } 00288 00289 00290 RetCode_t RA8875::SelectDrawingLayer(uint16_t layer, uint16_t * prevLayer) 00291 { 00292 unsigned char mwcr1 = ReadCommand(0x41); // retain all but the currently selected layer 00293 00294 if (prevLayer) 00295 *prevLayer = mwcr1 & 1; 00296 00297 mwcr1 &= ~0x01; // remove the current layer 00298 if (screenwidth >= 800 && screenheight >= 480 && screenbpp > 8) { 00299 layer = 0; 00300 } else if (layer > 1) { 00301 layer = 0; 00302 } 00303 return WriteCommand(0x41, mwcr1 | layer); 00304 } 00305 00306 00307 RA8875::LayerMode_T RA8875::GetLayerMode(void) 00308 { 00309 return (LayerMode_T)(ReadCommand(0x52) & 0x7); 00310 } 00311 00312 00313 RetCode_t RA8875::SetLayerMode(LayerMode_T mode) 00314 { 00315 unsigned char ltpr0 = ReadCommand(0x52) & ~0x7; // retain all but the display layer mode 00316 00317 if (mode <= (LayerMode_T)6) { 00318 WriteCommand(0x52, ltpr0 | (mode & 0x7)); 00319 return noerror; 00320 } else { 00321 return bad_parameter; 00322 } 00323 } 00324 00325 00326 RetCode_t RA8875::SetLayerTransparency(uint8_t layer1, uint8_t layer2) 00327 { 00328 if (layer1 > 8) 00329 layer1 = 8; 00330 if (layer2 > 8) 00331 layer2 = 8; 00332 WriteCommand(0x53, ((layer2 & 0xF) << 4) | (layer1 & 0xF)); 00333 return noerror; 00334 } 00335 00336 00337 RetCode_t RA8875::SetBackgroundTransparencyColor(color_t color) 00338 { 00339 return _writeColorTrio(0x67, color); 00340 } 00341 00342 00343 color_t RA8875::GetBackgroundTransparencyColor(void) 00344 { 00345 RGBQUAD q; 00346 00347 q.rgbRed = ReadCommand(0x67); 00348 q.rgbGreen = ReadCommand(0x68); 00349 q.rgbBlue = ReadCommand(0x69); 00350 return RGBQuadToRGB16(&q, 0); 00351 } 00352 00353 00354 RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency, 00355 uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable) 00356 { 00357 uint8_t value = 0; 00358 00359 if (sampleTime > 3 || scanFrequency > 7 || longTimeAdjustment > 3) 00360 return bad_parameter; 00361 value |= (scanEnable) ? 0x80 : 0x00; 00362 value |= (longDetect) ? 0x40 : 0x00; 00363 value |= (sampleTime & 0x03) << 4; 00364 value |= (scanFrequency & 0x07); 00365 WriteCommand(0xC0, value); // KSCR1 - Enable Key Scan (and ignore possibility of an error) 00366 00367 value = 0; 00368 value |= (wakeupEnable) ? 0x80 : 0x00; 00369 value |= (longTimeAdjustment & 0x03) << 2; 00370 WriteCommand(0xC1, value); // KSCR2 - (and ignore possibility of an error) 00371 00372 value = ReadCommand(0xF0); // (and ignore possibility of an error) 00373 value &= ~0x10; 00374 value |= (interruptEnable) ? 0x10 : 0x00; 00375 return WriteCommand(0xF0, value); // INT 00376 } 00377 00378 00379 RetCode_t RA8875::SetKeyMap(const uint8_t * CodeList) 00380 { 00381 pKeyMap = CodeList; 00382 return noerror; 00383 } 00384 00385 00386 bool RA8875::readable(void) 00387 { 00388 return (ReadCommand(0xF1) & 0x10); // check KS status - true if kbhit 00389 } 00390 00391 00392 uint8_t RA8875::getc(void) 00393 { 00394 //#define GETC_DEV // for development 00395 #ifdef GETC_DEV 00396 uint8_t keyCode1, keyCode2; 00397 #endif 00398 uint8_t keyCode3; 00399 static uint8_t count = 0; 00400 uint8_t col, row; 00401 uint8_t key; 00402 00403 while (!readable()) { 00404 wait_us(POLLWAITuSec); 00405 // COUNTIDLETIME(POLLWAITuSec); // As it is voluntary to call the getc and pend. Don't tally it. 00406 if (idle_callback) { 00407 if (external_abort == (*idle_callback)(getc_wait)) { 00408 return 0; 00409 } 00410 } 00411 } 00412 // read the key press number 00413 uint8_t keyNumReg = ReadCommand(0xC1) & 0x03; 00414 count++; 00415 switch (keyNumReg) { 00416 case 0x01: // one key 00417 keyCode3 = ReadCommand(0xC2); 00418 #ifdef GETC_DEV 00419 keyCode2 = 0; 00420 keyCode1 = 0; 00421 #endif 00422 break; 00423 case 0x02: // two keys 00424 keyCode3 = ReadCommand(0xC3); 00425 #ifdef GETC_DEV 00426 keyCode2 = ReadCommand(0xC2); 00427 keyCode1 = 0; 00428 #endif 00429 break; 00430 case 0x03: // three keys 00431 keyCode3 = ReadCommand(0xC4); 00432 #ifdef GETC_DEV 00433 keyCode2 = ReadCommand(0xC3); 00434 keyCode1 = ReadCommand(0xC2); 00435 #endif 00436 break; 00437 default: // no keys (key released) 00438 keyCode3 = 0xFF; 00439 #ifdef GETC_DEV 00440 keyCode2 = 0; 00441 keyCode1 = 0; 00442 #endif 00443 break; 00444 } 00445 if (keyCode3 == 0xFF) 00446 key = pKeyMap[0]; // Key value 0 00447 else { 00448 row = (keyCode3 >> 4) & 0x03; 00449 col = (keyCode3 & 7); 00450 key = row * 5 + col + 1; // Keys value 1 - 20 00451 if (key > 21) { 00452 key = 21; 00453 } 00454 key = pKeyMap[key]; 00455 key |= (keyCode3 & 0x80); // combine the key held flag 00456 } 00457 #if GETC_DEV // for Development only 00458 SetTextCursor(0, 20); 00459 printf(" Reg: %02x\r\n", keyNumReg); 00460 printf(" key1: %02x\r\n", keyCode1); 00461 printf(" key2: %02x\r\n", keyCode2); 00462 printf(" key3: %02x\r\n", keyCode3); 00463 printf(" count: %02X\r\n", count); 00464 printf(" key: %02X\r\n", key); 00465 #endif 00466 WriteCommand(0xF1, 0x10); // Clear KS status 00467 return key; 00468 } 00469 00470 00471 #ifdef PERF_METRICS 00472 void RA8875::ClearPerformance() 00473 { 00474 int i; 00475 00476 for (i=0; i<METRICCOUNT; i++) 00477 metrics[i] = 0; 00478 idletime_usec = 0; 00479 for (i=0; i<256; i++) 00480 commandsUsed[i] = 0; 00481 } 00482 00483 00484 void RA8875::RegisterPerformance(method_e method) 00485 { 00486 unsigned long elapsed = performance.read_us(); 00487 00488 if (method < METRICCOUNT && elapsed > metrics[method]) 00489 metrics[method] = elapsed; 00490 } 00491 00492 00493 void RA8875::CountIdleTime(uint32_t t) 00494 { 00495 idletime_usec += t; 00496 } 00497 00498 00499 void RA8875::ReportPerformance(Serial & pc) 00500 { 00501 int i; 00502 00503 pc.printf("\r\nPerformance Metrics\r\n"); 00504 for (i=0; i<METRICCOUNT; i++) { 00505 pc.printf("%10d uS %s\r\n", metrics[i], metricsName[i]); 00506 } 00507 pc.printf("%10d uS Idle time polling display for ready.\r\n", idletime_usec); 00508 for (i=0; i<256; i++) { 00509 if (commandsUsed[i]) 00510 pc.printf("Command %02X used %5d times.\r\n", i, commandsUsed[i]); 00511 } 00512 } 00513 #endif 00514 00515 00516 bool RA8875::Intersect(rect_t rect, point_t p) 00517 { 00518 if (p.x >= min(rect.p1.x, rect.p2.x) && p.x <= max(rect.p1.x, rect.p2.x) 00519 && p.y >= min(rect.p1.y, rect.p2.y) && p.y <= max(rect.p1.y, rect.p2.y)) 00520 return true; 00521 else 00522 return false; 00523 } 00524 00525 00526 bool RA8875::Intersect(rect_t rect1, rect_t rect2) 00527 { 00528 #if 1 00529 // If one rectangle is on left side of other 00530 if (max(rect1.p1.x,rect1.p2.x) < min(rect2.p1.x,rect2.p2.x) 00531 || min(rect1.p1.x, rect1.p2.x) > max(rect2.p1.x, rect2.p2.x)) 00532 return false; 00533 // If one rectangle is above other 00534 if (max(rect1.p1.y, rect1.p2.y) < min(rect2.p1.y, rect2.p2.y) 00535 || min(rect1.p1.y, rect1.p2.y) > max(rect2.p1.y, rect2.p2.y)) 00536 return false; 00537 return true; // all that's left is they overlap 00538 #else 00539 point_t bl, tr; 00540 bl.x = rect2.p1.x; 00541 bl.y = rect2.p2.y; 00542 tr.x = rect2.p2.x; 00543 tr.y = rect2.p1.y; 00544 if (Intersect(rect1, rect2.p1) || Intersect(rect1, rect2.p2) 00545 || Intersect(rect1, bl) || Intersect(rect1, tr)) 00546 return true; 00547 else 00548 return false; 00549 #endif 00550 } 00551 00552 00553 bool RA8875::Intersect(rect_t * pRect1, const rect_t * pRect2) 00554 { 00555 if (Intersect(*pRect1, *pRect2)) { 00556 rect_t iSect; 00557 00558 iSect.p1.x = max(min(pRect1->p1.x,pRect1->p2.x),min(pRect2->p1.x,pRect2->p2.x)); 00559 iSect.p1.y = max(min(pRect1->p1.y,pRect1->p2.y),min(pRect2->p1.y,pRect2->p2.y)); 00560 iSect.p2.x = min(max(pRect1->p1.x,pRect1->p2.x),max(pRect2->p1.x,pRect2->p2.x)); 00561 iSect.p2.y = min(max(pRect1->p1.y,pRect1->p2.y),max(pRect2->p1.y,pRect2->p2.y)); 00562 *pRect1 = iSect; 00563 return true; 00564 } else { 00565 return false; 00566 } 00567 } 00568 00569 00570 RetCode_t RA8875::WriteCommandW(uint8_t command, uint16_t data) 00571 { 00572 WriteCommand(command, data & 0xFF); 00573 WriteCommand(command+1, data >> 8); 00574 return noerror; 00575 } 00576 00577 00578 RetCode_t RA8875::WriteCommand(unsigned char command, unsigned int data) 00579 { 00580 #ifdef PERF_METRICS 00581 if (commandsUsed[command] < 65535) 00582 commandsUsed[command]++; 00583 #endif 00584 _select(true); 00585 _spiwrite(0x80); // RS:1 (Cmd/Status), RW:0 (Write) 00586 _spiwrite(command); 00587 if (data <= 0xFF) { // only if in the valid range 00588 _spiwrite(0x00); 00589 _spiwrite(data); 00590 } 00591 _select(false); 00592 return noerror; 00593 } 00594 00595 00596 RetCode_t RA8875::WriteDataW(uint16_t data) 00597 { 00598 _select(true); 00599 _spiwrite(0x00); // RS:0 (Data), RW:0 (Write) 00600 _spiwrite(data & 0xFF); 00601 _spiwrite(data >> 8); 00602 _select(false); 00603 return noerror; 00604 } 00605 00606 00607 RetCode_t RA8875::WriteData(unsigned char data) 00608 { 00609 _select(true); 00610 _spiwrite(0x00); // RS:0 (Data), RW:0 (Write) 00611 _spiwrite(data); 00612 _select(false); 00613 return noerror; 00614 } 00615 00616 00617 unsigned char RA8875::ReadCommand(unsigned char command) 00618 { 00619 WriteCommand(command); 00620 return ReadData(); 00621 } 00622 00623 uint16_t RA8875::ReadCommandW(unsigned char command) 00624 { 00625 WriteCommand(command); 00626 return ReadDataW(); 00627 } 00628 00629 unsigned char RA8875::ReadData(void) 00630 { 00631 unsigned char data; 00632 00633 _select(true); 00634 _spiwrite(0x40); // RS:0 (Data), RW:1 (Read) 00635 data = _spiread(); 00636 _select(false); 00637 return data; 00638 } 00639 00640 00641 uint16_t RA8875::ReadDataW(void) 00642 { 00643 uint16_t data; 00644 00645 _select(true); 00646 _spiwrite(0x40); // RS:0 (Data), RW:1 (Read) 00647 data = _spiread(); 00648 data |= (_spiread() << 8); 00649 _select(false); 00650 return data; 00651 } 00652 00653 00654 unsigned char RA8875::ReadStatus(void) 00655 { 00656 unsigned char data; 00657 00658 _select(true); 00659 _spiwrite(0xC0); // RS:1 (Cmd/Status), RW:1 (Read) (Read STSR) 00660 data = _spiread(); 00661 _select(false); 00662 return data; 00663 } 00664 00665 00666 /// @todo add a timeout and return false, but how long 00667 /// to wait since some operations can be very long. 00668 bool RA8875::_WaitWhileBusy(uint8_t mask) 00669 { 00670 int i = 20000/POLLWAITuSec; // 20 msec max 00671 00672 while (i-- && ReadStatus() & mask) { 00673 wait_us(POLLWAITuSec); 00674 COUNTIDLETIME(POLLWAITuSec); 00675 if (idle_callback) { 00676 if (external_abort == (*idle_callback)(status_wait)) { 00677 return false; 00678 } 00679 } 00680 } 00681 if (i) 00682 return true; 00683 else 00684 return false; 00685 } 00686 00687 00688 /// @todo add a timeout and return false, but how long 00689 /// to wait since some operations can be very long. 00690 bool RA8875::_WaitWhileReg(uint8_t reg, uint8_t mask) 00691 { 00692 int i = 20000/POLLWAITuSec; // 20 msec max 00693 00694 while (i-- && ReadCommand(reg) & mask) { 00695 wait_us(POLLWAITuSec); 00696 COUNTIDLETIME(POLLWAITuSec); 00697 if (idle_callback) { 00698 if (external_abort == (*idle_callback)(command_wait)) { 00699 return false; 00700 } 00701 } 00702 } 00703 if (i) 00704 return true; 00705 else 00706 return false; 00707 } 00708 00709 // RRRR RGGG GGGB BBBB 00710 // 4321 0543 2104 3210 00711 // RRRG GGBB 00712 // 2102 1010 00713 uint8_t RA8875::_cvt16to8(color_t c16) 00714 { 00715 return ((c16 >> 8) & 0xE0) 00716 | ((c16 >> 6) & 0x1C) 00717 | ((c16 >> 3) & 0x03); 00718 } 00719 00720 // RRRG GGBB 00721 // 2102 1010 00722 // RRRR RGGG GGGB BBBB 00723 // 2101 0543 2104 3210 00724 color_t RA8875::_cvt8to16(uint8_t c8) 00725 { 00726 color_t c16; 00727 color_t temp = (color_t)c8; 00728 00729 c16 = ((temp & 0xE0) << 8) 00730 | ((temp & 0xC0) << 5) 00731 | ((temp & 0x1C) << 6) 00732 | ((temp & 0x1C) << 3) 00733 | ((temp & 0x03) << 3) 00734 | ((temp & 0x03) << 1) 00735 | ((temp & 0x03) >> 1); 00736 c16 = (c16 << 8) | (c16 >> 8); 00737 return c16; 00738 } 00739 00740 RetCode_t RA8875::_writeColorTrio(uint8_t regAddr, color_t color) 00741 { 00742 RetCode_t rt = noerror; 00743 00744 if (screenbpp == 16) { 00745 WriteCommand(regAddr+0, (color>>11)); // BGCR0 00746 WriteCommand(regAddr+1, (unsigned char)(color>>5)); // BGCR1 00747 rt = WriteCommand(regAddr+2, (unsigned char)(color)); // BGCR2 00748 } else { 00749 uint8_t r, g, b; 00750 00751 // RRRR RGGG GGGB BBBB RGB 00752 // RRR GGG B B 00753 r = (uint8_t)((color) >> 13); 00754 g = (uint8_t)((color) >> 8); 00755 b = (uint8_t)((color) >> 3); 00756 WriteCommand(regAddr+0, r); // BGCR0 00757 WriteCommand(regAddr+1, g); // BGCR1 00758 rt = WriteCommand(regAddr+2, b); // BGCR2 00759 } 00760 return rt; 00761 } 00762 00763 color_t RA8875::_readColorTrio(uint8_t regAddr) 00764 { 00765 color_t color; 00766 uint8_t r, g, b; 00767 00768 r = ReadCommand(regAddr+0); 00769 g = ReadCommand(regAddr+1); 00770 b = ReadCommand(regAddr+2); 00771 if (screenbpp == 16) { 00772 // 000R RRRR 00GG GGGG 000B BBBB 00773 // RRRR RGGG GGGB BBBB 00774 color = (r & 0x1F) << 11; 00775 color |= (g & 0x3F) << 5; 00776 color |= (b & 0x1F); 00777 } else { 00778 // RRRG GGBB 00779 // RRRR RGGG GGGB BBBB 00780 color = (r & 0x07) << 13; 00781 color |= (g & 0x07) << 8; 00782 color |= (b & 0x03) << 3; 00783 } 00784 return color; 00785 } 00786 00787 00788 dim_t RA8875::fontwidth(void) 00789 { 00790 if (font == NULL) 00791 return (((ReadCommand(0x22) >> 2) & 0x3) + 1) * 8; 00792 else 00793 return extFontWidth; 00794 } 00795 00796 00797 dim_t RA8875::fontheight(void) 00798 { 00799 if (font == NULL) 00800 return (((ReadCommand(0x22) >> 0) & 0x3) + 1) * 16; 00801 else 00802 return extFontHeight; 00803 } 00804 00805 00806 RetCode_t RA8875::locate(textloc_t column, textloc_t row) 00807 { 00808 return SetTextCursor(column * fontwidth(), row * fontheight()); 00809 } 00810 00811 00812 int RA8875::columns(void) 00813 { 00814 return screenwidth / fontwidth(); 00815 } 00816 00817 00818 int RA8875::rows(void) 00819 { 00820 return screenheight / fontheight(); 00821 } 00822 00823 00824 dim_t RA8875::width(void) 00825 { 00826 if (portraitmode) 00827 return screenheight; 00828 else 00829 return screenwidth; 00830 } 00831 00832 00833 dim_t RA8875::height(void) 00834 { 00835 if (portraitmode) 00836 return screenwidth; 00837 else 00838 return screenheight; 00839 } 00840 00841 00842 dim_t RA8875::color_bpp(void) 00843 { 00844 return screenbpp; 00845 } 00846 00847 RetCode_t RA8875::SetTextCursor(point_t p) 00848 { 00849 return SetTextCursor(p.x, p.y); 00850 } 00851 00852 RetCode_t RA8875::SetTextCursor(loc_t x, loc_t y) 00853 { 00854 INFO("SetTextCursor(%d, %d)", x, y); 00855 cursor_x = x; // set these values for non-internal fonts 00856 cursor_y = y; 00857 WriteCommandW(0x2A, x); 00858 WriteCommandW(0x2C, y); 00859 return noerror; 00860 } 00861 00862 point_t RA8875::GetTextCursor(void) 00863 { 00864 point_t p; 00865 00866 p.x = GetTextCursor_X(); 00867 p.y = GetTextCursor_Y(); 00868 return p; 00869 } 00870 00871 loc_t RA8875::GetTextCursor_Y(void) 00872 { 00873 loc_t y; 00874 00875 if (font == NULL) 00876 y = ReadCommand(0x2C) | (ReadCommand(0x2D) << 8); 00877 else 00878 y = cursor_y; 00879 INFO("GetTextCursor_Y = %d", y); 00880 return y; 00881 } 00882 00883 00884 loc_t RA8875::GetTextCursor_X(void) 00885 { 00886 loc_t x; 00887 00888 if (font == NULL) 00889 x = ReadCommand(0x2A) | (ReadCommand(0x2B) << 8); 00890 else 00891 x = cursor_x; 00892 INFO("GetTextCursor_X = %d", x); 00893 return x; 00894 } 00895 00896 00897 RetCode_t RA8875::SetTextCursorControl(cursor_t cursor, bool blink) 00898 { 00899 unsigned char mwcr0 = ReadCommand(0x40) & 0x0F; // retain direction, auto-increase 00900 unsigned char mwcr1 = ReadCommand(0x41) & 0x01; // retain currently selected layer 00901 unsigned char horz = 0; 00902 unsigned char vert = 0; 00903 00904 mwcr0 |= 0x80; // text mode 00905 if (cursor != NOCURSOR) 00906 mwcr0 |= 0x40; // visible 00907 if (blink) 00908 mwcr0 |= 0x20; // blink 00909 WriteCommand(0x40, mwcr0); // configure the cursor 00910 WriteCommand(0x41, mwcr1); // close the graphics cursor 00911 WriteCommand(0x44, 0x1f); // The cursor flashing cycle 00912 switch (cursor) { 00913 case IBEAM: 00914 horz = 0x01; 00915 vert = 0x1F; 00916 break; 00917 case UNDER: 00918 horz = 0x07; 00919 vert = 0x01; 00920 break; 00921 case BLOCK: 00922 horz = 0x07; 00923 vert = 0x1F; 00924 break; 00925 case NOCURSOR: 00926 default: 00927 break; 00928 } 00929 WriteCommand(0x4e, horz); // The cursor size horz 00930 WriteCommand(0x4f, vert); // The cursor size vert 00931 return noerror; 00932 } 00933 00934 00935 RetCode_t RA8875::SetTextFont(RA8875::font_t font) 00936 { 00937 if (/*font >= RA8875::ISO8859_1 && */ font <= RA8875::ISO8859_4) { 00938 WriteCommand(0x21, (unsigned int)(font)); 00939 return noerror; 00940 } else { 00941 return bad_parameter; 00942 } 00943 } 00944 00945 00946 RetCode_t RA8875::SetOrientation(RA8875::orientation_t angle) 00947 { 00948 uint8_t fncr1Val = ReadCommand(0x22); 00949 uint8_t dpcrVal = ReadCommand(0x20); 00950 00951 fncr1Val &= ~0x10; // remove the old direction bit 00952 dpcrVal &= ~0x0C; // remove the old scan direction bits 00953 switch (angle) { 00954 case RA8875::normal: 00955 //fncr1Val |= 0x10; 00956 //dpcrVal |= 0x00; 00957 portraitmode = false; 00958 break; 00959 case RA8875::rotate_90: 00960 fncr1Val |= 0x10; 00961 dpcrVal |= 0x08; 00962 portraitmode = true; 00963 break; 00964 case RA8875::rotate_180: 00965 //fncr1Val |= 0x00; 00966 dpcrVal |= 0x0C; 00967 portraitmode = false; 00968 break; 00969 case RA8875::rotate_270: 00970 fncr1Val |= 0x10; 00971 dpcrVal |= 0x04; 00972 portraitmode = true; 00973 break; 00974 default: 00975 return bad_parameter; 00976 } 00977 INFO("Orientation: %d, %d", angle, portraitmode); 00978 WriteCommand(0x22, fncr1Val); 00979 return WriteCommand(0x20, dpcrVal); 00980 } 00981 00982 00983 RetCode_t RA8875::SetTextFontControl(fill_t fillit, 00984 RA8875::HorizontalScale hScale, 00985 RA8875::VerticalScale vScale, 00986 RA8875::alignment_t alignment) 00987 { 00988 if (hScale >= 1 && hScale <= 4 && 00989 vScale >= 1 && vScale <= 4) { 00990 uint8_t fncr1Val = ReadCommand(0x22); 00991 00992 fncr1Val &= ~0x10; // do not disturb the rotate flag 00993 if (alignment == align_full) 00994 fncr1Val |= 0x80; 00995 if (fillit == NOFILL) 00996 fncr1Val |= 0x40; 00997 fncr1Val |= ((hScale - 1) << 2); 00998 fncr1Val |= ((vScale - 1) << 0); 00999 return WriteCommand(0x22, fncr1Val); 01000 } else { 01001 return bad_parameter; 01002 } 01003 } 01004 01005 01006 RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale) 01007 { 01008 unsigned char reg = ReadCommand(0x22); 01009 01010 if (vScale == -1) 01011 vScale = hScale; 01012 if (hScale >= 1 && hScale <= 4 && vScale >= 1 && vScale <= 4) { 01013 reg &= 0xF0; // keep the high nibble as is. 01014 reg |= ((hScale - 1) << 2); 01015 reg |= ((vScale - 1) << 0); 01016 WriteCommand(0x22, reg); 01017 return noerror; 01018 } else { 01019 return bad_parameter; 01020 } 01021 } 01022 01023 RetCode_t RA8875::GetTextFontSize(RA8875::HorizontalScale * hScale, RA8875::VerticalScale * vScale) 01024 { 01025 unsigned char reg = ReadCommand(0x22); 01026 01027 if (hScale) 01028 *hScale = 1 + (reg >> 2) & 0x03; 01029 if (vScale) 01030 *vScale = 1 + reg & 0x03; 01031 return noerror; 01032 } 01033 01034 int RA8875::_putc(int c) 01035 { 01036 if (font == NULL) { 01037 return _internal_putc(c); 01038 } else { 01039 return _external_putc(c); 01040 } 01041 } 01042 01043 01044 01045 // Questions to ponder - 01046 // - if we choose to wrap to the next line, because the character won't fit on the current line, 01047 // should it erase the space to the width of the screen (in case there is leftover junk there)? 01048 // - it currently wraps from the bottom of the screen back to the top. I have pondered what 01049 // it might take to scroll the screen - but haven't thought hard enough about it. 01050 // 01051 int RA8875::_external_putc(int c) 01052 { 01053 if (c) { 01054 if (c == '\r') { 01055 cursor_x = windowrect.p1.x; 01056 } else if (c == '\n') { 01057 cursor_y += extFontHeight; 01058 } else { 01059 dim_t charWidth, charHeight; 01060 const uint8_t * charRecord; 01061 01062 charRecord = getCharMetrics(c, &charWidth, &charHeight); 01063 //int advance = charwidth(c); 01064 INFO("(%d,%d) - (%d,%d):(%d,%d), charWidth: %d '%c", cursor_x, cursor_y, 01065 windowrect.p1.x, windowrect.p1.y, windowrect.p2.x, windowrect.p2.y, 01066 charWidth, c); 01067 if (charRecord) { 01068 //cursor_x += advance; 01069 if (cursor_x + charWidth >= windowrect.p2.x) { 01070 cursor_x = windowrect.p1.x; 01071 cursor_y += charHeight; 01072 } 01073 if (cursor_y + charHeight >= windowrect.p2.y) { 01074 cursor_y = windowrect.p1.y; // @todo Should it scroll? 01075 } 01076 (void)character(cursor_x, cursor_y, c); 01077 cursor_x += charWidth; 01078 } 01079 } 01080 } 01081 return c; 01082 } 01083 01084 01085 int RA8875::_internal_putc(int c) 01086 { 01087 if (c) { 01088 unsigned char mwcr0; 01089 01090 mwcr0 = ReadCommand(0x40); 01091 if ((mwcr0 & 0x80) == 0x00) { 01092 WriteCommand(0x40, 0x80 | mwcr0); // Put in Text mode if not already 01093 } 01094 if (c == '\r') { 01095 loc_t x; 01096 x = ReadCommand(0x30) | (ReadCommand(0x31) << 8); // Left edge of active window 01097 WriteCommandW(0x2A, x); 01098 } else if (c == '\n') { 01099 loc_t y; 01100 y = ReadCommand(0x2C) | (ReadCommand(0x2D) << 8); // current y location 01101 y += fontheight(); 01102 if (y >= height()) // @TODO after bottom of active window, then scroll window? 01103 y = 0; 01104 WriteCommandW(0x2C, y); 01105 } else { 01106 WriteCommand(0x02); // RA8875 Internal Fonts 01107 _select(true); 01108 WriteData(c); 01109 _WaitWhileBusy(0x80); 01110 _select(false); 01111 } 01112 } 01113 return c; 01114 } 01115 01116 01117 RetCode_t RA8875::_StartGraphicsStream(void) 01118 { 01119 WriteCommand(0x40,0x00); // Graphics write mode 01120 WriteCommand(0x02); // Prepare for streaming data 01121 return noerror; 01122 } 01123 01124 01125 RetCode_t RA8875::_EndGraphicsStream(void) 01126 { 01127 return noerror; 01128 } 01129 01130 01131 RetCode_t RA8875::_putp(color_t pixel) 01132 { 01133 WriteDataW((pixel>>8) | (pixel<<8)); 01134 return noerror; 01135 } 01136 01137 01138 void RA8875::puts(loc_t x, loc_t y, const char * string) 01139 { 01140 SetTextCursor(x,y); 01141 puts(string); 01142 } 01143 01144 01145 void RA8875::puts(const char * string) 01146 { 01147 if (font == NULL) { 01148 WriteCommand(0x40,0x80); // Put in Text mode if internal font 01149 } 01150 if (*string != '\0') { 01151 while (*string) { // @TODO calling individual _putc is slower... optimizations? 01152 _putc(*string++); 01153 } 01154 } 01155 } 01156 01157 01158 RetCode_t RA8875::SetGraphicsCursor(loc_t x, loc_t y) 01159 { 01160 WriteCommandW(0x46, x); 01161 WriteCommandW(0x48, y); 01162 return noerror; 01163 } 01164 01165 RetCode_t RA8875::SetGraphicsCursor(point_t p) 01166 { 01167 return SetGraphicsCursor(p.x, p.y); 01168 } 01169 01170 point_t RA8875::GetGraphicsCursor(void) 01171 { 01172 point_t p; 01173 01174 p.x = ReadCommandW(0x46); 01175 p.y = ReadCommandW(0x48); 01176 return p; 01177 } 01178 01179 RetCode_t RA8875::SetGraphicsCursorRead(loc_t x, loc_t y) 01180 { 01181 WriteCommandW(0x4A, x); 01182 WriteCommandW(0x4C, y); 01183 return noerror; 01184 } 01185 01186 RetCode_t RA8875::window(rect_t r) 01187 { 01188 return window(r.p1.x, r.p1.y, r.p2.x + 1 - r.p1.x, r.p2.y + 1 - r.p1.y); 01189 } 01190 01191 RetCode_t RA8875::window(loc_t x, loc_t y, dim_t width, dim_t height) 01192 { 01193 INFO("window(%d,%d,%d,%d)", x, y, width, height); 01194 if (width == (dim_t)-1) 01195 width = screenwidth - x; 01196 if (height == (dim_t)-1) 01197 height = screenheight - y; 01198 windowrect.p1.x = x; 01199 windowrect.p1.y = y; 01200 windowrect.p2.x = x + width - 1; 01201 windowrect.p2.y = y + height - 1; 01202 GraphicsDisplay::window(x,y, width,height); 01203 WriteCommandW(0x30, x); 01204 WriteCommandW(0x32, y); 01205 WriteCommandW(0x34, (x+width-1)); 01206 WriteCommandW(0x36, (y+height-1)); 01207 //SetTextCursor(x,y); 01208 //SetGraphicsCursor(x,y); 01209 return noerror; 01210 } 01211 01212 01213 RetCode_t RA8875::cls(uint16_t layers) 01214 { 01215 RetCode_t ret; 01216 01217 PERFORMANCE_RESET; 01218 if (layers == 0) { 01219 ret = clsw(FULLWINDOW); 01220 } else if (layers > 3) { 01221 ret = bad_parameter; 01222 } else { 01223 uint16_t prevLayer = GetDrawingLayer(); 01224 if (layers & 1) { 01225 SelectDrawingLayer(0); 01226 clsw(FULLWINDOW); 01227 } 01228 if (layers & 2) { 01229 SelectDrawingLayer(1); 01230 clsw(FULLWINDOW); 01231 } 01232 SelectDrawingLayer(prevLayer); 01233 } 01234 ret = SetTextCursor(0,0); 01235 ret = locate(0,0); 01236 REGISTERPERFORMANCE(PRF_CLS); 01237 return ret; 01238 } 01239 01240 01241 RetCode_t RA8875::clsw(RA8875::Region_t region) 01242 { 01243 PERFORMANCE_RESET; 01244 WriteCommand(0x8E, (region == ACTIVEWINDOW) ? 0xC0 : 0x80); 01245 if (!_WaitWhileReg(0x8E, 0x80)) { 01246 REGISTERPERFORMANCE(PRF_CLS); 01247 return external_abort; 01248 } 01249 REGISTERPERFORMANCE(PRF_CLS); 01250 return noerror; 01251 } 01252 01253 01254 RetCode_t RA8875::pixel(point_t p, color_t color) 01255 { 01256 return pixel(p.x, p.y, color); 01257 } 01258 01259 RetCode_t RA8875::pixel(point_t p) 01260 { 01261 return pixel(p.x, p.y); 01262 } 01263 01264 RetCode_t RA8875::pixel(loc_t x, loc_t y, color_t color) 01265 { 01266 RetCode_t ret; 01267 01268 PERFORMANCE_RESET; 01269 ret = pixelStream(&color, 1, x,y); 01270 REGISTERPERFORMANCE(PRF_DRAWPIXEL); 01271 return ret; 01272 } 01273 01274 01275 RetCode_t RA8875::pixel(loc_t x, loc_t y) 01276 { 01277 RetCode_t ret; 01278 01279 PERFORMANCE_RESET; 01280 color_t color = GetForeColor(); 01281 ret = pixelStream(&color, 1, x, y); 01282 REGISTERPERFORMANCE(PRF_DRAWPIXEL); 01283 return ret; 01284 } 01285 01286 01287 RetCode_t RA8875::pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) 01288 { 01289 PERFORMANCE_RESET; 01290 SetGraphicsCursor(x, y); 01291 _StartGraphicsStream(); 01292 _select(true); 01293 _spiwrite(0x00); // Cmd: write data 01294 while (count--) { 01295 if (screenbpp == 16) { 01296 _spiwrite(*p >> 8); 01297 _spiwrite(*p & 0xFF); 01298 } else { 01299 _spiwrite(_cvt16to8(*p)); 01300 } 01301 p++; 01302 } 01303 _select(false); 01304 _EndGraphicsStream(); 01305 REGISTERPERFORMANCE(PRF_PIXELSTREAM); 01306 return(noerror); 01307 } 01308 01309 RetCode_t RA8875::booleanStream(loc_t x, loc_t y, dim_t w, dim_t h, const uint8_t * boolStream) 01310 { 01311 PERFORMANCE_RESET; 01312 rect_t restore = windowrect; 01313 01314 window(x, y, w, h); 01315 SetGraphicsCursor(x, y); 01316 _StartGraphicsStream(); 01317 _select(true); 01318 _spiwrite(0x00); // Cmd: write data 01319 while (h--) { 01320 uint8_t pixels = w; 01321 uint8_t bitmask = 0x01; 01322 01323 while (pixels) { 01324 uint8_t byte = *boolStream; 01325 //INFO("byte, mask: %02X, %02X", byte, bitmask); 01326 color_t c = (byte & bitmask) ? _foreground : _background; 01327 if (screenbpp == 16) { 01328 _spiwrite(c >> 8); 01329 _spiwrite(c & 0xFF); 01330 } else { 01331 _spiwrite(_cvt16to8(c)); 01332 } 01333 bitmask <<= 1; 01334 if (pixels > 1 && bitmask == 0) { 01335 bitmask = 0x01; 01336 boolStream++; 01337 } 01338 pixels--; 01339 } 01340 boolStream++; 01341 } 01342 _select(false); 01343 _EndGraphicsStream(); 01344 window(restore); 01345 REGISTERPERFORMANCE(PRF_BOOLSTREAM); 01346 return(noerror); 01347 } 01348 01349 color_t RA8875::getPixel(loc_t x, loc_t y) 01350 { 01351 color_t pixel; 01352 01353 PERFORMANCE_RESET; 01354 WriteCommand(0x40,0x00); // Graphics write mode 01355 SetGraphicsCursorRead(x, y); 01356 WriteCommand(0x02); 01357 _select(true); 01358 _spiwrite(0x40); // Cmd: read data 01359 _spiwrite(0x00); // dummy read 01360 if (screenbpp == 16) { 01361 pixel = _spiread(); 01362 pixel |= (_spiread() << 8); 01363 } else { 01364 pixel = _cvt8to16(_spiread()); 01365 } 01366 _select(false); 01367 REGISTERPERFORMANCE(PRF_READPIXEL); 01368 return pixel; 01369 } 01370 01371 01372 RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) 01373 { 01374 color_t pixel; 01375 RetCode_t ret = noerror; 01376 01377 PERFORMANCE_RESET; 01378 ret = WriteCommand(0x40,0x00); // Graphics write mode 01379 ret = SetGraphicsCursorRead(x, y); 01380 ret = WriteCommand(0x02); 01381 _select(true); 01382 _spiwrite(0x40); // Cmd: read data 01383 _spiwrite(0x00); // dummy read 01384 if (screenbpp == 16) 01385 _spiwrite(0x00); // dummy read is only necessary when in 16-bit mode 01386 while (count--) { 01387 if (screenbpp == 16) { 01388 pixel = _spiread(); 01389 pixel |= (_spiread() << 8); 01390 } else { 01391 pixel = _cvt8to16(_spiread()); 01392 } 01393 *p++ = pixel; 01394 } 01395 _select(false); 01396 REGISTERPERFORMANCE(PRF_READPIXELSTREAM); 01397 return ret; 01398 } 01399 01400 01401 RetCode_t RA8875::line(point_t p1, point_t p2) 01402 { 01403 return line(p1.x, p1.y, p2.x, p2.y); 01404 } 01405 01406 01407 RetCode_t RA8875::line(point_t p1, point_t p2, color_t color) 01408 { 01409 return line(p1.x, p1.y, p2.x, p2.y, color); 01410 } 01411 01412 01413 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color) 01414 { 01415 foreground(color); 01416 return line(x1,y1,x2,y2); 01417 } 01418 01419 01420 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2) 01421 { 01422 PERFORMANCE_RESET; 01423 if (x1 == x2 && y1 == y2) { 01424 pixel(x1, y1); 01425 } else { 01426 WriteCommandW(0x91, x1); 01427 WriteCommandW(0x93, y1); 01428 WriteCommandW(0x95, x2); 01429 WriteCommandW(0x97, y2); 01430 unsigned char drawCmd = 0x00; // Line 01431 WriteCommand(0x90, drawCmd); 01432 WriteCommand(0x90, 0x80 + drawCmd); // Start drawing. 01433 if (!_WaitWhileReg(0x90, 0x80)) { 01434 REGISTERPERFORMANCE(PRF_DRAWLINE); 01435 return external_abort; 01436 } 01437 } 01438 REGISTERPERFORMANCE(PRF_DRAWLINE); 01439 return noerror; 01440 } 01441 01442 01443 RetCode_t RA8875::ThickLine(point_t p1, point_t p2, dim_t thickness, color_t color) 01444 { 01445 if (thickness == 1) { 01446 line(p1,p2, color); 01447 } else { 01448 int dx = abs(p2.x-p1.x), sx = p1.x<p2.x ? 1 : -1; 01449 int dy = abs(p2.y-p1.y), sy = p1.y<p2.y ? 1 : -1; 01450 int err = (dx>dy ? dx : -dy)/2, e2; 01451 01452 for (;;) { 01453 fillcircle(p1.x, p1.y, thickness/2, color); 01454 if (p1.x==p2.x && p1.y==p2.y) 01455 break; 01456 e2 = err; 01457 if (e2 >-dx) 01458 { err -= dy; p1.x += sx; } 01459 if (e2 < dy) 01460 { err += dx; p1.y += sy; } 01461 } 01462 } 01463 return noerror; 01464 } 01465 01466 01467 // 01468 // Rectangle functions all mostly helpers to the basic rectangle function 01469 // 01470 01471 RetCode_t RA8875::fillrect(rect_t r, color_t color, fill_t fillit) 01472 { 01473 return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit); 01474 } 01475 01476 RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01477 color_t color, fill_t fillit) 01478 { 01479 return rect(x1,y1,x2,y2,color,fillit); 01480 } 01481 01482 RetCode_t RA8875::rect(rect_t r, color_t color, fill_t fillit) 01483 { 01484 return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit); 01485 } 01486 01487 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01488 color_t color, fill_t fillit) 01489 { 01490 foreground(color); 01491 return rect(x1,y1,x2,y2,fillit); 01492 } 01493 01494 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01495 fill_t fillit) 01496 { 01497 RetCode_t ret = noerror; 01498 PERFORMANCE_RESET; 01499 // check for bad_parameter 01500 if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 01501 || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) { 01502 ret = bad_parameter; 01503 } else { 01504 if (x1 == x2 && y1 == y2) { 01505 pixel(x1, y1); 01506 } else if (x1 == x2) { 01507 line(x1, y1, x2, y2); 01508 } else if (y1 == y2) { 01509 line(x1, y1, x2, y2); 01510 } else { 01511 WriteCommandW(0x91, x1); 01512 WriteCommandW(0x93, y1); 01513 WriteCommandW(0x95, x2); 01514 WriteCommandW(0x97, y2); 01515 unsigned char drawCmd = 0x10; // Rectangle 01516 if (fillit == FILL) 01517 drawCmd |= 0x20; 01518 WriteCommand(0x90, drawCmd); 01519 ret = WriteCommand(0x90, 0x80 + drawCmd); // Start drawing. 01520 if (!_WaitWhileReg(0x90, 0x80)) { 01521 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE); 01522 return external_abort; 01523 } 01524 } 01525 } 01526 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE); 01527 return ret; 01528 } 01529 01530 01531 // 01532 // rounded rectangle functions are mostly helpers to the base round rect 01533 // 01534 01535 RetCode_t RA8875::fillroundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01536 { 01537 return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit); 01538 } 01539 01540 RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01541 dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01542 { 01543 foreground(color); 01544 return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); 01545 } 01546 01547 RetCode_t RA8875::roundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01548 { 01549 return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit); 01550 } 01551 01552 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01553 dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01554 { 01555 foreground(color); 01556 return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); 01557 } 01558 01559 01560 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01561 dim_t radius1, dim_t radius2, fill_t fillit) 01562 { 01563 RetCode_t ret = noerror; 01564 01565 PERFORMANCE_RESET; 01566 if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 01567 || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) { 01568 ret = bad_parameter; 01569 } else if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) { 01570 ret = bad_parameter; 01571 } else if (x1 == x2 && y1 == y2) { 01572 pixel(x1, y1); 01573 } else if (x1 == x2) { 01574 line(x1, y1, x2, y2); 01575 } else if (y1 == y2) { 01576 line(x1, y1, x2, y2); 01577 } else { 01578 WriteCommandW(0x91, x1); 01579 WriteCommandW(0x93, y1); 01580 WriteCommandW(0x95, x2); 01581 WriteCommandW(0x97, y2); 01582 WriteCommandW(0xA1, radius1); 01583 WriteCommandW(0xA3, radius2); 01584 // Should not need this... 01585 WriteCommandW(0xA5, 0); 01586 WriteCommandW(0xA7, 0); 01587 unsigned char drawCmd = 0x20; // Rounded Rectangle 01588 if (fillit == FILL) 01589 drawCmd |= 0x40; 01590 WriteCommand(0xA0, drawCmd); 01591 WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing. 01592 if (!_WaitWhileReg(0xA0, 0x80)) { 01593 REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE); 01594 return external_abort; 01595 } 01596 } 01597 REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE); 01598 return ret; 01599 } 01600 01601 01602 // 01603 // triangle functions 01604 // 01605 01606 RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01607 loc_t x3, loc_t y3, color_t color, fill_t fillit) 01608 { 01609 RetCode_t ret; 01610 01611 if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth || x3 < 0 || x3 >= screenwidth 01612 || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight || y3 < 0 || y3 >= screenheight) 01613 ret = bad_parameter; 01614 foreground(color); 01615 ret = triangle(x1,y1,x2,y2,x3,y3,fillit); 01616 return ret; 01617 } 01618 01619 01620 RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01621 loc_t x3, loc_t y3, color_t color, fill_t fillit) 01622 { 01623 RetCode_t ret; 01624 01625 foreground(color); 01626 ret = triangle(x1,y1,x2,y2,x3,y3,fillit); 01627 return ret; 01628 } 01629 01630 01631 RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2, 01632 loc_t x3, loc_t y3, fill_t fillit) 01633 { 01634 RetCode_t ret = noerror; 01635 01636 PERFORMANCE_RESET; 01637 if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) { 01638 pixel(x1, y1); 01639 } else { 01640 WriteCommandW(0x91, x1); 01641 WriteCommandW(0x93, y1); 01642 WriteCommandW(0x95, x2); 01643 WriteCommandW(0x97, y2); 01644 WriteCommandW(0xA9, x3); 01645 WriteCommandW(0xAB, y3); 01646 unsigned char drawCmd = 0x01; // Triangle 01647 if (fillit == FILL) 01648 drawCmd |= 0x20; 01649 WriteCommand(0x90, drawCmd); 01650 WriteCommand(0x90, 0x80 + drawCmd); // Start drawing. 01651 if (!_WaitWhileReg(0x90, 0x80)) { 01652 REGISTERPERFORMANCE(PRF_DRAWTRIANGLE); 01653 return external_abort; 01654 } 01655 } 01656 REGISTERPERFORMANCE(PRF_DRAWTRIANGLE); 01657 return ret; 01658 } 01659 01660 01661 RetCode_t RA8875::circle(point_t p, dim_t radius, 01662 color_t color, fill_t fillit) 01663 { 01664 foreground(color); 01665 return circle(p.x,p.y,radius,fillit); 01666 } 01667 01668 01669 RetCode_t RA8875::fillcircle(point_t p, dim_t radius, 01670 color_t color, fill_t fillit) 01671 { 01672 foreground(color); 01673 return circle(p.x,p.y,radius,fillit); 01674 } 01675 01676 01677 RetCode_t RA8875::circle(point_t p, dim_t radius, fill_t fillit) 01678 { 01679 return circle(p.x,p.y,radius,fillit); 01680 } 01681 01682 01683 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, 01684 color_t color, fill_t fillit) 01685 { 01686 foreground(color); 01687 return circle(x,y,radius,fillit); 01688 } 01689 01690 01691 RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius, 01692 color_t color, fill_t fillit) 01693 { 01694 foreground(color); 01695 return circle(x,y,radius,fillit); 01696 } 01697 01698 01699 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit) 01700 { 01701 RetCode_t ret = noerror; 01702 01703 PERFORMANCE_RESET; 01704 if (radius <= 0 || (x - radius) < 0 || (x + radius) > screenwidth 01705 || (y - radius) < 0 || (y + radius) > screenheight) { 01706 ret = bad_parameter; 01707 } else if (radius == 1) { 01708 pixel(x,y); 01709 } else { 01710 WriteCommandW(0x99, x); 01711 WriteCommandW(0x9B, y); 01712 WriteCommand(0x9d, radius & 0xFF); 01713 unsigned char drawCmd = 0x00; // Circle 01714 if (fillit == FILL) 01715 drawCmd |= 0x20; 01716 WriteCommand(0x90, drawCmd); 01717 WriteCommand(0x90, 0x40 + drawCmd); // Start drawing. 01718 if (!_WaitWhileReg(0x90, 0x40)) { 01719 REGISTERPERFORMANCE(PRF_DRAWCIRCLE); 01720 return external_abort; 01721 } 01722 } 01723 REGISTERPERFORMANCE(PRF_DRAWCIRCLE); 01724 return ret; 01725 } 01726 01727 01728 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01729 { 01730 foreground(color); 01731 return ellipse(x,y,radius1,radius2,fillit); 01732 } 01733 01734 01735 RetCode_t RA8875::fillellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01736 { 01737 foreground(color); 01738 return ellipse(x,y,radius1,radius2,fillit); 01739 } 01740 01741 01742 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit) 01743 { 01744 RetCode_t ret = noerror; 01745 01746 PERFORMANCE_RESET; 01747 if (radius1 <= 0 || radius2 <= 0 || (x - radius1) < 0 || (x + radius1) > screenwidth 01748 || (y - radius2) < 0 || (y + radius2) > screenheight) { 01749 ret = bad_parameter; 01750 } else if (radius1 == 1 && radius2 == 1) { 01751 pixel(x, y); 01752 } else { 01753 WriteCommandW(0xA5, x); 01754 WriteCommandW(0xA7, y); 01755 WriteCommandW(0xA1, radius1); 01756 WriteCommandW(0xA3, radius2); 01757 unsigned char drawCmd = 0x00; // Ellipse 01758 if (fillit == FILL) 01759 drawCmd |= 0x40; 01760 WriteCommand(0xA0, drawCmd); 01761 WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing. 01762 if (!_WaitWhileReg(0xA0, 0x80)) { 01763 REGISTERPERFORMANCE(PRF_DRAWELLIPSE); 01764 return external_abort; 01765 } 01766 } 01767 REGISTERPERFORMANCE(PRF_DRAWELLIPSE); 01768 return ret; 01769 } 01770 01771 01772 RetCode_t RA8875::frequency(unsigned long Hz, unsigned long Hz2) 01773 { 01774 spiwritefreq = Hz; 01775 if (Hz2 != 0) 01776 spireadfreq = Hz2; 01777 else 01778 spireadfreq = Hz/2; 01779 _setWriteSpeed(true); 01780 // __ ___ 01781 // Clock ___A Rising edge latched 01782 // ___ ____ 01783 // Data ___X____ 01784 spi.format(8, 3); // 8 bits and clock to data phase 0 01785 return noerror; 01786 } 01787 01788 void RA8875::_setWriteSpeed(bool writeSpeed) 01789 { 01790 if (writeSpeed) { 01791 spi.frequency(spiwritefreq); 01792 spiWriteSpeed = true; 01793 } else { 01794 spi.frequency(spireadfreq); 01795 spiWriteSpeed = false; 01796 } 01797 } 01798 01799 01800 01801 RetCode_t RA8875::BlockMove(uint8_t dstLayer, uint8_t dstDataSelect, point_t dstPoint, 01802 uint8_t srcLayer, uint8_t srcDataSelect, point_t srcPoint, 01803 dim_t bte_width, dim_t bte_height, 01804 uint8_t bte_op_code, uint8_t bte_rop_code) 01805 { 01806 uint8_t cmd; 01807 01808 PERFORMANCE_RESET; 01809 ///@todo range check and error return rather than to secretly fix 01810 srcPoint.x &= 0x3FF; // prevent high bits from doing unexpected things 01811 srcPoint.y &= 0x1FF; 01812 dstPoint.x &= 0x3FF; 01813 dstPoint.y &= 0x1FF; 01814 WriteCommandW(0x54, srcPoint.x); 01815 WriteCommandW(0x56, ((dim_t)(srcLayer & 1) << 15) | srcPoint.y); 01816 WriteCommandW(0x58, dstPoint.x); 01817 WriteCommandW(0x5A, ((dim_t)(dstLayer & 1) << 15) | dstPoint.y); 01818 WriteCommandW(0x5C, bte_width); 01819 WriteCommandW(0x5E, bte_height); 01820 WriteCommand(0x51, ((bte_rop_code & 0x0F) << 4) | (bte_op_code & 0x0F)); 01821 cmd = ((srcDataSelect & 1) << 6) | ((dstDataSelect & 1) << 5); 01822 WriteCommand(0x50, 0x80 | cmd); // enable the BTE 01823 if (!_WaitWhileBusy(0x40)) { 01824 REGISTERPERFORMANCE(PRF_BLOCKMOVE); 01825 return external_abort; 01826 } 01827 REGISTERPERFORMANCE(PRF_BLOCKMOVE); 01828 return noerror; 01829 } 01830 01831 01832 RetCode_t RA8875::Power(bool on) 01833 { 01834 WriteCommand(0x01, (on) ? 0x80 : 0x00); 01835 return noerror; 01836 } 01837 01838 01839 RetCode_t RA8875::Backlight_u8(uint8_t brightness) 01840 { 01841 static bool is_enabled = false; 01842 01843 if (brightness == 0) { 01844 WriteCommand(0x8a); // Disable the PWM 01845 WriteData(0x00); 01846 is_enabled = false; 01847 } else if (!is_enabled) { 01848 WriteCommand(0x8a); // Enable the PWM 01849 WriteData(0x80); 01850 WriteCommand(0x8a); // Not sure why this is needed, but following the pattern 01851 WriteData(0x81); // open PWM (SYS_CLK / 2 as best I can tell) 01852 is_enabled = true; 01853 } 01854 WriteCommand(0x8b, brightness); // Brightness parameter 0xff-0x00 01855 return noerror; 01856 } 01857 01858 uint8_t RA8875::GetBacklight_u8(void) 01859 { 01860 return ReadCommand(0x8b); 01861 } 01862 01863 RetCode_t RA8875::Backlight(float brightness) 01864 { 01865 unsigned char b; 01866 01867 if (brightness >= 1.0) 01868 b = 255; 01869 else if (brightness <= 0.0) 01870 b = 0; 01871 else 01872 b = (unsigned char)(brightness * 255); 01873 return Backlight_u8(b); 01874 } 01875 01876 float RA8875::GetBacklight(void) 01877 { 01878 return (float)(GetBacklight_u8())/255; 01879 } 01880 01881 RetCode_t RA8875::SelectUserFont(const uint8_t * _font) 01882 { 01883 INFO("Cursor(%d,%d) %p", cursor_x, cursor_y, _font); 01884 INFO("Text C(%d,%d)", GetTextCursor_X(), GetTextCursor_Y()); 01885 if (_font) { 01886 HexDump("Font Memory", _font, 16); 01887 extFontHeight = _font[6]; 01888 uint32_t totalWidth = 0; 01889 uint16_t firstChar = _font[3] * 256 + _font[2]; 01890 uint16_t lastChar = _font[5] * 256 + _font[4]; 01891 uint16_t i; 01892 01893 for (i=firstChar; i<=lastChar; i++) { 01894 // 8 bytes of preamble to the first level lookup table 01895 uint16_t offsetToCharLookup = 8 + 4 * (i - firstChar); // 4-bytes: width(pixels), 16-bit offset from table start, 0 01896 totalWidth += _font[offsetToCharLookup]; 01897 } 01898 extFontWidth = totalWidth / (lastChar - firstChar); 01899 INFO("Font Metrics: Avg W: %2d, H: %2d, First:%d, Last:%d", extFontWidth, extFontHeight, firstChar, lastChar); 01900 } 01901 SetTextCursor(GetTextCursor_X(), GetTextCursor_Y()); // soft-font cursor -> hw cursor 01902 font = _font; 01903 return GraphicsDisplay::SelectUserFont(_font); 01904 } 01905 01906 RetCode_t RA8875::background(color_t color) 01907 { 01908 GraphicsDisplay::background(color); 01909 return _writeColorTrio(0x60, color); 01910 } 01911 01912 01913 RetCode_t RA8875::background(unsigned char r, unsigned char g, unsigned char b) 01914 { 01915 background(RGB(r,g,b)); 01916 return noerror; 01917 } 01918 01919 01920 RetCode_t RA8875::foreground(color_t color) 01921 { 01922 GraphicsDisplay::foreground(color); 01923 return _writeColorTrio(0x63, color); 01924 } 01925 01926 01927 RetCode_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b) 01928 { 01929 foreground(RGB(r,g,b)); 01930 return noerror; 01931 } 01932 01933 01934 color_t RA8875::GetForeColor(void) 01935 { 01936 return _readColorTrio(0x63); 01937 } 01938 01939 01940 color_t RA8875::DOSColor(int i) 01941 { 01942 const color_t colors[16] = { 01943 Black, Blue, Green, Cyan, 01944 Red, Magenta, Brown, Gray, 01945 Charcoal, BrightBlue, BrightGreen, BrightCyan, 01946 Orange, Pink, Yellow, White 01947 }; 01948 if (i >= 0 && i < 16) 01949 return colors[i]; 01950 else 01951 return 0; 01952 } 01953 01954 01955 const char * RA8875::DOSColorNames(int i) 01956 { 01957 const char * names[16] = { 01958 "Black", "Blue", "Green", "Cyan", 01959 "Red", "Magenta", "Brown", "Gray", 01960 "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan", 01961 "Orange", "Pink", "Yellow", "White" 01962 }; 01963 if (i >= 0 && i < 16) 01964 return names[i]; 01965 else 01966 return NULL; 01967 } 01968 01969 01970 /////////////////////////////////////////////////////////////// 01971 // Private functions 01972 01973 unsigned char RA8875::_spiwrite(unsigned char data) 01974 { 01975 unsigned char retval; 01976 01977 if (!spiWriteSpeed) 01978 _setWriteSpeed(true); 01979 retval = spi.write(data); 01980 return retval; 01981 } 01982 01983 01984 unsigned char RA8875::_spiread(void) 01985 { 01986 unsigned char retval; 01987 unsigned char data = 0; 01988 01989 if (spiWriteSpeed) 01990 _setWriteSpeed(false); 01991 retval = spi.write(data); 01992 return retval; 01993 } 01994 01995 01996 RetCode_t RA8875::_select(bool chipsel) 01997 { 01998 cs = (chipsel == true) ? 0 : 1; 01999 return noerror; 02000 } 02001 02002 02003 RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP) 02004 { 02005 (void)layer; 02006 02007 // AttachPrintHandler(this, RA8875::_printCallback); 02008 // return PrintScreen(x,y,w,h); 02009 return PrintScreen(x, y, w, h, Name_BMP); 02010 } 02011 02012 RetCode_t RA8875::_printCallback(RA8875::filecmd_t cmd, uint8_t * buffer, uint16_t size) 02013 { 02014 HexDump("CB", buffer, size); 02015 switch(cmd) { 02016 case RA8875::OPEN: 02017 //pc.printf("About to write %lu bytes\r\n", *(uint32_t *)buffer); 02018 _printFH = fopen("file.bmp", "w+b"); 02019 if (_printFH == 0) 02020 return file_not_found; 02021 break; 02022 case RA8875::WRITE: 02023 //pc.printf(" Write %4u bytes\r\n", size); 02024 fwrite(buffer, 1, size, _printFH); 02025 break; 02026 case RA8875::CLOSE: 02027 //pc.printf(" close\r\n"); 02028 fclose(_printFH); 02029 _printFH = 0; 02030 break; 02031 default: 02032 //pc.printf("Unexpected callback %d\r\n", cmd); 02033 return file_not_found; 02034 //break; 02035 } 02036 return noerror; 02037 } 02038 02039 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h) 02040 { 02041 BITMAPFILEHEADER BMP_Header; 02042 BITMAPINFOHEADER BMP_Info; 02043 uint8_t * lineBuffer = NULL; 02044 color_t * pixelBuffer = NULL; 02045 color_t * pixelBuffer2 = NULL; 02046 02047 INFO("(%d,%d) - (%d,%d)", x,y,w,h); 02048 if (x >= 0 && x < screenwidth 02049 && y >= 0 && y < screenheight 02050 && w > 0 && x + w <= screenwidth 02051 && h > 0 && y + h <= screenheight) { 02052 02053 BMP_Header.bfType = BF_TYPE; 02054 BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header); 02055 BMP_Header.bfReserved1 = 0; 02056 BMP_Header.bfReserved2 = 0; 02057 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header); 02058 02059 BMP_Info.biSize = sizeof(BMP_Info); 02060 BMP_Info.biWidth = w; 02061 BMP_Info.biHeight = h; 02062 BMP_Info.biPlanes = 1; 02063 BMP_Info.biBitCount = 24; 02064 BMP_Info.biCompression = BI_RGB; 02065 BMP_Info.biSizeImage = 0; 02066 BMP_Info.biXPelsPerMeter = 0; 02067 BMP_Info.biYPelsPerMeter = 0; 02068 BMP_Info.biClrUsed = 0; 02069 BMP_Info.biClrImportant = 0; 02070 02071 // Allocate the memory we need to proceed 02072 int lineBufSize = ((24 * w + 7)/8); 02073 lineBuffer = (uint8_t *)swMalloc(lineBufSize); 02074 if (lineBuffer == NULL) { 02075 ERR("Not enough RAM for PrintScreen lineBuffer"); 02076 return(not_enough_ram); 02077 } 02078 02079 #define DOUBLEBUF /* one larger buffer instead of two */ 02080 02081 #ifdef DOUBLEBUF 02082 // In the "#else", pixelBuffer2 malloc returns a value, 02083 // but is actually causing a failure later. 02084 // This test helps determine if it is truly out of memory, 02085 // or if malloc is broken. 02086 pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t)); 02087 pixelBuffer2 = pixelBuffer + (w * sizeof(color_t)); 02088 #else 02089 pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t)); 02090 pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t)); 02091 #endif 02092 if (pixelBuffer == NULL || pixelBuffer2 == NULL) { 02093 ERR("Not enough RAM for pixelBuffer"); 02094 #ifndef DOUBLEBUF 02095 if (pixelBuffer2) 02096 swFree(pixelBuffer2); 02097 #endif 02098 if (pixelBuffer) 02099 swFree(pixelBuffer); 02100 swFree(lineBuffer); 02101 return(not_enough_ram); 02102 } 02103 02104 // Get the file primed... 02105 privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4); 02106 02107 // Be optimistic - don't check for errors. 02108 HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02109 //fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image); 02110 privateCallback(WRITE, (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02111 02112 HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02113 //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image); 02114 privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02115 02116 //color_t transparency = GetBackgroundTransparencyColor(); 02117 LayerMode_T ltpr0 = GetLayerMode(); 02118 02119 uint16_t prevLayer = GetDrawingLayer(); 02120 // If only one of the layers is visible, select that layer 02121 switch(ltpr0) { 02122 case ShowLayer0: 02123 SelectDrawingLayer(0); 02124 break; 02125 case ShowLayer1: 02126 SelectDrawingLayer(1); 02127 break; 02128 default: 02129 break; 02130 } 02131 02132 // Read the display from the last line toward the top 02133 // so we can write the file in one pass. 02134 for (int j = h - 1; j >= 0; j--) { 02135 if (ltpr0 >= 2) // Need to combine the layers... 02136 SelectDrawingLayer(0); // so read layer 0 first 02137 // Read one line of pixels to a local buffer 02138 if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) { 02139 ERR("getPixelStream error, and no recovery handler..."); 02140 } 02141 if (ltpr0 >= 2) { // Need to combine the layers... 02142 SelectDrawingLayer(1); // so read layer 1 next 02143 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) { 02144 ERR("getPixelStream error, and no recovery handler..."); 02145 } 02146 } 02147 INFO("1st Color: %04X", pixelBuffer[0]); 02148 HexDump("Raster", (uint8_t *)pixelBuffer, w); 02149 // Convert the local buffer to RGBQUAD format 02150 int lb = 0; 02151 for (int i=0; i<w; i++) { 02152 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]); // Scale to 24-bits 02153 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]); // Scale to 24-bits 02154 switch (ltpr0) { 02155 case 0: 02156 case 1: 02157 case 2: // lighten-overlay (@TODO Not supported yet) 02158 case 6: // Floating Windows (@TODO not sure how to support) 02159 default: // Reserved... 02160 lineBuffer[lb++] = q0.rgbBlue; 02161 lineBuffer[lb++] = q0.rgbGreen; 02162 lineBuffer[lb++] = q0.rgbRed; 02163 break; 02164 case 3: // transparent mode (@TODO Read the background color register for transparent) 02165 case 4: // boolean or 02166 lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue; 02167 lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen; 02168 lineBuffer[lb++] = q0.rgbRed | q1.rgbRed; 02169 break; 02170 case 5: // boolean AND 02171 lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue; 02172 lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen; 02173 lineBuffer[lb++] = q0.rgbRed & q1.rgbRed; 02174 break; 02175 } 02176 } 02177 if (j == h - 1) { 02178 HexDump("Line", lineBuffer, lineBufSize); 02179 } 02180 // Write to disk 02181 //fwrite(lineBuffer, sizeof(char), lb, Image); 02182 privateCallback(WRITE, (uint8_t *)lineBuffer, lb); 02183 } 02184 SelectDrawingLayer(prevLayer); 02185 //fclose(Image); 02186 privateCallback(CLOSE, NULL, 0); 02187 02188 #ifndef DOUBLEBUF 02189 if (pixelBuffer2) 02190 swFree(pixelBuffer2); 02191 #endif 02192 if (pixelBuffer) 02193 swFree(pixelBuffer); 02194 swFree(lineBuffer); 02195 INFO("Image closed"); 02196 return noerror; 02197 } else { 02198 return bad_parameter; 02199 } 02200 } 02201 02202 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP) 02203 { 02204 BITMAPFILEHEADER BMP_Header; 02205 BITMAPINFOHEADER BMP_Info; 02206 uint8_t * lineBuffer = NULL; 02207 color_t * pixelBuffer = NULL; 02208 color_t * pixelBuffer2 = NULL; 02209 02210 INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP); 02211 if (x >= 0 && x < screenwidth 02212 && y >= 0 && y < screenheight 02213 && w > 0 && x + w <= screenwidth 02214 && h > 0 && y + h <= screenheight) { 02215 02216 BMP_Header.bfType = BF_TYPE; 02217 BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header); 02218 BMP_Header.bfReserved1 = 0; 02219 BMP_Header.bfReserved2 = 0; 02220 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header); 02221 02222 BMP_Info.biSize = sizeof(BMP_Info); 02223 BMP_Info.biWidth = w; 02224 BMP_Info.biHeight = h; 02225 BMP_Info.biPlanes = 1; 02226 BMP_Info.biBitCount = 24; 02227 BMP_Info.biCompression = BI_RGB; 02228 BMP_Info.biSizeImage = 0; 02229 BMP_Info.biXPelsPerMeter = 0; 02230 BMP_Info.biYPelsPerMeter = 0; 02231 BMP_Info.biClrUsed = 0; 02232 BMP_Info.biClrImportant = 0; 02233 02234 // Allocate the memory we need to proceed 02235 int lineBufSize = ((24 * w + 7)/8); 02236 lineBuffer = (uint8_t *)swMalloc(lineBufSize); 02237 if (lineBuffer == NULL) { 02238 ERR("Not enough RAM for PrintScreen lineBuffer"); 02239 return(not_enough_ram); 02240 } 02241 02242 #define DOUBLEBUF /* one larger buffer instead of two */ 02243 02244 #ifdef DOUBLEBUF 02245 // In the "#else", pixelBuffer2 malloc returns a value, 02246 // but is actually causing a failure later. 02247 // This test helps determine if it is truly out of memory, 02248 // or if malloc is broken. 02249 pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t)); 02250 pixelBuffer2 = pixelBuffer + (w * sizeof(color_t)); 02251 #else 02252 pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t)); 02253 pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t)); 02254 #endif 02255 if (pixelBuffer == NULL || pixelBuffer2 == NULL) { 02256 ERR("Not enough RAM for pixelBuffer"); 02257 #ifndef DOUBLEBUF 02258 if (pixelBuffer2) 02259 swFree(pixelBuffer2); 02260 #endif 02261 if (pixelBuffer) 02262 swFree(pixelBuffer); 02263 swFree(lineBuffer); 02264 return(not_enough_ram); 02265 } 02266 02267 FILE *Image = fopen(Name_BMP, "wb"); 02268 if (!Image) { 02269 ERR("Can't open file for write"); 02270 #ifndef DOUBLEBUF 02271 if (pixelBuffer2) 02272 swFree(pixelBuffer2); 02273 #endif 02274 if (pixelBuffer) 02275 swFree(pixelBuffer); 02276 swFree(lineBuffer); 02277 return(file_not_found); 02278 } 02279 02280 // Be optimistic - don't check for errors. 02281 HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02282 fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image); 02283 02284 HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02285 fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image); 02286 02287 //color_t transparency = GetBackgroundTransparencyColor(); 02288 LayerMode_T ltpr0 = GetLayerMode(); 02289 02290 uint16_t prevLayer = GetDrawingLayer(); 02291 // If only one of the layers is visible, select that layer 02292 switch(ltpr0) { 02293 case ShowLayer0: 02294 SelectDrawingLayer(0); 02295 break; 02296 case ShowLayer1: 02297 SelectDrawingLayer(1); 02298 break; 02299 default: 02300 break; 02301 } 02302 02303 // Read the display from the last line toward the top 02304 // so we can write the file in one pass. 02305 for (int j = h - 1; j >= 0; j--) { 02306 if (ltpr0 >= 2) // Need to combine the layers... 02307 SelectDrawingLayer(0); // so read layer 0 first 02308 // Read one line of pixels to a local buffer 02309 if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) { 02310 ERR("getPixelStream error, and no recovery handler..."); 02311 } 02312 if (ltpr0 >= 2) { // Need to combine the layers... 02313 SelectDrawingLayer(1); // so read layer 1 next 02314 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) { 02315 ERR("getPixelStream error, and no recovery handler..."); 02316 } 02317 } 02318 INFO("1st Color: %04X", pixelBuffer[0]); 02319 HexDump("Raster", (uint8_t *)pixelBuffer, w); 02320 // Convert the local buffer to RGBQUAD format 02321 int lb = 0; 02322 for (int i=0; i<w; i++) { 02323 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]); // Scale to 24-bits 02324 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]); // Scale to 24-bits 02325 switch (ltpr0) { 02326 case 0: 02327 case 1: 02328 case 2: // lighten-overlay (@TODO Not supported yet) 02329 case 6: // Floating Windows (@TODO not sure how to support) 02330 default: // Reserved... 02331 lineBuffer[lb++] = q0.rgbBlue; 02332 lineBuffer[lb++] = q0.rgbGreen; 02333 lineBuffer[lb++] = q0.rgbRed; 02334 break; 02335 case 3: // transparent mode (@TODO Read the background color register for transparent) 02336 case 4: // boolean or 02337 lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue; 02338 lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen; 02339 lineBuffer[lb++] = q0.rgbRed | q1.rgbRed; 02340 break; 02341 case 5: // boolean AND 02342 lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue; 02343 lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen; 02344 lineBuffer[lb++] = q0.rgbRed & q1.rgbRed; 02345 break; 02346 } 02347 } 02348 if (j == h - 1) { 02349 HexDump("Line", lineBuffer, lineBufSize); 02350 } 02351 // Write to disk 02352 fwrite(lineBuffer, sizeof(char), lb, Image); 02353 } 02354 SelectDrawingLayer(prevLayer); 02355 fclose(Image); 02356 #ifndef DOUBLEBUF 02357 if (pixelBuffer2) 02358 swFree(pixelBuffer2); 02359 #endif 02360 if (pixelBuffer) 02361 swFree(pixelBuffer); 02362 swFree(lineBuffer); 02363 INFO("Image closed"); 02364 return noerror; 02365 } else { 02366 return bad_parameter; 02367 } 02368 } 02369 02370 02371 // ########################################################################## 02372 // ########################################################################## 02373 // ########################################################################## 02374 02375 #ifdef TESTENABLE 02376 02377 #include "BPG_Arial08x08.h" 02378 #include "BPG_Arial20x20.h" 02379 02380 // ______________ ______________ ______________ _______________ 02381 // /_____ _____/ / ___________/ / ___________/ /_____ ______/ 02382 // / / / / / / / / 02383 // / / / /___ / /__________ / / 02384 // / / / ____/ /__________ / / / 02385 // / / / / / / / / 02386 // / / / /__________ ___________/ / / / 02387 // /__/ /_____________/ /_____________/ /__/ 02388 // 02389 // Everything from here down is test code. 02390 // 02391 bool SuppressSlowStuff = false; 02392 02393 void TextWrapTest(RA8875 & display, Serial & pc) 02394 { 02395 if (!SuppressSlowStuff) 02396 pc.printf("Text Wrap Test\r\n"); 02397 display.background(Black); 02398 display.foreground(Blue); 02399 display.cls(); 02400 display.Backlight_u8(255); 02401 display.puts("Text Wrap Test.\r\n"); 02402 for (int i=1; i<60; i++) { 02403 display.printf("L%2d\n", i % 17); 02404 if (!SuppressSlowStuff) 02405 wait_ms(100); 02406 } 02407 if (!SuppressSlowStuff) 02408 wait_ms(3000); 02409 } 02410 02411 02412 void ShowKey(RA8875 & display, int key) 02413 { 02414 loc_t col, row; 02415 dim_t r1 = 25; 02416 color_t color = (key & 0x80) ? Red : Green; 02417 02418 key &= 0x7F; // remove the long-press flag 02419 row = (key - 1) / 5; 02420 col = (key - 1) % 5; 02421 if (col > 5) col = 5; 02422 if (row > 4) row = 4; 02423 display.circle(450 - + (2 * r1) * col, 200 - (2 * r1) * row, r1-2, color, FILL); 02424 } 02425 02426 void HideKey(RA8875 & display, int key) 02427 { 02428 loc_t col, row; 02429 dim_t r1 = 25; 02430 02431 row = (key - 1) / 5; 02432 col = (key - 1) % 5; 02433 if (col > 5) col = 5; 02434 if (row > 4) row = 4; 02435 display.background(Black); 02436 display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Black, FILL); 02437 display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Blue); 02438 } 02439 02440 void KeyPadTest(RA8875 & display, Serial & pc) 02441 { 02442 const uint8_t myMap[22] = { 02443 0, 02444 'a', 'b', 'c', 'd', 'e', 02445 'f', 'g', 'h', 'i', 'j', 02446 'k', 'l', 'm', 'n', 'o', 02447 'p', 'q', 'r', 's', 't', 02448 'x' 02449 }; 02450 02451 display.background(Black); 02452 display.foreground(Blue); 02453 display.cls(); 02454 display.Backlight_u8(255); 02455 display.puts("KeyPad Test. Touch the keypad..."); 02456 pc.printf("\r\n" 02457 "Raw KeyPad Test. Keypad returns the key-number.\r\n" 02458 "Press [most] any PC keyboard key to advance to next test.\r\n"); 02459 RetCode_t ret = display.KeypadInit(true, true, 3, 7, 3); 02460 if (ret != noerror) 02461 pc.printf("returncode from KeypadInit is %d\r\n", ret); 02462 int lastKey = 0; 02463 while (!pc.readable()) { 02464 if (display.readable()) { 02465 int key = display.getc(); 02466 if (key) { 02467 if (((key & 0x7F) != lastKey) && (lastKey != 0)) 02468 HideKey(display, lastKey); 02469 ShowKey(display, key); 02470 lastKey = key & 0x7F; 02471 } else { 02472 // erase the last one 02473 if (lastKey) 02474 HideKey(display, lastKey); 02475 } 02476 } 02477 } 02478 (void)pc.getc(); 02479 pc.printf("\r\n" 02480 "Map KeyPad Test. Keypad returns the remapped key 'a' - 't'.\r\n" 02481 "Press [most] any PC keyboard key to advance to exit test.\r\n"); 02482 display.SetKeyMap(myMap); 02483 while (!pc.readable()) { 02484 if (display.readable()) { 02485 int key = display.getc(); 02486 bool longPress = key & 0x80; 02487 display.SetTextCursor(0, 120); 02488 display.printf("Long Press: %d\r\n", longPress); 02489 display.printf(" Remapped: %c %02X\r\n", (key) ? key & 0x7F : ' ', key); 02490 } 02491 } 02492 (void)pc.getc(); 02493 display.SetKeyMap(); 02494 pc.printf("\r\n"); 02495 } 02496 02497 void TextCursorTest(RA8875 & display, Serial & pc) 02498 { 02499 const char * iCursor = "The I-Beam cursor should be visible for this text.\r\n"; 02500 const char * uCursor = "The Underscore cursor should be visible for this text.\r\n"; 02501 const char * bCursor = "The Block cursor should be visible for this text.\r\n"; 02502 const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n"; 02503 const char * p; 02504 int delay = 60; 02505 02506 if (!SuppressSlowStuff) 02507 pc.printf("Text Cursor Test\r\n"); 02508 else 02509 delay = 0; 02510 display.background(Black); 02511 display.foreground(Blue); 02512 display.cls(); 02513 display.Backlight_u8(255); 02514 display.puts("Text Cursor Test."); 02515 02516 // visible, non-blinking 02517 display.SetTextCursor(0,20); 02518 display.SetTextCursorControl(RA8875::IBEAM, false); 02519 p = iCursor; 02520 while (*p) { 02521 display._putc(*p++); 02522 wait_ms(delay); 02523 } 02524 02525 display.SetTextCursorControl(RA8875::UNDER, false); 02526 p = uCursor; 02527 while (*p) { 02528 display._putc(*p++); 02529 wait_ms(delay); 02530 } 02531 02532 display.SetTextCursorControl(RA8875::BLOCK, false); 02533 p = bCursor; 02534 while (*p) { 02535 display._putc(*p++); 02536 wait_ms(delay); 02537 } 02538 02539 display.SetTextCursorControl(RA8875::BLOCK, true); 02540 p = bbCursor; 02541 while (*p) { 02542 display._putc(*p++); 02543 wait_ms(delay); 02544 } 02545 wait_ms(delay * 20); 02546 display.SetTextCursorControl(RA8875::NOCURSOR, false); 02547 } 02548 02549 02550 void BacklightTest(RA8875 & display, Serial & pc, float ramptime) 02551 { 02552 char buf[60]; 02553 unsigned int w = (ramptime * 1000)/ 256; 02554 int delay = 200; 02555 02556 if (!SuppressSlowStuff) 02557 pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime); 02558 else { 02559 delay = 0; 02560 w = 0; 02561 } 02562 display.Backlight_u8(0); 02563 display.background(White); 02564 display.foreground(Blue); 02565 display.cls(); 02566 display.puts("RA8875 Backlight Test - Ramp up."); 02567 wait_ms(delay); 02568 for (int i=0; i <= 255; i++) { 02569 snprintf(buf, sizeof(buf), "%3d, %4d", i, w); 02570 display.puts(100,100,buf); 02571 display.Backlight_u8(i); 02572 wait_ms(w); 02573 } 02574 } 02575 02576 02577 void BacklightTest2(RA8875 & display, Serial & pc) 02578 { 02579 int delay = 20; 02580 02581 if (!SuppressSlowStuff) 02582 pc.printf("Backlight Test 2\r\n"); 02583 else 02584 delay = 0; 02585 02586 // Dim it out at the end of the tests. 02587 display.foreground(Blue); 02588 display.puts(0,0, "Ramp Backlight down."); 02589 // Ramp it off 02590 for (int i=255; i != 0; i--) { 02591 display.Backlight_u8(i); 02592 wait_ms(delay); 02593 } 02594 display.Backlight_u8(0); 02595 } 02596 02597 02598 void ExternalFontTest(RA8875 & display, Serial & pc) 02599 { 02600 if (!SuppressSlowStuff) 02601 pc.printf("External Font Test\r\n"); 02602 display.background(Black); 02603 display.foreground(Blue); 02604 display.cls(); 02605 display.puts("External Font Test."); 02606 display.Backlight(1); 02607 02608 display.SelectUserFont(BPG_Arial08x08); 02609 display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); 02610 02611 display.SelectUserFont(BPG_Arial20x20); 02612 display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); 02613 02614 display.SelectUserFont(); 02615 02616 display.puts("Normal font again."); 02617 //display.window(0,0, display.width(), display.height()); 02618 } 02619 02620 02621 void DOSColorTest(RA8875 & display, Serial & pc) 02622 { 02623 if (!SuppressSlowStuff) 02624 pc.printf("DOS Color Test\r\n"); 02625 display.background(Black); 02626 display.foreground(Blue); 02627 display.cls(); 02628 display.puts("DOS Colors - Fore"); 02629 display.puts(280,0, "Back"); 02630 display.background(Gray); 02631 for (int i=0; i<16; i++) { 02632 display.foreground(display.DOSColor(i)); 02633 display.puts(160, i*16, display.DOSColorNames(i)); 02634 display.background(Black); 02635 } 02636 display.foreground(White); 02637 for (int i=0; i<16; i++) { 02638 display.background(display.DOSColor(i)); 02639 display.puts(360, i*16, display.DOSColorNames(i)); 02640 display.foreground(White); 02641 } 02642 } 02643 02644 02645 void WebColorTest(RA8875 & display, Serial & pc) 02646 { 02647 if (!SuppressSlowStuff) 02648 pc.printf("Web Color Test\r\n"); 02649 display.background(Black); 02650 display.foreground(Blue); 02651 display.window(0,0, display.width(), display.height()); 02652 display.cls(); 02653 display.SetTextFontSize(1,1); 02654 display.puts(200,0, "Web Color Test"); 02655 display.SetTextCursor(0,0); 02656 display.puts(" "); 02657 for (int i=0; i<16; i++) 02658 display.printf("%X", i&0xF); 02659 display.puts("\r\n0 "); 02660 for (int i=0; i<sizeof(WebColors)/sizeof(WebColors[0]); i++) { 02661 display.background(WebColors[i]); 02662 display.puts(" "); 02663 if (i % 16 == 15 && i < 255) { 02664 display.printf("\r\n%X ", ((i+1)/16)); 02665 } 02666 } 02667 display.SetTextFontSize(1,1); 02668 } 02669 02670 02671 void PixelTest(RA8875 & display, Serial & pc) 02672 { 02673 int i, c, x, y; 02674 02675 if (!SuppressSlowStuff) 02676 pc.printf("Pixel Test\r\n"); 02677 display.background(Black); 02678 display.foreground(Blue); 02679 display.cls(); 02680 display.puts("Pixel Test"); 02681 for (i=0; i<1000; i++) { 02682 x = rand() % 480; 02683 y = 16 + rand() % (272-16); 02684 c = rand() % 16; 02685 //pc.printf(" (%d,%d) - %d\r\n", x,y,r1); 02686 display.pixel(x,y, display.DOSColor(c)); 02687 } 02688 } 02689 02690 02691 void LineTest(RA8875 & display, Serial & pc) 02692 { 02693 int i, x, y, x2, y2; 02694 02695 if (!SuppressSlowStuff) 02696 pc.printf("Line Test\r\n"); 02697 display.background(Black); 02698 display.foreground(Blue); 02699 display.cls(); 02700 display.puts("Line Test"); 02701 for (i=0; i<16; i++) { 02702 // Lines 02703 x = rand() % 480; 02704 y = rand() % 272; 02705 x2 = rand() % 480; 02706 y2 = rand() % 272; 02707 display.line(x,y, x2,y2, display.DOSColor(i)); 02708 } 02709 display.foreground(BrightRed); 02710 display.foreground(BrightGreen); 02711 display.foreground(BrightBlue); 02712 display.line(55,50, 79,74, BrightRed); 02713 display.line(57,50, 81,74, BrightGreen); 02714 display.line(59,50, 83,74, BrightBlue); 02715 // horz 02716 display.line(30,40, 32,40, BrightRed); 02717 display.line(30,42, 32,42, BrightGreen); 02718 display.line(30,44, 32,44, BrightBlue); 02719 // vert 02720 display.line(20,40, 20,42, BrightRed); 02721 display.line(22,40, 22,42, BrightGreen); 02722 display.line(24,40, 24,42, BrightBlue); 02723 // compare point to line-point 02724 display.pixel(20,50, BrightRed); 02725 display.pixel(22,50, BrightGreen); 02726 display.pixel(24,50, BrightBlue); 02727 display.line(20,52, 20,52, BrightRed); 02728 display.line(22,52, 22,52, BrightGreen); 02729 display.line(24,52, 24,52, BrightBlue); 02730 02731 // point 02732 display.line(50,50, 50,50, Red); 02733 display.line(52,52, 52,52, Green); 02734 display.line(54,54, 54,54, Blue); 02735 display.line(60,60, 60,60, BrightRed); 02736 display.line(62,62, 62,62, BrightGreen); 02737 display.line(64,64, 64,64, BrightBlue); 02738 display.line(70,70, 70,70, DarkRed); 02739 display.line(72,72, 72,72, DarkGreen); 02740 display.line(74,74, 74,74, DarkBlue); 02741 } 02742 02743 02744 void RectangleTest(RA8875 & display, Serial & pc) 02745 { 02746 int i, x1,y1, x2,y2; 02747 02748 if (!SuppressSlowStuff) 02749 pc.printf("Rectangle Test\r\n"); 02750 display.background(Black); 02751 display.foreground(Blue); 02752 display.cls(); 02753 display.puts("Rectangle Test"); 02754 for (i=0; i<16; i++) { 02755 x1 = rand() % 240; 02756 y1 = 50 + rand() % 200; 02757 x2 = rand() % 240; 02758 y2 = 50 + rand() % 200; 02759 display.rect(x1,y1, x2,y2, display.DOSColor(i)); 02760 02761 x1 = 240 + rand() % 240; 02762 y1 = 50 + rand() % 200; 02763 x2 = 240 + rand() % 240; 02764 y2 = 50 + rand() % 200; 02765 display.rect(x1,y1, x2,y2, FILL); 02766 } 02767 } 02768 02769 02770 void LayerTest(RA8875 & display, Serial & pc) 02771 { 02772 loc_t i, x1,y1, x2,y2, r1,r2; 02773 02774 if (!SuppressSlowStuff) 02775 pc.printf("Layer Test\r\n"); 02776 02777 display.SelectDrawingLayer(0); 02778 display.background(Black); 02779 display.foreground(Blue); 02780 display.cls(); 02781 display.puts("Layer 0"); 02782 for (i=0; i<16; i++) { 02783 x1 = rand() % 240; 02784 y1 = 50 + rand() % 200; 02785 x2 = x1 + rand() % 100; 02786 y2 = y1 + rand() % 100; 02787 r1 = rand() % (x2 - x1)/2; 02788 r2 = rand() % (y2 - y1)/2; 02789 display.roundrect(x1,y1, x2,y2, r1,r2, display.DOSColor(i)); 02790 if (!SuppressSlowStuff) 02791 wait_ms(20); 02792 } 02793 if (!SuppressSlowStuff) 02794 wait_ms(1000); 02795 02796 display.SelectDrawingLayer(1); 02797 display.background(Black); 02798 display.foreground(Yellow); 02799 display.cls(); 02800 display.puts(240,0, "Layer 1"); 02801 for (i=0; i<16; i++) { 02802 x1 = 300 + rand() % 100; 02803 y1 = 70 + rand() % 200; 02804 r1 = rand() % min(y1 - 20, 100); 02805 display.circle(x1,y1,r1, display.DOSColor(i)); 02806 if (!SuppressSlowStuff) 02807 wait_ms(20); 02808 } 02809 display.SetLayerMode(RA8875::ShowLayer1); // Show it after the build-up 02810 if (!SuppressSlowStuff) 02811 wait_ms(2000); 02812 02813 display.SelectDrawingLayer(0); 02814 display.SetLayerMode(RA8875::ShowLayer0); // Show Layer 0 again 02815 if (!SuppressSlowStuff) 02816 wait_ms(1000); 02817 display.SetLayerMode(RA8875::TransparentMode); // Transparent mode 02818 if (!SuppressSlowStuff) 02819 wait_ms(1000); 02820 for (i=0; i<=8; i++) { 02821 display.SetLayerTransparency(i, 8-i); 02822 if (!SuppressSlowStuff) 02823 wait_ms(200); 02824 } 02825 02826 // Restore before we exit 02827 display.SetLayerTransparency(0, 0); 02828 display.SetLayerMode(RA8875::ShowLayer0); // Restore to layer 0 02829 } 02830 02831 02832 void RoundRectTest(RA8875 & display, Serial & pc) 02833 { 02834 loc_t i, x1,y1, x2,y2, r1,r2; 02835 02836 if (!SuppressSlowStuff) 02837 pc.printf("Round Rectangle Test\r\n"); 02838 display.background(Black); 02839 display.foreground(Blue); 02840 display.cls(); 02841 display.puts("Rounded Rectangle Test"); 02842 02843 for (i=0; i<16; i++) { 02844 x1 = rand() % 240; 02845 y1 = 50 + rand() % 200; 02846 x2 = x1 + rand() % 100; 02847 y2 = y1 + rand() % 100; 02848 r1 = rand() % (x2 - x1)/2; 02849 r2 = rand() % (y2 - y1)/2; 02850 display.roundrect(x1,y1, x2,y2, 5,8, display.DOSColor(i)); 02851 02852 x1 = 240 + rand() % 240; 02853 y1 = 50 + rand() % 200; 02854 x2 = x1 + rand() % 100; 02855 y2 = y1 + rand() % 100; 02856 r1 = rand() % (x2 - x1)/2; 02857 r2 = rand() % (y2 - y1)/2; 02858 display.roundrect(x1,y1, x2,y2, r1,r2, FILL); 02859 } 02860 } 02861 02862 02863 void TriangleTest(RA8875 & display, Serial & pc) 02864 { 02865 int i, x1, y1, x2, y2, x3, y3; 02866 02867 if (!SuppressSlowStuff) 02868 pc.printf("Triangle Test\r\n"); 02869 display.background(Black); 02870 display.foreground(Blue); 02871 display.cls(); 02872 display.puts(0,0, "Triangle Test"); 02873 02874 x1 = 150; 02875 y1 = 2; 02876 x2 = 190; 02877 y2 = 7; 02878 x3 = 170; 02879 y3 = 16; 02880 display.triangle(x1,y1, x2,y2, x3,y3); 02881 02882 x1 = 200; 02883 y1 = 2; 02884 x2 = 240; 02885 y2 = 7; 02886 x3 = 220; 02887 y3 = 16; 02888 display.filltriangle(x1,y1, x2,y2, x3,y3, BrightRed); 02889 02890 x1 = 300; 02891 y1 = 2; 02892 x2 = 340; 02893 y2 = 7; 02894 x3 = 320; 02895 y3 = 16; 02896 display.triangle(x1,y1, x2,y2, x3,y3, NOFILL); 02897 02898 x1 = 400; 02899 y1 = 2; 02900 x2 = 440; 02901 y2 = 7; 02902 x3 = 420; 02903 y3 = 16; 02904 display.triangle(x1,y1, x2,y2, x3,y3, Blue); 02905 02906 for (i=0; i<16; i++) { 02907 x1 = rand() % 240; 02908 y1 = 50 + rand() % 200; 02909 x2 = rand() % 240; 02910 y2 = 50 + rand() % 200; 02911 x3 = rand() % 240; 02912 y3 = 50 + rand() % 200; 02913 display.triangle(x1,y1, x2,y2, x3,y3, display.DOSColor(i)); 02914 x1 = 240 + rand() % 240; 02915 y1 = 50 + rand() % 200; 02916 x2 = 240 + rand() % 240; 02917 y2 = 50 + rand() % 200; 02918 x3 = 240 + rand() % 240; 02919 y3 = 50 + rand() % 200; 02920 display.triangle(x1,y1, x2,y2, x3,y3, FILL); 02921 } 02922 } 02923 02924 02925 void CircleTest(RA8875 & display, Serial & pc) 02926 { 02927 int i, x, y, r1; 02928 02929 if (!SuppressSlowStuff) 02930 pc.printf("Circle Test\r\n"); 02931 display.background(Black); 02932 display.foreground(Blue); 02933 display.cls(); 02934 display.puts("Circle Test"); 02935 for (i=0; i<16; i++) { 02936 x = 100 + rand() % 100; 02937 y = 70 + rand() % 200; 02938 r1 = rand() % min(y - 20, 100); 02939 //pc.printf(" (%d,%d) - %d\r\n", x,y,r1); 02940 display.circle(x,y,r1, display.DOSColor(i)); 02941 02942 x = 300 + rand() % 100; 02943 y = 70 + rand() % 200; 02944 r1 = rand() % min(y - 20, 100); 02945 //pc.printf(" (%d,%d) - %d FILL\r\n", x,y,r1); 02946 display.circle(x,y,r1, display.DOSColor(i), FILL); 02947 } 02948 } 02949 02950 02951 void EllipseTest(RA8875 & display, Serial & pc) 02952 { 02953 int i,x,y,r1,r2; 02954 02955 if (!SuppressSlowStuff) 02956 pc.printf("Ellipse Test\r\n"); 02957 display.background(Black); 02958 display.foreground(Blue); 02959 display.cls(); 02960 display.puts("Ellipse Test"); 02961 for (i=0; i<16; i++) { 02962 x = 100 + rand() % 100; 02963 y = 70 + rand() % 200; 02964 r1 = rand() % min(y - 20, 100); 02965 r2 = rand() % min(y - 20, 100); 02966 display.ellipse(x,y,r1,r2, display.DOSColor(i)); 02967 02968 x = 300 + rand() % 100; 02969 y = 70 + rand() % 200; 02970 r1 = rand() % min(y - 20, 100); 02971 r2 = rand() % min(y - 20, 100); 02972 display.ellipse(x,y,r1,r2, FILL); 02973 } 02974 } 02975 02976 02977 void TestGraphicsBitmap(RA8875 & display, Serial & pc) 02978 { 02979 LocalFileSystem local("local"); 02980 if (!SuppressSlowStuff) 02981 pc.printf("Bitmap File Load\r\n"); 02982 display.background(Black); 02983 display.foreground(Blue); 02984 display.cls(); 02985 display.puts("Graphics Test, loading /local/TestPat.bmp"); 02986 wait(3); 02987 02988 int r = display.RenderBitmapFile(0,0, "/local/TestPat.bmp"); 02989 if (!SuppressSlowStuff) 02990 pc.printf(" returned %d\r\n", r); 02991 } 02992 02993 02994 void TouchPanelTest(RA8875 & display, Serial & pc) 02995 { 02996 Timer t; 02997 int x, y; 02998 tpMatrix_t calmatrix; 02999 03000 display.background(Black); 03001 display.foreground(Blue); 03002 display.cls(); 03003 display.puts("Touch Panel Test\r\n"); 03004 pc.printf("Touch Panel Test\r\n"); 03005 display.TouchPanelInit(); 03006 pc.printf(" TP: c - calibrate, r - restore, t - test\r\n"); 03007 int c = pc.getc(); 03008 if (c == 'c') { 03009 point_t pTest[3] = 03010 { { 50, 50 }, {450, 150}, {225,250} }; 03011 point_t pSample[3]; 03012 for (int i=0; i<3; i++) { 03013 display.foreground(Blue); 03014 display.printf(" (%3d,%3d) => ", pTest[i].x, pTest[i].y); 03015 display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, White); 03016 display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, White); 03017 while (!display.TouchPanelA2DFiltered(&x, &y)) 03018 wait_ms(20); 03019 pSample[i].x = x; 03020 pSample[i].y = y; 03021 display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, Black); 03022 display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, Black); 03023 display.foreground(Blue); 03024 display.printf(" (%4d,%4d)\r\n", x,y); 03025 while (display.TouchPanelA2DFiltered(&x, &y)) 03026 wait_ms(20); 03027 wait(2); 03028 } 03029 display.TouchPanelComputeCalibration(pTest, pSample, &calmatrix); 03030 display.printf(" Writing calibration to tpcal.cfg\r\n"); 03031 FILE * fh = fopen("/local/tpcal.cfg", "wb"); 03032 if (fh) { 03033 fwrite(&calmatrix, sizeof(calmatrix), 1, fh); 03034 fclose(fh); 03035 } 03036 display.printf(" Calibration is complete."); 03037 } else if (c == 'r') { 03038 display.printf(" Reading calibration from tpcal.cfg\r\n"); 03039 FILE * fh = fopen("/local/tpcal.cfg", "rb"); 03040 if (fh) { 03041 fread(&calmatrix, sizeof(calmatrix), 1, fh); 03042 fclose(fh); 03043 } 03044 display.printf(" Calibration is complete."); 03045 display.TouchPanelSetMatrix(&calmatrix); 03046 } 03047 t.start(); 03048 do { 03049 point_t point = {0, 0}; 03050 if (display.TouchPanelReadable(&point)) { 03051 display.pixel(point.x, point.y, Red); 03052 } 03053 } while (t.read_ms() < 30000); 03054 pc.printf(">"); 03055 } 03056 03057 03058 void SpeedTest(RA8875 & display, Serial & pc) 03059 { 03060 Timer t; 03061 SuppressSlowStuff = true; 03062 pc.printf("\r\nSpeedTest disables delays, runs tests, reports overall time.\r\n"); 03063 t.start(); 03064 // do stuff fast 03065 TextCursorTest(display, pc); 03066 TextWrapTest(display, pc); 03067 BacklightTest(display, pc, 0); 03068 BacklightTest2(display, pc); 03069 ExternalFontTest(display, pc); 03070 DOSColorTest(display, pc); 03071 WebColorTest(display, pc); 03072 PixelTest(display, pc); 03073 LineTest(display, pc); 03074 RectangleTest(display, pc); 03075 RoundRectTest(display, pc); 03076 TriangleTest(display, pc); 03077 CircleTest(display, pc); 03078 EllipseTest(display, pc); 03079 LayerTest(display, pc); 03080 //TestGraphicsBitmap(display, pc); 03081 pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms()); 03082 #ifdef PERF_METRICS 03083 display.ReportPerformance(pc); 03084 #endif 03085 SuppressSlowStuff = false; 03086 } 03087 03088 03089 void PrintScreen(RA8875 & display, Serial & pc) 03090 { 03091 if (!SuppressSlowStuff) 03092 pc.printf("PrintScreen\r\n"); 03093 display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp"); 03094 } 03095 03096 03097 void RunTestSet(RA8875 & lcd, Serial & pc) 03098 { 03099 int q = 0; 03100 int automode = 0; 03101 const unsigned char modelist[] = "BDWtGLlFROTPCEbw"; // auto-test in this order. 03102 03103 while(1) { 03104 pc.printf("\r\n" 03105 "B - Backlight up b - backlight dim\r\n" 03106 "D - DOS Colors W - Web Colors\r\n" 03107 "t - text cursor G - Graphics Bitmap\r\n" 03108 "L - Lines F - external Font\r\n" 03109 "R - Rectangles O - rOund rectangles\r\n" 03110 "T - Triangles P - Pixels \r\n" 03111 "C - Circles E - Ellipses\r\n" 03112 "A - Auto Test mode S - Speed Test\r\n" 03113 "K - Keypad Test s - touch screen test\r\n" 03114 "p - print screen r - reset \r\n" 03115 "l - layer test w - wrapping text \r\n" 03116 #ifdef PERF_METRICS 03117 "0 - clear performance 1 - report performance\r\n" 03118 #endif 03119 "> "); 03120 if (automode == -1 || pc.readable()) { 03121 automode = -1; 03122 q = pc.getc(); 03123 while (pc.readable()) 03124 pc.getc(); 03125 } else if (automode >= 0) { 03126 q = modelist[automode]; 03127 } 03128 switch(q) { 03129 #ifdef PERF_METRICS 03130 case '0': 03131 lcd.ClearPerformance(); 03132 break; 03133 case '1': 03134 lcd.ReportPerformance(pc); 03135 break; 03136 #endif 03137 case 'A': 03138 automode = 0; 03139 break; 03140 case 'B': 03141 BacklightTest(lcd, pc, 2); 03142 break; 03143 case 'b': 03144 BacklightTest2(lcd, pc); 03145 break; 03146 case 'D': 03147 DOSColorTest(lcd, pc); 03148 break; 03149 case 'K': 03150 KeyPadTest(lcd, pc); 03151 break; 03152 case 'W': 03153 WebColorTest(lcd, pc); 03154 break; 03155 case 't': 03156 TextCursorTest(lcd, pc); 03157 break; 03158 case 'w': 03159 TextWrapTest(lcd, pc); 03160 break; 03161 case 'F': 03162 ExternalFontTest(lcd, pc); 03163 break; 03164 case 'L': 03165 LineTest(lcd, pc); 03166 break; 03167 case 'l': 03168 LayerTest(lcd, pc); 03169 break; 03170 case 'R': 03171 RectangleTest(lcd, pc); 03172 break; 03173 case 'O': 03174 RoundRectTest(lcd, pc); 03175 break; 03176 case 'p': 03177 PrintScreen(lcd, pc); 03178 break; 03179 case 'S': 03180 SpeedTest(lcd, pc); 03181 break; 03182 case 's': 03183 TouchPanelTest(lcd, pc); 03184 break; 03185 case 'T': 03186 TriangleTest(lcd, pc); 03187 break; 03188 case 'P': 03189 PixelTest(lcd, pc); 03190 break; 03191 case 'G': 03192 TestGraphicsBitmap(lcd, pc); 03193 break; 03194 case 'C': 03195 CircleTest(lcd, pc); 03196 break; 03197 case 'E': 03198 EllipseTest(lcd, pc); 03199 break; 03200 case 'r': 03201 pc.printf("Resetting ...\r\n"); 03202 wait_ms(20); 03203 mbed_reset(); 03204 break; 03205 case ' ': 03206 break; 03207 default: 03208 printf("huh?\n"); 03209 break; 03210 } 03211 if (automode >= 0) { 03212 automode++; 03213 if (automode >= sizeof(modelist)) 03214 automode = 0; 03215 wait_ms(2000); 03216 } 03217 wait_ms(200); 03218 } 03219 } 03220 03221 #endif // TESTENABLE
Generated on Tue Jul 12 2022 19:25:30 by
