BurstSPI support for improved performance
Fork of RA8875 by
Embed:
(wiki syntax)
Show/hide line numbers
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, 0)) { 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, 0)) { 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, 0)) { 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 01319 _setWriteSpeed(true); 01320 01321 spi.write(0x00); // Cmd: write data 01322 while (h--) { 01323 uint8_t pixels = w; 01324 uint8_t bitmask = 0x01; 01325 01326 while (pixels) { 01327 uint8_t byte = *boolStream; 01328 //INFO("byte, mask: %02X, %02X", byte, bitmask); 01329 color_t c = (byte & bitmask) ? _foreground : _background; 01330 if (screenbpp == 16) { 01331 spi.fastWrite(c >> 8); 01332 spi.fastWrite(c & 0xFF); 01333 } else { 01334 spi.fastWrite(_cvt16to8(c)); 01335 } 01336 bitmask <<= 1; 01337 if (pixels > 1 && bitmask == 0) { 01338 bitmask = 0x01; 01339 boolStream++; 01340 } 01341 pixels--; 01342 } 01343 boolStream++; 01344 } 01345 spi.clearRX(); 01346 _select(false); 01347 _EndGraphicsStream(); 01348 window(restore); 01349 REGISTERPERFORMANCE(PRF_BOOLSTREAM); 01350 return(noerror); 01351 } 01352 01353 color_t RA8875::getPixel(loc_t x, loc_t y) 01354 { 01355 color_t pixel; 01356 01357 PERFORMANCE_RESET; 01358 WriteCommand(0x40,0x00); // Graphics write mode 01359 SetGraphicsCursorRead(x, y); 01360 WriteCommand(0x02); 01361 _select(true); 01362 _spiwrite(0x40); // Cmd: read data 01363 _spiwrite(0x00); // dummy read 01364 if (screenbpp == 16) { 01365 pixel = _spiread(); 01366 pixel |= (_spiread() << 8); 01367 } else { 01368 pixel = _cvt8to16(_spiread()); 01369 } 01370 _select(false); 01371 REGISTERPERFORMANCE(PRF_READPIXEL); 01372 return pixel; 01373 } 01374 01375 01376 RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) 01377 { 01378 color_t pixel; 01379 RetCode_t ret = noerror; 01380 01381 PERFORMANCE_RESET; 01382 ret = WriteCommand(0x40,0x00); // Graphics write mode 01383 ret = SetGraphicsCursorRead(x, y); 01384 ret = WriteCommand(0x02); 01385 _select(true); 01386 _spiwrite(0x40); // Cmd: read data 01387 _spiwrite(0x00); // dummy read 01388 if (screenbpp == 16) 01389 _spiwrite(0x00); // dummy read is only necessary when in 16-bit mode 01390 while (count--) { 01391 if (screenbpp == 16) { 01392 pixel = _spiread(); 01393 pixel |= (_spiread() << 8); 01394 } else { 01395 pixel = _cvt8to16(_spiread()); 01396 } 01397 *p++ = pixel; 01398 } 01399 _select(false); 01400 REGISTERPERFORMANCE(PRF_READPIXELSTREAM); 01401 return ret; 01402 } 01403 01404 01405 RetCode_t RA8875::line(point_t p1, point_t p2) 01406 { 01407 return line(p1.x, p1.y, p2.x, p2.y); 01408 } 01409 01410 01411 RetCode_t RA8875::line(point_t p1, point_t p2, color_t color) 01412 { 01413 return line(p1.x, p1.y, p2.x, p2.y, color); 01414 } 01415 01416 01417 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color) 01418 { 01419 foreground(color); 01420 return line(x1,y1,x2,y2); 01421 } 01422 01423 01424 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2) 01425 { 01426 PERFORMANCE_RESET; 01427 if (x1 == x2 && y1 == y2) { 01428 pixel(x1, y1); 01429 } else { 01430 WriteCommandW(0x91, x1); 01431 WriteCommandW(0x93, y1); 01432 WriteCommandW(0x95, x2); 01433 WriteCommandW(0x97, y2); 01434 unsigned char drawCmd = 0x00; // Line 01435 WriteCommand(0x90, drawCmd); 01436 WriteCommand(0x90, 0x80 + drawCmd); // Start drawing. 01437 if (!_WaitWhileReg(0x90, 0x80)) { 01438 REGISTERPERFORMANCE(PRF_DRAWLINE); 01439 return external_abort; 01440 } 01441 } 01442 REGISTERPERFORMANCE(PRF_DRAWLINE); 01443 return noerror; 01444 } 01445 01446 01447 RetCode_t RA8875::ThickLine(point_t p1, point_t p2, dim_t thickness, color_t color) 01448 { 01449 if (thickness == 1) { 01450 line(p1,p2, color); 01451 } else { 01452 int dx = abs(p2.x-p1.x), sx = p1.x<p2.x ? 1 : -1; 01453 int dy = abs(p2.y-p1.y), sy = p1.y<p2.y ? 1 : -1; 01454 int err = (dx>dy ? dx : -dy)/2, e2; 01455 01456 for (;;) { 01457 fillcircle(p1.x, p1.y, thickness/2, color); 01458 if (p1.x==p2.x && p1.y==p2.y) 01459 break; 01460 e2 = err; 01461 if (e2 >-dx) 01462 { err -= dy; p1.x += sx; } 01463 if (e2 < dy) 01464 { err += dx; p1.y += sy; } 01465 } 01466 } 01467 return noerror; 01468 } 01469 01470 01471 // 01472 // Rectangle functions all mostly helpers to the basic rectangle function 01473 // 01474 01475 RetCode_t RA8875::fillrect(rect_t r, color_t color, fill_t fillit) 01476 { 01477 return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit); 01478 } 01479 01480 RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01481 color_t color, fill_t fillit) 01482 { 01483 return rect(x1,y1,x2,y2,color,fillit); 01484 } 01485 01486 RetCode_t RA8875::rect(rect_t r, color_t color, fill_t fillit) 01487 { 01488 return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit); 01489 } 01490 01491 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01492 color_t color, fill_t fillit) 01493 { 01494 foreground(color); 01495 return rect(x1,y1,x2,y2,fillit); 01496 } 01497 01498 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01499 fill_t fillit) 01500 { 01501 RetCode_t ret = noerror; 01502 PERFORMANCE_RESET; 01503 // check for bad_parameter 01504 if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 01505 || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) { 01506 ret = bad_parameter; 01507 } else { 01508 if (x1 == x2 && y1 == y2) { 01509 pixel(x1, y1); 01510 } else if (x1 == x2) { 01511 line(x1, y1, x2, y2); 01512 } else if (y1 == y2) { 01513 line(x1, y1, x2, y2); 01514 } else { 01515 WriteCommandW(0x91, x1); 01516 WriteCommandW(0x93, y1); 01517 WriteCommandW(0x95, x2); 01518 WriteCommandW(0x97, y2); 01519 unsigned char drawCmd = 0x10; // Rectangle 01520 if (fillit == FILL) 01521 drawCmd |= 0x20; 01522 WriteCommand(0x90, drawCmd); 01523 ret = WriteCommand(0x90, 0x80 + drawCmd); // Start drawing. 01524 if (!_WaitWhileReg(0x90, 0x80)) { 01525 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE); 01526 return external_abort; 01527 } 01528 } 01529 } 01530 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE); 01531 return ret; 01532 } 01533 01534 01535 // 01536 // rounded rectangle functions are mostly helpers to the base round rect 01537 // 01538 01539 RetCode_t RA8875::fillroundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01540 { 01541 return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit); 01542 } 01543 01544 RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01545 dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01546 { 01547 foreground(color); 01548 return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); 01549 } 01550 01551 RetCode_t RA8875::roundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01552 { 01553 return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit); 01554 } 01555 01556 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01557 dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01558 { 01559 foreground(color); 01560 return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); 01561 } 01562 01563 01564 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01565 dim_t radius1, dim_t radius2, fill_t fillit) 01566 { 01567 RetCode_t ret = noerror; 01568 01569 PERFORMANCE_RESET; 01570 if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth 01571 || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight) { 01572 ret = bad_parameter; 01573 } else if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) { 01574 ret = bad_parameter; 01575 } else if (x1 == x2 && y1 == y2) { 01576 pixel(x1, y1); 01577 } else if (x1 == x2) { 01578 line(x1, y1, x2, y2); 01579 } else if (y1 == y2) { 01580 line(x1, y1, x2, y2); 01581 } else { 01582 WriteCommandW(0x91, x1); 01583 WriteCommandW(0x93, y1); 01584 WriteCommandW(0x95, x2); 01585 WriteCommandW(0x97, y2); 01586 WriteCommandW(0xA1, radius1); 01587 WriteCommandW(0xA3, radius2); 01588 // Should not need this... 01589 WriteCommandW(0xA5, 0); 01590 WriteCommandW(0xA7, 0); 01591 unsigned char drawCmd = 0x20; // Rounded Rectangle 01592 if (fillit == FILL) 01593 drawCmd |= 0x40; 01594 WriteCommand(0xA0, drawCmd); 01595 WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing. 01596 if (!_WaitWhileReg(0xA0, 0x80)) { 01597 REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE); 01598 return external_abort; 01599 } 01600 } 01601 REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE); 01602 return ret; 01603 } 01604 01605 01606 // 01607 // triangle functions 01608 // 01609 01610 RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01611 loc_t x3, loc_t y3, color_t color, fill_t fillit) 01612 { 01613 RetCode_t ret; 01614 01615 if (x1 < 0 || x1 >= screenwidth || x2 < 0 || x2 >= screenwidth || x3 < 0 || x3 >= screenwidth 01616 || y1 < 0 || y1 >= screenheight || y2 < 0 || y2 >= screenheight || y3 < 0 || y3 >= screenheight) 01617 ret = bad_parameter; 01618 foreground(color); 01619 ret = triangle(x1,y1,x2,y2,x3,y3,fillit); 01620 return ret; 01621 } 01622 01623 01624 RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 01625 loc_t x3, loc_t y3, color_t color, fill_t fillit) 01626 { 01627 RetCode_t ret; 01628 01629 foreground(color); 01630 ret = triangle(x1,y1,x2,y2,x3,y3,fillit); 01631 return ret; 01632 } 01633 01634 01635 RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2, 01636 loc_t x3, loc_t y3, fill_t fillit) 01637 { 01638 RetCode_t ret = noerror; 01639 01640 PERFORMANCE_RESET; 01641 if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) { 01642 pixel(x1, y1); 01643 } else { 01644 WriteCommandW(0x91, x1); 01645 WriteCommandW(0x93, y1); 01646 WriteCommandW(0x95, x2); 01647 WriteCommandW(0x97, y2); 01648 WriteCommandW(0xA9, x3); 01649 WriteCommandW(0xAB, y3); 01650 unsigned char drawCmd = 0x01; // Triangle 01651 if (fillit == FILL) 01652 drawCmd |= 0x20; 01653 WriteCommand(0x90, drawCmd); 01654 WriteCommand(0x90, 0x80 + drawCmd); // Start drawing. 01655 if (!_WaitWhileReg(0x90, 0x80)) { 01656 REGISTERPERFORMANCE(PRF_DRAWTRIANGLE); 01657 return external_abort; 01658 } 01659 } 01660 REGISTERPERFORMANCE(PRF_DRAWTRIANGLE); 01661 return ret; 01662 } 01663 01664 01665 RetCode_t RA8875::circle(point_t p, dim_t radius, 01666 color_t color, fill_t fillit) 01667 { 01668 foreground(color); 01669 return circle(p.x,p.y,radius,fillit); 01670 } 01671 01672 01673 RetCode_t RA8875::fillcircle(point_t p, dim_t radius, 01674 color_t color, fill_t fillit) 01675 { 01676 foreground(color); 01677 return circle(p.x,p.y,radius,fillit); 01678 } 01679 01680 01681 RetCode_t RA8875::circle(point_t p, dim_t radius, fill_t fillit) 01682 { 01683 return circle(p.x,p.y,radius,fillit); 01684 } 01685 01686 01687 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, 01688 color_t color, fill_t fillit) 01689 { 01690 foreground(color); 01691 return circle(x,y,radius,fillit); 01692 } 01693 01694 01695 RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius, 01696 color_t color, fill_t fillit) 01697 { 01698 foreground(color); 01699 return circle(x,y,radius,fillit); 01700 } 01701 01702 01703 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit) 01704 { 01705 RetCode_t ret = noerror; 01706 01707 PERFORMANCE_RESET; 01708 if (radius <= 0 || (x - radius) < 0 || (x + radius) > screenwidth 01709 || (y - radius) < 0 || (y + radius) > screenheight) { 01710 ret = bad_parameter; 01711 } else if (radius == 1) { 01712 pixel(x,y); 01713 } else { 01714 WriteCommandW(0x99, x); 01715 WriteCommandW(0x9B, y); 01716 WriteCommand(0x9d, radius & 0xFF); 01717 unsigned char drawCmd = 0x00; // Circle 01718 if (fillit == FILL) 01719 drawCmd |= 0x20; 01720 WriteCommand(0x90, drawCmd); 01721 WriteCommand(0x90, 0x40 + drawCmd); // Start drawing. 01722 if (!_WaitWhileReg(0x90, 0x40)) { 01723 REGISTERPERFORMANCE(PRF_DRAWCIRCLE); 01724 return external_abort; 01725 } 01726 } 01727 REGISTERPERFORMANCE(PRF_DRAWCIRCLE); 01728 return ret; 01729 } 01730 01731 01732 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01733 { 01734 foreground(color); 01735 return ellipse(x,y,radius1,radius2,fillit); 01736 } 01737 01738 01739 RetCode_t RA8875::fillellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 01740 { 01741 foreground(color); 01742 return ellipse(x,y,radius1,radius2,fillit); 01743 } 01744 01745 01746 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit) 01747 { 01748 RetCode_t ret = noerror; 01749 01750 PERFORMANCE_RESET; 01751 if (radius1 <= 0 || radius2 <= 0 || (x - radius1) < 0 || (x + radius1) > screenwidth 01752 || (y - radius2) < 0 || (y + radius2) > screenheight) { 01753 ret = bad_parameter; 01754 } else if (radius1 == 1 && radius2 == 1) { 01755 pixel(x, y); 01756 } else { 01757 WriteCommandW(0xA5, x); 01758 WriteCommandW(0xA7, y); 01759 WriteCommandW(0xA1, radius1); 01760 WriteCommandW(0xA3, radius2); 01761 unsigned char drawCmd = 0x00; // Ellipse 01762 if (fillit == FILL) 01763 drawCmd |= 0x40; 01764 WriteCommand(0xA0, drawCmd); 01765 WriteCommand(0xA0, 0x80 + drawCmd); // Start drawing. 01766 if (!_WaitWhileReg(0xA0, 0x80)) { 01767 REGISTERPERFORMANCE(PRF_DRAWELLIPSE); 01768 return external_abort; 01769 } 01770 } 01771 REGISTERPERFORMANCE(PRF_DRAWELLIPSE); 01772 return ret; 01773 } 01774 01775 01776 RetCode_t RA8875::frequency(unsigned long Hz, unsigned long Hz2) 01777 { 01778 spiwritefreq = Hz; 01779 if (Hz2 != 0) 01780 spireadfreq = Hz2; 01781 else 01782 spireadfreq = Hz/2; 01783 _setWriteSpeed(true); 01784 // __ ___ 01785 // Clock ___A Rising edge latched 01786 // ___ ____ 01787 // Data ___X____ 01788 spi.format(8, 3); // 8 bits and clock to data phase 0 01789 return noerror; 01790 } 01791 01792 void RA8875::_setWriteSpeed(bool writeSpeed) 01793 { 01794 if (writeSpeed) { 01795 spi.frequency(spiwritefreq); 01796 spiWriteSpeed = true; 01797 } else { 01798 spi.frequency(spireadfreq); 01799 spiWriteSpeed = false; 01800 } 01801 } 01802 01803 01804 01805 RetCode_t RA8875::BlockMove(uint8_t dstLayer, uint8_t dstDataSelect, point_t dstPoint, 01806 uint8_t srcLayer, uint8_t srcDataSelect, point_t srcPoint, 01807 dim_t bte_width, dim_t bte_height, 01808 uint8_t bte_op_code, uint8_t bte_rop_code) 01809 { 01810 uint8_t cmd; 01811 01812 PERFORMANCE_RESET; 01813 ///@todo range check and error return rather than to secretly fix 01814 srcPoint.x &= 0x3FF; // prevent high bits from doing unexpected things 01815 srcPoint.y &= 0x1FF; 01816 dstPoint.x &= 0x3FF; 01817 dstPoint.y &= 0x1FF; 01818 WriteCommandW(0x54, srcPoint.x); 01819 WriteCommandW(0x56, ((dim_t)(srcLayer & 1) << 15) | srcPoint.y); 01820 WriteCommandW(0x58, dstPoint.x); 01821 WriteCommandW(0x5A, ((dim_t)(dstLayer & 1) << 15) | dstPoint.y); 01822 WriteCommandW(0x5C, bte_width); 01823 WriteCommandW(0x5E, bte_height); 01824 WriteCommand(0x51, ((bte_rop_code & 0x0F) << 4) | (bte_op_code & 0x0F)); 01825 cmd = ((srcDataSelect & 1) << 6) | ((dstDataSelect & 1) << 5); 01826 WriteCommand(0x50, 0x80 | cmd); // enable the BTE 01827 if (!_WaitWhileBusy(0x40)) { 01828 REGISTERPERFORMANCE(PRF_BLOCKMOVE); 01829 return external_abort; 01830 } 01831 REGISTERPERFORMANCE(PRF_BLOCKMOVE); 01832 return noerror; 01833 } 01834 01835 01836 RetCode_t RA8875::Power(bool on) 01837 { 01838 WriteCommand(0x01, (on) ? 0x80 : 0x00); 01839 return noerror; 01840 } 01841 01842 01843 RetCode_t RA8875::Backlight_u8(uint8_t brightness) 01844 { 01845 static bool is_enabled = false; 01846 01847 if (brightness == 0) { 01848 WriteCommand(0x8a); // Disable the PWM 01849 WriteData(0x00); 01850 is_enabled = false; 01851 } else if (!is_enabled) { 01852 WriteCommand(0x8a); // Enable the PWM 01853 WriteData(0x80); 01854 WriteCommand(0x8a); // Not sure why this is needed, but following the pattern 01855 WriteData(0x81); // open PWM (SYS_CLK / 2 as best I can tell) 01856 is_enabled = true; 01857 } 01858 WriteCommand(0x8b, brightness); // Brightness parameter 0xff-0x00 01859 return noerror; 01860 } 01861 01862 uint8_t RA8875::GetBacklight_u8(void) 01863 { 01864 return ReadCommand(0x8b); 01865 } 01866 01867 RetCode_t RA8875::Backlight(float brightness) 01868 { 01869 unsigned char b; 01870 01871 if (brightness >= 1.0f) 01872 b = 255; 01873 else if (brightness <= 0.0f) 01874 b = 0; 01875 else 01876 b = (unsigned char)(brightness * 255); 01877 return Backlight_u8(b); 01878 } 01879 01880 float RA8875::GetBacklight(void) 01881 { 01882 return (float)(GetBacklight_u8())/255; 01883 } 01884 01885 RetCode_t RA8875::SelectUserFont(const uint8_t * _font) 01886 { 01887 INFO("Cursor(%d,%d) %p", cursor_x, cursor_y, _font); 01888 INFO("Text C(%d,%d)", GetTextCursor_X(), GetTextCursor_Y()); 01889 if (_font) { 01890 HexDump("Font Memory", _font, 16); 01891 extFontHeight = _font[6]; 01892 uint32_t totalWidth = 0; 01893 uint16_t firstChar = _font[3] * 256 + _font[2]; 01894 uint16_t lastChar = _font[5] * 256 + _font[4]; 01895 uint16_t i; 01896 01897 for (i=firstChar; i<=lastChar; i++) { 01898 // 8 bytes of preamble to the first level lookup table 01899 uint16_t offsetToCharLookup = 8 + 4 * (i - firstChar); // 4-bytes: width(pixels), 16-bit offset from table start, 0 01900 totalWidth += _font[offsetToCharLookup]; 01901 } 01902 extFontWidth = totalWidth / (lastChar - firstChar); 01903 INFO("Font Metrics: Avg W: %2d, H: %2d, First:%d, Last:%d", extFontWidth, extFontHeight, firstChar, lastChar); 01904 } 01905 SetTextCursor(GetTextCursor_X(), GetTextCursor_Y()); // soft-font cursor -> hw cursor 01906 font = _font; 01907 return GraphicsDisplay::SelectUserFont(_font); 01908 } 01909 01910 RetCode_t RA8875::background(color_t color) 01911 { 01912 GraphicsDisplay::background(color); 01913 return _writeColorTrio(0x60, color); 01914 } 01915 01916 01917 RetCode_t RA8875::background(unsigned char r, unsigned char g, unsigned char b) 01918 { 01919 background(RGB(r,g,b)); 01920 return noerror; 01921 } 01922 01923 01924 RetCode_t RA8875::foreground(color_t color) 01925 { 01926 GraphicsDisplay::foreground(color); 01927 return _writeColorTrio(0x63, color); 01928 } 01929 01930 01931 RetCode_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b) 01932 { 01933 foreground(RGB(r,g,b)); 01934 return noerror; 01935 } 01936 01937 01938 color_t RA8875::GetForeColor(void) 01939 { 01940 return _readColorTrio(0x63); 01941 } 01942 01943 01944 color_t RA8875::DOSColor(int i) 01945 { 01946 const color_t colors[16] = { 01947 Black, Blue, Green, Cyan, 01948 Red, Magenta, Brown, Gray, 01949 Charcoal, BrightBlue, BrightGreen, BrightCyan, 01950 Orange, Pink, Yellow, White 01951 }; 01952 if (i >= 0 && i < 16) 01953 return colors[i]; 01954 else 01955 return 0; 01956 } 01957 01958 01959 const char * RA8875::DOSColorNames(int i) 01960 { 01961 const char * names[16] = { 01962 "Black", "Blue", "Green", "Cyan", 01963 "Red", "Magenta", "Brown", "Gray", 01964 "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan", 01965 "Orange", "Pink", "Yellow", "White" 01966 }; 01967 if (i >= 0 && i < 16) 01968 return names[i]; 01969 else 01970 return NULL; 01971 } 01972 01973 01974 /////////////////////////////////////////////////////////////// 01975 // Private functions 01976 01977 unsigned char RA8875::_spiwrite(unsigned char data) 01978 { 01979 unsigned char retval; 01980 01981 if (!spiWriteSpeed) 01982 _setWriteSpeed(true); 01983 retval = spi.write(data); 01984 return retval; 01985 } 01986 01987 01988 unsigned char RA8875::_spiread(void) 01989 { 01990 unsigned char retval; 01991 unsigned char data = 0; 01992 01993 if (spiWriteSpeed) 01994 _setWriteSpeed(false); 01995 retval = spi.write(data); 01996 return retval; 01997 } 01998 01999 02000 RetCode_t RA8875::_select(bool chipsel) 02001 { 02002 cs = (chipsel == true) ? 0 : 1; 02003 return noerror; 02004 } 02005 02006 02007 RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP) 02008 { 02009 (void)layer; 02010 02011 // AttachPrintHandler(this, RA8875::_printCallback); 02012 // return PrintScreen(x,y,w,h); 02013 return PrintScreen(x, y, w, h, Name_BMP); 02014 } 02015 02016 RetCode_t RA8875::_printCallback(RA8875::filecmd_t cmd, uint8_t * buffer, uint16_t size) 02017 { 02018 HexDump("CB", buffer, size); 02019 switch(cmd) { 02020 case RA8875::OPEN: 02021 //pc.printf("About to write %lu bytes\r\n", *(uint32_t *)buffer); 02022 _printFH = fopen("file.bmp", "w+b"); 02023 if (_printFH == 0) 02024 return file_not_found; 02025 break; 02026 case RA8875::WRITE: 02027 //pc.printf(" Write %4u bytes\r\n", size); 02028 fwrite(buffer, 1, size, _printFH); 02029 break; 02030 case RA8875::CLOSE: 02031 //pc.printf(" close\r\n"); 02032 fclose(_printFH); 02033 _printFH = 0; 02034 break; 02035 default: 02036 //pc.printf("Unexpected callback %d\r\n", cmd); 02037 return file_not_found; 02038 //break; 02039 } 02040 return noerror; 02041 } 02042 02043 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h) 02044 { 02045 BITMAPFILEHEADER BMP_Header; 02046 BITMAPINFOHEADER BMP_Info; 02047 uint8_t * lineBuffer = NULL; 02048 color_t * pixelBuffer = NULL; 02049 color_t * pixelBuffer2 = NULL; 02050 02051 INFO("(%d,%d) - (%d,%d)", x,y,w,h); 02052 if (x >= 0 && x < screenwidth 02053 && y >= 0 && y < screenheight 02054 && w > 0 && x + w <= screenwidth 02055 && h > 0 && y + h <= screenheight) { 02056 02057 BMP_Header.bfType = BF_TYPE; 02058 BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header); 02059 BMP_Header.bfReserved1 = 0; 02060 BMP_Header.bfReserved2 = 0; 02061 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header); 02062 02063 BMP_Info.biSize = sizeof(BMP_Info); 02064 BMP_Info.biWidth = w; 02065 BMP_Info.biHeight = h; 02066 BMP_Info.biPlanes = 1; 02067 BMP_Info.biBitCount = 24; 02068 BMP_Info.biCompression = BI_RGB; 02069 BMP_Info.biSizeImage = 0; 02070 BMP_Info.biXPelsPerMeter = 0; 02071 BMP_Info.biYPelsPerMeter = 0; 02072 BMP_Info.biClrUsed = 0; 02073 BMP_Info.biClrImportant = 0; 02074 02075 // Allocate the memory we need to proceed 02076 int lineBufSize = ((24 * w + 7)/8); 02077 lineBuffer = (uint8_t *)swMalloc(lineBufSize); 02078 if (lineBuffer == NULL) { 02079 ERR("Not enough RAM for PrintScreen lineBuffer"); 02080 return(not_enough_ram); 02081 } 02082 02083 #define DOUBLEBUF /* one larger buffer instead of two */ 02084 02085 #ifdef DOUBLEBUF 02086 // In the "#else", pixelBuffer2 malloc returns a value, 02087 // but is actually causing a failure later. 02088 // This test helps determine if it is truly out of memory, 02089 // or if malloc is broken. 02090 pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t)); 02091 pixelBuffer2 = pixelBuffer + (w * sizeof(color_t)); 02092 #else 02093 pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t)); 02094 pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t)); 02095 #endif 02096 if (pixelBuffer == NULL || pixelBuffer2 == NULL) { 02097 ERR("Not enough RAM for pixelBuffer"); 02098 #ifndef DOUBLEBUF 02099 if (pixelBuffer2) 02100 swFree(pixelBuffer2); 02101 #endif 02102 if (pixelBuffer) 02103 swFree(pixelBuffer); 02104 swFree(lineBuffer); 02105 return(not_enough_ram); 02106 } 02107 02108 // Get the file primed... 02109 privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4); 02110 02111 // Be optimistic - don't check for errors. 02112 HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02113 //fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image); 02114 privateCallback(WRITE, (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02115 02116 HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02117 //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image); 02118 privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02119 02120 //color_t transparency = GetBackgroundTransparencyColor(); 02121 LayerMode_T ltpr0 = GetLayerMode(); 02122 02123 uint16_t prevLayer = GetDrawingLayer(); 02124 // If only one of the layers is visible, select that layer 02125 switch(ltpr0) { 02126 case ShowLayer0: 02127 SelectDrawingLayer(0); 02128 break; 02129 case ShowLayer1: 02130 SelectDrawingLayer(1); 02131 break; 02132 default: 02133 break; 02134 } 02135 02136 // Read the display from the last line toward the top 02137 // so we can write the file in one pass. 02138 for (int j = h - 1; j >= 0; j--) { 02139 if (idle_callback) { 02140 (*idle_callback)(progress, (h - 1 - j) * 100 / (h - 1)); 02141 } 02142 02143 if (ltpr0 >= 2) // Need to combine the layers... 02144 SelectDrawingLayer(0); // so read layer 0 first 02145 // Read one line of pixels to a local buffer 02146 if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) { 02147 ERR("getPixelStream error, and no recovery handler..."); 02148 } 02149 if (ltpr0 >= 2) { // Need to combine the layers... 02150 SelectDrawingLayer(1); // so read layer 1 next 02151 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) { 02152 ERR("getPixelStream error, and no recovery handler..."); 02153 } 02154 } 02155 INFO("1st Color: %04X", pixelBuffer[0]); 02156 HexDump("Raster", (uint8_t *)pixelBuffer, w); 02157 // Convert the local buffer to RGBQUAD format 02158 int lb = 0; 02159 for (int i=0; i<w; i++) { 02160 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]); // Scale to 24-bits 02161 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]); // Scale to 24-bits 02162 switch (ltpr0) { 02163 case 0: 02164 case 1: 02165 case 2: // lighten-overlay (@TODO Not supported yet) 02166 case 6: // Floating Windows (@TODO not sure how to support) 02167 default: // Reserved... 02168 lineBuffer[lb++] = q0.rgbBlue; 02169 lineBuffer[lb++] = q0.rgbGreen; 02170 lineBuffer[lb++] = q0.rgbRed; 02171 break; 02172 case 3: // transparent mode (@TODO Read the background color register for transparent) 02173 case 4: // boolean or 02174 lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue; 02175 lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen; 02176 lineBuffer[lb++] = q0.rgbRed | q1.rgbRed; 02177 break; 02178 case 5: // boolean AND 02179 lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue; 02180 lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen; 02181 lineBuffer[lb++] = q0.rgbRed & q1.rgbRed; 02182 break; 02183 } 02184 } 02185 if (j == h - 1) { 02186 HexDump("Line", lineBuffer, lineBufSize); 02187 } 02188 // Write to disk 02189 //fwrite(lineBuffer, sizeof(char), lb, Image); 02190 privateCallback(WRITE, (uint8_t *)lineBuffer, lb); 02191 } 02192 SelectDrawingLayer(prevLayer); 02193 //fclose(Image); 02194 privateCallback(CLOSE, NULL, 0); 02195 02196 #ifndef DOUBLEBUF 02197 if (pixelBuffer2) 02198 swFree(pixelBuffer2); 02199 #endif 02200 if (pixelBuffer) 02201 swFree(pixelBuffer); 02202 swFree(lineBuffer); 02203 INFO("Image closed"); 02204 return noerror; 02205 } else { 02206 return bad_parameter; 02207 } 02208 } 02209 02210 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP) 02211 { 02212 BITMAPFILEHEADER BMP_Header; 02213 BITMAPINFOHEADER BMP_Info; 02214 uint8_t * lineBuffer = NULL; 02215 color_t * pixelBuffer = NULL; 02216 color_t * pixelBuffer2 = NULL; 02217 02218 INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP); 02219 if (x >= 0 && x < screenwidth 02220 && y >= 0 && y < screenheight 02221 && w > 0 && x + w <= screenwidth 02222 && h > 0 && y + h <= screenheight) { 02223 02224 BMP_Header.bfType = BF_TYPE; 02225 BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header); 02226 BMP_Header.bfReserved1 = 0; 02227 BMP_Header.bfReserved2 = 0; 02228 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header); 02229 02230 BMP_Info.biSize = sizeof(BMP_Info); 02231 BMP_Info.biWidth = w; 02232 BMP_Info.biHeight = h; 02233 BMP_Info.biPlanes = 1; 02234 BMP_Info.biBitCount = 24; 02235 BMP_Info.biCompression = BI_RGB; 02236 BMP_Info.biSizeImage = 0; 02237 BMP_Info.biXPelsPerMeter = 0; 02238 BMP_Info.biYPelsPerMeter = 0; 02239 BMP_Info.biClrUsed = 0; 02240 BMP_Info.biClrImportant = 0; 02241 02242 // Allocate the memory we need to proceed 02243 int lineBufSize = ((24 * w + 7)/8); 02244 lineBuffer = (uint8_t *)swMalloc(lineBufSize); 02245 if (lineBuffer == NULL) { 02246 ERR("Not enough RAM for PrintScreen lineBuffer"); 02247 return(not_enough_ram); 02248 } 02249 02250 #define DOUBLEBUF /* one larger buffer instead of two */ 02251 02252 #ifdef DOUBLEBUF 02253 // In the "#else", pixelBuffer2 malloc returns a value, 02254 // but is actually causing a failure later. 02255 // This test helps determine if it is truly out of memory, 02256 // or if malloc is broken. 02257 pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t)); 02258 pixelBuffer2 = pixelBuffer + (w * sizeof(color_t)); 02259 #else 02260 pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t)); 02261 pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t)); 02262 #endif 02263 if (pixelBuffer == NULL || pixelBuffer2 == NULL) { 02264 ERR("Not enough RAM for pixelBuffer"); 02265 #ifndef DOUBLEBUF 02266 if (pixelBuffer2) 02267 swFree(pixelBuffer2); 02268 #endif 02269 if (pixelBuffer) 02270 swFree(pixelBuffer); 02271 swFree(lineBuffer); 02272 return(not_enough_ram); 02273 } 02274 02275 FILE *Image = fopen(Name_BMP, "wb"); 02276 if (!Image) { 02277 ERR("Can't open file for write"); 02278 #ifndef DOUBLEBUF 02279 if (pixelBuffer2) 02280 swFree(pixelBuffer2); 02281 #endif 02282 if (pixelBuffer) 02283 swFree(pixelBuffer); 02284 swFree(lineBuffer); 02285 return(file_not_found); 02286 } 02287 02288 // Be optimistic - don't check for errors. 02289 HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02290 fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image); 02291 02292 HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02293 fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image); 02294 02295 //color_t transparency = GetBackgroundTransparencyColor(); 02296 LayerMode_T ltpr0 = GetLayerMode(); 02297 02298 uint16_t prevLayer = GetDrawingLayer(); 02299 // If only one of the layers is visible, select that layer 02300 switch(ltpr0) { 02301 case ShowLayer0: 02302 SelectDrawingLayer(0); 02303 break; 02304 case ShowLayer1: 02305 SelectDrawingLayer(1); 02306 break; 02307 default: 02308 break; 02309 } 02310 02311 // Read the display from the last line toward the top 02312 // so we can write the file in one pass. 02313 for (int j = h - 1; j >= 0; j--) { 02314 if (idle_callback) { 02315 (*idle_callback)(progress, (h - 1 - j) * 100 / (h - 1)); 02316 } 02317 02318 if (ltpr0 >= 2) // Need to combine the layers... 02319 SelectDrawingLayer(0); // so read layer 0 first 02320 // Read one line of pixels to a local buffer 02321 if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) { 02322 ERR("getPixelStream error, and no recovery handler..."); 02323 } 02324 if (ltpr0 >= 2) { // Need to combine the layers... 02325 SelectDrawingLayer(1); // so read layer 1 next 02326 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) { 02327 ERR("getPixelStream error, and no recovery handler..."); 02328 } 02329 } 02330 INFO("1st Color: %04X", pixelBuffer[0]); 02331 HexDump("Raster", (uint8_t *)pixelBuffer, w); 02332 // Convert the local buffer to RGBQUAD format 02333 int lb = 0; 02334 for (int i=0; i<w; i++) { 02335 RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]); // Scale to 24-bits 02336 RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]); // Scale to 24-bits 02337 switch (ltpr0) { 02338 case 0: 02339 case 1: 02340 case 2: // lighten-overlay (@TODO Not supported yet) 02341 case 6: // Floating Windows (@TODO not sure how to support) 02342 default: // Reserved... 02343 lineBuffer[lb++] = q0.rgbBlue; 02344 lineBuffer[lb++] = q0.rgbGreen; 02345 lineBuffer[lb++] = q0.rgbRed; 02346 break; 02347 case 3: // transparent mode (@TODO Read the background color register for transparent) 02348 case 4: // boolean or 02349 lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue; 02350 lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen; 02351 lineBuffer[lb++] = q0.rgbRed | q1.rgbRed; 02352 break; 02353 case 5: // boolean AND 02354 lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue; 02355 lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen; 02356 lineBuffer[lb++] = q0.rgbRed & q1.rgbRed; 02357 break; 02358 } 02359 } 02360 if (j == h - 1) { 02361 HexDump("Line", lineBuffer, lineBufSize); 02362 } 02363 // Write to disk 02364 fwrite(lineBuffer, sizeof(char), lb, Image); 02365 } 02366 SelectDrawingLayer(prevLayer); 02367 fclose(Image); 02368 #ifndef DOUBLEBUF 02369 if (pixelBuffer2) 02370 swFree(pixelBuffer2); 02371 #endif 02372 if (pixelBuffer) 02373 swFree(pixelBuffer); 02374 swFree(lineBuffer); 02375 INFO("Image closed"); 02376 return noerror; 02377 } else { 02378 return bad_parameter; 02379 } 02380 } 02381 02382 02383 // ########################################################################## 02384 // ########################################################################## 02385 // ########################################################################## 02386 02387 #ifdef TESTENABLE 02388 02389 #include "BPG_Arial08x08.h" 02390 #include "BPG_Arial20x20.h" 02391 02392 // ______________ ______________ ______________ _______________ 02393 // /_____ _____/ / ___________/ / ___________/ /_____ ______/ 02394 // / / / / / / / / 02395 // / / / /___ / /__________ / / 02396 // / / / ____/ /__________ / / / 02397 // / / / / / / / / 02398 // / / / /__________ ___________/ / / / 02399 // /__/ /_____________/ /_____________/ /__/ 02400 // 02401 // Everything from here down is test code. 02402 // 02403 bool SuppressSlowStuff = false; 02404 02405 void TextWrapTest(RA8875 & display, Serial & pc) 02406 { 02407 if (!SuppressSlowStuff) 02408 pc.printf("Text Wrap Test\r\n"); 02409 display.background(Black); 02410 display.foreground(Blue); 02411 display.cls(); 02412 display.Backlight_u8(255); 02413 display.puts("Text Wrap Test.\r\n"); 02414 for (int i=1; i<60; i++) { 02415 display.printf("L%2d\n", i % 17); 02416 if (!SuppressSlowStuff) 02417 wait_ms(100); 02418 } 02419 if (!SuppressSlowStuff) 02420 wait_ms(3000); 02421 } 02422 02423 02424 void ShowKey(RA8875 & display, int key) 02425 { 02426 loc_t col, row; 02427 dim_t r1 = 25; 02428 color_t color = (key & 0x80) ? Red : Green; 02429 02430 key &= 0x7F; // remove the long-press flag 02431 row = (key - 1) / 5; 02432 col = (key - 1) % 5; 02433 if (col > 5) col = 5; 02434 if (row > 4) row = 4; 02435 display.circle(450 - + (2 * r1) * col, 200 - (2 * r1) * row, r1-2, color, FILL); 02436 } 02437 02438 void HideKey(RA8875 & display, int key) 02439 { 02440 loc_t col, row; 02441 dim_t r1 = 25; 02442 02443 row = (key - 1) / 5; 02444 col = (key - 1) % 5; 02445 if (col > 5) col = 5; 02446 if (row > 4) row = 4; 02447 display.background(Black); 02448 display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Black, FILL); 02449 display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Blue); 02450 } 02451 02452 void KeyPadTest(RA8875 & display, Serial & pc) 02453 { 02454 const uint8_t myMap[22] = { 02455 0, 02456 'a', 'b', 'c', 'd', 'e', 02457 'f', 'g', 'h', 'i', 'j', 02458 'k', 'l', 'm', 'n', 'o', 02459 'p', 'q', 'r', 's', 't', 02460 'x' 02461 }; 02462 02463 display.background(Black); 02464 display.foreground(Blue); 02465 display.cls(); 02466 display.Backlight_u8(255); 02467 display.puts("KeyPad Test. Touch the keypad..."); 02468 pc.printf("\r\n" 02469 "Raw KeyPad Test. Keypad returns the key-number.\r\n" 02470 "Press [most] any PC keyboard key to advance to next test.\r\n"); 02471 RetCode_t ret = display.KeypadInit(true, true, 3, 7, 3); 02472 if (ret != noerror) 02473 pc.printf("returncode from KeypadInit is %d\r\n", ret); 02474 int lastKey = 0; 02475 while (!pc.readable()) { 02476 if (display.readable()) { 02477 int key = display.getc(); 02478 if (key) { 02479 if (((key & 0x7F) != lastKey) && (lastKey != 0)) 02480 HideKey(display, lastKey); 02481 ShowKey(display, key); 02482 lastKey = key & 0x7F; 02483 } else { 02484 // erase the last one 02485 if (lastKey) 02486 HideKey(display, lastKey); 02487 } 02488 } 02489 } 02490 (void)pc.getc(); 02491 pc.printf("\r\n" 02492 "Map KeyPad Test. Keypad returns the remapped key 'a' - 't'.\r\n" 02493 "Press [most] any PC keyboard key to advance to exit test.\r\n"); 02494 display.SetKeyMap(myMap); 02495 while (!pc.readable()) { 02496 if (display.readable()) { 02497 int key = display.getc(); 02498 bool longPress = key & 0x80; 02499 display.SetTextCursor(0, 120); 02500 display.printf("Long Press: %d\r\n", longPress); 02501 display.printf(" Remapped: %c %02X\r\n", (key) ? key & 0x7F : ' ', key); 02502 } 02503 } 02504 (void)pc.getc(); 02505 display.SetKeyMap(); 02506 pc.printf("\r\n"); 02507 } 02508 02509 void TextCursorTest(RA8875 & display, Serial & pc) 02510 { 02511 const char * iCursor = "The I-Beam cursor should be visible for this text.\r\n"; 02512 const char * uCursor = "The Underscore cursor should be visible for this text.\r\n"; 02513 const char * bCursor = "The Block cursor should be visible for this text.\r\n"; 02514 const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n"; 02515 const char * p; 02516 int delay = 60; 02517 02518 if (!SuppressSlowStuff) 02519 pc.printf("Text Cursor Test\r\n"); 02520 else 02521 delay = 0; 02522 display.background(Black); 02523 display.foreground(Blue); 02524 display.cls(); 02525 display.Backlight_u8(255); 02526 display.puts("Text Cursor Test."); 02527 02528 // visible, non-blinking 02529 display.SetTextCursor(0,20); 02530 display.SetTextCursorControl(RA8875::IBEAM, false); 02531 p = iCursor; 02532 while (*p) { 02533 display._putc(*p++); 02534 wait_ms(delay); 02535 } 02536 02537 display.SetTextCursorControl(RA8875::UNDER, false); 02538 p = uCursor; 02539 while (*p) { 02540 display._putc(*p++); 02541 wait_ms(delay); 02542 } 02543 02544 display.SetTextCursorControl(RA8875::BLOCK, false); 02545 p = bCursor; 02546 while (*p) { 02547 display._putc(*p++); 02548 wait_ms(delay); 02549 } 02550 02551 display.SetTextCursorControl(RA8875::BLOCK, true); 02552 p = bbCursor; 02553 while (*p) { 02554 display._putc(*p++); 02555 wait_ms(delay); 02556 } 02557 wait_ms(delay * 20); 02558 display.SetTextCursorControl(RA8875::NOCURSOR, false); 02559 } 02560 02561 02562 void BacklightTest(RA8875 & display, Serial & pc, float ramptime) 02563 { 02564 char buf[60]; 02565 unsigned int w = (ramptime * 1000)/ 256; 02566 int delay = 200; 02567 02568 if (!SuppressSlowStuff) 02569 pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime); 02570 else { 02571 delay = 0; 02572 w = 0; 02573 } 02574 display.Backlight_u8(0); 02575 display.background(White); 02576 display.foreground(Blue); 02577 display.cls(); 02578 display.puts("RA8875 Backlight Test - Ramp up."); 02579 wait_ms(delay); 02580 for (int i=0; i <= 255; i++) { 02581 snprintf(buf, sizeof(buf), "%3d, %4d", i, w); 02582 display.puts(100,100,buf); 02583 display.Backlight_u8(i); 02584 wait_ms(w); 02585 } 02586 } 02587 02588 02589 void BacklightTest2(RA8875 & display, Serial & pc) 02590 { 02591 int delay = 20; 02592 02593 if (!SuppressSlowStuff) 02594 pc.printf("Backlight Test 2\r\n"); 02595 else 02596 delay = 0; 02597 02598 // Dim it out at the end of the tests. 02599 display.foreground(Blue); 02600 display.puts(0,0, "Ramp Backlight down."); 02601 // Ramp it off 02602 for (int i=255; i != 0; i--) { 02603 display.Backlight_u8(i); 02604 wait_ms(delay); 02605 } 02606 display.Backlight_u8(0); 02607 } 02608 02609 02610 void ExternalFontTest(RA8875 & display, Serial & pc) 02611 { 02612 if (!SuppressSlowStuff) 02613 pc.printf("External Font Test\r\n"); 02614 display.background(Black); 02615 display.foreground(Blue); 02616 display.cls(); 02617 display.puts("External Font Test."); 02618 display.Backlight(1); 02619 02620 display.SelectUserFont(BPG_Arial08x08); 02621 display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); 02622 02623 display.SelectUserFont(BPG_Arial20x20); 02624 display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); 02625 02626 display.SelectUserFont(); 02627 02628 display.puts("Normal font again."); 02629 //display.window(0,0, display.width(), display.height()); 02630 } 02631 02632 02633 void DOSColorTest(RA8875 & display, Serial & pc) 02634 { 02635 if (!SuppressSlowStuff) 02636 pc.printf("DOS Color Test\r\n"); 02637 display.background(Black); 02638 display.foreground(Blue); 02639 display.cls(); 02640 display.puts("DOS Colors - Fore"); 02641 display.puts(280,0, "Back"); 02642 display.background(Gray); 02643 for (int i=0; i<16; i++) { 02644 display.foreground(display.DOSColor(i)); 02645 display.puts(160, i*16, display.DOSColorNames(i)); 02646 display.background(Black); 02647 } 02648 display.foreground(White); 02649 for (int i=0; i<16; i++) { 02650 display.background(display.DOSColor(i)); 02651 display.puts(360, i*16, display.DOSColorNames(i)); 02652 display.foreground(White); 02653 } 02654 } 02655 02656 02657 void WebColorTest(RA8875 & display, Serial & pc) 02658 { 02659 if (!SuppressSlowStuff) 02660 pc.printf("Web Color Test\r\n"); 02661 display.background(Black); 02662 display.foreground(Blue); 02663 display.window(0,0, display.width(), display.height()); 02664 display.cls(); 02665 display.SetTextFontSize(1,1); 02666 display.puts(200,0, "Web Color Test"); 02667 display.SetTextCursor(0,0); 02668 display.puts(" "); 02669 for (int i=0; i<16; i++) 02670 display.printf("%X", i&0xF); 02671 display.puts("\r\n0 "); 02672 for (int i=0; i<sizeof(WebColors)/sizeof(WebColors[0]); i++) { 02673 display.background(WebColors[i]); 02674 display.puts(" "); 02675 if (i % 16 == 15 && i < 255) { 02676 display.printf("\r\n%X ", ((i+1)/16)); 02677 } 02678 } 02679 display.SetTextFontSize(1,1); 02680 } 02681 02682 02683 void PixelTest(RA8875 & display, Serial & pc) 02684 { 02685 int i, c, x, y; 02686 02687 if (!SuppressSlowStuff) 02688 pc.printf("Pixel Test\r\n"); 02689 display.background(Black); 02690 display.foreground(Blue); 02691 display.cls(); 02692 display.puts("Pixel Test"); 02693 for (i=0; i<1000; i++) { 02694 x = rand() % 480; 02695 y = 16 + rand() % (272-16); 02696 c = rand() % 16; 02697 //pc.printf(" (%d,%d) - %d\r\n", x,y,r1); 02698 display.pixel(x,y, display.DOSColor(c)); 02699 } 02700 } 02701 02702 02703 void LineTest(RA8875 & display, Serial & pc) 02704 { 02705 int i, x, y, x2, y2; 02706 02707 if (!SuppressSlowStuff) 02708 pc.printf("Line Test\r\n"); 02709 display.background(Black); 02710 display.foreground(Blue); 02711 display.cls(); 02712 display.puts("Line Test"); 02713 for (i=0; i<16; i++) { 02714 // Lines 02715 x = rand() % 480; 02716 y = rand() % 272; 02717 x2 = rand() % 480; 02718 y2 = rand() % 272; 02719 display.line(x,y, x2,y2, display.DOSColor(i)); 02720 } 02721 display.foreground(BrightRed); 02722 display.foreground(BrightGreen); 02723 display.foreground(BrightBlue); 02724 display.line(55,50, 79,74, BrightRed); 02725 display.line(57,50, 81,74, BrightGreen); 02726 display.line(59,50, 83,74, BrightBlue); 02727 // horz 02728 display.line(30,40, 32,40, BrightRed); 02729 display.line(30,42, 32,42, BrightGreen); 02730 display.line(30,44, 32,44, BrightBlue); 02731 // vert 02732 display.line(20,40, 20,42, BrightRed); 02733 display.line(22,40, 22,42, BrightGreen); 02734 display.line(24,40, 24,42, BrightBlue); 02735 // compare point to line-point 02736 display.pixel(20,50, BrightRed); 02737 display.pixel(22,50, BrightGreen); 02738 display.pixel(24,50, BrightBlue); 02739 display.line(20,52, 20,52, BrightRed); 02740 display.line(22,52, 22,52, BrightGreen); 02741 display.line(24,52, 24,52, BrightBlue); 02742 02743 // point 02744 display.line(50,50, 50,50, Red); 02745 display.line(52,52, 52,52, Green); 02746 display.line(54,54, 54,54, Blue); 02747 display.line(60,60, 60,60, BrightRed); 02748 display.line(62,62, 62,62, BrightGreen); 02749 display.line(64,64, 64,64, BrightBlue); 02750 display.line(70,70, 70,70, DarkRed); 02751 display.line(72,72, 72,72, DarkGreen); 02752 display.line(74,74, 74,74, DarkBlue); 02753 } 02754 02755 02756 void RectangleTest(RA8875 & display, Serial & pc) 02757 { 02758 int i, x1,y1, x2,y2; 02759 02760 if (!SuppressSlowStuff) 02761 pc.printf("Rectangle Test\r\n"); 02762 display.background(Black); 02763 display.foreground(Blue); 02764 display.cls(); 02765 display.puts("Rectangle Test"); 02766 for (i=0; i<16; i++) { 02767 x1 = rand() % 240; 02768 y1 = 50 + rand() % 200; 02769 x2 = rand() % 240; 02770 y2 = 50 + rand() % 200; 02771 display.rect(x1,y1, x2,y2, display.DOSColor(i)); 02772 02773 x1 = 240 + rand() % 240; 02774 y1 = 50 + rand() % 200; 02775 x2 = 240 + rand() % 240; 02776 y2 = 50 + rand() % 200; 02777 display.rect(x1,y1, x2,y2, FILL); 02778 } 02779 } 02780 02781 02782 void LayerTest(RA8875 & display, Serial & pc) 02783 { 02784 loc_t i, x1,y1, x2,y2, r1,r2; 02785 02786 if (!SuppressSlowStuff) 02787 pc.printf("Layer Test\r\n"); 02788 02789 display.SelectDrawingLayer(0); 02790 display.background(Black); 02791 display.foreground(Blue); 02792 display.cls(); 02793 display.puts("Layer 0"); 02794 for (i=0; i<16; i++) { 02795 x1 = rand() % 240; 02796 y1 = 50 + rand() % 200; 02797 x2 = x1 + rand() % 100; 02798 y2 = y1 + rand() % 100; 02799 r1 = rand() % (x2 - x1)/2; 02800 r2 = rand() % (y2 - y1)/2; 02801 display.roundrect(x1,y1, x2,y2, r1,r2, display.DOSColor(i)); 02802 if (!SuppressSlowStuff) 02803 wait_ms(20); 02804 } 02805 if (!SuppressSlowStuff) 02806 wait_ms(1000); 02807 02808 display.SelectDrawingLayer(1); 02809 display.background(Black); 02810 display.foreground(Yellow); 02811 display.cls(); 02812 display.puts(240,0, "Layer 1"); 02813 for (i=0; i<16; i++) { 02814 x1 = 300 + rand() % 100; 02815 y1 = 70 + rand() % 200; 02816 r1 = rand() % min(y1 - 20, 100); 02817 display.circle(x1,y1,r1, display.DOSColor(i)); 02818 if (!SuppressSlowStuff) 02819 wait_ms(20); 02820 } 02821 display.SetLayerMode(RA8875::ShowLayer1); // Show it after the build-up 02822 if (!SuppressSlowStuff) 02823 wait_ms(2000); 02824 02825 display.SelectDrawingLayer(0); 02826 display.SetLayerMode(RA8875::ShowLayer0); // Show Layer 0 again 02827 if (!SuppressSlowStuff) 02828 wait_ms(1000); 02829 display.SetLayerMode(RA8875::TransparentMode); // Transparent mode 02830 if (!SuppressSlowStuff) 02831 wait_ms(1000); 02832 for (i=0; i<=8; i++) { 02833 display.SetLayerTransparency(i, 8-i); 02834 if (!SuppressSlowStuff) 02835 wait_ms(200); 02836 } 02837 02838 // Restore before we exit 02839 display.SetLayerTransparency(0, 0); 02840 display.SetLayerMode(RA8875::ShowLayer0); // Restore to layer 0 02841 } 02842 02843 02844 void RoundRectTest(RA8875 & display, Serial & pc) 02845 { 02846 loc_t i, x1,y1, x2,y2, r1,r2; 02847 02848 if (!SuppressSlowStuff) 02849 pc.printf("Round Rectangle Test\r\n"); 02850 display.background(Black); 02851 display.foreground(Blue); 02852 display.cls(); 02853 display.puts("Rounded Rectangle Test"); 02854 02855 for (i=0; i<16; i++) { 02856 x1 = rand() % 240; 02857 y1 = 50 + rand() % 200; 02858 x2 = x1 + rand() % 100; 02859 y2 = y1 + rand() % 100; 02860 r1 = rand() % (x2 - x1)/2; 02861 r2 = rand() % (y2 - y1)/2; 02862 display.roundrect(x1,y1, x2,y2, 5,8, display.DOSColor(i)); 02863 02864 x1 = 240 + rand() % 240; 02865 y1 = 50 + rand() % 200; 02866 x2 = x1 + rand() % 100; 02867 y2 = y1 + rand() % 100; 02868 r1 = rand() % (x2 - x1)/2; 02869 r2 = rand() % (y2 - y1)/2; 02870 display.roundrect(x1,y1, x2,y2, r1,r2, FILL); 02871 } 02872 } 02873 02874 02875 void TriangleTest(RA8875 & display, Serial & pc) 02876 { 02877 int i, x1, y1, x2, y2, x3, y3; 02878 02879 if (!SuppressSlowStuff) 02880 pc.printf("Triangle Test\r\n"); 02881 display.background(Black); 02882 display.foreground(Blue); 02883 display.cls(); 02884 display.puts(0,0, "Triangle Test"); 02885 02886 x1 = 150; 02887 y1 = 2; 02888 x2 = 190; 02889 y2 = 7; 02890 x3 = 170; 02891 y3 = 16; 02892 display.triangle(x1,y1, x2,y2, x3,y3); 02893 02894 x1 = 200; 02895 y1 = 2; 02896 x2 = 240; 02897 y2 = 7; 02898 x3 = 220; 02899 y3 = 16; 02900 display.filltriangle(x1,y1, x2,y2, x3,y3, BrightRed); 02901 02902 x1 = 300; 02903 y1 = 2; 02904 x2 = 340; 02905 y2 = 7; 02906 x3 = 320; 02907 y3 = 16; 02908 display.triangle(x1,y1, x2,y2, x3,y3, NOFILL); 02909 02910 x1 = 400; 02911 y1 = 2; 02912 x2 = 440; 02913 y2 = 7; 02914 x3 = 420; 02915 y3 = 16; 02916 display.triangle(x1,y1, x2,y2, x3,y3, Blue); 02917 02918 for (i=0; i<16; i++) { 02919 x1 = rand() % 240; 02920 y1 = 50 + rand() % 200; 02921 x2 = rand() % 240; 02922 y2 = 50 + rand() % 200; 02923 x3 = rand() % 240; 02924 y3 = 50 + rand() % 200; 02925 display.triangle(x1,y1, x2,y2, x3,y3, display.DOSColor(i)); 02926 x1 = 240 + rand() % 240; 02927 y1 = 50 + rand() % 200; 02928 x2 = 240 + rand() % 240; 02929 y2 = 50 + rand() % 200; 02930 x3 = 240 + rand() % 240; 02931 y3 = 50 + rand() % 200; 02932 display.triangle(x1,y1, x2,y2, x3,y3, FILL); 02933 } 02934 } 02935 02936 02937 void CircleTest(RA8875 & display, Serial & pc) 02938 { 02939 int i, x, y, r1; 02940 02941 if (!SuppressSlowStuff) 02942 pc.printf("Circle Test\r\n"); 02943 display.background(Black); 02944 display.foreground(Blue); 02945 display.cls(); 02946 display.puts("Circle Test"); 02947 for (i=0; i<16; i++) { 02948 x = 100 + rand() % 100; 02949 y = 70 + rand() % 200; 02950 r1 = rand() % min(y - 20, 100); 02951 //pc.printf(" (%d,%d) - %d\r\n", x,y,r1); 02952 display.circle(x,y,r1, display.DOSColor(i)); 02953 02954 x = 300 + rand() % 100; 02955 y = 70 + rand() % 200; 02956 r1 = rand() % min(y - 20, 100); 02957 //pc.printf(" (%d,%d) - %d FILL\r\n", x,y,r1); 02958 display.circle(x,y,r1, display.DOSColor(i), FILL); 02959 } 02960 } 02961 02962 02963 void EllipseTest(RA8875 & display, Serial & pc) 02964 { 02965 int i,x,y,r1,r2; 02966 02967 if (!SuppressSlowStuff) 02968 pc.printf("Ellipse Test\r\n"); 02969 display.background(Black); 02970 display.foreground(Blue); 02971 display.cls(); 02972 display.puts("Ellipse Test"); 02973 for (i=0; i<16; i++) { 02974 x = 100 + rand() % 100; 02975 y = 70 + rand() % 200; 02976 r1 = rand() % min(y - 20, 100); 02977 r2 = rand() % min(y - 20, 100); 02978 display.ellipse(x,y,r1,r2, display.DOSColor(i)); 02979 02980 x = 300 + rand() % 100; 02981 y = 70 + rand() % 200; 02982 r1 = rand() % min(y - 20, 100); 02983 r2 = rand() % min(y - 20, 100); 02984 display.ellipse(x,y,r1,r2, FILL); 02985 } 02986 } 02987 02988 02989 void TestGraphicsBitmap(RA8875 & display, Serial & pc) 02990 { 02991 LocalFileSystem local("local"); 02992 if (!SuppressSlowStuff) 02993 pc.printf("Bitmap File Load\r\n"); 02994 display.background(Black); 02995 display.foreground(Blue); 02996 display.cls(); 02997 display.puts("Graphics Test, loading /local/TestPat.bmp"); 02998 wait(3); 02999 03000 int r = display.RenderBitmapFile(0,0, "/local/TestPat.bmp"); 03001 if (!SuppressSlowStuff) 03002 pc.printf(" returned %d\r\n", r); 03003 } 03004 03005 03006 void TouchPanelTest(RA8875 & display, Serial & pc) 03007 { 03008 Timer t; 03009 int x, y; 03010 tpMatrix_t calmatrix; 03011 03012 display.background(Black); 03013 display.foreground(Blue); 03014 display.cls(); 03015 display.puts("Touch Panel Test\r\n"); 03016 pc.printf("Touch Panel Test\r\n"); 03017 display.TouchPanelInit(); 03018 pc.printf(" TP: c - calibrate, r - restore, t - test\r\n"); 03019 int c = pc.getc(); 03020 if (c == 'c') { 03021 point_t pTest[3] = 03022 { { 50, 50 }, {450, 150}, {225,250} }; 03023 point_t pSample[3]; 03024 for (int i=0; i<3; i++) { 03025 display.foreground(Blue); 03026 display.printf(" (%3d,%3d) => ", pTest[i].x, pTest[i].y); 03027 display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, White); 03028 display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, White); 03029 while (!display.TouchPanelA2DFiltered(&x, &y)) 03030 wait_ms(20); 03031 pSample[i].x = x; 03032 pSample[i].y = y; 03033 display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, Black); 03034 display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, Black); 03035 display.foreground(Blue); 03036 display.printf(" (%4d,%4d)\r\n", x,y); 03037 while (display.TouchPanelA2DFiltered(&x, &y)) 03038 wait_ms(20); 03039 wait(2); 03040 } 03041 display.TouchPanelComputeCalibration(pTest, pSample, &calmatrix); 03042 display.printf(" Writing calibration to tpcal.cfg\r\n"); 03043 FILE * fh = fopen("/local/tpcal.cfg", "wb"); 03044 if (fh) { 03045 fwrite(&calmatrix, sizeof(calmatrix), 1, fh); 03046 fclose(fh); 03047 } 03048 display.printf(" Calibration is complete."); 03049 } else if (c == 'r') { 03050 display.printf(" Reading calibration from tpcal.cfg\r\n"); 03051 FILE * fh = fopen("/local/tpcal.cfg", "rb"); 03052 if (fh) { 03053 fread(&calmatrix, sizeof(calmatrix), 1, fh); 03054 fclose(fh); 03055 } 03056 display.printf(" Calibration is complete."); 03057 display.TouchPanelSetMatrix(&calmatrix); 03058 } 03059 t.start(); 03060 do { 03061 point_t point = {0, 0}; 03062 if (display.TouchPanelReadable(&point)) { 03063 display.pixel(point.x, point.y, Red); 03064 } 03065 } while (t.read_ms() < 30000); 03066 pc.printf(">"); 03067 } 03068 03069 03070 void SpeedTest(RA8875 & display, Serial & pc) 03071 { 03072 Timer t; 03073 SuppressSlowStuff = true; 03074 pc.printf("\r\nSpeedTest disables delays, runs tests, reports overall time.\r\n"); 03075 t.start(); 03076 // do stuff fast 03077 TextCursorTest(display, pc); 03078 TextWrapTest(display, pc); 03079 BacklightTest(display, pc, 0); 03080 BacklightTest2(display, pc); 03081 ExternalFontTest(display, pc); 03082 DOSColorTest(display, pc); 03083 WebColorTest(display, pc); 03084 PixelTest(display, pc); 03085 LineTest(display, pc); 03086 RectangleTest(display, pc); 03087 RoundRectTest(display, pc); 03088 TriangleTest(display, pc); 03089 CircleTest(display, pc); 03090 EllipseTest(display, pc); 03091 LayerTest(display, pc); 03092 //TestGraphicsBitmap(display, pc); 03093 pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms()); 03094 #ifdef PERF_METRICS 03095 display.ReportPerformance(pc); 03096 #endif 03097 SuppressSlowStuff = false; 03098 } 03099 03100 03101 void PrintScreen(RA8875 & display, Serial & pc) 03102 { 03103 if (!SuppressSlowStuff) 03104 pc.printf("PrintScreen\r\n"); 03105 display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp"); 03106 } 03107 03108 03109 void RunTestSet(RA8875 & lcd, Serial & pc) 03110 { 03111 int q = 0; 03112 int automode = 0; 03113 const unsigned char modelist[] = "BDWtGLlFROTPCEbw"; // auto-test in this order. 03114 03115 while(1) { 03116 pc.printf("\r\n" 03117 "B - Backlight up b - backlight dim\r\n" 03118 "D - DOS Colors W - Web Colors\r\n" 03119 "t - text cursor G - Graphics Bitmap\r\n" 03120 "L - Lines F - external Font\r\n" 03121 "R - Rectangles O - rOund rectangles\r\n" 03122 "T - Triangles P - Pixels \r\n" 03123 "C - Circles E - Ellipses\r\n" 03124 "A - Auto Test mode S - Speed Test\r\n" 03125 "K - Keypad Test s - touch screen test\r\n" 03126 "p - print screen r - reset \r\n" 03127 "l - layer test w - wrapping text \r\n" 03128 #ifdef PERF_METRICS 03129 "0 - clear performance 1 - report performance\r\n" 03130 #endif 03131 "> "); 03132 if (automode == -1 || pc.readable()) { 03133 automode = -1; 03134 q = pc.getc(); 03135 while (pc.readable()) 03136 pc.getc(); 03137 } else if (automode >= 0) { 03138 q = modelist[automode]; 03139 } 03140 switch(q) { 03141 #ifdef PERF_METRICS 03142 case '0': 03143 lcd.ClearPerformance(); 03144 break; 03145 case '1': 03146 lcd.ReportPerformance(pc); 03147 break; 03148 #endif 03149 case 'A': 03150 automode = 0; 03151 break; 03152 case 'B': 03153 BacklightTest(lcd, pc, 2); 03154 break; 03155 case 'b': 03156 BacklightTest2(lcd, pc); 03157 break; 03158 case 'D': 03159 DOSColorTest(lcd, pc); 03160 break; 03161 case 'K': 03162 KeyPadTest(lcd, pc); 03163 break; 03164 case 'W': 03165 WebColorTest(lcd, pc); 03166 break; 03167 case 't': 03168 TextCursorTest(lcd, pc); 03169 break; 03170 case 'w': 03171 TextWrapTest(lcd, pc); 03172 break; 03173 case 'F': 03174 ExternalFontTest(lcd, pc); 03175 break; 03176 case 'L': 03177 LineTest(lcd, pc); 03178 break; 03179 case 'l': 03180 LayerTest(lcd, pc); 03181 break; 03182 case 'R': 03183 RectangleTest(lcd, pc); 03184 break; 03185 case 'O': 03186 RoundRectTest(lcd, pc); 03187 break; 03188 case 'p': 03189 PrintScreen(lcd, pc); 03190 break; 03191 case 'S': 03192 SpeedTest(lcd, pc); 03193 break; 03194 case 's': 03195 TouchPanelTest(lcd, pc); 03196 break; 03197 case 'T': 03198 TriangleTest(lcd, pc); 03199 break; 03200 case 'P': 03201 PixelTest(lcd, pc); 03202 break; 03203 case 'G': 03204 TestGraphicsBitmap(lcd, pc); 03205 break; 03206 case 'C': 03207 CircleTest(lcd, pc); 03208 break; 03209 case 'E': 03210 EllipseTest(lcd, pc); 03211 break; 03212 case 'r': 03213 pc.printf("Resetting ...\r\n"); 03214 wait_ms(20); 03215 mbed_reset(); 03216 break; 03217 case ' ': 03218 break; 03219 default: 03220 printf("huh?\n"); 03221 break; 03222 } 03223 if (automode >= 0) { 03224 automode++; 03225 if (automode >= sizeof(modelist)) 03226 automode = 0; 03227 wait_ms(2000); 03228 } 03229 wait_ms(200); 03230 } 03231 } 03232 03233 #endif // TESTENABLE
Generated on Wed Jul 13 2022 02:00:16 by 1.7.2