/* ###################################################################
**     This component module is generated by Processor Expert. Do not modify it.
**     Filename    : McuGDisplaySSD1306.h
**     Project     : FRDM-K64F_Generator
**     Processor   : MK64FN1M0VLL12
**     Component   : GDisplay
**     Version     : Component 01.211, Driver 01.00, CPU db: 3.00.000
**     Compiler    : GNU C Compiler
**     Date/Time   : 2024-07-09, 10:10, # CodeGen: 829
**     Abstract    :
**          Graphical display driver for LCD or other displays
**     Settings    :
**          Component name                                 : McuGDisplaySSD1306
**          SDK                                            : McuLib
**          Inverted Pixels                                : no
**          Memory Buffer                                  : Enabled
**            Orientation                                  : Landscape
**          Clear screen on Init                           : no
**          Hardware                                       : 
**            Display                                      : McuSSD1306
**          Watchdog                                       : Disabled
**          RTOS                                           : Disabled
**     Contents    :
**         PutPixel              - void McuGDisplaySSD1306_PutPixel(McuGDisplaySSD1306_PixelDim x,...
**         SetPixel              - void McuGDisplaySSD1306_SetPixel(McuGDisplaySSD1306_PixelDim x,...
**         ClrPixel              - void McuGDisplaySSD1306_ClrPixel(McuGDisplaySSD1306_PixelDim x,...
**         Clear                 - void McuGDisplaySSD1306_Clear(void);
**         DrawBox               - void McuGDisplaySSD1306_DrawBox(McuGDisplaySSD1306_PixelDim x,...
**         DrawFilledBox         - void McuGDisplaySSD1306_DrawFilledBox(McuGDisplaySSD1306_PixelDim x,...
**         DrawHLine             - void McuGDisplaySSD1306_DrawHLine(McuGDisplaySSD1306_PixelDim x,...
**         DrawVLine             - void McuGDisplaySSD1306_DrawVLine(McuGDisplaySSD1306_PixelDim x,...
**         DrawLine              - void McuGDisplaySSD1306_DrawLine(McuGDisplaySSD1306_PixelDim xstart,...
**         DrawCircle            - void McuGDisplaySSD1306_DrawCircle(McuGDisplaySSD1306_PixelDim x0,...
**         DrawFilledCircle      - void McuGDisplaySSD1306_DrawFilledCircle(McuGDisplaySSD1306_PixelDim x0,...
**         DrawBarChart          - void McuGDisplaySSD1306_DrawBarChart(McuGDisplaySSD1306_PixelDim x,...
**         DrawMonoBitmap        - void McuGDisplaySSD1306_DrawMonoBitmap(int16_t x, int16_t y, PIMAGE image,...
**         DrawMonoBitmapMask    - void McuGDisplaySSD1306_DrawMonoBitmapMask(McuGDisplaySSD1306_PixelDim x,...
**         DrawColorBitmap       - void McuGDisplaySSD1306_DrawColorBitmap(McuGDisplaySSD1306_PixelDim x,...
**         Draw65kBitmap         - void McuGDisplaySSD1306_Draw65kBitmap(McuGDisplaySSD1306_PixelDim x1,...
**         Draw256BitmapLow      - void McuGDisplaySSD1306_Draw256BitmapLow(McuGDisplaySSD1306_PixelDim x1,...
**         Draw256BitmapHigh     - void McuGDisplaySSD1306_Draw256BitmapHigh(McuGDisplaySSD1306_PixelDim x1,...
**         UpdateFull            - void McuGDisplaySSD1306_UpdateFull(void);
**         UpdateRegion          - void McuGDisplaySSD1306_UpdateRegion(McuGDisplaySSD1306_PixelDim x,...
**         GetDisplayOrientation - McuGDisplaySSD1306_DisplayOrientation M...
**         SetDisplayOrientation - void McuGDisplaySSD1306_SetDisplayOrien...
**         GetWidth              - McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetWidth(void);
**         GetHeight             - McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetHeight(void);
**         GetLongerSide         - McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetLongerSide(void);
**         GetShorterSide        - McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetShorterSide(void);
**         GetDisplay            - void McuGDisplaySSD1306_GetDisplay(void);
**         GiveDisplay           - void McuGDisplaySSD1306_GiveDisplay(void);
**         Deinit                - void McuGDisplaySSD1306_Deinit(void);
**         Init                  - void McuGDisplaySSD1306_Init(void);
**
** * Copyright (c) 2013-2023, Erich Styger
**  * Web:         https://mcuoneclipse.com
**  * SourceForge: https://sourceforge.net/projects/mcuoneclipse
**  * Git:         https://github.com/ErichStyger/McuOnEclipse_PEx
**  * All rights reserved.
**  *
**  * Redistribution and use in source and binary forms, with or without modification,
**  * are permitted provided that the following conditions are met:
**  *
**  * - Redistributions of source code must retain the above copyright notice, this list
**  *   of conditions and the following disclaimer.
**  *
**  * - Redistributions in binary form must reproduce the above copyright notice, this
**  *   list of conditions and the following disclaimer in the documentation and/or
**  *   other materials provided with the distribution.
**  *
**  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
**  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
**  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
**  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
**  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
**  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
**  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
**  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
**  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
**  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** ###################################################################*/
/*!
** @file McuGDisplaySSD1306.h
** @version 01.00
** @brief
**          Graphical display driver for LCD or other displays
*/         
/*!
**  @addtogroup McuGDisplaySSD1306_module McuGDisplaySSD1306 module documentation
**  @{
*/         

/* MODULE McuGDisplaySSD1306. */

#include "McuGDisplaySSD1306.h"

#if McuGDisplaySSD1306_CONFIG_USE_MUTEX
  #include "FreeRTOS.h"
  #include "semphr.h"

  static SemaphoreHandle_t McuGDisplaySSD1306_displayMutex;
