LCD LIB

Dependents:   HagridOS5

Fork of RA8875 by David Smart

Files at this revision

API Documentation at this revision

Comitter:
WiredHome
Date:
Sat Nov 28 15:39:44 2015 +0000
Parent:
95:ef538bd687c0
Child:
97:03c509c3db18
Child:
98:ecebed9b80b2
Commit message:
Changes for the print screen function to use callbacks.

Changed in this revision

RA8875.cpp Show annotated file Show diff for this revision Revisions of this file
RA8875.h Show annotated file Show diff for this revision Revisions of this file
--- a/RA8875.cpp	Tue Jul 07 17:05:59 2015 +0000
+++ b/RA8875.cpp	Sat Nov 28 15:39:44 2015 +0000
@@ -97,6 +97,9 @@
     , cs(csel)
     , res(reset)
 {
+    c_callback = NULL;
+    obj_callback = NULL;
+    method_callback = NULL;
 }
 
 //RA8875::~RA8875()
@@ -1587,9 +1590,205 @@
 RetCode_t RA8875::PrintScreen(uint16_t layer, loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
 {
     (void)layer;
+    
+    // AttachPrintHandler(this, RA8875::_printCallback);
+    // return PrintScreen(x,y,w,h);
     return PrintScreen(x, y, w, h, Name_BMP);
 }
 
+RetCode_t RA8875::_printCallback(RA8875::filecmd_t cmd, uint8_t * buffer, uint16_t size)
+{
+    HexDump("CB", buffer, size);
+    switch(cmd) {
+        case RA8875::OPEN:
+            //pc.printf("About to write %lu bytes\r\n", *(uint32_t *)buffer);
+            _printFH = fopen("file.bmp", "w+b");
+            if (_printFH == 0)
+                return file_not_found;
+            break;
+        case RA8875::WRITE:
+            //pc.printf("  Write %4u bytes\r\n", size);
+            fwrite(buffer, 1, size, _printFH);
+            break;
+        case RA8875::CLOSE:
+            //pc.printf("  close\r\n");
+            fclose(_printFH);
+            _printFH = 0;
+            break;
+        default:
+            //pc.printf("Unexpected callback %d\r\n", cmd);
+            return file_not_found;
+            //break;
+    }
+    return noerror;
+}
+
+RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h)
+{
+    BITMAPFILEHEADER BMP_Header;
+    BITMAPINFOHEADER BMP_Info;
+    uint8_t * lineBuffer = NULL;
+    color_t * pixelBuffer = NULL;
+    color_t * pixelBuffer2 = NULL;
+    
+    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()) {
+
+        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;
+        BMP_Info.biPlanes = 1;
+        BMP_Info.biBitCount = 24;
+        BMP_Info.biCompression = BI_RGB;
+        BMP_Info.biSizeImage = 0;
+        BMP_Info.biXPelsPerMeter = 0;
+        BMP_Info.biYPelsPerMeter = 0;
+        BMP_Info.biClrUsed = 0;
+        BMP_Info.biClrImportant = 0;
+
+        // Allocate the memory we need to proceed
+        int lineBufSize = ((24 * w + 7)/8);
+        lineBuffer = (uint8_t *)malloc(lineBufSize);
+        if (lineBuffer == NULL) {
+            ERR("Not enough RAM for PrintScreen lineBuffer");
+            return(not_enough_ram);
+        }
+
+        #define DOUBLEBUF /* one larger buffer instead of two */
+        
+        #ifdef DOUBLEBUF
+        // In the "#else", pixelBuffer2 malloc returns a value, 
+        // but is actually causing a failure later. 
+        // This test helps determine if it is truly out of memory,
+        // or if malloc is broken.
+        pixelBuffer = (color_t *)malloc(2 * w * sizeof(color_t));
+        pixelBuffer2 = pixelBuffer + (w * sizeof(color_t));
+        #else
+        pixelBuffer = (color_t *)malloc(w * sizeof(color_t));
+        pixelBuffer2 = (color_t *)malloc(w * sizeof(color_t));
+        #endif
+        if (pixelBuffer == NULL || pixelBuffer2 == NULL) {
+            ERR("Not enough RAM for pixelBuffer");
+            #ifndef DOUBLEBUF
+            if (pixelBuffer2)
+                free(pixelBuffer2);
+            #endif
+            if (pixelBuffer)
+                free(pixelBuffer);
+            free(lineBuffer);
+            if (pixelBuffer)
+                free(pixelBuffer);
+            return(not_enough_ram);
+        }
+
+        // Get the file primed...
+        privateCallback(OPEN, (uint8_t *)&BMP_Header.bfSize, 4);
+
+        // Be optimistic - don't check for errors.
+        HexDump("BMP_Header", (uint8_t *)&BMP_Header, sizeof(BMP_Header));        
+        //fwrite(&BMP_Header, sizeof(char), sizeof(BMP_Header), Image);
+        privateCallback(WRITE, (uint8_t *)&BMP_Header, sizeof(BMP_Header));
+
+        HexDump("BMP_Info", (uint8_t *)&BMP_Info, sizeof(BMP_Info));
+        //fwrite(&BMP_Info, sizeof(char), sizeof(BMP_Info), Image);
+        privateCallback(WRITE, (uint8_t *)&BMP_Info, sizeof(BMP_Info));
+
+        //color_t transparency = GetBackgroundTransparencyColor();
+        LayerMode_T ltpr0 = GetLayerMode();
+
+        uint16_t prevLayer = GetDrawingLayer();
+        // If only one of the layers is visible, select that layer
+        switch(ltpr0) {
+            case ShowLayer0:
+                SelectDrawingLayer(0);
+                break;
+            case ShowLayer1:
+                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 1 next
+                if (getPixelStream(pixelBuffer2, w, x,y+j) != noerror) {
+                    ERR("getPixelStream error, and no recovery handler...");
+                }
+            }
+            INFO("1st Color: %04X", pixelBuffer[0]);
+            HexDump("Raster", (uint8_t *)pixelBuffer, w);
+            // Convert the local buffer to RGBQUAD format
+            int lb = 0;
+            for (int i=0; i<w; i++) {
+                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
+            //fwrite(lineBuffer, sizeof(char), lb, Image);
+            privateCallback(WRITE, (uint8_t *)lineBuffer, lb);
+        }
+        SelectDrawingLayer(prevLayer);
+        //fclose(Image);
+        privateCallback(CLOSE, NULL, 0);
+        
+        #ifndef DOUBLEBUF
+        if (pixelBuffer2)
+            free(pixelBuffer2);
+        #endif
+        if (pixelBuffer)
+            free(pixelBuffer);
+        free(lineBuffer);
+        if (pixelBuffer)
+            free(pixelBuffer);
+        INFO("Image closed");
+        return noerror;
+    } else {
+        return bad_parameter;
+    }
+}
 
 RetCode_t RA8875::PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP)
 {
--- a/RA8875.h	Tue Jul 07 17:05:59 2015 +0000
+++ b/RA8875.h	Sat Nov 28 15:39:44 2015 +0000
@@ -104,6 +104,7 @@
 //namespace SW_graphics
 //{
 
+class FPointerDummy;    // used by the callback methods.
 
 /// This is a graphics library for the Raio RA8875 Display Controller chip
 /// attached to a 4-wire SPI interface.
@@ -219,6 +220,49 @@
         TP_Auto,               ///< Auto touch detection mode
         TP_Manual,             ///< Manual touch detection mode
     } tpmode_t;
