Library to control a Graphics TFT connected to 4-wire SPI - revised for the Raio RA8875 Display Controller.
Dependents: FRDM_RA8875_mPaint RA8875_Demo RA8875_KeyPadDemo SignalGenerator ... more
Fork of SPI_TFT by
RA8875.cpp
00001 // RA8875 Display Controller Library. 00002 // 00003 // This is being created for a Raio RA8875-based display from buydisplay.com, 00004 // which is either 480 x 272 or 800 x 480, using a 4-wire SPI interface. 00005 // Support is provided for both a keypad and a resistive touch-screen. 00006 // 00007 // See the RA8875.h file for full details. 00008 // 00009 // 20161106: Updated the initialization to set the various registers based on 00010 // the BuyDisplay.com example code. This altered several registers 00011 // for the 800x480 display driver. 00012 // 00013 #include "RA8875.h" 00014 00015 //#include "Utility.h" // private memory manager 00016 #ifndef UTILITY_H 00017 #define swMalloc malloc // use the standard 00018 #define swFree free 00019 #endif 00020 00021 //#define DEBUG "RAIO" 00022 // ... 00023 // INFO("Stuff to show %d", var); // new-line is automatically appended 00024 // 00025 #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) 00026 #define INFO(x, ...) std::printf("[INF %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00027 #define WARN(x, ...) std::printf("[WRN %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00028 #define ERR(x, ...) std::printf("[ERR %s %4d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__); 00029 static void HexDump(const char * title, const uint8_t * p, int count) 00030 { 00031 int i; 00032 char buf[100] = "0000: "; 00033 00034 if (*title) 00035 INFO("%s", title); 00036 for (i=0; i<count; ) { 00037 sprintf(buf + strlen(buf), "%02X ", *(p+i)); 00038 if ((++i & 0x0F) == 0x00) { 00039 INFO("%s", buf); 00040 if (i < count) 00041 sprintf(buf, "%04X: ", i); 00042 else 00043 buf[0] = '\0'; 00044 } 00045 } 00046 if (strlen(buf)) 00047 INFO("%s", buf); 00048 } 00049 #else 00050 #define INFO(x, ...) 00051 #define WARN(x, ...) 00052 #define ERR(x, ...) 00053 #define HexDump(a, b, c) 00054 #endif 00055 00056 // Defaults. Users can override this with the init() method. 00057 #define RA8875_DISPLAY_WIDTH 480 00058 #define RA8875_DISPLAY_HEIGHT 272 00059 #define RA8875_COLORDEPTH_BPP 16 /* Not an API */ 00060 00061 #ifdef PERF_METRICS 00062 #define PERFORMANCE_RESET performance.reset() 00063 #define REGISTERPERFORMANCE(a) RegisterPerformance(a) 00064 #define COUNTIDLETIME(a) CountIdleTime(a) 00065 static const char *metricsName[] = { 00066 "Cls", "Pixel", "Pixel Stream", "Boolean Stream", 00067 "Read Pixel", "Read Pixel Stream", 00068 "Line", 00069 "Rectangle", "Rounded Rectangle", 00070 "Triangle", "Circle", "Ellipse" 00071 }; 00072 uint16_t commandsUsed[256]; // track which commands are used with simple counter of number of hits. 00073 #else 00074 #define PERFORMANCE_RESET 00075 #define REGISTERPERFORMANCE(a) 00076 #define COUNTIDLETIME(a) 00077 #endif 00078 00079 // When it is going to poll a register for completion, how many 00080 // uSec should it wait between each polling activity. 00081 #define POLLWAITuSec 10 00082 00083 // Private RawKeyMap for the Keyboard interface 00084 static const uint8_t DefaultKeyMap[22] = { 00085 0, 00086 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 00087 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 00088 255 00089 }; 00090 00091 static const char * ErrMessages[] = { 00092 "noerror", ///< no errors, command completed successfully 00093 "bad parameter", ///< one or more parameters are invalid 00094 "file not found", ///< specified file could not be found 00095 "not bmp format", ///< file is not a .bmp file 00096 "not ico format", ///< file is not a .ico file 00097 "not supported format", ///< file format is not yet supported 00098 "image too big", ///< image is too large for the screen 00099 "not enough ram", ///< could not allocate ram for scanline 00100 "touch cal. timeout", ///< calibration could not complete in time 00101 "external abort", ///< during an idle callback, the user code initiated an abort 00102 }; 00103 00104 typedef struct { 00105 uint8_t b; 00106 uint8_t g; 00107 uint8_t r; 00108 uint8_t a; 00109 } rgbTrio_t; 00110 00111 /// This is defined as a "Web-Safe" color palette of 216 colors. 00112 /// 00113 /// It is defined so it can be emitted into a BMP file as the color palette, and it is then used 00114 /// for downscaling from higher resolution color depth to an 8-bit format. 00115 /// 00116 static const rgbTrio_t WebColorPalette[] = { 00117 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x33,0xFF}, {0x00,0x00,0x66,0xFF}, {0x00,0x00,0x99,0xFF}, {0x00,0x00,0xCC,0xFF}, {0x00,0x00,0xFF,0xFF}, 00118 {0x00,0x33,0x00,0xFF}, {0x00,0x33,0x33,0xFF}, {0x00,0x33,0x66,0xFF}, {0x00,0x33,0x99,0xFF}, {0x00,0x33,0xCC,0xFF}, {0x00,0x33,0xFF,0xFF}, 00119 {0x00,0x66,0x00,0xFF}, {0x00,0x66,0x33,0xFF}, {0x00,0x66,0x66,0xFF}, {0x00,0x66,0x99,0xFF}, {0x00,0x66,0xCC,0xFF}, {0x00,0x66,0xFF,0xFF}, 00120 {0x00,0x99,0x00,0xFF}, {0x00,0x99,0x33,0xFF}, {0x00,0x99,0x66,0xFF}, {0x00,0x99,0x99,0xFF}, {0x00,0x99,0xCC,0xFF}, {0x00,0x99,0xFF,0xFF}, 00121 {0x00,0xCC,0x00,0xFF}, {0x00,0xCC,0x33,0xFF}, {0x00,0xCC,0x66,0xFF}, {0x00,0xCC,0x99,0xFF}, {0x00,0xCC,0xCC,0xFF}, {0x00,0xCC,0xFF,0xFF}, 00122 {0x00,0xFF,0x00,0xFF}, {0x00,0xFF,0x33,0xFF}, {0x00,0xFF,0x66,0xFF}, {0x00,0xFF,0x99,0xFF}, {0x00,0xFF,0xCC,0xFF}, {0x00,0xFF,0xFF,0xFF}, 00123 {0x33,0x00,0x00,0xFF}, {0x33,0x00,0x33,0xFF}, {0x33,0x00,0x66,0xFF}, {0x33,0x00,0x99,0xFF}, {0x33,0x00,0xCC,0xFF}, {0x33,0x00,0xFF,0xFF}, 00124 {0x33,0x33,0x00,0xFF}, {0x33,0x33,0x33,0xFF}, {0x33,0x33,0x66,0xFF}, {0x33,0x33,0x99,0xFF}, {0x33,0x33,0xCC,0xFF}, {0x33,0x33,0xFF,0xFF}, 00125 {0x33,0x66,0x00,0xFF}, {0x33,0x66,0x33,0xFF}, {0x33,0x66,0x66,0xFF}, {0x33,0x66,0x99,0xFF}, {0x33,0x66,0xCC,0xFF}, {0x33,0x66,0xFF,0xFF}, 00126 {0x33,0x99,0x00,0xFF}, {0x33,0x99,0x33,0xFF}, {0x33,0x99,0x66,0xFF}, {0x33,0x99,0x99,0xFF}, {0x33,0x99,0xCC,0xFF}, {0x33,0x99,0xFF,0xFF}, 00127 {0x33,0xCC,0x00,0xFF}, {0x33,0xCC,0x33,0xFF}, {0x33,0xCC,0x66,0xFF}, {0x33,0xCC,0x99,0xFF}, {0x33,0xCC,0xCC,0xFF}, {0x33,0xCC,0xFF,0xFF}, 00128 {0x33,0xFF,0x00,0xFF}, {0x33,0xFF,0x33,0xFF}, {0x33,0xFF,0x66,0xFF}, {0x33,0xFF,0x99,0xFF}, {0x33,0xFF,0xCC,0xFF}, {0x33,0xFF,0xFF,0xFF}, 00129 {0x66,0x00,0x00,0xFF}, {0x66,0x00,0x33,0xFF}, {0x66,0x00,0x66,0xFF}, {0x66,0x00,0x99,0xFF}, {0x66,0x00,0xCC,0xFF}, {0x66,0x00,0xFF,0xFF}, 00130 {0x66,0x33,0x00,0xFF}, {0x66,0x33,0x33,0xFF}, {0x66,0x33,0x66,0xFF}, {0x66,0x33,0x99,0xFF}, {0x66,0x33,0xCC,0xFF}, {0x66,0x33,0xFF,0xFF}, 00131 {0x66,0x66,0x00,0xFF}, {0x66,0x66,0x33,0xFF}, {0x66,0x66,0x66,0xFF}, {0x66,0x66,0x99,0xFF}, {0x66,0x66,0xCC,0xFF}, {0x66,0x66,0xFF,0xFF}, 00132 {0x66,0x99,0x00,0xFF}, {0x66,0x99,0x33,0xFF}, {0x66,0x99,0x66,0xFF}, {0x66,0x99,0x99,0xFF}, {0x66,0x99,0xCC,0xFF}, {0x66,0x99,0xFF,0xFF}, 00133 {0x66,0xCC,0x00,0xFF}, {0x66,0xCC,0x33,0xFF}, {0x66,0xCC,0x66,0xFF}, {0x66,0xCC,0x99,0xFF}, {0x66,0xCC,0xCC,0xFF}, {0x66,0xCC,0xFF,0xFF}, 00134 {0x66,0xFF,0x00,0xFF}, {0x66,0xFF,0x33,0xFF}, {0x66,0xFF,0x66,0xFF}, {0x66,0xFF,0x99,0xFF}, {0x66,0xFF,0xCC,0xFF}, {0x66,0xFF,0xFF,0xFF}, 00135 {0x99,0x00,0x00,0xFF}, {0x99,0x00,0x33,0xFF}, {0x99,0x00,0x66,0xFF}, {0x99,0x00,0x99,0xFF}, {0x99,0x00,0xCC,0xFF}, {0x99,0x00,0xFF,0xFF}, 00136 {0x99,0x33,0x00,0xFF}, {0x99,0x33,0x33,0xFF}, {0x99,0x33,0x66,0xFF}, {0x99,0x33,0x99,0xFF}, {0x99,0x33,0xCC,0xFF}, {0x99,0x33,0xFF,0xFF}, 00137 {0x99,0x66,0x00,0xFF}, {0x99,0x66,0x33,0xFF}, {0x99,0x66,0x66,0xFF}, {0x99,0x66,0x99,0xFF}, {0x99,0x66,0xCC,0xFF}, {0x99,0x66,0xFF,0xFF}, 00138 {0x99,0x99,0x00,0xFF}, {0x99,0x99,0x33,0xFF}, {0x99,0x99,0x66,0xFF}, {0x99,0x99,0x99,0xFF}, {0x99,0x99,0xCC,0xFF}, {0x99,0x99,0xFF,0xFF}, 00139 {0x99,0xCC,0x00,0xFF}, {0x99,0xCC,0x33,0xFF}, {0x99,0xCC,0x66,0xFF}, {0x99,0xCC,0x99,0xFF}, {0x99,0xCC,0xCC,0xFF}, {0x99,0xCC,0xFF,0xFF}, 00140 {0x99,0xFF,0x00,0xFF}, {0x99,0xFF,0x33,0xFF}, {0x99,0xFF,0x66,0xFF}, {0x99,0xFF,0x99,0xFF}, {0x99,0xFF,0xCC,0xFF}, {0x99,0xFF,0xFF,0xFF}, 00141 {0xCC,0x00,0x00,0xFF}, {0xCC,0x00,0x33,0xFF}, {0xCC,0x00,0x66,0xFF}, {0xCC,0x00,0x99,0xFF}, {0xCC,0x00,0xCC,0xFF}, {0xCC,0x00,0xFF,0xFF}, 00142 {0xCC,0x33,0x00,0xFF}, {0xCC,0x33,0x33,0xFF}, {0xCC,0x33,0x66,0xFF}, {0xCC,0x33,0x99,0xFF}, {0xCC,0x33,0xCC,0xFF}, {0xCC,0x33,0xFF,0xFF}, 00143 {0xCC,0x66,0x00,0xFF}, {0xCC,0x66,0x33,0xFF}, {0xCC,0x66,0x66,0xFF}, {0xCC,0x66,0x99,0xFF}, {0xCC,0x66,0xCC,0xFF}, {0xCC,0x66,0xFF,0xFF}, 00144 {0xCC,0x99,0x00,0xFF}, {0xCC,0x99,0x33,0xFF}, {0xCC,0x99,0x66,0xFF}, {0xCC,0x99,0x99,0xFF}, {0xCC,0x99,0xCC,0xFF}, {0xCC,0x99,0xFF,0xFF}, 00145 {0xCC,0xCC,0x00,0xFF}, {0xCC,0xCC,0x33,0xFF}, {0xCC,0xCC,0x66,0xFF}, {0xCC,0xCC,0x99,0xFF}, {0xCC,0xCC,0xCC,0xFF}, {0xCC,0xCC,0xFF,0xFF}, 00146 {0xCC,0xFF,0x00,0xFF}, {0xCC,0xFF,0x33,0xFF}, {0xCC,0xFF,0x66,0xFF}, {0xCC,0xFF,0x99,0xFF}, {0xCC,0xFF,0xCC,0xFF}, {0xCC,0xFF,0xFF,0xFF}, 00147 {0xFF,0x00,0x00,0xFF}, {0xFF,0x00,0x33,0xFF}, {0xFF,0x00,0x66,0xFF}, {0xFF,0x00,0x99,0xFF}, {0xFF,0x00,0xCC,0xFF}, {0xFF,0x00,0xFF,0xFF}, 00148 {0xFF,0x33,0x00,0xFF}, {0xFF,0x33,0x33,0xFF}, {0xFF,0x33,0x66,0xFF}, {0xFF,0x33,0x99,0xFF}, {0xFF,0x33,0xCC,0xFF}, {0xFF,0x33,0xFF,0xFF}, 00149 {0xFF,0x66,0x00,0xFF}, {0xFF,0x66,0x33,0xFF}, {0xFF,0x66,0x66,0xFF}, {0xFF,0x66,0x99,0xFF}, {0xFF,0x66,0xCC,0xFF}, {0xFF,0x66,0xFF,0xFF}, 00150 {0xFF,0x99,0x00,0xFF}, {0xFF,0x99,0x33,0xFF}, {0xFF,0x99,0x66,0xFF}, {0xFF,0x99,0x99,0xFF}, {0xFF,0x99,0xCC,0xFF}, {0xFF,0x99,0xFF,0xFF}, 00151 {0xFF,0xCC,0x00,0xFF}, {0xFF,0xCC,0x33,0xFF}, {0xFF,0xCC,0x66,0xFF}, {0xFF,0xCC,0x99,0xFF}, {0xFF,0xCC,0xCC,0xFF}, {0xFF,0xCC,0xFF,0xFF}, 00152 {0xFF,0xFF,0x00,0xFF}, {0xFF,0xFF,0x33,0xFF}, {0xFF,0xFF,0x66,0xFF}, {0xFF,0xFF,0x99,0xFF}, {0xFF,0xFF,0xCC,0xFF}, {0xFF,0xFF,0xFF,0xFF}, 00153 00154 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 00155 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 00156 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 00157 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 00158 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 00159 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 00160 {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, {0x00,0x00,0x00,0xFF}, 00161 }; 00162 00163 #define sqr(a) ((a) * (a)) 00164 00165 /// Find the nearest color match in the lookup table. 00166 /// 00167 /// The typical process is to find the difference between a given color and each entry in 00168 /// the table. The difference is defined as: 00169 /// diff = sqrt(sqr(r - table[i].r) + sqr(g - table[i].g) + sqr(b - table[i].b)) 00170 /// The square root function is very CPU intensive, especially w/o a floating point unit, 00171 /// so that step is omitted to speed it up a bit. 00172 /// 00173 static int FindNearestWebColor(uint8_t r, uint8_t g, uint8_t b) { 00174 int bestNdx = 0; 00175 float bestDiff = (sqr(r - WebColorPalette[0].r) + sqr(g - WebColorPalette[0].g) + sqr(b - WebColorPalette[0].b)); 00176 for (int i=1; i<216; i++) { 00177 float thisDiff = (sqr(r - WebColorPalette[i].r) + sqr(g - WebColorPalette[i].g) + sqr(b - WebColorPalette[i].b)); 00178 if (thisDiff < bestDiff) { 00179 bestDiff = thisDiff; 00180 bestNdx = i; 00181 } 00182 } 00183 return bestNdx; 00184 } 00185 00186 // Non-Touch, or Resistive Touch when later initialized that way 00187 // 00188 RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 00189 const char *name) 00190 : GraphicsDisplay(name) 00191 , spi(mosi, miso, sclk) 00192 , cs(csel) 00193 , res(NULL) 00194 { 00195 INFO("RA8875"); 00196 if (reset != NC) 00197 res = new DigitalOut(reset); 00198 InitAllMemberVars(); 00199 touchInfo = (touchInfo_T *)malloc(RESISTIVE_TOUCH_POINTS * sizeof(touchInfo_T)); 00200 if (touchInfo) 00201 useTouchPanel = TP_RES; 00202 } 00203 00204 // Touch, based on FT5206 Controller Chip 00205 // 00206 RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 00207 PinName sda, PinName scl, PinName irq, const char * name) 00208 : GraphicsDisplay(name) 00209 , spi(mosi, miso, sclk) 00210 , cs(csel) 00211 , res(NULL) 00212 { 00213 INFO("RA8875"); 00214 if (reset != NC) 00215 res = new DigitalOut(reset); 00216 InitAllMemberVars(); 00217 m_irq = new InterruptIn(irq); 00218 m_i2c = new I2C(sda, scl); 00219 INFO("m_i2c = %p", m_i2c); 00220 00221 // Cap touch panel config 00222 touchInfo = (touchInfo_T *)malloc(FT5206_TOUCH_POINTS * sizeof(touchInfo_T)); 00223 if (touchInfo) 00224 useTouchPanel = TP_FT5206; 00225 m_addr = (FT5206_I2C_ADDRESS << 1); 00226 m_i2c->frequency(FT5206_I2C_FREQUENCY); 00227 00228 // Interrupt 00229 m_irq->mode(PullUp); 00230 #if MBED_VERSION >= MBED_ENCODE_VERSION(5,8,0) 00231 eventThread.start(callback(&queue, &EventQueue::dispatch_forever)); 00232 m_irq->fall(queue.event(callback(this, &RA8875::TouchPanelISR))); 00233 #elif (MBED_MAJOR_VERSION >= 5) || (MBED_LIBRARY_VERSION > 127) 00234 m_irq->fall(callback(this, &RA8875::TouchPanelISR)); 00235 #else 00236 m_irq->fall(this, &RA8875::TouchPanelISR); 00237 #endif 00238 m_irq->disable_irq(); // ensure it is disabled until the init() 00239 TouchPanelInit(); 00240 INFO("RA8875 end."); 00241 } 00242 00243 00244 // Touch, based on GSL1680 Controller Chip 00245 // 00246 RA8875::RA8875(PinName mosi, PinName miso, PinName sclk, PinName csel, PinName reset, 00247 PinName sda, PinName scl, PinName wake, PinName irq, const char * name) 00248 : GraphicsDisplay(name) 00249 , spi(mosi, miso, sclk) 00250 , cs(csel) 00251 , res(NULL) 00252 { 00253 INFO("RA8875"); 00254 if (reset != NC) 00255 res = new DigitalOut(reset); 00256 InitAllMemberVars(); 00257 00258 m_irq = new InterruptIn(irq); 00259 m_i2c = new I2C(sda, scl); 00260 00261 // Cap touch panel config 00262 touchInfo = (touchInfo_T *)malloc(FT5206_TOUCH_POINTS * sizeof(touchInfo_T)); 00263 if (touchInfo) 00264 useTouchPanel = TP_GSL1680; 00265 m_addr = (GSL1680_I2C_ADDRESS << 1); 00266 m_i2c->frequency(GSL1680_I2C_FREQUENCY); 00267 m_wake = new DigitalOut(wake); 00268 00269 // Interrupt 00270 m_irq->mode(PullUp); 00271 #if MBED_VERSION >= MBED_ENCODE_VERSION(5,8,0) 00272 eventThread.start(callback(&queue, &EventQueue::dispatch_forever)); 00273 m_irq->fall(queue.event(callback(this, &RA8875::TouchPanelISR))); 00274 #elif (MBED_MAJOR_VERSION >= 5) || (MBED_LIBRARY_VERSION > 127) 00275 m_irq->fall(callback(this, &RA8875::TouchPanelISR)); 00276 #else 00277 m_irq->fall(this, &RA8875::TouchPanelISR); 00278 #endif 00279 m_irq->disable_irq(); // ensure it is disabled until the init() 00280 TouchPanelInit(); 00281 } 00282 00283 00284 00285 //RA8875::~RA8875() 00286 //{ 00287 //} 00288 00289 void RA8875::InitAllMemberVars() { 00290 tpFQFN = NULL; 00291 tpCalMessage = NULL; 00292 c_callback = NULL; 00293 obj_callback = NULL; 00294 method_callback = NULL; 00295 idle_callback = NULL; 00296 fontScaleX = fontScaleY = 1; 00297 m_addr = 0; 00298 m_wake = NULL; // not used for FT5206 00299 m_irq = NULL; 00300 m_i2c = NULL; 00301 touchInfo = NULL; 00302 useTouchPanel = TP_NONE; 00303 touchState = no_touch; 00304 numberOfTouchPoints = 0; 00305 gesture = 0; 00306 panelTouched = false; 00307 touchSample = 0; 00308 memset(&tpMatrix, 0, sizeof(tpMatrix_t)); 00309 pKeyMap = NULL; 00310 spiWriteSpeed = false; 00311 spiwritefreq = 1000000; 00312 spireadfreq = 1000000; 00313 screenbpp = 16; 00314 virt_screenwidth = 0; 00315 virt_screenheight = 0; 00316 memset(&windowrect, 0, sizeof(rect_t)); 00317 font = NULL; 00318 extFontHeight = 0; 00319 extFontWidth = 0; 00320 cursor_x = 0; 00321 cursor_y = 0; 00322 _printFH = NULL; 00323 roundCap = false; 00324 screen_orientation = normal; 00325 #ifdef PERF_METRICS 00326 ClearPerformance(); 00327 #endif 00328 } 00329 00330 RetCode_t RA8875::init(int width, int height, int color_bpp, uint8_t poweron, bool keypadon, bool touchscreenon) 00331 { 00332 INFO("RA8875::init()"); 00333 font = NULL; // no external font, use internal. 00334 pKeyMap = DefaultKeyMap; // set default key map 00335 _select(false); // deselect the display 00336 frequency(RA8875_DEFAULT_SPI_FREQ); // data rate 00337 Reset(); 00338 // Set PLL based on display size from buy-display.com sample code 00339 // RAIO Reference display values noted: 800w: 0x0B, 480w: 0x0A 00340 if (width == 800) { 00341 WriteCommand(RA8875_PLLC1, 0x0C); // PLLC1 - Phase Lock Loop registers [RAIO 0B] 00342 } else { 00343 WriteCommand(RA8875_PLLC1, 0x0B); // PLLC1 - Phase Lock Loop registers [RAIO 0A] 00344 } 00345 wait_us(1000); 00346 WriteCommand(RA8875_PLLC2, 0x02); 00347 wait_us(1000); 00348 00349 // System Config Register (SYSR) 00350 screenbpp = color_bpp; 00351 if (color_bpp == 16) { 00352 WriteCommand(RA8875_SYSR, 0x0C); // 16-bpp (65K colors) color depth, 8-bit interface 00353 } else { // color_bpp == 8 00354 WriteCommand(RA8875_SYSR, 0x00); // 8-bpp (256 colors) 00355 } 00356 00357 // Set Pixel Clock Setting Register (PCSR) based on display size from buy-display.com sample code 00358 if (width == 800) { 00359 WriteCommand(RA8875_PCSR, 0x81); // PDAT on PCLK falling edge, PCLK = 4 x System Clock 00360 wait_us(1000); 00361 00362 // Horizontal Settings 00363 virt_screenwidth = width; 00364 WriteCommand(RA8875_HDWR, width/8 - 1); //HDWR//Horizontal Display Width Setting Bit[6:0] 00365 WriteCommand(RA8875_HNDFTR, 0x00); //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0] 00366 WriteCommand(RA8875_HNDR, 0x03); //HNDR//Horizontal Non-Display Period Bit[4:0] [RAIO 0x01] 00367 WriteCommand(RA8875_HSTR, 0x03); //HSTR//HSYNC Start Position[4:0] [RAIO 0x00] 00368 WriteCommand(RA8875_HPWR, 0x0B); //HPWR//HSYNC Polarity ,The period width of HSYNC. [RAIO 0x05] 00369 00370 // Vertical Settings 00371 virt_screenheight = height; 00372 WriteCommand(RA8875_VDHR0, (height-1)&0xFF); //VDHR0 //Vertical Display Height Bit [7:0] 00373 WriteCommand(RA8875_VDHR1, (height-1)>>8); //VDHR1 //Vertical Display Height Bit [8] 00374 WriteCommand(RA8875_VNDR0, 0x20); //VNDR0 //Vertical Non-Display Period Bit [7:0] [RAIO 0x02] 00375 WriteCommand(RA8875_VNDR1, 0x00); //VNDR1 //Vertical Non-Display Period Bit [8] 00376 WriteCommand(RA8875_VSTR0, 0x16); //VSTR0 //VSYNC Start Position[7:0] [RAIO 0x07] 00377 WriteCommand(RA8875_VSTR1, 0x00); //VSTR1 //VSYNC Start Position[8] 00378 WriteCommand(RA8875_VPWR, 0x01); //VPWR //VSYNC Polarity ,VSYNC Pulse Width[6:0] [RAIO 0x09] 00379 } else { 00380 WriteCommand(RA8875_PCSR, 0x82); // PDAT on PCLK falling edge, PCLK = 4 x System Clock 00381 wait_us(1000); 00382 00383 // Horizontal Settings 00384 virt_screenwidth = width; 00385 WriteCommand(RA8875_HDWR, width/8 - 1); //HDWR//Horizontal Display Width Setting Bit[6:0] 00386 WriteCommand(RA8875_HNDFTR, 0x02); //HNDFCR//Horizontal Non-Display Period fine tune Bit[3:0] 00387 WriteCommand(RA8875_HNDR, 0x03); //HNDR//Horizontal Non-Display Period Bit[4:0] 00388 WriteCommand(RA8875_HSTR, 0x01); //HSTR//HSYNC Start Position[4:0] 00389 WriteCommand(RA8875_HPWR, 0x03); //HPWR//HSYNC Polarity ,The period width of HSYNC. 00390 00391 // Vertical Settings 00392 virt_screenheight = height; 00393 WriteCommand(RA8875_VDHR0, (height-1)&0xFF); //VDHR0 //Vertical Display Height Bit [7:0] 00394 WriteCommand(RA8875_VDHR1, (height-1)>>8); //VDHR1 //Vertical Display Height Bit [8] 00395 WriteCommand(RA8875_VNDR0, 0x0F); //VNDR0 //Vertical Non-Display Period Bit [7:0] 00396 WriteCommand(RA8875_VNDR1, 0x00); //VNDR1 //Vertical Non-Display Period Bit [8] 00397 WriteCommand(RA8875_VSTR0, 0x0e); //VSTR0 //VSYNC Start Position[7:0] 00398 WriteCommand(RA8875_VSTR1, 0x06); //VSTR1 //VSYNC Start Position[8] 00399 WriteCommand(RA8875_VPWR, 0x01); //VPWR //VSYNC Polarity ,VSYNC Pulse Width[6:0] 00400 } 00401 00402 if (width >= 800 && height >= 480 && color_bpp > 8) { 00403 WriteCommand(RA8875_DPCR, 0x00); // DPCR - 1-layer mode when the resolution is too high 00404 } else { 00405 WriteCommand(RA8875_DPCR, 0x80); // DPCR - 2-layer mode 00406 } 00407 00408 // Set display image to Blue on Black as default 00409 SetWindow(0,0, width-1, height-1); // Initialize to full screen 00410 SetTextCursorControl(); 00411 foreground(Blue); 00412 background(Black); 00413 cls(3); 00414 00415 Power(poweron); 00416 Backlight_u8(poweron); 00417 if (keypadon) 00418 KeypadInit(); 00419 if (touchscreenon) { 00420 if (useTouchPanel == TP_NONE) 00421 useTouchPanel = TP_RES; 00422 if (useTouchPanel == TP_RES) 00423 TouchPanelInit(); // only init again if resistive (due to HW reset applied above). 00424 } 00425 #ifdef PERF_METRICS 00426 performance.start(); 00427 ClearPerformance(); 00428 #endif 00429 INFO("RA8875::init() end"); 00430 return noerror; 00431 } 00432 00433 00434 RetCode_t RA8875::Reset(void) 00435 { 00436 RetCode_t ret; 00437 00438 #if 1 00439 if (res) { 00440 res->write(0); // Active low - assert reset 00441 wait_us(2000); // must be > 1024 clock periods. (@25 MHz, this is 40.96 usec) 00442 res->write(1); // de-assert reset 00443 } 00444 #endif 00445 ret = WriteCommand(RA8875_PWRR, 0x01); // Apply Display Off, Reset 00446 wait_us(2000); // no idea if I need to wait, or how long 00447 if (ret == noerror) { 00448 ret = WriteCommand(RA8875_PWRR, 0x00); // Display off, Remove reset 00449 wait_us(2000); // no idea if I need to wait, or how long 00450 } 00451 return ret; 00452 } 00453 00454 00455 const char * RA8875::GetErrorMessage(RetCode_t code) 00456 { 00457 if (code >= LastErrCode) 00458 code = bad_parameter; 00459 return ErrMessages[code]; 00460 } 00461 00462 00463 uint16_t RA8875::GetDrawingLayer(void) 00464 { 00465 return (ReadCommand(0x41) & 0x01); 00466 } 00467 00468 00469 uint16_t RA8875::SelectDrawingLayer(uint16_t layer) 00470 { 00471 uint16_t prevLayer; 00472 unsigned char mwcr1 = ReadCommand(0x41); // retain all but the currently selected layer 00473 prevLayer = (mwcr1 & 1); 00474 mwcr1 &= ~0x01; // remove the current layer 00475 if (virt_screenwidth >= 800 && virt_screenheight >= 480 && screenbpp > 8) { 00476 layer = 0; 00477 } else if (layer > 1) { 00478 layer = 0; 00479 } 00480 WriteCommand(RA8875_MWCR1, mwcr1 | layer); 00481 return prevLayer; 00482 } 00483 00484 00485 RA8875::LayerMode_T RA8875::GetLayerMode(void) 00486 { 00487 return (LayerMode_T)(ReadCommand(0x52) & 0x7); 00488 } 00489 00490 00491 RA8875::LayerMode_T RA8875::SetLayerMode(LayerMode_T mode) 00492 { 00493 unsigned char ltpr0 = ReadCommand(0x52); // retain all but the display layer mode 00494 LayerMode_T oldLayer = (LayerMode_T)(ltpr0 & 0x07); 00495 if (mode <= (LayerMode_T)6) { 00496 WriteCommand(RA8875_LTPR0, (ltpr0 & ~0x07) | (mode & 0x07)); 00497 } 00498 return oldLayer; 00499 } 00500 00501 00502 RetCode_t RA8875::SetLayerTransparency(uint8_t layer1, uint8_t layer2) 00503 { 00504 if (layer1 > 8) 00505 layer1 = 8; 00506 if (layer2 > 8) 00507 layer2 = 8; 00508 WriteCommand(RA8875_LTPR1, ((layer2 & 0xF) << 4) | (layer1 & 0xF)); 00509 return noerror; 00510 } 00511 00512 00513 color_t RA8875::SetBackgroundTransparencyColor(color_t color) 00514 { 00515 color_t oldColor = _readColorTrio(0x67); 00516 _writeColorTrio(0x67, color); 00517 return oldColor; 00518 } 00519 00520 00521 color_t RA8875::GetBackgroundTransparencyColor(void) 00522 { 00523 RGBQUAD q; 00524 00525 q.rgbRed = ReadCommand(0x67); 00526 q.rgbGreen = ReadCommand(0x68); 00527 q.rgbBlue = ReadCommand(0x69); 00528 return RGBQuadToRGB16(&q, 0); 00529 } 00530 00531 00532 RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency, 00533 uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable) 00534 { 00535 uint8_t value = 0; 00536 00537 if (sampleTime > 3 || scanFrequency > 7 || longTimeAdjustment > 3) 00538 return bad_parameter; 00539 value |= (scanEnable) ? 0x80 : 0x00; 00540 value |= (longDetect) ? 0x40 : 0x00; 00541 value |= (sampleTime & 0x03) << 4; 00542 value |= (scanFrequency & 0x07); 00543 WriteCommand(RA8875_KSCR1, value); // KSCR1 - Enable Key Scan (and ignore possibility of an error) 00544 00545 value = 0; 00546 value |= (wakeupEnable) ? 0x80 : 0x00; 00547 value |= (longTimeAdjustment & 0x03) << 2; 00548 WriteCommand(RA8875_KSCR2, value); // KSCR2 - (and ignore possibility of an error) 00549 00550 value = ReadCommand(0xF0); // (and ignore possibility of an error) 00551 value &= ~0x10; 00552 value |= (interruptEnable) ? 0x10 : 0x00; 00553 return WriteCommand(RA8875_INTC1, value); // INT 00554 } 00555 00556 00557 RetCode_t RA8875::SetKeyMap(const uint8_t * CodeList) 00558 { 00559 pKeyMap = CodeList; 00560 return noerror; 00561 } 00562 00563 00564 bool RA8875::readable(void) 00565 { 00566 return (ReadCommand(0xF1) & 0x10); // check KS status - true if kbhit 00567 } 00568 00569 00570 uint8_t RA8875::getc(void) 00571 { 00572 //#define GETC_DEV // for development 00573 #ifdef GETC_DEV 00574 uint8_t keyCode1, keyCode2; 00575 #endif 00576 uint8_t keyCode3; 00577 static uint8_t count = 0; 00578 uint8_t col, row; 00579 uint8_t key; 00580 00581 while (!readable()) { 00582 wait_us(POLLWAITuSec); 00583 // COUNTIDLETIME(POLLWAITuSec); // As it is voluntary to call the getc and pend. Don't tally it. 00584 if (idle_callback) { 00585 if (external_abort == (*idle_callback)(getc_wait, 0)) { 00586 return 0; 00587 } 00588 } 00589 } 00590 // read the key press number 00591 uint8_t keyNumReg = ReadCommand(0xC1) & 0x03; 00592 count++; 00593 switch (keyNumReg) { 00594 case 0x01: // one key 00595 keyCode3 = ReadCommand(0xC2); 00596 #ifdef GETC_DEV 00597 keyCode2 = 0; 00598 keyCode1 = 0; 00599 #endif 00600 break; 00601 case 0x02: // two keys 00602 keyCode3 = ReadCommand(0xC3); 00603 #ifdef GETC_DEV 00604 keyCode2 = ReadCommand(0xC2); 00605 keyCode1 = 0; 00606 #endif 00607 break; 00608 case 0x03: // three keys 00609 keyCode3 = ReadCommand(0xC4); 00610 #ifdef GETC_DEV 00611 keyCode2 = ReadCommand(0xC3); 00612 keyCode1 = ReadCommand(0xC2); 00613 #endif 00614 break; 00615 default: // no keys (key released) 00616 keyCode3 = 0xFF; 00617 #ifdef GETC_DEV 00618 keyCode2 = 0; 00619 keyCode1 = 0; 00620 #endif 00621 break; 00622 } 00623 if (keyCode3 == 0xFF) 00624 key = pKeyMap[0]; // Key value 0 00625 else { 00626 row = (keyCode3 >> 4) & 0x03; 00627 col = (keyCode3 & 7); 00628 key = row * 5 + col + 1; // Keys value 1 - 20 00629 if (key > 21) { 00630 key = 21; 00631 } 00632 key = pKeyMap[key]; 00633 key |= (keyCode3 & 0x80); // combine the key held flag 00634 } 00635 #if GETC_DEV // for Development only 00636 SetTextCursor(0, 20); 00637 printf(" Reg: %02x\r\n", keyNumReg); 00638 printf(" key1: %02x\r\n", keyCode1); 00639 printf(" key2: %02x\r\n", keyCode2); 00640 printf(" key3: %02x\r\n", keyCode3); 00641 printf(" count: %02X\r\n", count); 00642 printf(" key: %02X\r\n", key); 00643 #endif 00644 WriteCommand(RA8875_INTC2, 0x10); // Clear KS status 00645 return key; 00646 } 00647 00648 00649 #ifdef PERF_METRICS 00650 void RA8875::ClearPerformance() 00651 { 00652 int i; 00653 00654 for (i=0; i<METRICCOUNT; i++) 00655 metrics[i] = 0; 00656 idletime_usec = 0; 00657 for (i=0; i<256; i++) 00658 commandsUsed[i] = 0; 00659 } 00660 00661 00662 void RA8875::RegisterPerformance(method_e method) 00663 { 00664 unsigned long elapsed = performance.read_us(); 00665 00666 if (method < METRICCOUNT && elapsed > metrics[method]) 00667 metrics[method] = elapsed; 00668 } 00669 00670 00671 void RA8875::CountIdleTime(uint32_t t) 00672 { 00673 idletime_usec += t; 00674 } 00675 00676 00677 void RA8875::ReportPerformance(Serial & pc) 00678 { 00679 int i; 00680 00681 pc.printf("\r\nPerformance Metrics\r\n"); 00682 for (i=0; i<METRICCOUNT; i++) { 00683 pc.printf("%10d uS %s\r\n", metrics[i], metricsName[i]); 00684 } 00685 pc.printf("%10d uS Idle time polling display for ready.\r\n", idletime_usec); 00686 for (i=0; i<256; i++) { 00687 if (commandsUsed[i]) 00688 pc.printf("Command %02X used %5d times.\r\n", i, commandsUsed[i]); 00689 } 00690 } 00691 #endif 00692 00693 00694 rect_t RA8875::AlignRectInRect(rect_t toAlign, rect_t inRect, valign_t v, halign_t h) { 00695 rect_t newRect; dim_t width; dim_t height; 00696 width = toAlign.p2.x - toAlign.p1.x + 1; 00697 height = toAlign.p2.y - toAlign.p1.y + 1; 00698 INFO("Align(%d,%d)-(%d,%d) in (%d,%d)-(%d,%d) v:%d, h:%d", 00699 toAlign.p1.x,toAlign.p1.y,toAlign.p2.x,toAlign.p2.y, 00700 inRect.p1.x,inRect.p1.y,inRect.p2.x,inRect.p2.y, 00701 v,h 00702 ); 00703 switch (h) { 00704 case left: 00705 default: 00706 newRect.p1.x = inRect.p1.x; 00707 newRect.p2.x = newRect.p1.x + width - 1; 00708 break; 00709 case center: 00710 newRect.p1.x = (inRect.p1.x + inRect.p2.x + 1) / 2 - width / 2; 00711 newRect.p2.x = newRect.p1.x + width - 1; 00712 break; 00713 case right: 00714 newRect.p1.x = inRect.p2.x - width - 1; 00715 newRect.p2.x = newRect.p1.x + width - 1; 00716 break; 00717 } 00718 switch (v) { 00719 case top: 00720 default: 00721 newRect.p1.y = inRect.p1.y; 00722 newRect.p2.y = newRect.p1.y + height - 1; 00723 break; 00724 case middle: 00725 newRect.p1.y = (inRect.p1.y + inRect.p2.y + 1) / 2 - height / 2; 00726 newRect.p2.y = newRect.p1.y + height - 1; 00727 break; 00728 case bottom: 00729 newRect.p1.y = inRect.p2.y - height - 1; 00730 newRect.p2.y = newRect.p1.y + height - 1; 00731 break; 00732 } 00733 return newRect; 00734 } 00735 00736 00737 bool RA8875::Intersect(rect_t rect, point_t p) 00738 { 00739 if (p.x >= RAmin(rect.p1.x, rect.p2.x) && p.x <= RAmax(rect.p1.x, rect.p2.x) 00740 && p.y >= RAmin(rect.p1.y, rect.p2.y) && p.y <= RAmax(rect.p1.y, rect.p2.y)) 00741 return true; 00742 else 00743 return false; 00744 } 00745 00746 00747 bool RA8875::Intersect(rect_t rect1, rect_t rect2) 00748 { 00749 #if 1 00750 // If one rectangle is on left side of other 00751 if (RAmax(rect1.p1.x,rect1.p2.x) < RAmin(rect2.p1.x,rect2.p2.x) 00752 || RAmin(rect1.p1.x, rect1.p2.x) > RAmax(rect2.p1.x, rect2.p2.x)) 00753 return false; 00754 // If one rectangle is above other 00755 if (RAmax(rect1.p1.y, rect1.p2.y) < RAmin(rect2.p1.y, rect2.p2.y) 00756 || RAmin(rect1.p1.y, rect1.p2.y) > RAmax(rect2.p1.y, rect2.p2.y)) 00757 return false; 00758 return true; // all that's left is they overlap 00759 #else 00760 point_t bl, tr; 00761 bl.x = rect2.p1.x; 00762 bl.y = rect2.p2.y; 00763 tr.x = rect2.p2.x; 00764 tr.y = rect2.p1.y; 00765 if (Intersect(rect1, rect2.p1) || Intersect(rect1, rect2.p2) 00766 || Intersect(rect1, bl) || Intersect(rect1, tr)) 00767 return true; 00768 else 00769 return false; 00770 #endif 00771 } 00772 00773 00774 bool RA8875::Intersect(rect_t * pRect1, const rect_t * pRect2) 00775 { 00776 if (Intersect(*pRect1, *pRect2)) { 00777 rect_t iSect; 00778 00779 iSect.p1.x = RAmax(RAmin(pRect1->p1.x,pRect1->p2.x),RAmin(pRect2->p1.x,pRect2->p2.x)); 00780 iSect.p1.y = RAmax(RAmin(pRect1->p1.y,pRect1->p2.y),RAmin(pRect2->p1.y,pRect2->p2.y)); 00781 iSect.p2.x = RAmin(RAmax(pRect1->p1.x,pRect1->p2.x),RAmax(pRect2->p1.x,pRect2->p2.x)); 00782 iSect.p2.y = RAmin(RAmax(pRect1->p1.y,pRect1->p2.y),RAmax(pRect2->p1.y,pRect2->p2.y)); 00783 *pRect1 = iSect; 00784 return true; 00785 } else { 00786 return false; 00787 } 00788 } 00789 00790 00791 RetCode_t RA8875::WriteCommandW(uint8_t command, uint16_t data) 00792 { 00793 WriteCommand(command, data & 0xFF); 00794 WriteCommand(command+1, data >> 8); 00795 return noerror; 00796 } 00797 00798 00799 RetCode_t RA8875::WriteCommand(unsigned char command, unsigned int data) 00800 { 00801 #ifdef PERF_METRICS 00802 if (commandsUsed[command] < 65535) 00803 commandsUsed[command]++; 00804 #endif 00805 _select(true); 00806 _spiwrite(0x80); // RS:1 (Cmd/Status), RW:0 (Write) 00807 _spiwrite(command); 00808 if (data <= 0xFF) { // only if in the valid range 00809 _spiwrite(0x00); 00810 _spiwrite(data); 00811 } 00812 _select(false); 00813 return noerror; 00814 } 00815 00816 00817 RetCode_t RA8875::WriteDataW(uint16_t data) 00818 { 00819 _select(true); 00820 _spiwrite(0x00); // RS:0 (Data), RW:0 (Write) 00821 _spiwrite(data & 0xFF); 00822 _spiwrite(data >> 8); 00823 _select(false); 00824 return noerror; 00825 } 00826 00827 00828 RetCode_t RA8875::WriteData(unsigned char data) 00829 { 00830 _select(true); 00831 _spiwrite(0x00); // RS:0 (Data), RW:0 (Write) 00832 _spiwrite(data); 00833 _select(false); 00834 return noerror; 00835 } 00836 00837 00838 unsigned char RA8875::ReadCommand(unsigned char command) 00839 { 00840 WriteCommand(command); 00841 return ReadData(); 00842 } 00843 00844 uint16_t RA8875::ReadCommandW(unsigned char command) 00845 { 00846 WriteCommand(command); 00847 return ReadDataW(); 00848 } 00849 00850 unsigned char RA8875::ReadData(void) 00851 { 00852 unsigned char data; 00853 00854 _select(true); 00855 _spiwrite(0x40); // RS:0 (Data), RW:1 (Read) 00856 data = _spiread(); 00857 _select(false); 00858 return data; 00859 } 00860 00861 00862 uint16_t RA8875::ReadDataW(void) 00863 { 00864 uint16_t data; 00865 00866 _select(true); 00867 _spiwrite(0x40); // RS:0 (Data), RW:1 (Read) 00868 data = _spiread(); 00869 data |= (_spiread() << 8); 00870 _select(false); 00871 return data; 00872 } 00873 00874 00875 unsigned char RA8875::ReadStatus(void) 00876 { 00877 unsigned char data; 00878 00879 _select(true); 00880 _spiwrite(0xC0); // RS:1 (Cmd/Status), RW:1 (Read) (Read STSR) 00881 data = _spiread(); 00882 _select(false); 00883 return data; 00884 } 00885 00886 00887 /// @todo add a timeout and return false, but how long 00888 /// to wait since some operations can be very long. 00889 bool RA8875::_WaitWhileBusy(uint8_t mask) 00890 { 00891 int i = 20000/POLLWAITuSec; // 20 msec max 00892 00893 while (i-- && ReadStatus() & mask) { 00894 wait_us(POLLWAITuSec); 00895 COUNTIDLETIME(POLLWAITuSec); 00896 if (idle_callback) { 00897 if (external_abort == (*idle_callback)(status_wait, 0)) { 00898 return false; 00899 } 00900 } 00901 } 00902 if (i) 00903 return true; 00904 else 00905 return false; 00906 } 00907 00908 00909 /// @todo add a timeout and return false, but how long 00910 /// to wait since some operations can be very long. 00911 bool RA8875::_WaitWhileReg(uint8_t reg, uint8_t mask) 00912 { 00913 int i = 20000/POLLWAITuSec; // 20 msec max 00914 00915 while (i-- && ReadCommand(reg) & mask) { 00916 wait_us(POLLWAITuSec); 00917 COUNTIDLETIME(POLLWAITuSec); 00918 if (idle_callback) { 00919 if (external_abort == (*idle_callback)(command_wait, 0)) { 00920 return false; 00921 } 00922 } 00923 } 00924 if (i) 00925 return true; 00926 else 00927 return false; 00928 } 00929 00930 // RRRR RGGG GGGB BBBB 00931 // 4321 0543 2104 3210 00932 // RRRG GGBB 00933 // 2102 1010 00934 uint8_t RA8875::_cvt16to8(color_t c16) 00935 { 00936 return ((c16 >> 8) & 0xE0) 00937 | ((c16 >> 6) & 0x1C) 00938 | ((c16 >> 3) & 0x03); 00939 } 00940 00941 // RRRG GGBB 00942 // 2102 1010 00943 // RRRR RGGG GGGB BBBB 00944 // 2101 0543 2104 3210 00945 color_t RA8875::_cvt8to16(uint8_t c8) 00946 { 00947 color_t c16; 00948 color_t temp = (color_t)c8; 00949 00950 c16 = ((temp & 0xE0) << 8) 00951 | ((temp & 0xC0) << 5) 00952 | ((temp & 0x1C) << 6) 00953 | ((temp & 0x1C) << 3) 00954 | ((temp & 0x03) << 3) 00955 | ((temp & 0x03) << 1) 00956 | ((temp & 0x03) >> 1); 00957 c16 = (c16 << 8) | (c16 >> 8); 00958 return c16; 00959 } 00960 00961 RetCode_t RA8875::_writeColorTrio(uint8_t regAddr, color_t color) 00962 { 00963 RetCode_t rt = noerror; 00964 00965 if (screenbpp == 16) { 00966 WriteCommand(regAddr+0, (color>>11)); // BGCR0 00967 WriteCommand(regAddr+1, (unsigned char)(color>>5)); // BGCR1 00968 rt = WriteCommand(regAddr+2, (unsigned char)(color)); // BGCR2 00969 } else { 00970 uint8_t r, g, b; 00971 00972 // RRRR RGGG GGGB BBBB RGB 00973 // RRR GGG B B 00974 r = (uint8_t)((color) >> 13); 00975 g = (uint8_t)((color) >> 8); 00976 b = (uint8_t)((color) >> 3); 00977 WriteCommand(regAddr+0, r); // BGCR0 00978 WriteCommand(regAddr+1, g); // BGCR1 00979 rt = WriteCommand(regAddr+2, b); // BGCR2 00980 } 00981 return rt; 00982 } 00983 00984 color_t RA8875::_readColorTrio(uint8_t regAddr) 00985 { 00986 color_t color; 00987 uint8_t r, g, b; 00988 00989 r = ReadCommand(regAddr+0); 00990 g = ReadCommand(regAddr+1); 00991 b = ReadCommand(regAddr+2); 00992 if (screenbpp == 16) { 00993 // 000R RRRR 00GG GGGG 000B BBBB 00994 // RRRR RGGG GGGB BBBB 00995 color = (r & 0x1F) << 11; 00996 color |= (g & 0x3F) << 5; 00997 color |= (b & 0x1F); 00998 } else { 00999 // RRRG GGBB 01000 // RRRR RGGG GGGB BBBB 01001 color = (r & 0x07) << 13; 01002 color |= (g & 0x07) << 8; 01003 color |= (b & 0x03) << 3; 01004 } 01005 return color; 01006 } 01007 01008 01009 dim_t RA8875::fontwidth(void) 01010 { 01011 if (font == NULL) 01012 return (((ReadCommand(RA8875_FNCR1) >> 2) & 0x3) + 1) * 8; 01013 else 01014 return extFontWidth; 01015 } 01016 01017 01018 dim_t RA8875::fontheight(void) 01019 { 01020 if (font == NULL) 01021 return (((ReadCommand(RA8875_FNCR1) >> 0) & 0x3) + 1) * 16; 01022 else 01023 return extFontHeight; 01024 } 01025 01026 01027 point_t RA8875::locate(textloc_t column, textloc_t row) 01028 { 01029 return SetTextCursor(column * fontwidth(), row * fontheight()); 01030 } 01031 01032 01033 int RA8875::columns(void) 01034 { 01035 return virt_screenwidth / fontwidth(); 01036 } 01037 01038 01039 int RA8875::rows(void) 01040 { 01041 return virt_screenheight / fontheight(); 01042 } 01043 01044 01045 dim_t RA8875::width(void) 01046 { 01047 return virt_screenwidth; 01048 } 01049 01050 01051 dim_t RA8875::height(void) 01052 { 01053 return virt_screenheight; 01054 } 01055 01056 01057 dim_t RA8875::color_bpp(void) 01058 { 01059 return screenbpp; 01060 } 01061 01062 bool RA8875::SetWordWrap(bool _wordwrap) { 01063 bool prevWrap = wordwrap; 01064 wordwrap = _wordwrap; 01065 return prevWrap; 01066 } 01067 01068 point_t RA8875::SetTextCursor(point_t p) 01069 { 01070 return SetTextCursor(p.x, p.y); 01071 } 01072 01073 point_t RA8875::SetTextCursor(loc_t x, loc_t y) 01074 { 01075 point_t oldCursor = GetTextCursor(); 01076 if (x >= 0 && x <= virt_screenwidth 01077 && y >= 0 && y <= virt_screenheight) { 01078 cursor_x = x; // set these values for non-internal fonts 01079 cursor_y = y; 01080 switch (screen_orientation) { 01081 default: 01082 case rotate_0: 01083 case rotate_180: 01084 WriteCommandW(RA8875_FCURXL, x); 01085 WriteCommandW(RA8875_FCURYL, y); 01086 break; 01087 case rotate_90: 01088 case rotate_270: 01089 WriteCommandW(RA8875_FCURXL, y); 01090 WriteCommandW(RA8875_FCURYL, x); 01091 break; 01092 } 01093 } 01094 return oldCursor; 01095 } 01096 01097 point_t RA8875::GetTextCursor(void) 01098 { 01099 point_t p, tempPt; 01100 01101 if (font == NULL) { 01102 p.x = ReadCommand(RA8875_FCURXL) | (ReadCommand(RA8875_FCURXH) << 8); 01103 p.y = ReadCommand(RA8875_FCURYL) | (ReadCommand(RA8875_FCURYH) << 8); 01104 switch (screen_orientation) { 01105 case rotate_0: 01106 case rotate_180: 01107 // Nothing 01108 break; 01109 case rotate_90: 01110 case rotate_270: 01111 tempPt.x = p.y; 01112 tempPt.y = p.x; 01113 p = tempPt; 01114 break; 01115 default: 01116 p.x = 0; 01117 p.y = 0; 01118 break; 01119 } 01120 } else { 01121 p.x = cursor_x; 01122 p.y = cursor_y; 01123 } 01124 //INFO("GetCursor hw: (%d,%d)", p.x, p.y); 01125 return p; 01126 } 01127 01128 loc_t RA8875::GetTextCursor_Y(void) 01129 { 01130 point_t p = GetTextCursor(); 01131 INFO("GetTextCursor_Y = %d", p.y); 01132 return p.y; 01133 } 01134 01135 01136 loc_t RA8875::GetTextCursor_X(void) 01137 { 01138 point_t p = GetTextCursor(); 01139 INFO("GetTextCursor_X = %d", p.x); 01140 return p.x; 01141 } 01142 01143 01144 RetCode_t RA8875::SetTextCursorControl(cursor_t cursor, bool blink) 01145 { 01146 unsigned char mwcr0 = ReadCommand(RA8875_MWCR0) & 0x0F; // retain direction, auto-increase 01147 unsigned char mwcr1 = ReadCommand(RA8875_MWCR1) & 0x01; // retain currently selected layer 01148 unsigned char horz = 0; 01149 unsigned char vert = 0; 01150 01151 mwcr0 |= 0x80; // text mode 01152 if (cursor != NOCURSOR) 01153 mwcr0 |= 0x40; // visible 01154 if (blink) 01155 mwcr0 |= 0x20; // blink 01156 WriteCommand(RA8875_MWCR0, mwcr0); // configure the cursor 01157 WriteCommand(RA8875_MWCR1, mwcr1); // close the graphics cursor 01158 WriteCommand(RA8875_BTCR, 0x1f); // The cursor flashing cycle 01159 switch (cursor) { 01160 case IBEAM: 01161 horz = 0x01; 01162 vert = 0x1F; 01163 break; 01164 case UNDER: 01165 horz = 0x07; 01166 vert = 0x01; 01167 break; 01168 case BLOCK: 01169 horz = 0x07; 01170 vert = 0x1F; 01171 break; 01172 case NOCURSOR: 01173 default: 01174 break; 01175 } 01176 WriteCommand(RA8875_CURHS, horz); // The cursor size horz 01177 WriteCommand(RA8875_CURVS, vert); // The cursor size vert 01178 return noerror; 01179 } 01180 01181 01182 RetCode_t RA8875::SetTextFont(RA8875::font_t font) 01183 { 01184 if (/*font >= RA8875::ISO8859_1 && */ font <= RA8875::ISO8859_4) { 01185 WriteCommand(RA8875_FNCR0, (unsigned int)(font)); 01186 return noerror; 01187 } else { 01188 return bad_parameter; 01189 } 01190 } 01191 01192 point_t RA8875::TranslateOrientation(loc_t x, loc_t y) { 01193 point_t pt; 01194 01195 switch (screen_orientation) { 01196 default: 01197 case rotate_0: 01198 pt.x = x; 01199 pt.y = y; 01200 break; 01201 case rotate_90: 01202 pt.x = y; 01203 pt.y = virt_screenheight - 1 - x; 01204 break; 01205 case rotate_180: 01206 pt.x = virt_screenwidth - 1 - x; 01207 pt.y = virt_screenheight - 1 - y; 01208 break; 01209 case rotate_270: 01210 pt.x = virt_screenwidth - 1 - y; 01211 pt.y = x; 01212 break; 01213 } 01214 return pt; 01215 } 01216 01217 01218 orientation_t RA8875::GetGraphicsOrientation() 01219 { 01220 return screen_orientation; 01221 } 01222 01223 orientation_t RA8875::SetGraphicsOrientation(orientation_t angle) 01224 { 01225 uint8_t dpcrVal = ReadCommand(RA8875_DPCR); 01226 uint8_t mwcr0 = ReadCommand(RA8875_MWCR0); 01227 uint8_t mrcd = ReadCommand(RA8875_MRCD); 01228 dim_t tempWidth, tempHeight; 01229 orientation_t oldAngle = screen_orientation; 01230 01231 dpcrVal &= ~0x0C; // remove the old scan direction bits 01232 mwcr0 &= 0xE3; // remove the old direction bits 01233 mrcd &= 0xFC; // remove the old direction bits 01234 switch (angle) { 01235 case normal: 01236 //dpcrVal |= 0x00; 01237 tempWidth = RAmax(virt_screenwidth, virt_screenheight); 01238 tempHeight = RAmin(virt_screenwidth, virt_screenheight); 01239 break; 01240 case rotate_90: 01241 dpcrVal |= 0x08; 01242 mwcr0 |= 0x08; 01243 mrcd |= 0x02; 01244 tempWidth = RAmin(virt_screenwidth, virt_screenheight); 01245 tempHeight = RAmax(virt_screenwidth, virt_screenheight); 01246 break; 01247 case rotate_180: 01248 dpcrVal |= 0x0C; 01249 //mwcr0 |= 0x00; 01250 //mrcd |= 0x00; 01251 tempWidth = RAmax(virt_screenwidth, virt_screenheight); 01252 tempHeight = RAmin(virt_screenwidth, virt_screenheight); 01253 break; 01254 case rotate_270: 01255 dpcrVal |= 0x04; 01256 mwcr0 |= 0x08; 01257 mrcd |= 0x02; 01258 tempWidth = RAmin(virt_screenwidth, virt_screenheight); 01259 tempHeight = RAmax(virt_screenwidth, virt_screenheight); 01260 break; 01261 default: 01262 return invalid; 01263 } 01264 screen_orientation = angle; 01265 virt_screenwidth = tempWidth; 01266 virt_screenheight = tempHeight; 01267 WriteCommand(RA8875_MRCD, mrcd); 01268 WriteCommand(RA8875_MWCR0, mwcr0); 01269 WriteCommand(RA8875_DPCR, dpcrVal); 01270 return oldAngle; 01271 } 01272 01273 orientation_t RA8875::SetTextFontOrientation(orientation_t angle) 01274 { 01275 uint8_t fncr1Val = ReadCommand(RA8875_FNCR1); 01276 orientation_t oldAngle = text_orientation; 01277 01278 fncr1Val &= ~0x10; // remove the old direction bit 01279 switch (angle) { 01280 case normal: 01281 //fncr1Val |= 0x10; 01282 break; 01283 case rotate_90: 01284 fncr1Val |= 0x10; 01285 break; 01286 case rotate_180: 01287 //fncr1Val |= 0x00; 01288 break; 01289 case rotate_270: 01290 fncr1Val |= 0x10; 01291 break; 01292 default: 01293 return invalid; 01294 } 01295 WriteCommand(RA8875_FNCR1, fncr1Val); 01296 text_orientation = angle; 01297 return oldAngle; 01298 } 01299 01300 RetCode_t RA8875::SetTextFontControl(fill_t fillit, 01301 RA8875::HorizontalScale hScale, 01302 RA8875::VerticalScale vScale, 01303 RA8875::alignment_t alignment) 01304 { 01305 if (hScale >= 1 && hScale <= 4 && 01306 vScale >= 1 && vScale <= 4) { 01307 uint8_t fncr1Val = ReadCommand(RA8875_FNCR1); 01308 01309 fncr1Val &= 0x10; // remove all except the font rotation bit 01310 if (alignment == align_full) 01311 fncr1Val |= 0x80; 01312 if (fillit == NOFILL) 01313 fncr1Val |= 0x40; 01314 fncr1Val |= ((hScale - 1) << 2); 01315 fncr1Val |= ((vScale - 1) << 0); 01316 return WriteCommand(RA8875_FNCR1, fncr1Val); 01317 } else { 01318 return bad_parameter; 01319 } 01320 } 01321 01322 fill_t RA8875::SetTextFontFill(fill_t fillit) 01323 { 01324 fill_t prevFill = FILL; 01325 uint8_t fncr1Val = ReadCommand(RA8875_FNCR1); 01326 01327 if (fncr1Val & 0x40) 01328 prevFill = NOFILL; 01329 fncr1Val &= ~0x40; 01330 if (fillit == NOFILL) 01331 fncr1Val |= 0x40; 01332 WriteCommand(RA8875_FNCR1, fncr1Val); 01333 return prevFill; 01334 } 01335 01336 RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale) 01337 { 01338 unsigned char reg = ReadCommand(RA8875_FNCR1); 01339 01340 if (vScale == -1) 01341 vScale = hScale; 01342 if (hScale >= 1 && hScale <= 4 && vScale >= 1 && vScale <= 4) { 01343 fontScaleX = hScale; // save for use with a Soft Font 01344 fontScaleY = vScale; 01345 reg &= 0xF0; // keep the high nibble as is. 01346 reg |= ((hScale - 1) << 2); 01347 reg |= ((vScale - 1) << 0); 01348 WriteCommand(RA8875_FNCR1, reg); 01349 return noerror; 01350 } else { 01351 return bad_parameter; 01352 } 01353 } 01354 01355 RetCode_t RA8875::GetTextFontSize(RA8875::HorizontalScale * hScale, RA8875::VerticalScale * vScale) 01356 { 01357 unsigned char reg = ReadCommand(RA8875_FNCR1); 01358 01359 if (hScale) 01360 *hScale = 1 + ((reg >> 2) & 0x03); 01361 if (vScale) 01362 *vScale = 1 + (reg & 0x03); 01363 return noerror; 01364 } 01365 01366 dim_t RA8875::GetTextWidth(const char * text, bool charOnly) 01367 { 01368 if (font == NULL) { 01369 if (charOnly) 01370 return fontwidth(); 01371 else 01372 return fontwidth() * strlen(text); 01373 } else { 01374 dim_t width = 0; 01375 01376 while (*text) { 01377 dim_t cWidth; 01378 if (getCharMetrics(*text, &cWidth, NULL)) 01379 width += cWidth; 01380 if (charOnly) 01381 break; 01382 text++; 01383 } 01384 return width * fontScaleX; 01385 } 01386 } 01387 01388 rect_t RA8875::GetTextRect(const char* text, bool charOnly) { 01389 rect_t rect = { 0, 0, 0, 0 }; 01390 01391 if (charOnly) { 01392 if (font == NULL) { 01393 rect.p2.x = fontwidth(); 01394 rect.p2.y = fontheight(); 01395 } else { 01396 dim_t cWidth, cHeight; 01397 if (getCharMetrics(*text, &cWidth, &cHeight)) { 01398 rect.p2.x = cWidth; 01399 rect.p2.y = cHeight; 01400 } 01401 } 01402 } else { 01403 rect.p2.y = fontheight(); 01404 const char* p = text; 01405 dim_t curX = 0; 01406 while (*p) { 01407 rect_t cRect = GetTextRect(p, true); 01408 switch (*p) { 01409 case '\r': 01410 curX = 0; 01411 break; 01412 case '\n': 01413 rect.p2.y += cRect.p2.y; 01414 break; 01415 default: 01416 if ((curX + cRect.p2.x) >= virt_screenwidth) { 01417 rect.p2.x = virt_screenwidth - 1; 01418 curX = cRect.p2.x; 01419 if ((rect.p2.y + cRect.p2.y) > virt_screenheight) { 01420 rect.p2.y = virt_screenheight - 1; 01421 } else { 01422 rect.p2.y += cRect.p2.y; 01423 } 01424 } else { 01425 curX += cRect.p2.x; 01426 if (curX > rect.p2.x) 01427 rect.p2.x = curX; 01428 } 01429 break; 01430 } 01431 if (rect.p2.y >= virt_screenheight - 1) 01432 break; 01433 p++; 01434 } 01435 } 01436 return rect; 01437 } 01438 01439 01440 int RA8875::_putc(int c) 01441 { 01442 if (font == NULL) { 01443 return _internal_putc(c); 01444 } else { 01445 return _external_putc(c); 01446 } 01447 } 01448 01449 01450 01451 // Questions to ponder - 01452 // - if we choose to wrap to the next line, because the character won't fit on the current line, 01453 // should it erase the space to the width of the screen (in case there is leftover junk there)? 01454 // - it currently wraps from the bottom of the screen back to the top. I have pondered what 01455 // it might take to scroll the screen - but haven't thought hard enough about it. 01456 // 01457 int RA8875::_external_putc(int c) 01458 { 01459 if (c) { 01460 if (c == '\r') { 01461 cursor_x = windowrect.p1.x; 01462 } else if (c == '\n') { 01463 cursor_y += extFontHeight; 01464 } else { 01465 dim_t charWidth, charHeight; 01466 const uint8_t * charRecord = getCharMetrics(c, &charWidth, &charHeight); 01467 if (charRecord) { 01468 //cursor_x += advance; 01469 if (cursor_x + charWidth >= windowrect.p2.x) { 01470 cursor_x = windowrect.p1.x; 01471 cursor_y += charHeight; 01472 } 01473 if (cursor_y + charHeight >= windowrect.p2.y) { 01474 cursor_y = windowrect.p1.y; // @todo Should it scroll? 01475 } 01476 (void)character(cursor_x, cursor_y, c); 01477 cursor_x += charWidth * fontScaleX; 01478 } 01479 } 01480 } 01481 return c; 01482 } 01483 01484 01485 int RA8875::_internal_putc(int c) 01486 { 01487 if (c) { 01488 unsigned char mwcr0 = ReadCommand(RA8875_MWCR0); 01489 if ((mwcr0 & 0x80) == 0x00) 01490 WriteCommand(RA8875_MWCR0, 0x80 | mwcr0); // Put in Text mode if not already 01491 if (c == '\r' || c == '\n') { 01492 point_t cur = GetTextCursor(); 01493 if (c == '\r') { 01494 cur.x = windowrect.p1.x; 01495 } else if (c == '\n') { 01496 cur.y += fontheight(); 01497 if (cur.y >= windowrect.p2.y) // @TODO after bottom of active window, then scroll window? 01498 cur.y = windowrect.p1.y; 01499 } 01500 SetTextCursor(cur); 01501 } else { 01502 WriteCommand(RA8875_MRWC); // RA8875 Internal Fonts 01503 _select(true); 01504 WriteData(c); 01505 _WaitWhileBusy(0x80); 01506 _select(false); 01507 } 01508 } 01509 return c; 01510 } 01511 01512 01513 RetCode_t RA8875::_StartGraphicsStream(void) 01514 { 01515 unsigned char mwcr0; 01516 01517 mwcr0 = ReadCommand(RA8875_MWCR0) & ~0x80; 01518 mwcr0 |= 0x00; 01519 //INFO("_StartGraphicsStream mwcr0: %02X", mwcr0); 01520 WriteCommand(RA8875_MWCR0, mwcr0); // Graphics write mode 01521 WriteCommand(RA8875_MRWC); // Prepare for streaming data 01522 return noerror; 01523 } 01524 01525 01526 RetCode_t RA8875::_EndGraphicsStream(void) 01527 { 01528 return noerror; 01529 } 01530 01531 01532 RetCode_t RA8875::_putp(color_t pixel) 01533 { 01534 WriteDataW((pixel>>8) | (pixel<<8)); 01535 return noerror; 01536 } 01537 01538 01539 void RA8875::puts(point_t pt, const char * string) 01540 { 01541 SetTextCursor(pt); 01542 puts(string); 01543 } 01544 01545 void RA8875::puts(loc_t x, loc_t y, const char * string) 01546 { 01547 SetTextCursor(x,y); 01548 puts(string); 01549 } 01550 01551 01552 void RA8875::puts(const char * string) 01553 { 01554 INFO("puts len(%d), (%s)", strlen(string), string); 01555 if (font == NULL) { 01556 unsigned char mwcr0 = ReadCommand(RA8875_MWCR0); 01557 if ((mwcr0 & 0x80) == 0x00) 01558 WriteCommand(RA8875_MWCR0, 0x80 | mwcr0); // Put in Text mode if not already 01559 } 01560 while (string && *string) { // @TODO calling individual _putc is slower... optimizations? 01561 if (wordwrap) { 01562 const char * p = string; 01563 const char * pSpace = NULL; 01564 dim_t txtPos; 01565 bool newLineNeeded = false; 01566 01567 point_t cursor = GetTextCursor(); 01568 //INFO("cursor (%d,%d)", cursor.x, cursor.y); 01569 txtPos = cursor.x; 01570 INFO("(%d,%d) string: '%s'", cursor.x, cursor.y, string); 01571 // find what fits in the window 01572 do { 01573 if (*p == ' ') 01574 pSpace = p; 01575 if (*p == '\r') { 01576 pSpace = p; 01577 break; 01578 } 01579 if (*p == '\n') { 01580 break; 01581 } 01582 dim_t cWidth = GetTextWidth(p, true); 01583 INFO("txtPos: %d, cWidth: %d, p2.x: %d", txtPos, cWidth, windowrect.p2.x); 01584 if (txtPos + cWidth <= windowrect.p2.x) { 01585 txtPos += cWidth; 01586 } else { 01587 newLineNeeded = true; 01588 break; 01589 } 01590 INFO("+ %c width %d, ttl Width %d <= %d", *p, cWidth, txtPos, windowrect.p2.x); 01591 p++; 01592 } while (*p); 01593 INFO("p: len(%d), (%s)", strlen(p), p); 01594 if (*p && *p != ' ' && pSpace) { 01595 p = pSpace; 01596 INFO("p: len(%d), (%s)", strlen(p), p); 01597 } 01598 char dbgBuf[256]; 01599 strncpy(dbgBuf, string, (p - string)); 01600 dbgBuf[p - string] = '\0'; 01601 INFO("chunk: %d <= w.p2.x: %d - '%s'", txtPos, windowrect.p2.x, dbgBuf); 01602 if (txtPos <= windowrect.p2.x) { 01603 while (*string && string <= p) { 01604 INFO("*string %02X", *string); 01605 if (*string == '\r') { 01606 cursor = GetTextCursor(); 01607 SetTextCursor(windowrect.p1.x, cursor.y); 01608 } else if (*string == '\n') { 01609 cursor = GetTextCursor(); 01610 SetTextCursor(cursor.x, cursor.y + fontheight()); 01611 } else { 01612 INFO("cursor (%d,%d) - %c", cursor.x, cursor.y, *string); 01613 _putc(*string); 01614 } 01615 string++; 01616 } 01617 } 01618 while (*string == ' ') 01619 string++; 01620 if (newLineNeeded) { 01621 cursor.y += fontheight(); 01622 SetTextCursor(cursor); 01623 INFO("\r\n"); 01624 } 01625 INFO("### '%s'\r\n\r\n", string); 01626 // if != ' ', find ' ', accumulating width along the way 01627 // if the width fits, print the chars 01628 } else { 01629 _putc(*string++); 01630 } 01631 } 01632 //point_t cursor = GetTextCursor(); 01633 //INFO("cursor (%d,%d)", cursor.x, cursor.y); 01634 } 01635 01636 01637 RetCode_t RA8875::SetGraphicsCursor(loc_t x, loc_t y) 01638 { 01639 switch (screen_orientation) { 01640 case rotate_0: 01641 case rotate_180: 01642 WriteCommandW(RA8875_CURH0, x); 01643 WriteCommandW(RA8875_CURV0, y); 01644 break; 01645 case rotate_90: 01646 case rotate_270: 01647 WriteCommandW(RA8875_CURH0, y); 01648 WriteCommandW(RA8875_CURV0, x); 01649 break; 01650 case invalid: 01651 return bad_parameter; 01652 } 01653 return noerror; 01654 } 01655 01656 RetCode_t RA8875::SetGraphicsCursor(point_t p) 01657 { 01658 return SetGraphicsCursor(p.x, p.y); 01659 } 01660 01661 point_t RA8875::GetGraphicsCursor(void) 01662 { 01663 point_t p; 01664 01665 switch (screen_orientation) { 01666 case rotate_0: 01667 case rotate_180: 01668 p.x = ReadCommandW(RA8875_CURH0); 01669 p.y = ReadCommandW(RA8875_CURV0); 01670 break; 01671 case rotate_90: 01672 case rotate_270: 01673 p.y = ReadCommandW(RA8875_CURH0); 01674 p.x = ReadCommandW(RA8875_CURV0); 01675 break; 01676 case invalid: 01677 p.x = p.y = 0; 01678 break; 01679 } 01680 return p; 01681 } 01682 01683 RetCode_t RA8875::SetGraphicsCursorRead(loc_t x, loc_t y) 01684 { 01685 switch (screen_orientation) { 01686 case rotate_0: 01687 case rotate_180: 01688 WriteCommandW(RA8875_RCURH0, x); 01689 WriteCommandW(RA8875_RCURV0, y); 01690 break; 01691 case rotate_90: 01692 case rotate_270: 01693 WriteCommandW(RA8875_RCURH0, y); 01694 WriteCommandW(RA8875_RCURV0, x); 01695 break; 01696 case invalid: 01697 return bad_parameter; 01698 } 01699 return noerror; 01700 } 01701 01702 01703 rect_t RA8875::GetWindow() { 01704 return windowrect; 01705 } 01706 01707 rect_t RA8875::SetWindow(rect_t r) 01708 { 01709 return SetWindow(r.p1.x, r.p1.y, r.p2.x, r.p2.y); 01710 } 01711 01712 rect_t RA8875::SetWindow(loc_t x1, loc_t y1, loc_t x2, loc_t y2) 01713 { 01714 rect_t nullRect = { 0,0,0,0 }; // in case it is invalid 01715 rect_t oldWin = windowrect; 01716 dim_t tempWidth, tempHeight; 01717 nullRect.p2.x = virt_screenwidth - 1; 01718 nullRect.p2.y = virt_screenheight - 1; 01719 //INFO("SetWindow(%d,%d)-(%d,%d)", x1,y1, x2,y2); 01720 // Correct the initial values (0,-1) - (0,-1) 01721 if (x2 == (loc_t)-1) x2 = virt_screenwidth - 1; 01722 if (y2 == (loc_t)-1) y2 = virt_screenheight - 1; 01723 // Sanity check the parameters. 01724 if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0 01725 || x1 >= virt_screenwidth || y1 >= virt_screenheight 01726 || x2 >= virt_screenwidth || y2 >= virt_screenheight) { 01727 return nullRect; 01728 } 01729 windowrect.p1.x = x1; 01730 windowrect.p1.y = y1; 01731 windowrect.p2.x = x2; 01732 windowrect.p2.y = y2; 01733 switch (screen_orientation) { 01734 case rotate_0: 01735 case rotate_180: 01736 tempWidth = RAmax(virt_screenwidth, virt_screenheight); 01737 tempHeight = RAmin(virt_screenwidth, virt_screenheight); 01738 virt_screenwidth = tempWidth; 01739 virt_screenheight = tempHeight; 01740 //GraphicsDisplay::SetWindow(x1, y1, x2, y2); 01741 WriteCommandW(RA8875_HSAW0, x1); 01742 WriteCommandW(RA8875_VSAW0, y1); 01743 WriteCommandW(RA8875_HEAW0, x2); 01744 WriteCommandW(RA8875_VEAW0, y2); 01745 break; 01746 case rotate_90: 01747 case rotate_270: 01748 tempWidth = RAmin(virt_screenwidth, virt_screenheight); 01749 tempHeight = RAmax(virt_screenwidth, virt_screenheight); 01750 virt_screenwidth = tempWidth; 01751 virt_screenheight = tempHeight; 01752 //GraphicsDisplay::SetWindow(x1, y1, x2, y2); 01753 WriteCommandW(RA8875_HSAW0, y1); 01754 WriteCommandW(RA8875_VSAW0, x1); 01755 WriteCommandW(RA8875_HEAW0, y2); 01756 WriteCommandW(RA8875_VEAW0, x2); 01757 break; 01758 case invalid: 01759 break; 01760 } 01761 return oldWin; 01762 } 01763 01764 RetCode_t RA8875::cls(uint16_t layers) 01765 { 01766 RetCode_t ret = noerror; 01767 01768 INFO("cls(%d)", layers); 01769 PERFORMANCE_RESET; 01770 if (layers == 0) { 01771 ret = clsw(FULLWINDOW); 01772 } else if (layers > 3) { 01773 ret = bad_parameter; 01774 } else { 01775 uint16_t prevLayer = GetDrawingLayer(); 01776 if (layers & 1) { 01777 SelectDrawingLayer(0); 01778 clsw(FULLWINDOW); 01779 } 01780 if (layers & 2) { 01781 SelectDrawingLayer(1); 01782 clsw(FULLWINDOW); 01783 } 01784 SelectDrawingLayer(prevLayer); 01785 } 01786 SetTextCursor(0,0); 01787 //ret = locate(0,0); 01788 REGISTERPERFORMANCE(PRF_CLS); 01789 return ret; 01790 } 01791 01792 01793 RetCode_t RA8875::clsw(RA8875::Region_t region) 01794 { 01795 INFO("clsw(%d)", region); 01796 PERFORMANCE_RESET; 01797 WriteCommand(RA8875_MCLR, (region == ACTIVEWINDOW) ? 0xC0 : 0x80); 01798 if (!_WaitWhileReg(RA8875_MCLR, 0x80)) { 01799 WriteCommand(RA8875_MCLR, 0x00); // Abort clearing on request 01800 REGISTERPERFORMANCE(PRF_CLS); 01801 return external_abort; 01802 } 01803 REGISTERPERFORMANCE(PRF_CLS); 01804 return noerror; 01805 } 01806 01807 01808 RetCode_t RA8875::pixel(point_t p, color_t color) 01809 { 01810 return pixel(p.x, p.y, color); 01811 } 01812 01813 RetCode_t RA8875::pixel(point_t p) 01814 { 01815 return pixel(p.x, p.y); 01816 } 01817 01818 RetCode_t RA8875::pixel(loc_t x, loc_t y, color_t color) 01819 { 01820 RetCode_t ret; 01821 01822 PERFORMANCE_RESET; 01823 ret = pixelStream(&color, 1, x,y); 01824 REGISTERPERFORMANCE(PRF_DRAWPIXEL); 01825 return ret; 01826 } 01827 01828 01829 RetCode_t RA8875::pixel(loc_t x, loc_t y) 01830 { 01831 RetCode_t ret; 01832 01833 PERFORMANCE_RESET; 01834 color_t color = GetForeColor(); 01835 ret = pixelStream(&color, 1, x, y); 01836 REGISTERPERFORMANCE(PRF_DRAWPIXEL); 01837 return ret; 01838 } 01839 01840 01841 RetCode_t RA8875::pixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) 01842 { 01843 PERFORMANCE_RESET; 01844 SetGraphicsCursor(x, y); 01845 _StartGraphicsStream(); 01846 _select(true); 01847 _spiwrite(0x00); // Cmd: write data 01848 while (count--) { 01849 if (screenbpp == 16) { 01850 _spiwrite(*p >> 8); 01851 _spiwrite(*p & 0xFF); 01852 } else { 01853 _spiwrite(_cvt16to8(*p)); 01854 } 01855 p++; 01856 } 01857 _select(false); 01858 _EndGraphicsStream(); 01859 REGISTERPERFORMANCE(PRF_PIXELSTREAM); 01860 return(noerror); 01861 } 01862 01863 // With a font scale X = 1, a pixel stream is "abcdefg..." 01864 // With a font scale X = 2, a pixel stream is "aabbccddeeffgg..." 01865 // With a font scale Y = 2, a pixel stream is "abcdefg..." 01866 // "abcdefg..." 01867 // 01868 RetCode_t RA8875::booleanStream(loc_t x, loc_t y, dim_t w, dim_t h, const uint8_t * boolStream) 01869 { 01870 PERFORMANCE_RESET; 01871 const uint8_t * rowStream = boolStream; 01872 loc_t x2,y2; 01873 x2 = x + w * fontScaleX - 1; 01874 y2 = y + h * fontScaleY - 1; 01875 if (x2 >= virt_screenwidth) { 01876 x -= (x2 - virt_screenwidth + 1); 01877 x2 = virt_screenwidth - 1; 01878 } 01879 if (y2 >= virt_screenheight) { 01880 y -= (y2 - virt_screenheight + 1); 01881 y2 = virt_screenheight - 1; 01882 } 01883 rect_t restore = SetWindow(x, y, x2, y2); 01884 SetGraphicsCursor(x, y); 01885 _StartGraphicsStream(); 01886 _select(true); 01887 _spiwrite(0x00); // Cmd: write data 01888 while (h--) { 01889 for (int dy=0; dy<fontScaleY; dy++) { // Vertical Font Scale Factor 01890 uint8_t pixels = w; 01891 uint8_t bitmask = 0x01; 01892 rowStream = boolStream; 01893 while (pixels) { 01894 uint8_t byte = *rowStream; 01895 //INFO("byte, mask: %02X, %02X", byte, bitmask); 01896 color_t c = (byte & bitmask) ? _foreground : _background; 01897 01898 for (int dx=0; dx<fontScaleX; dx++) { // Horizontal Font Scale Factor 01899 if (screenbpp == 16) { 01900 _spiwrite(c >> 8); 01901 _spiwrite(c & 0xFF); 01902 } else { 01903 _spiwrite(_cvt16to8(c)); 01904 } 01905 } 01906 bitmask <<= 1; 01907 if (pixels > 1 && bitmask == 0) { 01908 bitmask = 0x01; 01909 rowStream++; 01910 } 01911 pixels--; 01912 } 01913 } 01914 boolStream += (rowStream - boolStream + 1); 01915 } 01916 _select(false); 01917 _EndGraphicsStream(); 01918 SetWindow(restore); 01919 REGISTERPERFORMANCE(PRF_BOOLSTREAM); 01920 return(noerror); 01921 } 01922 01923 color_t RA8875::getPixel(loc_t x, loc_t y) 01924 { 01925 color_t pixel; 01926 unsigned char mwcr0; 01927 01928 PERFORMANCE_RESET; 01929 mwcr0 = ReadCommand(RA8875_MWCR0); 01930 if (mwcr0 & 0x80) 01931 WriteCommand(RA8875_MWCR0, mwcr0 & ~0x80); // Graphics write mode 01932 SetGraphicsCursorRead(x, y); 01933 WriteCommand(RA8875_MRWC); 01934 _select(true); 01935 _spiwrite(0x40); // Cmd: read data 01936 _spiwrite(0x00); // dummy read 01937 if (screenbpp == 16) { 01938 pixel = _spiread(); 01939 pixel |= (_spiread() << 8); 01940 } else { 01941 pixel = _cvt8to16(_spiread()); 01942 } 01943 _select(false); 01944 REGISTERPERFORMANCE(PRF_READPIXEL); 01945 return pixel; 01946 } 01947 01948 01949 RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) 01950 { 01951 color_t pixel; 01952 unsigned char mwcr0; 01953 RetCode_t ret = noerror; 01954 01955 PERFORMANCE_RESET; 01956 mwcr0 = ReadCommand(RA8875_MWCR0); 01957 if (mwcr0 & 0x80) 01958 WriteCommand(RA8875_MWCR0, mwcr0 & ~0x80); // Graphics write mode 01959 ret = SetGraphicsCursorRead(x, y); 01960 ret = WriteCommand(RA8875_MRWC); 01961 _select(true); 01962 _spiwrite(0x40); // Cmd: read data 01963 _spiwrite(0x00); // dummy read 01964 if (screenbpp == 16) 01965 _spiwrite(0x00); // dummy read is only necessary when in 16-bit mode 01966 while (count--) { 01967 if (screenbpp == 16) { 01968 pixel = _spiread(); 01969 pixel |= (_spiread() << 8); 01970 } else { 01971 pixel = _cvt8to16(_spiread()); 01972 } 01973 *p++ = pixel; 01974 } 01975 _select(false); 01976 REGISTERPERFORMANCE(PRF_READPIXELSTREAM); 01977 return ret; 01978 } 01979 01980 01981 RetCode_t RA8875::line(point_t p1, point_t p2) 01982 { 01983 return line(p1.x, p1.y, p2.x, p2.y); 01984 } 01985 01986 01987 RetCode_t RA8875::line(point_t p1, point_t p2, color_t color) 01988 { 01989 return line(p1.x, p1.y, p2.x, p2.y, color); 01990 } 01991 01992 01993 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2, color_t color) 01994 { 01995 foreground(color); 01996 return line(x1,y1,x2,y2); 01997 } 01998 01999 02000 RetCode_t RA8875::line(loc_t x1, loc_t y1, loc_t x2, loc_t y2) 02001 { 02002 PERFORMANCE_RESET; 02003 if (x1 == x2 && y1 == y2) { 02004 switch (screen_orientation) { 02005 case invalid: 02006 return bad_parameter; 02007 //break; 02008 case rotate_0: 02009 case rotate_180: 02010 pixel(x1, y1); 02011 break; 02012 case rotate_90: 02013 case rotate_270: 02014 pixel(y1, x1); 02015 break; 02016 } 02017 } else { 02018 switch (screen_orientation) { 02019 case invalid: 02020 return bad_parameter; 02021 //break; 02022 case rotate_0: 02023 case rotate_180: 02024 WriteCommandW(RA8875_DLHSR0, x1); 02025 WriteCommandW(RA8875_DLVSR0, y1); 02026 WriteCommandW(RA8875_DLHER0, x2); 02027 WriteCommandW(RA8875_DLVER0, y2); 02028 break; 02029 case rotate_90: 02030 case rotate_270: 02031 WriteCommandW(RA8875_DLHSR0, y1); 02032 WriteCommandW(RA8875_DLVSR0, x1); 02033 WriteCommandW(RA8875_DLHER0, y2); 02034 WriteCommandW(RA8875_DLVER0, x2); 02035 break; 02036 } 02037 unsigned char drawCmd = 0x00; // Line 02038 WriteCommand(RA8875_DCR, drawCmd); 02039 WriteCommand(RA8875_DCR, 0x80 + drawCmd); // Start drawing. 02040 if (!_WaitWhileReg(0x90, 0x80)) { 02041 REGISTERPERFORMANCE(PRF_DRAWLINE); 02042 return external_abort; 02043 } 02044 } 02045 REGISTERPERFORMANCE(PRF_DRAWLINE); 02046 return noerror; 02047 } 02048 02049 02050 RetCode_t RA8875::ThickLine(point_t p1, point_t p2, dim_t thickness, color_t color) 02051 { 02052 //INFO("ThickLine()"); 02053 if (thickness == 1) { 02054 line(p1,p2, color); 02055 } else { 02056 if (p1.x == p2.x) { 02057 // vertical 02058 if (roundCap) { 02059 fillcircle(p1, thickness / 2, color); 02060 fillcircle(p2, thickness / 2, color); 02061 } 02062 fillrect(p1.x-thickness/2,p1.y, p2.x+thickness/2,p2.y, color); 02063 } else if (p1.y == p2.y) { 02064 // horizontal 02065 if (roundCap) { 02066 fillcircle(p1, thickness / 2, color); 02067 fillcircle(p2, thickness / 2, color); 02068 } 02069 fillrect(p1.x,p1.y-thickness/2, p2.x,p2.y+thickness/2, color); 02070 } else { 02071 // some diagonal, drawn rather slowly with filled circles 02072 // @todo draw the end-points with circles, then draw the diagonal 02073 // with 2 triangles. 02074 //Round-caps 02075 if (roundCap) { 02076 fillcircle(p1, thickness / 2, color); 02077 fillcircle(p2, thickness / 2, color); 02078 } 02079 // Compute the perpendicular points to draw the triangles 02080 // + fillTriangle: p1a,p1b,p2a 02081 // / + p1a p1a,p2a,p2b 02082 // + +p1+ . . . . . 02083 // p1b + / . angle 02084 // + . 02085 // . 02086 // 02087 // . + 02088 // / + p2a 02089 // + +p2+ 02090 // p2b + / 02091 // + 02092 point_t pTri[4]; 02093 float slope = (p2.y - p1.y) / (p2.x - p1.x); 02094 slope = -1/slope; 02095 //centerline 02096 //line(p1,p2,color); 02097 float dx = (thickness/2 / sqrt(thickness/2 + (slope * slope))); 02098 float dy = slope * dx; 02099 pTri[0].x = p1.x + dx; 02100 pTri[0].y = p1.y + dy; 02101 pTri[1].x = p1.x - dx; 02102 pTri[1].y = p1.y - dy; 02103 pTri[2].x = p2.x + dx; 02104 pTri[2].y = p2.y + dy; 02105 pTri[3].x = p2.x - dx; 02106 pTri[3].y = p2.y - dy; 02107 filltriangle(pTri[0],pTri[1],pTri[3], color); 02108 filltriangle(pTri[0],pTri[2],pTri[3], color); 02109 } 02110 } 02111 return noerror; 02112 } 02113 02114 02115 bool RA8875::SetEndCap(bool _roundCap) { 02116 bool prevCap = roundCap; 02117 roundCap = _roundCap; 02118 return prevCap; 02119 } 02120 02121 02122 // 02123 // Rectangle functions all mostly helpers to the basic rectangle function 02124 // 02125 02126 RetCode_t RA8875::fillrect(rect_t r, color_t color, fill_t fillit) 02127 { 02128 return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit); 02129 } 02130 02131 RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02132 color_t color, fill_t fillit) 02133 { 02134 return rect(x1,y1,x2,y2,color,fillit); 02135 } 02136 02137 RetCode_t RA8875::rect(rect_t r, color_t color, fill_t fillit) 02138 { 02139 return rect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, color, fillit); 02140 } 02141 02142 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02143 color_t color, fill_t fillit) 02144 { 02145 foreground(color); 02146 return rect(x1,y1,x2,y2,fillit); 02147 } 02148 02149 RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02150 fill_t fillit) 02151 { 02152 RetCode_t ret = noerror; 02153 PERFORMANCE_RESET; 02154 // check for bad_parameter 02155 if (x1 < 0 || x1 >= virt_screenwidth || x2 < 0 || x2 >= virt_screenwidth 02156 || y1 < 0 || y1 >= virt_screenheight || y2 < 0 || y2 >= virt_screenheight) { 02157 ret = bad_parameter; 02158 } else { 02159 if (x1 == x2 && y1 == y2) { 02160 pixel(x1, y1); 02161 } else if (x1 == x2) { 02162 line(x1, y1, x2, y2); 02163 } else if (y1 == y2) { 02164 line(x1, y1, x2, y2); 02165 } else { 02166 switch (screen_orientation) { 02167 case rotate_0: 02168 case rotate_180: 02169 WriteCommandW(RA8875_DLHSR0, x1); 02170 WriteCommandW(RA8875_DLVSR0, y1); 02171 WriteCommandW(RA8875_DLHER0, x2); 02172 WriteCommandW(RA8875_DLVER0, y2); 02173 break; 02174 case rotate_90: 02175 case rotate_270: 02176 WriteCommandW(RA8875_DLHSR0, y1); 02177 WriteCommandW(RA8875_DLVSR0, x1); 02178 WriteCommandW(RA8875_DLHER0, y2); 02179 WriteCommandW(RA8875_DLVER0, x2); 02180 break; 02181 case invalid: 02182 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE); 02183 ret = bad_parameter; 02184 return ret; 02185 //break; 02186 } 02187 unsigned char drawCmd = 0x10; // Rectangle 02188 if (fillit == FILL) 02189 drawCmd |= 0x20; 02190 WriteCommand(RA8875_DCR, drawCmd); 02191 ret = WriteCommand(RA8875_DCR, 0x80 + drawCmd); // Start drawing. 02192 if (!_WaitWhileReg(0x90, 0x80)) { 02193 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE); 02194 return external_abort; 02195 } 02196 } 02197 } 02198 REGISTERPERFORMANCE(PRF_DRAWRECTANGLE); 02199 return ret; 02200 } 02201 02202 02203 // 02204 // rounded rectangle functions are mostly helpers to the base round rect 02205 // 02206 02207 RetCode_t RA8875::fillroundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02208 { 02209 return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit); 02210 } 02211 02212 RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02213 dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02214 { 02215 foreground(color); 02216 return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); 02217 } 02218 02219 RetCode_t RA8875::roundrect(rect_t r, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02220 { 02221 return roundrect(r.p1.x, r.p1.y, r.p2.x, r.p2.y, radius1, radius2, color, fillit); 02222 } 02223 02224 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02225 dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02226 { 02227 foreground(color); 02228 return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); 02229 } 02230 02231 02232 RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02233 dim_t radius1, dim_t radius2, fill_t fillit) 02234 { 02235 RetCode_t ret = noerror; 02236 02237 INFO("roundrect()"); 02238 PERFORMANCE_RESET; 02239 if (x1 < 0 || x1 >= virt_screenwidth || x2 < 0 || x2 >= virt_screenwidth 02240 || y1 < 0 || y1 >= virt_screenheight || y2 < 0 || y2 >= virt_screenheight) { 02241 ret = bad_parameter; 02242 } else if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) { 02243 ret = bad_parameter; 02244 } else if (x1 == x2 && y1 == y2) { 02245 pixel(x1, y1); 02246 } else if (x1 == x2) { 02247 line(x1, y1, x2, y2); 02248 } else if (y1 == y2) { 02249 line(x1, y1, x2, y2); 02250 } else { 02251 switch (screen_orientation) { 02252 case rotate_0: 02253 case rotate_180: 02254 WriteCommandW(RA8875_DLHSR0, x1); 02255 WriteCommandW(RA8875_DLVSR0, y1); 02256 WriteCommandW(RA8875_DLHER0, x2); 02257 WriteCommandW(RA8875_DLVER0, y2); 02258 WriteCommandW(RA8875_ELLA0, radius1); 02259 WriteCommandW(RA8875_ELLB0, radius2); 02260 break; 02261 case rotate_90: 02262 case rotate_270: 02263 WriteCommandW(RA8875_DLHSR0, y1); 02264 WriteCommandW(RA8875_DLVSR0, x1); 02265 WriteCommandW(RA8875_DLHER0, y2); 02266 WriteCommandW(RA8875_DLVER0, x2); 02267 WriteCommandW(RA8875_ELLA0, radius2); 02268 WriteCommandW(RA8875_ELLB0, radius1); 02269 break; 02270 case invalid: 02271 REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE); 02272 return bad_parameter; 02273 //break; 02274 } 02275 // Should not need this... 02276 WriteCommandW(RA8875_DEHR0, 0); 02277 WriteCommandW(RA8875_DEVR0, 0); 02278 unsigned char drawCmd = 0x20; // Rounded Rectangle 02279 if (fillit == FILL) 02280 drawCmd |= 0x40; 02281 WriteCommand(RA8875_ELLIPSE, drawCmd); 02282 WriteCommand(RA8875_ELLIPSE, 0x80 + drawCmd); // Start drawing. 02283 if (!_WaitWhileReg(0xA0, 0x80)) { 02284 REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE); 02285 return external_abort; 02286 } 02287 } 02288 REGISTERPERFORMANCE(PRF_DRAWROUNDEDRECTANGLE); 02289 return ret; 02290 } 02291 02292 02293 // 02294 // triangle functions 02295 // 02296 RetCode_t RA8875::filltriangle(point_t p1, point_t p2, point_t p3, color_t color, fill_t fillit) 02297 { 02298 return filltriangle(p1.x,p1.y, p2.x,p2.y, p3.x,p3.y, color, fillit); 02299 } 02300 02301 RetCode_t RA8875::triangle(point_t p1, point_t p2, point_t p3, color_t color, fill_t fillit) 02302 { 02303 return triangle(p1.x,p1.y, p2.x,p2.y, p3.x,p3.y, color, fillit); 02304 } 02305 02306 RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02307 loc_t x3, loc_t y3, color_t color, fill_t fillit) 02308 { 02309 RetCode_t ret; 02310 02311 if (x1 < 0 || x1 >= virt_screenwidth || x2 < 0 || x2 >= virt_screenwidth || x3 < 0 || x3 >= virt_screenwidth 02312 || y1 < 0 || y1 >= virt_screenheight || y2 < 0 || y2 >= virt_screenheight || y3 < 0 || y3 >= virt_screenheight) 02313 ret = bad_parameter; 02314 foreground(color); 02315 ret = triangle(x1,y1,x2,y2,x3,y3,fillit); 02316 return ret; 02317 } 02318 02319 02320 RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, 02321 loc_t x3, loc_t y3, color_t color, fill_t fillit) 02322 { 02323 RetCode_t ret; 02324 02325 foreground(color); 02326 ret = triangle(x1,y1,x2,y2,x3,y3,fillit); 02327 return ret; 02328 } 02329 02330 02331 RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2, 02332 loc_t x3, loc_t y3, fill_t fillit) 02333 { 02334 RetCode_t ret = noerror; 02335 02336 INFO("triangle"); 02337 PERFORMANCE_RESET; 02338 if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) { 02339 pixel(x1, y1); 02340 } else { 02341 switch (screen_orientation) { 02342 case rotate_0: 02343 case rotate_180: 02344 WriteCommandW(RA8875_DLHSR0, x1); 02345 WriteCommandW(RA8875_DLVSR0, y1); 02346 WriteCommandW(RA8875_DLHER0, x2); 02347 WriteCommandW(RA8875_DLVER0, y2); 02348 WriteCommandW(RA8875_DTPH0, x3); 02349 WriteCommandW(RA8875_DTPV0, y3); 02350 break; 02351 case rotate_90: 02352 case rotate_270: 02353 WriteCommandW(RA8875_DLHSR0, y1); 02354 WriteCommandW(RA8875_DLVSR0, x1); 02355 WriteCommandW(RA8875_DLHER0, y2); 02356 WriteCommandW(RA8875_DLVER0, x2); 02357 WriteCommandW(RA8875_DTPH0, y3); 02358 WriteCommandW(RA8875_DTPV0, x3); 02359 break; 02360 case invalid: 02361 REGISTERPERFORMANCE(PRF_DRAWTRIANGLE); 02362 return bad_parameter; 02363 //break; 02364 } 02365 unsigned char drawCmd = 0x01; // Triangle 02366 if (fillit == FILL) 02367 drawCmd |= 0x20; 02368 WriteCommand(RA8875_DCR, drawCmd); 02369 WriteCommand(RA8875_DCR, 0x80 + drawCmd); // Start drawing. 02370 if (!_WaitWhileReg(0x90, 0x80)) { 02371 REGISTERPERFORMANCE(PRF_DRAWTRIANGLE); 02372 return external_abort; 02373 } 02374 } 02375 REGISTERPERFORMANCE(PRF_DRAWTRIANGLE); 02376 return ret; 02377 } 02378 02379 02380 RetCode_t RA8875::circle(point_t p, dim_t radius, 02381 color_t color, fill_t fillit) 02382 { 02383 foreground(color); 02384 return circle(p.x,p.y,radius,fillit); 02385 } 02386 02387 02388 RetCode_t RA8875::fillcircle(point_t p, dim_t radius, 02389 color_t color, fill_t fillit) 02390 { 02391 foreground(color); 02392 return circle(p.x,p.y,radius,fillit); 02393 } 02394 02395 02396 RetCode_t RA8875::circle(point_t p, dim_t radius, fill_t fillit) 02397 { 02398 return circle(p.x,p.y,radius,fillit); 02399 } 02400 02401 02402 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, 02403 color_t color, fill_t fillit) 02404 { 02405 foreground(color); 02406 return circle(x,y,radius,fillit); 02407 } 02408 02409 02410 RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius, 02411 color_t color, fill_t fillit) 02412 { 02413 foreground(color); 02414 return circle(x,y,radius,fillit); 02415 } 02416 02417 RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit) 02418 { 02419 RetCode_t ret = noerror; 02420 02421 INFO("circle"); 02422 PERFORMANCE_RESET; 02423 if ((x - radius) < 0 || (x + radius) > width() 02424 || (y - radius) < 0 || (y + radius) > height()) { 02425 ret = bad_parameter; 02426 } else if (radius == 1) { 02427 pixel(x,y); 02428 } else { 02429 switch (screen_orientation) { 02430 case rotate_0: 02431 case rotate_180: 02432 WriteCommandW(RA8875_DCHR0, x); 02433 WriteCommandW(RA8875_DCVR0, y); 02434 break; 02435 case rotate_90: 02436 case rotate_270: 02437 WriteCommandW(RA8875_DCHR0, y); 02438 WriteCommandW(RA8875_DCVR0, x); 02439 break; 02440 case invalid: 02441 REGISTERPERFORMANCE(PRF_DRAWCIRCLE); 02442 return bad_parameter; 02443 //break; 02444 } 02445 WriteCommand(RA8875_DCRR, radius & 0xFF); 02446 unsigned char drawCmd = 0x00; // Circle 02447 if (fillit == FILL) 02448 drawCmd |= 0x20; 02449 WriteCommand(RA8875_DCR, drawCmd); 02450 WriteCommand(RA8875_DCR, 0x40 + drawCmd); // Start drawing. 02451 if (!_WaitWhileReg(0x90, 0x40)) { 02452 REGISTERPERFORMANCE(PRF_DRAWCIRCLE); 02453 return external_abort; 02454 } 02455 } 02456 REGISTERPERFORMANCE(PRF_DRAWCIRCLE); 02457 return ret; 02458 } 02459 02460 02461 RetCode_t RA8875::ellipse(point_t p, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02462 { 02463 return ellipse(p.x, p.y, radius1, radius2, color, fillit); 02464 } 02465 02466 02467 RetCode_t RA8875::fillellipse(point_t p, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02468 { 02469 return fillellipse(p.x, p.y, radius1, radius2, color, fillit); 02470 } 02471 02472 02473 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02474 { 02475 foreground(color); 02476 return ellipse(x,y,radius1,radius2,fillit); 02477 } 02478 02479 02480 RetCode_t RA8875::fillellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, color_t color, fill_t fillit) 02481 { 02482 foreground(color); 02483 return ellipse(x,y,radius1,radius2,fillit); 02484 } 02485 02486 02487 RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit) 02488 { 02489 RetCode_t ret = noerror; 02490 02491 INFO("ellipse"); 02492 PERFORMANCE_RESET; 02493 if ((x - radius1) < 0 || (x + radius1) > virt_screenwidth 02494 || (y - radius2) < 0 || (y + radius2) > virt_screenheight) { 02495 ret = bad_parameter; 02496 } else if (radius1 == 1 && radius2 == 1) { 02497 pixel(x, y); 02498 } else { 02499 switch (screen_orientation) { 02500 case rotate_0: 02501 case rotate_180: 02502 WriteCommandW(RA8875_DEHR0, x); 02503 WriteCommandW(RA8875_DEVR0, y); 02504 break; 02505 case rotate_90: 02506 case rotate_270: 02507 WriteCommandW(RA8875_DEHR0, y); 02508 WriteCommandW(RA8875_DEVR0, x); 02509 break; 02510 case invalid: 02511 REGISTERPERFORMANCE(PRF_DRAWELLIPSE); 02512 return bad_parameter; 02513 //break; 02514 } 02515 WriteCommandW(RA8875_ELLA0, radius1); 02516 WriteCommandW(RA8875_ELLB0, radius2); 02517 unsigned char drawCmd = 0x00; // Ellipse 02518 if (fillit == FILL) 02519 drawCmd |= 0x40; 02520 WriteCommand(RA8875_ELLIPSE, drawCmd); 02521 WriteCommand(RA8875_ELLIPSE, 0x80 + drawCmd); // Start drawing. 02522 if (!_WaitWhileReg(0xA0, 0x80)) { 02523 REGISTERPERFORMANCE(PRF_DRAWELLIPSE); 02524 return external_abort; 02525 } 02526 } 02527 REGISTERPERFORMANCE(PRF_DRAWELLIPSE); 02528 return ret; 02529 } 02530 02531 02532 RetCode_t RA8875::frequency(unsigned long Hz, unsigned long Hz2) 02533 { 02534 spiwritefreq = Hz; 02535 if (Hz2 != 0) 02536 spireadfreq = Hz2; 02537 else 02538 spireadfreq = Hz/2; 02539 _setWriteSpeed(true); 02540 // __ ___ 02541 // Clock ___A Rising edge latched 02542 // ___ ____ 02543 // Data ___X____ 02544 spi.format(8, 3); // 8 bits and clock to data phase 0 02545 return noerror; 02546 } 02547 02548 void RA8875::_setWriteSpeed(bool writeSpeed) 02549 { 02550 if (writeSpeed) { 02551 spi.frequency(spiwritefreq); 02552 spiWriteSpeed = true; 02553 } else { 02554 spi.frequency(spireadfreq); 02555 spiWriteSpeed = false; 02556 } 02557 } 02558 02559 02560 02561 RetCode_t RA8875::BlockMove(uint8_t dstLayer, uint8_t dstDataSelect, point_t dstPoint, 02562 uint8_t srcLayer, uint8_t srcDataSelect, point_t srcPoint, 02563 dim_t bte_width, dim_t bte_height, 02564 uint8_t bte_op_code, uint8_t bte_rop_code) 02565 { 02566 uint8_t cmd; 02567 02568 PERFORMANCE_RESET; 02569 ///@todo range check and error return rather than to secretly fix 02570 srcPoint.x &= 0x3FF; // prevent high bits from doing unexpected things 02571 srcPoint.y &= 0x1FF; 02572 dstPoint.x &= 0x3FF; 02573 dstPoint.y &= 0x1FF; 02574 WriteCommandW(RA8875_HSBE0, srcPoint.x); 02575 WriteCommandW(RA8875_VSBE0, ((dim_t)(srcLayer & 1) << 15) | srcPoint.y); 02576 WriteCommandW(RA8875_HDBE0, dstPoint.x); 02577 WriteCommandW(RA8875_VDBE0, ((dim_t)(dstLayer & 1) << 15) | dstPoint.y); 02578 WriteCommandW(RA8875_BEWR0, bte_width); 02579 WriteCommandW(RA8875_BEHR0, bte_height); 02580 WriteCommand(RA8875_BECR1, ((bte_rop_code & 0x0F) << 4) | (bte_op_code & 0x0F)); 02581 cmd = ((srcDataSelect & 1) << 6) | ((dstDataSelect & 1) << 5); 02582 WriteCommand(RA8875_BECR0, 0x80 | cmd); // enable the BTE 02583 if (!_WaitWhileBusy(0x40)) { 02584 REGISTERPERFORMANCE(PRF_BLOCKMOVE); 02585 return external_abort; 02586 } 02587 REGISTERPERFORMANCE(PRF_BLOCKMOVE); 02588 return noerror; 02589 } 02590 02591 02592 RetCode_t RA8875::Power(bool on) 02593 { 02594 WriteCommand(RA8875_PWRR, (on) ? 0x80 : 0x00); 02595 return noerror; 02596 } 02597 02598 02599 RetCode_t RA8875::Backlight_u8(uint8_t brightness) 02600 { 02601 static bool is_enabled = false; 02602 02603 if (brightness == 0) { 02604 WriteCommand(RA8875_P1CR); // Disable the PWM 02605 WriteData(0x00); 02606 is_enabled = false; 02607 } else if (!is_enabled) { 02608 WriteCommand(RA8875_P1CR); // Enable the PWM 02609 WriteData(0x80); 02610 WriteCommand(RA8875_P1CR); // Not sure why this is needed, but following the pattern 02611 WriteData(0x81); // open PWM (SYS_CLK / 2 as best I can tell) 02612 is_enabled = true; 02613 } 02614 WriteCommand(RA8875_P1DCR, brightness); // Brightness parameter 0xff-0x00 02615 return noerror; 02616 } 02617 02618 uint8_t RA8875::GetBacklight_u8(void) 02619 { 02620 return ReadCommand(0x8b); 02621 } 02622 02623 RetCode_t RA8875::Backlight(float brightness) 02624 { 02625 unsigned char b; 02626 02627 if (brightness >= 1.0) 02628 b = 255; 02629 else if (brightness <= 0.0) 02630 b = 0; 02631 else 02632 b = (unsigned char)(brightness * 255); 02633 return Backlight_u8(b); 02634 } 02635 02636 float RA8875::GetBacklight(void) 02637 { 02638 return (float)(GetBacklight_u8())/255; 02639 } 02640 02641 RetCode_t RA8875::SelectUserFont(const uint8_t * _font) 02642 { 02643 INFO("SelectUserFont(%p)", _font); 02644 if (_font) { 02645 HexDump("Font Memory", _font, 16); 02646 extFontHeight = _font[6]; 02647 uint32_t totalWidth = 0; 02648 uint16_t firstChar = _font[3] * 256 + _font[2]; 02649 uint16_t lastChar = _font[5] * 256 + _font[4]; 02650 uint16_t i; 02651 02652 for (i=firstChar; i<=lastChar; i++) { 02653 // 8 bytes of preamble to the first level lookup table 02654 uint16_t offsetToCharLookup = 8 + 4 * (i - firstChar); // 4-bytes: width(pixels), 16-bit offset from table start, 0 02655 totalWidth += _font[offsetToCharLookup]; 02656 } 02657 extFontWidth = totalWidth / (lastChar - firstChar); 02658 INFO("Font Metrics: Avg W: %2d, H: %2d, First:%d, Last:%d", extFontWidth, extFontHeight, firstChar, lastChar); 02659 } 02660 SetTextCursor(GetTextCursor()); // soft-font cursor -> hw cursor 02661 font = _font; 02662 return GraphicsDisplay::SelectUserFont(_font); 02663 } 02664 02665 color_t RA8875::background(color_t color) 02666 { 02667 color_t oldColor = GetBackColor(); 02668 GraphicsDisplay::background(color); 02669 _writeColorTrio(0x60, color); 02670 return oldColor; 02671 } 02672 02673 02674 color_t RA8875::background(unsigned char r, unsigned char g, unsigned char b) 02675 { 02676 return background(RGB(r,g,b)); 02677 } 02678 02679 color_t RA8875::GetBackColor(void) 02680 { 02681 return _readColorTrio(0x60); 02682 } 02683 02684 02685 color_t RA8875::foreground(color_t color) 02686 { 02687 color_t oldColor = GetForeColor(); 02688 GraphicsDisplay::foreground(color); 02689 _writeColorTrio(0x63, color); 02690 return oldColor; 02691 } 02692 02693 02694 color_t RA8875::foreground(unsigned char r, unsigned char g, unsigned char b) 02695 { 02696 return foreground(RGB(r,g,b)); 02697 } 02698 02699 color_t RA8875::GetForeColor(void) 02700 { 02701 return _readColorTrio(0x63); 02702 } 02703 02704 02705 02706 color_t RA8875::DOSColor(int i) 02707 { 02708 const color_t colors[16] = { 02709 Black, Blue, Green, Cyan, 02710 Red, Magenta, Brown, Gray, 02711 Charcoal, BrightBlue, BrightGreen, BrightCyan, 02712 Orange, Pink, Yellow, White 02713 }; 02714 if (i >= 0 && i < 16) 02715 return colors[i]; 02716 else 02717 return 0; 02718 } 02719 02720 02721 const char * RA8875::DOSColorNames(int i) 02722 { 02723 const char * names[16] = { 02724 "Black", "Blue", "Green", "Cyan", 02725 "Red", "Magenta", "Brown", "Gray", 02726 "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan", 02727 "Orange", "Pink", "Yellow", "White" 02728 }; 02729 if (i >= 0 && i < 16) 02730 return names[i]; 02731 else 02732 return NULL; 02733 } 02734 02735 02736 /////////////////////////////////////////////////////////////// 02737 // Private functions 02738 02739 unsigned char RA8875::_spiwrite(unsigned char data) 02740 { 02741 unsigned char retval; 02742 02743 if (!spiWriteSpeed) 02744 _setWriteSpeed(true); 02745 retval = spi.write(data); 02746 return retval; 02747 } 02748 02749 02750 unsigned char RA8875::_spiread(void) 02751 { 02752 unsigned char retval; 02753 unsigned char data = 0; 02754 02755 if (spiWriteSpeed) 02756 _setWriteSpeed(false); 02757 retval = spi.write(data); 02758 return retval; 02759 } 02760 02761 02762 RetCode_t RA8875::_select(bool chipsel) 02763 { 02764 cs = (chipsel == true) ? 0 : 1; 02765 return noerror; 02766 } 02767 02768 02769 RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP) 02770 { 02771 (void)layer; 02772 02773 // AttachPrintHandler(this, RA8875::_printCallback); 02774 // return PrintScreen(x,y,w,h); 02775 return PrintScreen(x, y, w, h, Name_BMP); 02776 } 02777 02778 RetCode_t RA8875::_printCallback(RA8875::filecmd_t cmd, uint8_t * buffer, uint16_t size) 02779 { 02780 HexDump("CB", buffer, size); 02781 switch(cmd) { 02782 case RA8875::filecmd_t::OPEN: 02783 //pc.printf("About to write %lu bytes\r\n", *(uint32_t *)buffer); 02784 _printFH = fopen("file.bmp", "w+b"); 02785 if (_printFH == 0) 02786 return file_not_found; 02787 break; 02788 case RA8875::filecmd_t::WRITE: 02789 //pc.printf(" Write %4u bytes\r\n", size); 02790 fwrite(buffer, 1, size, _printFH); 02791 break; 02792 case RA8875::filecmd_t::CLOSE: 02793 //pc.printf(" close\r\n"); 02794 fclose(_printFH); 02795 _printFH = 0; 02796 break; 02797 default: 02798 //pc.printf("Unexpected callback %d\r\n", cmd); 02799 return file_not_found; 02800 //break; 02801 } 02802 return noerror; 02803 } 02804 02805 int RA8875::RoundUp(int value, int roundTo) 02806 { 02807 if (roundTo == 0) 02808 return 0; 02809 return ((value + roundTo - 1) / roundTo) * roundTo; 02810 } 02811 02812 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, uint8_t bitsPerPixel) 02813 { 02814 BITMAPFILEHEADER BMP_Header; 02815 BITMAPINFOHEADER BMP_Info; 02816 uint8_t * lineBuffer = NULL; 02817 color_t * pixelBuffer = NULL; 02818 color_t * pixelBuffer2 = NULL; 02819 02820 INFO("(%d,%d)-(%d,%d)x%d", x,y,w,h,bitsPerPixel); 02821 if (x >= 0 && x < virt_screenwidth 02822 && y >= 0 && y < virt_screenheight 02823 && w > 0 && x + w <= virt_screenwidth 02824 && h > 0 && y + h <= virt_screenheight) { 02825 BMP_Header.bfType = BF_TYPE; 02826 BMP_Header.bfReserved1 = 0; 02827 BMP_Header.bfReserved2 = 0; 02828 switch (bitsPerPixel) { 02829 case 24: 02830 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info); 02831 BMP_Header.bfSize = (h * RoundUp(w * sizeof(RGBQUAD),4)) + BMP_Header.bfOffBits; 02832 break; 02833 case 8: 02834 default: 02835 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette); 02836 INFO("Initial Offset to Bitstream %lX", BMP_Header.bfOffBits); 02837 //if (BMP_Header.bfOffBits & 0x03) { 02838 // BMP_Header.bfOffBits += (4 - (BMP_Header.bfOffBits & 0x03)); 02839 //} 02840 BMP_Header.bfSize = (h * RoundUp(w * 1,4)) + BMP_Header.bfOffBits; 02841 break; 02842 } 02843 INFO("Offset to Bitstream %lX", BMP_Header.bfOffBits); 02844 02845 // Bytes in the line buffer 02846 int lineBufSize = RoundUp(((bitsPerPixel == 24) ? 3 : 1) * w, 4); 02847 INFO("LineBufSize: %d", lineBufSize); 02848 02849 BMP_Info.biSize = sizeof(BMP_Info); 02850 BMP_Info.biWidth = w; 02851 BMP_Info.biHeight = h; 02852 BMP_Info.biPlanes = 1; 02853 BMP_Info.biBitCount = bitsPerPixel; 02854 BMP_Info.biCompression = BI_RGB; 02855 BMP_Info.biSizeImage = lineBufSize * h; 02856 BMP_Info.biXPelsPerMeter = 0; 02857 BMP_Info.biYPelsPerMeter = 0; 02858 // for 24-bit, there is no palette, so these are zero 02859 // for 8-bit, there can be up to 256 RGB values in the palette 02860 02861 BMP_Info.biClrUsed = (bitsPerPixel == 24) ? 0 : sizeof(WebColorPalette)/sizeof(WebColorPalette[0]); // for 8b/pixel 02862 BMP_Info.biClrImportant = BMP_Info.biClrUsed; 02863 02864 // Allocate the memory we need to proceed 02865 lineBuffer = (uint8_t *)swMalloc(lineBufSize); 02866 if (lineBuffer == NULL) { 02867 ERR("Not enough RAM for PrintScreen lineBuffer"); 02868 return(not_enough_ram); 02869 } 02870 memset(lineBuffer, 0, lineBufSize); // zero-Fill 02871 02872 #define DOUBLEBUF /* one larger buffer instead of two */ 02873 02874 #ifdef DOUBLEBUF 02875 // In the "#else", pixelBuffer2 malloc returns a value, 02876 // but is actually causing a failure later. 02877 // This test helps determine if it is truly out of memory, 02878 // or if malloc is broken. 02879 pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t)); 02880 if (pixelBuffer) 02881 pixelBuffer2 = pixelBuffer + (w * sizeof(color_t)); 02882 else 02883 pixelBuffer2 = NULL; 02884 #else 02885 pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t)); 02886 pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t)); 02887 #endif 02888 if (pixelBuffer == NULL || pixelBuffer2 == NULL) { 02889 ERR("Not enough RAM for pixelBuffer"); 02890 #ifndef DOUBLEBUF 02891 if (pixelBuffer2) 02892 swFree(pixelBuffer2); 02893 #endif 02894 if (pixelBuffer) 02895 swFree(pixelBuffer); 02896 swFree(lineBuffer); 02897 return(not_enough_ram); 02898 } 02899 02900 // Get the file primed... 02901 /// @todo check return value for possibility of a fatal error 02902 privateCallback(filecmd_t::OPEN, (uint8_t *)&BMP_Header.bfSize, 4); 02903 02904 // Be optimistic - don't check for errors. 02905 //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02906 //fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image); 02907 privateCallback(filecmd_t::WRITE, (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 02908 02909 //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02910 //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image); 02911 privateCallback(filecmd_t::WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 02912 if (bitsPerPixel != 24) { 02913 //HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette)); 02914 //fwrite(&WebColorPalette, sizeof(char), sizeof(WebColorPalette), Image); 02915 privateCallback(filecmd_t::WRITE, (uint8_t *)&WebColorPalette, sizeof(WebColorPalette)); 02916 //if (sizeof(WebColorPalette) % 4) { 02917 // const uint8_t padd[] = { 0, 0, 0 }; 02918 // //fwrite(&padd, sizeof(char), (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4, Image); 02919 // privateCallback(filecmd_t::WRITE, (uint8_t *)&padd, (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4); 02920 //} 02921 } 02922 //color_t transparency = GetBackgroundTransparencyColor(); 02923 LayerMode_T ltpr0 = GetLayerMode(); 02924 uint16_t prevLayer = GetDrawingLayer(); 02925 // If only one of the layers is visible, select that layer 02926 switch(ltpr0) { 02927 case ShowLayer0: 02928 SelectDrawingLayer(0); 02929 break; 02930 case ShowLayer1: 02931 SelectDrawingLayer(1); 02932 break; 02933 default: 02934 break; 02935 } 02936 02937 // Read the display from the last line toward the top 02938 // so we can write the file in one pass. 02939 for (int j = h - 1; j >= 0; j--) { 02940 if (idle_callback && h >= 1) { 02941 (*idle_callback)(progress, (h - 1 - j) * 100 / (h - 1)); 02942 } 02943 if (ltpr0 >= 2) // Need to combine the layers... 02944 SelectDrawingLayer(0); // so read layer 0 first 02945 // Read one line of pixels to a local buffer 02946 INFO("x,y %d,%d", x, y + j); 02947 if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) { 02948 ERR("getPixelStream error, and no recovery handler..."); 02949 } 02950 if (ltpr0 >= 2) { // Need to combine the layers... 02951 SelectDrawingLayer(1); // so read layer 1 next 02952 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) { 02953 ERR("getPixelStream error, and no recovery handler..."); 02954 } 02955 } 02956 INFO("Line: %3d", j); 02957 //HexDump("Raster", (uint8_t *)pixelBuffer, w * sizeof(color_t)); 02958 // Convert the local buffer to RGBQUAD format 02959 int lb = 0; 02960 for (int i=0; i<w; i++) { 02961 color_t tColor = pixelBuffer[x+i]; 02962 tColor = (tColor >> 8) | (tColor << 8); // Byte Swap 02963 RGBQUAD q0 = RGB16ToRGBQuad(tColor); // Scale to 24-bits 02964 tColor = pixelBuffer2[x+i]; 02965 tColor = (tColor >> 8) | (tColor << 8); // Byte Swap 02966 RGBQUAD q1 = RGB16ToRGBQuad(tColor); // Scale to 24-bits 02967 switch (ltpr0) { 02968 case 0: 02969 case 1: 02970 case 2: // lighten-overlay (@TODO Not supported yet) 02971 case 6: // Floating Windows (@TODO not sure how to support) 02972 default: // Reserved... 02973 //lineBuffer[lb++] = q0.rgbBlue; 02974 //lineBuffer[lb++] = q0.rgbGreen; 02975 //lineBuffer[lb++] = q0.rgbRed; 02976 break; 02977 case 3: // transparent mode (@TODO Read the background color register for transparent) 02978 case 4: // boolean or 02979 q0.rgbBlue = q0.rgbBlue | q1.rgbBlue; 02980 q0.rgbGreen = q0.rgbGreen | q1.rgbGreen; 02981 q0.rgbRed = q0.rgbRed | q1.rgbRed; 02982 break; 02983 case 5: // boolean AND 02984 q0.rgbBlue = q0.rgbBlue & q1.rgbBlue; 02985 q0.rgbGreen = q0.rgbGreen & q1.rgbGreen; 02986 q0.rgbRed = q0.rgbRed & q1.rgbRed; 02987 break; 02988 } 02989 switch (bitsPerPixel) { 02990 case 24: 02991 lineBuffer[lb++] = q0.rgbBlue; 02992 lineBuffer[lb++] = q0.rgbGreen; 02993 lineBuffer[lb++] = q0.rgbRed; 02994 break; 02995 case 8: 02996 default: 02997 lineBuffer[lb++] = FindNearestWebColor(q0.rgbRed,q0.rgbGreen,q0.rgbBlue); 02998 break; 02999 } 03000 } 03001 if (j == h - 1) { 03002 HexDump("Line", lineBuffer, lineBufSize); 03003 } 03004 // Write to disk 03005 privateCallback(WRITE, (uint8_t *)lineBuffer, lineBufSize); 03006 } 03007 SelectDrawingLayer(prevLayer); 03008 privateCallback(CLOSE, NULL, 0); 03009 #ifndef DOUBLEBUF 03010 if (pixelBuffer2) 03011 swFree(pixelBuffer2); 03012 #endif 03013 if (pixelBuffer) 03014 swFree(pixelBuffer); 03015 swFree(lineBuffer); 03016 INFO("Image closed"); 03017 return noerror; 03018 } else { 03019 return bad_parameter; 03020 } 03021 } 03022 03023 03024 03025 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP, uint8_t bitsPerPixel) 03026 { 03027 BITMAPFILEHEADER BMP_Header; 03028 BITMAPINFOHEADER BMP_Info; 03029 uint8_t * lineBuffer = NULL; 03030 color_t * pixelBuffer = NULL; 03031 color_t * pixelBuffer2 = NULL; 03032 03033 //INFO("(%d,%d)-(%d,%d)x%d %s", x,y,w,h,bitsPerPixel,Name_BMP); 03034 if (x >= 0 && x < virt_screenwidth 03035 && y >= 0 && y < virt_screenheight 03036 && w > 0 && x + w <= virt_screenwidth 03037 && h > 0 && y + h <= virt_screenheight) { 03038 BMP_Header.bfType = BF_TYPE; 03039 BMP_Header.bfReserved1 = 0; 03040 BMP_Header.bfReserved2 = 0; 03041 switch (bitsPerPixel) { 03042 case 24: 03043 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info); 03044 BMP_Header.bfSize = (h * RoundUp(w * sizeof(RGBQUAD),4)) + BMP_Header.bfOffBits; 03045 break; 03046 case 8: 03047 default: 03048 BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette); 03049 //INFO("Initial Offset to Bitstream %lX", BMP_Header.bfOffBits); 03050 //if (BMP_Header.bfOffBits & 0x03) { 03051 // BMP_Header.bfOffBits += (4 - (BMP_Header.bfOffBits & 0x03)); 03052 //} 03053 BMP_Header.bfSize = (h * RoundUp(w * 1,4)) + BMP_Header.bfOffBits; 03054 break; 03055 } 03056 //INFO("Offset to Bitstream %lX", BMP_Header.bfOffBits); 03057 03058 // Bytes in the line buffer 03059 int lineBufSize = RoundUp(((bitsPerPixel == 24) ? 3 : 1) * w, 4); 03060 //INFO("LineBufSize: %d", lineBufSize); 03061 03062 BMP_Info.biSize = sizeof(BMP_Info); 03063 BMP_Info.biWidth = w; 03064 BMP_Info.biHeight = h; 03065 BMP_Info.biPlanes = 1; 03066 BMP_Info.biBitCount = bitsPerPixel; 03067 BMP_Info.biCompression = BI_RGB; 03068 BMP_Info.biSizeImage = lineBufSize * h; 03069 BMP_Info.biXPelsPerMeter = 0; 03070 BMP_Info.biYPelsPerMeter = 0; 03071 // for 24-bit, there is no palette, so these are zero 03072 // for 8-bit, there can be up to 256 RGB values in the palette 03073 03074 BMP_Info.biClrUsed = (bitsPerPixel == 24) ? 0 : sizeof(WebColorPalette)/sizeof(WebColorPalette[0]); // for 8b/pixel 03075 BMP_Info.biClrImportant = BMP_Info.biClrUsed; 03076 03077 // Allocate the memory we need to proceed 03078 lineBuffer = (uint8_t *)swMalloc(lineBufSize); 03079 if (lineBuffer == NULL) { 03080 ERR("Not enough RAM for PrintScreen lineBuffer"); 03081 return(not_enough_ram); 03082 } 03083 memset(lineBuffer, 0, lineBufSize); // zero-Fill 03084 03085 #define DOUBLEBUF /* one larger buffer instead of two */ 03086 03087 #ifdef DOUBLEBUF 03088 // In the "#else", pixelBuffer2 malloc returns a value, 03089 // but is actually causing a failure later. 03090 // This test helps determine if it is truly out of memory, 03091 // or if malloc is broken. 03092 pixelBuffer = (color_t *)swMalloc(2 * w * sizeof(color_t)); 03093 if (pixelBuffer) 03094 pixelBuffer2 = pixelBuffer + (w * sizeof(color_t)); 03095 else 03096 pixelBuffer2 = NULL; 03097 #else 03098 pixelBuffer = (color_t *)swMalloc(w * sizeof(color_t)); 03099 pixelBuffer2 = (color_t *)swMalloc(w * sizeof(color_t)); 03100 #endif 03101 if (pixelBuffer == NULL || pixelBuffer2 == NULL) { 03102 ERR("Not enough RAM for pixelBuffer"); 03103 #ifndef DOUBLEBUF 03104 if (pixelBuffer2) 03105 swFree(pixelBuffer2); 03106 #endif 03107 if (pixelBuffer) 03108 swFree(pixelBuffer); 03109 swFree(lineBuffer); 03110 return(not_enough_ram); 03111 } 03112 03113 FILE *Image = fopen(Name_BMP, "wb"); 03114 if (!Image) { 03115 ERR("Can't open file for write"); 03116 #ifndef DOUBLEBUF 03117 if (pixelBuffer2) 03118 swFree(pixelBuffer2); 03119 #endif 03120 if (pixelBuffer) 03121 swFree(pixelBuffer); 03122 swFree(lineBuffer); 03123 return(file_not_found); 03124 } 03125 03126 // Be optimistic - don't check for errors. 03127 //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); 03128 fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image); 03129 03130 //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); 03131 fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image); 03132 03133 if (bitsPerPixel != 24) { 03134 //HexDump("Palette", (uint8_t *)&WebColorPalette, sizeof(WebColorPalette)); 03135 fwrite(&WebColorPalette, sizeof(char), sizeof(WebColorPalette), Image); 03136 //if (0 && sizeof(WebColorPalette) % 4) { 03137 // const uint8_t padd[] = { 0, 0, 0 }; 03138 // fwrite(&padd, sizeof(char), 03139 // (sizeof(BMP_Header) + sizeof(BMP_Info) + sizeof(WebColorPalette)) % 4, Image); 03140 //} 03141 } 03142 //color_t transparency = GetBackgroundTransparencyColor(); 03143 LayerMode_T ltpr0 = GetLayerMode(); 03144 03145 uint16_t prevLayer = GetDrawingLayer(); 03146 // If only one of the layers is visible, select that layer 03147 switch(ltpr0) { 03148 case ShowLayer0: 03149 SelectDrawingLayer(0); 03150 break; 03151 case ShowLayer1: 03152 SelectDrawingLayer(1); 03153 break; 03154 default: 03155 break; 03156 } 03157 03158 // Read the display from the last line toward the top 03159 // so we can write the file in one pass. 03160 for (int j = h - 1; j >= 0; j--) { 03161 if (idle_callback && h >= 1) { 03162 (*idle_callback)(progress, (h - 1 - j) * 100 / (h - 1)); 03163 } 03164 03165 if (ltpr0 >= 2) // Need to combine the layers... 03166 SelectDrawingLayer(0); // so read layer 0 first 03167 03168 // Read one line of pixels to a local buffer 03169 if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) { 03170 ERR("getPixelStream error, and no recovery handler..."); 03171 } 03172 if (ltpr0 >= 2) { // Need to combine the layers... 03173 SelectDrawingLayer(1); // so read layer 1 next 03174 if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) { 03175 ERR("getPixelStream error, and no recovery handler..."); 03176 } 03177 } 03178 //INFO("Line: %3d", j); 03179 //HexDump("Raster", (uint8_t *)pixelBuffer, w * sizeof(color_t)); 03180 // Convert the local buffer to RGBQUAD format 03181 int lb = 0; 03182 for (int i=0; i<w; i++) { 03183 color_t tColor = pixelBuffer[x+i]; 03184 tColor = (tColor >> 8) | (tColor << 8); // Byte Swap 03185 RGBQUAD q0 = RGB16ToRGBQuad(tColor); // Scale to 24-bits 03186 tColor = pixelBuffer2[x+i]; 03187 tColor = (tColor >> 8) | (tColor << 8); // Byte Swap 03188 RGBQUAD q1 = RGB16ToRGBQuad(tColor); // Scale to 24-bits 03189 switch (ltpr0) { 03190 case 0: 03191 case 1: 03192 case 2: // lighten-overlay (@TODO Not supported yet) 03193 case 6: // Floating Windows (@TODO not sure how to support) 03194 default: // Reserved... 03195 //lineBuffer[lb++] = q0.rgbBlue; 03196 //lineBuffer[lb++] = q0.rgbGreen; 03197 //lineBuffer[lb++] = q0.rgbRed; 03198 break; 03199 case 3: // transparent mode (@TODO Read the background color register for transparent) 03200 case 4: // boolean or 03201 q0.rgbBlue = q0.rgbBlue | q1.rgbBlue; 03202 q0.rgbGreen = q0.rgbGreen | q1.rgbGreen; 03203 q0.rgbRed = q0.rgbRed | q1.rgbRed; 03204 break; 03205 case 5: // boolean AND 03206 q0.rgbBlue = q0.rgbBlue & q1.rgbBlue; 03207 q0.rgbGreen = q0.rgbGreen & q1.rgbGreen; 03208 q0.rgbRed = q0.rgbRed & q1.rgbRed; 03209 break; 03210 } 03211 switch (bitsPerPixel) { 03212 case 24: 03213 lineBuffer[lb++] = q0.rgbBlue; 03214 lineBuffer[lb++] = q0.rgbGreen; 03215 lineBuffer[lb++] = q0.rgbRed; 03216 break; 03217 case 8: 03218 default: 03219 lineBuffer[lb++] = FindNearestWebColor(q0.rgbRed,q0.rgbGreen,q0.rgbBlue); 03220 break; 03221 } 03222 } 03223 //if (j == h - 1) { 03224 // HexDump("Line", lineBuffer, lineBufSize); 03225 //} 03226 // Write to disk 03227 fwrite(lineBuffer, sizeof(char), lineBufSize, Image); 03228 } 03229 SelectDrawingLayer(prevLayer); 03230 fclose(Image); 03231 #ifndef DOUBLEBUF 03232 if (pixelBuffer2) 03233 swFree(pixelBuffer2); 03234 #endif 03235 if (pixelBuffer) 03236 swFree(pixelBuffer); 03237 swFree(lineBuffer); 03238 //INFO("Image closed"); 03239 return noerror; 03240 } else { 03241 return bad_parameter; 03242 } 03243 } 03244 03245 03246 // ########################################################################## 03247 // ########################################################################## 03248 // ########################################################################## 03249 03250 #ifdef TESTENABLE 03251 03252 #include "BPG_Arial08x08.h" 03253 #include "BPG_Arial20x20.h" 03254 03255 // ______________ ______________ ______________ _______________ 03256 // /_____ _____/ / ___________/ / ___________/ /_____ ______/ 03257 // / / / / / / / / 03258 // / / / /___ / /__________ / / 03259 // / / / ____/ /__________ / / / 03260 // / / / / / / / / 03261 // / / / /__________ ___________/ / / / 03262 // /__/ /_____________/ /_____________/ /__/ 03263 // 03264 // Everything from here down is test code. 03265 // 03266 bool SuppressSlowStuff = false; 03267 03268 void TextWrapTest(RA8875 & display, Serial & pc) 03269 { 03270 if (!SuppressSlowStuff) 03271 pc.printf("Text Wrap Test\r\n"); 03272 display.background(Black); 03273 display.foreground(Blue); 03274 display.cls(); 03275 display.Backlight_u8(255); 03276 display.puts("Text Wrap Test.\r\n"); 03277 for (int i=1; i<60; i++) { 03278 display.printf("L%2d\n", i % 17); 03279 if (!SuppressSlowStuff) 03280 wait_us(100000); 03281 } 03282 if (!SuppressSlowStuff) 03283 wait_us(3000000); 03284 } 03285 03286 03287 void ShowKey(RA8875 & display, int key) 03288 { 03289 loc_t col, row; 03290 dim_t r1 = 25; 03291 color_t color = (key & 0x80) ? Red : Green; 03292 03293 key &= 0x7F; // remove the long-press flag 03294 row = (key - 1) / 5; 03295 col = (key - 1) % 5; 03296 if (col > 5) col = 5; 03297 if (row > 4) row = 4; 03298 display.circle(450 - + (2 * r1) * col, 200 - (2 * r1) * row, r1-2, color, FILL); 03299 } 03300 03301 void HideKey(RA8875 & display, int key) 03302 { 03303 loc_t col, row; 03304 dim_t r1 = 25; 03305 03306 row = (key - 1) / 5; 03307 col = (key - 1) % 5; 03308 if (col > 5) col = 5; 03309 if (row > 4) row = 4; 03310 display.background(Black); 03311 display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Black, FILL); 03312 display.circle(450 - (2 * r1) * col, 200 - (2 * r1) * row, r1-2, Blue); 03313 } 03314 03315 void KeyPadTest(RA8875 & display, Serial & pc) 03316 { 03317 const uint8_t myMap[22] = { 03318 0, 03319 'a', 'b', 'c', 'd', 'e', 03320 'f', 'g', 'h', 'i', 'j', 03321 'k', 'l', 'm', 'n', 'o', 03322 'p', 'q', 'r', 's', 't', 03323 'x' 03324 }; 03325 03326 display.background(Black); 03327 display.foreground(Blue); 03328 display.cls(); 03329 display.Backlight_u8(255); 03330 display.puts("KeyPad Test. Touch the keypad..."); 03331 pc.printf("\r\n" 03332 "Raw KeyPad Test. Keypad returns the key-number.\r\n" 03333 "Press [most] any PC keyboard key to advance to next test.\r\n"); 03334 RetCode_t ret = display.KeypadInit(true, true, 3, 7, 3); 03335 if (ret != noerror) 03336 pc.printf("returncode from KeypadInit is %d\r\n", ret); 03337 int lastKey = 0; 03338 while (!pc.readable()) { 03339 if (display.readable()) { 03340 int key = display.getc(); 03341 if (key) { 03342 if (((key & 0x7F) != lastKey) && (lastKey != 0)) 03343 HideKey(display, lastKey); 03344 ShowKey(display, key); 03345 lastKey = key & 0x7F; 03346 } else { 03347 // erase the last one 03348 if (lastKey) 03349 HideKey(display, lastKey); 03350 } 03351 } 03352 } 03353 (void)pc.getc(); 03354 pc.printf("\r\n" 03355 "Map KeyPad Test. Keypad returns the remapped key 'a' - 't'.\r\n" 03356 "Press [most] any PC keyboard key to advance to exit test.\r\n"); 03357 display.SetKeyMap(myMap); 03358 while (!pc.readable()) { 03359 if (display.readable()) { 03360 int key = display.getc(); 03361 bool longPress = key & 0x80; 03362 display.SetTextCursor(0, 120); 03363 display.printf("Long Press: %d\r\n", longPress); 03364 display.printf(" Remapped: %c %02X\r\n", (key) ? key & 0x7F : ' ', key); 03365 } 03366 } 03367 (void)pc.getc(); 03368 display.SetKeyMap(); 03369 pc.printf("\r\n"); 03370 } 03371 03372 void TextCursorTest(RA8875 & display, Serial & pc) 03373 { 03374 const char * iCursor = "The I-Beam cursor should be visible for this text.\r\n"; 03375 const char * uCursor = "The Underscore cursor should be visible for this text.\r\n"; 03376 const char * bCursor = "The Block cursor should be visible for this text.\r\n"; 03377 const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n"; 03378 const char * p; 03379 int delay = 60; 03380 03381 if (!SuppressSlowStuff) 03382 pc.printf("Text Cursor Test\r\n"); 03383 else 03384 delay = 0; 03385 display.background(Black); 03386 display.foreground(Blue); 03387 display.cls(); 03388 display.Backlight_u8(255); 03389 display.puts("Text Cursor Test."); 03390 03391 // visible, non-blinking 03392 display.SetTextCursor(0,20); 03393 display.SetTextCursorControl(RA8875::IBEAM, false); 03394 p = iCursor; 03395 while (*p) { 03396 display._putc(*p++); 03397 wait_ms(delay); 03398 } 03399 03400 display.SetTextCursorControl(RA8875::UNDER, false); 03401 p = uCursor; 03402 while (*p) { 03403 display._putc(*p++); 03404 wait_ms(delay); 03405 } 03406 03407 display.SetTextCursorControl(RA8875::BLOCK, false); 03408 p = bCursor; 03409 while (*p) { 03410 display._putc(*p++); 03411 wait_ms(delay); 03412 } 03413 03414 display.SetTextCursorControl(RA8875::BLOCK, true); 03415 p = bbCursor; 03416 while (*p) { 03417 display._putc(*p++); 03418 wait_ms(delay); 03419 } 03420 wait_ms(delay * 20); 03421 display.SetTextCursorControl(RA8875::NOCURSOR, false); 03422 } 03423 03424 03425 void BacklightTest(RA8875 & display, Serial & pc, float ramptime) 03426 { 03427 char buf[60]; 03428 unsigned int w = (ramptime * 1000)/ 256; 03429 int delay = 200; 03430 03431 if (!SuppressSlowStuff) 03432 pc.printf("Backlight Test - ramp over %f sec.\r\n", ramptime); 03433 else { 03434 delay = 0; 03435 w = 0; 03436 } 03437 display.Backlight_u8(0); 03438 display.background(White); 03439 display.foreground(Blue); 03440 display.cls(); 03441 display.puts("RA8875 Backlight Test - Ramp up."); 03442 wait_ms(delay); 03443 for (int i=0; i <= 255; i++) { 03444 snprintf(buf, sizeof(buf), "%3d, %4u", i, w); 03445 display.puts(100,100,buf); 03446 display.Backlight_u8(i); 03447 wait_ms(w); 03448 } 03449 } 03450 03451 03452 void BacklightTest2(RA8875 & display, Serial & pc) 03453 { 03454 int delay = 20; 03455 03456 if (!SuppressSlowStuff) 03457 pc.printf("Backlight Test 2\r\n"); 03458 else 03459 delay = 0; 03460 03461 // Dim it out at the end of the tests. 03462 display.foreground(Blue); 03463 display.puts(0,0, "Ramp Backlight down."); 03464 // Ramp it off 03465 for (int i=255; i != 0; i--) { 03466 display.Backlight_u8(i); 03467 wait_ms(delay); 03468 } 03469 display.Backlight_u8(0); 03470 } 03471 03472 03473 void ExternalFontTest(RA8875 & display, Serial & pc) 03474 { 03475 if (!SuppressSlowStuff) 03476 pc.printf("External Font Test\r\n"); 03477 display.background(Black); 03478 display.foreground(Blue); 03479 display.cls(); 03480 display.puts("External Font Test."); 03481 display.Backlight(1); 03482 03483 display.SelectUserFont(BPG_Arial08x08); 03484 display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); 03485 03486 display.SelectUserFont(BPG_Arial20x20); 03487 display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); 03488 03489 display.SelectUserFont(); 03490 03491 display.puts("Normal font again."); 03492 //display.window(0,0, display.width(), display.height()); 03493 } 03494 03495 03496 void DOSColorTest(RA8875 & display, Serial & pc) 03497 { 03498 if (!SuppressSlowStuff) 03499 pc.printf("DOS Color Test\r\n"); 03500 display.background(Black); 03501 display.foreground(Blue); 03502 display.cls(); 03503 display.puts("DOS Colors - Fore"); 03504 display.puts(280,0, "Back"); 03505 display.background(Gray); 03506 for (int i=0; i<16; i++) { 03507 display.foreground(display.DOSColor(i)); 03508 display.puts(160, i*16, display.DOSColorNames(i)); 03509 display.background(Black); 03510 } 03511 display.foreground(White); 03512 for (int i=0; i<16; i++) { 03513 display.background(display.DOSColor(i)); 03514 display.puts(360, i*16, display.DOSColorNames(i)); 03515 display.foreground(White); 03516 } 03517 } 03518 03519 03520 void WebColorTest(RA8875 & display, Serial & pc) 03521 { 03522 if (!SuppressSlowStuff) 03523 pc.printf("Web Color Test\r\n"); 03524 display.background(Black); 03525 display.foreground(Blue); 03526 display.window(0,0, display.width(), display.height()); 03527 display.cls(); 03528 display.SetTextFontSize(1,1); 03529 display.puts(200,0, "Web Color Test"); 03530 display.SetTextCursor(0,0); 03531 display.puts(" "); 03532 for (int i=0; i<16; i++) 03533 display.printf("%X", i&0xF); 03534 display.puts("\r\n0 "); 03535 for (int i=0; i<sizeof(WebColors)/sizeof(WebColors[0]); i++) { 03536 display.background(WebColors[i]); 03537 display.puts(" "); 03538 if (i % 16 == 15 && i < 255) { 03539 display.printf("\r\n%X ", ((i+1)/16)); 03540 } 03541 } 03542 display.SetTextFontSize(1,1); 03543 } 03544 03545 03546 void PixelTest(RA8875 & display, Serial & pc) 03547 { 03548 int i, c, x, y; 03549 03550 if (!SuppressSlowStuff) 03551 pc.printf("Pixel Test\r\n"); 03552 display.background(Black); 03553 display.foreground(Blue); 03554 display.cls(); 03555 display.puts("Pixel Test"); 03556 for (i=0; i<1000; i++) { 03557 x = rand() % 480; 03558 y = 16 + rand() % (272-16); 03559 c = rand() % 16; 03560 //pc.printf(" (%d,%d) - %d\r\n", x,y,r1); 03561 display.pixel(x,y, display.DOSColor(c)); 03562 } 03563 } 03564 03565 03566 void LineTest(RA8875 & display, Serial & pc) 03567 { 03568 int i, x, y, x2, y2; 03569 03570 if (!SuppressSlowStuff) 03571 pc.printf("Line Test\r\n"); 03572 display.background(Black); 03573 display.foreground(Blue); 03574 display.cls(); 03575 display.puts("Line Test"); 03576 for (i=0; i<16; i++) { 03577 // Lines 03578 x = rand() % 480; 03579 y = rand() % 272; 03580 x2 = rand() % 480; 03581 y2 = rand() % 272; 03582 display.line(x,y, x2,y2, display.DOSColor(i)); 03583 } 03584 display.foreground(BrightRed); 03585 display.foreground(BrightGreen); 03586 display.foreground(BrightBlue); 03587 display.line(55,50, 79,74, BrightRed); 03588 display.line(57,50, 81,74, BrightGreen); 03589 display.line(59,50, 83,74, BrightBlue); 03590 // horz 03591 display.line(30,40, 32,40, BrightRed); 03592 display.line(30,42, 32,42, BrightGreen); 03593 display.line(30,44, 32,44, BrightBlue); 03594 // vert 03595 display.line(20,40, 20,42, BrightRed); 03596 display.line(22,40, 22,42, BrightGreen); 03597 display.line(24,40, 24,42, BrightBlue); 03598 // compare point to line-point 03599 display.pixel(20,50, BrightRed); 03600 display.pixel(22,50, BrightGreen); 03601 display.pixel(24,50, BrightBlue); 03602 display.line(20,52, 20,52, BrightRed); 03603 display.line(22,52, 22,52, BrightGreen); 03604 display.line(24,52, 24,52, BrightBlue); 03605 03606 // point 03607 display.line(50,50, 50,50, Red); 03608 display.line(52,52, 52,52, Green); 03609 display.line(54,54, 54,54, Blue); 03610 display.line(60,60, 60,60, BrightRed); 03611 display.line(62,62, 62,62, BrightGreen); 03612 display.line(64,64, 64,64, BrightBlue); 03613 display.line(70,70, 70,70, DarkRed); 03614 display.line(72,72, 72,72, DarkGreen); 03615 display.line(74,74, 74,74, DarkBlue); 03616 } 03617 03618 03619 void RectangleTest(RA8875 & display, Serial & pc) 03620 { 03621 int i, x1,y1, x2,y2; 03622 03623 if (!SuppressSlowStuff) 03624 pc.printf("Rectangle Test\r\n"); 03625 display.background(Black); 03626 display.foreground(Blue); 03627 display.cls(); 03628 display.puts("Rectangle Test"); 03629 for (i=0; i<16; i++) { 03630 x1 = rand() % 240; 03631 y1 = 50 + rand() % 200; 03632 x2 = rand() % 240; 03633 y2 = 50 + rand() % 200; 03634 display.rect(x1,y1, x2,y2, display.DOSColor(i)); 03635 03636 x1 = 240 + rand() % 240; 03637 y1 = 50 + rand() % 200; 03638 x2 = 240 + rand() % 240; 03639 y2 = 50 + rand() % 200; 03640 display.rect(x1,y1, x2,y2, FILL); 03641 } 03642 } 03643 03644 03645 void LayerTest(RA8875 & display, Serial & pc) 03646 { 03647 loc_t i, x1,y1, x2,y2, r1,r2; 03648 03649 if (!SuppressSlowStuff) 03650 pc.printf("Layer Test\r\n"); 03651 03652 display.SelectDrawingLayer(0); 03653 display.background(Black); 03654 display.foreground(Blue); 03655 display.cls(); 03656 display.puts("Layer 0"); 03657 for (i=0; i<16; i++) { 03658 x1 = rand() % 240; 03659 y1 = 50 + rand() % 200; 03660 x2 = x1 + rand() % 100; 03661 y2 = y1 + rand() % 100; 03662 r1 = rand() % (x2 - x1)/2; 03663 r2 = rand() % (y2 - y1)/2; 03664 display.roundrect(x1,y1, x2,y2, r1,r2, display.DOSColor(i)); 03665 if (!SuppressSlowStuff) 03666 wait_us(20000); 03667 } 03668 if (!SuppressSlowStuff) 03669 wait_us(1000000); 03670 03671 display.SelectDrawingLayer(1); 03672 display.background(Black); 03673 display.foreground(Yellow); 03674 display.cls(); 03675 display.puts(240,0, "Layer 1"); 03676 for (i=0; i<16; i++) { 03677 x1 = 300 + rand() % 100; 03678 y1 = 70 + rand() % 200; 03679 r1 = rand() % RAmin(y1 - 20, 100); 03680 display.circle(x1,y1,r1, display.DOSColor(i)); 03681 if (!SuppressSlowStuff) 03682 wait_us(20000); 03683 } 03684 display.SetLayerMode(RA8875::ShowLayer1); // Show it after the build-up 03685 if (!SuppressSlowStuff) 03686 wait_us(2000000); 03687 03688 display.SelectDrawingLayer(0); 03689 display.SetLayerMode(RA8875::ShowLayer0); // Show Layer 0 again 03690 if (!SuppressSlowStuff) 03691 wait_us(1000000); 03692 display.SetLayerMode(RA8875::TransparentMode); // Transparent mode 03693 if (!SuppressSlowStuff) 03694 wait_us(1000000); 03695 for (i=0; i<=8; i++) { 03696 display.SetLayerTransparency(i, 8-i); 03697 if (!SuppressSlowStuff) 03698 wait_us(200000); 03699 } 03700 03701 // Restore before we exit 03702 display.SetLayerTransparency(0, 0); 03703 display.SetLayerMode(RA8875::ShowLayer0); // Restore to layer 0 03704 } 03705 03706 03707 void RoundRectTest(RA8875 & display, Serial & pc) 03708 { 03709 loc_t i, x1,y1, x2,y2, r1,r2; 03710 03711 if (!SuppressSlowStuff) 03712 pc.printf("Round Rectangle Test\r\n"); 03713 display.background(Black); 03714 display.foreground(Blue); 03715 display.cls(); 03716 display.puts("Rounded Rectangle Test"); 03717 03718 for (i=0; i<16; i++) { 03719 x1 = rand() % 240; 03720 y1 = 50 + rand() % 200; 03721 x2 = x1 + rand() % 100; 03722 y2 = y1 + rand() % 100; 03723 r1 = rand() % (x2 - x1)/2; 03724 r2 = rand() % (y2 - y1)/2; 03725 display.roundrect(x1,y1, x2,y2, 5,8, display.DOSColor(i)); 03726 03727 x1 = 240 + rand() % 240; 03728 y1 = 50 + rand() % 200; 03729 x2 = x1 + rand() % 100; 03730 y2 = y1 + rand() % 100; 03731 r1 = rand() % (x2 - x1)/2; 03732 r2 = rand() % (y2 - y1)/2; 03733 display.roundrect(x1,y1, x2,y2, r1,r2, FILL); 03734 } 03735 } 03736 03737 03738 void TriangleTest(RA8875 & display, Serial & pc) 03739 { 03740 int i, x1, y1, x2, y2, x3, y3; 03741 03742 if (!SuppressSlowStuff) 03743 pc.printf("Triangle Test\r\n"); 03744 display.background(Black); 03745 display.foreground(Blue); 03746 display.cls(); 03747 display.puts(0,0, "Triangle Test"); 03748 03749 x1 = 150; 03750 y1 = 2; 03751 x2 = 190; 03752 y2 = 7; 03753 x3 = 170; 03754 y3 = 16; 03755 display.triangle(x1,y1, x2,y2, x3,y3); 03756 03757 x1 = 200; 03758 y1 = 2; 03759 x2 = 240; 03760 y2 = 7; 03761 x3 = 220; 03762 y3 = 16; 03763 display.filltriangle(x1,y1, x2,y2, x3,y3, BrightRed); 03764 03765 x1 = 300; 03766 y1 = 2; 03767 x2 = 340; 03768 y2 = 7; 03769 x3 = 320; 03770 y3 = 16; 03771 display.triangle(x1,y1, x2,y2, x3,y3, NOFILL); 03772 03773 x1 = 400; 03774 y1 = 2; 03775 x2 = 440; 03776 y2 = 7; 03777 x3 = 420; 03778 y3 = 16; 03779 display.triangle(x1,y1, x2,y2, x3,y3, Blue); 03780 03781 for (i=0; i<16; i++) { 03782 x1 = rand() % 240; 03783 y1 = 50 + rand() % 200; 03784 x2 = rand() % 240; 03785 y2 = 50 + rand() % 200; 03786 x3 = rand() % 240; 03787 y3 = 50 + rand() % 200; 03788 display.triangle(x1,y1, x2,y2, x3,y3, display.DOSColor(i)); 03789 x1 = 240 + rand() % 240; 03790 y1 = 50 + rand() % 200; 03791 x2 = 240 + rand() % 240; 03792 y2 = 50 + rand() % 200; 03793 x3 = 240 + rand() % 240; 03794 y3 = 50 + rand() % 200; 03795 display.triangle(x1,y1, x2,y2, x3,y3, FILL); 03796 } 03797 } 03798 03799 03800 void CircleTest(RA8875 & display, Serial & pc) 03801 { 03802 int i, x, y, r1; 03803 03804 if (!SuppressSlowStuff) 03805 pc.printf("Circle Test\r\n"); 03806 display.background(Black); 03807 display.foreground(Blue); 03808 display.cls(); 03809 display.puts("Circle Test"); 03810 for (i=0; i<16; i++) { 03811 x = 100 + rand() % 100; 03812 y = 70 + rand() % 200; 03813 r1 = rand() % RAmin(y - 20, 100); 03814 //pc.printf(" (%d,%d) - %d\r\n", x,y,r1); 03815 display.circle(x,y,r1, display.DOSColor(i)); 03816 03817 x = 300 + rand() % 100; 03818 y = 70 + rand() % 200; 03819 r1 = rand() % RAmin(y - 20, 100); 03820 //pc.printf(" (%d,%d) - %d FILL\r\n", x,y,r1); 03821 display.circle(x,y,r1, display.DOSColor(i), FILL); 03822 } 03823 } 03824 03825 03826 void EllipseTest(RA8875 & display, Serial & pc) 03827 { 03828 int i,x,y,r1,r2; 03829 03830 if (!SuppressSlowStuff) 03831 pc.printf("Ellipse Test\r\n"); 03832 display.background(Black); 03833 display.foreground(Blue); 03834 display.cls(); 03835 display.puts("Ellipse Test"); 03836 for (i=0; i<16; i++) { 03837 x = 100 + rand() % 100; 03838 y = 70 + rand() % 200; 03839 r1 = rand() % RAmin(y - 20, 100); 03840 r2 = rand() % RAmin(y - 20, 100); 03841 display.ellipse(x,y,r1,r2, display.DOSColor(i)); 03842 03843 x = 300 + rand() % 100; 03844 y = 70 + rand() % 200; 03845 r1 = rand() % RAmin(y - 20, 100); 03846 r2 = rand() % RAmin(y - 20, 100); 03847 display.ellipse(x,y,r1,r2, FILL); 03848 } 03849 } 03850 03851 03852 void TestGraphicsBitmap(RA8875 & display, Serial & pc) 03853 { 03854 LocalFileSystem local("local"); 03855 if (!SuppressSlowStuff) 03856 pc.printf("Bitmap File Load\r\n"); 03857 display.background(Black); 03858 display.foreground(Blue); 03859 display.cls(); 03860 display.puts("Graphics Test, loading /local/TestPat.bmp"); 03861 wait(3); 03862 03863 int r = display.RenderBitmapFile(0,0, "/local/TestPat.bmp"); 03864 if (!SuppressSlowStuff) 03865 pc.printf(" returned %d\r\n", r); 03866 } 03867 03868 03869 void TouchPanelTest(RA8875 & display, Serial & pc) 03870 { 03871 Timer t; 03872 int x, y; 03873 tpMatrix_t calmatrix; 03874 03875 display.background(Black); 03876 display.foreground(Blue); 03877 display.cls(); 03878 display.puts("Touch Panel Test\r\n"); 03879 pc.printf("Touch Panel Test\r\n"); 03880 display.TouchPanelInit(); 03881 pc.printf(" TP: c - calibrate, r - restore, t - test\r\n"); 03882 int c = pc.getc(); 03883 if (c == 'c') { 03884 point_t pTest[3] = 03885 { { 50, 50 }, {450, 150}, {225,250} }; 03886 point_t pSample[3]; 03887 for (int i=0; i<3; i++) { 03888 display.foreground(Blue); 03889 display.printf(" (%3d,%3d) => ", pTest[i].x, pTest[i].y); 03890 display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, White); 03891 display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, White); 03892 while (!display.TouchPanelA2DFiltered(&x, &y)) 03893 wait_us(20000); 03894 pSample[i].x = x; 03895 pSample[i].y = y; 03896 display.line(pTest[i].x-10, pTest[i].y, pTest[i].x+10, pTest[i].y, Black); 03897 display.line(pTest[i].x, pTest[i].y-10, pTest[i].x, pTest[i].y+10, Black); 03898 display.foreground(Blue); 03899 display.printf(" (%4d,%4d)\r\n", x,y); 03900 while (display.TouchPanelA2DFiltered(&x, &y)) 03901 wait_us(20000); 03902 wait(2); 03903 } 03904 display.TouchPanelComputeCalibration(pTest, pSample, &calmatrix); 03905 display.printf(" Writing calibration to tpcal.cfg\r\n"); 03906 FILE * fh = fopen("/local/tpcal.cfg", "wb"); 03907 if (fh) { 03908 fwrite(&calmatrix, sizeof(calmatrix), 1, fh); 03909 fclose(fh); 03910 } 03911 display.printf(" Calibration is complete."); 03912 } else if (c == 'r') { 03913 display.printf(" Reading calibration from tpcal.cfg\r\n"); 03914 FILE * fh = fopen("/local/tpcal.cfg", "rb"); 03915 if (fh) { 03916 fread(&calmatrix, sizeof(calmatrix), 1, fh); 03917 fclose(fh); 03918 } 03919 display.printf(" Calibration is complete."); 03920 display.TouchPanelSetMatrix(&calmatrix); 03921 } 03922 t.start(); 03923 do { 03924 point_t point = {0, 0}; 03925 if (display.TouchPanelReadable(&point)) { 03926 display.pixel(point.x, point.y, Red); 03927 } 03928 } while (t.read_ms() < 30000); 03929 pc.printf(">"); 03930 } 03931 03932 03933 void SpeedTest(RA8875 & display, Serial & pc) 03934 { 03935 Timer t; 03936 SuppressSlowStuff = true; 03937 pc.printf("\r\nSpeedTest disables delays, runs tests, reports overall time.\r\n"); 03938 t.start(); 03939 // do stuff fast 03940 TextCursorTest(display, pc); 03941 TextWrapTest(display, pc); 03942 BacklightTest(display, pc, 0); 03943 BacklightTest2(display, pc); 03944 ExternalFontTest(display, pc); 03945 DOSColorTest(display, pc); 03946 WebColorTest(display, pc); 03947 PixelTest(display, pc); 03948 LineTest(display, pc); 03949 RectangleTest(display, pc); 03950 RoundRectTest(display, pc); 03951 TriangleTest(display, pc); 03952 CircleTest(display, pc); 03953 EllipseTest(display, pc); 03954 LayerTest(display, pc); 03955 //TestGraphicsBitmap(display, pc); 03956 pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms()); 03957 #ifdef PERF_METRICS 03958 display.ReportPerformance(pc); 03959 #endif 03960 SuppressSlowStuff = false; 03961 } 03962 03963 03964 void PrintScreen(RA8875 & display, Serial & pc) 03965 { 03966 if (!SuppressSlowStuff) 03967 pc.printf("PrintScreen\r\n"); 03968 display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp"); 03969 } 03970 03971 03972 void RunTestSet(RA8875 & lcd, Serial & pc) 03973 { 03974 int q = 0; 03975 int automode = 0; 03976 const unsigned char modelist[] = "BDWtGLlFROTPCEbw"; // auto-test in this order. 03977 03978 while(1) { 03979 pc.printf("\r\n" 03980 "B - Backlight up b - backlight dim\r\n" 03981 "D - DOS Colors W - Web Colors\r\n" 03982 "t - text cursor G - Graphics Bitmap\r\n" 03983 "L - Lines F - external Font\r\n" 03984 "R - Rectangles O - rOund rectangles\r\n" 03985 "T - Triangles P - Pixels \r\n" 03986 "C - Circles E - Ellipses\r\n" 03987 "A - Auto Test mode S - Speed Test\r\n" 03988 "K - Keypad Test s - touch screen test\r\n" 03989 "p - print screen r - reset \r\n" 03990 "l - layer test w - wrapping text \r\n" 03991 #ifdef PERF_METRICS 03992 "0 - clear performance 1 - report performance\r\n" 03993 #endif 03994 "> "); 03995 if (automode == -1 || pc.readable()) { 03996 automode = -1; 03997 q = pc.getc(); 03998 while (pc.readable()) 03999 pc.getc(); 04000 } else if (automode >= 0) { 04001 q = modelist[automode]; 04002 } 04003 switch(q) { 04004 #ifdef PERF_METRICS 04005 case '0': 04006 lcd.ClearPerformance(); 04007 break; 04008 case '1': 04009 lcd.ReportPerformance(pc); 04010 break; 04011 #endif 04012 case 'A': 04013 automode = 0; 04014 break; 04015 case 'B': 04016 BacklightTest(lcd, pc, 2); 04017 break; 04018 case 'b': 04019 BacklightTest2(lcd, pc); 04020 break; 04021 case 'D': 04022 DOSColorTest(lcd, pc); 04023 break; 04024 case 'K': 04025 KeyPadTest(lcd, pc); 04026 break; 04027 case 'W': 04028 WebColorTest(lcd, pc); 04029 break; 04030 case 't': 04031 TextCursorTest(lcd, pc); 04032 break; 04033 case 'w': 04034 TextWrapTest(lcd, pc); 04035 break; 04036 case 'F': 04037 ExternalFontTest(lcd, pc); 04038 break; 04039 case 'L': 04040 LineTest(lcd, pc); 04041 break; 04042 case 'l': 04043 LayerTest(lcd, pc); 04044 break; 04045 case 'R': 04046 RectangleTest(lcd, pc); 04047 break; 04048 case 'O': 04049 RoundRectTest(lcd, pc); 04050 break; 04051 case 'p': 04052 PrintScreen(lcd, pc); 04053 break; 04054 case 'S': 04055 SpeedTest(lcd, pc); 04056 break; 04057 case 's': 04058 TouchPanelTest(lcd, pc); 04059 break; 04060 case 'T': 04061 TriangleTest(lcd, pc); 04062 break; 04063 case 'P': 04064 PixelTest(lcd, pc); 04065 break; 04066 case 'G': 04067 TestGraphicsBitmap(lcd, pc); 04068 break; 04069 case 'C': 04070 CircleTest(lcd, pc); 04071 break; 04072 case 'E': 04073 EllipseTest(lcd, pc); 04074 break; 04075 case 'r': 04076 pc.printf("Resetting ...\r\n"); 04077 wait_us(20000); 04078 mbed_reset(); 04079 break; 04080 case ' ': 04081 break; 04082 default: 04083 printf("huh?\n"); 04084 break; 04085 } 04086 if (automode >= 0) { 04087 automode++; 04088 if (automode >= sizeof(modelist)) 04089 automode = 0; 04090 wait_us(2000000); 04091 } 04092 wait_us(200000); 04093 } 04094 } 04095 04096 #endif // TESTENABLE
Generated on Tue Jul 12 2022 17:28:36 by 1.7.2