#endif
static const uint16_t c332to565[256] = { /* converts a 3-3-2 RBG value into a 5-6-5 RGB value */
 0x0000, 0x000A, 0x0014, 0xF81E, 0x0120, 0x012A, 0x0134, 0xF93E,
 0x0240, 0x024A, 0x0254, 0xFA5E, 0x0360, 0x036A, 0x0374, 0xFB7E,
 0x0480, 0x048A, 0x0494, 0xFC9E, 0x05A0, 0x05AA, 0x05B4, 0xFDBE,
 0x06C0, 0x06CA, 0x06D4, 0xFEDE, 0x07E0, 0x07EA, 0x07F4, 0xFFFE,
 0x2000, 0x200A, 0x2014, 0xF81E, 0x2120, 0x212A, 0x2134, 0xF93E,
 0x2240, 0x224A, 0x2254, 0xFA5E, 0x2360, 0x236A, 0x2374, 0xFB7E,
 0x2480, 0x248A, 0x2494, 0xFC9E, 0x25A0, 0x25AA, 0x25B4, 0xFDBE,
 0x26C0, 0x26CA, 0x26D4, 0xFEDE, 0x27E0, 0x27EA, 0x27F4, 0xFFFE,
 0x4000, 0x400A, 0x4014, 0xF81E, 0x4120, 0x412A, 0x4134, 0xF93E,
 0x4240, 0x424A, 0x4254, 0xFA5E, 0x4360, 0x436A, 0x4374, 0xFB7E,
 0x4480, 0x448A, 0x4494, 0xFC9E, 0x45A0, 0x45AA, 0x45B4, 0xFDBE,
 0x46C0, 0x46CA, 0x46D4, 0xFEDE, 0x47E0, 0x47EA, 0x47F4, 0xFFFE,
 0x6000, 0x600A, 0x6014, 0xF81E, 0x6120, 0x612A, 0x6134, 0xF93E,
 0x6240, 0x624A, 0x6254, 0xFA5E, 0x6360, 0x636A, 0x6374, 0xFB7E,
 0x6480, 0x648A, 0x6494, 0xFC9E, 0x65A0, 0x65AA, 0x65B4, 0xFDBE,
 0x66C0, 0x66CA, 0x66D4, 0xFEDE, 0x67E0, 0x67EA, 0x67F4, 0xFFFE,
 0x8000, 0x800A, 0x8014, 0xF81E, 0x8120, 0x812A, 0x8134, 0xF93E,
 0x8240, 0x824A, 0x8254, 0xFA5E, 0x8360, 0x836A, 0x8374, 0xFB7E,
 0x8480, 0x848A, 0x8494, 0xFC9E, 0x85A0, 0x85AA, 0x85B4, 0xFDBE,
 0x86C0, 0x86CA, 0x86D4, 0xFEDE, 0x87E0, 0x87EA, 0x87F4, 0xFFFE,
 0xA000, 0xA00A, 0xA014, 0xF81E, 0xA120, 0xA12A, 0xA134, 0xF93E,
 0xA240, 0xA24A, 0xA254, 0xFA5E, 0xA360, 0xA36A, 0xA374, 0xFB7E,
 0xA480, 0xA48A, 0xA494, 0xFC9E, 0xA5A0, 0xA5AA, 0xA5B4, 0xFDBE,
 0xA6C0, 0xA6CA, 0xA6D4, 0xFEDE, 0xA7E0, 0xA7EA, 0xA7F4, 0xFFFE,
 0xC000, 0xC00A, 0xC014, 0xF81E, 0xC120, 0xC12A, 0xC134, 0xF93E,
 0xC240, 0xC24A, 0xC254, 0xFA5E, 0xC360, 0xC36A, 0xC374, 0xFB7E,
 0xC480, 0xC48A, 0xC494, 0xFC9E, 0xC5A0, 0xC5AA, 0xC5B4, 0xFDBE,
 0xC6C0, 0xC6CA, 0xC6D4, 0xFEDE, 0xC7E0, 0xC7EA, 0xC7F4, 0xFFFE,
 0xF800, 0xF80A, 0xF814, 0xF81E, 0xF920, 0xF92A, 0xF934, 0xF93E,
 0xFA40, 0xFA4A, 0xFA54, 0xFA5E, 0xFB60, 0xFB6A, 0xFB74, 0xFB7E,
 0xFC80, 0xFC8A, 0xFC94, 0xFC9E, 0xFDA0, 0xFDAA, 0xFDB4, 0xFDBE,
 0xFEC0, 0xFECA, 0xFED4, 0xFEDE, 0xFFE0, 0xFFEA, 0xFFF4, 0xFFFE,
};
/*
** ===================================================================
**     Method      :  Clear (component GDisplay)
**
**     Description :
**         Clears the display buffer.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_Clear(void)
{
#if McuGDisplaySSD1306_CONFIG_USE_DOUBLE_BUFFER
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLEAR_BUFFER(McuGDisplaySSD1306_COLOR_PIXEL_CLR);
#else
  McuGDisplaySSD1306_DrawFilledBox(0, 0, McuGDisplaySSD1306_GetWidth(), McuGDisplaySSD1306_GetHeight(), McuGDisplaySSD1306_COLOR_PIXEL_CLR);
#endif
}

/*
** ===================================================================
**     Method      :  SetPixel (component GDisplay)
**
**     Description :
**         Sets a pixel in the display buffer
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - Pixel x position
**         y               - Pixel y position
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_SetPixel(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y)
{
  if (x>=McuGDisplaySSD1306_GetWidth() || y>=McuGDisplaySSD1306_GetHeight()) { /* values out of range */
    return;
  }
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
#endif
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_CONFIG_FCT_NAME_OPENWINDOW(x, y, x, y); /* set up a one pixel window */
  McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(McuGDisplaySSD1306_COLOR_BLACK); /* store pixel with color information */
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLOSEWINDOW(); /* close and execute window */
#else
  McuGDisplaySSD1306_CONFIG_FCT_NAME_PUTPIXEL(x, y, McuGDisplaySSD1306_COLOR_PIXEL_SET);