+
+    /// printscreen callback commands
+    typedef enum
+    {
+        OPEN,       ///< command to open the file. cast uint32_t * to the buffer to get the total size to be written.
+        WRITE,      ///< command to write some data, buffer points to the data and the size is in bytes.
+        CLOSE,      ///< command to close the file
+    } filecmd_t;
+
+    /// print screen callback
+    ///
+    /// The special form of the print screen will pass one blob at a time 
+    /// to the callback. There are basic command declaring that the stream
+    /// can be opened, a block written, and the stream closed. There is
+    /// also a command to communicate the total size being delivered.
+    ///
+    /// @code
+    /// lcd.PrintScreen(x,y,w,h,callback);
+    /// ... 
+    /// void callback(filecmd_t cmd, uint8_t * buffer, uint16_t size) {
+    ///     switch(cmd) {
+    ///         case OPEN:
+    ///             pc.printf("About to write %u bytes\r\n", *(uint32_t *)buffer);
+    ///             fh = fopen("file.bmp", "w+b");
+    ///             break;
+    ///         case WRITE:
+    ///             fwrite(buffer, size, fh);
+    ///             break;
+    ///         case CLOSE:
+    ///             fclose(fh);
+    ///             break;
+    ///         default:
+    ///             pc.printf("Unexpected callback %d\r\n", cmd);
+    ///             break;
+    ///     }
+    /// }
+    /// @endcode
+    ///
+    /// @param cmd is the command to execute. @see filecmd_t.
+    /// @param buffer is a pointer to the buffer being passed.
+    /// @param size is the number of bytes in the buffer.
+    ///
+    typedef RetCode_t (* PrintCallback_T)(filecmd_t cmd, uint8_t * buffer, uint16_t size);
     
     /// Constructor for a display based on the RAiO RA8875 
     /// display controller.
