From 6ab3c1cdbcaae4c1fd0369ec4ea1a349a5a944c8 Mon Sep 17 00:00:00 2001
From: Mateusz Zalega <mateusz@appliedsourcery.com>
Date: Sun, 28 Jul 2019 20:20:59 +0200
Subject: [PATCH] LCD: implemented double buffering and asynchronous updates

Signed-off-by: Mateusz Zalega <mateusz@appliedsourcery.com>
---
 lib/gfx/GUI_DEV/DEV_Config.c |  5 +++--
 lib/gfx/GUI_DEV/DEV_Config.h |  6 +++--
 lib/gfx/LCD/LCD_Driver.c     | 43 +++++++++++++++++++++++++++++-------
 lib/gfx/LCD/LCD_Driver.h     |  8 ++++---
 4 files changed, 47 insertions(+), 15 deletions(-)

diff --git a/lib/gfx/GUI_DEV/DEV_Config.c b/lib/gfx/GUI_DEV/DEV_Config.c
index 881b9eeb..5c1e4b22 100644
--- a/lib/gfx/GUI_DEV/DEV_Config.c
+++ b/lib/gfx/GUI_DEV/DEV_Config.c
@@ -39,10 +39,11 @@
 static spi_req_t req = {.rx_data = NULL, .bits=8, .width = SPI17Y_WIDTH_1, .ssel = 0, .deass = 1, .ssel_pol = SPI17Y_POL_LOW, .tx_num = 0, .rx_num = 0};
 
 /********************************************************************************/
-void lcd_write(uint8_t *data, int size)
+void lcd_write(uint8_t *data, int size, lcd_write_cb_t wr_callback)
 {
     req.tx_data = data;
     req.len = size;
-    SPI_MasterTrans(SPI, &req);
+    req.callback = wr_callback;
+    SPI_MasterTransAsync(SPI, &req);
 }
 
diff --git a/lib/gfx/GUI_DEV/DEV_Config.h b/lib/gfx/GUI_DEV/DEV_Config.h
index 64487005..5e4ed5f7 100644
--- a/lib/gfx/GUI_DEV/DEV_Config.h
+++ b/lib/gfx/GUI_DEV/DEV_Config.h
@@ -43,6 +43,8 @@
 #define UWORD   uint16_t
 #define UDOUBLE uint32_t
 
+typedef spi_callback_fn lcd_write_cb_t;
+
 /**
  * GPIO config
 **/
@@ -57,9 +59,9 @@ extern const gpio_cfg_t DEV_DC_PIN;
 /**
  * SPI
 **/
-void lcd_write(uint8_t* data, int size);
+void lcd_write(uint8_t* data, int size, lcd_write_cb_t wr_callback);
 void display_set_reset_pin(uint8_t state);
-#define DEV_SPI_WRITE(_dat) lcd_write(&_dat, 1)
+#define DEV_SPI_WRITE(_dat) lcd_write(&_dat, 1, NULL)
 #define DEV_RESET_LOW() display_set_reset_pin(0)
 #define DEV_RESET_HIGH() display_set_reset_pin(1)
 /**
diff --git a/lib/gfx/LCD/LCD_Driver.c b/lib/gfx/LCD/LCD_Driver.c
index 7cc1d15f..a75582d3 100644
--- a/lib/gfx/LCD/LCD_Driver.c
+++ b/lib/gfx/LCD/LCD_Driver.c
@@ -28,7 +28,27 @@
 #
 ******************************************************************************/
 #include "LCD_Driver.h"
-static uint8_t screen[LCD_HEIGHT][LCD_WIDTH][2];
+
+typedef union {
+    uint8_t fb[LCD_HEIGHT][LCD_WIDTH][2];
+    uint8_t raw[LCD_HEIGHT * LCD_WIDTH * 2];
+} frame_t;
+
+static frame_t frames[2];
+static uint8_t active_frame;
+static uint8_t update_in_progress;
+
+#define FRAME_SIZE sizeof(frames[0])
+
+static inline frame_t *frame(void)
+{
+   return &frames[active_frame];
+}
+
+static void update_cb(void *spi_req, int error_code)
+{
+    update_in_progress = 0;
+}
 
 /*******************************************************************************
 function:
@@ -197,7 +217,7 @@ parameter	:
 	  Xend  :		End UWORD coordinates
 	  Yend  :		End UWORD coordinatesen
 ******************************************************************************/
-void LCD_SetCursor(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)
+static void LCD_SetCursor(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend)
 {
 	Xstart = Xstart + 1;
 	Xend   = Xend + 1;
@@ -289,8 +309,8 @@ void LCD_SetUWORD(UWORD x, UWORD y, UWORD Color)
 
 void LCD_SetUWORD(UWORD x, UWORD y, UWORD Color)
 {
-	screen[y][x][0] = (Color >> 8);
-	screen[y][x][1] = (Color & 0xFF);
+	frame()->fb[y][x][0] = (Color >> 8);
+	frame()->fb[y][x][1] = (Color & 0xFF);
 }
 
 void LCD_Clear(UWORD Color)
@@ -303,14 +323,21 @@ void LCD_Clear(UWORD Color)
 	}
 }
 
-void LCD_Set(uint8_t *data, int len)
+static void LCD_Set(uint8_t *data, int len)
 {
 	LCD_SetCursor(0, 0, 160 - 1, 80 - 1);
 	DEV_Digital_Write(DEV_DC_PIN, 1);
-	lcd_write(data, len);
+    update_in_progress = 1;
+    lcd_write(data, len, update_cb);
 }
 
-void LCD_Update(void)
+int LCD_Update(void)
 {
-	LCD_Set((uint8_t *)screen, sizeof(screen));
+    if (update_in_progress)
+        return 1;
+
+    LCD_Set(frame()->raw, FRAME_SIZE);
+    active_frame = !active_frame;
+    return 0;
 }
+
diff --git a/lib/gfx/LCD/LCD_Driver.h b/lib/gfx/LCD/LCD_Driver.h
index 54980b0c..6e4f3ed9 100644
--- a/lib/gfx/LCD/LCD_Driver.h
+++ b/lib/gfx/LCD/LCD_Driver.h
@@ -40,7 +40,6 @@ void LCD_WriteData_Byte(UBYTE da);
 void LCD_WriteData_Word(UWORD da);
 void LCD_WriteReg(UBYTE da);
 
-void LCD_SetCursor(UWORD x1, UWORD y1, UWORD x2,UWORD y2);
 void LCD_SetUWORD(UWORD x, UWORD y, UWORD Color);
 
 void LCD_Init(void);
@@ -48,7 +47,10 @@ void LCD_SetBacklight(UWORD Value);
 void LCD_Clear(UWORD Color);
 void LCD_ClearWindow(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD UWORD);
 
-void LCD_Set(uint8_t *data, int len);
-void LCD_Update(void);
+/*
+ *  return value: 0 - asynchronous update was scheduled
+ *                1 - an update was already in progress
+ */
+int LCD_Update(void);
 
 #endif
-- 
GitLab