#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
#endif
}

/*
** ===================================================================
**     Method      :  ClrPixel (component GDisplay)
**
**     Description :
**         Clears a single pixel in the display.
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - Pixel x position.
**         y               - Pixel y position.
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_ClrPixel(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y)
{
  if (x>=McuGDisplaySSD1306_GetWidth() || y>=McuGDisplaySSD1306_GetHeight()) { /* values out of range */
    return;
  }
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
#endif
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_CONFIG_FCT_NAME_OPENWINDOW(x, y, x, y); /* set up a one pixel window */
  McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(McuGDisplaySSD1306_COLOR_WHITE); /* store pixel with color information */
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLOSEWINDOW(); /* close and execute window */
#else
  McuGDisplaySSD1306_CONFIG_FCT_NAME_PUTPIXEL(x, y, McuGDisplaySSD1306_COLOR_PIXEL_CLR);
#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
#endif
}

/*
** ===================================================================
**     Method      :  UpdateFull (component GDisplay)
**
**     Description :
**         Updates the image on the display. This is needed in case the
**         display requires a periodic refresh. For display using
**         windowing, this function may be implemented as dummy stub,
**         as the display content already is written.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
/* method is implemented as macro in header file
void McuGDisplaySSD1306_UpdateFull(void)
{
}
*/

/*
** ===================================================================
**     Method      :  PutPixel (component GDisplay)
**
**     Description :
**         
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x coordinate
**         y               - y coordinate
**         color           - color to be used for the pixel
**     Returns     : Nothing
** ===================================================================
*/
#ifdef __HC08__
  #pragma MESSAGE DISABLE C4001 /* condition always FALSE */
#endif
void McuGDisplaySSD1306_PutPixel(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, McuGDisplaySSD1306_PixelColor color)
{
  if (x>=McuGDisplaySSD1306_GetWidth() || y>=McuGDisplaySSD1306_GetHeight()) { /* values out of range */
    return;
  }
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
#endif
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_CONFIG_FCT_NAME_OPENWINDOW(x, y, x, y); /* set up window as large as the box */
  McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(color); /* store pixel with color information */
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLOSEWINDOW(); /* close and execute window */
#else
  McuGDisplaySSD1306_CONFIG_FCT_NAME_PUTPIXEL(x, y, color);
#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
#endif
}
#ifdef __HC08__
  #pragma MESSAGE DEFAULT C4001 /* condition always FALSE */
#endif

/*
** ===================================================================
**     Method      :  DrawFilledBox (component GDisplay)
**
**     Description :
**         Draws a rectangle box (filled)
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x left upper coordinate
**         y               - y left upper coordinate
**         width           - Width in pixels
**         height          - Height in pixels
**         color           - color to be used to fill the box.
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawFilledBox(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, McuGDisplaySSD1306_PixelDim width, McuGDisplaySSD1306_PixelDim height, McuGDisplaySSD1306_PixelColor color)
{
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_PixelCount pixCnt;
  McuGDisplaySSD1306_PixelDim x1, y1;
#else
  McuGDisplaySSD1306_PixelDim x0, xe, y0, ye;
#endif
  McuGDisplaySSD1306_PixelDim d_width = McuGDisplaySSD1306_GetWidth();
  McuGDisplaySSD1306_PixelDim d_height = McuGDisplaySSD1306_GetHeight();

  if (   width==0 || height==0
      || x>=d_width || y>=d_height
     ) {
    return; /* nothing to do */
  }
  if (x+width>d_width) { /* value out of range */
    if (x>=d_width) {
      return;                          /* completely outside of display */
    } else {
      width = (McuGDisplaySSD1306_PixelDim)(d_width-x);
    }
  }
  if (y+height>d_height) { /* value out of range */
    if (y>=d_height) {
      return;                          /* completely outside of display */
    } else {
      height = (McuGDisplaySSD1306_PixelDim)(d_height-y);
    }
  }
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  x1 = (McuGDisplaySSD1306_PixelDim)(x+width-1); /* set window lower right x coordinate */
  y1 = (McuGDisplaySSD1306_PixelDim)(y+height-1); /* set window lower right y coordinate */
  pixCnt = (McuGDisplaySSD1306_PixelCount)((x1-x+1)*(y1-y+1)); /* number of pixels to write */
  #if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
  #endif
  McuGDisplaySSD1306_CONFIG_FCT_NAME_OPENWINDOW(x, y, x1, y1); /* set up window as large as the box */
  while (pixCnt>0) {
    McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(color); /* store pixel with color information */
    pixCnt--;
  } /* while */
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLOSEWINDOW(); /* close and execute window */
  #if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
  #endif
#else
  y0 = y; ye = (McuGDisplaySSD1306_PixelDim)(y0+height-1);
  #if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
  #endif
  for(;;) { /* breaks */
    x0 = x; xe = (McuGDisplaySSD1306_PixelDim)(x0+width-1);
    for(;;) { /* process line, breaks */
      McuGDisplaySSD1306_PutPixel(x0, y0, color);
      if (x0==xe) {
        break; /* reached end of line */
      }
      x0++;
    } /* for */
    if (y0==ye) {
      break; /* reached end */
    }
    y0++;
  } /* for */
  #if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
  #endif
#endif
}

