Преглед на файлове

Merge remote-tracking branch 'origin/master' into httpd

Conflicts:
	components/wifi-manager/http_server.c
Sebastien преди 5 години
родител
ревизия
75af26c55e
променени са 53 файла, в които са добавени 2292 реда и са изтрити 1699 реда
  1. 5 0
      README.md
  2. 1 1
      build-scripts/ESP32-A1S-sdkconfig.defaults
  3. 1 1
      build-scripts/I2S-4MFlash-sdkconfig.defaults
  4. 1 1
      build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults
  5. 1 1
      build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults
  6. 1 1
      build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults
  7. 1 1
      build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults
  8. 145 0
      components/display/SH1106.c
  9. 146 0
      components/display/SSD1306.c
  10. 2 2
      components/display/component.mk
  11. 92 0
      components/display/core/gds.c
  12. 30 0
      components/display/core/gds.h
  13. 20 0
      components/display/core/gds_default_if.h
  14. 292 0
      components/display/core/gds_draw.c
  15. 26 0
      components/display/core/gds_draw.h
  16. 6 6
      components/display/core/gds_err.h
  17. 38 71
      components/display/core/gds_font.c
  18. 91 0
      components/display/core/gds_font.h
  19. 146 0
      components/display/core/gds_private.h
  20. 195 0
      components/display/core/gds_text.c
  21. 45 0
      components/display/core/gds_text.h
  22. 32 46
      components/display/core/ifaces/default_if_i2c.c
  23. 109 0
      components/display/core/ifaces/default_if_spi.c
  24. 72 31
      components/display/display.c
  25. 3 34
      components/display/display.h
  26. 0 446
      components/display/driver_SSD13x6.c
  27. 0 0
      components/display/fonts/LICENSE-apache
  28. 0 0
      components/display/fonts/LICENSE-liberation-mono
  29. 2 2
      components/display/fonts/font_droid_sans_fallback_11x13.c
  30. 2 2
      components/display/fonts/font_droid_sans_fallback_15x17.c
  31. 2 2
      components/display/fonts/font_droid_sans_fallback_24x28.c
  32. 2 2
      components/display/fonts/font_droid_sans_mono_13x24.c
  33. 2 2
      components/display/fonts/font_droid_sans_mono_16x31.c
  34. 2 2
      components/display/fonts/font_droid_sans_mono_7x13.c
  35. 2 2
      components/display/fonts/font_liberation_mono_13x21.c
  36. 2 2
      components/display/fonts/font_liberation_mono_17x30.c
  37. 2 2
      components/display/fonts/font_liberation_mono_9x15.c
  38. 2 2
      components/display/fonts/font_line_1.c
  39. 2 2
      components/display/fonts/font_line_2.c
  40. 2 2
      components/display/fonts/font_tarable7seg_16x32.c
  41. 2 2
      components/display/fonts/font_tarable7seg_32x64.c
  42. 0 123
      components/display/tarablessd13x6/ifaces/default_if_spi.c
  43. 0 351
      components/display/tarablessd13x6/ssd13x6.c
  44. 0 99
      components/display/tarablessd13x6/ssd13x6.h
  45. 0 18
      components/display/tarablessd13x6/ssd13x6_default_if.h
  46. 0 253
      components/display/tarablessd13x6/ssd13x6_draw.c
  47. 0 54
      components/display/tarablessd13x6/ssd13x6_draw.h
  48. 0 91
      components/display/tarablessd13x6/ssd13x6_font.h
  49. 11 6
      components/raop/raop.c
  50. 51 0
      components/services/monitor.c
  51. 35 35
      components/squeezelite/display.c
  52. 654 0
      components/wifi-manager/http_server.c
  53. 14 1
      sdkconfig.defaults

+ 5 - 0
README.md