@@ -1812,6 +1856,51 @@
     ///
     RetCode_t PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h, const char *Name_BMP);
     
+    /// This method captures the specified area as a 24-bit bitmap file
+    /// and delivers it to the previously attached callback.
+    ///
+    /// 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), it
+    /// will return the blended image.
+    ///
+    /// @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
+    /// @param[in] h is the height of the region to capture.
+    /// @return success or error code.
+    ///
+    RetCode_t PrintScreen(loc_t x, loc_t y, dim_t w, dim_t h);
+    
+    /// PrintScreen callback registration.
+    ///
+    /// This method attaches a simple c-compatible callback of type PrintCallback_T.
+    /// Then, the PrintScreen(x,y,w,h) method is called. Each chunk of data in the
+    /// BMP file to be created is passed to this callback.
+    /// 
+    /// @param callback is the callback function.
+    ///
+    void AttachPrintHandler(PrintCallback_T callback) { c_callback = callback; }
+
+    /// PrintScreen callback registration.
+    ///
+    /// This method attaches a c++ class method as a callback of type PrintCallback_T.
+    /// Then, the PrintScreen(x,y,w,h) method is called. Each chunk of data in the
+    /// BMP file to be created is passed to this callback.
+    /// 
+    /// @param object is the class hosting the callback function.
+    /// @param callback is the callback function.
+    ///
+    template <class T>
+    void AttachPrintHandler(T *object, RetCode_t (T::*member)(void)) { 
+        obj_callback    = (FPointerDummy *)item; 
+        method_callback = (uint32_t (FPointerDummy::*)(uint32_t))method;
+    }
+
     /// This method captures the specified area as a 24-bit bitmap file,
     /// including the option of layer selection.
     ///
@@ -2003,8 +2092,29 @@
     void RegisterPerformance(method_e method);
     Timer performance;
     #endif
+    
+    RetCode_t _printCallback(RA8875::filecmd_t cmd, uint8_t * buffer, uint16_t size);
+    
+    FILE * _printFH;             ///< PrintScreen file handle
+    
+    RetCode_t privateCallback(filecmd_t cmd, uint8_t * buffer, uint16_t size) {
+        if (c_callback != NULL) {
+            return (*c_callback)(cmd, buffer, size);
+        }
+        else {
+            if (obj_callback != NULL && method_callback != NULL) {
+                return (obj_callback->*method_callback)(cmd, buffer, size);
+            }
+        }
+        return noerror;
+    }
+    
+    RetCode_t (* c_callback)(filecmd_t cmd, uint8_t * buffer, uint16_t size);
+    FPointerDummy  *obj_callback;
+    RetCode_t (FPointerDummy::*method_callback)(filecmd_t cmd, uint8_t * buffer, uint16_t size);
 };
 
+
 //}     // namespace
 
 //using namespace SW_graphics;