/*
** ===================================================================
**     Method      :  DrawBox (component GDisplay)
**
**     Description :
**         Draws a rectangle line box
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x left upper coordinate
**         y               - y left upper coordinate
**         width           - width in pixels
**         height          - height in pixels
**         lineWidth       - width of the line
**         color           - color for the box
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawBox(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, McuGDisplaySSD1306_PixelDim width, McuGDisplaySSD1306_PixelDim height, McuGDisplaySSD1306_PixelDim lineWidth, McuGDisplaySSD1306_PixelColor color)
{
  /* top line: */
  McuGDisplaySSD1306_DrawFilledBox(x, y, width, lineWidth, color);
  /* left line: */
  McuGDisplaySSD1306_DrawFilledBox(x, (McuGDisplaySSD1306_PixelDim)(y+lineWidth), lineWidth, (McuGDisplaySSD1306_PixelDim)(height-(2*lineWidth)), color);
  /* right line: */
  McuGDisplaySSD1306_DrawFilledBox((McuGDisplaySSD1306_PixelDim)(x+width-lineWidth), (McuGDisplaySSD1306_PixelDim)(y+lineWidth), lineWidth, (McuGDisplaySSD1306_PixelDim)(height-(2*lineWidth)), color);
  /* bottom line: */
  McuGDisplaySSD1306_DrawFilledBox(x, (McuGDisplaySSD1306_PixelDim)(y+height-lineWidth), width, lineWidth, color);
}

/*
** ===================================================================
**     Method      :  DrawMonoBitmap (component GDisplay)
**
**     Description :
**         Draws a B/W bitmap.
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x position of left upper corner
**         y               - y position of left upper corner
**         image           - Pointer to image structure and
**                           information.
**         pixelColor      - Color to be used for pixels
**                           (pixel set)
**         backgroundColor - Color to be used
**                           for background (pixel not set)
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawMonoBitmap(int16_t x, int16_t y, PIMAGE image, McuGDisplaySSD1306_PixelColor pixelColor, McuGDisplaySSD1306_PixelColor backgroundColor)
{
  int x0, y0, xe, ye;
  McuGDisplaySSD1306_PixelColor pixel;
  uint8_t i;
  const uint8_t *data;

  data = image->pixmap;
  y0 = y;
  ye = (y+image->height-1);
  xe = (x+image->width-1);
  for(;;) {
    i=7;
    x0 = x;
    for(;;) {
      pixel = (McuGDisplaySSD1306_PixelColor)(((*data)&(1<<i))>>i); /* extract pixel out of bitstream */
      if (x0>=0 && y0>=0) { /* do not write pixel if outside of display */
        McuGDisplaySSD1306_PutPixel(x0, y0, (McuGDisplaySSD1306_PixelColor)(pixel==1?pixelColor:backgroundColor));
      }
      if (i==0 && x0!=xe) { /* next byte inside the row */
        data++;
        i = 7;
      } else {
        i--;
      }
      if (x0==xe) { /* reached end of line, next row */
        data++; /* next data byte */
        break;
      }
      x0++;
    } /* for */
    if (y0==ye) break; /* reached end */
    y0++;
  } /* for */
}

/*
** ===================================================================
**     Method      :  DrawMonoBitmapMask (component GDisplay)
**
**     Description :
**         Draws a B/W bitmap, but only the pixels which are set
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x position of left upper corner
**         y               - y position of left upper corner
**         image           - Pointer to image structure and
**                           information.
**         pixelColor      - Color to be used for pixels
**                           (pixel set)
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawMonoBitmapMask(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, PIMAGE image, McuGDisplaySSD1306_PixelColor pixelColor)
{
  McuGDisplaySSD1306_PixelDim x0, y0, xe, ye;
  McuGDisplaySSD1306_PixelColor pixel;
  uint8_t i;
  const uint8_t *data;

  data = image->pixmap;
  y0 = y;
  ye = (McuGDisplaySSD1306_PixelDim)(y+image->height-1);
  xe = (McuGDisplaySSD1306_PixelDim)(x+image->width-1);
  for(;;) {
    i=7;
    x0 = x;
    for(;;) {
      pixel = (McuGDisplaySSD1306_PixelColor)(((*data)&(1<<i))>>i); /* extract pixel out of bitstream */
      if (pixel) { /* only draw if pixel is set, everything else is transparent */
        McuGDisplaySSD1306_PutPixel(x0, y0, pixelColor);
      }
      if (i==0 && x0!=xe) { /* next byte inside the row */
        data++;
        i = 7;
      } else {
        i--;
      }
      if (x0==xe) { /* reached end of line, next row */
        data++; /* next data byte */
        break;
      }
      x0++;
    } /* for */
    if (y0==ye) break; /* reached end */
    y0++;
  } /* for */
}

/*
** ===================================================================
**     Method      :  DrawColorBitmap (component GDisplay)
**
**     Description :
**         Draws a color bitmap. Pixel data is in 3-3-2 RGB format.
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x position of left upper corner
**         y               - y position of left upper corner
**         image           - Pointer to image structure and
**                           information.
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawColorBitmap(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, PIMAGE image)
{
  McuGDisplaySSD1306_PixelDim x0, y0, xe, ye;
  McuGDisplaySSD1306_PixelColor pixel;
  const uint8_t *data;

  data = image->pixmap;
  y0 = y;
  ye = (McuGDisplaySSD1306_PixelDim)(y+image->height-1);
  xe = (McuGDisplaySSD1306_PixelDim)(x+image->width-1);
  for(;;) {
    x0 = x;
    for(;;) {
      pixel = (McuGDisplaySSD1306_PixelColor)c332to565[*data]; /* extract pixel out of bitstream and convert it to our color mode*/
      McuGDisplaySSD1306_PutPixel(x0, y0, pixel);
      data++;
      if (x0==xe) { /* reached end of line, next row */
        break;
      }
      x0++;
    } /* for */
    if (y0==ye) break; /* reached end */
    y0++;
  } /* for */
}