@@ -238,6 +238,11 @@ python ${IDF_PATH}/components/esptool_py/esptool/esptool.py --chip esp32 --port
 make monitor
 
 ```
+
+You can also manually download the recovery & initial boot
+```
+python ${IDF_PATH}/components/esptool_py/esptool/esptool.py --chip esp32 --port ${ESPPORT} --baud ${ESPBAUD} --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xd000 ./build/ota_data_initial.bin 0x1000 ./build/bootloader/bootloader.bin 0x10000 ./build/recovery.bin 0x8000 ./build/partitions.bin
+```
  
 # Configuration
 1/ setup WiFi

+ 1 - 1
build-scripts/ESP32-A1S-sdkconfig.defaults

@@ -613,7 +613,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 
 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 

+ 1 - 1
build-scripts/I2S-4MFlash-sdkconfig.defaults

@@ -613,7 +613,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 
 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 

+ 1 - 1
build-scripts/NonOTA-I2S-4MFlash-sdkconfig.defaults

@@ -614,7 +614,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 
 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 

+ 1 - 1
build-scripts/NonOTA-SqueezeAmp-sdkconfig.defaults

@@ -613,7 +613,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 
 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 

+ 1 - 1
build-scripts/SqueezeAmp4MBFlash-sdkconfig.defaults

@@ -613,7 +613,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 
 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 

+ 1 - 1
build-scripts/SqueezeAmp8MBFlash-sdkconfig.defaults

@@ -607,7 +607,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 
 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 

+ 145 - 0
components/display/SH1106.c

@@ -0,0 +1,145 @@
+/**
+ * Copyright (c) 2017-2018 Tara Keeling
+ *				 2020 Philippe G. 
+ * 
+ * This software is released under the MIT License.
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <esp_heap_caps.h>
+#include <esp_log.h>
+
+#include "gds.h"
+#include "gds_private.h"
+
+#define SHADOW_BUFFER
+
+static char TAG[] = "SH1106";
+
+// Functions are not declared to minimize # of lines
+
+static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
+	// well, unfortunately this driver is 132 colums but most displays are 128...
+	if (Device->Width != 132) Start += 2;
+	Device->WriteCommand( Device, 0x10 | (Start >> 4) );
+	Device->WriteCommand( Device, 0x00 | (Start & 0x0f) );
+}
+
+static void SetPageAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
+	Device->WriteCommand( Device, 0xB0 | Start );	
+}	
+
+static void Update( struct GDS_Device* Device ) {
+#ifdef SHADOW_BUFFER
+	// not sure the compiler does not have to redo all calculation in for loops, so local it is
+	int width = Device->Width, rows = Device->Height / 8;
+	uint8_t *optr = Device->Shadowbuffer, *iptr = Device->Framebuffer;
+	
+	// by row, find first and last columns that have been updated
+	for (int r = 0; r < rows; r++) {
+		uint8_t first = 0, last;	
+		for (int c = 0; c < width; c++) {
+			if (*iptr != *optr) {
+				if (!first) first = c + 1;
+				last = c ;
+			}	
+			*optr++ = *iptr++;
+		}
+		
+		// now update the display by "byte rows"
+		if (first--) {
+			SetColumnAddress( Device, first, last );
+			SetPageAddress( Device, r, r);
+			Device->WriteData( Device, Device->Shadowbuffer + r*width + first, last - first + 1);
+		}
+	}	
+#else	
+	// SH1106 requires a page-by-page update and has no end Page/Column
+	for (int i = 0; i < Device->Height / 8 ; i++) {
+		SH1106_SetPageAddress( Device, i, 0);
+		SH1106_SetColumnAddress( Device, 0, 0);			
+		SH1106_WriteData( Device, Device->Framebuffer + i*Device->Width, Device->Width );
+	}	
+#endif	
+}
+
+static void SetHFlip( struct GDS_Device* Device, bool On ) { Device->WriteCommand( Device, On ? 0xA1 : 0xA0 ); }
+static void SetVFlip( struct GDS_Device *Device, bool On ) { Device->WriteCommand( Device, On ? 0xC8 : 0xC0 ); }
+static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
+static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
+
+static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
+    Device->WriteCommand( Device, 0x81 );
+    Device->WriteCommand( Device, Contrast );
+}
+
+static bool Init( struct GDS_Device* Device ) {
+	Device->FramebufferSize = ( Device->Width * Device->Height ) / 8;	
+	Device->Framebuffer = calloc( 1, Device->FramebufferSize );
+    NullCheck( Device->Framebuffer, return false );
+	
+#ifdef SHADOW_BUFFER	
+	if (Device->IF == IF_I2C) Device->Shadowbuffer = malloc( Device->FramebufferSize );
+	else Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
+	NullCheck( Device->Shadowbuffer, return false );
+	memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize);
+#endif	
+		
+	// need to be off and disable display RAM
+	Device->DisplayOff( Device );
+    Device->WriteCommand( Device, 0xA5 );
+	
+	// charge pump regulator, do direct init
+	Device->WriteCommand( Device, 0xAD );
+	Device->WriteCommand( Device, 0x8B ); 
+			
+	// COM pins HW config (alternative:EN) - some display might need something difference
+	Device->WriteCommand( Device, 0xDA );
+	Device->WriteCommand( Device, 1 << 4);
+		
+	// MUX Ratio
+    Device->WriteCommand( Device, 0xA8 );
+    Device->WriteCommand( Device, Device->Height - 1);
+	// Display Offset
+    Device->WriteCommand( Device, 0xD3 );
+    Device->WriteCommand( Device, 0 );
+	// Display Start Line
+    Device->WriteCommand( Device, 0x40 + 0x00 );
+	Device->SetContrast( Device, 0x7F );
+	// set flip modes
+	Device->SetVFlip( Device, false );
+	Device->SetHFlip( Device, false );
+	// no Display Inversion
+    Device->WriteCommand( Device, 0xA6 );
+	// set Clocks
+    Device->WriteCommand( Device, 0xD5 );
+    Device->WriteCommand( Device, ( 0x08 << 4 ) | 0x00 );
+		
+	// gone with the wind
+	Device->WriteCommand( Device, 0xA4 );
+	Device->DisplayOn( Device );
+	Device->Update( Device );
+	
+	return true;
+}	
+
+static const struct GDS_Device SH1106 = {
+	.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
+	.SetVFlip = SetVFlip, .SetHFlip = SetHFlip,
+	.DrawPixelFast = GDS_DrawPixelFast,
+	.Update = Update, .Init = Init,
+};	
+
+struct GDS_Device* SH1106_Detect(char *Driver, struct GDS_Device* Device) {
+	if (!strcasestr(Driver, "SH1106")) return NULL;
+	
+	if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
+	*Device = SH1106;	
+	ESP_LOGI(TAG, "SH1106 driver");
+	
+	return Device;
+}

+ 146 - 0
components/display/SSD1306.c

@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2017-2018 Tara Keeling
+ *				 2020 Philippe G.
+ * 
+ * This software is released under the MIT License.
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <esp_heap_caps.h>
+#include <esp_log.h>
+
+#include "gds.h"
+#include "gds_private.h"
+
+#define SHADOW_BUFFER
+
+static char TAG[] = "SSD1306";
+
+// Functions are not deckared to minimize # of lines
+
+static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
+	Device->WriteCommand( Device, 0x21 );
+	Device->WriteCommand( Device, Start );
+	Device->WriteCommand( Device, End );
+}
+static void SetPageAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
+	Device->WriteCommand( Device, 0x22 );	
+	Device->WriteCommand( Device, Start );
+	Device->WriteCommand( Device, End );
+}
+
+static void Update( struct GDS_Device* Device ) {
+#ifdef SHADOW_BUFFER
+	// not sure the compiler does not have to redo all calculation in for loops, so local it is
+	int width = Device->Width, rows = Device->Height / 8;
+	uint8_t *optr = Device->Shadowbuffer, *iptr = Device->Framebuffer;
+	
+	// by row, find first and last columns that have been updated
+	for (int r = 0; r < rows; r++) {
+		uint8_t first = 0, last;	
+		for (int c = 0; c < width; c++) {
+			if (*iptr != *optr) {
+				if (!first) first = c + 1;
+				last = c ;
+			}	
+			*optr++ = *iptr++;
+		}
+		
+		// now update the display by "byte rows"
+		if (first--) {
+			SetColumnAddress( Device, first, last );
+			SetPageAddress( Device, r, r);
+			Device->WriteData( Device, Device->Shadowbuffer + r*width + first, last - first + 1);
+		}
+	}	
+#else	
+	// automatic counter and end Page/Column
+	SetColumnAddress( Device, 0, Device->Width - 1);
+	SetPageAddress( Device, 0, Device->Height / 8 - 1);
+	Device->WriteData( Device, Device->Framebuffer, Device->FramebufferSize );
+#endif	
+}
+
+static void SetHFlip( struct GDS_Device* Device, bool On ) { Device->WriteCommand( Device, On ? 0xA1 : 0xA0 ); }
+static void SetVFlip( struct GDS_Device *Device, bool On ) { Device->WriteCommand( Device, On ? 0xC8 : 0xC0 ); }
+static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
+static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
+
+static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
+    Device->WriteCommand( Device, 0x81 );
+    Device->WriteCommand( Device, Contrast );
+}
+
+static bool Init( struct GDS_Device* Device ) {
+	Device->FramebufferSize = ( Device->Width * Device->Height ) / 8;	
+	Device->Framebuffer = calloc( 1, Device->FramebufferSize );
+    NullCheck( Device->Framebuffer, return false );
+	
+#ifdef SHADOW_BUFFER	
+	if (Device->IF == IF_I2C) Device->Shadowbuffer = malloc( Device->FramebufferSize );
+	else Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
+	NullCheck( Device->Shadowbuffer, return false );
+	memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize);
+#endif	
+		
+	// need to be off and disable display RAM
+	Device->DisplayOff( Device );
+    Device->WriteCommand( Device, 0xA5 );
+	
+	// charge pump regulator, do direct init
+	Device->WriteCommand( Device, 0x8D );
+	Device->WriteCommand( Device, 0x14 ); 
+			
+	// COM pins HW config (alternative:EN if 64, DIS if 32, remap:DIS) - some display might need something difference
+	Device->WriteCommand( Device, 0xDA );
+	Device->WriteCommand( Device, ((Device->Height == 64 ? 1 : 0) << 4) | (0 < 5) );
+		
+	// MUX Ratio
+    Device->WriteCommand( Device, 0xA8 );
+    Device->WriteCommand( Device, Device->Height - 1);
+	// Display Offset
+    Device->WriteCommand( Device, 0xD3 );
+    Device->WriteCommand( Device, 0 );
+	// Display Start Line
+    Device->WriteCommand( Device, 0x40 + 0x00 );
+	Device->SetContrast( Device, 0x7F );
+	// set flip modes
+	Device->SetVFlip( Device, false );
+	Device->SetHFlip( Device, false );
+	// no Display Inversion
+    Device->WriteCommand( Device, 0xA6 );
+	// set Clocks
+    Device->WriteCommand( Device, 0xD5 );
+    Device->WriteCommand( Device, ( 0x08 << 4 ) | 0x00 );
+	// set Adressing Mode Horizontal
+	Device->WriteCommand( Device, 0x20 );
+	Device->WriteCommand( Device, 0 );
+	
+	// gone with the wind
+	Device->WriteCommand( Device, 0xA4 );
+	Device->DisplayOn( Device );
+	Device->Update( Device );
+	
+	return true;
+}	
+
+static const struct GDS_Device SSD1306 = {
+	.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
+	.SetVFlip = SetVFlip, .SetHFlip = SetHFlip,
+	.DrawPixelFast = GDS_DrawPixelFast,
+	.Update = Update, .Init = Init,
+};	
+
+struct GDS_Device* SSD1306_Detect(char *Driver, struct GDS_Device* Device) {
+	if (!strcasestr(Driver, "SSD1306")) return NULL;
+	
+	if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
+	*Device = SSD1306;	
+	ESP_LOGI(TAG, "SSD1306 driver");
+	
+	return Device;
+}

+ 2 - 2
components/display/component.mk

@@ -7,6 +7,6 @@
 # please read the SDK documents if you need to do this.
 #
 
-COMPONENT_SRCDIRS := . tarablessd13x6 tarablessd13x6/fonts tarablessd13x6/ifaces
+COMPONENT_SRCDIRS := . core core/ifaces fonts 
 COMPONENT_ADD_INCLUDEDIRS := .
-COMPONENT_ADD_INCLUDEDIRS += ./tarablessd13x6 
+COMPONENT_ADD_INCLUDEDIRS += ./core

+ 92 - 0
components/display/core/gds.c

@@ -0,0 +1,92 @@
+/**
+ * Copyright (c) 2017-2018 Tara Keeling
+ *				 2020 Philippe G. 
+ * 
+ * This software is released under the MIT License.
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "driver/gpio.h"
+#include "esp_log.h"
+
+#include "gds.h"
+#include "gds_private.h"
+
+static struct GDS_Device Display;
+
+static char TAG[] = "gds";
+
+struct GDS_Device*	GDS_AutoDetect( char *Driver, GDS_DetectFunc DetectFunc[] ) {
+	for (int i = 0; DetectFunc[i]; i++) {
+		if (DetectFunc[i](Driver, &Display)) {
+			ESP_LOGD(TAG, "Detected driver %p", &Display);
+			return &Display;
+		}	
+	}
+	
+	return NULL;
+}
+
+void GDS_ClearExt(struct GDS_Device* Device, bool full, ...) {
+	bool commit = true;
+	
+	if (full) {
+		GDS_Clear( Device, GDS_COLOR_BLACK ); 
+	} else {
+		va_list args;
+		va_start(args, full);
+		commit = va_arg(args, int);
+		int x1 = va_arg(args, int), y1 = va_arg(args, int), x2 = va_arg(args, int), y2 = va_arg(args, int);
+		if (x2 < 0) x2 = Device->Width - 1;
+		if (y2 < 0) y2 = Device->Height - 1;
+		GDS_ClearWindow( Device, x1, y1, x2, y2, GDS_COLOR_BLACK );
+		va_end(args);
+	}
+	
+	Device->Dirty = true;
+	if (commit)	GDS_Update(Device);		
+}	
+
+void GDS_Clear( struct GDS_Device* Device, int Color ) {
+    memset( Device->Framebuffer, Color, Device->FramebufferSize );
+}
+
+void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ) {
+	// cheap optimization on boundaries
+	if (x1 == 0 && x2 == Device->Width - 1 && y1 % 8 == 0 && (y2 + 1) % 8 == 0) {
+		memset( Device->Framebuffer + (y1 / 8) * Device->Width, 0, (y2 - y1 + 1) / 8 * Device->Width );
+	} else {
+		for (int y = y1; y <= y2; y++) {
+			for (int x = x1; x <= x2; x++) {
+				Device->DrawPixelFast( Device, x, y, Color);
+			}		
+		}	
+	}	
+}
+
+void GDS_Update( struct GDS_Device* Device ) {
+	if (Device->Dirty) Device->Update( Device );
+	Device->Dirty = false;
+}
+
+bool GDS_Reset( struct GDS_Device* Device ) {
+	if ( Device->RSTPin >= 0 ) {
+		gpio_set_level( Device->RSTPin, 0 );
+		vTaskDelay( pdMS_TO_TICKS( 100 ) );
+        gpio_set_level( Device->RSTPin, 1 );
+    }
+    return true;
+}
+
+void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast ) { Device->SetContrast( Device, Contrast); }
+void GDS_SetHFlip( struct GDS_Device* Device, bool On ) { Device->SetHFlip( Device, On ); }
+void GDS_SetVFlip( struct GDS_Device* Device, bool On ) { Device->SetVFlip( Device, On ); }
+int	GDS_GetWidth( struct GDS_Device* Device ) { return Device->Width; }
+int	GDS_GetHeight( struct GDS_Device* Device ) { return Device->Height; }
+void GDS_DisplayOn( struct GDS_Device* Device ) { Device->DisplayOn( Device ); }
+void GDS_DisplayOff( struct GDS_Device* Device ) { Device->DisplayOff( Device ); }

+ 30 - 0
components/display/core/gds.h

@@ -0,0 +1,30 @@
+#ifndef _GDS_H_
+#define _GDS_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define GDS_COLOR_BLACK 0
+#define GDS_COLOR_WHITE 1
+#define GDS_COLOR_XOR 2
+
+struct GDS_Device;
+struct GDS_FontDef;
+
+typedef struct GDS_Device* (*GDS_DetectFunc)(char *Driver, struct GDS_Device *Device);
+
+struct GDS_Device*	GDS_AutoDetect( char *Driver, GDS_DetectFunc[] );
+
+void 	GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast );
+void 	GDS_DisplayOn( struct GDS_Device* Device );
+void 	GDS_DisplayOff( struct GDS_Device* Device ); 
+void 	GDS_Update( struct GDS_Device* Device );
+void 	GDS_SetHFlip( struct GDS_Device* Device, bool On );
+void 	GDS_SetVFlip( struct GDS_Device* Device, bool On );
+int 	GDS_GetWidth( struct GDS_Device* Device );
+int 	GDS_GetHeight( struct GDS_Device* Device );
+void 	GDS_ClearExt( struct GDS_Device* Device, bool full, ...);
+void 	GDS_Clear( struct GDS_Device* Device, int Color );
+void 	GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color );
+
+#endif

+ 20 - 0
components/display/core/gds_default_if.h

@@ -0,0 +1,20 @@
+#ifndef _GDS_DEFAULT_IF_H_
+#define _GDS_DEFAULT_IF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GDS_Device;
+
+bool GDS_I2CInit( int PortNumber, int SDA, int SCL );
+bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int I2CAddress, int RSTPin );
+
+bool GDS_SPIInit( int SPI, int DC );
+bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 292 - 0
components/display/core/gds_draw.c

@@ -0,0 +1,292 @@
+/**
+ * Copyright (c) 2017-2018 Tara Keeling
+ *				 2020 Philippe G.
+ * 
+ * This software is released under the MIT License.
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <math.h>
+#include <esp_attr.h>
+
+#include "gds.h"
+#include "gds_private.h"
+#include "gds_draw.h"
+
+static const unsigned char BitReverseTable256[] = 
+{
+  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 
+  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 
+  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 
+  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 
+  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 
+  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 
+  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 
+  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 
+  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 
+  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+__attribute__( ( always_inline ) ) static inline void SwapInt( int* a, int* b ) {
+    int Temp = *b;
+
+    *b = *a;
+    *a = Temp;
+}
+
+inline void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ) {
+    uint32_t YBit = ( Y & 0x07 );
+    uint8_t* FBOffset = NULL;
+
+    /* 
+     * We only need to modify the Y coordinate since the pitch
+     * of the screen is the same as the width.
+     * Dividing Y by 8 gives us which row the pixel is in but not
+     * the bit position.
+     */
+    Y>>= 3;
+
+    FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
+
+    if ( Color == GDS_COLOR_XOR ) {
+        *FBOffset ^= BIT( YBit );
+    } else {
+        *FBOffset = ( Color == GDS_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
+    }
+}
+
+inline void IRAM_ATTR GDS_DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
+    uint32_t YBit = ( Y & 0x07 );
+    uint8_t* FBOffset = NULL;
+
+    /* 
+     * We only need to modify the Y coordinate since the pitch
+     * of the screen is the same as the width.
+     * Dividing Y by 8 gives us which row the pixel is in but not
+     * the bit position.
+     */
+    Y>>= 3;
+
+    FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
+
+    if ( Color == GDS_COLOR_XOR ) {
+        *FBOffset ^= BIT( YBit );
+    } else {
+        *FBOffset = ( Color == GDS_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
+    }
+}
+
+void IRAM_ATTR GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Color ) {
+    int XEnd = x + Width;
+
+	Device->Dirty = true;
+	
+	if (x < 0) x = 0;
+	if (XEnd >= Device->Width) XEnd = Device->Width - 1;
+	
+	if (y < 0) y = 0;
+	else if (y >= Device->Height) x = Device->Height - 1;
+
+    for ( ; x < XEnd; x++ ) {
+        if ( IsPixelVisible( Device, x, y ) == true ) {
+            Device->DrawPixelFast( Device, x, y, Color );
+        } else {
+            break;
+        }
+    }
+}
+
+void IRAM_ATTR GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color ) {
+    int YEnd = y + Height;
+
+	Device->Dirty = true;
+
+    for ( ; y < YEnd; y++ ) {
+        if ( IsPixelVisible( Device, x, y ) == true ) {
+            GDS_DrawPixel( Device, x, y, Color );
+        } else {
+            break;
+        }
+    }
+}
+
+static inline void IRAM_ATTR DrawWideLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
+    int dx = ( x1 - x0 );
+    int dy = ( y1 - y0 );
+    int Error = 0;
+    int Incr = 1;
+    int x = x0;
+    int y = y0;
+
+    if ( dy < 0 ) {
+        Incr = -1;
+        dy = -dy;
+    }
+
+    Error = ( dy * 2 ) - dx;
+
+    for ( ; x < x1; x++ ) {
+        if ( IsPixelVisible( Device, x, y ) == true ) {
+            Device->DrawPixelFast( Device, x, y, Color );
+        }
+
+        if ( Error > 0 ) {
+            Error-= ( dx * 2 );
+            y+= Incr;
+        }
+
+        Error+= ( dy * 2 );
+    }
+}
+
+static inline void IRAM_ATTR DrawTallLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
+    int dx = ( x1 - x0 );
+    int dy = ( y1 - y0 );
+    int Error = 0;
+    int Incr = 1;
+    int x = x0;
+    int y = y0;
+
+    if ( dx < 0 ) {
+        Incr = -1;
+        dx = -dx;
+    }
+
+    Error = ( dx * 2 ) - dy;
+
+    for ( ; y < y1; y++ ) {
+        if ( IsPixelVisible( Device, x, y ) == true ) {
+            Device->DrawPixelFast( Device, x, y, Color );
+        }
+
+        if ( Error > 0 ) {
+            Error-= ( dy * 2 );
+            x+= Incr;
+        }
+
+        Error+= ( dx * 2 );
+    }
+}
+
+void IRAM_ATTR GDS_DrawLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
+    if ( x0 == x1 ) {
+        GDS_DrawVLine( Device, x0, y0, ( y1 - y0 ), Color );
+    } else if ( y0 == y1 ) {
+        GDS_DrawHLine( Device, x0, y0, ( x1 - x0 ), Color );
+    } else {
+		Device->Dirty = true;
+        if ( abs( x1 - x0 ) > abs( y1 - y0 ) ) {
+            /* Wide ( run > rise ) */
+            if ( x0 > x1 ) {
+                SwapInt( &x0, &x1 );
+                SwapInt( &y0, &y1 );
+            }
+
+            DrawWideLine( Device, x0, y0, x1, y1, Color );
+        } else {
+            /* Tall ( rise > run ) */
+            if ( y0 > y1 ) {
+                SwapInt( &y0, &y1 );
+                SwapInt( &x0, &x1 );
+            }
+
+            DrawTallLine( Device, x0, y0, x1, y1, Color );
+        }
+    }
+}
+
+void IRAM_ATTR GDS_DrawBox( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color, bool Fill ) {
+    int Width = ( x2 - x1 );
+    int Height = ( y2 - y1 );
+
+	Device->Dirty = true;
+	
+    if ( Fill == false ) {
+        /* Top side */
+        GDS_DrawHLine( Device, x1, y1, Width, Color );
+
+        /* Bottom side */
+        GDS_DrawHLine( Device, x1, y1 + Height, Width, Color );
+
+        /* Left side */
+        GDS_DrawVLine( Device, x1, y1, Height, Color );
+
+        /* Right side */
+        GDS_DrawVLine( Device, x1 + Width, y1, Height, Color );
+    } else {
+        /* Fill the box by drawing horizontal lines */
+        for ( ; y1 <= y2; y1++ ) {
+            GDS_DrawHLine( Device, x1, y1, Width, Color );
+        }
+    }
+}
+
+
+/****************************************************************************************
+ * Process graphic display data from column-oriented data (MSbit first)
+ */
+void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int Height) {
+	if (!Height) Height = Device->Height;
+	if (!Width) Width = Device->Width;
+
+	// need to do row/col swap and bit-reverse
+	int Rows = Height / 8;
+	for (int r = 0; r < Rows; r++) {
+		uint8_t *optr = Device->Framebuffer + r*Device->Width, *iptr = Data + r;
+		for (int c = Width; --c >= 0;) {
+			*optr++ = BitReverseTable256[*iptr];;
+			iptr += Rows;
+		}	
+	}
+	
+	Device->Dirty = true;
+}
+
+/****************************************************************************************
+ * Process graphic display data MSBit first
+ * WARNING: this has not been tested yet
+ */
+ /*
+static void draw_raw(int x1, int y1, int x2, int y2, bool by_column, bool MSb, u8_t *data) {
+	// default end point to display size
+	if (x2 == -1) x2 = Display.Width - 1;
+	if (y2 == -1) y2 = Display.Height - 1;
+	
+	display->dirty = true;
+	
+	//	not a boundary draw
+	// same comment about bit depth
+	if (y1 % 8 || y2 % 8 || x1 % 8 | x2 % 8) {
+		ESP_LOGW(TAG, "can't write on non cols/rows boundaries for now");
+	} else {	
+		// set addressing mode to match data
+		if (by_column) {
+			// copy the window and do row/col exchange
+			for (int r = y1/8; r <=  y2/8; r++) {
+				uint8_t *optr = Display.Framebuffer + r*Display.Width + x1, *iptr = data + r;
+				for (int c = x1; c <= x2; c++) {
+					*optr++ = MSb ? BitReverseTable256[*iptr] : *iptr;
+					iptr += (y2-y1)/8 + 1;
+			}	
+			}	
+		} else {
+			// just copy the window inside the frame buffer
+			for (int r = y1/8; r <= y2/8; r++) {
+				uint8_t *optr = Display.Framebuffer + r*Display.Width + x1, *iptr = data + r*(x2-x1+1);
+				for (int c = x1; c <= x2; c++) *optr++ = *iptr++;
+			}	
+		}
+	}	
+}
+*/

+ 26 - 0
components/display/core/gds_draw.h

@@ -0,0 +1,26 @@
+#ifndef _GDS_DRAW_H_
+#define _GDS_DRAW_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "esp_attr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GDS_Device;
+
+void IRAM_ATTR GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Color );
+void IRAM_ATTR GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color );
+void IRAM_ATTR GDS_DrawLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color );
+void IRAM_ATTR GDS_DrawBox( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color, bool Fill );
+
+// draw a bitmap with source 1-bit depth organized in column and col0 = bit7 of byte 0
+void IRAM_ATTR GDS_DrawBitmapCBR( struct GDS_Device* Device, uint8_t *Data, int Width, int Height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 6 - 6
components/display/tarablessd13x6/ssd13x6_err.h → components/display/core/gds_err.h

@@ -1,15 +1,15 @@
-#ifndef _SSD13x6_ERR_H_
-#define _SSD13x6_ERR_H_
+#ifndef _GDS_ERR_H_
+#define _GDS_ERR_H_
 
 #include <esp_log.h>
 
-#define SSD13x6_DoAbort( )
+#define GDS_DoAbort( )
 
 #if ! defined NullCheck
     #define NullCheck( ptr, retexpr ) { \
         if ( ptr == NULL ) { \
             ESP_LOGE( __FUNCTION__, "%s == NULL", #ptr ); \
-            SSD13x6_DoAbort( ); \
+            GDS_DoAbort( ); \
             retexpr; \
         } \
     }
@@ -20,7 +20,7 @@
         esp_err_t __err_rc = ( expr ); \
         if ( __err_rc != ESP_OK ) { \
             ESP_LOGE( __FUNCTION__, "%s != ESP_OK, result: %d", #expr, __err_rc ); \
-            SSD13x6_DoAbort( ); \
+            GDS_DoAbort( ); \
             retexpr; \
         } \
     }
@@ -30,7 +30,7 @@
     #define CheckBounds( expr, retexpr ) { \
         if ( expr ) { \
             ESP_LOGE( __FUNCTION__, "Line %d: %s", __LINE__, #expr ); \
-            SSD13x6_DoAbort( ); \
+            GDS_DoAbort( ); \
             retexpr; \
         } \
     }

+ 38 - 71
components/display/tarablessd13x6/ssd13x6_font.c → components/display/core/gds_font.c

@@ -9,11 +9,13 @@
 #include <string.h>
 #include <stdint.h>
 #include <math.h>
-#include "ssd13x6.h"
-#include "ssd13x6_draw.h"
-#include "ssd13x6_font.h"
+#include "gds.h"
+#include "gds_draw.h"
+#include "gds_font.h"
+#include "gds_private.h"
+#include "gds_err.h"
 
-static int RoundUpFontHeight( const struct SSD13x6_FontDef* Font ) {
+static int RoundUpFontHeight( const struct GDS_FontDef* Font ) {
     int Height = Font->Height;
 
     if ( ( Height % 8 ) != 0 ) {
@@ -23,11 +25,11 @@ static int RoundUpFontHeight( const struct SSD13x6_FontDef* Font ) {
     return Height;
 }
 
-static const uint8_t* GetCharPtr( const struct SSD13x6_FontDef* Font, char Character ) {
+static const uint8_t* GetCharPtr( const struct GDS_FontDef* Font, char Character ) {
     return &Font->FontData[ ( Character - Font->StartChar ) * ( ( Font->Width * ( RoundUpFontHeight( Font ) / 8 ) ) + 1 ) ];
 }
 
-void SSD13x6_FontDrawChar( struct SSD13x6_Device* DisplayHandle, char Character, int x, int y, int Color ) {
+void GDS_FontDrawChar( struct GDS_Device* Device, char Character, int x, int y, int Color ) {
     const uint8_t* GlyphData = NULL;
     int GlyphColumnLen = 0;
     int CharStartX =  0;
@@ -42,18 +44,15 @@ void SSD13x6_FontDrawChar( struct SSD13x6_Device* DisplayHandle, char Character,
     int YBit = 0;
     int i = 0;
 
-    NullCheck( DisplayHandle, return );
-    NullCheck( DisplayHandle->Font, return );
-    
-    NullCheck( ( GlyphData = GetCharPtr( DisplayHandle->Font, Character ) ), return );
+    NullCheck( ( GlyphData = GetCharPtr( Device->Font, Character ) ), return );
 
-    if ( Character >= DisplayHandle->Font->StartChar && Character <= DisplayHandle->Font->EndChar ) {
+    if ( Character >= Device->Font->StartChar && Character <= Device->Font->EndChar ) {
         /* The first byte in the glyph data is the width of the character in pixels, skip over */
         GlyphData++;
-        GlyphColumnLen = RoundUpFontHeight( DisplayHandle->Font ) / 8;
+        GlyphColumnLen = RoundUpFontHeight( Device->Font ) / 8;
         
-        CharWidth = SSD13x6_FontGetCharWidth( DisplayHandle, Character );
-        CharHeight = SSD13x6_FontGetHeight( DisplayHandle );
+        CharWidth = GDS_FontGetCharWidth( Device, Character );
+        CharHeight = GDS_FontGetHeight( Device );
 
         CharStartX = x;
         CharStartY = y;
@@ -74,14 +73,15 @@ void SSD13x6_FontDrawChar( struct SSD13x6_Device* DisplayHandle, char Character,
         CharStartY+= OffsetY;
 
         /* Do not attempt to draw if this character is entirely offscreen */
-        if ( CharEndX < 0 || CharStartX >= DisplayHandle->Width || CharEndY < 0 || CharStartY >= DisplayHandle->Height ) {
+        if ( CharEndX < 0 || CharStartX >= Device->Width || CharEndY < 0 || CharStartY >= Device->Height ) {
             ClipDebug( x, y );
             return;
         }
 
         /* Do not attempt to draw past the end of the screen */
-        CharEndX = ( CharEndX >= DisplayHandle->Width ) ? DisplayHandle->Width - 1 : CharEndX;
-        CharEndY = ( CharEndY >= DisplayHandle->Height ) ? DisplayHandle->Height - 1 : CharEndY;
+        CharEndX = ( CharEndX >= Device->Width ) ? Device->Width - 1 : CharEndX;
+        CharEndY = ( CharEndY >= Device->Height ) ? Device->Height - 1 : CharEndY;
+		Device->Dirty = true;
 
         for ( x = CharStartX; x < CharEndX; x++ ) {
             for ( y = CharStartY, i = 0; y < CharEndY && i < CharHeight; y++, i++ ) {
@@ -89,7 +89,7 @@ void SSD13x6_FontDrawChar( struct SSD13x6_Device* DisplayHandle, char Character,
                 YBit = ( i + OffsetY ) & 0x07;
 
                 if ( GlyphData[ YByte ] & BIT( YBit ) ) {
-                    SSD13x6_DrawPixel( DisplayHandle, x, y, Color );
+                    GDS_DrawPixel( Device, x, y, Color );
                 }            
             }
 
@@ -98,10 +98,7 @@ void SSD13x6_FontDrawChar( struct SSD13x6_Device* DisplayHandle, char Character,
     }
 }
 
-bool SSD13x6_SetFont( struct SSD13x6_Device* Display, const struct SSD13x6_FontDef* Font ) {
-    NullCheck( Display, return false );
-    NullCheck( Font, return false );
-
+bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font ) {
     Display->FontForceProportional = false;
     Display->FontForceMonospace = false;
     Display->Font = Font;
@@ -109,41 +106,26 @@ bool SSD13x6_SetFont( struct SSD13x6_Device* Display, const struct SSD13x6_FontD
     return true;
 }
 
-void SSD13x6_FontForceProportional( struct SSD13x6_Device* Display, bool Force ) {
-    NullCheck( Display, return );
-    NullCheck( Display->Font, return );
-
+void GDS_FontForceProportional( struct GDS_Device* Display, bool Force ) {
     Display->FontForceProportional = Force;
 }
 
-void SSD13x6_FontForceMonospace( struct SSD13x6_Device* Display, bool Force ) {
-    NullCheck( Display, return );
-    NullCheck( Display->Font, return );
-
+void GDS_FontForceMonospace( struct GDS_Device* Display, bool Force ) {
     Display->FontForceMonospace = Force;
 }
 
-int SSD13x6_FontGetWidth( struct SSD13x6_Device* Display ) {
-    NullCheck( Display, return 0 );
-    NullCheck( Display->Font, return 0 );
-
+int GDS_FontGetWidth( struct GDS_Device* Display ) {
     return Display->Font->Width;
 }
 
-int SSD13x6_FontGetHeight( struct SSD13x6_Device* Display ) {
-    NullCheck( Display, return 0 );
-    NullCheck( Display->Font, return 0 );
-
+int GDS_FontGetHeight( struct GDS_Device* Display ) {
     return Display->Font->Height;
 }
 
-int SSD13x6_FontGetCharWidth( struct SSD13x6_Device* Display, char Character ) {
+int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character ) {
     const uint8_t* CharPtr = NULL;
     int Width = 0;
 
-    NullCheck( Display, return 0 );
-    NullCheck( Display->Font, return 0 );
-    
     if ( Character >= Display->Font->StartChar && Character <= Display->Font->EndChar ) {
         CharPtr = GetCharPtr( Display->Font, Character );
 
@@ -161,82 +143,67 @@ int SSD13x6_FontGetCharWidth( struct SSD13x6_Device* Display, char Character ) {
     return Width;
 }
 
-int SSD13x6_FontGetMaxCharsPerRow( struct SSD13x6_Device* Display ) {
-    NullCheck( Display, return 0 );
-    NullCheck( Display->Font, return 0 );
-
+int GDS_FontGetMaxCharsPerRow( struct GDS_Device* Display ) {
     return Display->Width / Display->Font->Width;
 }
 
-int SSD13x6_FontGetMaxCharsPerColumn( struct SSD13x6_Device* Display ) {
-    NullCheck( Display, return 0 );
-    NullCheck( Display->Font, return 0 );
-
+int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display ) {
     return Display->Height / Display->Font->Height;    
 }
 
-int SSD13x6_FontGetCharHeight( struct SSD13x6_Device* Display ) {
-    NullCheck( Display, return 0 );
-    NullCheck( Display->Font, return 0 );
-
+int GDS_FontGetCharHeight( struct GDS_Device* Display ) {
     return Display->Font->Height;
 }
 
-int SSD13x6_FontMeasureString( struct SSD13x6_Device* Display, const char* Text ) {
+int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text ) {
     int Width = 0;
     int Len = 0;
 
-    NullCheck( Display, return 0 );
-    NullCheck( Display->Font, return 0 );
     NullCheck( Text, return 0 );
 
     for ( Len = strlen( Text ); Len >= 0; Len--, Text++ ) {
         if ( *Text >= Display->Font->StartChar && *Text <= Display->Font->EndChar ) {
-            Width+= SSD13x6_FontGetCharWidth( Display, *Text );
+            Width+= GDS_FontGetCharWidth( Display, *Text );
         }
     }
 
     return Width;
 }
 
-void SSD13x6_FontDrawString( struct SSD13x6_Device* Display, int x, int y, const char* Text, int Color ) {
+void GDS_FontDrawString( struct GDS_Device* Display, int x, int y, const char* Text, int Color ) {
     int Len = 0;
     int i = 0;
 
-    NullCheck( Display, return );
-    NullCheck( Display->Font, return );
     NullCheck( Text, return );
 
     for ( Len = strlen( Text ), i = 0; i < Len; i++ ) {
-        SSD13x6_FontDrawChar( Display, *Text, x, y, Color );
+        GDS_FontDrawChar( Display, *Text, x, y, Color );
 
-        x+= SSD13x6_FontGetCharWidth( Display, *Text );
+        x+= GDS_FontGetCharWidth( Display, *Text );
         Text++;
     }
 }
 
-void SSD13x6_FontDrawAnchoredString( struct SSD13x6_Device* Display, TextAnchor Anchor, const char* Text, int Color ) {
+void GDS_FontDrawAnchoredString( struct GDS_Device* Display, TextAnchor Anchor, const char* Text, int Color ) {
     int x = 0;
     int y = 0;
 
-    NullCheck( Display, return );
     NullCheck( Text, return );
 
-    SSD13x6_FontGetAnchoredStringCoords( Display, &x, &y, Anchor, Text );
-    SSD13x6_FontDrawString( Display, x, y, Text, Color );
+    GDS_FontGetAnchoredStringCoords( Display, &x, &y, Anchor, Text );
+    GDS_FontDrawString( Display, x, y, Text, Color );
 }
 
-void SSD13x6_FontGetAnchoredStringCoords( struct SSD13x6_Device* Display, int* OutX, int* OutY, TextAnchor Anchor, const char* Text ) {
+void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int* OutY, TextAnchor Anchor, const char* Text ) {
     int StringWidth = 0;
     int StringHeight = 0;
 
-    NullCheck( Display, return );
     NullCheck( OutX, return );
     NullCheck( OutY, return );
     NullCheck( Text, return );
 
-    StringWidth = SSD13x6_FontMeasureString( Display, Text );
-    StringHeight = SSD13x6_FontGetCharHeight( Display );
+    StringWidth = GDS_FontMeasureString( Display, Text );
+    StringHeight = GDS_FontGetCharHeight( Display );
 
     switch ( Anchor ) {
         case TextAnchor_East: {

+ 91 - 0
components/display/core/gds_font.h

@@ -0,0 +1,91 @@
+#ifndef _GDS_FONT_H_
+#define _GDS_FONT_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct GDS_Device;
+
+/* 
+ * X-GLCD Font format:
+ *
+ * First byte of glyph is it's width in pixels.
+ * Each data byte represents 8 pixels going down from top to bottom.
+ * 
+ * Example glyph layout for a 16x16 font
+ * 'a': [Glyph width][Pixel column 0][Pixel column 1] where the number of pixel columns is the font height divided by 8
+ * 'b': [Glyph width][Pixel column 0][Pixel column 1]...
+ * 'c': And so on...
+ */
+ 
+struct GDS_FontDef {
+    const uint8_t* FontData;
+
+    int Width;
+    int Height;
+
+    int StartChar;
+    int EndChar;
+
+    bool Monospace;
+};
+
+typedef enum {
+    TextAnchor_East = 0,
+    TextAnchor_West,
+    TextAnchor_North,
+    TextAnchor_South,
+    TextAnchor_NorthEast,
+    TextAnchor_NorthWest,
+    TextAnchor_SouthEast,
+    TextAnchor_SouthWest,
+    TextAnchor_Center
+} TextAnchor;
+
+bool GDS_SetFont( struct GDS_Device* Display, const struct GDS_FontDef* Font );
+
+void GDS_FontForceProportional( struct GDS_Device* Display, bool Force );
+void GDS_FontForceMonospace( struct GDS_Device* Display, bool Force );
+
+int GDS_FontGetWidth( struct GDS_Device* Display );
+int GDS_FontGetHeight( struct GDS_Device* Display );
+
+int GDS_FontGetMaxCharsPerRow( struct GDS_Device* Display );
+int GDS_FontGetMaxCharsPerColumn( struct GDS_Device* Display );
+
+int GDS_FontGetCharWidth( struct GDS_Device* Display, char Character );
+int GDS_FontGetCharHeight( struct GDS_Device* Display );
+int GDS_FontMeasureString( struct GDS_Device* Display, const char* Text );\
+
+void GDS_FontDrawChar( struct GDS_Device* Display, char Character, int x, int y, int Color );
+void GDS_FontDrawString( struct GDS_Device* Display, int x, int y, const char* Text, int Color );
+void GDS_FontDrawAnchoredString( struct GDS_Device* Display, TextAnchor Anchor, const char* Text, int Color );
+void GDS_FontGetAnchoredStringCoords( struct GDS_Device* Display, int* OutX, int* OutY, TextAnchor Anchor, const char* Text );
+
+extern const struct GDS_FontDef Font_droid_sans_fallback_11x13;
+extern const struct GDS_FontDef Font_droid_sans_fallback_15x17;
+extern const struct GDS_FontDef Font_droid_sans_fallback_24x28;
+
+extern const struct GDS_FontDef Font_droid_sans_mono_7x13;
+extern const struct GDS_FontDef Font_droid_sans_mono_13x24;
+extern const struct GDS_FontDef Font_droid_sans_mono_16x31;
+
+extern const struct GDS_FontDef Font_liberation_mono_9x15;
+extern const struct GDS_FontDef Font_liberation_mono_13x21;
+extern const struct GDS_FontDef Font_liberation_mono_17x30;
+
+extern const struct GDS_FontDef Font_Tarable7Seg_16x32;
+extern const struct GDS_FontDef Font_Tarable7Seg_32x64;
+
+extern const struct GDS_FontDef Font_line_1;
+extern const struct GDS_FontDef Font_line_2;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 146 - 0
components/display/core/gds_private.h

@@ -0,0 +1,146 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "esp_attr.h"
+#include "gds.h"
+#include "gds_err.h"
+
+#define GDS_CLIPDEBUG_NONE 0
+#define GDS_CLIPDEBUG_WARNING 1
+#define GDS_CLIPDEBUG_ERROR 2
+
+#define SHADOW_BUFFER
+
+#if CONFIG_GDS_CLIPDEBUG == GDS_CLIPDEBUG_NONE
+    /*
+     * Clip silently with no console output.
+     */
+    #define ClipDebug( x, y )
+#elif CONFIG_GDS_CLIPDEBUG == GDS_CLIPDEBUG_WARNING
+    /*
+     * Log clipping to the console as a warning.
+     */
+    #define ClipDebug( x, y ) { \
+        ESP_LOGW( __FUNCTION__, "Line %d: Pixel at %d, %d CLIPPED", __LINE__, x, y ); \
+    }
+#elif CONFIG_GDS_CLIPDEBUG == GDS_CLIPDEBUG_ERROR
+    /*
+     * Log clipping as an error to the console.
+     * Also invokes an abort with stack trace.
+     */
+    #define ClipDebug( x, y ) { \
+        ESP_LOGE( __FUNCTION__, "Line %d: Pixel at %d, %d CLIPPED, ABORT", __LINE__, x, y ); \
+        abort( ); \
+    }
+#endif
+
+
+#define GDS_ALWAYS_INLINE __attribute__( ( always_inline ) )
+
+#define MAX_LINES	8
+
+#if ! defined BIT
+#define BIT( n ) ( 1 << n )
+#endif
+
+struct GDS_Device;
+struct GDS_FontDef;
+
+/*
+ * These can optionally return a succeed/fail but are as of yet unused in the driver.
+ */
+typedef bool ( *WriteCommandProc ) ( struct GDS_Device* Device, uint8_t Command );
+typedef bool ( *WriteDataProc ) ( struct GDS_Device* Device, const uint8_t* Data, size_t DataLength );
+
+struct spi_device_t;
+typedef struct spi_device_t* spi_device_handle_t;
+
+#define IF_SPI	0
+#define IF_I2C	1
+
+struct GDS_Device {
+	uint8_t IF;
+	union {
+		// I2C Specific
+		struct {
+			uint8_t Address;
+		};
+		// SPI specific
+		struct {
+			spi_device_handle_t SPIHandle;
+			int8_t RSTPin;
+			int8_t CSPin;
+		};
+	};	
+
+    // cooked text mode
+	struct {
+		int16_t Y, Space;
+		const struct GDS_FontDef* Font;
+	} Lines[MAX_LINES];
+	
+	uint16_t Width;
+    uint16_t Height;
+	uint8_t Depth;
+		
+	uint8_t* Framebuffer, *Shadowbuffer;
+    uint16_t FramebufferSize;
+	bool Dirty;
+
+	// default fonts when using direct draw	
+	const struct GDS_FontDef* Font;
+    bool FontForceProportional;
+    bool FontForceMonospace;
+
+	// various driver-specific method
+	bool (*Init)( struct GDS_Device* Device);
+	void (*SetContrast)( struct GDS_Device* Device, uint8_t Contrast );
+	void (*DisplayOn)( struct GDS_Device* Device );
+	void (*DisplayOff)( struct GDS_Device* Device );
+	void (*Update)( struct GDS_Device* Device );
+	void (*DrawPixelFast)( struct GDS_Device* Device, int X, int Y, int Color );
+	void (*SetHFlip)( struct GDS_Device* Device, bool On );
+	void (*SetVFlip)( struct GDS_Device* Device, bool On );
+	    
+	// interface-specific methods	
+    WriteCommandProc WriteCommand;
+    WriteDataProc WriteData;
+};
+
+bool GDS_Reset( struct GDS_Device* Device );
+
+void IRAM_ATTR 	GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color );
+void IRAM_ATTR 	GDS_DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color );
+
+inline bool IsPixelVisible( struct GDS_Device* Device, int x, int y )  {
+    bool Result = (
+        ( x >= 0 ) &&
+        ( x < Device->Width ) &&
+        ( y >= 0 ) &&
+        ( y < Device->Height )
+    ) ? true : false;
+
+#if CONFIG_GDS_CLIPDEBUG > 0
+    if ( Result == false ) {
+        ClipDebug( x, y );
+    }
+#endif
+
+    return Result;
+}
+
+inline void IRAM_ATTR GDS_DrawPixel( struct GDS_Device* Device, int x, int y, int Color ) {
+    if ( IsPixelVisible( Device, x, y ) == true ) {
+        Device->DrawPixelFast( Device, x, y, Color );
+    }
+}
+
+inline void IRAM_ATTR GDS_DrawPixel4( struct GDS_Device* Device, int x, int y, int Color ) {
+    if ( IsPixelVisible( Device, x, y ) == true ) {
+        Device->DrawPixelFast( Device, x, y, Color );
+    }
+}
+
+
+

+ 195 - 0
components/display/core/gds_text.c

@@ -0,0 +1,195 @@
+/* 
+ *  (c) 2004,2006 Richard Titmuss for SlimProtoLib 
+ *  (c) Philippe G. 2019, philippe_44@outlook.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <stdint.h>
+#include <arpa/inet.h>
+#include "esp_log.h"
+#include "gds.h"
+#include "gds_draw.h"
+#include "gds_text.h"
+#include "gds_private.h"
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+
+static char TAG[] = "gds";
+
+/****************************************************************************************
+ *  Set fonts for each line in text mode
+ */
+static const struct GDS_FontDef *GuessFont( struct GDS_Device *Device, int FontType) {
+	switch(FontType) {
+	case GDS_FONT_LINE_1:	
+		return &Font_line_1;
+	case GDS_FONT_LINE_2:	
+		return &Font_line_2;
+	case GDS_FONT_SMALL:	
+		return &Font_droid_sans_fallback_11x13;	
+	case GDS_FONT_MEDIUM:			
+	default:		
+		return &Font_droid_sans_fallback_15x17;	
+	case GDS_FONT_LARGE:	
+		return &Font_droid_sans_fallback_24x28;
+		break;		
+	case GDS_FONT_SEGMENT:			
+		if (Device->Height == 32) return &Font_Tarable7Seg_16x32;
+		else return &Font_Tarable7Seg_32x64;
+	}
+}
+
+
+/****************************************************************************************
+ *  Set fonts for each line in text mode
+ */
+bool GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space) {
+	const struct GDS_FontDef *Font = GuessFont( Device, FontType );
+	return GDS_TextSetFont( Device, N, Font, Space );
+}
+
+/****************************************************************************************
+ *  Set fonts for each line in text mode
+ */
+bool GDS_TextSetFont(struct GDS_Device* Device, int N, const struct GDS_FontDef *Font, int Space) {
+	if (--N >= MAX_LINES) return false;
+
+	Device->Lines[N].Font = Font;
+	
+	// re-calculate lines absolute position
+	Device->Lines[N].Space = Space;
+	Device->Lines[0].Y = Device->Lines[0].Space;
+	for (int i = 1; i <= N; i++) Device->Lines[i].Y = Device->Lines[i-1].Y + Device->Lines[i-1].Font->Height + Device->Lines[i].Space;
+		
+	ESP_LOGI(TAG, "Adding line %u at %d (height:%u)", N + 1, Device->Lines[N].Y, Device->Lines[N].Font->Height);
+	
+	if (Device->Lines[N].Y + Device->Lines[N].Font->Height > Device->Height) {
+		ESP_LOGW(TAG, "line does not fit display");
+		return false;
+	}
+	
+	return true;
+}
+
+/****************************************************************************************
+ * 
+ */
+bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Text) {
+	int Width, X = Pos;
+
+	// counting 1..n
+	N--;
+	
+	GDS_SetFont( Device, Device->Lines[N].Font );	
+	if (Attr & GDS_TEXT_MONOSPACE) GDS_FontForceMonospace( Device, true );
+	
+	Width = GDS_FontMeasureString( Device, Text );
+	
+	// adjusting position, erase only EoL for rigth-justified
+	if (Pos == GDS_TEXT_RIGHT) X = Device->Width - Width - 1;
+	else if (Pos == GDS_TEXT_CENTER) X = (Device->Width - Width) / 2;
+	
+	// erase if requested
+	if (Attr & GDS_TEXT_CLEAR) {
+		int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height);
+		for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++) 
+			for (int y = Y_min; y < Y_max; y++)
+				Device->DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );
+	}
+		
+	GDS_FontDrawString( Device, X, Device->Lines[N].Y, Text, GDS_COLOR_WHITE );
+	
+	ESP_LOGD(TAG, "displaying %s line %u (x:%d, attr:%u)", Text, N+1, X, Attr);
+	
+	// update whole display if requested
+	Device->Dirty = true;
+	if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );
+		
+	return Width + X < Device->Width;
+}
+
+/****************************************************************************************
+ * Try to align string for better scrolling visual. there is probably much better to do
+ */
+int GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max) {
+	char Space[] = "     ";
+	int Len = strlen(String), Extra = 0, Boundary;
+	
+	N--;
+	
+	// we might already fit
+	GDS_SetFont( Device, Device->Lines[N].Font );	
+	if (GDS_FontMeasureString( Device, String ) <= Device->Width) return 0;
+		
+	// add some space for better visual 
+	strncat(String, Space, Max-Len);
+	String[Max] = '\0';
+	Len = strlen(String);
+	
+	// mark the end of the extended string
+	Boundary = GDS_FontMeasureString( Device, String );
+			
+	// add a full display width	
+	while (Len < Max && GDS_FontMeasureString( Device, String ) - Boundary < Device->Width) {
+		String[Len++] = String[Extra++];
+		String[Len] = '\0';
+	}
+		
+	return Boundary;
+}
+
+/****************************************************************************************
+ * 
+ */
+void GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...) {
+	va_list args;
+
+	TextAnchor Anchor = TextAnchor_Center;	
+	
+	if (Attr & GDS_TEXT_CLEAR) GDS_Clear( Device, GDS_COLOR_BLACK );
+	
+	if (!Text) return;
+	
+	va_start(args, Text);
+	
+	switch(Where) {
+	case GDS_TEXT_TOP_LEFT: 
+	default:
+		Anchor = TextAnchor_NorthWest; 
+		break;
+	case GDS_TEXT_MIDDLE_LEFT:
+		Anchor = TextAnchor_West;
+		break;
+	case GDS_TEXT_BOTTOM_LEFT:
+		Anchor = TextAnchor_SouthWest;
+		break;
+	case GDS_TEXT_CENTERED:
+		Anchor = TextAnchor_Center;
+		break;
+	}	
+	
+	ESP_LOGD(TAG, "Displaying %s at %u with attribute %u", Text, Anchor, Attr);
+	
+	GDS_SetFont( Device, GuessFont( Device, FontType ) );	
+	GDS_FontDrawAnchoredString( Device, Anchor, Text, GDS_COLOR_WHITE );
+	
+	Device->Dirty = true;
+	if (Attr & GDS_TEXT_UPDATE) GDS_Update( Device );
+	
+	va_end(args);
+}

+ 45 - 0
components/display/core/gds_text.h

@@ -0,0 +1,45 @@
+/* 
+ *  (c) Philippe G. 2019, philippe_44@outlook.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include "gds_font.h"
+
+#define GDS_TEXT_CLEAR 		0x01
+#define	GDS_TEXT_CLEAR_EOL	0x02
+#define GDS_TEXT_UPDATE		0x04
+#define GDS_TEXT_MONOSPACE	0x08
+
+// these ones are for 'Pos' parameter of TextLine
+#define GDS_TEXT_LEFT 	0
+#define GDS_TEXT_RIGHT	0xff00
+#define	GDS_TEXT_CENTER 0xff01
+
+// these ones are for the 'Where' parameter of TextPos
+enum { GDS_TEXT_TOP_LEFT, GDS_TEXT_MIDDLE_LEFT, GDS_TEXT_BOTTOM_LEFT, GDS_TEXT_CENTERED };
+
+enum { GDS_FONT_DEFAULT, GDS_FONT_LINE_1, GDS_FONT_LINE_2, GDS_FONT_SEGMENT, 
+	   GDS_FONT_TINY, GDS_FONT_SMALL, GDS_FONT_MEDIUM, GDS_FONT_LARGE, GDS_FONT_FONT_HUGE };
+	   
+struct GDS_Device;
+	   
+bool 	GDS_TextSetFontAuto(struct GDS_Device* Device, int N, int FontType, int Space);
+bool 	GDS_TextSetFont(struct GDS_Device* Device, int N, const struct GDS_FontDef *Font, int Space);
+bool 	GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Text);
+int 	GDS_TextStretch(struct GDS_Device* Device, int N, char *String, int Max);
+void 	GDS_TextPos(struct GDS_Device* Device, int FontType, int Where, int Attr, char *Text, ...);

+ 32 - 46
components/display/tarablessd13x6/ifaces/default_if_i2c.c → components/display/core/ifaces/default_if_i2c.c

@@ -11,18 +11,19 @@
 #include <string.h>
 #include <driver/i2c.h>
 #include <driver/gpio.h>
-#include "ssd13x6.h"
-#include "ssd13x6_default_if.h"
+#include "gds.h"
+#include "gds_err.h"
+#include "gds_private.h"
+#include "gds_default_if.h"
 
 static int I2CPortNumber;
 
-static const int SSD13x6_I2C_COMMAND_MODE = 0x80;
-static const int SSD13x6_I2C_DATA_MODE = 0x40;
+static const int GDS_I2C_COMMAND_MODE = 0x80;
+static const int GDS_I2C_DATA_MODE = 0x40;
 
 static bool I2CDefaultWriteBytes( int Address, bool IsCommand, const uint8_t* Data, size_t DataLength );
-static bool I2CDefaultWriteCommand( struct SSD13x6_Device* Display, SSDCmd Command );
-static bool I2CDefaultWriteData( struct SSD13x6_Device* Display, const uint8_t* Data, size_t DataLength );
-static bool I2CDefaultReset( struct SSD13x6_Device* Display );
+static bool I2CDefaultWriteCommand( struct GDS_Device* Device, uint8_t Command );
+static bool I2CDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data, size_t DataLength );
 
 /*
  * Initializes the i2c master with the parameters specified
@@ -30,7 +31,7 @@ static bool I2CDefaultReset( struct SSD13x6_Device* Display );
  * 
  * Returns true on successful init of the i2c bus.
  */
-bool SSD13x6_I2CMasterInitDefault( int PortNumber, int SDA, int SCL ) {
+bool GDS_I2CInit( int PortNumber, int SDA, int SCL ) {
 	I2CPortNumber = PortNumber;
 	
 	if (SDA != -1 && SCL != -1) {
@@ -54,7 +55,7 @@ bool SSD13x6_I2CMasterInitDefault( int PortNumber, int SDA, int SCL ) {
  * Attaches a display to the I2C bus using default communication functions.
  * 
  * Params:
- * DisplayHandle: Pointer to your SSD13x6_Device object
+ * Device: Pointer to your GDS_Device object
  * Width: Width of display
  * Height: Height of display
  * I2CAddress: Address of your display
@@ -62,26 +63,24 @@ bool SSD13x6_I2CMasterInitDefault( int PortNumber, int SDA, int SCL ) {
  * 
  * Returns true on successful init of display.
  */
-bool SSD13x6_I2CMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle, int Model, int Width, int Height, int I2CAddress, int RSTPin ) {
-    NullCheck( DeviceHandle, return false );
-
-    if ( RSTPin >= 0 ) {
+bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int I2CAddress, int RSTPin ) {
+    NullCheck( Device, return false );
+
+    Device->WriteCommand = I2CDefaultWriteCommand;
+    Device->WriteData = I2CDefaultWriteData;
+    Device->Address = I2CAddress;
+    Device->RSTPin = RSTPin;
+	Device->IF = IF_I2C;
+	Device->Width = Width;
+	Device->Height = Height;
+	
+	if ( RSTPin >= 0 ) {
         ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( RSTPin, GPIO_MODE_OUTPUT ), return false );
         ESP_ERROR_CHECK_NONFATAL( gpio_set_level( RSTPin, 1 ), return false );
+		GDS_Reset( Device );
     }
 	
-	memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );	
-	DeviceHandle->Model = Model;
-	
-    return SSD13x6_Init_I2C( DeviceHandle,
-        Width,
-        Height,
-        I2CAddress,
-        RSTPin,
-        I2CDefaultWriteCommand,
-        I2CDefaultWriteData,
-        I2CDefaultReset
-    );
+    return Device->Init( Device );
 }
 
 static bool I2CDefaultWriteBytes( int Address, bool IsCommand, const uint8_t* Data, size_t DataLength ) {
@@ -91,7 +90,7 @@ static bool I2CDefaultWriteBytes( int Address, bool IsCommand, const uint8_t* Da
     NullCheck( Data, return false );
 
     if ( ( CommandHandle = i2c_cmd_link_create( ) ) != NULL ) {
-        ModeByte = ( IsCommand == true ) ? SSD13x6_I2C_COMMAND_MODE: SSD13x6_I2C_DATA_MODE;
+        ModeByte = ( IsCommand == true ) ? GDS_I2C_COMMAND_MODE: GDS_I2C_DATA_MODE;
 
         ESP_ERROR_CHECK_NONFATAL( i2c_master_start( CommandHandle ), goto error );
         ESP_ERROR_CHECK_NONFATAL( i2c_master_write_byte( CommandHandle, ( Address << 1 ) | I2C_MASTER_WRITE, true ), goto error );
@@ -110,29 +109,16 @@ error:
 	return false;
 }
 
-static bool I2CDefaultWriteCommand( struct SSD13x6_Device* Display, SSDCmd Command ) {
+static bool I2CDefaultWriteCommand( struct GDS_Device* Device, uint8_t Command ) {
     uint8_t CommandByte = ( uint8_t ) Command;
-
-    NullCheck( Display, return false );
-    return I2CDefaultWriteBytes( Display->Address, true, ( const uint8_t* ) &CommandByte, 1 );
+	
+    NullCheck( Device, return false );
+    return I2CDefaultWriteBytes( Device->Address, true, ( const uint8_t* ) &CommandByte, 1 );
 }
 
-static bool I2CDefaultWriteData( struct SSD13x6_Device* Display, const uint8_t* Data, size_t DataLength ) {
-    NullCheck( Display, return false );
+static bool I2CDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data, size_t DataLength ) {
+    NullCheck( Device, return false );
     NullCheck( Data, return false );
 
-    return I2CDefaultWriteBytes( Display->Address, false, Data, DataLength );
-}
-
-static bool I2CDefaultReset( struct SSD13x6_Device* Display ) {
-    NullCheck( Display, return false );
-
-    if ( Display->RSTPin >= 0 ) {
-        ESP_ERROR_CHECK_NONFATAL( gpio_set_level( Display->RSTPin, 0 ), return true );
-            vTaskDelay( pdMS_TO_TICKS( 100 ) );
-        ESP_ERROR_CHECK_NONFATAL( gpio_set_level( Display->RSTPin, 1 ), return true );
-    }
-
-    return true;
+    return I2CDefaultWriteBytes( Device->Address, false, Data, DataLength );
 }
-

+ 109 - 0
components/display/core/ifaces/default_if_spi.c

@@ -0,0 +1,109 @@
+
+/**
+ * Copyright (c) 2017-2018 Tara Keeling
+ * 
+ * This software is released under the MIT License.
+ * https://opensource.org/licenses/MIT
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <driver/spi_master.h>
+#include <driver/gpio.h>
+#include <freertos/task.h>
+#include "gds.h"
+#include "gds_err.h"
+#include "gds_private.h"
+#include "gds_default_if.h"
+
+static const int GDS_SPI_Command_Mode = 0;
+static const int GDS_SPI_Data_Mode = 1;
+
+static spi_host_device_t SPIHost;
+static int DCPin;
+
+static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength );
+static bool SPIDefaultWriteCommand( struct GDS_Device* Device, uint8_t Command );
+static bool SPIDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data, size_t DataLength );
+
+bool GDS_SPIInit( int SPI, int DC ) {
+	SPIHost = SPI;
+	DCPin = DC;
+    return true;
+}
+
+bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed ) {
+    spi_device_interface_config_t SPIDeviceConfig;
+    spi_device_handle_t SPIDevice;
+
+    NullCheck( Device, return false );
+	
+	if (CSPin >= 0) {
+		ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( CSPin, GPIO_MODE_OUTPUT ), return false );
+		ESP_ERROR_CHECK_NONFATAL( gpio_set_level( CSPin, 0 ), return false );
+	}	
+
+    memset( &SPIDeviceConfig, 0, sizeof( spi_device_interface_config_t ) );
+
+    SPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_8M;
+    SPIDeviceConfig.spics_io_num = CSPin;
+    SPIDeviceConfig.queue_size = 1;
+
+    ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDevice ), return false );
+	
+	Device->WriteCommand = SPIDefaultWriteCommand;
+    Device->WriteData = SPIDefaultWriteData;
+    Device->SPIHandle = SPIDevice;
+    Device->RSTPin = RSTPin;
+    Device->CSPin = CSPin;
+	Device->IF = IF_SPI;
+	Device->Width = Width;
+	Device->Height = Height;
+	
+	if ( RSTPin >= 0 ) {
+        ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( RSTPin, GPIO_MODE_OUTPUT ), return false );
+        ESP_ERROR_CHECK_NONFATAL( gpio_set_level( RSTPin, 0 ), return false );
+		GDS_Reset( Device );
+    }
+	
+	return Device->Init( Device );
+}
+
+static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ) {
+    spi_transaction_t SPITransaction = { 0 };
+
+    NullCheck( SPIHandle, return false );
+    NullCheck( Data, return false );
+
+    if ( DataLength > 0 ) {
+		gpio_set_level( DCPin, WriteMode );
+		
+		SPITransaction.length = DataLength * 8;
+		SPITransaction.tx_buffer = Data;
+            
+		// only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes)		
+		ESP_ERROR_CHECK_NONFATAL( spi_device_polling_transmit(SPIHandle, &SPITransaction), return false );
+    }
+
+    return true;
+}
+
+static bool SPIDefaultWriteCommand( struct GDS_Device* Device, uint8_t Command ) {
+    static uint8_t CommandByte = 0;
+
+    NullCheck( Device, return false );
+    NullCheck( Device->SPIHandle, return false );
+
+    CommandByte = Command;
+
+    return SPIDefaultWriteBytes( Device->SPIHandle, GDS_SPI_Command_Mode, &CommandByte, 1 );
+}
+
+static bool SPIDefaultWriteData( struct GDS_Device* Device, const uint8_t* Data, size_t DataLength ) {
+    NullCheck( Device, return false );
+    NullCheck( Device->SPIHandle, return false );
+
+    return SPIDefaultWriteBytes( Device->SPIHandle, GDS_SPI_Data_Mode, Data, DataLength );
+}

+ 72 - 31
components/display/display.c

@@ -22,14 +22,15 @@
 #include <stdint.h>
 #include <arpa/inet.h>
 #include "esp_log.h"
+#include "globdefs.h"
 #include "config.h"
 #include "tools.h"
 #include "display.h"
-
-// here we should include all possible drivers
-extern struct display_s SSD13x6_display;
-
-struct display_s *display = NULL;
+#include "gds.h"
+#include "gds_default_if.h"
+#include "gds_draw.h"
+#include "gds_text.h"
+#include "gds_font.h"
 
 static const char *TAG = "display";
 
@@ -57,34 +58,74 @@ static EXT_RAM_ATTR struct {
 
 static void displayer_task(void *args);
 
+struct GDS_Device *display;
+struct GDS_Device* SSD1306_Detect(char *Driver, struct GDS_Device* Device);
+struct GDS_Device* SH1106_Detect(char *Driver, struct GDS_Device* Device);
+GDS_DetectFunc drivers[] = { SH1106_Detect, SSD1306_Detect, NULL };
+
 /****************************************************************************************
  * 
  */
 void display_init(char *welcome) {
 	bool init = false;
-	char *item = config_alloc_get(NVS_TYPE_STR, "display_config");
+	char *config = config_alloc_get(NVS_TYPE_STR, "display_config");
 
-	if (item && *item) {
-		char * drivername=strstr(item,"driver");
-		if (!drivername  || (drivername && (strcasestr(drivername,"SSD1306") || strcasestr(drivername,"SSD1326") || strcasestr(drivername,"SH1106")))) {
-			display = &SSD13x6_display;
-			if (display->init(item, welcome)) {
-				init = true;
-				ESP_LOGI(TAG, "Display initialization successful");
-			} else {
-				display = NULL;
-				ESP_LOGW(TAG, "Display initialization failed");
-			}
+	if (!config) {
+		ESP_LOGI(TAG, "no display");
+		return false;
+	}	
+	
+	int width = -1, height = -1;
+	char *p, *drivername = strstr(config, "driver");
+		
+	// query drivers to see if we have a match
+	ESP_LOGI(TAG, "Trying to configure display with %s", config);
+	display = GDS_AutoDetect(drivername ? drivername : "SSD1306", drivers);
+		
+	if ((p = strcasestr(config, "width")) != NULL) width = atoi(strchr(p, '=') + 1);
+	if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1);
+		
+	// so far so good
+	if (display && width > 0 && height > 0) {
+		// Detect driver interface
+		if (strstr(config, "I2C") && i2c_system_port != -1) {
+			int address = 0x3C;
+				
+			if ((p = strcasestr(config, "address")) != NULL) address = atoi(strchr(p, '=') + 1);
+		
+			init = true;
+			GDS_I2CInit( i2c_system_port, -1, -1 ) ;
+			GDS_I2CAttachDevice( display, width, height, address, -1 );
+		
+			ESP_LOGI(TAG, "Display is I2C on port %u", address);
+		} else if (strstr(config, "SPI") && spi_system_host != -1) {
+			int CS_pin = -1, speed = 0;
+		
+			if ((p = strcasestr(config, "cs")) != NULL) CS_pin = atoi(strchr(p, '=') + 1);
+			if ((p = strcasestr(config, "speed")) != NULL) speed = atoi(strchr(p, '=') + 1);
+		
+			init = true;
+			GDS_SPIInit( spi_system_host, spi_system_dc_gpio );
+			GDS_SPIAttachDevice( display, width, height, CS_pin, -1, speed );
+				
+			ESP_LOGI(TAG, "Display is SPI host %u with cs:%d", spi_system_host, CS_pin);
 		} else {
-			ESP_LOGE(TAG,"Unknown display driver name in display config: %s",item);
+			display = NULL;
+			ESP_LOGI(TAG, "Unsupported display interface or serial link not configured");
 		}
 	} else {
-		ESP_LOGI(TAG, "no display");
-	}
+		display = NULL;
+		ESP_LOGW(TAG, "No display driver");
+	}	
 	
 	if (init) {
 		static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
 		static EXT_RAM_ATTR StackType_t xStack[DISPLAYER_STACK_SIZE] __attribute__ ((aligned (4)));
+		
+		GDS_SetHFlip(display, strcasestr(config, "HFlip") ? true : false);
+		GDS_SetVFlip(display, strcasestr(config, "VFlip") ? true : false);
+		GDS_SetFont(display, &Font_droid_sans_fallback_15x17 );
+		GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome);
 
 		// start the task that will handle scrolling & counting
 		displayer.mutex = xSemaphoreCreateMutex();
@@ -94,13 +135,13 @@ void display_init(char *welcome) {
 		displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "displayer_thread", DISPLAYER_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
 		
 		// set lines for "fixed" text mode
-		display->set_font(1, DISPLAY_FONT_LINE_1, -3);
-		display->set_font(2, DISPLAY_FONT_LINE_2, -3);
+		GDS_TextSetFontAuto(display, 1, GDS_FONT_LINE_1, -3);
+		GDS_TextSetFontAuto(display, 2, GDS_FONT_LINE_2, -3);
 		
 		displayer.metadata_config = config_alloc_get(NVS_TYPE_STR, "metadata_config");
 	}
 	
-	if (item) free(item);
+	free(config);
 }
 
 /****************************************************************************************
@@ -114,14 +155,14 @@ static void displayer_task(void *args) {
 	while (1) {
 		// suspend ourselves if nothing to do
 		if (displayer.state < DISPLAYER_ACTIVE) {
-			if (displayer.state == DISPLAYER_IDLE) display->line(2, 0, DISPLAY_CLEAR | DISPLAY_UPDATE, displayer.string);
+			if (displayer.state == DISPLAYER_IDLE) GDS_TextLine(display, 2, 0, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, displayer.string);
 			vTaskSuspend(NULL);
 			scroll_sleep = 0;
-			display->clear(true);
-			display->line(1, DISPLAY_LEFT, DISPLAY_UPDATE, displayer.header);
+			GDS_ClearExt(display, true);
+			GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_UPDATE, displayer.header);
 		} else if (displayer.refresh) {
 			// little trick when switching master while in IDLE and missing it
-			display->line(1, DISPLAY_LEFT, DISPLAY_CLEAR | DISPLAY_UPDATE, displayer.header);	
+			GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, displayer.header);	
 			displayer.refresh = false;			
 		}
 		
@@ -140,7 +181,7 @@ static void displayer_task(void *args) {
 				xSemaphoreGive(displayer.mutex);				
 				
 				// now display using safe copies, can be lengthy
-				display->line(2, offset, DISPLAY_CLEAR | DISPLAY_UPDATE, string);
+				GDS_TextLine(display, 2, offset, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, string);
 				free(string);
 			} else {
 				scroll_sleep = DEFAULT_SLEEP;
@@ -160,7 +201,7 @@ static void displayer_task(void *args) {
 				xSemaphoreGive(displayer.mutex);				
 				if (displayer.elapsed < 3600) sprintf(counter, "%5u:%02u", displayer.elapsed / 60, displayer.elapsed % 60);
 				else sprintf(counter, "%2u:%02u:%02u", displayer.elapsed / 3600, (displayer.elapsed % 3600) / 60, displayer.elapsed % 60);
-				display->line(1, DISPLAY_RIGHT, (DISPLAY_CLEAR | DISPLAY_ONLY_EOL) | DISPLAY_UPDATE, counter);
+				GDS_TextLine(display, 1, GDS_TEXT_RIGHT, (GDS_TEXT_CLEAR | GDS_TEXT_CLEAR_EOL) | GDS_TEXT_UPDATE, counter);
 				timer_sleep = 1000;
 			} else timer_sleep = max(1000 - elapsed, 0);	
 		} else timer_sleep = DEFAULT_SLEEP;
@@ -240,7 +281,7 @@ void displayer_metadata(char *artist, char *album, char *title) {
 	displayer.offset = 0;	
 	utf8_decode(displayer.string);
 	ESP_LOGI(TAG, "playing %s", displayer.string);
-	displayer.boundary = display->stretch(2, displayer.string, SCROLLABLE_SIZE);
+	displayer.boundary = GDS_TextStretch(display, 2, displayer.string, SCROLLABLE_SIZE);
 		
 	xSemaphoreGive(displayer.mutex);
 }	
@@ -258,7 +299,7 @@ void displayer_scroll(char *string, int speed) {
 	displayer.offset = 0;	
 	strncpy(displayer.string, string, SCROLLABLE_SIZE);
 	displayer.string[SCROLLABLE_SIZE] = '\0';
-	displayer.boundary = display->stretch(2, displayer.string, SCROLLABLE_SIZE);
+	displayer.boundary = GDS_TextStretch(display, 2, displayer.string, SCROLLABLE_SIZE);
 		
 	xSemaphoreGive(displayer.mutex);
 }

+ 3 - 34
components/display/display.h

@@ -18,6 +18,8 @@
 
 #pragma once
 
+#include "gds.h"
+
 /* 
  The displayer is not thread-safe and the caller must ensure use its own 
  mutexes if it wants something better. Especially, text() line() and draw()
@@ -32,44 +34,11 @@
  when this one (the main) wants to take control over display, it can signal
  that to others
 */ 
+extern struct GDS_Device *display;
   
-#define DISPLAY_CLEAR 		0x01
-#define	DISPLAY_ONLY_EOL	0x02
-#define DISPLAY_UPDATE		0x04
-#define DISPLAY_MONOSPACE	0x08
-
-// these ones are for 'x' parameter of line() function
-#define DISPLAY_LEFT 	0
-#define DISPLAY_RIGHT	0xff00
-#define	DISPLAY_CENTER  0xff01
-
-enum display_pos_e 	{ DISPLAY_TOP_LEFT, DISPLAY_MIDDLE_LEFT, DISPLAY_BOTTOM_LEFT, DISPLAY_CENTERED };
-enum display_font_e { DISPLAY_FONT_DEFAULT, 
-					  DISPLAY_FONT_LINE_1, DISPLAY_FONT_LINE_2, DISPLAY_FONT_SEGMENT, 
-					  DISPLAY_FONT_TINY, DISPLAY_FONT_SMALL,  DISPLAY_FONT_MEDIUM, DISPLAY_FONT_LARGE, DISPLAY_FONT_HUGE };
-					  
 enum displayer_cmd_e 	{ DISPLAYER_SHUTDOWN, DISPLAYER_ACTIVATE, DISPLAYER_SUSPEND, DISPLAYER_TIMER_PAUSE, DISPLAYER_TIMER_RUN };
 enum displayer_time_e 	{ DISPLAYER_ELAPSED, DISPLAYER_REMAINING };
 
-// don't change anything there w/o changing all drivers init code
-extern struct display_s {
-	int width, height;
-	bool dirty;
-	bool (*init)(char *config, char *welcome);
-	void (*clear)(bool full, ...);
-	bool (*set_font)(int num, enum display_font_e font, int space);
-	void (*on)(bool state);
-	void (*brightness)(uint8_t level);
-	void (*text)(enum display_font_e font, enum display_pos_e pos, int attribute, char *msg, ...);
-	bool (*line)(int num, int x, int attribute, char *text);
-	int (*stretch)(int num, char *string, int max);
-	void (*update)(void);
-	void (*draw_raw)(int x1, int y1, int x2, int y2, bool by_column, bool MSb, uint8_t *data);
-	void (*draw_cbr)(uint8_t *data, int width, int height);		// width and height is the # of rows/columns in data, as opposed to display height (0 = display width, 0 = display height) 
-	void (*draw_line)(int x1, int y1, int x2, int y2);
-	void (*draw_box)( int x1, int y1, int x2, int y2, bool fill);
-} *display;
-
 enum display_bus_cmd_e { DISPLAY_BUS_TAKE, DISPLAY_BUS_GIVE };
 bool (*display_bus)(void *from, enum display_bus_cmd_e cmd);
 

+ 0 - 446
components/display/driver_SSD13x6.c

@@ -1,446 +0,0 @@
-/* 
- *  (c) 2004,2006 Richard Titmuss for SlimProtoLib 
- *  (c) Philippe G. 2019, philippe_44@outlook.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <string.h>
-#include <ctype.h>
-#include <stdint.h>
-#include <arpa/inet.h>
-#include "esp_log.h"
-#include "display.h"
-#include "globdefs.h"
-
-#include "ssd13x6.h"
-#include "ssd13x6_draw.h"
-#include "ssd13x6_font.h"
-#include "ssd13x6_default_if.h"
-
-#define I2C_ADDRESS	0x3C
-
-static const char *TAG = "display";
-
-#define max(a,b) (((a) > (b)) ? (a) : (b))
-
-// handlers
-static bool init(char *config, char *welcome);
-static void clear(bool full, ...);
-static bool set_font(int num, enum display_font_e font, int space);
-static void text(enum display_font_e font, enum display_pos_e pos, int attribute, char *text, ...);
-static bool line(int num, int x, int attribute, char *text);
-static int stretch(int num, char *string, int max);
-static void draw_cbr(u8_t *data, int width, int height);
-static void draw_raw(int x1, int y1, int x2, int y2, bool by_column, bool MSb, u8_t *data);
-static void draw_line(int x1, int y1, int x2, int y2);
-static void draw_box( int x1, int y1, int x2, int y2, bool fill);
-static void brightness(u8_t level);
-static void on(bool state);
-static void update(void);
-
-// display structure for others to use
-struct display_s SSD13x6_display = { 0, 0, true,
-									init, clear, set_font, on, brightness, 
-									text, line, stretch, update, draw_raw, draw_cbr, draw_line, draw_box };
-
-// SSD13x6 specific function
-static struct SSD13x6_Device Display;
-
-static const unsigned char BitReverseTable256[] = 
-{
-  0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 
-  0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 
-  0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, 
-  0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, 
-  0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 
-  0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
-  0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, 
-  0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
-  0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
-  0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 
-  0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
-  0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
-  0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, 
-  0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
-  0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, 
-  0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
-};
-
-#define MAX_LINES	8
-
-static struct {
-	int y, space;
-	const struct SSD13x6_FontDef *font;
-} lines[MAX_LINES];
-
-/****************************************************************************************
- * 
- */
-static bool init(char *config, char *welcome) {
-	bool res = true;
-	int width = -1, height = -1, model = SSD1306;
-	char *p;
-	
-	ESP_LOGI(TAG, "Initializing display with config: %s",config);
-	
-	// no time for smart parsing - this is for tinkerers
-	if ((p = strcasestr(config, "width")) != NULL) width = atoi(strchr(p, '=') + 1);
-	if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1);
-	
-	if (strcasestr(config, "ssd1326")) model = SSD1326;
-	else if (strcasestr(config, "sh1106")) model = SH1106;
-	
-	if (width == -1 || height == -1) {
-		ESP_LOGW(TAG, "No display configured %s [%d x %d]", config, width, height);
-		return false;
-	}	
-
-	if (strstr(config, "I2C") && i2c_system_port != -1) {
-		int address = I2C_ADDRESS;
-				
-		if ((p = strcasestr(config, "address")) != NULL) address = atoi(strchr(p, '=') + 1);
-		
-		SSD13x6_I2CMasterInitDefault( i2c_system_port, -1, -1 ) ;
-		SSD13x6_I2CMasterAttachDisplayDefault( &Display, model, width, height, address, -1 );
-		SSD13x6_SetHFlip( &Display, strcasestr(config, "HFlip") ? true : false);
-		SSD13x6_SetVFlip( &Display, strcasestr(config, "VFlip") ? true : false);
-		SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
-		SSD13x6_display.width = width;
-		SSD13x6_display.height = height;
-		
-		text(DISPLAY_FONT_MEDIUM, DISPLAY_CENTERED, DISPLAY_CLEAR | DISPLAY_UPDATE, welcome);
-		
-		ESP_LOGI(TAG, "Display is I2C on port %u", address);
-	} else if (strstr(config, "SPI") && spi_system_host != -1) {
-		int CS_pin = -1, speed = 0;
-		
-		if ((p = strcasestr(config, "cs")) != NULL) CS_pin = atoi(strchr(p, '=') + 1);
-		if ((p = strcasestr(config, "speed")) != NULL) speed = atoi(strchr(p, '=') + 1);
-		
-		SSD13x6_SPIMasterInitDefault( spi_system_host, spi_system_dc_gpio );
-        SSD13x6_SPIMasterAttachDisplayDefault( &Display, model, width, height, CS_pin, -1, speed );
-		SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
-		SSD13x6_display.width = width;
-		SSD13x6_display.height = height;
-		
-		text(DISPLAY_FONT_MEDIUM, DISPLAY_CENTERED, DISPLAY_CLEAR | DISPLAY_UPDATE, welcome);
-		
-		ESP_LOGI(TAG, "Display is SPI host %u with cs:%d", spi_system_host, CS_pin);
-		
-	} else {
-		res = false;
-		ESP_LOGW(TAG, "Unknown display type or no serial interface configured");
-	}
-
-	return res;
-}
-
-/****************************************************************************************
- * 
- */
-static void clear(bool full, ...) {
-	bool commit = true;
-	
-	if (full) {
-		SSD13x6_Clear( &Display, SSD_COLOR_BLACK ); 
-	} else {
-		va_list args;
-		va_start(args, full);
-		commit = va_arg(args, int);
-		int x1 = va_arg(args, int), y1 = va_arg(args, int), x2 = va_arg(args, int), y2 = va_arg(args, int);
-		if (x2 < 0) x2 = display->width - 1;
-		if (y2 < 0) y2 = display->height - 1;
-		SSD13x6_ClearWindow( &Display, x1, y1, x2, y2, SSD_COLOR_BLACK );
-		va_end(args);
-	}
-	
-	SSD13x6_display.dirty = true;
-	if (commit)	update();		
-}	
-
-/****************************************************************************************
- *  Set fonts for each line in text mode
- */
-static bool set_font(int num, enum display_font_e font, int space) {
-	if (--num >= MAX_LINES) return false;
-	
-	switch(font) {
-	case DISPLAY_FONT_LINE_1:	
-		lines[num].font = &Font_line_1;
-		break;
-	case DISPLAY_FONT_LINE_2:	
-		lines[num].font = &Font_line_2;
-		break;		
-	case DISPLAY_FONT_SMALL:	
-		lines[num].font = &Font_droid_sans_fallback_11x13;	
-		break;
-	case DISPLAY_FONT_MEDIUM:			
-	case DISPLAY_FONT_DEFAULT:
-	default:		
-		lines[num].font = &Font_droid_sans_fallback_15x17;	
-		break;
-	case DISPLAY_FONT_LARGE:	
-		lines[num].font = &Font_droid_sans_fallback_24x28;
-		break;		
-	case DISPLAY_FONT_SEGMENT:			
-		if (Display.Height == 32) lines[num].font = &Font_Tarable7Seg_16x32;
-		else lines[num].font = &Font_Tarable7Seg_32x64;
-		break;		
-	}
-	
-	// re-calculate lines absolute position
-	lines[num].space = space;
-	lines[0].y = lines[0].space;
-	for (int i = 1; i <= num; i++) lines[i].y = lines[i-1].y + lines[i-1].font->Height + lines[i].space;
-		
-	ESP_LOGI(TAG, "Adding line %u at %d (height:%u)", num + 1, lines[num].y, lines[num].font->Height);
-	
-	if (lines[num].y + lines[num].font->Height > Display.Height) {
-		ESP_LOGW(TAG, "line does not fit display");
-		return false;
-	}
-	
-	return true;
-}
-
-/****************************************************************************************
- * 
- */
-static bool line(int num, int x, int attribute, char *text) {
-	int width;
-
-	// counting 1..n
-	num--;
-	
-	SSD13x6_SetFont( &Display, lines[num].font );	
-	if (attribute & DISPLAY_MONOSPACE) SSD13x6_FontForceMonospace( &Display, true );
-	
-	width = SSD13x6_FontMeasureString( &Display, text );
-	
-	// adjusting position, erase only EoL for rigth-justified
-	if (x == DISPLAY_RIGHT) x = Display.Width - width - 1;
-	else if (x == DISPLAY_CENTER) x = (Display.Width - width) / 2;
-	
-	// erase if requested
-	if (attribute & DISPLAY_CLEAR) {
-		int y_min = max(0, lines[num].y), y_max = max(0, lines[num].y + lines[num].font->Height);
-		for (int c = (attribute & DISPLAY_ONLY_EOL) ? x : 0; c < Display.Width; c++) 
-			for (int y = y_min; y < y_max; y++)
-				SSD13x6_DrawPixelFast( &Display, c, y, SSD_COLOR_BLACK );
-	}
-		
-	SSD13x6_FontDrawString( &Display, x, lines[num].y, text, SSD_COLOR_WHITE );
-	
-	ESP_LOGD(TAG, "displaying %s line %u (x:%d, attr:%u)", text, num+1, x, attribute);
-	
-	// update whole display if requested
-	SSD13x6_display.dirty = true;
-	if (attribute & DISPLAY_UPDATE) update();
-		
-	return width + x < Display.Width;
-}
-
-/****************************************************************************************
- * Try to align string for better scrolling visual. there is probably much better to do
- */
-static int stretch(int num, char *string, int max) {
-	char space[] = "     ";
-	int len = strlen(string), extra = 0, boundary;
-	
-	num--;
-	
-	// we might already fit
-	SSD13x6_SetFont( &Display, lines[num].font );	
-	if (SSD13x6_FontMeasureString( &Display, string ) <= Display.Width) return 0;
-		
-	// add some space for better visual 
-	strncat(string, space, max-len);
-	string[max] = '\0';
-	len = strlen(string);
-	
-	// mark the end of the extended string
-	boundary = SSD13x6_FontMeasureString( &Display, string );
-			
-	// add a full display width	
-	while (len < max && SSD13x6_FontMeasureString( &Display, string ) - boundary < Display.Width) {
-		string[len++] = string[extra++];
-		string[len] = '\0';
-	}
-		
-	return boundary;
-}
-
-/****************************************************************************************
- * 
- */
-static void text(enum display_font_e font, enum display_pos_e pos, int attribute, char *text, ...) {
-	va_list args;
-
-	TextAnchor Anchor = TextAnchor_Center;	
-	
-	if (attribute & DISPLAY_CLEAR) SSD13x6_Clear( &Display, SSD_COLOR_BLACK );
-	
-	if (!text) return;
-	
-	va_start(args, text);
-	
-	switch(font) {
-	case DISPLAY_FONT_LINE_1:	
-		SSD13x6_SetFont( &Display, &Font_line_1 );
-		break;
-	case DISPLAY_FONT_LINE_2:	
-		SSD13x6_SetFont( &Display, &Font_line_2 );
-		break;		
-	case DISPLAY_FONT_SMALL:	
-		SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_11x13 );	
-		break;	
-	case DISPLAY_FONT_MEDIUM:			
-	case DISPLAY_FONT_DEFAULT:
-	default:
-		SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_15x17 );	
-		break;		
-	case DISPLAY_FONT_LARGE:	
-		SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_24x28 );
-		break;		
-	case DISPLAY_FONT_SEGMENT:			
-		if (Display.Height == 32) SSD13x6_SetFont( &Display, &Font_Tarable7Seg_16x32 );
-		else SSD13x6_SetFont( &Display, &Font_Tarable7Seg_32x64 );
-		break;		
-	}
-
-	switch(pos) {
-	case DISPLAY_TOP_LEFT: 
-	default:
-		Anchor = TextAnchor_NorthWest; 
-		break;
-	case DISPLAY_MIDDLE_LEFT:
-		Anchor = TextAnchor_West;
-		break;
-	case DISPLAY_BOTTOM_LEFT:
-		Anchor = TextAnchor_SouthWest;
-		break;
-	case DISPLAY_CENTERED:
-		Anchor = TextAnchor_Center;
-		break;
-	}	
-	
-	ESP_LOGD(TAG, "SSDD13x6 displaying %s at %u with attribute %u", text, Anchor, attribute);
-	
-	SSD13x6_FontDrawAnchoredString( &Display, Anchor, text, SSD_COLOR_WHITE );
-	
-	SSD13x6_display.dirty = true;
-	if (attribute & DISPLAY_UPDATE) update();
-	
-	va_end(args);
-}
-
-/****************************************************************************************
- * Process graphic display data from column-oriented data (MSbit first)
- */
-static void draw_cbr(u8_t *data, int width, int height) {
-	if (!height) height = Display.Height;
-	if (!width) width = Display.Width;
-
-	// need to do row/col swap and bit-reverse
-	int rows = height / 8;
-	for (int r = 0; r < rows; r++) {
-		uint8_t *optr = Display.Framebuffer + r*Display.Width, *iptr = data + r;
-		for (int c = width; --c >= 0;) {
-			*optr++ = BitReverseTable256[*iptr];;
-			iptr += rows;
-		}	
-	}
-	
-	SSD13x6_display.dirty = true;
-}
-
-/****************************************************************************************
- * Process graphic display data MSBit first
- * WARNING: this has not been tested yet
- */
-static void draw_raw(int x1, int y1, int x2, int y2, bool by_column, bool MSb, u8_t *data) {
-	// default end point to display size
-	if (x2 == -1) x2 = Display.Width - 1;
-	if (y2 == -1) y2 = Display.Height - 1;
-	
-	display->dirty = true;
-	
-	//	not a boundary draw
-	if (y1 % 8 || y2 % 8 || x1 % 8 | x2 % 8) {
-		ESP_LOGW(TAG, "can't write on non cols/rows boundaries for now");
-	} else {	
-		// set addressing mode to match data
-		if (by_column) {
-			// copy the window and do row/col exchange
-			for (int r = y1/8; r <=  y2/8; r++) {
-				uint8_t *optr = Display.Framebuffer + r*Display.Width + x1, *iptr = data + r;
-				for (int c = x1; c <= x2; c++) {
-					*optr++ = MSb ? BitReverseTable256[*iptr] : *iptr;
-					iptr += (y2-y1)/8 + 1;
-			}	
-			}	
-		} else {
-			// just copy the window inside the frame buffer
-			for (int r = y1/8; r <= y2/8; r++) {
-				uint8_t *optr = Display.Framebuffer + r*Display.Width + x1, *iptr = data + r*(x2-x1+1);
-				for (int c = x1; c <= x2; c++) *optr++ = *iptr++;
-			}	
-		}
-	}	
-}
-
-/****************************************************************************************
- * Draw line
- */
-static void draw_line( int x1, int y1, int x2, int y2) {
-	SSD13x6_DrawLine( &Display, x1, y1, x2, y2, SSD_COLOR_WHITE );
-	SSD13x6_display.dirty = true;
-}
-
-/****************************************************************************************
- * Draw Box
- */
-static void draw_box( int x1, int y1, int x2, int y2, bool fill) {
-	SSD13x6_DrawBox( &Display, x1, y1, x2, y2, SSD_COLOR_WHITE, fill );
-	SSD13x6_display.dirty = true;
-}
-
-/****************************************************************************************
- * Brightness
- */
-static void brightness(u8_t level) {
-	SSD13x6_DisplayOn( &Display ); 
-	SSD13x6_SetContrast( &Display, (uint8_t) level);
-}
-
-/****************************************************************************************
- * Display On/Off
- */
-static void on(bool state) {
-	if (state) SSD13x6_DisplayOn( &Display ); 
-	else SSD13x6_DisplayOff( &Display ); 
-}
-
-/****************************************************************************************
- * Update 
- */
-static void update(void) {
-	if (SSD13x6_display.dirty) SSD13x6_Update( &Display );
-	SSD13x6_display.dirty = false;
-}
-
-
-

+ 0 - 0
components/display/tarablessd13x6/fonts/LICENSE-apache → components/display/fonts/LICENSE-apache


+ 0 - 0
components/display/tarablessd13x6/fonts/LICENSE-liberation-mono → components/display/fonts/LICENSE-liberation-mono


+ 2 - 2
components/display/tarablessd13x6/fonts/font_droid_sans_fallback_11x13.c → components/display/fonts/font_droid_sans_fallback_11x13.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Droid_Sans_Fallback11x13[ ] = {
     0x05, 0x00, 0x10, 0xE4, 0x11, 0x00, 0x0E, 0x00, 0x02, 0xE4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_droid_sans_fallback_11x13 = {
+const struct GDS_FontDef Font_droid_sans_fallback_11x13 = {
     Droid_Sans_Fallback11x13,
     11,
     13,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_droid_sans_fallback_15x17.c → components/display/fonts/font_droid_sans_fallback_15x17.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Droid_Sans_Fallback15x17[ ] = {
     0x07, 0xC0, 0x00, 0x01, 0x00, 0x03, 0x01, 0x10, 0x8C, 0x00, 0x00, 0x70, 0x00, 0x00, 0x0C, 0x00, 0x10, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_droid_sans_fallback_15x17 = {
+const struct GDS_FontDef Font_droid_sans_fallback_15x17 = {
     Droid_Sans_Fallback15x17,
     15,
     17,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_droid_sans_fallback_24x28.c → components/display/fonts/font_droid_sans_fallback_24x28.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Droid_Sans_Fallback24x28[ ] = {
     0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x0C, 0xE0, 0xF0, 0x03, 0x0C, 0xE0, 0x80, 0x0F, 0x0E, 0x00, 0x00, 0xFE, 0x07, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x7E, 0x00, 0xE0, 0x80, 0x0F, 0x00, 0xE0, 0xF0, 0x03, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_droid_sans_fallback_24x28 = {
+const struct GDS_FontDef Font_droid_sans_fallback_24x28 = {
     Droid_Sans_Fallback24x28,
     24,
     28,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_droid_sans_mono_13x24.c → components/display/fonts/font_droid_sans_mono_13x24.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Droid_Sans_Mono13x24[ ] = {
     0x0C, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x80, 0x07, 0xC0, 0x00, 0x1E, 0xC0, 0x18, 0xF8, 0xC0, 0x18, 0xC0, 0x7F, 0x00, 0x00, 0x1E, 0x00, 0xC0, 0x07, 0x18, 0xF8, 0x00, 0x18, 0x3E, 0x00, 0x80, 0x07, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_droid_sans_mono_13x24 = {
+const struct GDS_FontDef Font_droid_sans_mono_13x24 = {
     Droid_Sans_Mono13x24,
     13,
     24,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_droid_sans_mono_16x31.c → components/display/fonts/font_droid_sans_mono_16x31.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Droid_Sans_Mono16x31[ ] = {
     0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x60, 0x00, 0x78, 0x00, 0x60, 0x00, 0xF8, 0x01, 0x60, 0x00, 0xE0, 0x07, 0x60, 0xE0, 0x00, 0x3F, 0x70, 0xE0, 0x00, 0xFC, 0x3C, 0x40, 0x00, 0xE0, 0x1F, 0x00, 0x00, 0xE0, 0x07, 0x40, 0x00, 0xF8, 0x01, 0xE0, 0x00, 0x3F, 0x00, 0xE0, 0xC0, 0x0F, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_droid_sans_mono_16x31 = {
+const struct GDS_FontDef Font_droid_sans_mono_16x31 = {
     Droid_Sans_Mono16x31,
     16,
     31,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_droid_sans_mono_7x13.c → components/display/fonts/font_droid_sans_mono_7x13.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Droid_Sans_Mono7x13[ ] = {
     0x06, 0x00, 0x00, 0x30, 0x10, 0xC4, 0x10, 0x00, 0x0F, 0xC4, 0x01, 0x30, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_droid_sans_mono_7x13 = {
+const struct GDS_FontDef Font_droid_sans_mono_7x13 = {
     Droid_Sans_Mono7x13,
     7,
     13,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_liberation_mono_13x21.c → components/display/fonts/font_liberation_mono_13x21.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Liberation_Mono13x21[ ] = {
     0x0C, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xC0, 0x03, 0x10, 0x00, 0x0F, 0x10, 0x0C, 0x3C, 0x18, 0x00, 0xE0, 0x0D, 0x00, 0x80, 0x07, 0x00, 0xE0, 0x01, 0x0C, 0x3C, 0x00, 0x00, 0x0F, 0x00, 0xC0, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_liberation_mono_13x21 = {
+const struct GDS_FontDef Font_liberation_mono_13x21 = {
     Liberation_Mono13x21,
     13,
     21,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_liberation_mono_17x30.c → components/display/fonts/font_liberation_mono_17x30.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Liberation_Mono17x30[] = {
     0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x30, 0x00, 0x3F, 0x00, 0x30, 0x00, 0xFC, 0x01, 0x30, 0x38, 0xE0, 0x07, 0x38, 0x38, 0x00, 0x3F, 0x1C, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xF8, 0x01, 0x38, 0x00, 0x3F, 0x00, 0x38, 0xE0, 0x07, 0x00, 0x38, 0xFC, 0x01, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_liberation_mono_17x30 = {
+const struct GDS_FontDef Font_liberation_mono_17x30 = {
     Liberation_Mono17x30,
     17,
     30,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_liberation_mono_9x15.c → components/display/fonts/font_liberation_mono_9x15.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Liberation_Mono9x15[ ] = {
     0x08, 0x00, 0x00, 0x30, 0x40, 0xC6, 0x41, 0x06, 0x67, 0x00, 0x18, 0x06, 0x07, 0xC6, 0x01, 0x30, 0x00, 0x00, 0x00  // Code for char ÿ
 };
 
-const struct SSD13x6_FontDef Font_liberation_mono_9x15 = {
+const struct GDS_FontDef Font_liberation_mono_9x15 = {
     Liberation_Mono9x15,
     9,
     15,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_line_1.c → components/display/fonts/font_line_1.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -214,7 +214,7 @@ static const uint8_t Square721_BT11x14[] = {
         0x06, 0x00, 0x00, 0xE8, 0x03, 0xB0, 0x04, 0xA0, 0x04, 0xA0, 0x04, 0xE0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Code for char è
         };
 
-const struct SSD13x6_FontDef Font_line_1 = {
+const struct GDS_FontDef Font_line_1 = {
     Square721_BT11x14,
     11,
     14,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_line_2.c → components/display/fonts/font_line_2.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -237,7 +237,7 @@ static const uint8_t Archivo_Narrow18x24[] = {
         0x0A, 0x00, 0x01, 0x00, 0x00, 0x1F, 0xE0, 0x38, 0xFF, 0xE0, 0x38, 0xFC, 0xF7, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x3F, 0x38, 0xF0, 0x0F, 0x38, 0xFF, 0x01, 0x00, 0x1F, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00   // Code for char ÿ
         };
 				
-const struct SSD13x6_FontDef Font_line_2 = {
+const struct GDS_FontDef Font_line_2 = {
     Archivo_Narrow18x24,
     18,
     24,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_tarable7seg_16x32.c → components/display/fonts/font_tarable7seg_16x32.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -109,7 +109,7 @@ static const uint8_t Tarable7Seg_16x32[ ] = {
     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char 
 };
 
-const struct SSD13x6_FontDef Font_Tarable7Seg_16x32 = {
+const struct GDS_FontDef Font_Tarable7Seg_16x32 = {
     Tarable7Seg_16x32,
     16,
     32,

+ 2 - 2
components/display/tarablessd13x6/fonts/font_tarable7seg_32x64.c → components/display/fonts/font_tarable7seg_32x64.c

@@ -1,4 +1,4 @@
-#include <ssd13x6_font.h>
+#include <gds_font.h>
 
 //WARNING: This Font Require X-GLCD Lib.
 //         You can not use it with MikroE GLCD Lib.
@@ -109,7 +109,7 @@ static const uint8_t Tarable7Seg_32x64[ ] = {
     0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // Code for char 
 };
 
-const struct SSD13x6_FontDef Font_Tarable7Seg_32x64 = {
+const struct GDS_FontDef Font_Tarable7Seg_32x64 = {
     Tarable7Seg_32x64,
     32,
     64,

+ 0 - 123
components/display/tarablessd13x6/ifaces/default_if_spi.c

@@ -1,123 +0,0 @@
-
-/**
- * Copyright (c) 2017-2018 Tara Keeling
- * 
- * This software is released under the MIT License.
- * https://opensource.org/licenses/MIT
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <driver/spi_master.h>
-#include <driver/gpio.h>
-#include <freertos/task.h>
-#include "ssd13x6.h"
-#include "ssd13x6_default_if.h"
-
-static const int SSD13x6_SPI_Command_Mode = 0;
-static const int SSD13x6_SPI_Data_Mode = 1;
-
-static spi_host_device_t SPIHost;
-static int DCPin;
-
-static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength );
-static bool SPIDefaultWriteCommand( struct SSD13x6_Device* DeviceHandle, SSDCmd Command );
-static bool SPIDefaultWriteData( struct SSD13x6_Device* DeviceHandle, const uint8_t* Data, size_t DataLength );
-static bool SPIDefaultReset( struct SSD13x6_Device* DeviceHandle );
-
-bool SSD13x6_SPIMasterInitDefault( int SPI, int DC ) {
-	SPIHost = SPI;
-	DCPin = DC;
-    return true;
-}
-
-bool SSD13x6_SPIMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle, int Model, int Width, int Height, int CSPin, int RSTPin, int Speed ) {
-    spi_device_interface_config_t SPIDeviceConfig;
-    spi_device_handle_t SPIDeviceHandle;
-
-    NullCheck( DeviceHandle, return false );
-	
-	if (CSPin >= 0) {
-		ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( CSPin, GPIO_MODE_OUTPUT ), return false );
-		ESP_ERROR_CHECK_NONFATAL( gpio_set_level( CSPin, 0 ), return false );
-	}	
-
-    memset( &SPIDeviceConfig, 0, sizeof( spi_device_interface_config_t ) );
-
-    SPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_8M;
-    SPIDeviceConfig.spics_io_num = CSPin;
-    SPIDeviceConfig.queue_size = 1;
-
-    if ( RSTPin >= 0 ) {
-        ESP_ERROR_CHECK_NONFATAL( gpio_set_direction( RSTPin, GPIO_MODE_OUTPUT ), return false );
-        ESP_ERROR_CHECK_NONFATAL( gpio_set_level( RSTPin, 0 ), return false );
-    }
-
-    ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDeviceHandle ), return false );
-
-	memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );	
-	DeviceHandle->Model = Model;
-		
-    return SSD13x6_Init_SPI( DeviceHandle,
-        Width,
-        Height,
-        RSTPin,
-        CSPin,
-        SPIDeviceHandle,
-        SPIDefaultWriteCommand,
-        SPIDefaultWriteData,
-        SPIDefaultReset
-    );
-}
-
-static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ) {
-    spi_transaction_t SPITransaction = { 0 };
-
-    NullCheck( SPIHandle, return false );
-    NullCheck( Data, return false );
-
-    if ( DataLength > 0 ) {
-		gpio_set_level( DCPin, WriteMode );
-		
-		SPITransaction.length = DataLength * 8;
-		SPITransaction.tx_buffer = Data;
-            
-		// only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes)		
-		ESP_ERROR_CHECK_NONFATAL( spi_device_polling_transmit(SPIHandle, &SPITransaction), return false );
-    }
-
-    return true;
-}
-
-static bool SPIDefaultWriteCommand( struct SSD13x6_Device* DeviceHandle, SSDCmd Command ) {
-    static uint8_t CommandByte = 0;
-
-    NullCheck( DeviceHandle, return false );
-    NullCheck( DeviceHandle->SPIHandle, return false );
-
-    CommandByte = Command;
-
-    return SPIDefaultWriteBytes( DeviceHandle->SPIHandle, SSD13x6_SPI_Command_Mode, &CommandByte, 1 );
-}
-
-static bool SPIDefaultWriteData( struct SSD13x6_Device* DeviceHandle, const uint8_t* Data, size_t DataLength ) {
-    NullCheck( DeviceHandle, return false );
-    NullCheck( DeviceHandle->SPIHandle, return false );
-
-    return SPIDefaultWriteBytes( DeviceHandle->SPIHandle, SSD13x6_SPI_Data_Mode, Data, DataLength );
-}
-
-static bool SPIDefaultReset( struct SSD13x6_Device* DeviceHandle ) {
-    NullCheck( DeviceHandle, return false );
-
-    if ( DeviceHandle->RSTPin >= 0 ) {
-        ESP_ERROR_CHECK_NONFATAL( gpio_set_level( DeviceHandle->RSTPin, 0 ), return false );
-            vTaskDelay( pdMS_TO_TICKS( 100 ) );
-        ESP_ERROR_CHECK_NONFATAL( gpio_set_level( DeviceHandle->RSTPin, 1 ), return false );
-    }
-
-    return true;
-}
-

+ 0 - 351
components/display/tarablessd13x6/ssd13x6.c

@@ -1,351 +0,0 @@
-/**
- * Copyright (c) 2017-2018 Tara Keeling
- * 
- * This software is released under the MIT License.
- * https://opensource.org/licenses/MIT
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <math.h>
-#include <esp_heap_caps.h>
-
-#include "ssd13x6.h"
-
-#define SHADOW_BUFFER
-
-// used by both but different
-static uint8_t SSDCmd_Set_Display_Start_Line;
-static uint8_t SSDCmd_Set_Display_Offset;
-static uint8_t SSDCmd_Set_Column_Address;
-static uint8_t SSDCmd_Set_Display_CLK;
-static uint8_t SSDCmd_Set_Page_Address;
-
-// misc boundaries
-static uint8_t SSD13x6_Max_Col;
-static const uint8_t SSD13x6_Max_Row = 7;
-
-static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int Height );
-
-int  SSD13x6_GetCaps( struct SSD13x6_Device* DeviceHandle ) {
-	if (DeviceHandle->Model == SH1106) return 0;
-	else return CAPS_COLUMN_RANGE | CAPS_PAGE_RANGE	| CAPS_ADDRESS_VERTICAL;
-}
-
-bool SSD13x6_WriteCommand( struct SSD13x6_Device* DeviceHandle, SSDCmd SSDCommand ) {
-    NullCheck( DeviceHandle->WriteCommand, return false );
-    return ( DeviceHandle->WriteCommand ) ( DeviceHandle, SSDCommand );
-}
-
-bool SSD13x6_WriteData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
-    NullCheck( DeviceHandle->WriteData, return false );
-    return ( DeviceHandle->WriteData ) ( DeviceHandle, Data, DataLength );
-}
-
-void SSD13x6_SetMuxRatio( struct SSD13x6_Device* DeviceHandle, uint8_t Ratio ) {
-    SSD13x6_WriteCommand( DeviceHandle, 0xA8 );
-    SSD13x6_WriteCommand( DeviceHandle, Ratio );
-}
-
-void SSD13x6_SetDisplayOffset( struct SSD13x6_Device* DeviceHandle, uint8_t Offset ) {
-    SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Display_Offset );
-    SSD13x6_WriteCommand( DeviceHandle, Offset );
-}
-
-void SSD13x6_SetDisplayStartLine( struct SSD13x6_Device* DeviceHandle, int Line ) {
-    SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Display_Start_Line + ( uint32_t ) ( Line & 0x1F ) );
-}
-
-void SSD13x6_SetContrast( struct SSD13x6_Device* DeviceHandle, uint8_t Contrast ) {
-    SSD13x6_WriteCommand( DeviceHandle, 0x81 );
-    SSD13x6_WriteCommand( DeviceHandle, Contrast );
-}
-
-void SSD13x6_EnableDisplayRAM( struct SSD13x6_Device* DeviceHandle ) {
-    SSD13x6_WriteCommand( DeviceHandle, 0xA4 );
-}
-
-void SSD13x6_DisableDisplayRAM( struct SSD13x6_Device* DeviceHandle ) {
-    SSD13x6_WriteCommand( DeviceHandle, 0xA5 );
-}
-
-void SSD13x6_SetInverted( struct SSD13x6_Device* DeviceHandle, bool Inverted ) {
-    SSD13x6_WriteCommand( DeviceHandle, Inverted ? 0xA7 : 0xA6 );
-}
-
-void SSD13x6_SetDisplayClocks( struct SSD13x6_Device* DeviceHandle, uint32_t DisplayClockDivider, uint32_t OSCFrequency ) {
-    DisplayClockDivider&= 0x0F;
-    OSCFrequency&= 0x0F;
-    SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Display_CLK );
-    SSD13x6_WriteCommand( DeviceHandle, ( ( OSCFrequency << 4 ) | DisplayClockDivider ) );
-}
-
-void SSD13x6_DisplayOn( struct SSD13x6_Device* DeviceHandle ) {
-    SSD13x6_WriteCommand( DeviceHandle, 0xAF );
-}
-
-void SSD13x6_DisplayOff( struct SSD13x6_Device* DeviceHandle ) {
-    SSD13x6_WriteCommand( DeviceHandle, 0xAE );
-}
-
-void SSD132x_ReMap( struct SSD13x6_Device* DeviceHandle ) {
-	SSD13x6_WriteCommand( DeviceHandle, 0xA0 );
-	SSD13x6_WriteCommand( DeviceHandle, DeviceHandle->ReMap );
-}
-
-void SSD13x6_SetDisplayAddressMode( struct SSD13x6_Device* DeviceHandle, SSD13x6_AddressMode AddressMode ) {
-	switch (DeviceHandle->Model) {
-	case SH1106:
-		// does not exist on SH1106
-		break;
-	case SSD1306:
-		SSD13x6_WriteCommand( DeviceHandle, 0x20 );
-		SSD13x6_WriteCommand( DeviceHandle, AddressMode );
-		break;
-	case SSD1326:
-		DeviceHandle->ReMap = (AddressMode == AddressMode_Horizontal) ? (DeviceHandle->ReMap & ~0x80) : (DeviceHandle->ReMap | 0x80);
-		SSD132x_ReMap(DeviceHandle);
-		break;
-	}
-}
-
-void SSD13x6_Update( struct SSD13x6_Device* DeviceHandle ) {
-#ifdef SHADOW_BUFFER
-	// not sure the compiler does not have to redo all calculation in for loops, so local it is
-	int width = DeviceHandle->Width, rows = DeviceHandle->Height / 8;
-	uint8_t *optr = DeviceHandle->Shadowbuffer, *iptr = DeviceHandle->Framebuffer;
-	
-	// by row, find first and last columns that have been updated
-	for (int r = 0; r < rows; r++) {
-		uint8_t first = 0, last;	
-		for (int c = 0; c < width; c++) {
-			if (*iptr != *optr) {
-				if (!first) first = c + 1;
-				last = c ;
-			}	
-			*optr++ = *iptr++;
-		}
-		
-		// now update the display by "byte rows"
-		if (first--) {
-			SSD13x6_SetColumnAddress( DeviceHandle, first, last );
-			SSD13x6_SetPageAddress( DeviceHandle, r, r);
-			SSD13x6_WriteData( DeviceHandle, DeviceHandle->Shadowbuffer + r*width + first, last - first + 1);
-		}
-	}	
-#else	
-	if (DeviceHandle->Model == SH1106) {
-		// SH1106 requires a page-by-page update and has no end Page/Column
-		for (int i = 0; i < DeviceHandle->Height / 8 ; i++) {
-			SSD13x6_SetPageAddress( DeviceHandle, i, 0);
-			SSD13x6_SetColumnAddress( DeviceHandle, 0, 0);			
-			SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer + i*DeviceHandle->Width, DeviceHandle->Width );
-		}	
-	} else {	
-		// others have an automatic counter and end Page/Column
-		SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1);
-		SSD13x6_SetPageAddress( DeviceHandle, 0, DeviceHandle->Height / 8 - 1);
-		SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer, DeviceHandle->FramebufferSize );
-	}	
-#endif	
-}
-
-void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
-    NullCheck( Data, return );
-    DataLength = DataLength > DeviceHandle->FramebufferSize ? DeviceHandle->FramebufferSize : DataLength;
-    if ( DataLength > 0 ) SSD13x6_WriteData( DeviceHandle, Data, DataLength );
-}
-
-void SSD13x6_SetHFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
-	switch (DeviceHandle->Model) {
-	case SH1106:		
-	case SSD1306:	
-		SSD13x6_WriteCommand( DeviceHandle, On ? 0xA1 : 0xA0 );
-		break;
-	case SSD1326:
-		DeviceHandle->ReMap = On ? (DeviceHandle->ReMap | 0x01) : (DeviceHandle->ReMap & ~0x01);
-		SSD132x_ReMap(DeviceHandle);
-		break;
-	}	
-}
-
-void SSD13x6_SetVFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
-	switch (DeviceHandle->Model) {
-	case SH1106:	
-	case SSD1306:	
-		SSD13x6_WriteCommand( DeviceHandle, On ? 0xC8 : 0xC0 );
-		break;
-	case SSD1326:
-		DeviceHandle->ReMap = On ? (DeviceHandle->ReMap | 0x05) : (DeviceHandle->ReMap & ~0x05);
-		SSD132x_ReMap( DeviceHandle );
-		break;
-	}	
-}
-
-void SSD13x6_SetColumnAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
-    CheckBounds( Start > SSD13x6_Max_Col, return );
-    CheckBounds( End > SSD13x6_Max_Col, return );
-	
-	// on SH1106, there is no "end column"
-	if (DeviceHandle->Model == SH1106) {
-		// well, unfortunately this driver is 132 colums but most displays are 128...
-		if (DeviceHandle->Width != 132) Start += 2;
-		SSD13x6_WriteCommand( DeviceHandle, 0x10 | (Start >> 4) );
-		SSD13x6_WriteCommand( DeviceHandle, 0x00 | (Start & 0x0f) );
-	} else {	
-		SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Column_Address );
-		SSD13x6_WriteCommand( DeviceHandle, Start );
-		SSD13x6_WriteCommand( DeviceHandle, End );
-	}	
-}
-
-void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
-    NullCheck( DeviceHandle, return );
-
-    CheckBounds( Start > SSD13x6_Max_Row, return );
-    CheckBounds( End > SSD13x6_Max_Row, return );
-	
-	// on SH1106, there is no "end page"
-	if (DeviceHandle->Model == SH1106) {
-			SSD13x6_WriteCommand( DeviceHandle, 0xB0 | Start );			
-	} else {	
-		// in case of SSD1326, this is sub-optimal as it can address by line, not by page
-		if (DeviceHandle->Model != SSD1306) {
-			Start *= 8;
-			End = (End + 1) * 8 - 1;
-		}
-	
-		SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Page_Address );	
-		SSD13x6_WriteCommand( DeviceHandle, Start );
-		SSD13x6_WriteCommand( DeviceHandle, End );
-	}	
-}
-
-bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle ) {
-    NullCheck( DeviceHandle, return 0 );
-
-    if ( DeviceHandle->Reset != NULL ) {
-        return ( DeviceHandle->Reset ) ( DeviceHandle );
-    }
-
-    /* This should always return true if there is no reset callback as
-     * no error would have occurred during the non existant reset.
-     */
-    return true;
-}
-
-static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int Height ) {
-    DeviceHandle->Width = Width;
-    DeviceHandle->Height = Height;
-	
-#ifdef SHADOW_BUFFER
-	DeviceHandle->Shadowbuffer = heap_caps_malloc( DeviceHandle->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
-	memset( DeviceHandle->Shadowbuffer, 0xFF, DeviceHandle->FramebufferSize );
-#endif	
-	
-	SSD13x6_HWReset( DeviceHandle );
-	SSD13x6_DisplayOff( DeviceHandle );
-
-	if (DeviceHandle->Model == SSD1306 || DeviceHandle->Model == SH1106) {
-		SSDCmd_Set_Display_Start_Line = 0x40;
-		SSDCmd_Set_Display_Offset = 0xD3;
-		SSDCmd_Set_Column_Address = 0x21,
-		SSDCmd_Set_Display_CLK = 0xD5;
-		SSDCmd_Set_Page_Address = 0x22;		
-		SSD13x6_Max_Col = 127;
-		
-		if (DeviceHandle->Model == SSD1306) {
-			// charge pump regulator, do direct init
-			SSD13x6_WriteCommand( DeviceHandle, 0x8D );
-			SSD13x6_WriteCommand( DeviceHandle, 0x14 ); 
-			
-			// COM pins HW config (alternative:EN if 64, DIS if 32, remap:DIS) - some display might need something difference
-			SSD13x6_WriteCommand( DeviceHandle, 0xDA );
-			SSD13x6_WriteCommand( DeviceHandle, ((Height == 64 ? 1 : 0) << 4) | (0 < 5) );
-
-		} else {
-			// charge pump regulator, do direct init
-			SSD13x6_WriteCommand( DeviceHandle, 0xAD );
-			SSD13x6_WriteCommand( DeviceHandle, 0x8B ); 
-			
-			// COM pins HW config (alternative:EN) - some display might need something difference
-			SSD13x6_WriteCommand( DeviceHandle, 0xDA );
-			SSD13x6_WriteCommand( DeviceHandle, 1 << 4);
-		}
-
-	} else if (DeviceHandle->Model == SSD1326) {
-		SSDCmd_Set_Display_Start_Line = 0xA1;
-		SSDCmd_Set_Display_Offset = 0xA2;
-		SSDCmd_Set_Column_Address = 0x15;
-		SSDCmd_Set_Display_CLK = 0xB3;
-		SSDCmd_Set_Page_Address = 0x75;		// not really a page but a row
-		
-		SSD13x6_Max_Col = 255;
-		
-		// no gray scale
-		DeviceHandle->ReMap |= 0x10;
-		SSD132x_ReMap( DeviceHandle );
-	}
-
-	SSD13x6_SetMuxRatio( DeviceHandle, Height - 1 );
-    SSD13x6_SetDisplayOffset( DeviceHandle, 0x00 );
-	SSD13x6_SetDisplayStartLine( DeviceHandle, 0 );
-	SSD13x6_SetContrast( DeviceHandle, 0x7F );
-    SSD13x6_DisableDisplayRAM( DeviceHandle );
-	SSD13x6_SetVFlip( DeviceHandle, false );
-	SSD13x6_SetHFlip( DeviceHandle, false );
-	SSD13x6_SetInverted( DeviceHandle, false );
-    SSD13x6_SetDisplayClocks( DeviceHandle, 0, 8 );
-	SSD13x6_SetDisplayAddressMode( DeviceHandle, AddressMode_Horizontal );
-    SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1 );
-    SSD13x6_SetPageAddress( DeviceHandle, 0, ( DeviceHandle->Height / 8 ) - 1 );
-	SSD13x6_EnableDisplayRAM( DeviceHandle );
-    SSD13x6_DisplayOn( DeviceHandle );
-	SSD13x6_Update( DeviceHandle );
-
-    return true;
-}
-
-bool SSD13x6_Init_I2C( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int I2CAddress, int ResetPin, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset ) {
-    NullCheck( DeviceHandle, return false );
-    NullCheck( WriteCommand, return false );
-    NullCheck( WriteData, return false );
-
-    DeviceHandle->WriteCommand = WriteCommand;
-    DeviceHandle->WriteData = WriteData;
-    DeviceHandle->Reset = Reset;
-    DeviceHandle->Address = I2CAddress;
-    DeviceHandle->RSTPin = ResetPin;
-	
-	DeviceHandle->FramebufferSize = ( Width * Height ) / 8;
-	DeviceHandle->Framebuffer = calloc( 1, DeviceHandle->FramebufferSize );
-    NullCheck( DeviceHandle->Framebuffer, return false );
-    
-    return SSD13x6_Init( DeviceHandle, Width, Height );
-}
-
-bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int ResetPin, int CSPin, spi_device_handle_t SPIHandle, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset ) {
-    NullCheck( DeviceHandle, return false );
-    NullCheck( WriteCommand, return false );
-    NullCheck( WriteData, return false );
-
-    DeviceHandle->WriteCommand = WriteCommand;
-    DeviceHandle->WriteData = WriteData;
-    DeviceHandle->Reset = Reset;
-    DeviceHandle->SPIHandle = SPIHandle;
-    DeviceHandle->RSTPin = ResetPin;
-    DeviceHandle->CSPin = CSPin;
-	
-	DeviceHandle->FramebufferSize = ( Width * Height ) / 8;
-#ifdef SHADOW_BUFFER	
-	DeviceHandle->Framebuffer = calloc( 1, DeviceHandle->FramebufferSize );
-#else	
-    DeviceHandle->Framebuffer = heap_caps_calloc( 1, DeviceHandle->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
-#endif
-    NullCheck( DeviceHandle->Framebuffer, return false );
-	
-    return SSD13x6_Init( DeviceHandle, Width, Height );
-}

+ 0 - 99
components/display/tarablessd13x6/ssd13x6.h

@@ -1,99 +0,0 @@
-#ifndef _SSD13X6_H_
-#define _SSD13X6_H_
-
-/* For uint(X)_t */
-#include <stdint.h>
-
-/* For booooool */
-#include <stdbool.h>
-
-#include "sdkconfig.h"
-#include "ssd13x6_err.h"
-
-#define SSD_ALWAYS_INLINE __attribute__( ( always_inline ) )
-
-#define CAPS_COLUMN_RANGE		0x01
-#define CAPS_PAGE_RANGE			0x02
-#define CAPS_ADDRESS_VERTICAL	0x04
-
-#if ! defined BIT
-#define BIT( n ) ( 1 << n )
-#endif
-
-typedef uint8_t SSDCmd;
-
-typedef enum {
-    AddressMode_Horizontal = 0,
-    AddressMode_Vertical,
-    AddressMode_Page,
-    AddressMode_Invalid
-} SSD13x6_AddressMode;
-
-struct SSD13x6_Device;
-
-/*
- * These can optionally return a succeed/fail but are as of yet unused in the driver.
- */
-typedef bool ( *WriteCommandProc ) ( struct SSD13x6_Device* DeviceHandle, SSDCmd Command );
-typedef bool ( *WriteDataProc ) ( struct SSD13x6_Device* DeviceHandle, const uint8_t* Data, size_t DataLength );
-typedef bool ( *ResetProc ) ( struct SSD13x6_Device* DeviceHandle );
-
-struct spi_device_t;
-typedef struct spi_device_t* spi_device_handle_t;
-
-struct SSD13x6_FontDef;
-
-struct SSD13x6_Device {
-    /* I2C Specific */
-    int Address;
-
-    /* SPI Specific */
-    spi_device_handle_t SPIHandle;
-    int RSTPin;
-    int CSPin;
-
-    /* Everything else */
-    int Width;
-    int Height;
-
-	enum { SSD1306, SSD1326, SH1106 } Model;
-	uint8_t ReMap;
-    uint8_t* Framebuffer, *Shadowbuffer;
-    int FramebufferSize;
-
-    WriteCommandProc WriteCommand;
-    WriteDataProc WriteData;
-    ResetProc Reset;
-
-    const struct SSD13x6_FontDef* Font;
-    bool FontForceProportional;
-    bool FontForceMonospace;
-};
-
-void SSD13x6_SetMuxRatio( struct SSD13x6_Device* DeviceHandle, uint8_t Ratio );
-void SSD13x6_SetDisplayOffset( struct SSD13x6_Device* DeviceHandle, uint8_t Offset );
-void SSD13x6_SetDisplayStartLines( struct SSD13x6_Device* DeviceHandle );
-
-void SSD13x6_SetSegmentRemap( struct SSD13x6_Device* DeviceHandle, bool Remap );
-
-void SSD13x6_SetContrast( struct SSD13x6_Device* DeviceHandle, uint8_t Contrast );
-void SSD13x6_EnableDisplayRAM( struct SSD13x6_Device* DeviceHandle );
-void SSD13x6_DisableDisplayRAM( struct SSD13x6_Device* DeviceHandle );
-void SSD13x6_SetInverted( struct SSD13x6_Device* DeviceHandle, bool Inverted );
-void SSD13x6_SetHFlip( struct SSD13x6_Device* DeviceHandle, bool On );
-void SSD13x6_SetVFlip( struct SSD13x6_Device* DeviceHandle, bool On );
-void SSD13x6_DisplayOn( struct SSD13x6_Device* DeviceHandle );
-void SSD13x6_DisplayOff( struct SSD13x6_Device* DeviceHandle ); 
-void SSD13x6_SetDisplayAddressMode( struct SSD13x6_Device* DeviceHandle, SSD13x6_AddressMode AddressMode );
-void SSD13x6_Update( struct SSD13x6_Device* DeviceHandle );
-void SSD13x6_SetDisplayClocks( struct SSD13x6_Device* DeviceHandle, uint32_t DisplayClockDivider, uint32_t OSCFrequency );
-void SSD13x6_SetColumnAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End );
-void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End );
-bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle );
-bool SSD13x6_Init_I2C( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int I2CAddress, int ResetPin, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset );
-bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int ResetPin, int CSPin, spi_device_handle_t SPIHandle, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset );
-int  SSD13x6_GetCaps( struct SSD13x6_Device* DeviceHandle );
-
-void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength );
-
-#endif

+ 0 - 18
components/display/tarablessd13x6/ssd13x6_default_if.h

@@ -1,18 +0,0 @@
-#ifndef _SSD13x6_DEFAULT_IF_H_
-#define _SSD13x6_DEFAULT_IF_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-bool SSD13x6_I2CMasterInitDefault( int PortNumber, int SDA, int SCL );
-bool SSD13x6_I2CMasterAttachDisplayDefault( struct SSD13x6_Device* DisplayHandle, int Model, int Width, int Height, int I2CAddress, int RSTPin );
-
-bool SSD13x6_SPIMasterInitDefault( int SPI, int DC);
-bool SSD13x6_SPIMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle, int Model, int Width, int Height, int CSPin, int RSTPin, int Speed );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 0 - 253
components/display/tarablessd13x6/ssd13x6_draw.c

@@ -1,253 +0,0 @@
-/**
- * Copyright (c) 2017-2018 Tara Keeling
- * 
- * This software is released under the MIT License.
- * https://opensource.org/licenses/MIT
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <math.h>
-#include <esp_attr.h>
-
-#include "ssd13x6.h"
-#include "ssd13x6_draw.h"
-
-#undef NullCheck
-#define NullCheck(X,Y)
-
-__attribute__( ( always_inline ) ) static inline bool IsPixelVisible( struct SSD13x6_Device* DeviceHandle, int x, int y )  {
-    bool Result = (
-        ( x >= 0 ) &&
-        ( x < DeviceHandle->Width ) &&
-        ( y >= 0 ) &&
-        ( y < DeviceHandle->Height )
-    ) ? true : false;
-
-#if CONFIG_SSD13x6_CLIPDEBUG > 0
-    if ( Result == false ) {
-        ClipDebug( x, y );
-    }
-#endif
-
-    return Result;
-}
-
-__attribute__( ( always_inline ) ) static inline void SwapInt( int* a, int* b ) {
-    int Temp = *b;
-
-    *b = *a;
-    *a = Temp;
-}
-
-inline void IRAM_ATTR SSD13x6_DrawPixelFast( struct SSD13x6_Device* DeviceHandle, int X, int Y, int Color ) {
-    uint32_t YBit = ( Y & 0x07 );
-    uint8_t* FBOffset = NULL;
-
-    /* 
-     * We only need to modify the Y coordinate since the pitch
-     * of the screen is the same as the width.
-     * Dividing Y by 8 gives us which row the pixel is in but not
-     * the bit position.
-     */
-    Y>>= 3;
-
-    FBOffset = DeviceHandle->Framebuffer + ( ( Y * DeviceHandle->Width ) + X );
-
-    if ( Color == SSD_COLOR_XOR ) {
-        *FBOffset ^= BIT( YBit );
-    } else {
-        *FBOffset = ( Color == SSD_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
-    }
-}
-
-void IRAM_ATTR SSD13x6_DrawPixel( struct SSD13x6_Device* DeviceHandle, int x, int y, int Color ) {
-    NullCheck( DeviceHandle, return );
-
-    if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
-        SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
-    }
-}
-
-void IRAM_ATTR SSD13x6_DrawHLine( struct SSD13x6_Device* DeviceHandle, int x, int y, int Width, int Color ) {
-    int XEnd = x + Width;
-
-    NullCheck( DeviceHandle, return );
-    NullCheck( DeviceHandle->Framebuffer, return );
-
-    for ( ; x < XEnd; x++ ) {
-        if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
-            SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
-        } else {
-            break;
-        }
-    }
-}
-
-void IRAM_ATTR SSD13x6_DrawVLine( struct SSD13x6_Device* DeviceHandle, int x, int y, int Height, int Color ) {
-    int YEnd = y + Height;
-
-    NullCheck( DeviceHandle, return );
-    NullCheck( DeviceHandle->Framebuffer, return );
-
-    for ( ; y < YEnd; y++ ) {
-        if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
-            SSD13x6_DrawPixel( DeviceHandle, x, y, Color );
-        } else {
-            break;
-        }
-    }
-}
-
-static inline void IRAM_ATTR DrawWideLine( struct SSD13x6_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
-    int dx = ( x1 - x0 );
-    int dy = ( y1 - y0 );
-    int Error = 0;
-    int Incr = 1;
-    int x = x0;
-    int y = y0;
-
-    if ( dy < 0 ) {
-        Incr = -1;
-        dy = -dy;
-    }
-
-    Error = ( dy * 2 ) - dx;
-
-    for ( ; x < x1; x++ ) {
-        if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
-            SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
-        }
-
-        if ( Error > 0 ) {
-            Error-= ( dx * 2 );
-            y+= Incr;
-        }
-
-        Error+= ( dy * 2 );
-    }
-}
-
-static inline void IRAM_ATTR DrawTallLine( struct SSD13x6_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
-    int dx = ( x1 - x0 );
-    int dy = ( y1 - y0 );
-    int Error = 0;
-    int Incr = 1;
-    int x = x0;
-    int y = y0;
-
-    if ( dx < 0 ) {
-        Incr = -1;
-        dx = -dx;
-    }
-
-    Error = ( dx * 2 ) - dy;
-
-    for ( ; y < y1; y++ ) {
-        if ( IsPixelVisible( DeviceHandle, x, y ) == true ) {
-            SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color );
-        }
-
-        if ( Error > 0 ) {
-            Error-= ( dy * 2 );
-            x+= Incr;
-        }
-
-        Error+= ( dx * 2 );
-    }
-}
-
-void IRAM_ATTR SSD13x6_DrawLine( struct SSD13x6_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color ) {
-    NullCheck( DeviceHandle, return );
-    NullCheck( DeviceHandle->Framebuffer, return );
-
-    if ( x0 == x1 ) {
-        SSD13x6_DrawVLine( DeviceHandle, x0, y0, ( y1 - y0 ), Color );
-    } else if ( y0 == y1 ) {
-        SSD13x6_DrawHLine( DeviceHandle, x0, y0, ( x1 - x0 ), Color );
-    } else {
-        if ( abs( x1 - x0 ) > abs( y1 - y0 ) ) {
-            /* Wide ( run > rise ) */
-            if ( x0 > x1 ) {
-                SwapInt( &x0, &x1 );
-                SwapInt( &y0, &y1 );
-            }
-
-            DrawWideLine( DeviceHandle, x0, y0, x1, y1, Color );
-        } else {
-            /* Tall ( rise > run ) */
-            if ( y0 > y1 ) {
-                SwapInt( &y0, &y1 );
-                SwapInt( &x0, &x1 );
-            }
-
-            DrawTallLine( DeviceHandle, x0, y0, x1, y1, Color );
-        }
-    }
-}
-
-void IRAM_ATTR SSD13x6_DrawBox( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color, bool Fill ) {
-    int Width = ( x2 - x1 );
-    int Height = ( y2 - y1 );
-
-    NullCheck( DeviceHandle, return );
-    NullCheck( DeviceHandle->Framebuffer, return );
-
-    if ( Fill == false ) {
-        /* Top side */
-        SSD13x6_DrawHLine( DeviceHandle, x1, y1, Width, Color );
-
-        /* Bottom side */
-        SSD13x6_DrawHLine( DeviceHandle, x1, y1 + Height, Width, Color );
-
-        /* Left side */
-        SSD13x6_DrawVLine( DeviceHandle, x1, y1, Height, Color );
-
-        /* Right side */
-        SSD13x6_DrawVLine( DeviceHandle, x1 + Width, y1, Height, Color );
-    } else {
-        /* Fill the box by drawing horizontal lines */
-        for ( ; y1 <= y2; y1++ ) {
-            SSD13x6_DrawHLine( DeviceHandle, x1, y1, Width, Color );
-        }
-    }
-}
-
-void SSD13x6_Clear( struct SSD13x6_Device* DeviceHandle, int Color ) {
-    NullCheck( DeviceHandle, return );
-    NullCheck( DeviceHandle->Framebuffer, return );
-
-    memset( DeviceHandle->Framebuffer, Color, DeviceHandle->FramebufferSize );
-}
-
-void SSD13x6_ClearWindow( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color ) {
-    NullCheck( DeviceHandle, return );
-    NullCheck( DeviceHandle->Framebuffer, return );
-	
-/*	
-	int xr = ((x1 - 1) / 8) + 1 ) * 8;
-	int xl = (x2 / 8) * 8;
-	
-	for (int y = y1; y <= y2; y++) {
-		for (int x = x1; x < xr; x++) SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
-		if (xl > xr) memset( DeviceHandle->Framebuffer + (y / 8) * DeviceHandle->Width + xr, 0, xl - xr );
-		for (int x = xl; x <= x2; x++) SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
-	}
-	
-	return;
-*/	
-		
-	// cheap optimization on boundaries
-	if (x1 == 0 && x2 == DeviceHandle->Width - 1 && y1 % 8 == 0 && (y2 + 1) % 8 == 0) {
-		memset( DeviceHandle->Framebuffer + (y1 / 8) * DeviceHandle->Width, 0, (y2 - y1 + 1) / 8 * DeviceHandle->Width );
-	} else {
-		for (int y = y1; y <= y2; y++) {
-			for (int x = x1; x <= x2; x++) {
-				SSD13x6_DrawPixelFast( DeviceHandle, x, y, Color);
-			}		
-		}	
-	}	
-}

+ 0 - 54
components/display/tarablessd13x6/ssd13x6_draw.h

@@ -1,54 +0,0 @@
-#ifndef _SSD13x6_DRAW_H_
-#define _SSD13x6_DRAW_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "sdkconfig.h"
-
-#define SSD13x6_CLIPDEBUG_NONE 0
-#define SSD13x6_CLIPDEBUG_WARNING 1
-#define SSD13x6_CLIPDEBUG_ERROR 2
-
-#if CONFIG_SSD13x6_CLIPDEBUG == SSD13x6_CLIPDEBUG_NONE
-    /*
-     * Clip silently with no console output.
-     */
-    #define ClipDebug( x, y )
-#elif CONFIG_SSD13x6_CLIPDEBUG == SSD13x6_CLIPDEBUG_WARNING
-    /*
-     * Log clipping to the console as a warning.
-     */
-    #define ClipDebug( x, y ) { \
-        ESP_LOGW( __FUNCTION__, "Line %d: Pixel at %d, %d CLIPPED", __LINE__, x, y ); \
-    }
-#elif CONFIG_SSD13x6_CLIPDEBUG == SSD13x6_CLIPDEBUG_ERROR
-    /*
-     * Log clipping as an error to the console.
-     * Also invokes an abort with stack trace.
-     */
-    #define ClipDebug( x, y ) { \
-        ESP_LOGE( __FUNCTION__, "Line %d: Pixel at %d, %d CLIPPED, ABORT", __LINE__, x, y ); \
-        abort( ); \
-    }
-#endif
-
-#define SSD_COLOR_BLACK 0
-#define SSD_COLOR_WHITE 1
-#define SSD_COLOR_XOR 2
-
-void SSD13x6_Clear( struct SSD13x6_Device* DeviceHandle, int Color );
-void SSD13x6_ClearWindow( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color );
-void SSD13x6_DrawPixel( struct SSD13x6_Device* DeviceHandle, int X, int Y, int Color );
-void SSD13x6_DrawPixelFast( struct SSD13x6_Device* DeviceHandle, int X, int Y, int Color );
-void SSD13x6_DrawHLine( struct SSD13x6_Device* DeviceHandle, int x, int y, int Width, int Color );
-void SSD13x6_DrawVLine( struct SSD13x6_Device* DeviceHandle, int x, int y, int Height, int Color );
-void SSD13x6_DrawLine( struct SSD13x6_Device* DeviceHandle, int x0, int y0, int x1, int y1, int Color );
-void SSD13x6_DrawBox( struct SSD13x6_Device* DeviceHandle, int x1, int y1, int x2, int y2, int Color, bool Fill );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 0 - 91
components/display/tarablessd13x6/ssd13x6_font.h

@@ -1,91 +0,0 @@
-#ifndef _SSD13x6_FONT_H_
-#define _SSD13x6_FONT_H_
-
-#include <stdint.h>
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct SSD13x6_Device;
-
-/* 
- * X-GLCD Font format:
- *
- * First byte of glyph is it's width in pixels.
- * Each data byte represents 8 pixels going down from top to bottom.
- * 
- * Example glyph layout for a 16x16 font
- * 'a': [Glyph width][Pixel column 0][Pixel column 1] where the number of pixel columns is the font height divided by 8
- * 'b': [Glyph width][Pixel column 0][Pixel column 1]...
- * 'c': And so on...
- */
-
-struct SSD13x6_FontDef {
-    const uint8_t* FontData;
-
-    int Width;
-    int Height;
-
-    int StartChar;
-    int EndChar;
-
-    bool Monospace;
-};
-
-typedef enum {
-    TextAnchor_East = 0,
-    TextAnchor_West,
-    TextAnchor_North,
-    TextAnchor_South,
-    TextAnchor_NorthEast,
-    TextAnchor_NorthWest,
-    TextAnchor_SouthEast,
-    TextAnchor_SouthWest,
-    TextAnchor_Center
-} TextAnchor;
-
-bool SSD13x6_SetFont( struct SSD13x6_Device* Display, const struct SSD13x6_FontDef* Font );
-
-void SSD13x6_FontForceProportional( struct SSD13x6_Device* Display, bool Force );
-void SSD13x6_FontForceMonospace( struct SSD13x6_Device* Display, bool Force );
-
-int SSD13x6_FontGetWidth( struct SSD13x6_Device* Display );
-int SSD13x6_FontGetHeight( struct SSD13x6_Device* Display );
-
-int SSD13x6_FontGetMaxCharsPerRow( struct SSD13x6_Device* Display );
-int SSD13x6_FontGetMaxCharsPerColumn( struct SSD13x6_Device* Display );
-
-int SSD13x6_FontGetCharWidth( struct SSD13x6_Device* Display, char Character );
-int SSD13x6_FontGetCharHeight( struct SSD13x6_Device* Display );
-int SSD13x6_FontMeasureString( struct SSD13x6_Device* Display, const char* Text );\
-
-void SSD13x6_FontDrawChar( struct SSD13x6_Device* Display, char Character, int x, int y, int Color );
-void SSD13x6_FontDrawString( struct SSD13x6_Device* Display, int x, int y, const char* Text, int Color );
-void SSD13x6_FontDrawAnchoredString( struct SSD13x6_Device* Display, TextAnchor Anchor, const char* Text, int Color );
-void SSD13x6_FontGetAnchoredStringCoords( struct SSD13x6_Device* Display, int* OutX, int* OutY, TextAnchor Anchor, const char* Text );
-
-extern const struct SSD13x6_FontDef Font_droid_sans_fallback_11x13;
-extern const struct SSD13x6_FontDef Font_droid_sans_fallback_15x17;
-extern const struct SSD13x6_FontDef Font_droid_sans_fallback_24x28;
-
-extern const struct SSD13x6_FontDef Font_droid_sans_mono_7x13;
-extern const struct SSD13x6_FontDef Font_droid_sans_mono_13x24;
-extern const struct SSD13x6_FontDef Font_droid_sans_mono_16x31;
-
-extern const struct SSD13x6_FontDef Font_liberation_mono_9x15;
-extern const struct SSD13x6_FontDef Font_liberation_mono_13x21;
-extern const struct SSD13x6_FontDef Font_liberation_mono_17x30;
-
-extern const struct SSD13x6_FontDef Font_Tarable7Seg_16x32;
-extern const struct SSD13x6_FontDef Font_Tarable7Seg_32x64;
-
-extern const struct SSD13x6_FontDef Font_line_1;
-extern const struct SSD13x6_FontDef Font_line_2;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 11 - 6
components/raop/raop.c

@@ -55,7 +55,7 @@ typedef struct raop_ctx_s {
 	short unsigned port;    // RTSP port for AirPlay
 	int sock;               // socket of the above
 	struct in_addr peer;	// IP of the iDevice (airplay sender)
-	bool running, abort;
+	bool running;
 #ifdef WIN32
 	pthread_t thread, search_thread;
 #else
@@ -63,6 +63,11 @@ typedef struct raop_ctx_s {
 	StaticTask_t *xTaskBuffer;
 	StackType_t xStack[RTSP_STACK_SIZE] __attribute__ ((aligned (4)));
 #endif
+	/* 
+	 Compiler/Execution bug: if this bool is next to 'running', the rtsp_thread 
+	 loop sees 'running' being set to false from at first execution ...
+	*/ 
+	bool abort;
 	unsigned char mac[6];
 	int latency;
 	struct {
@@ -182,7 +187,7 @@ struct raop_ctx_s *raop_create(struct in_addr host, char *name,
 	ctx->port = ntohs(addr.sin_port);
 #endif
 
	ctx->running = true;
-
	memcpy(ctx->mac, mac, 6);
+	
	memcpy(ctx->mac, mac, 6);
 	snprintf(id, 64, "%02X%02X%02X%02X%02X%02X@%s",  mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], name);
 
#ifdef WIN32
 	// seems that Windows snprintf does not add NULL char if actual size > max
@@ -214,7 +219,7 @@ void raop_delete(struct raop_ctx_s *ctx) {
 	socklen_t nlen = sizeof(struct sockaddr);
 #endif
 	
-if (!ctx) return;
+	if (!ctx) return;
 
 #ifdef WIN32
 	ctx->running = false;
@@ -406,7 +411,7 @@ static void *rtsp_thread(void *arg) {
 			sock = -1;
 		}
 	}
-
+	
 	if (sock != -1) closesocket(sock);
 
 #ifndef WIN32
@@ -692,10 +697,10 @@ void abort_rtsp(raop_ctx_t *ctx) {
 
 		heap_caps_free(ctx->active_remote.xTaskBuffer);
 		memset(&ctx->active_remote, 0, sizeof(ctx->active_remote));
-		
+
 		LOG_INFO("[%p]: Remote search thread aborted", ctx);
 	}	
-	
+
 	NFREE(ctx->rtsp.aeskey);
 	NFREE(ctx->rtsp.aesiv);
 	NFREE(ctx->rtsp.fmtp);

+ 51 - 0
components/services/monitor.c

@@ -40,6 +40,55 @@ bool jack_inserted_svc(void);
 void (*spkfault_handler_svc)(bool inserted);
 bool spkfault_svc(void);
 
+/****************************************************************************************
+ * 
+ */
+static void task_stats( void ) {
+#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY 
+	static struct {
+		TaskStatus_t *tasks;
+		uint32_t total, n;
+	} current, previous;
+	
+	current.n = uxTaskGetNumberOfTasks();
+	current.tasks = malloc( current.n * sizeof( TaskStatus_t ) );
+	current.n = uxTaskGetSystemState( current.tasks, current.n, &current.total );
+	
+	static EXT_RAM_ATTR char scratch[128+1];
+	*scratch = '\0';
+
+#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS
+	uint32_t elapsed = current.total - previous.total;
+    
+	for(int i = 0, n = 0; i < current.n; i++ ) {
+		for (int j = 0; j < previous.n; j++) {
+			if (current.tasks[i].xTaskNumber == previous.tasks[j].xTaskNumber) {
+				n += sprintf(scratch + n, "%16s %2u%% s:%5u", current.tasks[i].pcTaskName, 
+																		   100 * (current.tasks[i].ulRunTimeCounter - previous.tasks[j].ulRunTimeCounter) / elapsed, 
+																		   current.tasks[i].usStackHighWaterMark);
+				if (i % 3 == 2 || i == current.n - 1) {
+					ESP_LOGI(TAG, "%s", scratch);
+					n = 0;
+				}	
+				break;
+			}
+		}	
+	}	
+#else
+	for (int i = 0, n = 0; i < current.n; i ++) {
+		n += sprintf(scratch + n, "%16s s:%5u\t", current.tasks[i].pcTaskName, current.tasks[i].usStackHighWaterMark);
+		if (i % 3 == 2 || i == current.n - 1) {
+			ESP_LOGI(TAG, "%s", scratch);
+			n = 0;
+		}	
+	}
+#endif	
+	
+	if (previous.tasks) free(previous.tasks);
+	previous = current;
+#endif	
+}
+ 
 /****************************************************************************************
  * 
  */
@@ -49,6 +98,8 @@ static void monitor_callback(TimerHandle_t xTimer) {
 			heap_caps_get_minimum_free_size(MALLOC_CAP_INTERNAL),
 			heap_caps_get_free_size(MALLOC_CAP_SPIRAM),
 			heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM));
+			
+	task_stats();
 }
 
 /****************************************************************************************

+ 35 - 35
components/squeezelite/display.c

@@ -23,6 +23,9 @@
 #include "squeezelite.h"
 #include "slimproto.h"
 #include "display.h"
+#include "gds.h"
+#include "gds_text.h"
+#include "gds_draw.h"
 
 #pragma pack(push, 1)
 
@@ -85,8 +88,6 @@ struct ANIC_header {
 
 #pragma pack(pop)
 
-extern struct outputstate output;
-
 static struct {
 	TaskHandle_t task;
 	SemaphoreHandle_t mutex;
@@ -177,7 +178,6 @@ static void visu_handler(u8_t *data, int len);
 
 static void displayer_task(void* arg);
 
-
 /* scrolling undocumented information
 	grfs	
 		B: screen number
@@ -213,15 +213,15 @@ bool sb_display_init(void) {
 	static EXT_RAM_ATTR StackType_t xStack[SCROLL_STACK_SIZE] __attribute__ ((aligned (4)));
 	
 	// no display, just make sure we won't have requests
-	if (!display || display->height == 0 || display->width == 0) {
+	if (!display || GDS_GetWidth(display) <= 0 || GDS_GetHeight(display) <= 0) {
 		LOG_INFO("no display for LMS");
 		return false;
 	}	
 	
 	// need to force height to 32 maximum
-	displayer.width = display->width;
-	displayer.height = min(display->height, SB_HEIGHT);
-	SETD_width = display->width;
+	displayer.width = GDS_GetWidth(display);
+	displayer.height = min(GDS_GetHeight(display), SB_HEIGHT);
+	SETD_width = displayer.width;
 
 	// create visu configuration
 	visu.bar_gap = 1;
@@ -277,6 +277,7 @@ static bool display_bus_handler(void *from, enum display_bus_cmd_e cmd) {
 	
 	xSemaphoreGive(displayer.mutex);
 	
+	// chain to rest of "bus"
 	if (display_bus_chain) return (*display_bus_chain)(from, cmd);
 	else return true;
 }
@@ -330,8 +331,8 @@ static void send_server(void) {
 static void server(in_addr_t ip, u16_t hport, u16_t cport) {
 	char msg[32];
 	sprintf(msg, "%s:%hu", inet_ntoa(ip), hport);
-	if (displayer.owned) display->text(DISPLAY_FONT_DEFAULT, DISPLAY_CENTERED, DISPLAY_CLEAR | DISPLAY_UPDATE, msg);
-	SETD_width = display->width;
+	if (displayer.owned) GDS_TextPos(display, GDS_FONT_DEFAULT, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, msg);
+	SETD_width = displayer.width;
 	displayer.dirty = true;
 	if (notify_chain) (*notify_chain)(ip, hport, cport);
 }
@@ -426,8 +427,8 @@ static void show_display_buffer(char *ddram) {
 
 	LOG_DEBUG("\n\t%.40s\n\t%.40s", line1, line2);
 
-	display->line(1, DISPLAY_LEFT, DISPLAY_CLEAR, line1);	
-	display->line(2, DISPLAY_LEFT, DISPLAY_CLEAR | DISPLAY_UPDATE, line2);	
+	GDS_TextLine(display, 1, GDS_TEXT_LEFT, GDS_TEXT_CLEAR, line1);	
+	GDS_TextLine(display, 2, GDS_TEXT_LEFT, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, line2);	
 }
 
 /****************************************************************************************
@@ -495,13 +496,13 @@ static void grfe_handler( u8_t *data, int len) {
 	if (displayer.owned) {
 		// did we have something that might have write on the bottom of a SB_HEIGHT+ display
 		if (displayer.dirty) {
-			display->clear(true);
+			GDS_ClearExt(display, true);
 			displayer.dirty = false;
 		}	
 	
 		// draw new frame
-		display->draw_cbr(data + sizeof(struct grfe_packet), displayer.width, displayer.height);
-		display->update();
+		GDS_DrawBitmapCBR(display, data + sizeof(struct grfe_packet), displayer.width, displayer.height);
+		GDS_Update(display);
 	}	
 	
 	xSemaphoreGive(displayer.mutex);
@@ -519,10 +520,10 @@ static void grfb_handler(u8_t *data, int len) {
 	
 	LOG_INFO("brightness %hu", pkt->brightness);
 	if (pkt->brightness < 0) {
-		display->on(false); 
+		GDS_DisplayOff(display); 
 	} else {
-		display->on(true);
-		display->brightness(pkt->brightness);
+		GDS_DisplayOn(display);
+		GDS_SetContrast(display, pkt->brightness);
 	}
 }
 
@@ -603,8 +604,8 @@ static void grfg_handler(u8_t *data, int len) {
 	
 	// can only write if we really own display
 	if (displayer.owned) {
-		display->draw_cbr(scroller.frame, scroller.back.width, displayer.height);
-		display->update();
+		GDS_DrawBitmapCBR(display, scroller.frame, scroller.back.width, displayer.height);
+		GDS_Update(display);
 	}	
 		
 	// now we can active scrolling, but only if we are not on a small screen
@@ -703,7 +704,7 @@ static void visu_update(void) {
 	visu_export.level = 0;
 	pthread_mutex_unlock(&visu_export.mutex);
 
-	display->clear(false, false, visu.col, visu.row, visu.col + visu.width - 1, visu.row + visu.height - 1);
+	GDS_ClearExt(display, false, false, visu.col, visu.row, visu.col + visu.width - 1, visu.row + visu.height - 1);
 	
 	for (int i = visu.n; --i >= 0;) {
 		int x1 = visu.col + visu.border + visu.bar_border + i*(visu.bar_width + visu.bar_gap);
@@ -713,11 +714,11 @@ static void visu_update(void) {
 		else if (visu.bars[i].max) visu.bars[i].max--;
 			
 		for (int j = 0; j <= visu.bars[i].current; j += 2) 
-			display->draw_line( x1, y1 - j, x1 + visu.bar_width - 1, y1 - j);
+			GDS_DrawLine(display, x1, y1 - j, x1 + visu.bar_width - 1, y1 - j, GDS_COLOR_WHITE);
 			
 		if (visu.bars[i].max > 2) {
-			display->draw_line( x1, y1 - visu.bars[i].max, x1 + visu.bar_width - 1, y1 - visu.bars[i].max);			
-			display->draw_line( x1, y1 - visu.bars[i].max + 1, x1 + visu.bar_width - 1, y1 - visu.bars[i].max + 1);			
+			GDS_DrawLine(display, x1, y1 - visu.bars[i].max, x1 + visu.bar_width - 1, y1 - visu.bars[i].max, GDS_COLOR_WHITE);			
+			GDS_DrawLine(display, x1, y1 - visu.bars[i].max + 1, x1 + visu.bar_width - 1, y1 - visu.bars[i].max + 1, GDS_COLOR_WHITE);			
 		}	
 	}
 }
@@ -728,10 +729,9 @@ static void visu_update(void) {
  */
 void spectrum_limits(int min, int n, int pos) {
 	if (n / 2) {
-		int i;
-		float step = (DISPLAY_BW - min) * visu.spectrum_scale / (n/2);
+		int step = ((DISPLAY_BW - min) * visu.spectrum_scale * 2) / n;
 		visu.bars[pos].limit = min + step;
-		for (i = 1; i < n/2; i++) visu.bars[pos+i].limit = visu.bars[pos+i-1].limit + step;
+		for (int i = 1; i < n/2; i++) visu.bars[pos+i].limit = visu.bars[pos+i-1].limit + step;
 		spectrum_limits(visu.bars[pos + n/2 - 1].limit, n/2, pos + n/2);
 	} else {
 		visu.bars[pos].limit = DISPLAY_BW;
@@ -757,7 +757,7 @@ static void visu_handler( u8_t *data, int len) {
 	visu.mode = pkt->which;
 	
 	// little trick to clean the taller screens when switching visu 
-	if (visu.row >= SB_HEIGHT) display->clear(false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1);
+	if (visu.row >= SB_HEIGHT) GDS_ClearExt(display, false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1);
 	
 	if (visu.mode) {
 		if (pkt->count >= 4) {
@@ -768,17 +768,17 @@ static void visu_handler( u8_t *data, int len) {
 
 			visu.width = htonl(pkt->width);
 			visu.height = pkt->height ? pkt->height : SB_HEIGHT;
-			visu.col = pkt->col < 0 ? display->width + pkt->col : pkt->col;
-			visu.row = pkt->row < 0 ? display->height + pkt->row : pkt->row;
+			visu.col = pkt->col < 0 ? displayer.width + pkt->col : pkt->col;
+			visu.row = pkt->row < 0 ? GDS_GetHeight(display) + pkt->row : pkt->row;
 			visu.border =  htonl(pkt->border);
 			bars = htonl(pkt->bars);
 			visu.spectrum_scale = htonl(pkt->spectrum_scale) / 100.;
 		} else {
 			// full screen visu, try to use bottom screen if available
-			visu.width = display->width;
-			visu.height = display->height > SB_HEIGHT ? display->height - SB_HEIGHT : display->height;
+			visu.width = displayer.width;
+			visu.height = GDS_GetHeight(display) > SB_HEIGHT ? GDS_GetHeight(display) - SB_HEIGHT : GDS_GetHeight(display);
 			visu.col = visu.border = 0;
-			visu.row = display->height - visu.height;			
+			visu.row = GDS_GetHeight(display) - visu.height;			
 			bars = htonl(pkt->full.bars);
 			visu.spectrum_scale = htonl(pkt->full.spectrum_scale) / 100.;
 		}
@@ -812,7 +812,7 @@ static void visu_handler( u8_t *data, int len) {
 		// reset bars maximum
 		for (int i = visu.n; --i >= 0;) visu.bars[i].max = 0;
 				
-		display->clear(false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1);
+		GDS_ClearExt(display, false, true, visu.col, visu.row, visu.col + visu.width - 1, visu.row - visu.height - 1);
 		
 		LOG_INFO("Visualizer with %u bars of width %d:%d:%d:%d (%w:%u,h:%u,c:%u,r:%u,s:%.02f)", visu.n, visu.bar_border, visu.bar_width, visu.bar_gap, visu.border, visu.width, visu.height, visu.col, visu.row, visu.spectrum_scale);
 	} else {
@@ -855,7 +855,7 @@ static void displayer_task(void *args) {
 				memcpy(scroller.frame, scroller.back.frame, scroller.back.width * displayer.height / 8);
 				for (int i = 0; i < scroller.width * displayer.height / 8; i++) scroller.frame[i] |= scroller.scroll.frame[scroller.scrolled * displayer.height / 8 + i];
 				scroller.scrolled += scroller.by;
-				if (displayer.owned) display->draw_cbr(scroller.frame, scroller.width, displayer.height);	
+				if (displayer.owned) GDS_DrawBitmapCBR(display, scroller.frame, scroller.width, displayer.height);	
 				
 				// short sleep & don't need background update
 				scroller.wake = scroller.speed;
@@ -885,7 +885,7 @@ static void displayer_task(void *args) {
 		}
 		
 		// need to make sure we own display
-		if (displayer.owned) display->update();
+		if (displayer.owned) GDS_Update(display);
 		
 		// release semaphore and sleep what's needed
 		xSemaphoreGive(displayer.mutex);

+ 654 - 0
components/wifi-manager/http_server.c

@@ -0,0 +1,654 @@
+/*
+Copyright (c) 2017-2019 Tony Pottier
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+@file http_server.c
+@author Tony Pottier
+@brief Defines all functions necessary for the HTTP server to run.
+
+Contains the freeRTOS task for the HTTP listener and all necessary support
+function to process requests, decode URLs, serve files, etc. etc.
+
+@note http_server task cannot run without the wifi_manager task!
+@see https://idyl.io
+@see https://github.com/tonyp7/esp32-wifi-manager
+*/
+
+#include "http_server.h"
+#include "cmd_system.h"
+#include <inttypes.h>
+#include "squeezelite-ota.h"
+#include "nvs_utilities.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "cJSON.h"
+#include "esp_system.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "config.h"
+
+#define HTTP_STACK_SIZE	(5*1024)
+
+/* @brief tag used for ESP serial console messages */
+static const char TAG[] = "http_server";
+/* @brief task handle for the http server */
+static TaskHandle_t task_http_server = NULL;
+static StaticTask_t task_http_buffer;
+#if RECOVERY_APPLICATION
+static StackType_t task_http_stack[HTTP_STACK_SIZE];
+#else
+static StackType_t EXT_RAM_ATTR task_http_stack[HTTP_STACK_SIZE];
+#endif
+SemaphoreHandle_t http_server_config_mutex = NULL;
+
+/**
+ * @brief embedded binary data.
+ * @see file "component.mk"
+ * @see https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html#embedding-binary-data
+ */
+extern const uint8_t style_css_start[] asm("_binary_style_css_start");
+extern const uint8_t style_css_end[]   asm("_binary_style_css_end");
+extern const uint8_t jquery_gz_start[] asm("_binary_jquery_min_js_gz_start");
+extern const uint8_t jquery_gz_end[] asm("_binary_jquery_min_js_gz_end");
+extern const uint8_t popper_gz_start[] asm("_binary_popper_min_js_gz_start");
+extern const uint8_t popper_gz_end[] asm("_binary_popper_min_js_gz_end");
+extern const uint8_t bootstrap_js_gz_start[] asm("_binary_bootstrap_min_js_gz_start");
+extern const uint8_t bootstrap_js_gz_end[] asm("_binary_bootstrap_min_js_gz_end");
+extern const uint8_t bootstrap_css_gz_start[] asm("_binary_bootstrap_min_css_gz_start");
+extern const uint8_t bootstrap_css_gz_end[] asm("_binary_bootstrap_min_css_gz_end");
+extern const uint8_t code_js_start[] asm("_binary_code_js_start");
+extern const uint8_t code_js_end[] asm("_binary_code_js_end");
+extern const uint8_t index_html_start[] asm("_binary_index_html_start");
+extern const uint8_t index_html_end[] asm("_binary_index_html_end");
+
+
+/* const http headers stored in ROM */
+const static char http_hdr_template[] = "HTTP/1.1 200 OK\nContent-type: %s\nAccept-Ranges: bytes\nContent-Length: %d\nContent-Encoding: %s\nAccess-Control-Allow-Origin: *\n\n";
+const static char http_html_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/html\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n";
+const static char http_css_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/css\nCache-Control: public, max-age=31536000\nAccess-Control-Allow-Origin: *\n\n";
+const static char http_js_hdr[] = "HTTP/1.1 200 OK\nContent-type: text/javascript\nAccess-Control-Allow-Origin: *\n\n";
+const static char http_400_hdr[] = "HTTP/1.1 400 Bad Request\nContent-Length: 0\n\n";
+const static char http_404_hdr[] = "HTTP/1.1 404 Not Found\nContent-Length: 0\n\n";
+const static char http_503_hdr[] = "HTTP/1.1 503 Service Unavailable\nContent-Length: 0\n\n";
+const static char http_ok_json_no_cache_hdr[] = "HTTP/1.1 200 OK\nContent-type: application/json\nCache-Control: no-store, no-cache, must-revalidate, max-age=0\nPragma: no-cache\nAccess-Control-Allow-Origin: *\nAccept-Encoding: identity\n\n";
+const static char http_redirect_hdr_start[] = "HTTP/1.1 302 Found\nLocation: http://";
+const static char http_redirect_hdr_end[] = "/\n\n";
+
+
+void http_server_start() {
+	ESP_LOGD(TAG,  "http_server_start ");
+	if(task_http_server == NULL) {
+		task_http_server = xTaskCreateStatic( (TaskFunction_t) &http_server, "http_server", HTTP_STACK_SIZE, NULL, 
+										 WIFI_MANAGER_TASK_PRIORITY, task_http_stack, &task_http_buffer);
+	}
+}
+void http_server(void *pvParameters) {
+	http_server_config_mutex = xSemaphoreCreateMutex();
+	struct netconn *conn, *newconn;
+	err_t err;
+	conn = netconn_new(NETCONN_TCP);
+	netconn_bind(conn, IP_ADDR_ANY, 80);
+	netconn_listen(conn);
+	ESP_LOGI(TAG,   "HTTP Server listening on 80/tcp");
+	do {
+		err = netconn_accept(conn, &newconn);
+		if(err == ERR_OK) {
+			http_server_netconn_serve(newconn);
+			netconn_delete(newconn);
+		}
+		else
+		{
+			ESP_LOGE(TAG,  "Error accepting new connection. Terminating HTTP server");
+		}
+		taskYIELD();  /* allows the freeRTOS scheduler to take over if needed. */
+	} while(err == ERR_OK);
+
+	netconn_close(conn);
+	netconn_delete(conn);
+	vSemaphoreDelete(http_server_config_mutex);
+	http_server_config_mutex = NULL;
+	vTaskDelete( NULL );
+}
+
+
+char* http_server_get_header(char *request, char *header_name, int *len) {
+	*len = 0;
+	char *ret = NULL;
+	char *ptr = NULL;
+
+	ptr = strstr(request, header_name);
+	if(ptr) {
+		ret = ptr + strlen(header_name);
+		ptr = ret;
+		while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') {
+			(*len)++;
+			ptr++;
+		}
+		return ret;
+	}
+	return NULL;
+}
+char* http_server_search_header(char *request, char *header_name, int *len, char ** parm_name, char ** next_position, char * bufEnd) {
+	*len = 0;
+	char *ret = NULL;
+	char *ptr = NULL;
+	int currentLength=0;
+
+	ESP_LOGV(TAG,   "searching for header name: [%s]", header_name);
+	ptr = strstr(request, header_name);
+
+
+	if(ptr!=NULL && ptr<bufEnd) {
+		ret = ptr + strlen(header_name);
+		ptr = ret;
+		currentLength=(int)(ptr-request);
+		ESP_LOGV(TAG,   "found string at %d", currentLength);
+
+		while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r' && *ptr != ':' && ptr<bufEnd) {
+			ptr++;
+		}
+		if(*ptr==':') {
+			currentLength=(int)(ptr-ret);
+			ESP_LOGV(TAG,   "Found parameter name end, length : %d", currentLength);
+			// save the parameter name: the string between header name and ":"
+			*parm_name=malloc(currentLength+1);
+			if(*parm_name==NULL) {
+				ESP_LOGE(TAG,   "Unable to allocate memory for new header name");
+				return NULL;
+			}
+			memset(*parm_name, 0x00,currentLength+1);
+			strncpy(*parm_name,ret,currentLength);
+			ESP_LOGV(TAG,   "Found parameter name : %s ", *parm_name);
+			ptr++;
+			while (*ptr == ' ' && ptr<bufEnd) {
+				ptr++;
+			}
+
+		}
+		ret=ptr;
+		while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r'&& ptr<bufEnd) {
+			(*len)++;
+			ptr++;
+		}
+		// Terminate value inside its actual buffer so we can treat it as individual string
+		*ptr='\0';
+		currentLength=(int)(ptr-ret);
+		ESP_LOGV(TAG,   "Found parameter value end, length : %d, 	value: %s", currentLength,ret );
+
+		*next_position=++ptr;
+		return ret;
+	}
+	ESP_LOGD(TAG,   "No more match for : %s", header_name);
+	return NULL;
+}
+void http_server_send_resource_file(struct netconn *conn,const uint8_t * start, const uint8_t * end, char * content_type,char * encoding) {
+	uint16_t len=end - start;
+	size_t  buff_length= sizeof(http_hdr_template)+strlen(content_type)+strlen(encoding);
+	char * http_hdr=malloc(buff_length);
+	if( http_hdr == NULL) {
+		ESP_LOGE(TAG,  "Cound not allocate %d bytes for headers.",buff_length);
+		netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
+	}
+	else
+	{
+		memset(http_hdr,0x00,buff_length);
+		snprintf(http_hdr, buff_length-1,http_hdr_template,content_type,len,encoding);
+		netconn_write(conn, http_hdr, strlen(http_hdr), NETCONN_NOCOPY);
+		ESP_LOGD(TAG,  "sending response : %s",http_hdr);
+		netconn_write(conn, start, end - start, NETCONN_NOCOPY);
+		free(http_hdr);
+	}
+}
+
+err_t http_server_send_config_json(struct netconn *conn) {
+	char * json = config_alloc_get_json(false);
+	if(json!=NULL){
+		ESP_LOGD(TAG,  "config json : %s",json );
+		netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY);
+		netconn_write(conn, json, strlen(json), NETCONN_NOCOPY);
+		free(json);
+	}
+	else{
+		ESP_LOGD(TAG,  "Error retrieving config json string. ");
+		netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
+	}
+
+	return ESP_OK;
+}
+
+void http_server_process_config(struct netconn *conn, 	char *inbuf) {
+
+	// Here, we are passed a buffer which contains the http request
+
+//		netbuf_data(inbuf, (void**)&buf, &buflen);
+//		err = netconn_recv(conn, &inbuf);
+//		if(err == ERR_OK) {
+//
+//		/* extract the first line of the request */
+//		char *save_ptr = buf;
+//		char *line = strtok_r(save_ptr, new_line, &save_ptr);
+//		ESP_LOGD(TAG,  "Processing line %s",line);
+	ESP_LOGD(TAG,  "Processing request buffer: \n%s",inbuf);
+	char *last = NULL;
+	char *ptr = NULL;
+	last = ptr = inbuf;
+	bool bHeaders= true;
+	while(ptr!=NULL && *ptr != '\0') {
+		// Move to the end of the line, or to the end of the buffer
+		if(bHeaders) {
+			while (*ptr != '\0' && *ptr != '\n' && *ptr != '\r') {
+				ptr++;
+			}
+			// terminate the header string
+			if( *(ptr) == '\0' ) {
+				ESP_LOGD(TAG,   "End of buffer found");
+				return;
+			}
+			*ptr = '\0';
+			if( *(ptr+1) == '\n' ) {
+				*(ptr+1)='\0';
+				ptr+=2;
+			}
+			if(ptr==last) {
+				ESP_LOGD(TAG,  "Processing body. ");
+				break;
+			}
+			if(strlen(last)>0) {
+				ESP_LOGD(TAG,  "Found Header Line %s ", last);
+				//Content-Type: application/json
+			}
+			else {
+				ESP_LOGD(TAG,  "Found end of headers");
+				bHeaders = false;
+			}
+			last=ptr;
+		}
+		else {
+			//ESP_LOGD(TAG,  "Body content: %s", last);
+			//cJSON * json = cJSON_Parse(last);
+			//cJSON_Delete(json);
+			//todo:  implement body json parsing
+			// right now, body is coming as compressed, so we need some type of decompression to happen.
+			return;
+		}
+	}
+	return ;
+
+}
+
+void dump_net_buffer(void * buf, u16_t buflen) {
+	char * curbuf = malloc(buflen+1);
+	ESP_LOGV(TAG,  "netconn buffer, length=%u",buflen);
+	if(curbuf==NULL) {
+		ESP_LOGE(TAG,  "Unable to show netconn buffer.  Malloc failed");
+	}
+	memset(curbuf,0x0, buflen+1);
+	memcpy(curbuf,buf,buflen);
+	ESP_LOGV(TAG,  "netconn buffer content:\n%s",curbuf);
+	free(curbuf);
+}
+
+void http_server_netconn_serve(struct netconn *conn) {
+
+	struct netbuf *inbuf;
+	char *buf = NULL;
+	u16_t buflen = 0;
+	err_t err;
+	ip_addr_t remote_add;
+	u16_t port;
+	ESP_LOGV(TAG,  "Serving page.  Getting device AP address.");
+	const char new_line[2] = "\n";
+	char * ap_ip_address= config_alloc_get_default(NVS_TYPE_STR, "ap_ip_address", DEFAULT_AP_IP, 0);
+	if(ap_ip_address==NULL){
+		ESP_LOGE(TAG,  "Unable to retrieve default AP IP Address");
+		netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
+		netconn_close(conn);
+		return;
+	}
+	ESP_LOGV(TAG,  "Getting remote device IP address.");
+	netconn_getaddr(conn,	&remote_add,	&port,	0);
+	char * remote_address = strdup(ip4addr_ntoa(ip_2_ip4(&remote_add)));
+	ESP_LOGD(TAG,  "Local Access Point IP address is: %s. Remote device IP address is %s. Receiving request buffer", ap_ip_address, remote_address);
+
+	u16_t bufsize = 0;
+	netconn_set_recvtimeout(conn, 50);
+	while (netconn_recv(conn, &inbuf) == ERR_OK) {
+		do {
+			u8_t *rcvbuf;
+			u16_t rcvlen;
+			netbuf_data(inbuf, (void**)&rcvbuf, &rcvlen);
+			dump_net_buffer(rcvbuf, rcvlen);
+			if (buflen + rcvlen > bufsize) {
+				bufsize += rcvlen - bufsize < 2048 ? 2048 : rcvlen - bufsize;
+				buf = realloc(buf, bufsize);
+			}
+			memcpy(buf + buflen, rcvbuf, rcvlen);
+			buflen += rcvlen;
+			ESP_LOGI(TAG, "received netbuf of %hu", rcvlen);
+		} while (netbuf_next(inbuf) != -1);
+		netbuf_delete(inbuf);
+	}
+
+	if(buflen) {
+		ESP_LOGV(TAG,  "Getting data buffer.");
+		int lenH = 0;
+		/* extract the first line of the request */
+		char *save_ptr = buf;
+		char *line = strtok_r(save_ptr, new_line, &save_ptr);
+		char *temphost = http_server_get_header(save_ptr, "Host: ", &lenH);
+		char * host = malloc(lenH+1);
+		memset(host,0x00,lenH+1);
+		if(lenH>0){
+			strlcpy(host,temphost,lenH+1);
+		}
+		ESP_LOGD(TAG,  "http_server_netconn_serve Host: [%s], host: [%s], Processing line [%s]",remote_address,host,line);
+
+		if(line) {
+
+			/* captive portal functionality: redirect to access point IP for HOST that are not the access point IP OR the STA IP */
+			const char * host_name=NULL;
+			if((err=tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_STA, &host_name )) !=ESP_OK) {
+				ESP_LOGE(TAG,  "Unable to get host name. Error: %s",esp_err_to_name(err));
+			}
+			else {
+				ESP_LOGI(TAG,"System host name %s, http requested host: %s.",host_name, host);
+			}
+
+			/* determine if Host is from the STA IP address */
+			wifi_manager_lock_sta_ip_string(portMAX_DELAY);
+			bool access_from_sta_ip = lenH > 0?strcasestr(host, wifi_manager_get_sta_ip_string()):false;
+			wifi_manager_unlock_sta_ip_string();
+			bool access_from_host_name = (host_name!=NULL) && strcasestr(host,host_name);
+
+			if(lenH > 0 && !strcasestr(host, ap_ip_address) && !(access_from_sta_ip || access_from_host_name)) {
+				ESP_LOGI(TAG,  "Redirecting host [%s] to AP IP Address : %s",remote_address, ap_ip_address);
+				netconn_write(conn, http_redirect_hdr_start, sizeof(http_redirect_hdr_start) - 1, NETCONN_NOCOPY);
+				netconn_write(conn, ap_ip_address, strlen(ap_ip_address), NETCONN_NOCOPY);
+				netconn_write(conn, http_redirect_hdr_end, sizeof(http_redirect_hdr_end) - 1, NETCONN_NOCOPY);
+			}
+			else {
+                //static stuff
+				/* default page */
+				if(strstr(line, "GET / ")) {
+					netconn_write(conn, http_html_hdr, sizeof(http_html_hdr) - 1, NETCONN_NOCOPY);
+					netconn_write(conn, index_html_start, index_html_end- index_html_start, NETCONN_NOCOPY);
+				}
+				else if(strstr(line, "GET /code.js ")) {
+					netconn_write(conn, http_js_hdr, sizeof(http_js_hdr) - 1, NETCONN_NOCOPY);
+					netconn_write(conn, code_js_start, code_js_end - code_js_start, NETCONN_NOCOPY);
+				}
+				else if(strstr(line, "GET /style.css ")) {
+					netconn_write(conn, http_css_hdr, sizeof(http_css_hdr) - 1, NETCONN_NOCOPY);
+					netconn_write(conn, style_css_start, style_css_end - style_css_start, NETCONN_NOCOPY);
+				}
+				else if(strstr(line, "GET /jquery.js ")) {
+					http_server_send_resource_file(conn,jquery_gz_start, jquery_gz_end, "text/javascript", "gzip" );
+				}
+				else if(strstr(line, "GET /popper.js ")) {
+					http_server_send_resource_file(conn,popper_gz_start, popper_gz_end, "text/javascript", "gzip" );
+				}
+				else if(strstr(line, "GET /bootstrap.js ")) {
+					http_server_send_resource_file(conn,bootstrap_js_gz_start, bootstrap_js_gz_end, "text/javascript", "gzip" );
+				}
+				else if(strstr(line, "GET /bootstrap.css ")) {
+					http_server_send_resource_file(conn,bootstrap_css_gz_start, bootstrap_css_gz_end, "text/css", "gzip" );
+				}
+
+                //dynamic stuff
+				else if(strstr(line, "GET /scan.json ")) {
+					ESP_LOGI(TAG,  "Starting wifi scan");
+					wifi_manager_scan_async();
+				}
+				else if(strstr(line, "GET /ap.json ")) {
+					/* if we can get the mutex, write the last version of the AP list */
+					ESP_LOGI(TAG,  "Processing ap.json request");
+					if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) {
+						netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY);
+						char *buff = wifi_manager_alloc_get_ap_list_json();
+						wifi_manager_unlock_json_buffer();
+						if(buff!=NULL){
+							netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY);
+							free(buff);
+						}
+						else {
+							ESP_LOGD(TAG,  "Error retrieving ap list json string. ");
+							netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
+						}
+					}
+					else {
+						netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
+						ESP_LOGE(TAG,   "http_server_netconn_serve: GET /ap.json failed to obtain mutex");
+					}
+					/* request a wifi scan */
+					ESP_LOGI(TAG,  "Starting wifi scan");
+					wifi_manager_scan_async();
+					ESP_LOGI(TAG,  "Done serving ap.json");
+				}
+				else if(strstr(line, "GET /config.json ")) {
+					ESP_LOGI(TAG,  "Serving config.json");
+					ESP_LOGI(TAG,   "About to get config from flash");
+					http_server_send_config_json(conn);
+					ESP_LOGD(TAG,  "Done serving config.json");
+				}
+				else if(strstr(line, "POST /config.json ")) {
+					ESP_LOGI(TAG,  "Serving POST config.json");
+					int lenA=0;
+					char * last_parm=save_ptr;
+					char * next_parm=save_ptr;
+					char  * last_parm_name=NULL;
+					bool bErrorFound=false;
+					bool bOTA=false;
+					char * otaURL=NULL;
+					// todo:  implement json body parsing
+					//http_server_process_config(conn,save_ptr);
+
+					while(last_parm!=NULL) {
+						// Search will return
+						ESP_LOGD(TAG,   "Getting parameters from X-Custom headers");
+						last_parm = http_server_search_header(next_parm, "X-Custom-", &lenA, &last_parm_name,&next_parm,buf+buflen);
+						if(last_parm!=NULL && last_parm_name!=NULL) {
+							ESP_LOGI(TAG,   "http_server_netconn_serve: POST config.json, config %s=%s", last_parm_name, last_parm);
+							if(strcmp(last_parm_name, "fwurl")==0) {
+								// we're getting a request to do an OTA from that URL
+								ESP_LOGW(TAG,   "Found OTA request!");
+								otaURL=strdup(last_parm);
+								bOTA=true;
+							}
+							else {
+								ESP_LOGV(TAG,   "http_server_netconn_serve: POST config.json Storing parameter");
+								if(config_set_value(NVS_TYPE_STR, last_parm_name , last_parm) != ESP_OK){
+									ESP_LOGE(TAG,  "Unable to save nvs value.");
+								}
+							}
+						}
+						if(last_parm_name!=NULL) {
+							free(last_parm_name);
+							last_parm_name=NULL;
+						}
+					}
+					if(bErrorFound) {
+						netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY); //400 invalid request
+					}
+					else {
+						netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok
+						if(bOTA) {
+
+#if RECOVERY_APPLICATION
+							ESP_LOGW(TAG,   "Starting process OTA for url %s",otaURL);
+#else
+							ESP_LOGW(TAG,   "Restarting system to process OTA for url %s",otaURL);
+#endif
+							wifi_manager_reboot_ota(otaURL);
+							free(otaURL);
+						}
+					}
+					ESP_LOGI(TAG,  "Done Serving POST config.json");
+				} 
+				else if(strstr(line, "POST /connect.json ")) {
+					ESP_LOGI(TAG,   "http_server_netconn_serve: POST /connect.json");
+					bool found = false;
+					int lenS = 0, lenP = 0, lenN = 0;
+					char *ssid = NULL, *password = NULL;
+					ssid = http_server_get_header(save_ptr, "X-Custom-ssid: ", &lenS);
+					password = http_server_get_header(save_ptr, "X-Custom-pwd: ", &lenP);
+					char * new_host_name_b = http_server_get_header(save_ptr, "X-Custom-host_name: ", &lenN);
+					if(lenN > 0){
+						lenN++;
+						char * new_host_name = malloc(lenN);
+						strlcpy(new_host_name, new_host_name_b, lenN);
+						if(config_set_value(NVS_TYPE_STR, "host_name", new_host_name) != ESP_OK){
+							ESP_LOGE(TAG,  "Unable to save host name configuration");
+						}
+						free(new_host_name);
+					}
+
+					if(ssid && lenS <= MAX_SSID_SIZE && password && lenP <= MAX_PASSWORD_SIZE) {
+						wifi_config_t* config = wifi_manager_get_wifi_sta_config();
+						memset(config, 0x00, sizeof(wifi_config_t));
+						memcpy(config->sta.ssid, ssid, lenS);
+						memcpy(config->sta.password, password, lenP);
+						ESP_LOGD(TAG,   "http_server_netconn_serve: wifi_manager_connect_async() call, with ssid: %s, password: %s", config->sta.ssid, config->sta.password);
+						wifi_manager_connect_async();
+						netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); //200ok
+						found = true;
+					}
+					else{
+						ESP_LOGE(TAG,  "SSID or Password invalid");
+					}
+
+
+					if(!found) {
+						/* bad request the authentification header is not complete/not the correct format */
+						netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY);
+						ESP_LOGE(TAG,   "bad request the authentification header is not complete/not the correct format");
+					}
+
+					ESP_LOGI(TAG,   "http_server_netconn_serve: done serving connect.json");
+				}
+				else if(strstr(line, "DELETE /connect.json ")) {
+					ESP_LOGI(TAG,   "http_server_netconn_serve: DELETE /connect.json");
+					/* request a disconnection from wifi and forget about it */
+					wifi_manager_disconnect_async();
+					netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */
+					ESP_LOGI(TAG,   "http_server_netconn_serve: done serving DELETE /connect.json");
+				}
+				else if(strstr(line, "POST /reboot_ota.json ")) {
+					ESP_LOGI(TAG,   "http_server_netconn_serve: POST reboot_ota.json");
+					netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */
+					wifi_manager_reboot(OTA);
+					ESP_LOGI(TAG,   "http_server_netconn_serve: done serving POST reboot_ota.json");
+				}
+				else if(strstr(line, "POST /reboot.json ")) {
+					ESP_LOGI(TAG,   "http_server_netconn_serve: POST reboot.json");
+					netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */
+					wifi_manager_reboot(RESTART);
+					ESP_LOGI(TAG,   "http_server_netconn_serve: done serving POST reboot.json");
+				}
+				else if(strstr(line, "POST /recovery.json ")) {
+					ESP_LOGI(TAG,   "http_server_netconn_serve: POST recovery.json");
+					netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY); /* 200 ok */
+					wifi_manager_reboot(RECOVERY);
+					ESP_LOGI(TAG,   "http_server_netconn_serve: done serving POST recovery.json");
+				}
+				else if(strstr(line, "GET /status.json ")) {
+					ESP_LOGI(TAG,  "Serving status.json");
+					if(wifi_manager_lock_json_buffer(( TickType_t ) 10)) {
+						char *buff = wifi_manager_alloc_get_ip_info_json();
+						wifi_manager_unlock_json_buffer();
+						if(buff) {
+							netconn_write(conn, http_ok_json_no_cache_hdr, sizeof(http_ok_json_no_cache_hdr) - 1, NETCONN_NOCOPY);
+							netconn_write(conn, buff, strlen(buff), NETCONN_NOCOPY);
+							free(buff);
+						}
+						else {
+							netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
+						}
+
+					}
+					else {
+						netconn_write(conn, http_503_hdr, sizeof(http_503_hdr) - 1, NETCONN_NOCOPY);
+						ESP_LOGE(TAG,   "http_server_netconn_serve: GET /status failed to obtain mutex");
+					}
+					ESP_LOGI(TAG,  "Done Serving status.json");
+				}
+				else {
+					netconn_write(conn, http_400_hdr, sizeof(http_400_hdr) - 1, NETCONN_NOCOPY);
+					ESP_LOGE(TAG,   "bad request from host: %s, request %s",remote_address, line);
+				}
+			}
+		}
+		else {
+			ESP_LOGE(TAG,   "URL not found processing for remote host : %s",remote_address);
+			netconn_write(conn, http_404_hdr, sizeof(http_404_hdr) - 1, NETCONN_NOCOPY);
+		}
+		free(host);
+		free(buf);
+	}
+
+	free(ap_ip_address);
+	free(remote_address);
+	netconn_close(conn);
+	/* free the buffer */
+
+}
+
+bool http_server_lock_json_object(TickType_t xTicksToWait) {
+	ESP_LOGD(TAG,  "Locking config json object");
+	if(http_server_config_mutex) {
+		if( xSemaphoreTake( http_server_config_mutex, xTicksToWait ) == pdTRUE ) {
+			ESP_LOGV(TAG,  "config Json object locked!");
+			return true;
+		}
+		else {
+			ESP_LOGW(TAG,  "Semaphore take failed. Unable to lock config Json object mutex");
+			return false;
+		}
+	}
+	else {
+		ESP_LOGW(TAG,  "Unable to lock config Json object mutex");
+		return false;
+	}
+
+}
+
+void http_server_unlock_json_object() {
+	ESP_LOGD(TAG,  "Unlocking json buffer!");
+	xSemaphoreGive( http_server_config_mutex );
+}
+
+void strreplace(char *src, char *str, char *rep)
+{
+    char *p = strstr(src, str);
+    if(p)
+    {
+        int len = strlen(src)+strlen(rep)-strlen(str);
+        char r[len];
+        memset(r, 0, len);
+        if( p >= src ) {
+            strncpy(r, src, p-src);
+            r[p-src]='\0';
+            strncat(r, rep, strlen(rep));
+            strncat(r, p+strlen(str), p+strlen(str)-src+strlen(src));
+            strcpy(src, r);
+            strreplace(p+strlen(rep), str, rep);
+        }
+    }
+}
+

+ 14 - 1
sdkconfig.defaults

@@ -2,6 +2,11 @@
 # Automatically generated file. DO NOT EDIT.
 # Espressif IoT Development Framework (ESP-IDF) Project Configuration
 #
+
+# DSP
+CONFIG_DSP_OPTIMIZED=y
+CONFIG_DSP_OPTIMIZATION=1
+CONFIG_DSP_MAX_FFT_SIZE_512=y
 CONFIG_IDF_TARGET_ESP32=y
 CONFIG_IDF_TARGET="esp32"
 
@@ -11,7 +16,12 @@ CONFIG_IDF_TARGET="esp32"
 CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-"
 CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES=y
 CONFIG_APP_COMPILE_TIME_DATE=y
+
+
+
 CONFIG_OTA_ALLOW_HTTP=y
+
+
 CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
 
 
@@ -102,6 +112,7 @@ CONFIG_DEFAULT_AP_NETMASK="255.255.255.0"
 CONFIG_DEFAULT_AP_MAX_CONNECTIONS=4
 CONFIG_DEFAULT_AP_BEACON_INTERVAL=100
 CONFIG_DEFAULT_COMMAND_LINE="squeezelite -o I2S -b 500:2000 -d all=info -C 30"
+
 CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
 CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
 
@@ -570,7 +581,7 @@ CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
 
 CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
-CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2432
 CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
 CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 
@@ -599,6 +610,7 @@ CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
 
 CONFIG_LWIP_TIMERS_ONDEMAND=y
 CONFIG_LWIP_MAX_SOCKETS=16
+
 CONFIG_LWIP_SO_REUSE=y
 CONFIG_LWIP_SO_REUSE_RXTOALL=y
 
@@ -775,6 +787,7 @@ CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
 CONFIG_VFS_SUPPORT_TERMIOS=y
 CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
 CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+
 CONFIG_WL_SECTOR_SIZE_512=y
 #CONFIG_WL_SECTOR_SIZE_4096 is not defined
 CONFIG_WL_SECTOR_SIZE=512