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
See Components - RA8875 Based Display
Enhanced touch-screen support - where it previous supported both the Resistive Touch and Capacitive Touch based on the FT5206 Touch Controller, now it also has support for the GSL1680 Touch Controller.
Offline Help Manual (Windows chm)
/media/uploads/WiredHome/ra8875.zip.bin (download, rename to .zip and unzip)
Revision 73:f22a18707b5e, committed 2014-11-09
- Comitter:
- WiredHome
- Date:
- Sun Nov 09 18:52:46 2014 +0000
- Parent:
- 72:ecffe56af969
- Child:
- 74:686faa218914
- Commit message:
- Improved PrintScreen function automatically senses some of the modes of operation.
Changed in this revision
--- a/GraphicsDisplay.h Sat Oct 11 17:24:29 2014 +0000 +++ b/GraphicsDisplay.h Sun Nov 09 18:52:46 2014 +0000 @@ -207,11 +207,11 @@ /// @note This method probably has very little value outside of /// the internal methods for reading BMP files. /// - /// @param colorPalette is the handle to the color palette to use. - /// @param i is the index into the color palette. + /// @param colorPaletteArray is the handle to the color palette array to use. + /// @param index is the index into the color palette. /// @returns the color in color_t format. /// - color_t RGBQuadToRGB16(RGBQUAD * colorPalette, uint16_t i); + color_t RGBQuadToRGB16(RGBQUAD * colorPaletteArray, uint16_t index); /// This method converts a 16-bit color value into a 24-bit RGB Quad. ///
--- a/RA8875.cpp Sat Oct 11 17:24:29 2014 +0000 +++ b/RA8875.cpp Sun Nov 09 18:52:46 2014 +0000 @@ -1,7 +1,7 @@ /// RA8875 Display Controller Library. -/// +/// /// This is being created for a Raio RA8875-based display from buydisplay.com, -/// which is 480 x 272 using a 4-wire SPI interface. +/// which is 480 x 272 using a 4-wire SPI interface. /// This display controller is used in other display resolutions, up to 800x600. /// While this driver has not been tested with these variants, nothing was done /// to prevent easily supporting them. @@ -16,10 +16,31 @@ #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); +static void HexDump(char * title, uint8_t * p, int count) +{ + int i; + char buf[100] = "0000: "; + + if (*title) + INFO("%s", title); + for (i=0; i<count; ) { + sprintf(buf + strlen(buf), "%02X ", *(p+i)); + if ((++i & 0x0F) == 0x00) { + INFO("%s", buf); + if (i < count) + sprintf(buf, "%04X: ", i); + else + buf[0] = '\0'; + } + } + if (strlen(buf)) + INFO("%s", buf); +} #else #define INFO(x, ...) #define WARN(x, ...) #define ERR(x, ...) +#define HexDump(a, b, c) #endif @@ -31,12 +52,11 @@ #define PERFORMANCE_RESET performance.reset() #define REGISTERPERFORMANCE(a) RegisterPerformance(a) #define COUNTIDLETIME(a) CountIdleTime(a) -static const char *metricsName[] = -{ - "Cls", "Pixel", "Pixel Stream", +static const char *metricsName[] = { + "Cls", "Pixel", "Pixel Stream", "Read Pixel", "Read Pixel Stream", - "Line", - "Rectangle", "Rounded Rectangle", + "Line", + "Rectangle", "Rounded Rectangle", "Triangle", "Circle", "Ellipse" }; #else @@ -45,7 +65,7 @@ #define COUNTIDLETIME(a) #endif -// When it is going to poll a register for completion, how many +// When it is going to poll a register for completion, how many // uSec should it wait between each polling activity. #define POLLWAITuSec 10 @@ -123,14 +143,23 @@ return noerror; } +color_t RA8875::GetBackgroundTransparencyColor(void) +{ + RGBQUAD q; + q.rgbRed = ReadCommand(0x67); + q.rgbGreen = ReadCommand(0x68); + q.rgbBlue = ReadCommand(0x69); + return RGBQuadToRGB16(&q, 0); +} + // ### Touch Panel support code additions begin here RetCode_t RA8875::TouchPanelInit(void) -{ +{ //TPCR0: Set enable bit, default sample time, wakeup, and ADC clock WriteCommand(TPCR0, TP_ENABLE | TP_ADC_SAMPLE_DEFAULT_CLKS | TP_ADC_CLKDIV_DEFAULT); // TPCR1: Set auto/manual, Ref voltage, debounce, manual mode params - WriteCommand(TPCR1, TP_MODE_DEFAULT | TP_DEBOUNCE_DEFAULT); + WriteCommand(TPCR1, TP_MODE_DEFAULT | TP_DEBOUNCE_DEFAULT); WriteCommand(INTC1, ReadCommand(INTC1) | RA8875_INT_TP); // reg INTC1: Enable Touch Panel Interrupts (D2 = 1) WriteCommand(INTC2, RA8875_INT_TP); // reg INTC2: Clear any TP interrupt flag return noerror; @@ -140,13 +169,13 @@ { // Parameter bounds check if( \ - !(bTpEnable == TP_ENABLE || bTpEnable == TP_ENABLE) || \ - !(bTpAutoManual == TP_MODE_AUTO || bTpAutoManual == TP_MODE_MANUAL) || \ - !(bTpDebounce == TP_DEBOUNCE_OFF || bTpDebounce == TP_DEBOUNCE_ON) || \ - !(bTpManualMode <= TP_MANUAL_LATCH_Y) || \ - !(bTpAdcClkDiv <= TP_ADC_CLKDIV_128) || \ - !(bTpAdcSampleTime <= TP_ADC_SAMPLE_65536_CLKS) \ - ) return bad_parameter; + !(bTpEnable == TP_ENABLE || bTpEnable == TP_ENABLE) || \ + !(bTpAutoManual == TP_MODE_AUTO || bTpAutoManual == TP_MODE_MANUAL) || \ + !(bTpDebounce == TP_DEBOUNCE_OFF || bTpDebounce == TP_DEBOUNCE_ON) || \ + !(bTpManualMode <= TP_MANUAL_LATCH_Y) || \ + !(bTpAdcClkDiv <= TP_ADC_CLKDIV_128) || \ + !(bTpAdcSampleTime <= TP_ADC_SAMPLE_65536_CLKS) \ + ) return bad_parameter; // Construct the config byte for TPCR0 and write them WriteCommand(TPCR0, bTpEnable | bTpAdcClkDiv | bTpAdcSampleTime); // Note: Wakeup is never enabled // Construct the config byte for TPCR1 and write them @@ -154,7 +183,7 @@ // Set up the interrupt flag and enable bits WriteCommand(INTC1, ReadCommand(INTC1) | RA8875_INT_TP); // reg INTC1: Enable Touch Panel Interrupts (D2 = 1) WriteCommand(INTC2, RA8875_INT_TP); // reg INTC2: Clear any TP interrupt flag - return noerror; + return noerror; } unsigned char RA8875::TouchPanelRead(loc_t *x, loc_t *y) @@ -163,26 +192,26 @@ static int xbuf[TPBUFSIZE], ybuf[TPBUFSIZE], sample = 0; int i, j, temp; - if( (ReadCommand(INTC2) & RA8875_INT_TP) ) { // Test for TP Interrupt pending in register INTC2 + if( (ReadCommand(INTC2) & RA8875_INT_TP) ) { // Test for TP Interrupt pending in register INTC2 // Get the next data samples ybuf[sample] = ReadCommand(TPYH) << 2 | ( (ReadCommand(TPXYL) & 0xC) >> 2 ); // D[9:2] from reg TPYH, D[1:0] from reg TPXYL[3:2] xbuf[sample] = ReadCommand(TPXH) << 2 | ( (ReadCommand(TPXYL) & 0x3) ); // D[9:2] from reg TPXH, D[1:0] from reg TPXYL[1:0] // Check for a complete set if(++sample == TPBUFSIZE) { - // Buffers are full, so process them using Finn's method described in Analog Dialogue No. 44, Feb 2010 - // This requires sorting the samples in order of size, then discarding the top 25% and - // bottom 25% as noise spikes. Finally, the middle 50% of the values are averaged to - // reduce Gaussian noise. - - // Sort the Y buffer using an Insertion Sort + // Buffers are full, so process them using Finn's method described in Analog Dialogue No. 44, Feb 2010 + // This requires sorting the samples in order of size, then discarding the top 25% and + // bottom 25% as noise spikes. Finally, the middle 50% of the values are averaged to + // reduce Gaussian noise. + + // Sort the Y buffer using an Insertion Sort for(i = 1; i <= TPBUFSIZE; i++) { temp = ybuf[i]; j = i; while( j && (ybuf[j-1] > temp) ) { ybuf[j] = ybuf[j-1]; - j = j-1; + j = j-1; } - ybuf[j] = temp; + ybuf[j] = temp; } // End of Y sort // Sort the X buffer the same way for(i = 1; i <= TPBUFSIZE; i++) { @@ -190,31 +219,30 @@ j = i; while( j && (xbuf[j-1] > temp) ) { xbuf[j] = xbuf[j-1]; - j = j-1; + j = j-1; } - xbuf[j] = temp; + xbuf[j] = temp; } // End of X sort // Average the middle half of the Y values and report them j = 0; for(i = (TPBUFSIZE/4) - 1; i < TPBUFSIZE - TPBUFSIZE/4; i++ ) { - j += ybuf[i]; + j += ybuf[i]; } *y = j * (float)2/TPBUFSIZE; // This is the average // Average the middle half of the X values and report them j = 0; for(i = (TPBUFSIZE/4) - 1; i < TPBUFSIZE - TPBUFSIZE/4; i++ ) { - j += xbuf[i]; + j += xbuf[i]; } - *x = j * (float)2/TPBUFSIZE; // This is the average - // Tidy up and return + *x = j * (float)2/TPBUFSIZE; // This is the average + // Tidy up and return touchready = 1; sample = 0; // Ready to start on the next set of data samples - } - else { + } else { // Buffer not yet full, so do not return any results yet touchready = 0; } - WriteCommand(INTC2, RA8875_INT_TP); // reg INTC2: Clear that TP interrupt flag + WriteCommand(INTC2, RA8875_INT_TP); // reg INTC2: Clear that TP interrupt flag } // End of initial if -- data has been read and processed else touchready = 0; // Touch Panel "Int" was not set @@ -225,24 +253,23 @@ { unsigned char touchready; - if( (ReadCommand(INTC2) & RA8875_INT_TP) ) { // Test for TP Interrupt pending in register INTC2 + if( (ReadCommand(INTC2) & RA8875_INT_TP) ) { // Test for TP Interrupt pending in register INTC2 *y = ReadCommand(TPYH) << 2 | ( (ReadCommand(TPXYL) & 0xC) >> 2 ); // D[9:2] from reg TPYH, D[1:0] from reg TPXYL[3:2] *x = ReadCommand(TPXH) << 2 | ( (ReadCommand(TPXYL) & 0x3) ); // D[9:2] from reg TPXH, D[1:0] from reg TPXYL[1:0] - WriteCommand(INTC2, RA8875_INT_TP); // reg INTC2: Clear that TP interrupt flag + WriteCommand(INTC2, RA8875_INT_TP); // reg INTC2: Clear that TP interrupt flag touchready = 1; - } - else - touchready = 0; + } else + touchready = 0; return touchready; } // #### end of touch panel code additions -RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency, - uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable) +RetCode_t RA8875::KeypadInit(bool scanEnable, bool longDetect, uint8_t sampleTime, uint8_t scanFrequency, + uint8_t longTimeAdjustment, bool interruptEnable, bool wakeupEnable) { uint8_t value = 0; - + if (sampleTime > 3 || scanFrequency > 7 || longTimeAdjustment > 3) return bad_parameter; value |= (scanEnable) ? 0x80 : 0x00; @@ -250,12 +277,12 @@ value |= (sampleTime & 0x03) << 4; value |= (scanFrequency & 0x07); WriteCommand(0xC0, value); // Enable Key Scan (and ignore possibility of an error) - + value = 0; value |= (wakeupEnable) ? 0x80 : 0x00; value |= (longTimeAdjustment & 0x03) << 2; WriteCommand(0xC1, value); // (and ignore possibility of an error) - + value = ReadCommand(0xF0); // (and ignore possibility of an error) value &= ~0x10; value |= (interruptEnable) ? 0x10 : 0x00; @@ -294,7 +321,7 @@ void RA8875::RegisterPerformance(method_e method) { unsigned long elapsed = performance.read_us(); - + if (method < METRICCOUNT && elapsed > metrics[method]) metrics[method] = elapsed; } @@ -317,10 +344,10 @@ RetCode_t RA8875::WriteCommandW(uint8_t command, uint16_t data) { - #if 1 +#if 1 WriteCommand(command, data & 0xFF); WriteCommand(command+1, data >> 8); - #else +#else // This should be a little faster, but doesn't work... INFO("WriteCommandW(%02X, %04X)", command, data); select(true); @@ -330,7 +357,7 @@ spiwrite(data & 0xFF); spiwrite(data >> 8); select(false); - #endif +#endif return noerror; } @@ -380,7 +407,7 @@ unsigned char RA8875::ReadData(void) { unsigned char data; - + select(true); spiwrite(0x40); data = spiread(); @@ -392,7 +419,7 @@ uint16_t RA8875::ReadDataW(void) { uint16_t data; - + select(true); spiwrite(0x40); data = spiread(); @@ -405,7 +432,7 @@ unsigned char RA8875::ReadStatus(void) { unsigned char data; - + select(true); spiwrite(0xC0); // These two bits are for the special "Status Read" [STSR] data = spiread(); @@ -506,7 +533,8 @@ RetCode_t RA8875::SetTextCursor(loc_t x, loc_t y) { - cursor_x = x; cursor_y = y; // for non-internal fonts + cursor_x = x; + cursor_y = y; // for non-internal fonts WriteCommandW(0x2A, x); WriteCommandW(0x2C, y); return noerror; @@ -537,7 +565,7 @@ unsigned char mwcr1 = ReadCommand(0x41) & 0x01; // retain currently selected layer unsigned char horz = 0; unsigned char vert = 0; - + mwcr0 |= 0x80; // text mode if (cursor != NOCURSOR) mwcr0 |= 0x40; // visible @@ -581,15 +609,15 @@ RetCode_t RA8875::SetTextFontControl(fill_t fillit, - RA8875::font_angle_t angle, - RA8875::HorizontalScale hScale, - RA8875::VerticalScale vScale, - RA8875::alignment_t alignment) + RA8875::font_angle_t angle, + RA8875::HorizontalScale hScale, + RA8875::VerticalScale vScale, + RA8875::alignment_t alignment) { - if (hScale >= 1 && hScale <= 4 && - vScale >= 1 && vScale <= 4) { + if (hScale >= 1 && hScale <= 4 && + vScale >= 1 && vScale <= 4) { unsigned char x = 0; - + if (alignment == align_full) x |= 0x80; if (fillit == NOFILL) @@ -609,7 +637,7 @@ RetCode_t RA8875::SetTextFontSize(RA8875::HorizontalScale hScale, RA8875::VerticalScale vScale) { unsigned char reg = ReadCommand(0x22); - + if (vScale == -1) vScale = hScale; if (hScale >= 1 && hScale <= 4 && vScale >= 1 && vScale <= 4) { @@ -664,7 +692,7 @@ { if (c) { unsigned char mwcr0; - + mwcr0 = ReadCommand(0x40); if ((mwcr0 & 0x80) == 0x00) { WriteCommand(0x40, 0x80 | mwcr0); // Put in Text mode if not already @@ -709,7 +737,7 @@ RetCode_t RA8875::_putp(color_t pixel) { WriteDataW((pixel>>8) | (pixel<<8)); - return noerror; + return noerror; } @@ -723,7 +751,7 @@ void RA8875::puts(const char * string) { unsigned char mwcr0 = ReadCommand(0x40); - + if (font == NULL) { if ((mwcr0 & 0x80) == 0x00) WriteCommand(0x40,0x80); // Put in Text mode if not already @@ -731,11 +759,11 @@ _StartGraphicsStream(); } if (*string != '\0') { - #if 1 +#if 1 while (*string) { // @TODO calling individual _putc is slower... optimizations? _putc(*string++); } - #else +#else WriteCommand(0x02); select(true); while (*string != '\0') { @@ -744,7 +772,7 @@ _WaitWhileBusy(0x80); } select(false); - #endif +#endif } if (font) _EndGraphicsStream(); @@ -784,7 +812,7 @@ RetCode_t RA8875::cls(uint16_t layers) { RetCode_t ret; - + PERFORMANCE_RESET; if (layers == 0) { ret = clsw(FULLWINDOW); @@ -821,14 +849,14 @@ RetCode_t RA8875::pixel(loc_t x, loc_t y, color_t color) { RetCode_t ret; - + PERFORMANCE_RESET; - #if 1 +#if 1 ret = pixelStream(&color, 1, x,y); - #else +#else foreground(color); ret = pixel(x,y); - #endif +#endif REGISTERPERFORMANCE(PRF_DRAWPIXEL); return ret; } @@ -837,18 +865,18 @@ RetCode_t RA8875::pixel(loc_t x, loc_t y) { RetCode_t ret; - + PERFORMANCE_RESET; color_t color = GetForeColor(); - #if 1 +#if 1 ret = pixelStream(&color, 1, x, y); - #else +#else WriteCommand(0x40,0x00); // Graphics write mode SetGraphicsCursor(x, y); WriteCommand(0x02); WriteDataW(color); ret = noerror; - #endif +#endif REGISTERPERFORMANCE(PRF_DRAWPIXEL); return ret; } @@ -876,7 +904,7 @@ color_t RA8875::getPixel(loc_t x, loc_t y) { color_t pixel; - + PERFORMANCE_RESET; //WriteCommand(0x45,0x00); // read left->right, top->bottom WriteCommand(0x40,0x00); // Graphics write mode @@ -896,7 +924,7 @@ RetCode_t RA8875::getPixelStream(color_t * p, uint32_t count, loc_t x, loc_t y) { color_t pixel; - + PERFORMANCE_RESET; //WriteCommand(0x45,0x00); // read left->right, top->bottom WriteCommand(0x40,0x00); // Graphics write mode @@ -943,23 +971,23 @@ } -RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - color_t color, fill_t fillit) +RetCode_t RA8875::fillrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + color_t color, fill_t fillit) { return rect(x1,y1,x2,y2,color,fillit); } -RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - color_t color, fill_t fillit) +RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + color_t color, fill_t fillit) { foreground(color); return rect(x1,y1,x2,y2,fillit); } -RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - fill_t fillit) +RetCode_t RA8875::rect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + fill_t fillit) { PERFORMANCE_RESET; if (x1 == x2 && y1 == y2) { @@ -985,27 +1013,27 @@ } -RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - dim_t radius1, dim_t radius2, color_t color, fill_t fillit) +RetCode_t RA8875::fillroundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + dim_t radius1, dim_t radius2, color_t color, fill_t fillit) { foreground(color); return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); } -RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - dim_t radius1, dim_t radius2, color_t color, fill_t fillit) +RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + dim_t radius1, dim_t radius2, color_t color, fill_t fillit) { foreground(color); return roundrect(x1,y1,x2,y2,radius1,radius2,fillit); } -RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - dim_t radius1, dim_t radius2, fill_t fillit) +RetCode_t RA8875::roundrect(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + dim_t radius1, dim_t radius2, fill_t fillit) { RetCode_t ret = noerror; - + PERFORMANCE_RESET; if (x1 > x2 || y1 > y2 || (radius1 > (x2-x1)/2) || (radius2 > (y2-y1)/2) ) { ret = bad_parameter; @@ -1037,19 +1065,8 @@ } -RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - loc_t x3, loc_t y3, color_t color, fill_t fillit) -{ - RetCode_t ret; - - foreground(color); - ret = triangle(x1,y1,x2,y2,x3,y3,fillit); - return ret; -} - - -RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, - loc_t x3, loc_t y3, color_t color, fill_t fillit) +RetCode_t RA8875::triangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + loc_t x3, loc_t y3, color_t color, fill_t fillit) { RetCode_t ret; @@ -1059,11 +1076,22 @@ } -RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2, - loc_t x3, loc_t y3, fill_t fillit) +RetCode_t RA8875::filltriangle(loc_t x1, loc_t y1, loc_t x2, loc_t y2, + loc_t x3, loc_t y3, color_t color, fill_t fillit) +{ + RetCode_t ret; + + foreground(color); + ret = triangle(x1,y1,x2,y2,x3,y3,fillit); + return ret; +} + + +RetCode_t RA8875::triangle(loc_t x1, loc_t y1 ,loc_t x2, loc_t y2, + loc_t x3, loc_t y3, fill_t fillit) { RetCode_t ret = noerror; - + PERFORMANCE_RESET; if (x1 == x2 && y1 == y2 && x1 == x3 && y1 == y3) { pixel(x1, y1); @@ -1085,16 +1113,16 @@ return ret; } -RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, - color_t color, fill_t fillit) +RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, + color_t color, fill_t fillit) { foreground(color); return circle(x,y,radius,fillit); } -RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius, - color_t color, fill_t fillit) +RetCode_t RA8875::fillcircle(loc_t x, loc_t y, dim_t radius, + color_t color, fill_t fillit) { foreground(color); return circle(x,y,radius,fillit); @@ -1104,7 +1132,7 @@ RetCode_t RA8875::circle(loc_t x, loc_t y, dim_t radius, fill_t fillit) { RetCode_t ret = noerror; - + PERFORMANCE_RESET; if (radius <= 0) { ret = bad_parameter; @@ -1139,11 +1167,11 @@ return ellipse(x,y,radius1,radius2,fillit); } - + RetCode_t RA8875::ellipse(loc_t x, loc_t y, dim_t radius1, dim_t radius2, fill_t fillit) { RetCode_t ret = noerror; - + PERFORMANCE_RESET; if (radius1 <= 0 || radius2 <= 0) { ; // do nothing @@ -1205,7 +1233,7 @@ WriteCommand(0x01, 0x01); // Apply Display Off, Reset wait_ms(2); // no idea if I need to wait, or how long WriteCommand(0x01, 0x00); // Display off, Remove reset - wait_ms(2); // no idea if I need to wait, or how long + wait_ms(2); // no idea if I need to wait, or how long init(RA8875_DISPLAY_WIDTH, RA8875_DISPLAY_HEIGHT, RA8875_COLORDEPTH_BPP); return noerror; } @@ -1233,7 +1261,7 @@ RetCode_t RA8875::Backlight(float brightness) { unsigned char b; - + if (brightness >= 1.0) b = 255; else if (brightness <= 0.0) @@ -1298,7 +1326,7 @@ color_t RA8875::GetForeColor(void) { color_t color; - + color = (ReadCommand(0x63) & 0x1F) << 11; color |= (ReadCommand(0x64) & 0x3F) << 5; color |= (ReadCommand(0x65) & 0x1F); @@ -1307,35 +1335,33 @@ color_t RA8875::DOSColor(int i) - { - const color_t colors[16] = - { +{ + const color_t colors[16] = { Black, Blue, Green, Cyan, Red, Magenta, Brown, Gray, Charcoal, BrightBlue, BrightGreen, BrightCyan, Orange, Pink, Yellow, White - }; + }; if (i < 16) return colors[i]; else return 0; - } +} -const char * RA8875::DOSColorNames(int i) - { - const char * names[16] = - { +const char * RA8875::DOSColorNames(int i) +{ + const char * names[16] = { "Black", "Blue", "Green", "Cyan", "Red", "Magenta", "Brown", "Gray", "Charcoal", "BrightBlue", "BrightGreen", "BrightCyan", "Orange", "Pink", "Yellow", "White" - }; + }; if (i < 16) return names[i]; else return NULL; - } +} /////////////////////////////////////////////////////////////// @@ -1344,7 +1370,7 @@ unsigned char RA8875::spiwrite(unsigned char data) { unsigned char retval; - + if (!spiWriteSpeed) _setWriteSpeed(true); retval = spi.write(data); @@ -1356,7 +1382,7 @@ { unsigned char retval; unsigned char data = 0; - + if (spiWriteSpeed) _setWriteSpeed(false); retval = spi.write(data); @@ -1378,7 +1404,7 @@ wait_ms(1); WriteCommand(0x89, 0x02); wait_ms(1); - + // System Config Register (SYSR) if (color_bpp == 16) { WriteCommand(0x10, 0x0C); // 16-bpp (65K colors) color depth, 8-bit interface @@ -1410,7 +1436,7 @@ } else { WriteCommand(0x20, 0x80); // DPCR - 2-layer mode } - + // Set display image to Blue on Black as default window(0,0, width, height); // Initialize to full screen SetTextCursorControl(); @@ -1438,19 +1464,19 @@ { BITMAPFILEHEADER BMP_Header; BITMAPINFOHEADER BMP_Info; - + INFO("(%d,%d) - (%d,%d) %s", x,y,w,h,Name_BMP); if (x >= 0 && x < width() - && y >= 0 && y < height() - && w > 0 && x + w <= width() - && h > 0 && y + h <= height()) { + && y >= 0 && y < height() + && w > 0 && x + w <= width() + && h > 0 && y + h <= height()) { BMP_Header.bfType = BF_TYPE; BMP_Header.bfSize = (w * h * sizeof(RGBQUAD)) + sizeof(BMP_Header) + sizeof(BMP_Header); BMP_Header.bfReserved1 = 0; BMP_Header.bfReserved2 = 0; BMP_Header.bfOffBits = sizeof(BMP_Header) + sizeof(BMP_Header); - + BMP_Info.biSize = sizeof(BMP_Info); BMP_Info.biWidth = w; BMP_Info.biHeight = h; @@ -1474,11 +1500,11 @@ //HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header)); fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image); //INFO("fwrite returned %d", r); - + //HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info)); fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image); //INFO("fwrite returned %d", r); - + int lineBufSize = ((24 * w + 7)/8); uint8_t * lineBuffer = (uint8_t *)malloc(lineBufSize); if (lineBuffer == NULL) { @@ -1487,38 +1513,86 @@ return(not_enough_ram); } color_t * pixelBuffer = (color_t *)malloc(w * sizeof(color_t)); - if (pixelBuffer == NULL) { + color_t * pixelBuffer2 = (color_t *)malloc(w * sizeof(color_t)); + color_t transparency = GetBackgroundTransparencyColor(); + unsigned char ltpr0 = ReadCommand(0x52) & 0x7; + + if (pixelBuffer == NULL || pixelBuffer2 == NULL) { fclose(Image); free(lineBuffer); ERR("Not enough RAM for pixelBuffer"); + if (pixelBuffer) + free(pixelBuffer); return(not_enough_ram); } - + + uint16_t prevLayer = GetDrawingLayer(); + // If only one of the layers is visible, select that layer + switch(ltpr0) { + case 0: + SelectDrawingLayer(0); + break; + case 1: + SelectDrawingLayer(1); + break; + default: + break; + } + // Read the display from the last line toward the top // so we can write the file in one pass. for (int j = h - 1; j >= 0; j--) { + if (ltpr0 >= 2) // Need to combine the layers... + SelectDrawingLayer(0); // so read layer 0 first // Read one line of pixels to a local buffer if (getPixelStream(pixelBuffer, w, x,y+j) != noerror) { ERR("getPixelStream error, and no recovery handler..."); } + if (ltpr0 >= 2) { // Need to combine the layers... + SelectDrawingLayer(1); // so read layer 0 first + if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) { + ERR("getPixelStream error, and no recovery handler..."); + } + } // Convert the local buffer to RGBQUAD format int lb = 0; for (int i=0; i<w; i++) { - color_t pixel = pixelBuffer[x+i]; - // Scale to 24-bits - RGBQUAD q = RGB16ToRGBQuad(pixel); - lineBuffer[lb++] = q.rgbBlue; - lineBuffer[lb++] = q.rgbGreen; - lineBuffer[lb++] = q.rgbRed; + RGBQUAD q0 = RGB16ToRGBQuad(pixelBuffer[x+i]); // Scale to 24-bits + RGBQUAD q1 = RGB16ToRGBQuad(pixelBuffer2[x+i]); // Scale to 24-bits + switch (ltpr0) { + case 0: + case 1: + case 2: // lighten-overlay (@TODO Not supported yet) + case 6: // Floating Windows (@TODO not sure how to support) + default: // Reserved... + lineBuffer[lb++] = q0.rgbBlue; + lineBuffer[lb++] = q0.rgbGreen; + lineBuffer[lb++] = q0.rgbRed; + break; + case 3: // transparent mode (@TODO Read the background color register for transparent) + case 4: // boolean or + lineBuffer[lb++] = q0.rgbBlue | q1.rgbBlue; + lineBuffer[lb++] = q0.rgbGreen | q1.rgbGreen; + lineBuffer[lb++] = q0.rgbRed | q1.rgbRed; + break; + case 5: // boolean AND + lineBuffer[lb++] = q0.rgbBlue & q1.rgbBlue; + lineBuffer[lb++] = q0.rgbGreen & q1.rgbGreen; + lineBuffer[lb++] = q0.rgbRed & q1.rgbRed; + break; + } } + if (j == h - 1) + HexDump("Line", lineBuffer, lineBufSize); // Write to disk - //HexDump("Line", lineBuffer, lineBufSize); fwrite(lineBuffer, sizeof(char), lb, Image); } + SelectDrawingLayer(prevLayer); fclose(Image); - free(pixelBuffer); // don't leak memory. + free(pixelBuffer2); // don't leak memory. + free(pixelBuffer); free(lineBuffer); - INFO("Image closed"); + INFO("Image closed"); return noerror; } else { return bad_parameter; @@ -1574,17 +1648,17 @@ const char * bbCursor = "The Blinking Block cursor should be visible for this text.\r\n"; const char * p; int delay = 100; - + if (!SuppressSlowStuff) pc.printf("Text Cursor Test\r\n"); - else + else delay = 0; display.background(Black); display.foreground(Blue); display.cls(); display.Backlight_u8(255); display.puts(0,0, "Text Cursor Test."); - + // visible, non-blinking display.SetTextCursor(0,20); display.SetTextCursorControl(RA8875::IBEAM, false); @@ -1600,7 +1674,7 @@ display._putc(*p++); wait_ms(delay); } - + display.SetTextCursorControl(RA8875::BLOCK, false); p = bCursor; while (*p) { @@ -1678,12 +1752,12 @@ display.puts(0,0, "External Font Test."); display.set_font(Small_6); - display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); + display.puts(0,30, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); display.set_font(Arial12x12); display.puts("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\r\n"); display.set_font(); // restore to internal - + display.puts("Normal font again."); //display.window(0,0, display.width(), display.height()); } @@ -1798,7 +1872,7 @@ display.line(20,52, 20,52, BrightRed); display.line(22,52, 22,52, BrightGreen); display.line(24,52, 24,52, BrightBlue); - + // point display.line(50,50, 50,50, Red); display.line(52,52, 52,52, Green); @@ -1893,7 +1967,7 @@ if (!SuppressSlowStuff) wait_ms(200); } - + // Restore before we exit display.SetLayerTransparency(0, 0); display.SetLayerMode(RA8875::ShowLayer0); // Restore to layer 0 @@ -1910,7 +1984,7 @@ display.foreground(Blue); display.cls(); display.puts(0,0, "Rounded Rectangle Test"); - + for (i=0; i<16; i++) { x1 = rand() % 240; y1 = 50 + rand() % 200; @@ -2049,7 +2123,7 @@ { LocalFileSystem local("local"); if (!SuppressSlowStuff) - pc.printf("Bitmap File Load\r\n"); + pc.printf("Bitmap File Load\r\n"); display.background(Black); display.foreground(Blue); display.cls(); @@ -2086,9 +2160,9 @@ LayerTest(display, pc); //TestGraphicsBitmap(display, pc); pc.printf("SpeedTest completed in %d msec\r\n", t.read_ms()); - #ifdef PERF_METRICS +#ifdef PERF_METRICS display.ReportPerformance(pc); - #endif +#endif SuppressSlowStuff = false; } @@ -2097,7 +2171,7 @@ { LocalFileSystem local("local"); if (!SuppressSlowStuff) - pc.printf("PrintScreen\r\n"); + pc.printf("PrintScreen\r\n"); display.PrintScreen( 0,0, 480,272, "/local/Capture.bmp"); } @@ -2120,9 +2194,9 @@ "A - Auto Test mode S - Speed Test\r\n" "p - print screen r - reset \r\n" "l - layer test w - wrapping text \r\n" - #ifdef PERF_METRICS +#ifdef PERF_METRICS "0 - clear performance 1 - report performance\r\n" - #endif +#endif "> "); if (automode == -1 || pc.readable()) { automode = -1; @@ -2133,14 +2207,14 @@ q = modelist[automode]; } switch(q) { - #ifdef PERF_METRICS +#ifdef PERF_METRICS case '0': lcd.ClearPerformance(); break; case '1': lcd.ReportPerformance(pc); break; - #endif +#endif case 'A': automode = 0; break;
--- a/RA8875.h Sat Oct 11 17:24:29 2014 +0000 +++ b/RA8875.h Sun Nov 09 18:52:46 2014 +0000 @@ -293,6 +293,16 @@ /// RetCode_t SetBackgroundTransparencyColor(color_t color = RGB(0,0,0)); + + /// Get the background color value used for transparency. + /// + /// This command reads the background color registers that define + /// the transparency color for operations involving layers. + /// + /// @returns the color. + /// + color_t GetBackgroundTransparencyColor(void); + /// Initialize theTouch Panel controller with default values /// /// @returns success/failure code. @see RetCode_t. @@ -1286,6 +1296,11 @@ /// Even though this is a 16-bit display, the stored image is in /// 24-bit format. /// + /// This method will interrogate the current display setting and + /// create a bitmap based on those settings. For instance, if + /// only layer 1 is visible, then the bitmap is only layer 1. However, + /// if there is some other operation in effect (transparent mode). + /// /// @param[in] x is the left edge of the region to capture /// @param[in] y is the top edge of the region to capture /// @param[in] w is the width of the region to capture