/*
** ===================================================================
**     Method      :  DrawHLine (component GDisplay)
**
**     Description :
**         Draws a horizontal line
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x left upper coordinate
**         y               - y left upper coordinate
**         length          - Length of line in pixels
**         color           - color to be used to fill the box.
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawHLine(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, McuGDisplaySSD1306_PixelDim length, McuGDisplaySSD1306_PixelColor color)
{
  McuGDisplaySSD1306_DrawFilledBox(x, y, length, 1, color);
}

/*
** ===================================================================
**     Method      :  DrawVLine (component GDisplay)
**
**     Description :
**         Draws a vertical line
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x left upper coordinate
**         y               - y left upper coordinate
**         length          - Length of line in pixels
**         color           - color to be used to fill the box.
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawVLine(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, McuGDisplaySSD1306_PixelDim length, McuGDisplaySSD1306_PixelColor color)
{
  McuGDisplaySSD1306_DrawFilledBox(x, y, 1, length, color);
}

/*
** ===================================================================
**     Method      :  DrawBarChart (component GDisplay)
**
**     Description :
**         Draws a series of bars for a chart
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - upper left corner x coordinate
**         y               - upper left corner y coordinate
**         width           - Chart box width
**         height          - Chart box height
**       * data            - Pointer to data (series of % values
**                           from 0...100%)
**         nofData         - number of data bytes
**         barColor        - Color to be used for the bars.
**         borderWidth     - width of a border to be
**                           draw. Pass zero if there shall be no border.
**         borderColor     - Color to be used for the
**                           border (if borderWidth is not zero)
**         borderSpace     - Space to be used in pixels
**                           between border and bars.
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawBarChart(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, McuGDisplaySSD1306_PixelDim width, McuGDisplaySSD1306_PixelDim height, uint8_t *data, uint8_t nofData, McuGDisplaySSD1306_PixelColor barColor, uint8_t borderWidth, McuGDisplaySSD1306_PixelColor borderColor, uint8_t borderSpace)
{
  uint8_t i;
  McuGDisplaySSD1306_PixelDim barHeight; /* for calculation of each bar height */
  McuGDisplaySSD1306_PixelDim barWidth; /* bar width, based on even distribution of the bars */

  if (borderWidth > 0) { /* border */
    McuGDisplaySSD1306_DrawBox(x, y, width, height, borderWidth, borderColor);
  }
  /* reduce drawing area because of border */
  x += borderWidth+borderSpace;
  y += borderWidth+borderSpace;
  width -= 2*(borderWidth+borderSpace);
  height -= 2*(borderWidth+borderSpace);

  /* calculat bar width based on number of bars so we fill out our drawing area */
  barWidth = (McuGDisplaySSD1306_PixelDim)((width-(nofData+1)*borderSpace)/nofData);

  /* draw some bars */
  for(i=0; i<nofData; i++) {
    barHeight = (McuGDisplaySSD1306_PixelDim)((height*data[i])/100); /* scale with % value */
    if (barHeight > 0) {
      McuGDisplaySSD1306_DrawFilledBox(x, (McuGDisplaySSD1306_PixelDim)(y+height-barHeight), barWidth, barHeight, barColor);
    }
    x += barWidth+borderSpace;
  }
}

/*
** ===================================================================
**     Method      :  DrawLine (component GDisplay)
**
**     Description :
**         Draws a line using the Bresenham method
**     Parameters  :
**         NAME            - DESCRIPTION
**         xstart          - x start coordinate
**         ystart          - y start coordinate
**         xend            - x end coordinate
**         yend            - y end coordinate
**         color           - color to be used for the line
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawLine(McuGDisplaySSD1306_PixelDim xstart, McuGDisplaySSD1306_PixelDim ystart, McuGDisplaySSD1306_PixelDim xend, McuGDisplaySSD1306_PixelDim yend, McuGDisplaySSD1306_PixelColor color)
{
  /* Based on Bresenham algorithm and http://de.wikipedia.org/wiki/Bresenham-Algorithmus */
  #define sgn(x) ((x) > 0) ? 1 : ((x) < 0) ? -1 : 0
  McuGDisplaySSD1306_PixelDim x, y;
  int t, dx, dy, incx, incy, pdx, pdy, ddx, ddy, es, el, err;

  /* Calculate distance in both dimensions */
  dx = xend - xstart;
  dy = yend - ystart;
  /* Determin sign of increment */
  incx = sgn(dx);
  incy = sgn(dy);
  if(dx<0) dx = -dx;
  if(dy<0) dy = -dy;
  /* Check which distance is larger */
  if (dx>dy) { /* we are faster in x direction */
    pdx=incx; pdy=0;    /* pd. is parallel step */
    ddx=incx; ddy=incy; /* dd. is diagonal step */
    es =dy;   el =dx;   /* error steps fast (es) and slow (el) */
  } else { /* faster in y direction */
    pdx=0;    pdy=incy; /* pd. is parallel step */
    ddx=incx; ddy=incy; /* dd. is diagonal step */
    es =dx;   el =dy;   /* error step fast (es) and slow (el) */
  }
  /* Do some initialization first... */
  x = xstart; y = ystart; err = el/2;
  McuGDisplaySSD1306_PutPixel(x, y, color); /* put first pixel */
  /* calculate pixels */
  for(t=0; t<el; ++t) { /* t counts the pixels, el is the number of pixels */
    err -= es; /* adapt error */
    if(err<0) { /* make error positive again */
      err += el;
      /* step into the slow direction, diagonal step  */
      x += ddx;
      y += ddy;
    } else {
      /* step into the fast direction, parallel step*/
      x += pdx;
      y += pdy;
    }
    McuGDisplaySSD1306_PutPixel(x, y, color);
  }
}

