Forked para SNOCC
Fork of RA8875 by
Diff: RA8875.cpp
- Revision:
- 73:f22a18707b5e
- Parent:
- 72:ecffe56af969
- Child:
- 74:686faa218914
diff -r ecffe56af969 -r f22a18707b5e RA8875.cpp --- 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;