text: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *  http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  //  Display Driver for PineTime
  /**
   * @file lv_port_disp_templ.c
   *
   */
  
  /*********************
   *      INCLUDES
   *********************/
  #include <console/console.h>
  #include "lv_port_disp.h"
  
  /*********************
   *      DEFINES
   *********************/
  
  /**********************
   *      TYPEDEFS
   **********************/
  
  /**********************
   *  STATIC PROTOTYPES
   **********************/
  static void disp_init(void);
  
  static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p);
  #if LV_USE_GPU
  static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa);
  static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
          const lv_area_t * fill_area, lv_color_t color);
  #endif
  
  /**********************
   *  STATIC VARIABLES
   **********************/
  
  /**********************
   *      MACROS
   **********************/
  
  /**********************
   *   GLOBAL FUNCTIONS
   **********************/
  
  void lv_port_disp_init(void)
  {
      /*-------------------------
       * Initialize your display
       * -----------------------*/
      disp_init();
  
      /*-----------------------------
       * Create a buffer for drawing
       *----------------------------*/
  
      /* LVGL requires a buffer where it draws the objects. The buffer's has to be greater than 1 display row
       *
       * There are three buffering configurations:
       * 1. Create ONE buffer with some rows: 
       *      LVGL will draw the display's content here and writes it to your display
       * 
       * 2. Create TWO buffer with some rows: 
       *      LVGL will draw the display's content to a buffer and writes it your display.
       *      You should use DMA to write the buffer's content to the display.
       *      It will enable LVGL to draw the next part of the screen to the other buffer while
       *      the data is being sent form the first buffer. It makes rendering and flushing parallel.
       * 
       * 3. Create TWO screen-sized buffer: 
       *      Similar to 2) but the buffer have to be screen sized. When LVGL is ready it will give the
       *      whole frame to display. This way you only need to change the frame buffer's address instead of
       *      copying the pixels.
       * */
  
      /* Example for 1) */
      static lv_disp_buf_t disp_buf_1;
      static lv_color_t buf1_1[LV_HOR_RES_MAX * 10];                      /*A buffer for 10 rows*/
      lv_disp_buf_init(&disp_buf_1, buf1_1, NULL, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/
  
      /* Example for 2) */
      // static lv_disp_buf_t disp_buf_2;
      // static lv_color_t buf2_1[LV_HOR_RES_MAX * 10];                        /*A buffer for 10 rows*/
      // static lv_color_t buf2_2[LV_HOR_RES_MAX * 10];                        /*An other buffer for 10 rows*/
      // lv_disp_buf_init(&disp_buf_2, buf2_1, buf2_2, LV_HOR_RES_MAX * 10);   /*Initialize the display buffer*/
  
      /* Example for 3) */
      // static lv_disp_buf_t disp_buf_3;
      // static lv_color_t buf3_1[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*A screen sized buffer*/
      // static lv_color_t buf3_2[LV_HOR_RES_MAX * LV_VER_RES_MAX];            /*An other screen sized buffer*/
      // lv_disp_buf_init(&disp_buf_3, buf3_1, buf3_2, LV_HOR_RES_MAX * LV_VER_RES_MAX);   /*Initialize the display buffer*/
  
  
      /*-----------------------------------
       * Register the display in LVGL
       *----------------------------------*/
  
      lv_disp_drv_t disp_drv;                         /*Descriptor of a display driver*/
      lv_disp_drv_init(&disp_drv);                    /*Basic initialization*/
  
      /*Set up the functions to access to your display*/
  
      /*Set the resolution of the display*/
      disp_drv.hor_res = LV_HOR_RES_MAX;
      disp_drv.ver_res = LV_VER_RES_MAX;
  
      /*Used to copy the buffer's content to the display*/
      disp_drv.flush_cb = disp_flush;
  
      /*Set a display buffer*/
      disp_drv.buffer = &disp_buf_1;
  
  #if LV_USE_GPU
      /*Optionally add functions to access the GPU. (Only in buffered mode, LV_VDB_SIZE != 0)*/
  
      /*Blend two color array using opacity*/
      disp_drv.gpu_blend_cb = gpu_blend;
  
      /*Fill a memory array with a color*/
      disp_drv.gpu_fill_cb = gpu_fill;
  #endif
  
      /*Finally register the driver*/
      lv_disp_drv_register(&disp_drv);
  }
  
  /**********************
   *   STATIC FUNCTIONS
   **********************/
  
  /* Initialize your display and the required peripherals. */
  static void disp_init(void)
  {
      //  puts("Init display...");
      /*You code here*/
  }
  
  //  ST7789 Commands. From https://github.com/lupyuen/st7735-lcd-batch-rs/blob/master/src/instruction.rs
  //  TODO: Move to display.c
  #define RAMWR 0x2C
  
  /* Flush the content of the internal buffer the specific area on the display
   * You can use DMA or any hardware acceleration to do this operation in the background but
   * 'lv_disp_flush_ready()' has to be called when finished. */
  static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
  {
      console_printf("Flush display: left=%d, top=%d, right=%d, bottom=%d...\n", area->x1, area->y1, area->x2, area->y2);
      assert(area->x2 >= area->x1);
      assert(area->y2 >= area->y1);
  
      //  Set the ST7789 display window
      int rc = pinetime_lvgl_mynewt_set_window(area->x1, area->y1, area->x2, area->y2); assert(rc == 0);
  
      //  Write Pixels (RAMWR): st7735_lcd::draw() → set_pixel()
      //  TODO: Move to display.c
      int len = 
          ((area->x2 - area->x1) + 1) *  //  Width
          ((area->y2 - area->y1) + 1) *  //  Height
          2;                             //  2 bytes per pixel
      rc = pinetime_lvgl_mynewt_write_command(RAMWR, NULL, 0); assert(rc == 0);
      rc = pinetime_lvgl_mynewt_write_data((const uint8_t *) color_p, len); assert(rc == 0);
  
      /* IMPORTANT!!!
       * Inform the graphics library that you are ready with the flushing*/
      lv_disp_flush_ready(disp_drv);
  }
  
  //  OPTIONAL: GPU INTERFACE
  #ifdef NOTUSED  //  No GPU
  #if LV_USE_GPU
  
  /* If your MCU has hardware accelerator (GPU) then you can use it to blend to memories using opacity
   * It can be used only in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
  static void gpu_blend(lv_disp_drv_t * disp_drv, lv_color_t * dest, const lv_color_t * src, uint32_t length, lv_opa_t opa)
  {
      /*It's an example code which should be done by your GPU*/
      uint32_t i;
      for(i = 0; i < length; i++) {
          dest[i] = lv_color_mix(dest[i], src[i], opa);
      }
  }
  
  /* If your MCU has hardware accelerator (GPU) then you can use it to fill a memory with a color
   * It can be used only in buffered mode (LV_VDB_SIZE != 0 in lv_conf.h)*/
  static void gpu_fill(lv_disp_drv_t * disp_drv, lv_color_t * dest_buf, lv_coord_t dest_width,
                      const lv_area_t * fill_area, lv_color_t color)
  {
      /*It's an example code which should be done by your GPU*/
      int32_t x, y;
      dest_buf += dest_width * fill_area->y1; /*Go to the first line*/
  
      for(y = fill_area->y1; y <= fill_area->y2; y++) {
          for(x = fill_area->x1; x <= fill_area->x2; x++) {
              dest_buf[x] = color;
          }
          dest_buf+=dest_width;    /*Go to the next line*/
      }
  }
  
  #endif  //  LV_USE_GPU
  #endif  //  NOTUSED
  