/*
** ===================================================================
**     Method      :  DrawCircle (component GDisplay)
**
**     Description :
**         Draws a circle using the Bresenham method
**     Parameters  :
**         NAME            - DESCRIPTION
**         x0              - x start coordinate
**         y0              - y start coordinate
**         radius          - Radius of the circle
**         color           - color to be used for the line
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawCircle(McuGDisplaySSD1306_PixelDim x0, McuGDisplaySSD1306_PixelDim y0, McuGDisplaySSD1306_PixelDim radius, McuGDisplaySSD1306_PixelColor color)
{
  /* draw a circle using the Bresenham method, see http://de.wikipedia.org/wiki/Bresenham-Algorithmus */
  int f = 1 - radius;
  int ddF_x = 0;
  int ddF_y = -2 * radius;
  McuGDisplaySSD1306_PixelDim x = 0;
  McuGDisplaySSD1306_PixelDim y = radius;

  McuGDisplaySSD1306_PutPixel(x0, (McuGDisplaySSD1306_PixelDim)(y0 + radius), color);
  McuGDisplaySSD1306_PutPixel(x0, (McuGDisplaySSD1306_PixelDim)(y0 - radius), color);
  McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 + radius), y0, color);
  McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 - radius), y0, color);
  while(x < y) {
    if(f >= 0) {
      y--;
      ddF_y += 2;
      f += ddF_y;
    }
    x++;
    ddF_x += 2;
    f += ddF_x + 1;
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 + x), (McuGDisplaySSD1306_PixelDim)(y0 + y), color);
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 - x), (McuGDisplaySSD1306_PixelDim)(y0 + y), color);
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 + x), (McuGDisplaySSD1306_PixelDim)(y0 - y), color);
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 - x), (McuGDisplaySSD1306_PixelDim)(y0 - y), color);
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 + y), (McuGDisplaySSD1306_PixelDim)(y0 + x), color);
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 - y), (McuGDisplaySSD1306_PixelDim)(y0 + x), color);
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 + y), (McuGDisplaySSD1306_PixelDim)(y0 - x), color);
    McuGDisplaySSD1306_PutPixel((McuGDisplaySSD1306_PixelDim)(x0 - y), (McuGDisplaySSD1306_PixelDim)(y0 - x), color);
  }
}

/*
** ===================================================================
**     Method      :  DrawFilledCircle (component GDisplay)
**
**     Description :
**         Draws a circle using the Bresenham method
**     Parameters  :
**         NAME            - DESCRIPTION
**         x0              - x start coordinate
**         y0              - y start coordinate
**         radius          - Radius of the circle
**         color           - fill color to be used
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_DrawFilledCircle(McuGDisplaySSD1306_PixelDim x0, McuGDisplaySSD1306_PixelDim y0, McuGDisplaySSD1306_PixelDim radius, McuGDisplaySSD1306_PixelColor color)
{
  /* draw a circle using the Bresenham method, see http://de.wikipedia.org/wiki/Bresenham-Algorithmus and
  http://forums.tigsource.com/index.php?topic=17068.0;wap2 */
  McuGDisplaySSD1306_PixelDim xoff=0;
  McuGDisplaySSD1306_PixelDim yoff=radius;
  int balance=-((int)radius);
  McuGDisplaySSD1306_PixelDim p0, p1, w0, w1;

  while (xoff <= yoff) {
    p0 = (McuGDisplaySSD1306_PixelDim)(x0-xoff);
    p1 = (McuGDisplaySSD1306_PixelDim)(x0-yoff);
    w0 = (McuGDisplaySSD1306_PixelDim)(2*xoff);
    w1 = (McuGDisplaySSD1306_PixelDim)(2*yoff);
    McuGDisplaySSD1306_DrawHLine(p0, (McuGDisplaySSD1306_PixelDim)(y0+yoff), w0, color);
    McuGDisplaySSD1306_DrawHLine(p0, (McuGDisplaySSD1306_PixelDim)(y0-yoff), w0, color);
    McuGDisplaySSD1306_DrawHLine(p1, (McuGDisplaySSD1306_PixelDim)(y0+xoff), w1, color);
    McuGDisplaySSD1306_DrawHLine(p1, (McuGDisplaySSD1306_PixelDim)(y0-xoff), w1, color);
    balance += 2*xoff;
    xoff++;
    if (balance>=0) {
      yoff--;
      balance -= 2*yoff;
    }
  } /* while */
}

/*
** ===================================================================
**     Method      :  Draw65kBitmap (component GDisplay)
**
**     Description :
**         Draws a 65k color bitmap (compressed or uncompressed)
**     Parameters  :
**         NAME            - DESCRIPTION
**         x1              - left upper starting corner
**         y1              - left upper starting corner
**         x2              - right lower corner
**         y2              - right lower corner
**       * bmp             - Pointer to bitmap
**         compressed      - 
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_Draw65kBitmap(McuGDisplaySSD1306_PixelDim x1, McuGDisplaySSD1306_PixelDim y1, McuGDisplaySSD1306_PixelDim x2, McuGDisplaySSD1306_PixelDim y2, uint16_t *bmp, bool compressed)
{
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_PixelCount pixelCount = (McuGDisplaySSD1306_PixelCount)((x2-x1+1) * (y2-y1+1));

#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
#endif
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_CONFIG_FCT_NAME_OPENWINDOW(x1, y1, x2, y2); /* set up window as large as the box */
  if (compressed) {
    McuGDisplaySSD1306_PixelColor PixelColor = 0;
    uint16_t Pos = 0;
    bool FirstRead = TRUE;
    uint16_t i;
    uint16_t Repeat;

    for (i=0; i<pixelCount; i++) {
      if (FirstRead) {                  /* read first pixel after first start or after finishing a compressed bunch of data */
        PixelColor = (McuGDisplaySSD1306_PixelColor)bmp[Pos++];
        McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(PixelColor); /* paint pixel */
        FirstRead = FALSE;
      } else {
        uint16_t LastPixel = PixelColor; /* save data of last pixel (word format) to temporary variable */

        PixelColor = (McuGDisplaySSD1306_PixelColor)bmp[Pos++]; /* read next pixel */
        McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(PixelColor); /* paint new pixel */
        if (LastPixel == PixelColor) {  /* check if the last two read pixels are identical */
          Repeat = bmp[Pos++];          /* if yes: read number following pixels of this color */
          i += Repeat;                  /* increment pixel counter */
          while (Repeat--) {            /* output requested number of pixels */
            McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(PixelColor);
          }
          FirstRead = TRUE;             /* restart potential repetition sequence */
        }
      }
    }
  } else {
    uint16_t i;
    McuGDisplaySSD1306_PixelColor pixelColor;

    for(i=0; i<pixelCount; i++) {
      pixelColor = (McuGDisplaySSD1306_PixelColor)bmp[i];
      McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(pixelColor);
    }
  }
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLOSEWINDOW(); /* close and execute window */
#else
  /* NYI */
  (void)x1; (void)y1; (void)x2; (void)y2; (void)bmp; (void)compressed; /* avoid compiler warning */
#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
#endif
}

/*
** ===================================================================
**     Method      :  Draw256BitmapHigh (component GDisplay)
**
**     Description :
**         Draws a 256 color bitmap (compressed or uncompressed) with a
**         color table.
**     Parameters  :
**         NAME            - DESCRIPTION
**         x1              - left upper starting corner
**         y1              - left upper starting corner
**         x2              - right lower corner
**         y2              - right lower corner
**       * bmp             - Pointer to bitmap
**       * ColorTable      - Pointer to array of colors
**                           (color table)
**         compressed      - 
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_Draw256BitmapHigh(McuGDisplaySSD1306_PixelDim x1, McuGDisplaySSD1306_PixelDim y1, McuGDisplaySSD1306_PixelDim x2, McuGDisplaySSD1306_PixelDim y2, uint8_t *bmp, McuGDisplaySSD1306_PixelColor *ColorTable, bool compressed)
{
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_PixelCount pixelCount = (McuGDisplaySSD1306_PixelCount)((x2-x1+1) * (y2-y1+1));

#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
#endif
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_CONFIG_FCT_NAME_OPENWINDOW(x1, y1, x2, y2); /* set up window as large as the box */
  if (compressed) {
    uint8_t PixelColorIndex = 0;
    uint16_t Pos = 0;
    bool FirstRead = TRUE;
    uint16_t i;
    uint8_t LastPixelIndex;
    uint8_t Repeat;

    for (i=0; i<pixelCount; i++) {
      if (FirstRead) {                  /* read first pixel after first start or after finishing a compressed bunch of data */
        PixelColorIndex = bmp[Pos++];
        McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(ColorTable[PixelColorIndex]);
        FirstRead = FALSE;
      } else {
        LastPixelIndex = PixelColorIndex; /* save data of last pixel (word format) to temporary variable */
        PixelColorIndex = bmp[Pos++];   /* read next pixel */
        McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(ColorTable[PixelColorIndex]);
        if (LastPixelIndex == PixelColorIndex) { /* check if the last two read pixels are identical */
          Repeat = bmp[Pos++];          /* if yes: read number following pixels of this color */
          i += Repeat;                  /* increment pixel counter */
          while (Repeat--) {            /* output requested number of pixels */
            McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(ColorTable[PixelColorIndex]);
          }
          FirstRead = TRUE;             /* restart potential repetition sequence */
        }
      }
    }
  } else {
    McuGDisplaySSD1306_PixelCount i;
    uint8_t PixelColorIndex;
    uint16_t PixelColor;

    for(i=0; i<pixelCount; i++) {
      PixelColorIndex = bmp[i];
      PixelColor = ColorTable[PixelColorIndex];
      McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(PixelColor);
    }
  }
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLOSEWINDOW(); /* close and execute window */
#else
  /* NYI */
  (void)x1; (void)y1; (void)x2; (void)y2; (void)bmp;  (void)ColorTable; (void)compressed; /* avoid compiler warning */
#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
#endif
}

/*
** ===================================================================
**     Method      :  Draw256BitmapLow (component GDisplay)
**
**     Description :
**         Draws a 256 color bitmap (compressed or uncompressed)
**     Parameters  :
**         NAME            - DESCRIPTION
**         x1              - left upper starting corner
**         y1              - left upper starting corner
**         x2              - right lower corner
**         y2              - right lower corner
**       * bmp             - Pointer to bitmap
**         compressed      - 
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_Draw256BitmapLow(McuGDisplaySSD1306_PixelDim x1, McuGDisplaySSD1306_PixelDim y1, McuGDisplaySSD1306_PixelDim x2, McuGDisplaySSD1306_PixelDim y2, uint8_t *bmp, bool compressed)
{
/* For uncompressed bitmap data:
      The pixels are provided in an array of 8bit pixel information (bmp[]).
      Each byte describes a pixel in 3-3-2 RBG format
   For compressed bitmap data:
      If two bytes are the same, this means that the 3rd byte contains how many times the color has to be repeated.
      Example: 10 red dots are compressed as:
        RED RED 8
 */

#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_PixelCount pixelCount = (McuGDisplaySSD1306_PixelCount)((x2-x1+1) * (y2-y1+1));

#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
#endif
#if McuGDisplaySSD1306_CONFIG_USE_WINDOW_CAPABILITY
  McuGDisplaySSD1306_CONFIG_FCT_NAME_OPENWINDOW(x1, y1, x2, y2); /* set up window as large as the box */
  if (compressed) {
    /* compressed pixel information */
    uint8_t pixelColor = 0;
    uint8_t lastPixel;
    McuGDisplaySSD1306_PixelCount pos = 0;
    bool first = TRUE;                  /* if we read the first time, or if we may have a new sequence */
    uint8_t repeat;

    while(pixelCount!=0) {              /* while there are pixels to write... */
      if (first) {                      /* first pixel, or first after a compressed sequence */
        pixelColor = *bmp;              /* read pixel */
        bmp++;                          /* advance pointer to next pixel */
        McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(c332to565[pixelColor]); /* write pixel */
        pixelCount--;                   /* one more done */
        first = FALSE;                  /* reset flag */
      } else {
        lastPixel = pixelColor;         /* remember already written pixel to detect potential compressed sequence */
        pixelColor = *bmp;              /* read pixel */
        bmp++;                          /* advance pointer to next pixel */
        McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(c332to565[pixelColor]); /* write pixel */
        pixelCount--;                   /* one more done */
        if (lastPixel == pixelColor) {  /* do we have twice the same pixel? Then it this starts a compressed sequence... */
          repeat = *bmp;                /* yes! read the number of pixels to repeat */
          bmp++;                        /* next byte in stream */
          pixelCount -= repeat;         /* a bunch more will be done */
          while (repeat--) {            /* write requested amount of pixels */
            McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(c332to565[pixelColor]); /* write pixel */
          } /* while */
          first = TRUE;                 /* set flag for new sequence */
        }
      }
    }
  } else {
    /* uncompressed pixel information */
    while(pixelCount != 0) {            /* while there are pixels to write... */
      McuGDisplaySSD1306_CONFIG_FCT_NAME_WRITEPIXEL(c332to565[*bmp]); /* write pixel */
      bmp++;                            /* next byte */
      pixelCount--;                     /* one more done */
    } /* for */
  }
  McuGDisplaySSD1306_CONFIG_FCT_NAME_CLOSEWINDOW(); /* close and execute window */
#else
  /* NYI */
  (void)x1; (void)y1; (void)x2; (void)y2; (void)bmp; (void)compressed; /* avoid compiler warning */
#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
#endif
}

/*
** ===================================================================
**     Method      :  UpdateRegion (component GDisplay)
**
**     Description :
**         Update a region of the display.
**     Parameters  :
**         NAME            - DESCRIPTION
**         x               - x coordinate
**         y               - y coordinate
**         w               - Width of the update region
**         h               - height of the update region
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_UpdateRegion(McuGDisplaySSD1306_PixelDim x, McuGDisplaySSD1306_PixelDim y, McuGDisplaySSD1306_PixelDim w, McuGDisplaySSD1306_PixelDim h)
{
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GetDisplay();
#endif
  McuSSD1306_UpdateRegion(x,y,w,h);
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_GiveDisplay();
#endif
}

/*
** ===================================================================
**     Method      :  GetDisplayOrientation (component GDisplay)
**
**     Description :
**         Returns the current display orientation
**     Parameters  : None
**     Returns     :
**         ---             - current display orientation
** ===================================================================
*/
/*
McuGDisplaySSD1306_DisplayOrientation McuGDisplaySSD1306_GetDisplayOrientation(void)
  ** This method is implemented as macro
*/

/*
** ===================================================================
**     Method      :  SetDisplayOrientation (component GDisplay)
**
**     Description :
**         Sets the display orientation. If you enable this method,
**         then the orientation of the display can be changed at
**         runtime. However, this requires additional resources.
**     Parameters  :
**         NAME            - DESCRIPTION
**         newOrientation  - new orientation to
**                           be used
**     Returns     : Nothing
** ===================================================================
*/
/*
void McuGDisplaySSD1306_SetDisplayOrientation(McuGDisplaySSD1306_DisplayOrientation newOrientation)
  ** This method is implemented as macro
*/

/*
** ===================================================================
**     Method      :  GetWidth (component GDisplay)
**
**     Description :
**         Returns the width of the display in pixels (in x direction)
**     Parameters  : None
**     Returns     :
**         ---             - pixel count
** ===================================================================
*/
/*
McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetWidth(void)
  ** This method is implemented as macro
*/

/*
** ===================================================================
**     Method      :  GetHeight (component GDisplay)
**
**     Description :
**         Returns the height of the display in pixels (in y direction)
**     Parameters  : None
**     Returns     :
**         ---             - pixel count
** ===================================================================
*/
/*
McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetHeight(void)
  ** This method is implemented as macro
*/

/*
** ===================================================================
**     Method      :  GetLongerSide (component GDisplay)
**
**     Description :
**         Returns the size of the longer side of the display
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
/*
McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetLongerSide(void)
  ** This method is implemented as macro
*/

/*
** ===================================================================
**     Method      :  GetShorterSide (component GDisplay)
**
**     Description :
**         Returns the size of the shorter side of the display
**     Parameters  : None
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
/*
McuGDisplaySSD1306_PixelDim McuGDisplaySSD1306_GetShorterSide(void)
  ** This method is implemented as macro
*/

/*
** ===================================================================
**     Method      :  GetDisplay (component GDisplay)
**
**     Description :
**         Method used to reserve the display (for mutual exclusive
**         access)
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_GetDisplay(void)
{
#if McuGDisplaySSD1306_CONFIG_USE_MUTEX
  xSemaphoreTakeRecursive(McuGDisplaySSD1306_displayMutex, portMAX_DELAY);
#endif
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING_OnGet();
#endif
  McuSSD1306_GetLCD();
}

/*
** ===================================================================
**     Method      :  GiveDisplay (component GDisplay)
**
**     Description :
**         Returns the display after having it reserved with
**         GetDisplay()
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_GiveDisplay(void)
{
  McuSSD1306_GiveLCD();
#if McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING
  McuGDisplaySSD1306_CONFIG_USE_DISPLAY_SHARING_OnGive();
#endif
#if McuGDisplaySSD1306_CONFIG_USE_MUTEX
  xSemaphoreGiveRecursive(McuGDisplaySSD1306_displayMutex);
#endif
}

/*
** ===================================================================
**     Method      :  Init (component GDisplay)
**
**     Description :
**         Driver initialization
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_Init(void)
{
#if McuGDisplaySSD1306_CONFIG_CLEAR_DISPLAY_IN_INIT
  McuGDisplaySSD1306_Clear(); /* clear display memory */
  McuGDisplaySSD1306_UpdateFull(); /* update display */
#endif
#if McuGDisplaySSD1306_CONFIG_USE_MUTEX
  McuGDisplaySSD1306_displayMutex = xSemaphoreCreateRecursiveMutex();
#endif
}

/*
** ===================================================================
**     Method      :  Deinit (component GDisplay)
**
**     Description :
**         Driver de-initialization
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuGDisplaySSD1306_Deinit(void)
{
#if McuGDisplaySSD1306_CONFIG_USE_MUTEX
  vSemaphoreDelete(McuGDisplaySSD1306_displayMutex);
  McuGDisplaySSD1306_displayMutex = NULL;
#endif
}

/* END McuGDisplaySSD1306. */

/*!
** @}
*/
