Răsfoiți Sursa

Merge branch 'master' of https://gitee.com/openLuat/LuatOS

13917187172 4 luni în urmă
părinte
comite
0af53a4904
84 a modificat fișierele cu 10536 adăugiri și 1068 ștergeri
  1. 16 13
      components/network/adapter/luat_network_adapter.c
  2. 2 0
      components/u8g2/luat_u8g2.h
  3. 111 46
      components/u8g2/mui.c
  4. 12 7
      components/u8g2/mui.h
  5. 857 187
      components/u8g2/mui_u8g2.c
  6. 53 2
      components/u8g2/mui_u8g2.h
  7. 289 5
      components/u8g2/u8g2.h
  8. 107 0
      components/u8g2/u8g2_arc.c
  9. 59 2
      components/u8g2/u8g2_bitmap.c
  10. 264 33
      components/u8g2/u8g2_d_memory.c
  11. 766 106
      components/u8g2/u8g2_d_setup.c
  12. 140 45
      components/u8g2/u8g2_font.c
  13. 676 146
      components/u8g2/u8g2_fonts.c
  14. 5 0
      components/u8g2/u8g2_selection_list.c
  15. 1 0
      components/u8g2/u8log.c
  16. 45 3
      components/u8g2/u8x8.h
  17. 2 2
      components/u8g2/u8x8_8x8.c
  18. 53 6
      components/u8g2/u8x8_cad.c
  19. 311 0
      components/u8g2/u8x8_d_ch1120.c
  20. 2 2
      components/u8g2/u8x8_d_ks0108.c
  21. 42 0
      components/u8g2/u8x8_d_ls013b7dh03.c
  22. 138 0
      components/u8g2/u8x8_d_pcf8812.c
  23. 219 0
      components/u8g2/u8x8_d_s1d15300.c
  24. 83 0
      components/u8g2/u8x8_d_sed1330.c
  25. 10 2
      components/u8g2/u8x8_d_sh1107.c
  26. 1 1
      components/u8g2/u8x8_d_sh1108.c
  27. 119 29
      components/u8g2/u8x8_d_ssd1309.c
  28. 354 0
      components/u8g2/u8x8_d_ssd1312.c
  29. 215 0
      components/u8g2/u8x8_d_ssd1315_128x64_noname.c
  30. 166 0
      components/u8g2/u8x8_d_ssd1320.c
  31. 219 0
      components/u8g2/u8x8_d_ssd1322.c
  32. 344 0
      components/u8g2/u8x8_d_ssd1363.c
  33. 501 0
      components/u8g2/u8x8_d_st7302.c
  34. 694 0
      components/u8g2/u8x8_d_st7305.c
  35. 428 0
      components/u8g2/u8x8_d_st75161.c
  36. 114 0
      components/u8g2/u8x8_d_st75256.c
  37. 304 156
      components/u8g2/u8x8_d_st7567.c
  38. 76 0
      components/u8g2/u8x8_d_st7571.c
  39. 243 0
      components/u8g2/u8x8_d_st7586s_md240128.c
  40. 44 10
      components/u8g2/u8x8_d_st7920.c
  41. 82 0
      components/u8g2/u8x8_d_t6963.c
  42. 93 0
      components/u8g2/u8x8_d_uc1604.c
  43. 457 0
      components/u8g2/u8x8_d_uc1628.c
  44. 3 3
      components/u8g2/u8x8_display.c
  45. 42 0
      components/u8g2/u8x8_u8toa.c
  46. 1 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/main.lua
  47. 31 45
      module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_eth_spi.lua
  48. 9 0
      module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_multiple.lua
  49. 1 1
      module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/netdrv_device.lua
  50. 6 5
      module/Air780EHM_Air780EHV_Air780EGH/project/sms_call_forward/main.lua
  51. 0 37
      module/Air780EHM_Air780EHV_Air780EGH/project/sms_call_forward/netdrv/netdrv_device.lua
  52. 21 11
      module/Air780EHM_Air780EHV_Air780EGH/project/sms_call_forward/readme.md
  53. 33 51
      module/Air780EPM/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_eth_spi.lua
  54. 9 0
      module/Air780EPM/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_multiple.lua
  55. 1 1
      module/Air780EPM/demo/accessory_board/AirETH_1000/http/netdrv_device.lua
  56. 1 1
      module/Air780EPM/demo/accessory_board/AirETH_1000/network_routing/4g_out_ethernet_in/netif_app.lua
  57. 1 1
      module/Air8000/demo/accessory_board/AirETH_1000/http/main.lua
  58. 1 1
      module/Air8000/demo/accessory_board/AirETH_1000/http/netdrv_device.lua
  59. 1 1
      module/Air8000/demo/accessory_board/AirSPINAND_1000/lf_fs.lua
  60. 3 3
      module/Air8000/demo/accessory_board/AirSPINAND_1000/readme.md
  61. 98 0
      module/Air8000/demo/socket/server/main.lua
  62. 68 0
      module/Air8000/demo/socket/server/netdrv/netdrv_eth_spi.lua
  63. 81 0
      module/Air8000/demo/socket/server/netdrv/netdrv_wifi_ap.lua
  64. 59 0
      module/Air8000/demo/socket/server/netdrv/netdrv_wifi_sta.lua
  65. 29 0
      module/Air8000/demo/socket/server/netdrv_device.lua
  66. 187 0
      module/Air8000/demo/socket/server/readme.md
  67. 332 0
      module/Air8000/demo/socket/server/tcp/tcp_server_main.lua
  68. 87 0
      module/Air8000/demo/socket/server/tcp/tcp_server_receiver.lua
  69. 136 0
      module/Air8000/demo/socket/server/tcp/tcp_server_sender.lua
  70. 71 0
      module/Air8000/demo/socket/server/timer_app.lua
  71. 101 0
      module/Air8000/demo/socket/server/uart_app.lua
  72. 112 0
      module/Air8000/demo/socket/server/udp/udp_server_main.lua
  73. 83 0
      module/Air8000/demo/socket/server/udp/udp_server_receiver.lua
  74. 115 0
      module/Air8000/demo/socket/server/udp/udp_server_sender.lua
  75. 6 5
      module/Air8000/project/sms_call_forward/main.lua
  76. 17 3
      module/Air8000/project/sms_call_forward/readme.md
  77. 1 1
      module/Air8101/demo/accessory_board/AirETH_1000/http/main.lua
  78. 39 59
      module/Air8101/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_eth_spi.lua
  79. 13 11
      module/Air8101/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_multiple.lua
  80. 2 2
      module/Air8101/demo/accessory_board/AirETH_1000/http/netdrv_device.lua
  81. 9 11
      module/Air8101/demo/accessory_board/AirETH_1000/http/readme.md
  82. 5 5
      module/Air8101/demo/accessory_board/AirETH_1000/network_routing/wifi_out_ethernet_in_wifi_in/netif_app.lua
  83. 3 5
      module/Air8101/demo/accessory_board/AirETH_1000/network_routing/wifi_out_ethernet_in_wifi_in/readme.md
  84. 1 1
      module/Air8101/demo/accessory_board/AirETH_1000/readme.md

+ 16 - 13
components/network/adapter/luat_network_adapter.c

@@ -1589,23 +1589,26 @@ int network_socket_connect(network_ctrl_t *ctrl, luat_ip_addr_t *remote_ip)
 	if (!local_port)
 	{
 		local_port = ctrl->adapter_index;
-		local_port *= 640;
-		uint32_t offset = ctrl - adapter->ctrl_table;
-		if (offset >= sizeof(network_ctrl_t))
-		{
-			offset /= sizeof(network_ctrl_t);
-		}
-		if (offset >= adapter->opt->max_socket_num)
-		{
-			offset = adapter->opt->max_socket_num;
-		}
+		local_port *= 1000;
+		G_LOCK;
 		adapter->port++;
-		if (adapter->port >= 10)
+		if (adapter->port >= 500)
 		{
 			adapter->port = 0;
 		}
-		local_port += 50000 + adapter->port + offset * 10;
-		DBG("network %d local port auto select %u",offset, local_port);
+		local_port += 50000 + adapter->port;
+		G_UNLOCK;
+//		local_port += 50000 + adapter->port + offset * 10;
+//		DBG("network %d local port auto select %u",offset, local_port);
+		if (ctrl->is_debug)
+		{
+			uint32_t offset = ctrl - adapter->ctrl_table;
+			if (offset >= sizeof(network_ctrl_t))
+			{
+				offset /= sizeof(network_ctrl_t);
+			}
+			DBG("network %d-%d local port auto select %u",ctrl->adapter_index,offset, local_port);
+		}
 	}
 	#ifdef LUAT_USE_NETDRV
 	luat_netdrv_fire_socket_event_netctrl(0x83 + EV_NW_RESET, ctrl, 0);

+ 2 - 0
components/u8g2/luat_u8g2.h

@@ -21,6 +21,8 @@ typedef struct luat_u8g2_conf
     void* userdata;
 } luat_u8g2_conf_t;
 
+uint8_t u8x8_d_custom_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+
 int luat_u8g2_setup(luat_u8g2_conf_t *conf);
 
 int luat_u8g2_close(luat_u8g2_conf_t *conf);

+ 111 - 46
components/u8g2/mui.c

@@ -298,9 +298,10 @@ void mui_Init(mui_t *ui, void *graphics_data, fds_t *fds, muif_t *muif_tlist, si
   ui->muif_tlist = muif_tlist;
   ui->muif_tcnt = muif_tcnt;
   ui->graphics_data = graphics_data;
+  ui->last_form_stack_pos = -1;
 }
 
-int mui_find_uif(mui_t *ui, uint8_t id0, uint8_t id1)
+static int mui_find_uif(mui_t *ui, uint8_t id0, uint8_t id1)
 {
   size_t i;
   for( i = 0; i < ui->muif_tcnt; i++ )
@@ -460,7 +461,7 @@ static void mui_loop_over_form(mui_t *ui, uint8_t (*task)(mui_t *ui))
 /*
   n is the form number
 */
-fds_t *mui_find_form(mui_t *ui, uint8_t n)
+static fds_t *mui_find_form(mui_t *ui, uint8_t n)
 {
   fds_t *fds = ui->root_fds;
   uint8_t cmd;
@@ -487,20 +488,20 @@ fds_t *mui_find_form(mui_t *ui, uint8_t n)
 /* === task procedures (arguments for mui_loop_over_form) === */
 /* ui->fds contains the current field */
 
-uint8_t mui_task_draw(mui_t *ui)
+static uint8_t mui_task_draw(mui_t *ui)
 {
   //printf("mui_task_draw fds=%p uif=%p text=%s\n", ui->fds, ui->uif, ui->text);
   muif_get_cb(ui->uif)(ui, MUIF_MSG_DRAW);
   return 0;     /* continue with the loop */
 }
 
-uint8_t mui_task_form_start(mui_t *ui)
+static uint8_t mui_task_form_start(mui_t *ui)
 {
   muif_get_cb(ui->uif)(ui, MUIF_MSG_FORM_START);
   return 0;     /* continue with the loop */
 }
 
-uint8_t mui_task_form_end(mui_t *ui)
+static uint8_t mui_task_form_end(mui_t *ui)
 {
   muif_get_cb(ui->uif)(ui, MUIF_MSG_FORM_END);
   return 0;     /* continue with the loop */
@@ -516,7 +517,7 @@ static uint8_t mui_uif_is_cursor_selectable(mui_t *ui)
   return 0;
 }
 
-uint8_t mui_task_find_prev_cursor_uif(mui_t *ui)
+static uint8_t mui_task_find_prev_cursor_uif(mui_t *ui)
 {
   //if ( muif_get_cflags(ui->uif) & MUIF_CFLAG_IS_CURSOR_SELECTABLE )
   if ( mui_uif_is_cursor_selectable(ui) )
@@ -531,7 +532,7 @@ uint8_t mui_task_find_prev_cursor_uif(mui_t *ui)
   return 0;     /* continue with the loop */
 }
 
-uint8_t mui_task_find_first_cursor_uif(mui_t *ui)
+static uint8_t mui_task_find_first_cursor_uif(mui_t *ui)
 {
   //if ( muif_get_cflags(ui->uif) & MUIF_CFLAG_IS_CURSOR_SELECTABLE )
   if ( mui_uif_is_cursor_selectable(ui) )
@@ -545,7 +546,7 @@ uint8_t mui_task_find_first_cursor_uif(mui_t *ui)
   return 0;     /* continue with the loop */
 }
 
-uint8_t mui_task_find_last_cursor_uif(mui_t *ui)
+static uint8_t mui_task_find_last_cursor_uif(mui_t *ui)
 {
   //if ( muif_get_cflags(ui->uif) & MUIF_CFLAG_IS_CURSOR_SELECTABLE )
   if ( mui_uif_is_cursor_selectable(ui) )
@@ -556,7 +557,7 @@ uint8_t mui_task_find_last_cursor_uif(mui_t *ui)
   return 0;     /* continue with the loop */
 }
 
-uint8_t mui_task_find_next_cursor_uif(mui_t *ui)
+static uint8_t mui_task_find_next_cursor_uif(mui_t *ui)
 {
   //if ( muif_get_cflags(ui->uif) & MUIF_CFLAG_IS_CURSOR_SELECTABLE )
   if ( mui_uif_is_cursor_selectable(ui) )
@@ -575,7 +576,7 @@ uint8_t mui_task_find_next_cursor_uif(mui_t *ui)
   return 0;     /* continue with the loop */
 }
 
-uint8_t mui_task_get_current_cursor_focus_position(mui_t *ui)
+static uint8_t mui_task_get_current_cursor_focus_position(mui_t *ui)
 {
   //if ( muif_get_cflags(ui->uif) & MUIF_CFLAG_IS_CURSOR_SELECTABLE )
   if ( mui_uif_is_cursor_selectable(ui) )
@@ -587,7 +588,8 @@ uint8_t mui_task_get_current_cursor_focus_position(mui_t *ui)
   return 0;     /* continue with the loop */
 }
 
-uint8_t mui_task_read_nth_selectable_field(mui_t *ui)
+#ifdef OBSOLETE
+static uint8_t mui_task_read_nth_selectable_field(mui_t *ui)
 {
   //if ( muif_get_cflags(ui->uif) & MUIF_CFLAG_IS_CURSOR_SELECTABLE )
   if ( mui_uif_is_cursor_selectable(ui) )
@@ -598,8 +600,9 @@ uint8_t mui_task_read_nth_selectable_field(mui_t *ui)
   }
   return 0;     /* continue with the loop */
 }
+#endif
 
-uint8_t mui_task_find_execute_on_select_field(mui_t *ui)
+static uint8_t mui_task_find_execute_on_select_field(mui_t *ui)
 {
   if ( muif_get_cflags(ui->uif) & MUIF_CFLAG_IS_EXECUTE_ON_SELECT )
   {
@@ -651,7 +654,7 @@ void mui_Draw(mui_t *ui)
   mui_loop_over_form(ui, mui_task_draw);
 }
 
-void mui_next_field(mui_t *ui)
+static void mui_next_field(mui_t *ui)
 {
   mui_loop_over_form(ui, mui_task_find_next_cursor_uif);
   // ui->cursor_focus_position++;
@@ -677,36 +680,46 @@ void mui_next_field(mui_t *ui)
 */
 uint8_t mui_GetSelectableFieldTextOption(mui_t *ui, fds_t *fds, uint8_t nth_token)
 {
-  fds_t *fds_backup = ui->fds;                                // backup the current fds, so that this function can be called inside a task loop 
-  int len = ui->len;          // backup length of the current command, 26 sep 2021: probably this is not required any more
-  uint8_t is_found;
-  
-  ui->fds = fds;
-  // at this point ui->fds contains the field which contains the tokens  
-  // now get the opion string out of the text field. nth_token can be 0 if this is no opion string
-  is_found = mui_fds_get_nth_token(ui, nth_token);          // return value is ignored here
-  
-  ui->fds = fds_backup;                        // restore the previous fds position
-  ui->len = len;
-  // result is stored in ui->text
-  return is_found;
+  if ( fds != NULL )
+  {
+    fds_t *fds_backup = ui->fds;                                // backup the current fds, so that this function can be called inside a task loop 
+    int len = ui->len;          // backup length of the current command, 26 sep 2021: probably this is not required any more
+    uint8_t is_found;
+    
+    ui->fds = fds;
+    // at this point ui->fds contains the field which contains the tokens  
+    // now get the opion string out of the text field. nth_token can be 0 if this is no opion string
+    is_found = mui_fds_get_nth_token(ui, nth_token);          // return value is ignored here
+    
+    ui->fds = fds_backup;                        // restore the previous fds position
+    ui->len = len;
+    // result is stored in ui->text
+    return is_found;
+  }
+  ui->text[0] = '\0';
+  return 0;
 }
 
 uint8_t mui_GetSelectableFieldOptionCnt(mui_t *ui, fds_t *fds)
 {
-  fds_t *fds_backup = ui->fds;                                // backup the current fds, so that this function can be called inside a task loop 
-  int len = ui->len;          // backup length of the current command   26 sep 2021: probably this is not required any more
-  uint8_t cnt = 0;
-  
-  ui->fds = fds;
-  // at this point ui->fds contains the field which contains the tokens  
-  // now get the opion string out of the text field. nth_token can be 0 if this is no opion string
-  cnt = mui_fds_get_token_cnt(ui); 
-  
-  ui->fds = fds_backup;                        // restore the previous fds position
-  ui->len = len;
-  // result is stored in ui->text
-  return cnt;
+  if ( fds != NULL )
+  {
+    fds_t *fds_backup = ui->fds;                                // backup the current fds, so that this function can be called inside a task loop 
+    int len = ui->len;          // backup length of the current command   26 sep 2021: probably this is not required any more
+    uint8_t cnt = 0;
+    
+    ui->fds = fds;
+    // at this point ui->fds contains the field which contains the tokens  
+    // now get the opion string out of the text field. nth_token can be 0 if this is no opion string
+    cnt = mui_fds_get_token_cnt(ui); 
+    
+    ui->fds = fds_backup;                        // restore the previous fds position
+    ui->len = len;
+    // result is stored in ui->text
+    return cnt;
+  }
+  ui->text[0] = '\0';
+  return 0;
 }
 
 
@@ -793,39 +806,91 @@ uint8_t mui_GotoForm(mui_t *ui, uint8_t form_id, uint8_t initial_cursor_position
   return 1;
 }
 
-void mui_SaveForm(mui_t *ui)
+/* 
+  Save current form+cursor position. Used together with mui_RestoreForm 
+*/
+void mui_SaveFormWithCursorPosition(mui_t *ui, uint8_t cursor_pos)
 {
   if ( mui_IsFormActive(ui) == 0 )
     return;
   
-  ui->last_form_fds = ui->cursor_focus_fds;
-  ui->last_form_id = mui_get_fds_char(ui->current_form_fds+1);
-  ui->last_form_cursor_focus_position = mui_GetCurrentCursorFocusPosition(ui);
+  if ( ui->last_form_stack_pos < MUI_MENU_LAST_FORM_STACK_SIZE-1 )
+    ui->last_form_stack_pos++;
+  else  // discard the oldes entry
+  {
+    uint8_t i;
+    for( i = 0; i < ui->last_form_stack_pos; i++ )
+    {
+      ui->last_form_id[i] = ui->last_form_id[i+1];
+      ui->last_form_cursor_focus_position[i] = ui->last_form_cursor_focus_position[i+1];
+    }
+  }
+  
+  ui->last_form_fds = ui->cursor_focus_fds;             // 25 Aug 2024: I think this is not required, u8g2 data function will store the value manually in last_form_fds
+  ui->last_form_id[ui->last_form_stack_pos] = mui_get_fds_char(ui->current_form_fds+1);
+  ui->last_form_cursor_focus_position[ui->last_form_stack_pos] = cursor_pos;
+}
+
+/* 
+  Save current form+cursor position. Simplified version, which will not work with pseudo scrolling forms
+*/
+void mui_SaveForm(mui_t *ui)
+{
+  mui_SaveFormWithCursorPosition(ui, mui_GetCurrentCursorFocusPosition(ui));
 }
 
+
 /*
+  Restore previous saved form and cursor position.
   if called from a field function, then the current field variables are destroyed, so that call should be the last call in the field callback.
+  returns 0 if there is no form to restore
 */
-void mui_RestoreForm(mui_t *ui)
+uint8_t mui_RestoreForm(mui_t *ui)
 {
-  mui_GotoForm(ui, ui->last_form_id, ui->last_form_cursor_focus_position);
+  MUI_DEBUG("mui_RestoreForm last_form_stack_pos=%d\n", ui->last_form_stack_pos);
+  if ( ui->last_form_stack_pos >= 0 )
+  {
+    uint8_t form_id = ui->last_form_id[ui->last_form_stack_pos];
+    uint8_t focus = ui->last_form_cursor_focus_position[ui->last_form_stack_pos];
+    ui->last_form_stack_pos--;
+    return mui_GotoForm(ui, form_id, focus);
+    //ui->last_form_fds = NULL;
+  }
+  return 0;
 }
 
 /*
   Save a cursor position for mui_GotoFormAutoCursorPosition command
-  Two such positions is stored.
 */
 void mui_SaveCursorPosition(mui_t *ui, uint8_t cursor_position)
 {
   uint8_t form_id = mui_get_fds_char(ui->current_form_fds+1);
+  uint8_t i;
   MUI_DEBUG("mui_SaveCursorPosition form_id=%d cursor_position=%d\n", form_id, cursor_position);
   
+  for( i = 0; i < MUI_MENU_CACHE_CNT; i++ )
+  {
+    if ( form_id == ui->menu_form_id[i] )
+    {
+      ui->menu_form_last_added = i;
+      break;
+    }
+  }
+  if ( i >= MUI_MENU_CACHE_CNT )
+  {
+      ui->menu_form_last_added++ ;
+      if ( ui->menu_form_last_added >= MUI_MENU_CACHE_CNT )
+        ui->menu_form_last_added = 0;
+  }
+    
+  /*
   if ( form_id == ui->menu_form_id[0] )
     ui->menu_form_last_added = 0;
   else if ( form_id == ui->menu_form_id[1] )
     ui->menu_form_last_added = 1;
   else 
     ui->menu_form_last_added ^= 1;
+  */
   ui->menu_form_id[ui->menu_form_last_added] = form_id;
   ui->menu_form_cursor_focus_position[ui->menu_form_last_added] = cursor_position;
   MUI_DEBUG("mui_SaveCursorPosition ui->menu_form_last_added=%d \n", ui->menu_form_last_added);

+ 12 - 7
components/u8g2/mui.h

@@ -223,7 +223,9 @@ struct muif_struct
 #define MUI_MAX_TEXT_LEN 41
 #endif
 
-#define MUI_MENU_CACHE_CNT 2
+#define MUI_MENU_CACHE_CNT 4
+
+#define MUI_MENU_LAST_FORM_STACK_SIZE 4
 
 struct mui_struct
 {
@@ -259,7 +261,7 @@ struct mui_struct
   uint8_t x;               // position of the field
   uint8_t y;
   uint8_t dflags;
-  uint8_t arg;          // extra argument of the field. For example the G: form is put here
+  uint8_t arg;          // extra argument of the field. For example the G: form is put here, assigned by MUI_XYA or MUI_XYAT 
   int len;          // length of the current command
   fds_t *fds;             // current position, *fds = cmd
   muif_t *uif;                   // user interface field or style for the given id0 / id1, assigned by mui_prepare_current_field()
@@ -270,14 +272,16 @@ struct mui_struct
   fds_t *target_fds;     // used by several task functions as a return / result value
   
   /* last form and field, used by mui_SaveForm and mui_RestoreForm */
-  uint8_t last_form_id;
-  uint8_t last_form_cursor_focus_position;
-  fds_t *last_form_fds;           // not used by mui_RestoreForm, but can be used by field functions
+  uint8_t last_form_id[MUI_MENU_LAST_FORM_STACK_SIZE];
+  uint8_t last_form_cursor_focus_position[MUI_MENU_LAST_FORM_STACK_SIZE];
+  fds_t *last_form_fds;           // not used by mui_RestoreForm, but can be used by field functions, warning: this is the FDS of the field, from where the jump started to the child (cursor_focus_fds)
+  int8_t last_form_stack_pos;
   
   /* menu cursor position backup */
+  /* idea is, to restore the cursor position if we jump to that form */
+  uint8_t menu_form_last_added;
   uint8_t menu_form_id[MUI_MENU_CACHE_CNT];
   uint8_t menu_form_cursor_focus_position[MUI_MENU_CACHE_CNT];
-  uint8_t menu_form_last_added;
 } ;
 
 #define mui_IsCursorFocus(mui) ((mui)->dflags & MUIF_DFLAG_IS_CURSOR_FOCUS)
@@ -583,8 +587,9 @@ uint8_t mui_GetSelectableFieldOptionCnt(mui_t *ui, fds_t *fds);
 void mui_EnterForm(mui_t *ui, fds_t *fds, uint8_t initial_cursor_position);
 void mui_LeaveForm(mui_t *ui);
 uint8_t mui_GotoForm(mui_t *ui, uint8_t form_id, uint8_t initial_cursor_position);
+void mui_SaveFormWithCursorPosition(mui_t *ui, uint8_t cursor_pos); /* Save current form with manully provied cursor position, Used together with mui_RestoreForm */
 void mui_SaveForm(mui_t *ui);     /* Save current form+cursor position. Used together with mui_RestoreForm */
-void mui_RestoreForm(mui_t *ui);        /* Restore form and cursor position, previously saved with mui_SaveForm */
+uint8_t mui_RestoreForm(mui_t *ui);        /* Restore form and cursor position, previously saved with mui_SaveForm */
 void mui_SaveCursorPosition(mui_t *ui, uint8_t cursor_position);         /* stores a cursor position for use with mui_GotoFormAutoCursorPosition */
 uint8_t mui_GotoFormAutoCursorPosition(mui_t *ui, uint8_t form_id);
 

Fișier diff suprimat deoarece este prea mare
+ 857 - 187
components/u8g2/mui_u8g2.c


+ 53 - 2
components/u8g2/mui_u8g2.h

@@ -65,6 +65,7 @@
 #ifndef MUI_U8G2_H
 #define MUI_U8G2_H
 
+#include "u8g2.h"
 #include "mui.h"
 
 /*==========================================*/
@@ -122,6 +123,26 @@ typedef const struct mui_u8g2_u8_min_max_struct mui_u8g2_u8_min_max_t;
 #  define mui_u8g2_u8mm_get_valptr(u8mm) ((u8mm)->value)
 #endif
 
+struct mui_u8g2_s8_min_max_struct
+{
+  int8_t *value;
+  int8_t min;
+  int8_t max;
+} MUI_PROGMEM;
+
+typedef const struct mui_u8g2_s8_min_max_struct mui_u8g2_s8_min_max_t;
+
+#if defined(__GNUC__) && defined(__AVR__)
+#  define mui_u8g2_s8mm_get_min(u8mm) ((int8_t)mui_pgm_read(&((u8mm)->min)))
+#  define mui_u8g2_s8mm_get_max(u8mm) ((int8_t)mui_pgm_read(&((u8mm)->max)))
+#  define mui_u8g2_s8mm_get_valptr(u8mm) ((int8_t *)mui_pgm_wread(&((u8mm)->value)))
+#else
+#  define mui_u8g2_s8mm_get_min(u8mm) ((u8mm)->min)
+#  define mui_u8g2_s8mm_get_max(u8mm) ((u8mm)->max)
+#  define mui_u8g2_s8mm_get_valptr(u8mm) ((u8mm)->value)
+#endif
+
+
 
 struct mui_u8g2_u8_min_max_step_struct
 {
@@ -164,6 +185,8 @@ typedef const struct mui_u8g2_u8_min_max_step_struct mui_u8g2_u8_min_max_step_t;
 
 u8g2_uint_t mui_get_x(mui_t *ui);
 u8g2_uint_t mui_get_y(mui_t *ui);
+u8g2_uint_t mui_get_arg(mui_t *ui);
+char *mui_get_text(mui_t *ui);
 u8g2_t *mui_get_U8g2(mui_t *ui);
 
 void mui_u8g2_draw_button_utf(mui_t *ui, u8g2_uint_t flags, u8g2_uint_t width, u8g2_uint_t padding_h, u8g2_uint_t padding_v, const char *text);
@@ -180,15 +203,27 @@ void mui_u8g2_draw_button_if(mui_t *ui, u8g2_uint_t width, u8g2_uint_t padding_h
 
 /* ready to use field functions */
 
+uint8_t mui_hline(mui_t *ui, uint8_t msg);
+
 uint8_t mui_u8g2_draw_text(mui_t *ui, uint8_t msg);
+
 uint8_t mui_u8g2_btn_goto_wm_fi(mui_t *ui, uint8_t msg);        /* GIF */
 uint8_t mui_u8g2_btn_goto_wm_if(mui_t *ui, uint8_t msg);
 uint8_t mui_u8g2_btn_goto_w2_fi(mui_t *ui, uint8_t msg);         /* GIF */
 uint8_t mui_u8g2_btn_goto_w2_if(mui_t *ui, uint8_t msg);
-
 uint8_t mui_u8g2_btn_goto_w1_pi(mui_t *ui, uint8_t msg);        /* GIF */
 uint8_t mui_u8g2_btn_goto_w1_fi(mui_t *ui, uint8_t msg);        /* GIF */
 
+uint8_t mui_u8g2_btn_back_wm_fi(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_btn_back_wm_if(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_btn_back_w2_fi(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_btn_back_w2_if(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_btn_back_w1_pi(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_btn_back_w1_fi(mui_t *ui, uint8_t msg);
+
+
+
+
 uint8_t mui_u8g2_btn_exit_wm_fi(mui_t *ui, uint8_t msg);        /* similar to 'mui_u8g2_btn_goto_wm_fi' but will exit the menu system */
 
 uint8_t mui_u8g2_u8_chkbox_wm_pi(mui_t *ui, uint8_t msg);       /* GIF, MUIF_VARIABLE, MUI_XY */
@@ -247,10 +282,26 @@ uint8_t mui_u8g2_set_font_style_function(mui_t *ui, uint8_t msg);
 
 uint8_t mui_u8g2_u8_min_max_wm_mse_pi(mui_t *ui, uint8_t msg);   /* GIF, MUIF_U8G2_U8_MIN_MAX, MUI_XY */
 uint8_t mui_u8g2_u8_min_max_wm_mud_pi(mui_t *ui, uint8_t msg);  /* GIF, MUIF_U8G2_U8_MIN_MAX, MUI_XY */
-
 uint8_t mui_u8g2_u8_min_max_wm_mse_pf(mui_t *ui, uint8_t msg);  /* GIF, MUIF_U8G2_U8_MIN_MAX, MUI_XY */
 uint8_t mui_u8g2_u8_min_max_wm_mud_pf(mui_t *ui, uint8_t msg);  /* GIF, MUIF_U8G2_U8_MIN_MAX, MUI_XY */
 
+/* hex format */
+uint8_t mui_u8g2_x8_min_max_wm_mse_pi(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_x8_min_max_wm_mud_pi(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_x8_min_max_wm_mse_pf(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_x8_min_max_wm_mud_pf(mui_t *ui, uint8_t msg);
+
+#define MUIF_U8G2_S8_MIN_MAX(id, valptr, min, max, muif) \
+  MUIF(id, MUIF_CFLAG_IS_CURSOR_SELECTABLE,  \
+  (void *)((mui_u8g2_s8_min_max_t [] ) {{ (valptr) MUI_U8G2_COMMA (min) MUI_U8G2_COMMA (max)}}), \
+  (muif))
+
+uint8_t mui_u8g2_s8_min_max_wm_mse_pi(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_s8_min_max_wm_mud_pi(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_s8_min_max_wm_mse_pf(mui_t *ui, uint8_t msg);
+uint8_t mui_u8g2_s8_min_max_wm_mud_pf(mui_t *ui, uint8_t msg);
+
+
 /*===== data = mui_u8g2_u8_min_max_step_t*  =====*/
 
 /* gcc note: the macro uses array compound literals to extend the lifetime in C++, see last section in https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html */

+ 289 - 5
components/u8g2/u8g2.h

@@ -59,7 +59,9 @@
 #define U8G2_H
 
 #include "u8x8.h"
+#if (defined __LUATOS__) || defined (__USER_CODE__)
 #include "stdio.h"
+#endif
 /*
   The following macro enables 16 Bit mode. 
   Without defining this macro all calculations are done with 8 Bit (1 Byte) variables.
@@ -521,6 +523,9 @@ uint8_t *u8g2_m_6_8_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_12_2_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_12_2_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_12_2_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_15_4_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_15_4_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_15_4_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_12_4_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_12_4_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_12_4_f(uint8_t *page_cnt);
@@ -551,6 +556,9 @@ uint8_t *u8g2_m_50_30_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_18_21_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_18_21_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_18_21_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_20_9_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_20_9_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_20_9_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_11_6_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_11_6_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_11_6_f(uint8_t *page_cnt);
@@ -569,6 +577,9 @@ uint8_t *u8g2_m_30_15_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_30_16_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_30_16_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_30_16_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_32_16_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_32_16_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_32_16_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_16_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_16_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_16_f(uint8_t *page_cnt);
@@ -581,9 +592,6 @@ uint8_t *u8g2_m_20_13_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_30_20_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_30_20_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_30_20_f(uint8_t *page_cnt);
-uint8_t *u8g2_m_32_16_1(uint8_t *page_cnt);
-uint8_t *u8g2_m_32_16_2(uint8_t *page_cnt);
-uint8_t *u8g2_m_32_16_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_40_30_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_40_30_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_40_30_f(uint8_t *page_cnt);
@@ -599,6 +607,15 @@ uint8_t *u8g2_m_17_8_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_17_9_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_17_9_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_17_9_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_16_32_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_16_32_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_16_32_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_26_25_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_26_25_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_26_25_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_21_48_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_21_48_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_21_48_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_48_17_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_48_17_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_48_17_f(uint8_t *page_cnt);
@@ -623,6 +640,9 @@ uint8_t *u8g2_m_20_10_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_19_4_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_19_4_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_19_4_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_16_9_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_16_9_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_16_9_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_17_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_17_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_17_f(uint8_t *page_cnt);
@@ -650,6 +670,9 @@ uint8_t *u8g2_m_4_1_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_1_1_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_1_1_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_1_1_f(uint8_t *page_cnt);
+uint8_t *u8g2_m_13_4_1(uint8_t *page_cnt);
+uint8_t *u8g2_m_13_4_2(uint8_t *page_cnt);
+uint8_t *u8g2_m_13_4_f(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_2_1(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_2_2(uint8_t *page_cnt);
 uint8_t *u8g2_m_20_2_f(uint8_t *page_cnt);
@@ -822,6 +845,12 @@ void u8g2_Setup_sh1108_128x160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_m
 void u8g2_Setup_sh1108_i2c_128x160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sh1108_i2c_128x160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sh1108_i2c_128x160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ch1120_128x160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ch1120_128x160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ch1120_128x160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ch1120_i2c_128x160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ch1120_i2c_128x160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ch1120_i2c_128x160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sh1108_160x160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sh1108_160x160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sh1108_160x160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -900,6 +929,30 @@ void u8g2_Setup_ssd1309_128x64_noname0_f(u8g2_t *u8g2, const u8g2_cb_t *rotation
 void u8g2_Setup_ssd1309_i2c_128x64_noname0_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1309_i2c_128x64_noname0_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1309_i2c_128x64_noname0_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1309_128x128_noname0_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1309_128x128_noname0_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1309_128x128_noname0_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1309_i2c_128x128_noname0_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1309_i2c_128x128_noname0_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1309_i2c_128x128_noname0_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_128x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_128x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_128x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_128x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_128x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_128x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_120x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_120x28_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_120x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_120x28_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_120x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_120x28_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_120x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_120x28_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_120x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_120x28_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_120x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1312_i2c_120x28_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1316_128x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1316_128x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1316_128x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -974,12 +1027,15 @@ void u8g2_Setup_ssd1327_zjy_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u
 void u8g2_Setup_ssd1327_ws_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_ea_w128128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_midas_128x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1327_i2c_zjy_128x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_ws_128x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_ea_w128128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_midas_128x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1327_i2c_zjy_128x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_ws_128x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_ea_w128128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_midas_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1327_i2c_zjy_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_i2c_ws_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_visionox_128x96_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1327_visionox_128x96_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1029,6 +1085,15 @@ void u8g2_Setup_st7920_144x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_ms
 void u8g2_Setup_st7920_s_144x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7920_s_144x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7920_s_144x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_p_128x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_p_128x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_p_128x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_128x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_128x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_128x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_s_128x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_s_128x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7920_s_128x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7920_p_160x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7920_p_160x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7920_p_160x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1068,6 +1133,9 @@ void u8g2_Setup_ls027b7dh01_m0_400x240_f(u8g2_t *u8g2, const u8g2_cb_t *rotation
 void u8g2_Setup_ls013b7dh05_144x168_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ls013b7dh05_144x168_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ls013b7dh05_144x168_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ls011b7dh03_160x68_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ls011b7dh03_160x68_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ls011b7dh03_160x68_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1701_ea_dogs102_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1701_ea_dogs102_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1701_ea_dogs102_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1080,6 +1148,9 @@ void u8g2_Setup_pcd8544_84x48_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_ms
 void u8g2_Setup_pcf8812_96x65_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_pcf8812_96x65_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_pcf8812_96x65_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_pcf8812_101x64_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_pcf8812_101x64_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_pcf8812_101x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_hx1230_96x68_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_hx1230_96x68_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_hx1230_96x68_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1089,6 +1160,12 @@ void u8g2_Setup_uc1604_jlx19264_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_
 void u8g2_Setup_uc1604_i2c_jlx19264_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1604_i2c_jlx19264_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1604_i2c_jlx19264_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1604_jlx12864_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1604_jlx12864_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1604_jlx12864_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1604_i2c_jlx12864_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1604_i2c_jlx12864_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1604_i2c_jlx12864_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1608_erc24064_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1608_dem240064_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1608_erc24064_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1119,6 +1196,24 @@ void u8g2_Setup_uc1609_slg19264_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_
 void u8g2_Setup_uc1609_i2c_slg19264_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1609_i2c_slg19264_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1609_i2c_slg19264_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_128x64_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_128x64_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_128x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_128x64_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_128x64_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_128x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_256x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_256x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_256x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_256x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_256x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_256x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_256x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_256x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_256x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_256x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_256x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_uc1628_i2c_256x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1638_160x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1638_160x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_uc1638_160x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1284,6 +1379,15 @@ void u8g2_Setup_st7567_erc13232_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_
 void u8g2_Setup_st7567_i2c_erc13232_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_i2c_erc13232_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_i2c_erc13232_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_erc12864_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_erc12864_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_erc12864_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_96x65_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_96x65_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_96x65_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_i2c_96x65_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_i2c_96x65_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_i2c_96x65_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_122x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_122x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_122x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1303,8 +1407,11 @@ void u8g2_Setup_st7567_i2c_hem6432_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8
 void u8g2_Setup_st7567_i2c_64x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_i2c_hem6432_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_lw12832_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_yxd12832_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_lw12832_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_yxd12832_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_lw12832_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7567_yxd12832_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_i2c_lw12832_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_i2c_lw12832_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7567_i2c_lw12832_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1315,11 +1422,29 @@ void u8g2_Setup_st7571_i2c_128x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8
 void u8g2_Setup_st7571_i2c_128x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7571_i2c_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7571_128x96_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7571_g12896_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7571_128x96_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7571_g12896_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7571_128x96_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7571_g12896_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7571_i2c_128x96_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7571_i2c_g12896_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7571_i2c_128x96_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7571_i2c_g12896_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7571_i2c_128x96_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7571_i2c_g12896_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7302_122x250_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7302_122x250_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7302_122x250_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_122x250_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_122x250_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_122x250_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_200x200_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_200x200_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_200x200_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_168x384_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_168x384_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7305_168x384_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7586s_s028hn118a_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7586s_s028hn118a_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7586s_s028hn118a_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1335,6 +1460,9 @@ void u8g2_Setup_st7586s_ymc240160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x
 void u8g2_Setup_st7586s_jlx320160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7586s_jlx320160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7586s_jlx320160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7586s_md240128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7586s_md240128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st7586s_md240128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7588_jlx12864_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7588_jlx12864_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st7588_jlx12864_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1347,6 +1475,12 @@ void u8g2_Setup_st75160_jm16096_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_
 void u8g2_Setup_st75160_i2c_jm16096_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75160_i2c_jm16096_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75160_i2c_jm16096_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75161_jlx160160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75161_jlx160160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75161_jlx160160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75161_i2c_jlx160160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75161_i2c_jlx160160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75161_i2c_jlx160160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_jlx256128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_wo256x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_jlx256128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1359,6 +1493,12 @@ void u8g2_Setup_st75256_i2c_jlx256128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation,
 void u8g2_Setup_st75256_i2c_wo256x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_i2c_jlx256128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_i2c_wo256x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75256_128x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75256_128x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75256_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75256_i2c_128x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75256_i2c_128x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_st75256_i2c_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_jlx256160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_jlx256160m_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_st75256_jlx256160_alt_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1479,9 +1619,15 @@ void u8g2_Setup_t6963_160x80_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg
 void u8g2_Setup_t6963_128x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_t6963_128x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_t6963_128x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_t6963_128x160_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_t6963_128x160_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_t6963_128x160_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1320_160x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1320_160x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1320_160x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1320_128x72_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1320_128x72_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1320_128x72_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1320_160x132_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1320_160x132_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1320_160x132_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1492,11 +1638,17 @@ void u8g2_Setup_ssd1320_i2c_160x80_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8
 void u8g2_Setup_ssd1320_i2c_160x80_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1320_i2c_160x80_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_240x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1322_topwin_240x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_240x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1322_topwin_240x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_240x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1322_topwin_240x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_nhd_256x64_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1322_zjy_256x64_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_nhd_256x64_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1322_zjy_256x64_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_nhd_256x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1322_zjy_256x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_nhd_128x64_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_nhd_128x64_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1322_nhd_128x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1512,6 +1664,12 @@ void u8g2_Setup_ssd1362_206x36_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_m
 void u8g2_Setup_ssd1362_i2c_206x36_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1362_i2c_206x36_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1362_i2c_206x36_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1363_256x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1363_256x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1363_256x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1363_i2c_256x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1363_i2c_256x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1363_i2c_256x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1606_172x72_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1606_172x72_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_ssd1606_172x72_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1533,6 +1691,9 @@ void u8g2_Setup_il3820_v2_296x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x
 void u8g2_Setup_sed1330_240x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sed1330_240x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sed1330_240x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_sed1330_240x64_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_sed1330_240x64_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_sed1330_240x64_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sed1330_256x128_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sed1330_256x128_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_sed1330_256x128_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1557,6 +1718,15 @@ void u8g2_Setup_max7219_8x8_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_
 void u8g2_Setup_s1d15300_lm6023_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_s1d15300_lm6023_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_s1d15300_lm6023_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_97x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_100x32_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_100x32i_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_97x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_100x32_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_100x32i_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_97x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_100x32_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_s1d15300_100x32i_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_s1d15e06_160100_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_s1d15e06_160100_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_s1d15e06_160100_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
@@ -1581,6 +1751,13 @@ void u8g2_Setup_gp1294ai_256x48_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_
 void u8g2_Setup_a2printer_384x240_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_a2printer_384x240_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
 void u8g2_Setup_a2printer_384x240_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1315_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1315_128x64_noname_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1315_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1315_i2c_128x64_noname_1(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1315_i2c_128x64_noname_2(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+void u8g2_Setup_ssd1315_i2c_128x64_noname_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb);
+
 void u8g2_Setup_st7565_jlx12864g109pc_f(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb); // 2023年8月4日 晶联讯12864G-109-PC,12864G-139-P
 
 /* u8g2_d_setup.c generated code end */
@@ -1603,8 +1780,8 @@ uint8_t u8g2_NextPage(u8g2_t *u8g2);
 
 #ifdef U8G2_USE_DYNAMIC_ALLOC
 #define u8g2_SetBufferPtr(u8g2, buf) ((u8g2)->tile_buf_ptr = (buf));
-#define u8g2_GetBufferSize(u8g2) ((u8g2)->u8x8.display_info->tile_width * 8 * (u8g2)->tile_buf_height)
 #endif
+#define u8g2_GetBufferSize(u8g2) ((u8g2)->u8x8.display_info->tile_width * 8 * (u8g2)->tile_buf_height)
 #define u8g2_GetBufferPtr(u8g2) ((u8g2)->tile_buf_ptr)
 #define u8g2_GetBufferTileHeight(u8g2)	((u8g2)->tile_buf_height)
 #define u8g2_GetBufferTileWidth(u8g2)	(u8g2_GetU8x8(u8g2)->display_info->tile_width)
@@ -1682,6 +1859,12 @@ void u8g2_DrawDisc(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad
 void u8g2_DrawEllipse(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t option);
 void u8g2_DrawFilledEllipse(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t option);
 
+
+/*==========================================*/
+/* u8g2_arc.c */
+void u8g2_DrawArc(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t start, uint8_t end);
+
+
 /*==========================================*/
 /* u8g2_line.c */
 void u8g2_DrawLine(u8g2_t *u8g2, u8g2_uint_t x1, u8g2_uint_t y1, u8g2_uint_t x2, u8g2_uint_t y2);
@@ -1759,9 +1942,12 @@ void u8g2_SetFontMode(u8g2_t *u8g2, uint8_t is_transparent);
 
 uint8_t u8g2_IsGlyph(u8g2_t *u8g2, uint16_t requested_encoding);
 int8_t u8g2_GetGlyphWidth(u8g2_t *u8g2, uint16_t requested_encoding);
+
 u8g2_uint_t u8g2_DrawGlyph(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding);
 u8g2_uint_t u8g2_DrawGlyphX2(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding);
-int8_t u8g2_GetStrX(u8g2_t *u8g2, const char *s);	/* for u8g compatibility */
+int8_t u8g2_GetStrX(u8g2_t *u8g2, const char *s);	/* for u8g compatibility, WARNING: use u8g2_GetGlyphXOffset() instead! */
+int8_t u8g2_GetXOffsetGlyph(u8g2_t *u8g2, uint16_t encoding);
+int8_t u8g2_GetXOffsetUTF8(u8g2_t *u8g2, const char *utf8);
 
 void u8g2_SetFontDirection(u8g2_t *u8g2, uint8_t dir);
 u8g2_uint_t u8g2_DrawStr(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const char *str);
@@ -1794,6 +1980,9 @@ void u8g2_SetFontRefHeightText(u8g2_t *u8g2);
 void u8g2_SetFontRefHeightExtendedText(u8g2_t *u8g2);
 void u8g2_SetFontRefHeightAll(u8g2_t *u8g2);
 
+void u8g2_DrawHB(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const unsigned char *data);
+
+
 /*==========================================*/
 /* u8log_u8g2.c */
 void u8g2_DrawLog(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8log_t *u8log);
@@ -1820,6 +2009,7 @@ uint8_t u8g2_UserInterfaceInputValue(u8g2_t *u8g2, const char *title, const char
 void u8g2_SetupBuffer_SDL_128x64(u8g2_t *u8g2, const u8g2_cb_t *u8g2_cb);
 void u8g2_SetupBuffer_SDL_128x64_4(u8g2_t *u8g2, const u8g2_cb_t *u8g2_cb);
 void u8g2_SetupBuffer_SDL_128x64_1(u8g2_t *u8g2, const u8g2_cb_t *u8g2_cb);
+void u8g2_SetupBuffer_SDL_256x128(u8g2_t *u8g2, const u8g2_cb_t *u8g2_cb);
 
 /*==========================================*/
 /* u8x8_d_tga.c */
@@ -1880,6 +2070,8 @@ extern const uint8_t u8g2_font_7_Seg_33x19_mn[] U8G2_FONT_SECTION("u8g2_font_7_S
 extern const uint8_t u8g2_font_7_Seg_41x21_mn[] U8G2_FONT_SECTION("u8g2_font_7_Seg_41x21_mn");
 extern const uint8_t u8g2_font_tiny5_tf[] U8G2_FONT_SECTION("u8g2_font_tiny5_tf");
 extern const uint8_t u8g2_font_tiny5_tr[] U8G2_FONT_SECTION("u8g2_font_tiny5_tr");
+extern const uint8_t u8g2_font_tiny5_te[] U8G2_FONT_SECTION("u8g2_font_tiny5_te");
+extern const uint8_t u8g2_font_tiny5_t_all[] U8G2_FONT_SECTION("u8g2_font_tiny5_t_all");
 extern const uint8_t u8g2_font_04b_03b_tr[] U8G2_FONT_SECTION("u8g2_font_04b_03b_tr");
 extern const uint8_t u8g2_font_04b_03_tr[] U8G2_FONT_SECTION("u8g2_font_04b_03_tr");
 extern const uint8_t u8g2_font_amstrad_cpc_extended_8f[] U8G2_FONT_SECTION("u8g2_font_amstrad_cpc_extended_8f");
@@ -2084,6 +2276,7 @@ extern const uint8_t u8g2_font_t0_11_mr[] U8G2_FONT_SECTION("u8g2_font_t0_11_mr"
 extern const uint8_t u8g2_font_t0_11_mn[] U8G2_FONT_SECTION("u8g2_font_t0_11_mn");
 extern const uint8_t u8g2_font_t0_11_me[] U8G2_FONT_SECTION("u8g2_font_t0_11_me");
 extern const uint8_t u8g2_font_t0_11_t_all[] U8G2_FONT_SECTION("u8g2_font_t0_11_t_all");
+extern const uint8_t u8g2_font_t0_11_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_11_t_symbol");
 extern const uint8_t u8g2_font_t0_11b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_11b_tf");
 extern const uint8_t u8g2_font_t0_11b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_11b_tr");
 extern const uint8_t u8g2_font_t0_11b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_11b_tn");
@@ -2100,6 +2293,7 @@ extern const uint8_t u8g2_font_t0_12_mf[] U8G2_FONT_SECTION("u8g2_font_t0_12_mf"
 extern const uint8_t u8g2_font_t0_12_mr[] U8G2_FONT_SECTION("u8g2_font_t0_12_mr");
 extern const uint8_t u8g2_font_t0_12_mn[] U8G2_FONT_SECTION("u8g2_font_t0_12_mn");
 extern const uint8_t u8g2_font_t0_12_me[] U8G2_FONT_SECTION("u8g2_font_t0_12_me");
+extern const uint8_t u8g2_font_t0_12_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_12_t_symbol");
 extern const uint8_t u8g2_font_t0_12b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_12b_tf");
 extern const uint8_t u8g2_font_t0_12b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_12b_tr");
 extern const uint8_t u8g2_font_t0_12b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_12b_tn");
@@ -2116,6 +2310,7 @@ extern const uint8_t u8g2_font_t0_13_mf[] U8G2_FONT_SECTION("u8g2_font_t0_13_mf"
 extern const uint8_t u8g2_font_t0_13_mr[] U8G2_FONT_SECTION("u8g2_font_t0_13_mr");
 extern const uint8_t u8g2_font_t0_13_mn[] U8G2_FONT_SECTION("u8g2_font_t0_13_mn");
 extern const uint8_t u8g2_font_t0_13_me[] U8G2_FONT_SECTION("u8g2_font_t0_13_me");
+extern const uint8_t u8g2_font_t0_13_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_13_t_symbol");
 extern const uint8_t u8g2_font_t0_13b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_13b_tf");
 extern const uint8_t u8g2_font_t0_13b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_13b_tr");
 extern const uint8_t u8g2_font_t0_13b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_13b_tn");
@@ -2132,6 +2327,7 @@ extern const uint8_t u8g2_font_t0_14_mf[] U8G2_FONT_SECTION("u8g2_font_t0_14_mf"
 extern const uint8_t u8g2_font_t0_14_mr[] U8G2_FONT_SECTION("u8g2_font_t0_14_mr");
 extern const uint8_t u8g2_font_t0_14_mn[] U8G2_FONT_SECTION("u8g2_font_t0_14_mn");
 extern const uint8_t u8g2_font_t0_14_me[] U8G2_FONT_SECTION("u8g2_font_t0_14_me");
+extern const uint8_t u8g2_font_t0_14_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_14_t_symbol");
 extern const uint8_t u8g2_font_t0_14b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_14b_tf");
 extern const uint8_t u8g2_font_t0_14b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_14b_tr");
 extern const uint8_t u8g2_font_t0_14b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_14b_tn");
@@ -2148,6 +2344,7 @@ extern const uint8_t u8g2_font_t0_15_mf[] U8G2_FONT_SECTION("u8g2_font_t0_15_mf"
 extern const uint8_t u8g2_font_t0_15_mr[] U8G2_FONT_SECTION("u8g2_font_t0_15_mr");
 extern const uint8_t u8g2_font_t0_15_mn[] U8G2_FONT_SECTION("u8g2_font_t0_15_mn");
 extern const uint8_t u8g2_font_t0_15_me[] U8G2_FONT_SECTION("u8g2_font_t0_15_me");
+extern const uint8_t u8g2_font_t0_15_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_15_t_symbol");
 extern const uint8_t u8g2_font_t0_15b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_15b_tf");
 extern const uint8_t u8g2_font_t0_15b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_15b_tr");
 extern const uint8_t u8g2_font_t0_15b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_15b_tn");
@@ -2164,6 +2361,7 @@ extern const uint8_t u8g2_font_t0_16_mf[] U8G2_FONT_SECTION("u8g2_font_t0_16_mf"
 extern const uint8_t u8g2_font_t0_16_mr[] U8G2_FONT_SECTION("u8g2_font_t0_16_mr");
 extern const uint8_t u8g2_font_t0_16_mn[] U8G2_FONT_SECTION("u8g2_font_t0_16_mn");
 extern const uint8_t u8g2_font_t0_16_me[] U8G2_FONT_SECTION("u8g2_font_t0_16_me");
+extern const uint8_t u8g2_font_t0_16_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_16_t_symbol");
 extern const uint8_t u8g2_font_t0_16b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_16b_tf");
 extern const uint8_t u8g2_font_t0_16b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_16b_tr");
 extern const uint8_t u8g2_font_t0_16b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_16b_tn");
@@ -2180,6 +2378,7 @@ extern const uint8_t u8g2_font_t0_17_mf[] U8G2_FONT_SECTION("u8g2_font_t0_17_mf"
 extern const uint8_t u8g2_font_t0_17_mr[] U8G2_FONT_SECTION("u8g2_font_t0_17_mr");
 extern const uint8_t u8g2_font_t0_17_mn[] U8G2_FONT_SECTION("u8g2_font_t0_17_mn");
 extern const uint8_t u8g2_font_t0_17_me[] U8G2_FONT_SECTION("u8g2_font_t0_17_me");
+extern const uint8_t u8g2_font_t0_17_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_17_t_symbol");
 extern const uint8_t u8g2_font_t0_17b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_17b_tf");
 extern const uint8_t u8g2_font_t0_17b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_17b_tr");
 extern const uint8_t u8g2_font_t0_17b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_17b_tn");
@@ -2196,6 +2395,7 @@ extern const uint8_t u8g2_font_t0_18_mf[] U8G2_FONT_SECTION("u8g2_font_t0_18_mf"
 extern const uint8_t u8g2_font_t0_18_mr[] U8G2_FONT_SECTION("u8g2_font_t0_18_mr");
 extern const uint8_t u8g2_font_t0_18_mn[] U8G2_FONT_SECTION("u8g2_font_t0_18_mn");
 extern const uint8_t u8g2_font_t0_18_me[] U8G2_FONT_SECTION("u8g2_font_t0_18_me");
+extern const uint8_t u8g2_font_t0_18_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_18_t_symbol");
 extern const uint8_t u8g2_font_t0_18b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_18b_tf");
 extern const uint8_t u8g2_font_t0_18b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_18b_tr");
 extern const uint8_t u8g2_font_t0_18b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_18b_tn");
@@ -2212,6 +2412,7 @@ extern const uint8_t u8g2_font_t0_22_mf[] U8G2_FONT_SECTION("u8g2_font_t0_22_mf"
 extern const uint8_t u8g2_font_t0_22_mr[] U8G2_FONT_SECTION("u8g2_font_t0_22_mr");
 extern const uint8_t u8g2_font_t0_22_mn[] U8G2_FONT_SECTION("u8g2_font_t0_22_mn");
 extern const uint8_t u8g2_font_t0_22_me[] U8G2_FONT_SECTION("u8g2_font_t0_22_me");
+extern const uint8_t u8g2_font_t0_22_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_22_t_symbol");
 extern const uint8_t u8g2_font_t0_22b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_22b_tf");
 extern const uint8_t u8g2_font_t0_22b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_22b_tr");
 extern const uint8_t u8g2_font_t0_22b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_22b_tn");
@@ -2220,6 +2421,40 @@ extern const uint8_t u8g2_font_t0_22b_mf[] U8G2_FONT_SECTION("u8g2_font_t0_22b_m
 extern const uint8_t u8g2_font_t0_22b_mr[] U8G2_FONT_SECTION("u8g2_font_t0_22b_mr");
 extern const uint8_t u8g2_font_t0_22b_mn[] U8G2_FONT_SECTION("u8g2_font_t0_22b_mn");
 extern const uint8_t u8g2_font_t0_22b_me[] U8G2_FONT_SECTION("u8g2_font_t0_22b_me");
+extern const uint8_t u8g2_font_t0_30_tf[] U8G2_FONT_SECTION("u8g2_font_t0_30_tf");
+extern const uint8_t u8g2_font_t0_30_tr[] U8G2_FONT_SECTION("u8g2_font_t0_30_tr");
+extern const uint8_t u8g2_font_t0_30_tn[] U8G2_FONT_SECTION("u8g2_font_t0_30_tn");
+extern const uint8_t u8g2_font_t0_30_te[] U8G2_FONT_SECTION("u8g2_font_t0_30_te");
+extern const uint8_t u8g2_font_t0_30_mf[] U8G2_FONT_SECTION("u8g2_font_t0_30_mf");
+extern const uint8_t u8g2_font_t0_30_mr[] U8G2_FONT_SECTION("u8g2_font_t0_30_mr");
+extern const uint8_t u8g2_font_t0_30_mn[] U8G2_FONT_SECTION("u8g2_font_t0_30_mn");
+extern const uint8_t u8g2_font_t0_30_me[] U8G2_FONT_SECTION("u8g2_font_t0_30_me");
+extern const uint8_t u8g2_font_t0_30_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_30_t_symbol");
+extern const uint8_t u8g2_font_t0_30b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_30b_tf");
+extern const uint8_t u8g2_font_t0_30b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_30b_tr");
+extern const uint8_t u8g2_font_t0_30b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_30b_tn");
+extern const uint8_t u8g2_font_t0_30b_te[] U8G2_FONT_SECTION("u8g2_font_t0_30b_te");
+extern const uint8_t u8g2_font_t0_30b_mf[] U8G2_FONT_SECTION("u8g2_font_t0_30b_mf");
+extern const uint8_t u8g2_font_t0_30b_mr[] U8G2_FONT_SECTION("u8g2_font_t0_30b_mr");
+extern const uint8_t u8g2_font_t0_30b_mn[] U8G2_FONT_SECTION("u8g2_font_t0_30b_mn");
+extern const uint8_t u8g2_font_t0_30b_me[] U8G2_FONT_SECTION("u8g2_font_t0_30b_me");
+extern const uint8_t u8g2_font_t0_40_tf[] U8G2_FONT_SECTION("u8g2_font_t0_40_tf");
+extern const uint8_t u8g2_font_t0_40_tr[] U8G2_FONT_SECTION("u8g2_font_t0_40_tr");
+extern const uint8_t u8g2_font_t0_40_tn[] U8G2_FONT_SECTION("u8g2_font_t0_40_tn");
+extern const uint8_t u8g2_font_t0_40_te[] U8G2_FONT_SECTION("u8g2_font_t0_40_te");
+extern const uint8_t u8g2_font_t0_40_mf[] U8G2_FONT_SECTION("u8g2_font_t0_40_mf");
+extern const uint8_t u8g2_font_t0_40_mr[] U8G2_FONT_SECTION("u8g2_font_t0_40_mr");
+extern const uint8_t u8g2_font_t0_40_mn[] U8G2_FONT_SECTION("u8g2_font_t0_40_mn");
+extern const uint8_t u8g2_font_t0_40_me[] U8G2_FONT_SECTION("u8g2_font_t0_40_me");
+extern const uint8_t u8g2_font_t0_40_t_symbol[] U8G2_FONT_SECTION("u8g2_font_t0_40_t_symbol");
+extern const uint8_t u8g2_font_t0_40b_tf[] U8G2_FONT_SECTION("u8g2_font_t0_40b_tf");
+extern const uint8_t u8g2_font_t0_40b_tr[] U8G2_FONT_SECTION("u8g2_font_t0_40b_tr");
+extern const uint8_t u8g2_font_t0_40b_tn[] U8G2_FONT_SECTION("u8g2_font_t0_40b_tn");
+extern const uint8_t u8g2_font_t0_40b_te[] U8G2_FONT_SECTION("u8g2_font_t0_40b_te");
+extern const uint8_t u8g2_font_t0_40b_mf[] U8G2_FONT_SECTION("u8g2_font_t0_40b_mf");
+extern const uint8_t u8g2_font_t0_40b_mr[] U8G2_FONT_SECTION("u8g2_font_t0_40b_mr");
+extern const uint8_t u8g2_font_t0_40b_mn[] U8G2_FONT_SECTION("u8g2_font_t0_40b_mn");
+extern const uint8_t u8g2_font_t0_40b_me[] U8G2_FONT_SECTION("u8g2_font_t0_40b_me");
 extern const uint8_t u8g2_font_open_iconic_all_1x_t[] U8G2_FONT_SECTION("u8g2_font_open_iconic_all_1x_t");
 extern const uint8_t u8g2_font_open_iconic_app_1x_t[] U8G2_FONT_SECTION("u8g2_font_open_iconic_app_1x_t");
 extern const uint8_t u8g2_font_open_iconic_arrow_1x_t[] U8G2_FONT_SECTION("u8g2_font_open_iconic_arrow_1x_t");
@@ -2613,6 +2848,7 @@ extern const uint8_t u8g2_font_iconquadpix_m_all[] U8G2_FONT_SECTION("u8g2_font_
 extern const uint8_t u8g2_font_tallpix_tr[] U8G2_FONT_SECTION("u8g2_font_tallpix_tr");
 extern const uint8_t u8g2_font_botmaker_te[] U8G2_FONT_SECTION("u8g2_font_botmaker_te");
 extern const uint8_t u8g2_font_efraneextracondensed_te[] U8G2_FONT_SECTION("u8g2_font_efraneextracondensed_te");
+extern const uint8_t u8g2_font_minimal3x3_tu[] U8G2_FONT_SECTION("u8g2_font_minimal3x3_tu");
 extern const uint8_t u8g2_font_3x3basic_tr[] U8G2_FONT_SECTION("u8g2_font_3x3basic_tr");
 extern const uint8_t u8g2_font_tiny_gk_tr[] U8G2_FONT_SECTION("u8g2_font_tiny_gk_tr");
 extern const uint8_t u8g2_font_threepix_tr[] U8G2_FONT_SECTION("u8g2_font_threepix_tr");
@@ -2628,6 +2864,9 @@ extern const uint8_t u8g2_font_smolfont_te[] U8G2_FONT_SECTION("u8g2_font_smolfo
 extern const uint8_t u8g2_font_tinyunicode_tf[] U8G2_FONT_SECTION("u8g2_font_tinyunicode_tf");
 extern const uint8_t u8g2_font_tinyunicode_tr[] U8G2_FONT_SECTION("u8g2_font_tinyunicode_tr");
 extern const uint8_t u8g2_font_tinyunicode_te[] U8G2_FONT_SECTION("u8g2_font_tinyunicode_te");
+extern const uint8_t u8g2_font_micropixel_tf[] U8G2_FONT_SECTION("u8g2_font_micropixel_tf");
+extern const uint8_t u8g2_font_micropixel_tr[] U8G2_FONT_SECTION("u8g2_font_micropixel_tr");
+extern const uint8_t u8g2_font_micropixel_te[] U8G2_FONT_SECTION("u8g2_font_micropixel_te");
 extern const uint8_t u8g2_font_tinypixie2_tr[] U8G2_FONT_SECTION("u8g2_font_tinypixie2_tr");
 extern const uint8_t u8g2_font_standardized3x5_tr[] U8G2_FONT_SECTION("u8g2_font_standardized3x5_tr");
 extern const uint8_t u8g2_font_fivepx_tr[] U8G2_FONT_SECTION("u8g2_font_fivepx_tr");
@@ -2960,6 +3199,7 @@ extern const uint8_t u8g2_font_unifont_t_tibetan[] U8G2_FONT_SECTION("u8g2_font_
 extern const uint8_t u8g2_font_unifont_t_urdu[] U8G2_FONT_SECTION("u8g2_font_unifont_t_urdu");
 extern const uint8_t u8g2_font_unifont_t_polish[] U8G2_FONT_SECTION("u8g2_font_unifont_t_polish");
 extern const uint8_t u8g2_font_unifont_t_devanagari[] U8G2_FONT_SECTION("u8g2_font_unifont_t_devanagari");
+extern const uint8_t u8g2_font_unifont_t_malayalam[] U8G2_FONT_SECTION("u8g2_font_unifont_t_malayalam");
 extern const uint8_t u8g2_font_unifont_t_arabic[] U8G2_FONT_SECTION("u8g2_font_unifont_t_arabic");
 extern const uint8_t u8g2_font_unifont_t_symbols[] U8G2_FONT_SECTION("u8g2_font_unifont_t_symbols");
 extern const uint8_t u8g2_font_unifont_h_symbols[] U8G2_FONT_SECTION("u8g2_font_unifont_h_symbols");
@@ -2971,6 +3211,9 @@ extern const uint8_t u8g2_font_unifont_t_weather[] U8G2_FONT_SECTION("u8g2_font_
 extern const uint8_t u8g2_font_unifont_t_chinese1[] U8G2_FONT_SECTION("u8g2_font_unifont_t_chinese1");
 extern const uint8_t u8g2_font_unifont_t_chinese2[] U8G2_FONT_SECTION("u8g2_font_unifont_t_chinese2");
 extern const uint8_t u8g2_font_unifont_t_chinese3[] U8G2_FONT_SECTION("u8g2_font_unifont_t_chinese3");
+extern const uint8_t u8g2_font_unifont_t_gb2312[] U8G2_FONT_SECTION("u8g2_font_unifont_t_gb2312");
+extern const uint8_t u8g2_font_unifont_t_gb2312a[] U8G2_FONT_SECTION("u8g2_font_unifont_t_gb2312a");
+extern const uint8_t u8g2_font_unifont_t_gb2312b[] U8G2_FONT_SECTION("u8g2_font_unifont_t_gb2312b");
 extern const uint8_t u8g2_font_unifont_t_japanese1[] U8G2_FONT_SECTION("u8g2_font_unifont_t_japanese1");
 extern const uint8_t u8g2_font_unifont_t_japanese2[] U8G2_FONT_SECTION("u8g2_font_unifont_t_japanese2");
 extern const uint8_t u8g2_font_unifont_t_japanese3[] U8G2_FONT_SECTION("u8g2_font_unifont_t_japanese3");
@@ -3014,6 +3257,39 @@ extern const uint8_t u8g2_font_wqy16_t_chinese3[] U8G2_FONT_SECTION("u8g2_font_w
 extern const uint8_t u8g2_font_wqy16_t_gb2312[] U8G2_FONT_SECTION("u8g2_font_wqy16_t_gb2312");
 extern const uint8_t u8g2_font_wqy16_t_gb2312a[] U8G2_FONT_SECTION("u8g2_font_wqy16_t_gb2312a");
 extern const uint8_t u8g2_font_wqy16_t_gb2312b[] U8G2_FONT_SECTION("u8g2_font_wqy16_t_gb2312b");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_tf[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_tf");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_tr[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_tr");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_tn[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_tn");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_te[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_te");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_t_all[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_t_all");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_t_chinese1[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_t_chinese1");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_t_chinese2[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_t_chinese2");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_t_chinese3[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_t_chinese3");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_t_gb2312[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_t_gb2312");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_t_gb2312a[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_t_gb2312a");
+extern const uint8_t u8g2_font_boutique_bitmap_7x7_t_gb2312b[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_7x7_t_gb2312b");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_tf[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_tf");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_tr[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_tr");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_tn[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_tn");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_te[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_te");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_t_all[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_t_all");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_t_chinese1[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_t_chinese1");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_t_chinese2[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_t_chinese2");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_t_chinese3[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_t_chinese3");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_t_gb2312[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_t_gb2312");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_t_gb2312a[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_t_gb2312a");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_t_gb2312b[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_t_gb2312b");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_tf[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_tf");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_tr[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_tr");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_tn[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_tn");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_te[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_te");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_t_all[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_t_all");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_t_chinese1[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_t_chinese1");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_t_chinese2[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_t_chinese2");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_t_chinese3[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_t_chinese3");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_t_gb2312[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_t_gb2312");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_t_gb2312a[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_t_gb2312a");
+extern const uint8_t u8g2_font_boutique_bitmap_9x9_bold_t_gb2312b[] U8G2_FONT_SECTION("u8g2_font_boutique_bitmap_9x9_bold_t_gb2312b");
 extern const uint8_t u8g2_font_b10_t_japanese1[] U8G2_FONT_SECTION("u8g2_font_b10_t_japanese1");
 extern const uint8_t u8g2_font_b10_t_japanese2[] U8G2_FONT_SECTION("u8g2_font_b10_t_japanese2");
 extern const uint8_t u8g2_font_b10_b_t_japanese1[] U8G2_FONT_SECTION("u8g2_font_b10_b_t_japanese1");
@@ -3747,6 +4023,14 @@ extern const uint8_t u8g2_font_logisoso58_tn[] U8G2_FONT_SECTION("u8g2_font_logi
 extern const uint8_t u8g2_font_logisoso62_tn[] U8G2_FONT_SECTION("u8g2_font_logisoso62_tn");
 extern const uint8_t u8g2_font_logisoso78_tn[] U8G2_FONT_SECTION("u8g2_font_logisoso78_tn");
 extern const uint8_t u8g2_font_logisoso92_tn[] U8G2_FONT_SECTION("u8g2_font_logisoso92_tn");
+extern const uint8_t u8g2_font_gulim11_t_korean1[] U8G2_FONT_SECTION("u8g2_font_gulim11_t_korean1");
+extern const uint8_t u8g2_font_gulim11_t_korean2[] U8G2_FONT_SECTION("u8g2_font_gulim11_t_korean2");
+extern const uint8_t u8g2_font_gulim12_t_korean1[] U8G2_FONT_SECTION("u8g2_font_gulim12_t_korean1");
+extern const uint8_t u8g2_font_gulim12_t_korean2[] U8G2_FONT_SECTION("u8g2_font_gulim12_t_korean2");
+extern const uint8_t u8g2_font_gulim14_t_korean1[] U8G2_FONT_SECTION("u8g2_font_gulim14_t_korean1");
+extern const uint8_t u8g2_font_gulim14_t_korean2[] U8G2_FONT_SECTION("u8g2_font_gulim14_t_korean2");
+extern const uint8_t u8g2_font_gulim16_t_korean1[] U8G2_FONT_SECTION("u8g2_font_gulim16_t_korean1");
+extern const uint8_t u8g2_font_gulim16_t_korean2[] U8G2_FONT_SECTION("u8g2_font_gulim16_t_korean2");
 extern const uint8_t u8g2_font_pressstart2p_8f[] U8G2_FONT_SECTION("u8g2_font_pressstart2p_8f");
 extern const uint8_t u8g2_font_pressstart2p_8r[] U8G2_FONT_SECTION("u8g2_font_pressstart2p_8r");
 extern const uint8_t u8g2_font_pressstart2p_8n[] U8G2_FONT_SECTION("u8g2_font_pressstart2p_8n");

+ 107 - 0
components/u8g2/u8g2_arc.c

@@ -0,0 +1,107 @@
+/*
+
+  u8g2_arc.c
+  
+  Contributed... see here: https://github.com/olikraus/u8g2/issues/2243
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2023, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+*/
+
+#include "u8g2.h"
+
+
+static void u8g2_draw_arc(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t start, uint8_t end)
+{
+  // Manage angle inputs
+  uint8_t full = (start == end);
+  uint8_t inverted = (start > end);
+  uint8_t a_start = inverted ? end : start;
+  uint8_t a_end = inverted ? start : end;
+
+  // Initialize variables
+  uint32_t ratio;
+  u8g2_int_t x = 0;
+  u8g2_int_t y = rad;
+  u8g2_int_t d = rad - 1;
+
+  // Trace arc radius with the Andres circle algorithm (process each pixel of a 1/8th circle of radius rad)
+  while (y >= x)
+  {
+    // Get the percentage of 1/8th circle drawn with a fast approximation of arctan(x/y)
+    ratio = x * 255 / y; // x/y [0..255]
+    ratio = ratio * (770195 - (ratio - 255) * (ratio + 941)) / 6137491; // arctan(x/y) [0..32]
+
+    // Fill the pixels of the 8 sections of the circle, but only on the arc defined by the angles (start and end)
+    if(full || ((ratio >= a_start && ratio < a_end) ^ inverted)) u8g2_DrawPixel(u8g2, x0 + y, y0 - x);
+    if(full || (((ratio + a_end) > 63 && (ratio + a_start) <= 63) ^ inverted)) u8g2_DrawPixel(u8g2, x0 + x, y0 - y);
+    if(full || (((ratio + 64) >= a_start && (ratio + 64) < a_end) ^ inverted)) u8g2_DrawPixel(u8g2, x0 - x, y0 - y);
+    if(full || (((ratio + a_end) > 127 && (ratio + a_start) <= 127) ^ inverted)) u8g2_DrawPixel(u8g2, x0 - y, y0 - x);
+    if(full || (((ratio + 128) >= a_start && (ratio + 128) < a_end) ^ inverted)) u8g2_DrawPixel(u8g2, x0 - y, y0 + x);
+    if(full || (((ratio + a_end) > 191 && (ratio + a_start) <= 191) ^ inverted)) u8g2_DrawPixel(u8g2, x0 - x, y0 + y);
+    if(full || (((ratio + 192) >= a_start && (ratio + 192) < a_end) ^ inverted)) u8g2_DrawPixel(u8g2, x0 + x, y0 + y);
+    if(full || (((ratio + a_end) > 255 && (ratio + a_start) <= 255) ^ inverted)) u8g2_DrawPixel(u8g2, x0 + y, y0 + x);
+
+    // Run Andres circle algorithm to get to the next pixel
+    if (d >= 2 * x)
+    {
+      d = d - 2 * x - 1;
+      x = x + 1;
+    }
+    else if (d < 2 * (rad - y))
+    {
+      d = d + 2 * y - 1;
+      y = y - 1;
+    }
+    else
+    {
+      d = d + 2 * (y - x - 1);
+      y = y - 1;
+      x = x + 1;
+    }
+  }
+}
+
+void u8g2_DrawArc(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t start, uint8_t end)
+{
+  /* check for bounding box */
+#ifdef U8G2_WITH_INTERSECTION
+  {
+    if ( u8g2_IsIntersection(u8g2, x0-rad, y0-rad, x0+rad+1, y0+rad+1) == 0 ) 
+      return;
+  }
+#endif /* U8G2_WITH_INTERSECTION */
+  
+  
+  /* draw arc */
+  u8g2_draw_arc(u8g2, x0, y0, rad, start, end);
+}
+
+

+ 59 - 2
components/u8g2/u8g2_bitmap.c

@@ -116,7 +116,9 @@ void u8g2_DrawHXBM(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t len,
   
   mask = 1;
   while(len > 0) {
-    if ( *b & mask ) {
+    uint8_t current_bit = (*b) & mask;
+#ifdef OLD
+    if ( current_bit ) {
       u8g2->draw_color = color;
       u8g2_DrawHVLine(u8g2, x, y, 1, 0);
     } else if ( u8g2->bitmap_transparency == 0 ) {
@@ -131,6 +133,32 @@ void u8g2_DrawHXBM(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t len,
       b++;
     }
     len--;
+#else
+    u8g2_uint_t run_length = 0;
+    // Determine the run length of consecutive bits with the same color
+    while (len > 0 && (current_bit == 0 ? (((*b) & mask) == 0) : (((*b) & mask) != 0 )  ))
+    {
+        run_length++;
+        x++;
+        mask <<= 1;
+        if (mask == 0)
+        {
+            mask = 1;
+            b++;
+        }
+        len--;
+    }
+    if (current_bit)
+    {
+        u8g2->draw_color = color;
+        u8g2_DrawHVLine(u8g2, x - run_length, y, run_length, 0);
+    }
+    else if (u8g2->bitmap_transparency == 0)
+    {
+        u8g2->draw_color = ncolor;
+        u8g2_DrawHVLine(u8g2, x - run_length, y, run_length, 0);
+    }
+#endif
   }
   u8g2->draw_color = color;
 }
@@ -174,7 +202,10 @@ void u8g2_DrawHXBMP(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t len,
   mask = 1;
   while(len > 0)
   {
-    if( u8x8_pgm_read(b) & mask ) {
+    uint8_t current_bit = u8x8_pgm_read(b) & mask;
+//#define OLD
+#ifdef OLD
+    if ( current_bit ) {
       u8g2->draw_color = color;
       u8g2_DrawHVLine(u8g2, x, y, 1, 0);
     } else if( u8g2->bitmap_transparency == 0 ) {
@@ -190,6 +221,32 @@ void u8g2_DrawHXBMP(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t len,
       b++;
     }
     len--;
+#else
+    u8g2_uint_t run_length = 0;
+    // Determine the run length of consecutive bits with the same color
+    while (len > 0 && (current_bit == 0 ? ((u8x8_pgm_read(b) & mask) == 0) : ((u8x8_pgm_read(b) & mask) != 0 )  ))
+    {
+        run_length++;
+        x++;
+        mask <<= 1;
+        if (mask == 0)
+        {
+            mask = 1;
+            b++;
+        }
+        len--;
+    }
+    if (current_bit)
+    {
+        u8g2->draw_color = color;
+        u8g2_DrawHVLine(u8g2, x - run_length, y, run_length, 0);
+    }
+    else if (u8g2->bitmap_transparency == 0)
+    {
+        u8g2->draw_color = ncolor;
+        u8g2_DrawHVLine(u8g2, x - run_length, y, run_length, 0);
+    }
+#endif
   }
   u8g2->draw_color = color;
 }

+ 264 - 33
components/u8g2/u8g2_d_memory.c

@@ -564,6 +564,39 @@ uint8_t *u8g2_m_12_2_f(uint8_t *page_cnt)
   return buf;
   #endif
 }
+uint8_t *u8g2_m_15_4_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[120];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_15_4_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[240];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_15_4_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 4;
+  return 0;
+  #else
+  static uint8_t buf[480];
+  *page_cnt = 4;
+  return buf;
+  #endif
+}
 uint8_t *u8g2_m_12_4_1(uint8_t *page_cnt)
 {
   #ifdef U8G2_USE_DYNAMIC_ALLOC
@@ -894,6 +927,39 @@ uint8_t *u8g2_m_18_21_f(uint8_t *page_cnt)
   return buf;
   #endif
 }
+uint8_t *u8g2_m_20_9_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[160];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_20_9_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[320];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_20_9_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 9;
+  return 0;
+  #else
+  static uint8_t buf[1440];
+  *page_cnt = 9;
+  return buf;
+  #endif
+}
 uint8_t *u8g2_m_11_6_1(uint8_t *page_cnt)
 {
   #ifdef U8G2_USE_DYNAMIC_ALLOC
@@ -1092,6 +1158,39 @@ uint8_t *u8g2_m_30_16_f(uint8_t *page_cnt)
   return buf;
   #endif
 }
+uint8_t *u8g2_m_32_16_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[256];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_32_16_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[512];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_32_16_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 16;
+  return 0;
+  #else
+  static uint8_t buf[4096];
+  *page_cnt = 16;
+  return buf;
+  #endif
+}
 uint8_t *u8g2_m_20_16_1(uint8_t *page_cnt)
 {
   #ifdef U8G2_USE_DYNAMIC_ALLOC
@@ -1224,39 +1323,6 @@ uint8_t *u8g2_m_30_20_f(uint8_t *page_cnt)
   return buf;
   #endif
 }
-uint8_t *u8g2_m_32_16_1(uint8_t *page_cnt)
-{
-  #ifdef U8G2_USE_DYNAMIC_ALLOC
-  *page_cnt = 1;
-  return 0;
-  #else
-  static uint8_t buf[256];
-  *page_cnt = 1;
-  return buf;
-  #endif
-}
-uint8_t *u8g2_m_32_16_2(uint8_t *page_cnt)
-{
-  #ifdef U8G2_USE_DYNAMIC_ALLOC
-  *page_cnt = 2;
-  return 0;
-  #else
-  static uint8_t buf[512];
-  *page_cnt = 2;
-  return buf;
-  #endif
-}
-uint8_t *u8g2_m_32_16_f(uint8_t *page_cnt)
-{
-  #ifdef U8G2_USE_DYNAMIC_ALLOC
-  *page_cnt = 16;
-  return 0;
-  #else
-  static uint8_t buf[4096];
-  *page_cnt = 16;
-  return buf;
-  #endif
-}
 uint8_t *u8g2_m_40_30_1(uint8_t *page_cnt)
 {
   #ifdef U8G2_USE_DYNAMIC_ALLOC
@@ -1422,6 +1488,105 @@ uint8_t *u8g2_m_17_9_f(uint8_t *page_cnt)
   return buf;
   #endif
 }
+uint8_t *u8g2_m_16_32_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[128];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_16_32_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[256];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_16_32_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 32;
+  return 0;
+  #else
+  static uint8_t buf[4096];
+  *page_cnt = 32;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_26_25_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[208];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_26_25_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[416];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_26_25_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 25;
+  return 0;
+  #else
+  static uint8_t buf[5200];
+  *page_cnt = 25;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_21_48_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[168];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_21_48_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[336];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_21_48_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 48;
+  return 0;
+  #else
+  static uint8_t buf[8064];
+  *page_cnt = 48;
+  return buf;
+  #endif
+}
 uint8_t *u8g2_m_48_17_1(uint8_t *page_cnt)
 {
   #ifdef U8G2_USE_DYNAMIC_ALLOC
@@ -1686,6 +1851,39 @@ uint8_t *u8g2_m_19_4_f(uint8_t *page_cnt)
   return buf;
   #endif
 }
+uint8_t *u8g2_m_16_9_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[128];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_16_9_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[256];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_16_9_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 9;
+  return 0;
+  #else
+  static uint8_t buf[1152];
+  *page_cnt = 9;
+  return buf;
+  #endif
+}
 uint8_t *u8g2_m_20_17_1(uint8_t *page_cnt)
 {
   #ifdef U8G2_USE_DYNAMIC_ALLOC
@@ -1983,6 +2181,39 @@ uint8_t *u8g2_m_1_1_f(uint8_t *page_cnt)
   return buf;
   #endif
 }
+uint8_t *u8g2_m_13_4_1(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 1;
+  return 0;
+  #else
+  static uint8_t buf[104];
+  *page_cnt = 1;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_13_4_2(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 2;
+  return 0;
+  #else
+  static uint8_t buf[208];
+  *page_cnt = 2;
+  return buf;
+  #endif
+}
+uint8_t *u8g2_m_13_4_f(uint8_t *page_cnt)
+{
+  #ifdef U8G2_USE_DYNAMIC_ALLOC
+  *page_cnt = 4;
+  return 0;
+  #else
+  static uint8_t buf[416];
+  *page_cnt = 4;
+  return buf;
+  #endif
+}
 uint8_t *u8g2_m_20_2_1(uint8_t *page_cnt)
 {
   #ifdef U8G2_USE_DYNAMIC_ALLOC

Fișier diff suprimat deoarece este prea mare
+ 766 - 106
components/u8g2/u8g2_d_setup.c


+ 140 - 45
components/u8g2/u8g2_font.c

@@ -799,6 +799,7 @@ int8_t u8g2_font_2x_decode_glyph(u8g2_t *u8g2, const uint8_t *glyph_data)
 */
 const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding)
 {
+    // printf("u8g2_font_get_glyph_data: encoding=%02X\n", encoding);
   const uint8_t *font = u8g2->font;
     uint8_t font_data[4] = {0};
     // luat_fs_fread(font_info, 1, 21, u8g2->font_file);
@@ -827,47 +828,62 @@ const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding)
                 luat_fs_fseek(u8g2->font_file, font_data[1] - 2, SEEK_CUR);
             }
         }
-        #ifdef U8G2_WITH_UNICODE
-            else{
-                uint16_t e;
-                // const uint8_t *unicode_lookup_table;
-                // font += u8g2->font_info.start_pos_unicode;
-                luat_fs_fseek(u8g2->font_file, u8g2->font_info.start_pos_unicode, SEEK_CUR);
-                // unicode_lookup_table = font; 
-                /* issue 596: search for the glyph start in the unicode lookup table */
-                // do{
-                //     font += u8g2_font_get_word(unicode_lookup_table, 0);
-                //     e = u8g2_font_get_word(unicode_lookup_table, 2);
-                //     unicode_lookup_table+=4;
-                // } while( e < encoding );
-                for(;;){
-                    // e = u8x8_pgm_read( font );
-                    // e <<= 8;
-                    // e |= u8x8_pgm_read( font + 1 );
-                    // if ( e == 0 )
-                    //     break;
-                    // if ( e == encoding ){
-                    //     return font+3;	/* skip encoding and glyph size */
-                    // }
-                    // font += u8x8_pgm_read( font + 2 );
-
-                    luat_fs_fread(font_data, 1, 3, u8g2->font_file);
-                    e = font_data[0]<<8 | font_data[1];
-                    if ( e == 0 )
-                        break;
-                    if ( e == encoding ){
-                        if(u8g2->font){
-                            u8g2->font = luat_heap_realloc(u8g2->font, font_data[2] - 3);
-                        }else{
-                            u8g2->font = luat_heap_malloc(font_data[2] - 3);
-                        }
-                        luat_fs_fread(u8g2->font, 1, font_data[2] - 3, u8g2->font_file);
-                        return u8g2->font;
+#ifdef U8G2_WITH_UNICODE
+        else{
+            uint16_t e;
+            // const uint8_t *unicode_lookup_table;
+            // font += u8g2->font_info.start_pos_unicode;
+            luat_fs_fseek(u8g2->font_file, u8g2->font_info.start_pos_unicode, SEEK_CUR);
+            uint16_t pos_unicode = 0;
+            uint16_t unicode_lookup_pos = 0;
+            // unicode_lookup_table = font; 
+            /* issue 596: search for the glyph start in the unicode lookup table */
+            // do{
+            //     font += u8g2_font_get_word(unicode_lookup_table, 0);
+            //     e = u8g2_font_get_word(unicode_lookup_table, 2);
+            //     unicode_lookup_table+=4;
+            // } while( e < encoding );
+            // do{
+            //     luat_fs_fread(font_data, 1, 4, u8g2->font_file);
+            //     // uint16_t pos = font_data[0]<<8 | font_data[1];
+            //     pos_unicode += font_data[0]<<8 | font_data[1];
+            //     e = font_data[2]<<8 | font_data[3];
+            //     unicode_lookup_pos+=4;
+            //     // printf("0: unicode e=%02X\n", e);
+            // } while( e < encoding );
+            // luat_fs_fseek(u8g2->font_file, pos_unicode - unicode_lookup_pos, SEEK_CUR);
+            // printf("1: pos_unicode %d\n", pos_unicode);
+            // printf("1: unicode e=%02X\n", e);
+            // return NULL;
+            for(;;){
+                // e = u8x8_pgm_read( font );
+                // e <<= 8;
+                // e |= u8x8_pgm_read( font + 1 );
+                // if ( e == 0 )
+                //     break;
+                // if ( e == encoding ){
+                //     return font+3;	/* skip encoding and glyph size */
+                // }
+                // font += u8x8_pgm_read( font + 2 );
+
+                luat_fs_fread(font_data, 1, 3, u8g2->font_file);
+                e = font_data[0]<<8 | font_data[1];
+                if ( e == 0 )
+                    break;
+                // printf("2: unicode e=%02X\n", e);
+                if ( e == encoding ){
+                    if(u8g2->font){
+                        u8g2->font = luat_heap_realloc(u8g2->font, font_data[2] - 3);
+                    }else{
+                        u8g2->font = luat_heap_malloc(font_data[2] - 3);
                     }
-                    luat_fs_fseek(u8g2->font_file, font_data[2] - 3, SEEK_CUR);
-                }  
-            }
-        #endif
+                    luat_fs_fread(u8g2->font, 1, font_data[2] - 3, u8g2->font_file);
+                    return u8g2->font;
+                }
+                luat_fs_fseek(u8g2->font_file, font_data[2]-3, SEEK_CUR);
+            }  
+        }
+#endif
         return NULL;
     }
 #endif
@@ -913,16 +929,17 @@ const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding)
 
     font += u8g2->font_info.start_pos_unicode;
     unicode_lookup_table = font; 
-  
     /* issue 596: search for the glyph start in the unicode lookup table */
+    uint8_t* pos_unicode = font;
     do
     {
       font += u8g2_font_get_word(unicode_lookup_table, 0);
       e = u8g2_font_get_word(unicode_lookup_table, 2);
       unicode_lookup_table+=4;
+    //printf("0: unicode e=%02X\n", e);
     } while( e < encoding );
-    
-  
+    // printf("1: pos_unicode %d\n", font - pos_unicode);
+    // printf("1: unicode e=%02X\n", e);
     for(;;)
     {
       e = u8x8_pgm_read( font );
@@ -937,7 +954,7 @@ const uint8_t *u8g2_font_get_glyph_data(u8g2_t *u8g2, uint16_t encoding)
 
       if ( e == 0 )
 	break;
-  
+//   printf("2: unicode e=%02X\n", e);
       if ( e == encoding )
       {
 // removed, there is now the new index table
@@ -1461,7 +1478,7 @@ static u8g2_uint_t u8g2_string_width(u8g2_t *u8g2, const char *str)
     str++;
     if ( e != 0x0fffe )
     {
-      dx = u8g2_GetGlyphWidth(u8g2, e);		/* delta x value of the glyph */
+      dx = u8g2_GetGlyphWidth(u8g2, e);		/* delta x value of the glyph, side effect: updates u8g2->glyph_x_offset */
 #ifdef U8G2_BALANCED_STR_WIDTH_CALCULATION
       if ( initial_x_offset == -64 )
         initial_x_offset = u8g2->glyph_x_offset;
@@ -1491,6 +1508,28 @@ static u8g2_uint_t u8g2_string_width(u8g2_t *u8g2, const char *str)
   return w;  
 }
 
+int8_t u8g2_GetXOffsetGlyph(u8g2_t *u8g2, uint16_t encoding)
+{
+  u8g2_GetGlyphWidth(u8g2, encoding);		/* delta x value of the glyph, side effect: updates u8g2->glyph_x_offset */
+  return u8g2->glyph_x_offset;
+}
+
+int8_t u8g2_GetXOffsetUTF8(u8g2_t *u8g2, const char *utf8)
+{
+  uint16_t e; 
+  u8x8_utf8_init(u8g2_GetU8x8(u8g2));
+  for(;;)  // extract encoding from UTF8 byte stream
+  {
+    e = u8x8_utf8_next(u8g2_GetU8x8(u8g2), (uint8_t)*utf8);
+    if ( e == 0x0ffff )
+      return 0;
+    if ( e < 0x0fffe )  // 0x0fffe means: just continue 
+      break;
+    utf8++;
+  }
+  return u8g2_GetXOffsetGlyph(u8g2, e);
+}
+
 static void u8g2_GetGlyphHorizontalProperties(u8g2_t *u8g2, uint16_t requested_encoding, uint8_t *w, int8_t *ox, int8_t *dx)
 {
   const uint8_t *glyph_data = u8g2_font_get_glyph_data(u8g2, requested_encoding);
@@ -1652,4 +1691,60 @@ void u8g2_SetFontDirection(u8g2_t *u8g2, uint8_t dir)
 #endif
 }
 
+/*=======================================*/
+/*
+  Draw a string, which is produced by hbshape2u8g2 (libharfbuzz toolchain)
+
+  The data argument should look like this:
+    static const unsigned char teststring[] U8X8_PROGMEM = {
+      0x09, 0x28, 0x00, 0x00, // u8g2_DrawGlyph(&u8g2, 0, 0, 2344);
+      0x09, 0x2e, 0x10, 0x00, // u8g2_DrawGlyph(&u8g2, 16, 0, 2350);
+      0x09, 0x38, 0x10, 0x00, // u8g2_DrawGlyph(&u8g2, 32, 0, 2360);
+      0x09, 0x4d, 0x00, 0x00, // u8g2_DrawGlyph(&u8g2, 32, 0, 2381);
+      0x09, 0x24, 0x10, 0x00, // u8g2_DrawGlyph(&u8g2, 48, 0, 2340);
+      0x09, 0x47, 0x00, 0x00, // u8g2_DrawGlyph(&u8g2, 48, 0, 2375);
+      0x00, 0x00  // end of binary
+    };
+
+  The data row contains four bytes, which are:
+    <encoding high byte> <encoding low byte> <delta-x> <delta-y>
+  The last row is marked with encoding=0
+
+  The algorithm is
+    Input: x,y
+    with all rows (until encoding is 0)      
+      x += <delta-x>
+      y += <delta-y>
+      draw glyph with <encoding> at x, y
+
+  A call to this function will require transparent mode:
+    u8g2_SetFontMode(&u8g2, 1);
+    
+  Limitation:
+    Glyph delta must be lower than 128, this bascially means, that the glyph size is limited to
+    hight/width of 128 pixel
+    
+  Further details: 
+    https://github.com/olikraus/u8g2/issues/2656
+
+*/
+void u8g2_DrawHB(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, const unsigned char *data)
+{
+    uint16_t encoding = 0;
+    for (;;)
+    {
+        encoding = u8x8_pgm_read(data);
+        data++;
+        encoding <<= 8;
+        encoding  |= u8x8_pgm_read(data);
+        data++;
+        if (encoding == 0)
+            break;
+        x += (int8_t)u8x8_pgm_read(data);
+        data++;
+        y += (int8_t)u8x8_pgm_read(data);
+        data++;
+        u8g2_DrawGlyph(u8g2, x, y, encoding);
+    }
+}
 

Fișier diff suprimat deoarece este prea mare
+ 676 - 146
components/u8g2/u8g2_fonts.c


+ 5 - 0
components/u8g2/u8g2_selection_list.c

@@ -63,6 +63,11 @@ void u8g2_DrawUTF8Line(u8g2_t *u8g2, u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w
   /* calculate the width of the string in pixel */
   str_width = u8g2_GetUTF8Width(u8g2, s);
 
+#ifdef U8G2_BALANCED_STR_WIDTH_CALCULATION
+  /* subtract the first character offset added by the width calculation */
+  str_width -= u8g2_GetXOffsetUTF8(u8g2, s);
+#endif
+
   /* calculate delta d within the box */
   d = 0;
   if ( str_width < w )

+ 1 - 0
components/u8g2/u8log.c

@@ -147,6 +147,7 @@ void u8log_write_char(u8log_t *u8log, uint8_t c)
       u8log->is_redraw_all_required_for_next_nl = 0;
       u8log->cursor_y++;
       u8log->cursor_x = 0;
+      u8log_cursor_on_screen(u8log);  // 31 Aug 2024 https://github.com/olikraus/u8g2/issues/2319
       break;	
     case '\r':	// 13
       u8log->is_redraw_line = 1;

+ 45 - 3
components/u8g2/u8x8.h

@@ -646,6 +646,7 @@ void u8x8_SendF(u8x8_t * u8x8, const char *fmt, ...);
 #define U8X8_D1(d0)			(U8X8_MSG_CAD_SEND_DATA), (d0)
 
 #define U8X8_A4(a0,a1,a2,a3)		U8X8_A(a0), U8X8_A(a1), U8X8_A(a2), U8X8_A(a3)
+#define U8X8_A6(a0,a1,a2,a3,a4,a5)		U8X8_A(a0), U8X8_A(a1), U8X8_A(a2), U8X8_A(a3), U8X8_A(a4), U8X8_A(a5)
 #define U8X8_A8(a0,a1,a2,a3,a4,a5,a6,a7)	U8X8_A4((a0), (a1), (a2), (a3)), U8X8_A4((a4), (a5), (a6), (a7))
 
 
@@ -662,8 +663,9 @@ uint8_t u8x8_cad_001(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_cad_011(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_cad_100(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_cad_st7920_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
-uint8_t u8x8_cad_ssd13xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
-uint8_t u8x8_cad_ssd13xx_fast_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_cad_ssd13xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);        /* CAD=001 */
+uint8_t u8x8_cad_011_ssd13xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);     /* CAD=011 */
+uint8_t u8x8_cad_ssd13xx_fast_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);   /* CAD=001 */
 uint8_t u8x8_cad_st75256_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_cad_ld7032_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_cad_uc16xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);  /* CAD=001 */
@@ -800,6 +802,7 @@ void u8x8_SetupStdio(u8x8_t *u8x8);
 /* u8x8_d_sdl_128x64.c */
 void u8x8_Setup_SDL_128x64(u8x8_t *u8x8);
 void u8x8_Setup_SDL_240x160(u8x8_t *u8x8);
+void u8x8_Setup_SDL_256x128(u8x8_t *u8x8);
 int u8g_sdl_get_key(void);
 
 /*==========================================*/
@@ -832,7 +835,6 @@ void utf8_show(void);		/* show content of UTF-8 frame buffer */
 uint8_t u8x8_d_null_cb(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 
 /* u8x8_d_XXX.c */
-uint8_t u8x8_d_custom_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1701_ea_dogs102(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1701_mini12864(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1305_128x32_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -844,8 +846,16 @@ uint8_t u8x8_d_ssd1306_128x64_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
 uint8_t u8x8_d_ssd1306_128x64_vcomh0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1306_128x64_alt0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1309_128x64_noname0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+/* CSC ==> */
+uint8_t u8x8_d_ssd1309_128x128_noname0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+/* <== CSC */
 uint8_t u8x8_d_ssd1309_128x64_noname2(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+
 uint8_t u8x8_d_ssd1312_128x64_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1312_128x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1312_120x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1312_120x28(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+
 uint8_t u8x8_d_ssd1306_2040x16(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1306_128x32_univision(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1306_128x32_winstar(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -874,7 +884,9 @@ uint8_t u8x8_d_sh1107_hjr_oel1m0201_96x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg
 uint8_t u8x8_d_sh1107_tk078f288_80x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_sh1108_128x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_sh1108_160x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ch1120_128x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_sh1122_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7920_128x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7920_144x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7920_160x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7920_192x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -884,6 +896,7 @@ uint8_t u8x8_d_ls013b7dh03_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, v
 uint8_t u8x8_d_ls027b7dh01_400x240(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ls027b7dh01_m0_400x240(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ls013b7dh05_144x168(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ls011b7dh03_160x68(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7511_avd_320x240(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7528_nhd_c160100(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7528_erc16064(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -910,17 +923,28 @@ uint8_t u8x8_d_st7567_64x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *ar
 uint8_t u8x8_d_st7567_hem6432(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7567_os12864(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7567_erc13232(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7567_erc12864(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7567_lw12832(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7567_yxd12832(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7567_96x65(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7571_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7571_128x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7571_g12896(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7302_122x250(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7305_122x250(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7305_200x200(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7305_168x384(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);       /* https://github.com/olikraus/u8g2/issues/2661 */
 uint8_t u8x8_d_st7586s_s028hn118a(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7586s_jlx384160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7586s_erc240160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7586s_ymc240160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7586s_jlx320160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st7586s_md240128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7588_jlx12864(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st75160_jm16096(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st75161_jlx160160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st75256_jlx256128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_st75256_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); /* https://github.com/olikraus/u8g2/issues/2702 */
 uint8_t u8x8_d_st75256_wo256x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st75256_jlx256160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st75256_jlx256160m(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -942,6 +966,7 @@ uint8_t u8x8_d_t6963_128x64_alt(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void
 uint8_t u8x8_d_t6963_160x80(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_t6963_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_t6963_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_t6963_128x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1316_128x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1316_96x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1317_96x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -950,13 +975,18 @@ uint8_t u8x8_d_ssd1318_128x96_xcp(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, vo
 uint8_t u8x8_d_ssd1320_160x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1320_160x132(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1320_160x80(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1320_128x72(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1322_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1322_topwin_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1322_nhd_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1322_zjy_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1322_nhd_128x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1362_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1362_206x36(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1363_256x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_a2printer_384x240(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_sed1330_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_sed1330_240x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_sed1330_256x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_sed1330_320x200(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ra8835_nhd_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -975,6 +1005,7 @@ uint8_t u8x8_d_ssd1329_128x96_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
 uint8_t u8x8_d_ssd1329_96x96_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1601_128x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1601_128x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_uc1604_jlx12864(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1604_jlx19264(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1608_erc24064(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1608_dem240064(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -988,6 +1019,9 @@ uint8_t u8x8_d_uc1611_ew50850(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
 uint8_t u8x8_d_uc1611_cg160160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); /* 160x160 */
 uint8_t u8x8_d_uc1617_jlx128128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1611_ids4073(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); /* 256x128 */
+uint8_t u8x8_d_uc1628_128x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_uc1628_256x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_uc1628_256x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1638_160x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1638_192x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_uc1638_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -999,6 +1033,7 @@ uint8_t u8x8_d_sbn1661_122x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
 uint8_t u8x8_d_sed1520_122x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_pcd8544_84x48(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_pcf8812_96x65(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_pcf8812_101x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_hx1230_96x68(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1606_172x72(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_ssd1607_200x200(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
@@ -1021,12 +1056,16 @@ uint8_t u8x8_d_max7219_16x16(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
 uint8_t u8x8_d_max7219_8x8(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_s1d15e06_160100(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_s1d15300_lm6023(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_s1d15300_97x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_s1d15300_100x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_s1d15300_100x32i(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_s1d15721_240x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_gu800_128x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_gu800_160x16(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_gp1287ai_256x50(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_gp1247ai_253x63(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_gp1294ai_256x48(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
+uint8_t u8x8_d_ssd1315_128x64_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
 uint8_t u8x8_d_st7565_jlx12864g109pc(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); // 2023年8月4日 晶联讯12864G-109-PC,12864G-139-P
 
 
@@ -1035,6 +1074,7 @@ uint8_t u8x8_d_st7565_jlx12864g109pc(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int,
 
 uint16_t u8x8_upscale_byte(uint8_t x) U8X8_NOINLINE;
 
+void u8x8_get_glyph_data(u8x8_t *u8x8, uint8_t encoding, uint8_t *buf, uint8_t tile_offset) U8X8_NOINLINE;
 
 void u8x8_utf8_init(u8x8_t *u8x8);
 uint16_t u8x8_ascii_next(u8x8_t *u8x8, uint8_t b);
@@ -1059,6 +1099,8 @@ uint8_t u8x8_GetUTF8Len(u8x8_t *u8x8, const char *s);
 /*==========================================*/
 /* itoa procedures */
 const char *u8x8_u8toa(uint8_t v, uint8_t d);
+const char *u8x8_s8toa(int8_t v, uint8_t d);
+const char *u8x8_u8tox(uint8_t v, uint8_t d);
 const char *u8x8_u16toa(uint16_t v, uint8_t d);
 const char *u8x8_utoa(uint16_t v);
 

+ 2 - 2
components/u8g2/u8x8_8x8.c

@@ -58,8 +58,8 @@ void u8x8_SetFont(u8x8_t *u8x8, const uint8_t *font_8x8)
    encoding: glyph for which the data is requested (must be between 0 and 255)
    buf: pointer to 8 bytes
 */
-static void u8x8_get_glyph_data(u8x8_t *u8x8, uint8_t encoding, uint8_t *buf, uint8_t tile_offset) U8X8_NOINLINE;
-static void u8x8_get_glyph_data(u8x8_t *u8x8, uint8_t encoding, uint8_t *buf, uint8_t tile_offset) 
+void u8x8_get_glyph_data(u8x8_t *u8x8, uint8_t encoding, uint8_t *buf, uint8_t tile_offset) U8X8_NOINLINE;
+void u8x8_get_glyph_data(u8x8_t *u8x8, uint8_t encoding, uint8_t *buf, uint8_t tile_offset) 
 {
   uint8_t first, last, tiles, i;
   uint16_t offset;

+ 53 - 6
components/u8g2/u8x8_cad.c

@@ -480,6 +480,7 @@ static void u8x8_i2c_data_transfer(u8x8_t *u8x8, uint8_t arg_int, void *arg_ptr)
 }
 
 /* classic version: will put a start/stop condition around each command and arg */
+/* implements CAD = 001 */
 uint8_t u8x8_cad_ssd13xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 {
   uint8_t *p;
@@ -505,7 +506,53 @@ uint8_t u8x8_cad_ssd13xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
       /* Unfortunately, this can not be handled in the byte level drivers, */
       /* so this is done here. Even further, only 24 bytes will be sent, */
       /* because there will be another byte (DC) required during the transfer */
-      p = arg_ptr;
+      p = (uint8_t *)arg_ptr;
+       while( arg_int > 24 )
+      {
+	u8x8_i2c_data_transfer(u8x8, 24, p);
+	arg_int-=24;
+	p+=24;
+      }
+      u8x8_i2c_data_transfer(u8x8, arg_int, p);
+      break;
+    case U8X8_MSG_CAD_INIT:
+      /* apply default i2c adr if required so that the start transfer msg can use this */
+      if ( u8x8->i2c_address == 255 )
+	u8x8->i2c_address = 0x078;
+      return u8x8->byte_cb(u8x8, msg, arg_int, arg_ptr);
+    case U8X8_MSG_CAD_START_TRANSFER:
+    case U8X8_MSG_CAD_END_TRANSFER:
+      /* cad transfer commands are ignored */
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+
+
+/* classic version: will put a start/stop condition around each command and arg */
+/* implements CAD = 011 for the SSD1363 */
+uint8_t u8x8_cad_011_ssd13xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t *p;
+  switch(msg)
+  {
+    case U8X8_MSG_CAD_SEND_CMD:
+      u8x8_byte_StartTransfer(u8x8);
+      u8x8_byte_SendByte(u8x8, 0x000);
+      u8x8_byte_SendByte(u8x8, arg_int);
+      u8x8_byte_EndTransfer(u8x8);      
+      break;
+    case U8X8_MSG_CAD_SEND_ARG:
+      u8x8_byte_StartTransfer(u8x8);
+      u8x8_byte_SendByte(u8x8, 0x040);
+      u8x8_byte_SendByte(u8x8, arg_int);
+      u8x8_byte_EndTransfer(u8x8);      
+      break;
+    case U8X8_MSG_CAD_SEND_DATA:
+      p = (uint8_t *)arg_ptr;
        while( arg_int > 24 )
       {
 	u8x8_i2c_data_transfer(u8x8, 24, p);
@@ -575,7 +622,7 @@ uint8_t u8x8_cad_ssd13xx_fast_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, vo
       /* Unfortunately, this can not be handled in the byte level drivers, */
       /* so this is done here. Even further, only 24 bytes will be sent, */
       /* because there will be another byte (DC) required during the transfer */
-      p = arg_ptr;
+      p = (uint8_t *)arg_ptr;
        while( arg_int > 24 )
       {
 	u8x8_i2c_data_transfer(u8x8, 24, p);
@@ -627,7 +674,7 @@ uint8_t u8x8_cad_st75256_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
       break;
     case U8X8_MSG_CAD_SEND_DATA:
       /* see ssd13xx driver */
-      p = arg_ptr;
+      p = (uint8_t *)arg_ptr;
        while( arg_int > 24 )
       {
 	u8x8_i2c_data_transfer(u8x8, 24, p);
@@ -680,7 +727,7 @@ uint8_t u8x8_cad_ld7032_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *ar
       /* Unfortunately, this can not be handled in the byte level drivers, */
       /* so this is done here. Even further, only 24 bytes will be sent, */
       /* because there will be another byte (DC) required during the transfer */
-      p = arg_ptr;
+      p = (uint8_t *)arg_ptr;
        while( arg_int > 24 )
       {
 	u8x8->byte_cb(u8x8, U8X8_MSG_CAD_SEND_DATA, 24, p);
@@ -764,7 +811,7 @@ uint8_t u8x8_cad_uc16xx_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *ar
       in_transfer = 1;
       // is_data = 1;  // 20 Jun 2021: I assume that this is missing here
       
-      p = arg_ptr;
+      p = (uint8_t *)arg_ptr;
       while( arg_int > 24 )
       {
 	u8x8->byte_cb(u8x8, U8X8_MSG_CAD_SEND_DATA, 24, p);
@@ -871,7 +918,7 @@ uint8_t u8x8_cad_uc1638_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *ar
       in_transfer = 1;
       is_data = 1;
       
-      p = arg_ptr;
+      p = (uint8_t *)arg_ptr;
       while( arg_int > 24 )
       {
 	u8x8->byte_cb(u8x8, U8X8_MSG_CAD_SEND_DATA, 24, p);

+ 311 - 0
components/u8g2/u8x8_d_ch1120.c

@@ -0,0 +1,311 @@
+/*
+
+  u8x8_d_ch1120.c
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2018, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+  
+*/
+
+
+#include "u8x8.h"
+
+/* 
+  code copyied from sh1107
+  ch1120: 160x160 controller from Sino Wealth
+  https://github.com/olikraus/u8g2/issues/2496
+*/
+
+
+
+static const uint8_t u8x8_d_ch1120_noname_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0af),		                /* display on */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ch1120_noname_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0ae),		                /* display off */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ch1120_160x160_noname_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a0),				/* segment remap a0/a1*/
+  U8X8_C(0x0c0),				/* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ch1120_160x160_noname_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a1),				/* segment remap a0/a1*/
+  U8X8_C(0x0c8),				/* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+static uint8_t u8x8_d_ch1120_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t x, c;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ch1120_64x128_noname_display_info);
+      break;
+    */
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ch1120_64x128_noname_init_seq);    
+      break;
+    */
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ch1120_noname_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ch1120_noname_powersave1_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ch1120_160x160_noname_powersave0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ch1120_160x160_noname_powersave1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x081 );
+      u8x8_cad_SendArg(u8x8, arg_int );	/* ch1120 has range from 0 to 255 */
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      u8x8_cad_StartTransfer(u8x8);
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+      x += u8x8->x_offset;
+
+      //u8x8_cad_SendCmd(u8x8, 0x040 ); /* set line offset to 0 */
+
+      // set column address
+      u8x8_cad_SendCmd(u8x8, 0x010 | (x >> 4));
+      u8x8_cad_SendCmd(u8x8, 0x000 | ((x & 15))); 
+      
+      // set page address
+      u8x8_cad_SendCmd(u8x8, 0x0b0 ); 		// page cmd is a two byte command
+      u8x8_cad_SendArg(u8x8, (((u8x8_tile_t *)arg_ptr)->y_pos)); 
+    
+      do
+      {
+	c = ((u8x8_tile_t *)arg_ptr)->cnt;
+	ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+	u8x8_cad_SendData(u8x8, c*8, ptr); 	/* note: SendData can not handle more than 255 bytes */
+	arg_int--;
+      } while( arg_int > 0 );
+      
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+/*==================================================*/
+
+#ifdef NOT_YET_REQUESTED
+/* 160x160 OLED */
+static const uint8_t u8x8_d_ch1120_160x160_noname_init_seq[] = {
+    
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+    
+  U8X8_C(0x0ae),		                /* display off */
+  U8X8_CA(0x0d5, 0x060),		/* clock divide ratio and oscillator frequency */
+  U8X8_CA(0x0a9, 0x003), 		/* set display resolution, 0=64x160, 1=96x160, 2=128x160, 3=160x160 */
+  U8X8_C(0x020),		                /* addressing mode */
+  U8X8_CA(0x081, 0x01f), 		/* set contrast control */
+  U8X8_CA(0x0ad, 0x80),			/* DC/DC control 80=Use external Vpp, 89=Use internal DC/DC*/
+  U8X8_C(0x030),				/* set discharge VSL level, 0x030..0x03f */
+  U8X8_CA(0x0d9, 0x028), 		/* pre-charge period */
+  U8X8_CA(0x0db, 0x035), 		/* vcomh deselect level */    
+  U8X8_CA(0x0dc, 0x035),		/* VSEGM Deselect Level */
+
+  U8X8_C(0x0a0),				/* segment remap a0/a1*/
+  U8X8_C(0x0c0),				/* c0: scan dir normal, c8: reverse */
+  
+  U8X8_C(0x0a4),				/* output ram to display */
+  U8X8_C(0x0a6),				/* none inverted normal display mode */
+    
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const u8x8_display_info_t u8x8_ch1120_160x160_noname_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 60,
+  /* pre_chip_disable_wait_ns = */ 120,
+  /* reset_pulse_width_ms = */ 100, 	/* ch1120: 3 us */
+  /* post_reset_wait_ms = */ 100, /* sometimes OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 100,		/* ch1120: 100ns */
+  /* sck_pulse_width_ns = */ 100,	/* ch1120: 100ns */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 150,	/* ch1120: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 20,
+  /* tile_height = */ 20,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 160,
+  /* pixel_height = */ 160
+};
+
+uint8_t u8x8_d_ch1120_160x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+    
+  if ( u8x8_d_ch1120_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+  
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ch1120_160x160_noname_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ch1120_160x160_noname_display_info);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+#endif
+
+/*==================================================*/
+
+
+/* https://github.com/olikraus/u8g2/issues/2496, 128x160 OLED */
+static const uint8_t u8x8_d_ch1120_128x160_noname_init_seq[] = {
+    
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+    
+  U8X8_C(0x0ae),		                /* display off */
+  //U8X8_CAA(0x21, 0x00, 0x1f),           /* Set Column Start/End Address of Display RAM, mono mode */
+  //U8X8_CAA(0x22, 0x00, 0x4f),           /* Set Row Start/End Address of Display RAM, mono mode */
+  U8X8_CA(0x0a2, 0x000),		/* display start */
+  U8X8_CA(0x081, 0x08f), 		/* set contrast control */
+  U8X8_CA(0x0ac, 0x001),		/* mono mode, or 0x003???*/
+  U8X8_CA(0x020, 0x000),		/* addressing mode */
+  U8X8_C(0x0C8),		                /* scan direction */
+  U8X8_CA(0x0a3, 0x000),		/* display rotation */
+  
+  U8X8_CA(0x0a8, 0x07f),		/* multiplex ratio */
+  U8X8_CA(0x0d3, 0x010),		/* display offset */
+  
+  U8X8_CA(0x0d5, 0x01f),		/* clock divide ratio and oscillator frequency */
+  
+  U8X8_CA(0x048, 0x002),		/*  */
+  U8X8_CA(0x093, 0x002),		/*  */
+  U8X8_CA(0x0d8, 0x001),		/*  */
+  U8X8_CA(0x049, 0x006),		/*  */
+  U8X8_CA(0x0d9, 0x00f),		/*  */
+  U8X8_CA(0x094, 0x01f),		/*  */
+  U8X8_CA(0x04b, 0x004),		/*  */
+  U8X8_CA(0x0da, 0x000),		/*  */
+  U8X8_CA(0x0dc, 0x040),		/* VSEGM Deselect Level */
+  U8X8_CA(0x0ad, 0x002),		/*  */
+   
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const u8x8_display_info_t u8x8_ch1120_128x160_noname_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 20,
+  /* reset_pulse_width_ms = */ 100, 	/* ch1120: 3 us */
+  /* post_reset_wait_ms = */ 100, /* sometimes OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 100,		/* ch1120: 100ns */
+  /* sck_pulse_width_ns = */ 100,	/* ch1120: 100ns */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 40,	/* ch1120: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 16,
+  /* tile_height = */ 20,
+  /* default_x_offset = */ 16,
+  /* flipmode_x_offset = */ 16,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 160
+};
+
+uint8_t u8x8_d_ch1120_128x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+    
+  if ( u8x8_d_ch1120_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+  
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ch1120_128x160_noname_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ch1120_128x160_noname_display_info);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+/*==================================================*/

+ 2 - 2
components/u8g2/u8x8_d_ks0108.c

@@ -110,7 +110,7 @@ static const u8x8_display_info_t u8x8_ks0108_128x64_display_info =
   
   /* post_chip_enable_wait_ns = */ 100,
   /* pre_chip_disable_wait_ns = */ 20,
-  /* reset_pulse_width_ms = */ 1, 
+  /* reset_pulse_width_ms = */ 5, 
   /* post_reset_wait_ms = */ 6, 		/* could be faster for the KS0108 */
   /* sda_setup_time_ns = */ 12,		
   /* sck_pulse_width_ns = */ 75,	/* KS0108: Not used */
@@ -217,7 +217,7 @@ static const u8x8_display_info_t u8x8_ks0108_192x64_display_info =
   
   /* post_chip_enable_wait_ns = */ 100,
   /* pre_chip_disable_wait_ns = */ 20,
-  /* reset_pulse_width_ms = */ 1, 
+  /* reset_pulse_width_ms = */ 5, 
   /* post_reset_wait_ms = */ 6, 		/* could be faster for the KS0108 */
   /* sda_setup_time_ns = */ 12,		
   /* sck_pulse_width_ns = */ 75,	/* KS0108: Not used */

+ 42 - 0
components/u8g2/u8x8_d_ls013b7dh03.c

@@ -121,6 +121,7 @@ uint8_t u8x8_d_ls013b7dh03_128x128(u8x8_t *u8x8, uint8_t msg, U8X8_UNUSED uint8_
   return 1;
 }
 
+/*===============================================*/
 
 static const u8x8_display_info_t u8x8_ls027b7dh01_400x240_display_info =
 {
@@ -158,6 +159,8 @@ uint8_t u8x8_d_ls027b7dh01_400x240(u8x8_t *u8x8, uint8_t msg, U8X8_UNUSED uint8_
   return 1;
 }
 
+/*===============================================*/
+
 static const u8x8_display_info_t u8x8_ls027b7dh01_m0_400x240_display_info =
 {
   /* chip_enable_level = */ 1,
@@ -194,6 +197,7 @@ uint8_t u8x8_d_ls027b7dh01_m0_400x240(u8x8_t *u8x8, uint8_t msg, U8X8_UNUSED uin
   return 1;
 }
 
+/*===============================================*/
 
 static const u8x8_display_info_t u8x8_ls013b7dh05_144x168_display_info =
 {
@@ -231,4 +235,42 @@ uint8_t u8x8_d_ls013b7dh05_144x168(u8x8_t *u8x8, uint8_t msg, U8X8_UNUSED uint8_
   return 1;
 }
 
+/*===============================================*/
+/* https://github.com/olikraus/u8g2/issues/2210 */
+
+static const u8x8_display_info_t u8x8_ls011b7dh03_160x68_display_info =
+{
+  /* chip_enable_level = */ 1,
+  /* chip_disable_level = */ 0,
+  /* post_chip_enable_wait_ns = */ 50,
+  /* pre_chip_disable_wait_ns = */ 50,
+  /* reset_pulse_width_ms = */ 1,
+  /* post_reset_wait_ms = */ 6,
+  /* sda_setup_time_ns = */ 227,	/* 227 nsec according to the datasheet */		
+  /* sck_pulse_width_ns = */  255,	/* 450 nsec according to the datasheet */
+  /* sck_clock_hz = */ 1000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* changed from 2 to 0 (https://github.com/olikraus/u8g2/issues/1771) */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 100,
+  /* write_pulse_width_ns = */ 100,
+  /* tile_width = */ 20,
+  /* tile_height = */ 9,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 160,
+  /* pixel_height = */ 68
+};
+
+uint8_t u8x8_d_ls011b7dh03_160x68(u8x8_t *u8x8, uint8_t msg, U8X8_UNUSED uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ls011b7dh03_160x68_display_info);
+      break;
+    default:
+      return u8x8_d_ls013b7dh03_128x128(u8x8, msg, arg_int, arg_ptr);
+  }    
+  return 1;
+}
 

+ 138 - 0
components/u8g2/u8x8_d_pcf8812.c

@@ -60,6 +60,22 @@ static const uint8_t u8x8_d_pcf8812_96x65_init_seq[] = {
   U8X8_END()             			/* end of sequence */
 };
 
+
+static const uint8_t u8x8_d_pcf8812_101x64_init_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x21), // PowerON, ExtCommandSet
+  U8X8_C(0x09), // Internal HV-gen x3
+  U8X8_C(0xB7), // Set Vop
+  U8X8_C(0x16), // Bias n=2    //15
+  U8X8_C(0x06), // Temperature coeff 2
+  U8X8_C(0x20), // StandartCommandSet
+  U8X8_C(0x0C), // normal mode, display non-inverted
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+
 static const uint8_t u8x8_d_pcf8812_96x65_powersave0_seq[] = {
   U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
   U8X8_C(0x020),		                /* power on */
@@ -156,6 +172,86 @@ static uint8_t u8x8_d_pcf8812_96x65_generic(u8x8_t *u8x8, uint8_t msg, uint8_t a
 }
 
 
+static uint8_t u8x8_d_pcf8812_101x64_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t x, c;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_pcf8812_96x65_display_info);
+      break;
+    */
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_pcf8812_101x64_init_seq);    
+      break;
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_pcf8812_96x65_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_pcf8812_96x65_powersave1_seq);
+      break;
+/*
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_pcf8812_96x65_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_pcf8812_96x65_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+*/
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x021 );    /* command mode, extended function set */
+      u8x8_cad_SendArg(u8x8, (arg_int>>1)|0x80 );	/* 0..127 for contrast */
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      u8x8_cad_StartTransfer(u8x8);
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+      x += u8x8->x_offset;
+    
+      u8x8_cad_SendCmd(u8x8, 0x020 );	/* activate chip (PD=0), horizontal increment (V=0), enter normal command set (H=0) */
+      u8x8_cad_SendCmd(u8x8, 0x080 | x);
+      u8x8_cad_SendCmd(u8x8, 0x040 | ((u8x8_tile_t *)arg_ptr)->y_pos);
+      
+      do
+      {
+	c = ((u8x8_tile_t *)arg_ptr)->cnt;
+	ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+	u8x8_cad_SendData(u8x8, c*8, ptr); 	/* note: SendData can not handle more than 255 bytes */
+	/*
+	do
+	{
+	  u8x8_cad_SendData(u8x8, 8, ptr);
+	  ptr += 8;
+	  c--;
+	} while( c > 0 );
+	*/
+	arg_int--;
+      } while( arg_int > 0 );
+      
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+
+
+
 static const u8x8_display_info_t u8x8_pcf8812_96x65_display_info =
 {
   /* chip_enable_level = */ 0,
@@ -190,4 +286,46 @@ uint8_t u8x8_d_pcf8812_96x65(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
     return u8x8_d_pcf8812_96x65_generic(u8x8, msg, arg_int, arg_ptr);
 }
 
+/* https://github.com/olikraus/u8g2/issues/2421 */
+static const u8x8_display_info_t u8x8_pcf8812_101x64_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 100,
+  /* pre_chip_disable_wait_ns = */ 100,
+  /* reset_pulse_width_ms = */ 100, 
+  /* post_reset_wait_ms = */ 100, 
+  /* sda_setup_time_ns = */ 100,	
+  /* sck_pulse_width_ns = */ 100,	
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 150,	
+  /* tile_width = */ 13,
+  /* tile_height = */ 8,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 101,
+  /* pixel_height = */ 64
+};
+
+
+
+
+uint8_t u8x8_d_pcf8812_101x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+    if ( msg == U8X8_MSG_DISPLAY_SETUP_MEMORY )
+    {
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_pcf8812_101x64_display_info);
+      return 1;
+    }
+    else if ( msg == U8X8_MSG_DISPLAY_INIT )
+    {
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_pcf8812_101x64_init_seq);    
+    }    
+    return u8x8_d_pcf8812_101x64_generic(u8x8, msg, arg_int, arg_ptr);
+}
 

+ 219 - 0
components/u8g2/u8x8_d_s1d15300.c

@@ -251,5 +251,224 @@ uint8_t u8x8_d_s1d15300_lm6023(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void
 }
 
 /*================================================*/
+/* https://github.com/olikraus/u8g2/issues/2377 */
+
+static const u8x8_display_info_t u8x8_s1d15300_97x32_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 250,	/*  */
+  /* pre_chip_disable_wait_ns = */ 120,	/*  */
+  /* reset_pulse_width_ms = */ 1, 
+  /* post_reset_wait_ms = */ 1, 
+  /* sda_setup_time_ns = */ 200,		/* */
+  /* sck_pulse_width_ns = */ 200,	/* half of cycle time (100ns according to datasheet), AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 1000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 200,	/* st7565 datasheet, table 24, tds8 */
+  /* write_pulse_width_ns = */ 200,	/* st7565 datasheet, table 24, tcclw */
+  /* tile_width = */ 13,		/* width of 16*8=128 pixel */
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 97,
+  /* pixel_height = */ 32
+};
+
+
+static const u8x8_display_info_t u8x8_s1d15300_100x32_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 250,	/*  */
+  /* pre_chip_disable_wait_ns = */ 120,	/*  */
+  /* reset_pulse_width_ms = */ 1, 
+  /* post_reset_wait_ms = */ 1, 
+  /* sda_setup_time_ns = */ 200,		/* */
+  /* sck_pulse_width_ns = */ 200,	/* half of cycle time (100ns according to datasheet), AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 1000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 200,	/* st7565 datasheet, table 24, tds8 */
+  /* write_pulse_width_ns = */ 200,	/* st7565 datasheet, table 24, tcclw */
+  /* tile_width = */ 13,		/* width of 16*8=128 pixel */
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 100,
+  /* pixel_height = */ 32
+};
+
+static const u8x8_display_info_t u8x8_s1d15300_100x32i_display_info =
+{
+  /* chip_enable_level = */ 1,
+  /* chip_disable_level = */ 0,
+  
+  /* post_chip_enable_wait_ns = */ 250,	/*  */
+  /* pre_chip_disable_wait_ns = */ 120,	/*  */
+  /* reset_pulse_width_ms = */ 1, 
+  /* post_reset_wait_ms = */ 1, 
+  /* sda_setup_time_ns = */ 200,		/* */
+  /* sck_pulse_width_ns = */ 200,	/* half of cycle time (100ns according to datasheet), AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 1000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 200,	/* st7565 datasheet, table 24, tds8 */
+  /* write_pulse_width_ns = */ 200,	/* st7565 datasheet, table 24, tcclw */
+  /* tile_width = */ 13,		/* width of 16*8=128 pixel */
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 100,
+  /* pixel_height = */ 32
+};
+
+
+static const uint8_t u8x8_d_s1d15300_100x32_init_seq[] = {
+
+
+    U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
+
+    U8X8_C(0x0e2), /* soft reset */
+
+    U8X8_C(0x0ae), /* display off */
+    U8X8_C(0x040), /* set display start line to 0 */
+    U8X8_C(0x0a0), /* ADC set to normal */
+    U8X8_C(0x0a6), /* Display normal */
+    U8X8_C(0x0a4), /* all point normal */
+
+    U8X8_C(0x0a2), /* LCD bias 1/8 */
+    U8X8_C(0x0c8), /* common output mode */
+    U8X8_C(0x02f), /* power, might be 0x02c */
+
+
+    U8X8_C(0x094), /* set contrast */
+    //U8X8_C(0x0af), /* display on */
+
+    U8X8_C(0x0b0), /* set page address */
+    U8X8_C(0x010), /* set column address upper */
+    U8X8_C(0x000), /* set column address lower */
+
+    U8X8_END_TRANSFER(), /* disable chip */
+    U8X8_END()           /* end of sequence */  
+};
+
+uint8_t u8x8_d_s1d15300_97x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  /* call common procedure first and handle messages there */
+  if ( u8x8_d_s1d15300_common(u8x8, msg, arg_int, arg_ptr) == 0 )
+  {
+    /* msg not handled, then try here */
+    switch(msg)
+    {
+      case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+	u8x8_d_helper_display_setup_memory(u8x8, &u8x8_s1d15300_97x32_display_info);
+	break;
+      case U8X8_MSG_DISPLAY_INIT:
+	u8x8_d_helper_display_init(u8x8);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_100x32_init_seq);
+	break;
+      case U8X8_MSG_DISPLAY_SET_FLIP_MODE: 
+        /* needs to be fixed regarding a0/c0 */
+        /*
+	if ( arg_int == 0 )
+	{
+	  u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_flip0_seq);
+	  u8x8->x_offset = u8x8->display_info->default_x_offset;
+	}
+	else
+	{
+	  u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_flip1_seq);
+	  u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+	}
+        */
+	break;
+      default:
+	return 0;		/* msg unknown */
+    }
+  }
+  return 1;
+}
+
+
+uint8_t u8x8_d_s1d15300_100x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  /* call common procedure first and handle messages there */
+  if ( u8x8_d_s1d15300_common(u8x8, msg, arg_int, arg_ptr) == 0 )
+  {
+    /* msg not handled, then try here */
+    switch(msg)
+    {
+      case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+	u8x8_d_helper_display_setup_memory(u8x8, &u8x8_s1d15300_100x32_display_info);
+	break;
+      case U8X8_MSG_DISPLAY_INIT:
+	u8x8_d_helper_display_init(u8x8);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_100x32_init_seq);
+	break;
+      case U8X8_MSG_DISPLAY_SET_FLIP_MODE: 
+        /* needs to be fixed regarding a0/c0 */
+        /*
+	if ( arg_int == 0 )
+	{
+	  u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_flip0_seq);
+	  u8x8->x_offset = u8x8->display_info->default_x_offset;
+	}
+	else
+	{
+	  u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_flip1_seq);
+	  u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+	}
+        */
+	break;
+      default:
+	return 0;		/* msg unknown */
+    }
+  }
+  return 1;
+}
+
+uint8_t u8x8_d_s1d15300_100x32i(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  /* call common procedure first and handle messages there */
+  if ( u8x8_d_s1d15300_common(u8x8, msg, arg_int, arg_ptr) == 0 )
+  {
+    /* msg not handled, then try here */
+    switch(msg)
+    {
+      case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+	u8x8_d_helper_display_setup_memory(u8x8, &u8x8_s1d15300_100x32i_display_info);
+	break;
+      case U8X8_MSG_DISPLAY_INIT:
+	u8x8_d_helper_display_init(u8x8);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_100x32_init_seq);
+	break;
+      case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+        /* needs to be fixed regarding a0/c0 */
+        /*
+	if ( arg_int == 0 )
+	{
+	  u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_flip0_seq);
+	  u8x8->x_offset = u8x8->display_info->default_x_offset;
+	}
+	else
+	{
+	  u8x8_cad_SendSequence(u8x8, u8x8_d_s1d15300_flip1_seq);
+	  u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+	}
+        */
+	break;
+      default:
+	return 0;		/* msg unknown */
+    }
+  }
+  return 1;
+}
+
+
+/*================================================*/
 
 

+ 83 - 0
components/u8g2/u8x8_d_sed1330.c

@@ -264,6 +264,89 @@ uint8_t u8x8_d_ra8835_nhd_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, vo
   return 1;
 }
 
+/*=============================================*/
+/* issue 2518 https://github.com/olikraus/u8g2/issues/2518 */
+
+static const u8x8_display_info_t u8x8_sed1330_240x64_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 30,	/* G242CX Datasheet p5 */
+  /* pre_chip_disable_wait_ns = */ 10,	/* G242CX Datasheet p5 */
+  /* reset_pulse_width_ms = */ 1, 
+  /* post_reset_wait_ms = */ 6, 
+  /* sda_setup_time_ns = */ 20,		
+  /* sck_pulse_width_ns = */  140,	
+  /* sck_clock_hz = */ 1000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 120,		/* G242CX Datasheet p5 */
+  /* write_pulse_width_ns = */ 220,		/* G242CX Datasheet p5 */
+  /* tile_width = */ 30,
+  /* tile_height = */ 8,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 240,
+  /* pixel_height = */ 64
+};
+
+static const uint8_t u8x8_d_sed1330_240x64_init_seq[] = {
+  U8X8_DLY(100),
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_DLY(100),
+
+  /* system init command, see also u8x8_d_sed1330_powersave0_seq */
+  U8X8_CA(0x040, 0x030),		/* sys init (0x040) with one arg, where 0x030 is a wild guess */
+  /* system init has total 8 parameters, so 7 more are here */
+  U8X8_A(0x087),				/* no idea here... WF (topmost bit) is set to one because it is suggested in the datasheet, lowest 3 bits refer to text mode only */
+  U8X8_A(0x007),				/* FY: height of a char+1, does not matter here (hopefully), because we use graphics mode only */
+  U8X8_A(0x01d),				/* C/R: this could be the number of horizontal bytes - 1 (Value confirmed with app notes p41) */
+  U8X8_A(0x050),					/* TC/R: According to app notes fOSC=6Mhz fFF=70Hz --> TC/R = 74d*/
+  U8X8_A(0x03f),				/* L/F: Lines per frame - 1, probably this is the height of the display - 1 (value confirmed with app notes p41)*/
+  U8X8_A(0x01e),				/* Low byte of the virtual screen size. (Value confirmed with app notes p41)   */
+  U8X8_A(0),					/* High byte of the virtual screen size, see also section 9.1.2 */
+	
+  U8X8_C(0x044),				/* SCROLL */
+  U8X8_A(0x000),				
+  U8X8_A(0x000),				
+  U8X8_A(0x080),
+  U8X8_A(0x000),
+  U8X8_A(0x040),
+  U8X8_A(0x080),
+  U8X8_A(0x000),
+  U8X8_A(0x000),
+  U8X8_A(0x000),
+  U8X8_A(0x000),
+	
+  U8X8_CA(0x05a, 0),			/* HDOT SCR: Horizontal dotwise scroll... set to 0 */
+	
+  U8X8_CA(0x05b, 0x0c),			/* OVLAY: 2-layer, all graphics, OR between layer 1 and 2 */
+
+
+  U8X8_DLY(100),
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_DLY(100),
+};
+
+
+uint8_t u8x8_d_sed1330_240x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_sed1330_240x64_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_sed1330_240x64_init_seq);
+      u8x8_SendF(u8x8, "caaaaaaaa", 0x40, 0x30, 0x87, 0x07, 0x1d, 0x50, 0x3f, 0x1e, 0x00);  /* send init again, issue 2518 https://github.com/olikraus/u8g2/issues/2518 */
+      break;
+    default:
+      return u8x8_d_sed1330_common(u8x8, msg, arg_int, arg_ptr);
+  }
+  return 1;
+}
 
 
 /*=============================================*/

+ 10 - 2
components/u8g2/u8x8_d_sh1107.c

@@ -465,6 +465,14 @@ uint8_t u8x8_d_sh1107_hjr_oel1m0201_96x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg
 /*==================================================*/
 /* 128x128 OLED: this display has a very strange x offset */
 
+/* 
+6 Feb 2025: 
+There is an issue 
+https://github.com/olikraus/u8g2/issues/2581#issuecomment-2628394758 
+Looks like there are displays where the x offset must be 0
+*/
+
+
 /* sequence taken over from 64x128 sequence, because it seems to work mostly */
 static const uint8_t u8x8_d_sh1107_128x128_init_seq[] = {
     
@@ -516,8 +524,8 @@ static const u8x8_display_info_t u8x8_sh1107_128x128_display_info =
   /* write_pulse_width_ns = */ 150,	/* sh1107: cycle time is 300ns, so use 300/2 = 150 */
   /* tile_width = */ 16,
   /* tile_height = */ 16,
-  /* default_x_offset = */ 0,
-  /* flipmode_x_offset = */ 0,
+  /* default_x_offset = */ 96,
+  /* flipmode_x_offset = */ 96,
   /* pixel_width = */ 128,
   /* pixel_height = */ 128
 };

+ 1 - 1
components/u8g2/u8x8_d_sh1108.c

@@ -232,7 +232,7 @@ static const uint8_t u8x8_d_sh1108_128x160_noname_init_seq[] = {
     
   U8X8_C(0x0ae),		                /* display off */
   U8X8_CA(0x0d5, 0x060),		/* clock divide ratio and oscillator frequency */
-  U8X8_CA(0x0a9, 0x003), 		/* set display resolution, 0=64x160, 1=96x160, 2=128x160, 3=160x160 */
+  U8X8_CA(0x0a9, 0x002), 		/* set display resolution, 0=64x160, 1=96x160, 2=128x160, 3=160x160 */
   U8X8_C(0x020),		                /* addressing mode */
   U8X8_CA(0x081, 0x01f), 		/* set contrast control */
   U8X8_CA(0x0ad, 0x80),			/* DC/DC control 80=Use external Vpp, 89=Use internal DC/DC*/

+ 119 - 29
components/u8g2/u8x8_d_ssd1309.c

@@ -33,44 +33,40 @@
   
 */
 
-
 #include "u8x8.h"
 
-
-
-
 static const uint8_t u8x8_d_ssd1309_powersave0_seq[] = {
   U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
-  U8X8_C(0x0af),		                /* display on */
-  U8X8_END_TRANSFER(),             	/* disable chip */
-  U8X8_END()             			/* end of sequence */
+  U8X8_C(0x0af),		                  /* display on */
+  U8X8_END_TRANSFER(),             	  /* disable chip */
+  U8X8_END()             			        /* end of sequence */
 };
 
 static const uint8_t u8x8_d_ssd1309_powersave1_seq[] = {
   U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
-  U8X8_C(0x0ae),		                /* display off */
-  U8X8_END_TRANSFER(),             	/* disable chip */
-  U8X8_END()             			/* end of sequence */
+  U8X8_C(0x0ae),		                  /* display off */
+  U8X8_END_TRANSFER(),             	  /* disable chip */
+  U8X8_END()             			        /* end of sequence */
 };
 
-static const uint8_t u8x8_d_ssd1309_128x64_flip0_seq[] = {
+/* ==> CSC rename u8x8_d_ssd1309_128x64_flip0_seq => u8x8_d_ssd1309_flip0_seq <== */
+static const uint8_t u8x8_d_ssd1309_flip0_seq[] = {
   U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
-  U8X8_C(0x0a1),				/* segment remap a0/a1*/
-  U8X8_C(0x0c8),				/* c0: scan dir normal, c8: reverse */
-  U8X8_END_TRANSFER(),             	/* disable chip */
-  U8X8_END()             			/* end of sequence */
+  U8X8_C(0x0a1),				              /* segment remap a0/a1*/
+  U8X8_C(0x0c8),				              /* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),             	  /* disable chip */
+  U8X8_END()             			        /* end of sequence */
 };
 
-static const uint8_t u8x8_d_ssd1309_128x64_flip1_seq[] = {
+/* ==> CSC rename u8x8_d_ssd1309_128x64_flip1_seq => u8x8_d_ssd1309_flip1_seq <== */
+static const uint8_t u8x8_d_ssd1309_flip1_seq[] = {
   U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
-  U8X8_C(0x0a0),				/* segment remap a0/a1*/
-  U8X8_C(0x0c0),				/* c0: scan dir normal, c8: reverse */
-  U8X8_END_TRANSFER(),             	/* disable chip */
-  U8X8_END()             			/* end of sequence */
+  U8X8_C(0x0a0),				              /* segment remap a0/a1*/
+  U8X8_C(0x0c0),				              /* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),             	  /* disable chip */
+  U8X8_END()             			        /* end of sequence */
 };
 
-
-
 static uint8_t u8x8_d_ssd1309_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 {
   uint8_t x, c;
@@ -160,7 +156,6 @@ static const uint8_t u8x8_d_ssd1309_128x64_noname_init_seq[] = {
     
   U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
   
-  
   U8X8_C(0x0ae),		                /* display off */
   U8X8_CA(0x0d5, 0x0a0),		/* clock divide ratio (0x00=1) and oscillator frequency (0x8) */
   //U8X8_CA(0x0a8, 0x03f),		/* multiplex ratio */
@@ -191,6 +186,41 @@ static const uint8_t u8x8_d_ssd1309_128x64_noname_init_seq[] = {
   U8X8_END()             			/* end of sequence */
 };
 
+/* CSC ==> */
+static const uint8_t u8x8_d_ssd1309_128x128_noname_init_seq[] = {
+
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+
+  U8X8_C(0x0ae),		                  /* display off */
+  U8X8_CA(0x0d5, 0x0a0),		          /* clock divide ratio (0x00=1) and oscillator frequency (0x8) */
+  U8X8_CA(0x0a8, 0x07f),              /* multiplex ratio */ /* 128 Zeilen  0x07f, 64 Zeilen 0x03f */
+  U8X8_C(0x040),            	        /* set display start line to 0 */
+  U8X8_CA(0x020, 0x002),		          /* horizontal addressing mode */
+
+  U8X8_C(0x0a1),				              /* segment remap a0/a1*/
+  U8X8_C(0x0c8),				              /* c0: scan dir normal, c8: reverse */
+  // Flipmode
+  // U8X8_C(0x0a0),				            /* segment remap a0/a1*/
+  // U8X8_C(0x0c0),				            /* c0: scan dir normal, c8: reverse */
+
+  U8X8_CA(0x0da, 0x012),		          /* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) */
+
+  U8X8_CA(0x081, 0x06f), 		          /* [2] set contrast control */
+  U8X8_CA(0x0d9, 0x0d3), 		          /* [2] pre-charge period 0x022/f1*/
+  U8X8_CA(0x0db, 0x020), 		          /* vcomh deselect level */
+  // if vcomh is 0, then this will give the biggest range for contrast control issue #98
+  // restored the old values for the noname constructor, because vcomh=0 will not work for all OLEDs, #116
+
+  U8X8_C(0x02e),				              /* Deactivate scroll */
+  U8X8_C(0x0a4),				              /* output ram to display */
+  U8X8_C(0x0a6),				              /* none inverted normal display mode */
+
+  //U8X8_C(0x0af),		                /* display on */
+
+  U8X8_END_TRANSFER(),             	  /* disable chip */
+  U8X8_END()             			        /* end of sequence */
+};
+/* <== CSC */
 
 uint8_t u8x8_d_ssd1309_128x64_noname2(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 {
@@ -203,12 +233,12 @@ uint8_t u8x8_d_ssd1309_128x64_noname2(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int
     case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
       if ( arg_int == 0 )
       {
-	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_128x64_flip0_seq);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip0_seq);
 	u8x8->x_offset = u8x8->display_info->default_x_offset;
       }
       else
       {
-	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_128x64_flip1_seq);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip1_seq);
 	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
       }
       break;
@@ -254,6 +284,32 @@ static const u8x8_display_info_t u8x8_ssd1309_128x64_noname0_display_info =
   /* pixel_height = */ 64
 };
 
+/* CSC ==> */
+static const u8x8_display_info_t u8x8_ssd1309_128x128_noname0_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* SSD1306: 3 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* SSD1306: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 150,	/* SSD1306: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 16,
+  /* tile_height = */ 16,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 128
+};
+/* <== CSC */
+
 uint8_t u8x8_d_ssd1309_128x64_noname0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 {
     
@@ -265,12 +321,12 @@ uint8_t u8x8_d_ssd1309_128x64_noname0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int
     case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
       if ( arg_int == 0 )
       {
-	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_128x64_flip0_seq);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip0_seq);
 	u8x8->x_offset = u8x8->display_info->default_x_offset;
       }
       else
       {
-	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_128x64_flip1_seq);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip1_seq);
 	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
       }
       break;
@@ -287,6 +343,40 @@ uint8_t u8x8_d_ssd1309_128x64_noname0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int
   return 1;
 }
 
+/* CSC ==> */
+uint8_t u8x8_d_ssd1309_128x128_noname0(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+
+  if ( u8x8_d_ssd1309_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	    u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip0_seq);
+	    u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	    u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip1_seq);
+	    u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_128x128_noname_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1309_128x128_noname0_display_info);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+/* <== CSC */
 
 /*=================================================*/
 /*
@@ -352,12 +442,12 @@ uint8_t u8x8_d_ssd1306_102x64_ea_oleds102(u8x8_t *u8x8, uint8_t msg, uint8_t arg
     case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
       if ( arg_int == 0 )
       {
-	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_128x64_flip0_seq);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip0_seq);
 	u8x8->x_offset = u8x8->display_info->default_x_offset;
       }
       else
       {
-	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_128x64_flip1_seq);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1309_flip1_seq);
 	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
       }
       break;

+ 354 - 0
components/u8g2/u8x8_d_ssd1312.c

@@ -0,0 +1,354 @@
+/*
+
+  u8x8_d_ssd1312.c
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2024, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+
+  NOTE: There is another SSD1312 128x64 in u8x8_d_ssd1306_128x64_noname.c
+
+*/
+
+
+#include "u8x8.h"
+
+
+static const uint8_t u8x8_d_ssd1312_128x32_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0af),		                /* display on */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1312_128x32_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0ae),		                /* display off */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+
+static uint8_t u8x8_d_ssd1312_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t x, c;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1306_128x64_noname_display_info);
+      break;
+    */
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1306_128x64_noname_init_seq);    
+      break;
+    */
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_powersave1_seq);
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x081 );
+      u8x8_cad_SendArg(u8x8, arg_int );	/* ssd1306 has range from 0 to 255 */
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      u8x8_cad_StartTransfer(u8x8);
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+      x += u8x8->x_offset;
+    
+      u8x8_cad_SendCmd(u8x8, 0x040 );	/* set line offset to 0 */
+    
+      u8x8_cad_SendCmd(u8x8, 0x010 | (x>>4) );
+      u8x8_cad_SendArg(u8x8, 0x000 | ((x&15)));					/* probably wrong, should be SendCmd */
+      u8x8_cad_SendArg(u8x8, 0x0b0 | (((u8x8_tile_t *)arg_ptr)->y_pos));	/* probably wrong, should be SendCmd */
+
+    
+      do
+      {
+	c = ((u8x8_tile_t *)arg_ptr)->cnt;
+	ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+	u8x8_cad_SendData(u8x8, c*8, ptr); 	/* note: SendData can not handle more than 255 bytes */
+	/*
+	do
+	{
+	  u8x8_cad_SendData(u8x8, 8, ptr);
+	  ptr += 8;
+	  c--;
+	} while( c > 0 );
+	*/
+	arg_int--;
+      } while( arg_int > 0 );
+      
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+
+static const uint8_t u8x8_d_ssd1312_128x32_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a1),				/* segment remap a0/a1*/
+  U8X8_C(0x0c0),				/* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1312_128x32_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a0),				/* segment remap a0/a1*/
+  U8X8_C(0x0c8),				/* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1312_128x32_init_seq[] = {
+    
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+    
+  U8X8_C(0x0ae),		                /* display off */
+  U8X8_CA(0x0d5, 0x080),		/* clock divide ratio (0x00=1) and oscillator frequency (0x8) */
+  U8X8_CA(0x0a8, 0x03f),		/* multiplex ratio */
+  U8X8_CA(0x0d3, 0x000),		/* display offset */
+  U8X8_C(0x040),		                /* set display start line to 0 */
+  U8X8_CA(0x08d, 0x014),		/* [2] charge pump setting (p62): 0x014 enable, 0x010 disable, SSD1306 only, should be removed for SH1106 */
+  U8X8_CA(0x020, 0x000),		/* horizontal addressing mode */
+  
+  U8X8_C(0x0a1),				/* segment remap a0/a1*/
+  U8X8_C(0x0c0),				/* c0: scan dir normal, c8: reverse */
+  
+  /* 11 Aug 2025: The value below doesn't mach the bits 4 and 5, actually 0x12 would enable the alternate odd/even remapping */
+  /* probably the correct configuration value should be 0x00, see https://github.com/olikraus/u8g2/issues/2690 ??? */
+  U8X8_CA(0x0da, 0x012),		/* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) */
+
+  U8X8_CA(0x0d3, 0x030),		/* line shift by 3*16 = 48 */
+
+  U8X8_CA(0x081, 0x0cf), 		/* [2] set contrast control */
+  U8X8_CA(0x0d9, 0x0f1), 		/* [2] pre-charge period 0x022/f1*/
+  U8X8_CA(0x0db, 0x040), 		/* vcomh deselect level */  
+  // if vcomh is 0, then this will give the biggest range for contrast control issue #98
+  // restored the old values for the noname constructor, because vcomh=0 will not work for all OLEDs, #116
+  
+  U8X8_C(0x02e),				/* Deactivate scroll */ 
+  U8X8_C(0x0a4),				/* output ram to display */
+  U8X8_C(0x0a6),				/* none inverted normal display mode */
+    
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const u8x8_display_info_t u8x8_ssd1312_128x32_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* SSD1306: 3 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* SSD1306: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 8000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215) */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 150,	/* SSD1306: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 16,
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 32
+};
+
+/* https://github.com/olikraus/u8g2/issues/2368 128x32 */
+
+
+uint8_t u8x8_d_ssd1312_128x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1312_128x32_display_info);
+      break;
+    default:
+      if ( u8x8_d_ssd1312_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+        return 1;
+  }
+  return 1;
+}
+
+/*====================================*/
+/* issue https://github.com/olikraus/u8g2/issues/2483 */
+
+static const u8x8_display_info_t u8x8_ssd1312_120x32_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* SSD1306: 3 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* SSD1306: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 8000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215) */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 150,	/* SSD1306: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 15,
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 120,
+  /* pixel_height = */ 32
+};
+
+
+uint8_t u8x8_d_ssd1312_120x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1312_120x32_display_info);
+      break;
+    default:
+      if ( u8x8_d_ssd1312_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+        return 1;
+  }
+  return 1;
+}
+
+
+
+
+
+static const u8x8_display_info_t u8x8_ssd1312_120x28_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* SSD1306: 3 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* SSD1306: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 8000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215) */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 150,	/* SSD1306: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 15,
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 120,
+  /* pixel_height = */ 28
+};
+
+
+
+
+uint8_t u8x8_d_ssd1312_120x28(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1312_128x32_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1312_120x28_display_info);
+      break;
+    default:
+      if ( u8x8_d_ssd1312_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+        return 1;
+  }
+  return 1;
+}
+

+ 215 - 0
components/u8g2/u8x8_d_ssd1315_128x64_noname.c

@@ -0,0 +1,215 @@
+/*
+
+  u8x8_d_ssd1315_128x64_noname.c
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2016, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+  
+*/
+
+#include "u8x8.h"
+
+/* more or less generic setup of all these small OLEDs */
+static const uint8_t u8x8_d_ssd1315_128x64_noname_init_seq[] = {
+  U8X8_START_TRANSFER(),  /* enable chip, delay is part of the transfer start */
+
+  U8X8_C(0x0ae),          /* display off */
+  U8X8_CA(0x0d5, 0x090),  /* Set Display Clock Divide */
+  U8X8_CA(0x0a8, 0x03f),  /* multiplex ratio */
+  U8X8_CA(0x0d3, 0x000),  /* display offset */
+  U8X8_C(0x040),          /* set display start line to 0 */
+  U8X8_C(0x0a1),          /* segment remap a0/a1*/
+  U8X8_C(0x0c8),          /* c0: scan dir normal, c8: reverse */
+  U8X8_CA(0x0da, 0x012),  /* com pin HW config, sequential com pin config (bit 4), disable left/right remap (bit 5) */
+  U8X8_CA(0x081, 0x07f),  /* set contrast control */
+  U8X8_CA(0x0d9, 0x022),  /* pre-charge period 0x022/f1*/
+  U8X8_CA(0x0db, 0x030),  /* vcomh deselect level */  
+  U8X8_C(0x0a4),          /* output ram to display */
+  U8X8_C(0x0a6),          /* none inverted normal display mode */
+  U8X8_CA(0x0ad, 0x010),  /* Select External or Internal Iref: 0x20 External Iref = 200kΩ = (9 - 3) / 30uA, 0x10 or 0x30 Internal Iref */
+  U8X8_CA(0x08d, 0x014),  /* charge pump setting: 0x14 enable, VCC=7.5V, 0x00 disable */
+
+  U8X8_END_TRANSFER(),    /* disable chip */
+  U8X8_END()              /* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1315_128x64_noname_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),  /* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0af),          /* display on */
+  U8X8_END_TRANSFER(),    /* disable chip */
+  U8X8_END()              /* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1315_128x64_noname_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),  /* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0ae),          /* display off */
+  U8X8_END_TRANSFER(),    /* disable chip */
+  U8X8_END()              /* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1315_128x64_noname_flip0_seq[] = {
+  U8X8_START_TRANSFER(),  /* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a1),          /* segment remap a0/a1*/
+  U8X8_C(0x0c8),          /* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),    /* disable chip */
+  U8X8_END()              /* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1315_128x64_noname_flip1_seq[] = {
+  U8X8_START_TRANSFER(),  /* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a0),          /* segment remap a0/a1*/
+  U8X8_C(0x0c0),          /* c0: scan dir normal, c8: reverse */
+  U8X8_END_TRANSFER(),    /* disable chip */
+  U8X8_END()              /* end of sequence */
+};
+
+
+static uint8_t u8x8_d_ssd1315_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t x, c;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1306_128x64_noname_display_info);
+      break;
+    */
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1306_128x64_noname_init_seq);    
+      break;
+    */
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	    u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1315_128x64_noname_powersave0_seq);
+      else
+	    u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1315_128x64_noname_powersave1_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+        u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1315_128x64_noname_flip0_seq);
+        u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+        u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1315_128x64_noname_flip1_seq);
+        u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+  case U8X8_MSG_DISPLAY_SET_CONTRAST:
+    u8x8_cad_StartTransfer(u8x8);
+    u8x8_cad_SendCmd(u8x8, 0x081 );
+    u8x8_cad_SendArg(u8x8, arg_int );	/* ssd1306 has range from 0 to 255 */
+    u8x8_cad_EndTransfer(u8x8);
+    break;
+#endif
+  case U8X8_MSG_DISPLAY_DRAW_TILE:
+    u8x8_cad_StartTransfer(u8x8);
+    x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+    x *= 8;
+    x += u8x8->x_offset;
+
+    u8x8_cad_SendCmd(u8x8, 0x040 ); /* set line offset to 0 */
+
+    u8x8_cad_SendCmd(u8x8, 0x010 | (x>>4) );
+    u8x8_cad_SendArg(u8x8, 0x000 | ((x&15))); /* probably wrong, should be SendCmd */
+    u8x8_cad_SendArg(u8x8, 0x0b0 | (((u8x8_tile_t *)arg_ptr)->y_pos));  /* probably wrong, should be SendCmd */
+
+    do
+    {
+      c = ((u8x8_tile_t *)arg_ptr)->cnt;
+      ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+      u8x8_cad_SendData(u8x8, c*8, ptr);  /* note: SendData can not handle more than 255 bytes */
+    /*
+    do
+    {
+      u8x8_cad_SendData(u8x8, 8, ptr);
+      ptr += 8;
+      c--;
+    } while( c > 0 );
+    */
+	    arg_int--;
+    } while( arg_int > 0 );
+      
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+static const u8x8_display_info_t u8x8_ssd1315_128x64_noname_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* SSD1306: 3 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* SSD1306: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* SSD1306: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 8000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 40,
+  /* write_pulse_width_ns = */ 150,	/* SSD1306: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 16,
+  /* tile_height = */ 8,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 64
+};
+
+uint8_t u8x8_d_ssd1315_128x64_noname(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+    
+  if ( u8x8_d_ssd1315_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+  return 1;
+
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1315_128x64_noname_init_seq);    
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1315_128x64_noname_display_info);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}

+ 166 - 0
components/u8g2/u8x8_d_ssd1320.c

@@ -720,3 +720,169 @@ uint8_t u8x8_d_ssd1320_160x80(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *
   }
   return 1;
 }
+
+
+/*=========================================================*/
+/* https://github.com/olikraus/u8g2/issues/2565 */
+/* 128x72, https://www.buydisplay.com/128x72-grayscale-oled-spi-white-0-72-inch-arduino-raspberry-pi */
+
+static const uint8_t u8x8_d_ssd1320_128x72_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a0),		/* remap */
+  U8X8_C(0xc8),	             /* Set COM Output Scan Direction: normal mode CS1 */
+  U8X8_CA(0xd3, 0x2c),        /* display offset WARNING: ALSO ASSIGN THIS IN THE INIT SEQ */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1320_128x72_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0a1),		/* remap */
+  U8X8_C(0xc0),	             /* Set COM Output Scan Direction: normal mode CS1 */
+  U8X8_CA(0xd3, 0x74),        /* display offset */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const u8x8_display_info_t u8x8_d_ssd1320_128x72_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* ssd1320: 2 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* ssd1320: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* ssd1320: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 10000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215), 10 MHz (issue 301) */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 10,
+  /* write_pulse_width_ns = */ 150,	/* ssd1320: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 16,		/* 128 */
+  /* tile_height = */ 9,                /* 72 */
+  /* default_x_offset = */ 16,	/* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 72
+};
+
+/*      from the buydisplay.com example code for the 8051:
+        Contrast_level=0xDF
+
+	OLED_WR_Byte(0xae,OLED_CMD);//Set y Off
+	OLED_WR_Byte(0xD5,OLED_CMD);//Set Display Clock Divide Ratio/Oscillator Frequency
+	OLED_WR_Byte(0x11,OLED_CMD); 
+	OLED_WR_Byte(0xA8,OLED_CMD);//Set Multiplex Ratio 
+	OLED_WR_Byte(0x47,OLED_CMD); 
+	OLED_WR_Byte(0xA2,OLED_CMD);//Set Display Start Line
+	OLED_WR_Byte(0x00,OLED_CMD); 
+
+  if(USE_HORIZONTAL==0)
+	{
+	 x_offset=0x10;
+	 OLED_WR_Byte(0xD3,OLED_CMD);//Set Display Offset
+	 OLED_WR_Byte(0x2C,OLED_CMD);
+	 OLED_WR_Byte(0xa0,OLED_CMD);//Set COM Output Scan Direction
+	 OLED_WR_Byte(0xC8,OLED_CMD); 
+	}
+	else
+	{
+	 x_offset=0;
+	 OLED_WR_Byte(0xD3,OLED_CMD);//Set Display Offset
+	 OLED_WR_Byte(0x74,OLED_CMD);
+	 OLED_WR_Byte(0xa1,OLED_CMD);//Set COM Output Scan Direction
+	 OLED_WR_Byte(0xC0,OLED_CMD); 
+	}
+	
+	
+	OLED_WR_Byte(0xDA,OLED_CMD);//SetSEGPinsHardwareConfiguration
+	OLED_WR_Byte(0x32,OLED_CMD);
+	
+
+	OLED_WR_Byte(0x81,OLED_CMD);//Set Contrast Control
+	OLED_WR_Byte(Contrast_level,OLED_CMD);
+
+	OLED_WR_Byte(0xD9,OLED_CMD);//SSet Pre-Charge Priod
+	OLED_WR_Byte(0x72,OLED_CMD);
+	OLED_WR_Byte(0xDB,OLED_CMD);//Set VCOMH Deselect Level 
+	OLED_WR_Byte(0x20,OLED_CMD);
+	
+	
+	OLED_WR_Byte(0xAD,OLED_CMD);//Set Internal IREF Enable
+	OLED_WR_Byte(0x00,OLED_CMD);
+	OLED_WR_Byte(0xBC,OLED_CMD);
+	OLED_WR_Byte(0x1E,OLED_CMD); 
+*/
+
+
+static const uint8_t u8x8_d_ssd1320_128x72_init_seq[] = {
+    U8X8_DLY(1),
+    U8X8_START_TRANSFER(),    /* enable chip, delay is part of the transfer start */
+    U8X8_DLY(1),
+    
+    U8X8_C(0xae),		          /* display off */
+    U8X8_CA(0xa8, 0x47),	/* multiplex ratio 1/72 Duty  (128x72 init code) */  
+    U8X8_CA(0xa2, 0),	/* display start line (128x72 init code) */  
+
+    U8X8_C(0xa0),	                /* Set Segment Re-Map */
+    U8X8_C(0xc8),	             	/* Set COM Output Scan Direction: normal mode */
+
+    U8X8_CA(0xad, 0x10), 		/* select Iref: 0x00 external (reset default), 0x10 internal (datasheet: 0x00, but no difference with 0x10) */
+    U8X8_CA(0xbc, 0x1e), 		/* pre-charge voltage level 0x00..0x1f, reset default: 0x1e (128x72 init code)*/
+    U8X8_C(0xbf),		        	/* select linear LUT */  
+    //U8X8_DLY(1),
+  
+    U8X8_CA(0xd5, 0x11 ), 		/* Bit 0..3: clock ratio 1, 2, 4, 8, ...256, reset=0x1, Bit 4..7: F_osc 0..15 (128x72 init code)*/
+
+    U8X8_CA(0xd3, 0x2c),        /* display offset */
+    
+    U8X8_CA(0xda, 0x12),	/* Set SEG Pins Hardware Configuration:  (128x72 init code: 0x32, but 0x12 req here) */  
+    U8X8_CA(0x81, 0xDF),			/* contrast (128x72 init code)  */  
+    U8X8_CA(0xd9, 0x72),		/* Set Phase 1&2 Length, Bit 0..3: Phase 1, Bit 4..7: Phase 2, reset default 0x72 */  
+    U8X8_CA(0xdb, 0x20),		/* VCOMH Deselect Level  (128x72 init code 0x20) */  
+    U8X8_CA(0x20, 0x00),	    /* Memory Addressing Mode: Horizontal */  
+    
+    U8X8_C(0xa4),		        	/* display RAM on */  
+    U8X8_C(0xa6),		          /* normal display */
+
+    U8X8_DLY(1),					/* delay 2ms */
+
+    U8X8_END_TRANSFER(),             	/* disable chip */
+    U8X8_END()             			/* end of sequence */
+};
+
+uint8_t u8x8_d_ssd1320_128x72(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  
+  if ( u8x8_d_ssd1320_common_2(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+        u8x8_d_helper_display_setup_memory(u8x8, &u8x8_d_ssd1320_128x72_display_info);
+      break;
+
+    case U8X8_MSG_DISPLAY_INIT:
+        u8x8_d_helper_display_init(u8x8);
+        u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_128x72_init_seq);
+      break;
+
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 ){
+        u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_128x72_flip0_seq);
+        u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else{
+        u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1320_128x72_flip1_seq);
+        u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    
+    default:
+      break;
+  }
+  return 1;
+}

+ 219 - 0
components/u8g2/u8x8_d_ssd1322.c

@@ -330,6 +330,104 @@ uint8_t u8x8_d_ssd1322_nhd_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, vo
   return 1;
 }
 
+/*=========================================================*/
+/*
+https://github.com/olikraus/u8g2/issues/2386
+*/
+
+
+static const u8x8_display_info_t u8x8_ssd1322_zjy_256x64_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* SSD1322: 2 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* SSD1322: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* SSD1322: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 10000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215), 10 MHz (issue 301) */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 10,
+  /* write_pulse_width_ns = */ 150,	/* SSD1322: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 32,		/* 256 pixel, so we require 32 bytes for this */
+  /* tile_height = */ 8,
+  /* default_x_offset = */ 0x018,	/* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
+  /* flipmode_x_offset = */ 0x018,
+  /* pixel_width = */ 256,
+  /* pixel_height = */ 64
+};
+
+
+static const uint8_t u8x8_d_ssd1322_zjy_256x64_init_seq[] = {
+    
+  U8X8_DLY(1),
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_DLY(1),
+  
+  U8X8_CA(0xfd, 0x12),            	/* unlock */
+  U8X8_C(0xae),		                /* display off */
+  U8X8_CA(0xb3, 0x91),			/* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec)  */  
+  U8X8_CA(0xca, 0x3f),			/* multiplex ratio 1/64 Duty (0x0F~0x3F) */  
+  U8X8_CA(0xa2, 0x00),			/* display offset, shift mapping ram counter */  
+  U8X8_CA(0xa1, 0x00),			/* display start line */  
+  //U8X8_CAA(0xa0, 0x14, 0x11),	/* Set Re-Map / Dual COM Line Mode */  
+  U8X8_CAA(0xa0, 0x16, 0x011),	/* Set Re-Map / Dual COM Line Mode */  
+  U8X8_CA(0xab, 0x01),			/* Enable Internal VDD Regulator */  
+  U8X8_CAA(0xb4, 0xa0, 0x005|0x0fd),	/* Display Enhancement A */  
+  U8X8_CA(0xc1, 0x9f),			/* contrast */  
+  U8X8_CA(0xc7, 0x0f),			/* Set Scale Factor of Segment Output Current Control */  
+  U8X8_C(0xb9),		                /* linear grayscale */
+  U8X8_CA(0xb1, 0xe2),			/* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment */  
+  U8X8_CAA(0xd1, 0x082|0x020, 0x020),	/* Display Enhancement B */  
+  U8X8_CA(0xbb, 0x1f),			/* precharge  voltage */  
+  U8X8_CA(0xb6, 0x08),			/* precharge  period */  
+  U8X8_CA(0xbe, 0x07),			/* vcomh */  
+  U8X8_C(0xa6),		                /* normal display */
+  U8X8_C(0xa9),		                /* exit partial display */
+
+
+  U8X8_DLY(1),					/* delay 2ms */
+
+  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+uint8_t u8x8_d_ssd1322_zjy_256x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1322_zjy_256x64_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_zjy_256x64_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_256x64_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    
+    default:
+      return u8x8_d_ssd1322_common(u8x8, msg, arg_int, arg_ptr);
+  }
+  return 1;
+}
+
+
 /*=========================================================*/
 /*
 https://github.com/olikraus/u8g2/issues/2092
@@ -427,6 +525,127 @@ uint8_t u8x8_d_ssd1322_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void
   return 1;
 }
 
+
+
+/*=========================================================*/
+/*
+
+  Top Win OLED 240x128
+
+  Discussion: https://github.com/olikraus/u8g2/discussions/2308
+  Issue: https://github.com/olikraus/u8g2/issues/2310
+  
+  The main difference to the previous device seems to be the dual com line mode
+  (0x0a0 command)
+
+*/
+
+static const uint8_t u8x8_d_ssd1322_topwin_240x128_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_CAA(0x0a0, 0x036, 0x001),		/* remap */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1322_topwin_240x128_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_CAA(0x0a0, 0x024, 0x001),		/* remap */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+static const u8x8_display_info_t u8x8_ssd1322_topwin_240x128_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* SSD1322: 2 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* SSD1322: 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* SSD1322: 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 10000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215), 10 MHz (issue 301) */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 10,
+  /* write_pulse_width_ns = */ 150,	/* SSD1322: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 30,		/* 240 pixel, so we require 30 bytes for this */
+  /* tile_height = */ 16,
+  /* default_x_offset = */ 24,	/* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
+  /* flipmode_x_offset = */ 0x000,
+  /* pixel_width = */ 240,
+  /* pixel_height = */ 128
+};
+
+
+static const uint8_t u8x8_d_ssd1322_topwin_240x128_init_seq[] = {
+    
+  U8X8_DLY(1),
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_DLY(1),
+  
+  U8X8_CA(0xfd, 0x12),            	/* unlock */
+  U8X8_C(0xae),		                /* display off */
+  U8X8_CA(0xb3, 0x91),			/* set display clock divide ratio/oscillator frequency (set clock as 80 frames/sec)  */  
+  U8X8_CA(0xca, 0x7f),			/* multiplex ratio 1/128 Duty (0x0F~0x7F) */  
+  U8X8_CA(0xa2, 0x00),			/* display offset, shift mapping ram counter */  
+  U8X8_CA(0xa1, 0x00),			/* display start line */  
+  U8X8_CAA(0xa0, 0x36, 0x001),	/* Set Re-Map / Dual COM Line Mode, https://github.com/olikraus/u8g2/discussions/2308 */  
+  U8X8_CA(0xab, 0x01),			/* Enable Internal VDD Regulator */  
+  U8X8_CAA(0xb4, 0xa0, 0x005|0x0fd),	/* Display Enhancement A */  
+  U8X8_CA(0xc1, 0x9f),			/* contrast */  
+  U8X8_CA(0xc7, 0x0f),			/* Set Scale Factor of Segment Output Current Control */  
+  U8X8_C(0xb9),		                /* linear grayscale */
+  U8X8_CA(0xb1, 0xe2),			/* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment */  
+  U8X8_CAA(0xd1, 0x082|0x020, 0x020),	/* Display Enhancement B */  
+  U8X8_CA(0xbb, 0x1f),			/* precharge  voltage */  
+  U8X8_CA(0xb6, 0x08),			/* precharge  period */  
+  U8X8_CA(0xbe, 0x07),			/* vcomh */  
+  U8X8_C(0xa6),		                /* normal display */
+  U8X8_C(0xa9),		                /* exit partial display */
+
+
+  U8X8_DLY(1),					/* delay 2ms */
+
+  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+uint8_t u8x8_d_ssd1322_topwin_240x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1322_topwin_240x128_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_topwin_240x128_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_topwin_240x128_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1322_topwin_240x128_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    
+    default:
+      return u8x8_d_ssd1322_common(u8x8, msg, arg_int, arg_ptr);
+  }
+  return 1;
+}
+
+
 /*=========================================================*/
 /* 
   NHD-2.7-12864WDW3-M 

+ 344 - 0
components/u8g2/u8x8_d_ssd1363.c

@@ -0,0 +1,344 @@
+/*
+
+  u8x8_d_ssd1363.c
+  
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2016, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+
+  SSD1363: 
+    320 x 160 dot matrix
+    16 gray scale
+
+  https://github.com/olikraus/u8g2/issues/2490
+  
+*/
+#include "u8x8.h"
+
+
+
+
+static const uint8_t u8x8_d_ssd1363_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0af),		                /* ssd1363: display on */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1363_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x0ae),		                /* ssd1363: display off */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+
+/* interpret b as a monochrome bit pattern, write value 15 for high bit and value 0 for a low bit */
+/* topbit (msb) is sent last */
+/* example: b = 0x083 will send 0xff, 0x00, 0x00, 0xf0 */
+
+
+
+/*
+  input:
+    one tile (8 Bytes)
+  output:
+    Tile for SSD1363 (32 Bytes)
+*/
+
+static uint8_t u8x8_ssd1363_to32_dest_buf[32];
+
+static uint8_t *u8x8_ssd1363_8to32(U8X8_UNUSED u8x8_t *u8x8, uint8_t *ptr)
+{
+  uint8_t a;
+  uint8_t i;
+  uint8_t *dest;
+
+  dest = u8x8_ssd1363_to32_dest_buf;
+  
+  if ( ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0 && ptr[4] == 0 && ptr[5] == 0 && ptr[6] == 0 && ptr[7] == 0 )
+  {
+    for( i = 0; i < 32; i++ )
+      *dest++ = 0;
+    return u8x8_ssd1363_to32_dest_buf;
+  }
+  
+  a = 1;
+  for( i = 0; i < 8; i++ )
+  {
+    dest[0] = 0;
+    dest[1] = 0;
+    dest[2] = 0;
+    dest[3] = 0;
+    if ( ptr[0] & a )
+      dest[1] |= 0x0f;
+    if ( ptr[1] & a )
+      dest[1] |= 0xf0;
+    if ( ptr[2] & a )
+      dest[0] |= 0x0f;
+    if ( ptr[3] & a )
+      dest[0] |= 0xf0;
+
+    if ( ptr[4] & a )
+      dest[3] |= 0x0f;
+    if ( ptr[5] & a )
+      dest[3] |= 0xf0;
+    if ( ptr[6] & a )
+      dest[2] |= 0x0f;
+    if ( ptr[7] & a )
+      dest[2] |= 0xf0;
+    
+    a <<= 1;
+    dest += 4;
+  }  
+
+    
+  return u8x8_ssd1363_to32_dest_buf;
+}
+
+
+uint8_t u8x8_d_ssd1363_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t x; 
+  uint8_t y, c;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    /* U8X8_MSG_DISPLAY_SETUP_MEMORY is handled by the calling function */
+    /*
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1363_256x128_init_seq);
+      break;
+    */
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1363_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1363_powersave1_seq);
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x0C1 );
+      u8x8_cad_SendArg(u8x8, arg_int );	/* ssd1363 has range from 0 to 255 */
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      u8x8_cad_StartTransfer(u8x8);
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 2;		// only every 4th col can be addressed
+      x += u8x8->x_offset;		
+    
+      y = (((u8x8_tile_t *)arg_ptr)->y_pos);
+      y *= 8;
+    
+      
+      u8x8_cad_SendCmd(u8x8, 0x075 );	/* set row address, moved out of the loop (issue 302) */
+      u8x8_cad_SendArg(u8x8, y);
+      u8x8_cad_SendArg(u8x8, y+7);
+      
+      do
+      {
+	c = ((u8x8_tile_t *)arg_ptr)->cnt;
+	ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+
+	do
+	{
+	  u8x8_cad_SendCmd(u8x8, 0x015 );	/* set column address */
+	  u8x8_cad_SendArg(u8x8, x );	/* start */
+	  u8x8_cad_SendArg(u8x8, x+1 );	/* end */
+
+	  u8x8_cad_SendCmd(u8x8, 0x05c );	/* write to ram */
+	  
+	  u8x8_cad_SendData(u8x8, 32, u8x8_ssd1363_8to32(u8x8, ptr));
+	  
+	  ptr += 8;
+	  x += 2;
+	  c--;
+	} while( c > 0 );
+	
+	//x += 2;
+	arg_int--;
+      } while( arg_int > 0 );
+      
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+/*=========================================================*/
+
+static const uint8_t u8x8_d_ssd1363_256x128_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_CAA(0x0a0, 0x032, 0x000),		/* remap */
+  U8X8_CA(0xa2, 0x20),			/* display offset, shift mapping ram counter */  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_ssd1363_256x128_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_CAA(0x0a0, 0x020, 0x000),		/* remap */
+  U8X8_CA(0xa2, 0x80),			/* display offset, shift mapping ram counter */  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+/*=========================================================*/
+/*
+  https://github.com/olikraus/u8g2/issues/2490
+  ZJY270S0700XG21
+*/
+
+
+static const u8x8_display_info_t u8x8_ssd1363_256x128_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 100, 	/* ssd1363: 2 us */
+  /* post_reset_wait_ms = */ 100, /* far east OLEDs need much longer setup time */
+  /* sda_setup_time_ns = */ 50,		/* 15ns, but cycle time is 100ns, so use 100/2 */
+  /* sck_pulse_width_ns = */ 50,	/* 20ns, but cycle time is 100ns, so use 100/2, AVR: below 70: 8 MHz, >= 70 --> 4MHz clock */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns, increased to 8MHz (issue 215), 10 MHz (issue 301) */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 10,
+  /* write_pulse_width_ns = */ 150,	/* ssd1363: cycle time is 300ns, so use 300/2 = 150 */
+  /* tile_width = */ 32,		/* 256 pixel, so we require 32 bytes for this */
+  /* tile_height = */ 16,
+  /* default_x_offset = */ 8,	/* this is the byte offset (there are two pixel per byte with 4 bit per pixel) */
+  /* flipmode_x_offset = */ 8,
+  /* pixel_width = */ 256,
+  /* pixel_height = */ 128
+};
+
+
+static const uint8_t u8x8_d_ssd1363_256x128_init_seq[] = {
+  
+  U8X8_DLY(1),
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_DLY(1),
+  
+  U8X8_CA(0xfd, 0x12),            	/* unlock */
+  U8X8_C(0xae),		                /* display off */
+  U8X8_CA(0xb3, 0x30),			/* clock divide ratio/oscillator frequency (midas: 0x30 )  */  
+  U8X8_CA(0xca, 127),			/* multiplex ratio  (3..159) */  
+  U8X8_CA(0xa2, 0x20),			/* display offset, shift mapping ram counter */  
+
+  U8X8_CA(0xa1, 0x00),			/* display start line */  
+  
+  //U8X8_CA(0xab, 0x01),			/* Enable Internal VDD Regulator */  
+/*
+	A[0]=0b, Horizontal address increment [reset]    ***
+	A[0]=1b, Vertical address increment
+	
+	A[1]=0b, Disable Column Address Re-map [reset]
+	A[1]=1b, Enable Column Address Re-map		***
+	
+	A[4]=0b, Scan from COM0 to COM[N –1] [reset]	
+	A[4]=1b, Scan from COM[N-1] to COM0, where N is the	***
+	
+	Multiplex ratio
+	A[5]=0b, Disable COM Split Odd Even [reset]	***
+	A[5]=1b, Enable COM Split Odd Even
+	
+	B[4], Enable / disable Dual COM Line mode
+	0b, Disable Dual COM mode [reset]
+	1b, Enable Dual COM mode (MUX ≤ 79)
+	
+	0x16 = 00010110
+*/
+  U8X8_CAA(0xa0, 0x32, 0x000),	/* Set Re-Map / Dual COM Line Mode (midas datasheet) */  
+  U8X8_CAA(0xb4, 0x32, 0x00c),	/* Display Enhancement A (midas datasheet) NOT DOCUMENTED */  
+  //U8X8_CA(0xc7, 0x0f),			/* Set Scale Factor of Segment Output Current Control */  
+  U8X8_CA(0xc1, 0xff),			/* contrast */  
+  U8X8_CA(0xba, 0x03),			/* voltage config: Vp pin is connected to cap */    
+  U8X8_C(0xb9),		                /* linear grayscale */
+  U8X8_CA(0xad, 0x90),			/* internal IREF: 0x90, external IREF: 0x80 */    
+
+  U8X8_CA(0xb1, 0x74),			/* Phase 1 (Reset) & Phase 2 (Pre-Charge) Period Adjustment (midas) */  
+  U8X8_CA(0xbb, 0x0c),			/* precharge  voltage */    
+  
+  U8X8_CA(0xb6, 0xc8),			/* second pre charge (midas) */  
+  U8X8_CA(0xbe, 0x04),			/* vcomh (midas) */  
+  
+  U8X8_C(0xa6),		                /* normal display */
+  U8X8_C(0xa9),		                /* exit partial display */
+
+
+  U8X8_DLY(1),					/* delay 2ms */
+
+  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+uint8_t u8x8_d_ssd1363_256x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_ssd1363_256x128_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1363_256x128_init_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1363_256x128_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_ssd1363_256x128_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+    
+    default:
+      return u8x8_d_ssd1363_common(u8x8, msg, arg_int, arg_ptr);
+  }
+  return 1;
+}
+
+

+ 501 - 0
components/u8g2/u8x8_d_st7302.c

@@ -0,0 +1,501 @@
+/*
+
+  u8x8_d_st7302.c
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2024, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+
+  st7302: 
+    Ultra-Low Power Active Matrix 240 x 320
+    Mono TFT Display Driver with Controller
+  
+  https://github.com/olikraus/u8g2/issues/2436
+  
+    No Hardware Flip
+    No U8x8 Support
+
+*/
+
+
+#include "u8x8.h"
+#include <string.h>
+
+static const uint8_t u8x8_d_st7302_122x250_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x29), 				// display on
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7302_122x250_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x028),		                /* display off */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7302_122x250_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  //U8X8_CA(0x36, 0x60), 			// Memory Control 
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7302_122x250_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  //U8X8_CA(0x36, 0xa0), 			// Memory Control 
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+
+
+/*===================================================*/
+/* see also: http://www.technoblogy.com/show?3YB0 */
+
+
+#ifdef NOT_USED
+static uint8_t *u8x8_st7302_convert_60(u8x8_t *u8x8, uint8_t *p)   
+{
+  static uint8_t buf[6];
+  uint8_t bytes_per_row = u8x8->display_info->tile_width;
+  
+  
+  memset(buf, 0, 6);
+  
+  //   U8X8_CA(0x36, 0x60), 			// Memory Control 
+
+
+  // first row, left 12 pixel
+  
+  if ( p[0] & 0x80 )
+    buf[2] |= 0x02;
+  if ( p[0] & 0x40 )
+    buf[2] |= 0x08;
+  if ( p[0] & 0x20 )
+    buf[2] |= 0x20;
+  if ( p[0] & 0x10 )
+    buf[2] |= 0x80;
+
+  if ( p[0] & 0x08 )
+    buf[1] |= 0x02;
+  if ( p[0] & 0x04 )
+    buf[1] |= 0x08;
+  if ( p[0] & 0x02 )
+    buf[1] |= 0x20;
+  if ( p[0] & 0x01 )
+    buf[1] |= 0x80;
+
+  if ( p[1] & 0x80 )
+    buf[0] |= 0x02;
+  if ( p[1] & 0x40 )
+    buf[0] |= 0x08;
+  if ( p[1] & 0x20 )
+    buf[0] |= 0x20;
+  if ( p[1] & 0x10 )
+    buf[0] |= 0x80;
+
+ // first row, right 12 pixel
+   
+  if ( p[1] & 0x08 )
+    buf[5] |= 0x02;
+  if ( p[1] & 0x04 )
+    buf[5] |= 0x08;
+  if ( p[1] & 0x02 )
+    buf[5] |= 0x20;
+  if ( p[1] & 0x01 )
+    buf[5] |= 0x80;
+
+  if ( p[2] & 0x80 )
+    buf[4] |= 0x02;
+  if ( p[2] & 0x40 )
+    buf[4] |= 0x08;
+  if ( p[2] & 0x20 )
+    buf[4] |= 0x20;
+  if ( p[2] & 0x10 )
+    buf[4] |= 0x80;
+  
+  if ( p[2] & 0x08 )
+    buf[3] |= 0x02;
+  if ( p[2] & 0x04 )
+    buf[3] |= 0x08;
+  if ( p[2] & 0x02 )
+    buf[3] |= 0x20;
+  if ( p[2] & 0x01 )
+    buf[3] |= 0x80;
+  
+  p += u8x8->display_info->tile_width;
+
+  // second row, left 12 pixel
+  
+  if ( p[0] & 0x80 )
+    buf[2] |= 0x01;
+  if ( p[0] & 0x40 )
+    buf[2] |= 0x04;
+  if ( p[0] & 0x20 )
+    buf[2] |= 0x10;
+  if ( p[0] & 0x10 )
+    buf[2] |= 0x40;
+
+  if ( p[0] & 0x08 )
+    buf[1] |= 0x01;
+  if ( p[0] & 0x04 )
+    buf[1] |= 0x04;
+  if ( p[0] & 0x02 )
+    buf[1] |= 0x10;
+  if ( p[0] & 0x01 )
+    buf[1] |= 0x40;
+
+  if ( p[1] & 0x80 )
+    buf[0] |= 0x01;
+  if ( p[1] & 0x40 )
+    buf[0] |= 0x04;
+  if ( p[1] & 0x20 )
+    buf[0] |= 0x10;
+  if ( p[1] & 0x10 )
+    buf[0] |= 0x40;
+
+ // second row, right 12 pixel
+   
+  if ( p[1] & 0x08 )
+    buf[5] |= 0x01;
+  if ( p[1] & 0x04 )
+    buf[5] |= 0x04;
+  if ( p[1] & 0x02 )
+    buf[5] |= 0x10;
+  if ( p[1] & 0x01 )
+    buf[5] |= 0x40;
+
+  if ( p[2] & 0x80 )
+    buf[4] |= 0x01;
+  if ( p[2] & 0x40 )
+    buf[4] |= 0x04;
+  if ( p[2] & 0x20 )
+    buf[4] |= 0x10;
+  if ( p[2] & 0x10 )
+    buf[4] |= 0x40;
+  
+  if ( p[2] & 0x08 )
+    buf[3] |= 0x01;
+  if ( p[2] & 0x04 )
+    buf[3] |= 0x04;
+  if ( p[2] & 0x02 )
+    buf[3] |= 0x10;
+  if ( p[2] & 0x01 )
+    buf[3] |= 0x40;
+  
+  return buf;
+}
+#endif
+
+static uint8_t *u8x8_st7302_convert_a0(u8x8_t *u8x8, uint8_t *p)   
+{
+  static uint8_t buf[6];
+  static uint8_t map1[16] = {
+      /* 0x00 0000 */ 0,
+      /* 0x01 0001 */0x01,
+      /* 0x02 0010 */0x04,
+      /* 0x03 0011 */0x04+0x01,
+      /* 0x04 0100 */0x10,
+      /* 0x05 0101 */0x10+0x01,
+      /* 0x06 0110 */0x10+0x04,
+      /* 0x07 0111 */0x10+0x04+0x01,
+      /* 0x08 1000 */ 0x40,
+      /* 0x09 1001 */ 0x40+0x01,
+      /* 0x0a 1010 */ 0x40+0x04,
+      /* 0x0b 1011 */ 0x40+0x04+0x01,
+      /* 0x0c 1100 */ 0x40+0x10,
+      /* 0x0d 1101 */ 0x40+0x10+0x01,
+      /* 0x0e 1110 */ 0x40+0x10+0x04,
+      /* 0x0f 1111 */  0x40+0x10+0x04+0x01
+  };
+  static uint8_t map2[16] = {
+      /* 0x00 0000 */ 0,
+      /* 0x01 0001 */0x02,
+      /* 0x02 0010 */0x08,
+      /* 0x03 0011 */0x08+0x02,
+      /* 0x04 0100 */0x20,
+      /* 0x05 0101 */0x20+0x02,
+      /* 0x06 0110 */0x20+0x08,
+      /* 0x07 0111 */0x20+0x08+0x02,
+      /* 0x08 1000 */ 0x80,
+      /* 0x09 1001 */ 0x80+0x02,
+      /* 0x0a 1010 */ 0x80+0x08,
+      /* 0x0b 1011 */ 0x80+0x08+0x02,
+      /* 0x0c 1100 */ 0x80+0x20,
+      /* 0x0d 1101 */ 0x80+0x20+0x02,
+      /* 0x0e 1110 */ 0x80+0x20+0x08,
+      /* 0x0f 1111 */  0x80+0x20+0x08+0x02
+  };
+  
+  
+  memset(buf, 0, 6);
+  
+  //   U8X8_CA(0x36, 0x0), 			// Memory Control 
+
+
+  // first row, left 12 pixel
+
+  buf[0] |= map1[p[0]>>4];
+  buf[1] |= map1[p[0] & 0x0f];
+  buf[2] |= map1[p[1]>>4];
+
+ // first row, right 12 pixel
+   
+  buf[3] |= map1[p[1] & 0x0f];
+  buf[4] |= map1[p[2]>>4];
+  buf[5] |= map1[p[2] & 0x0f];
+  
+  p += u8x8->display_info->tile_width;
+
+  // second row, left 12 pixel
+
+  buf[0] |= map2[p[0]>>4];
+  buf[1] |= map2[p[0] & 0x0f];
+  buf[2] |= map2[p[1]>>4];
+  
+ // second row, right 12 pixel
+
+  buf[3] |= map2[p[1] & 0x0f];
+  buf[4] |= map2[p[2]>>4];
+  buf[5] |= map2[p[2] & 0x0f];
+  return buf;
+}
+
+
+
+
+/*===================================================*/
+/* 
+  see also:
+  https://github.com/zhcong/ST7302-for-arduino/blob/c9390fabcacefe7c36a113cd3e62959418c13b97/libraries/ST7302SPI/ST7302SPI.cpp#L21
+*/
+static const uint8_t u8x8_d_st7302_122x250_init_seq[] = {
+    
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  
+  U8X8_C(0x01),                                 // software reset
+  U8X8_DLY(100),
+  U8X8_C(0x28), 				// display off
+  U8X8_CAA(0xC7, 0x26, 0xE9), 			// disable OSC
+  U8X8_CA(0xD1, 0x00), 			// Booster disable
+  U8X8_DLY(20),
+  U8X8_C(0x10),                                 // sleep in: enter sleep mode
+  U8X8_DLY(20),
+  U8X8_C(0x01),                                 // software reset
+  U8X8_DLY(20),                                 // wait
+  U8X8_C(0x38), 				// High Power Mode
+  U8X8_CA(0xEB, 0x02), 			// Disable NVM Load
+  U8X8_CA(0xD7, 0x68), 			// NVM Load Control: Enable ID1 ID2 ID3 Load
+  U8X8_CA(0xD1, 0x01), 			// Booster Enable
+  U8X8_CA(0xC0, 0x80), 			// Gate Voltage Setting VGH=12V (upper 4 bit, 8V-15V); VGL=-5V (lower 4 bit, -5V .. -10V)
+  U8X8_C(0x0C1),                                // Source Voltage Control 1
+  U8X8_A6(0x28,0x28,0x28,0x28,0x14,0x00),       // Source high voltage in reflective and transmissive mode, gamma voltage 1&2 
+  U8X8_C(0x0C2),                                // Source Voltage Control 1
+  U8X8_A4(0x00,0x00,0x00,0x00),       // Source low voltage in reflective and transmissive mode 
+  U8X8_CA(0xCB, 0x14), 			// VCOMH: 0x14 = 4V (0x28 = 5V)
+  U8X8_CAA(0xB4, 0xE5, 0x77), 			// Update Period Gate EQ Control, why 0x77??? it should be 0x66 according to the datasheet
+  U8X8_A8(0xF1, 0xFF, 0xFF, 0x4F, 0xF1, 0xFF, 0xFF, 0X4F),
+  U8X8_CA(0xB0, 0x64), 			// Duty Cycle... this must be before sleep out
+  U8X8_C(0x11),                                 // sleep out: furn off sleep mode
+  U8X8_DLY(120),
+  U8X8_CAA(0xC7, 0xA6, 0xE9), 			// Enable OSC
+  U8X8_CA(0x36, 0xa0), 			// Memory Control 
+  
+  U8X8_CA(0x3A, 0x11), 			// Data Format 
+  U8X8_CA(0xB9, 0x23), 			// Source Setting: Clear RAM off 
+  U8X8_CA(0xB8, 0x09), 			// Panel Setting / Panel Layout 
+  U8X8_CAA(0x2A, 0x05, 0x36), 			// col addr
+  U8X8_CAA(0x2B, 0x00, 0xC7), 			// row addr
+  U8X8_CA(0xD0, 0x1F), 			// Not in datasheet
+  U8X8_C(0x29), 				// display on
+  U8X8_CA(0x72, 0x00), 			// Not in datasheet
+  U8X8_CAA(0xB2,1, 5),                  // Frame Rate for High and Low Power Mode (hier: 32Hz and 8Hz) 
+  U8X8_C(0x39), 				// enable Low Power Mode...: 8Hz, see above
+  U8X8_DLY(100),
+
+  /*
+  U8X8_CAA(0x2A, 0x19, 0x3a), 			// col addr  0x14 < col < 0x3b
+  U8X8_CAA(0x2B, 115, 115), 			// row addr (0..250, y in u8g2), 0 is top row in u8g2
+  U8X8_C(0x2C), 			// write start
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+  
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+  
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+  U8X8_D1(0xff), 			// pixel data
+
+  U8X8_CAA(0x2A, 0x19, 0x3a), 			// col addr  0x14 < col < 0x3b
+  U8X8_CAA(0x2B, 116, 116), 			// row addr (0..250, y in u8g2), 0 is top row in u8g2
+  U8X8_C(0x2C), 			// write start
+  U8X8_D1(0x80), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+  
+  U8X8_D1(0x00), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+
+  U8X8_D1(0x00), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+  
+  U8X8_D1(0x00), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+  U8X8_D1(0x00), 			// pixel data
+  */
+
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()           			/* end of sequence */
+};
+
+
+
+
+static const u8x8_display_info_t u8x8_st7302_122x250_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 20,
+  /* reset_pulse_width_ms = */ 3, 	
+  /* post_reset_wait_ms = */ 3, 		/**/
+  /* sda_setup_time_ns = */ 10,		/* */
+  /* sck_pulse_width_ns = */ 30,	/*  */
+  /* sck_clock_hz = */ 2000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 15,
+  /* write_pulse_width_ns = */ 70,	
+  /* tile_width = */ 16,
+  /* tile_height = */ 32,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 122,
+  /* pixel_height = */ 250
+};
+
+uint8_t u8x8_d_st7302_122x250(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint16_t x;
+  uint8_t c, i, y;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7302_122x250_init_seq);    
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7302_122x250_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7302_122x250_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7302_122x250_powersave1_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7302_122x250_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7302_122x250_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x081 );
+      u8x8_cad_SendArg(u8x8, arg_int<<2 );	
+      u8x8_cad_SendArg(u8x8, arg_int>>6 );	
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+      x += u8x8->x_offset;
+      y= (((u8x8_tile_t *)arg_ptr)->y_pos);
+      y*=4;
+    
+      y+=115;           // specific for the 122x250 LCD
+
+      u8x8_cad_StartTransfer(u8x8);
+
+      for( i = 0; i < 4; i++ )
+      {
+        
+        u8x8_cad_SendCmd(u8x8, 0x2a);
+        u8x8_cad_SendArg(u8x8, 0x19);   // specific for the 122x250 LCD
+        u8x8_cad_SendArg(u8x8, 0x3a );
+      
+        u8x8_cad_SendCmd(u8x8, 0x2b ); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendCmd(u8x8, 0x02c );		// write data 
+      
+        c = ((u8x8_tile_t *)arg_ptr)->cnt;
+        ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+        
+        ptr += u8x8->display_info->tile_width*i*2;
+        
+        c = (c+2)/3;          // calculate the number of 24 bit blocks to send
+        
+        
+        while( c > 0 )
+        {
+          u8x8_cad_SendData(u8x8, 6, u8x8_st7302_convert_a0(u8x8, ptr)); 	
+          ptr+=3;
+          --c;
+        }
+      }
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}

+ 694 - 0
components/u8g2/u8x8_d_st7305.c

@@ -0,0 +1,694 @@
+/*
+
+  u8x8_d_st7305.c
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2025, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+
+  st7305: 240 x 320             122x250
+  st7305: 264 x 320             168x384, 200x200
+    Mono TFT Display Driver with Controller
+    
+  st7305 seems to be almost compatible to the st7303, however they have a different memory architecture
+  
+  https://github.com/olikraus/u8g2/issues/2436
+  
+    No Hardware Flip
+    No U8x8 Support
+
+*/
+
+
+#include "u8x8.h"
+#include <string.h>
+
+static const uint8_t u8x8_d_st7305_122x250_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x29), 				// display on
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7305_122x250_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x028),		                /* display off */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7305_122x250_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  //U8X8_CA(0x36, 0x60), 			// Memory Control 
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7305_122x250_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  //U8X8_CA(0x36, 0xa0), 			// Memory Control 
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+
+
+/*===================================================*/
+/* see also: http://www.technoblogy.com/show?3YB0 */
+
+
+static uint8_t *u8x8_st7305_convert_a0(u8x8_t *u8x8, uint8_t *p)   
+{
+  static uint8_t buf[6];
+  
+#ifdef NOT_WORKING
+  /* u8g2 first row */
+  static uint8_t map1[16] = {
+      /* 0x00 0000 */ 0,
+      /* 0x01 0001 */0x04,
+      /* 0x02 0010 */0x01,
+      /* 0x03 0011 */0x04+0x01,
+      /* 0x04 0100 */0x40,
+      /* 0x05 0101 */0x40+0x04,
+      /* 0x06 0110 */0x40+0x01,
+      /* 0x07 0111 */0x40+0x04+0x01,
+      /* 0x08 1000 */ 0x10,
+      /* 0x09 1001 */ 0x10+0x04,
+      /* 0x0a 1010 */ 0x10+0x01,
+      /* 0x0b 1011 */ 0x10+0x04+0x01,
+      /* 0x0c 1100 */ 0x40+0x10,
+      /* 0x0d 1101 */ 0x40+0x10+0x04,
+      /* 0x0e 1110 */ 0x40+0x10+0x01,
+      /* 0x0f 1111 */  0x40+0x10+0x04+0x01
+  };
+  /* u8g2 second row */
+  static uint8_t map2[16] = {
+      /* 0x00 0000 */ 0,
+      /* 0x01 0001 */0x08,
+      /* 0x02 0010 */0x02,
+      /* 0x03 0011 */0x08+0x02,
+      /* 0x04 0100 */0x80,
+      /* 0x05 0101 */0x80+0x08,
+      /* 0x06 0110 */0x80+0x02,
+      /* 0x07 0111 */0x80+0x08+0x02,
+      /* 0x08 1000 */ 0x20,
+      /* 0x09 1001 */ 0x20+0x08,
+      /* 0x0a 1010 */ 0x20+0x02,
+      /* 0x0b 1011 */ 0x20+0x08+0x02,
+      /* 0x0c 1100 */ 0x80+0x20,
+      /* 0x0d 1101 */ 0x80+0x20+0x08,
+      /* 0x0e 1110 */ 0x80+0x20+0x02,
+      /* 0x0f 1111 */  0x80+0x20+0x08+0x02
+  };
+  #endif
+
+ /* contributed by https://github.com/ischenz */
+ /* u8g2 first row */ 
+  static uint8_t map1[16] = { 
+      0x00, 0x02, 0x08, 0x0A, 
+      0x20, 0x22, 0x28, 0x2A, 
+      0x80, 0x82, 0x88, 0x8A, 
+      0xA0, 0xA2, 0xA8, 0xAA }; 
+ /* u8g2 second row */ 
+  static uint8_t map2[16] = { 
+    0x00, 0x01, 0x04, 0x05, 
+    0x10, 0x11, 0x14, 0x15, 
+    0x40, 0x41, 0x44, 0x45, 
+    0x50, 0x51, 0x54, 0x55 };  
+  
+  memset(buf, 0, 6);
+  
+
+  // first row, left 12 pixel out of 24 pixel (=3 bytes)
+
+  buf[0] |= map1[p[0]>>4];
+  buf[1] |= map1[p[0] & 0x0f];
+  buf[2] |= map1[p[1]>>4];
+
+ // first row, right 12 pixel
+   
+  buf[3] |= map1[p[1] & 0x0f];
+  buf[4] |= map1[p[2]>>4];
+  buf[5] |= map1[p[2] & 0x0f];
+  
+  p += u8x8->display_info->tile_width;
+
+  // second row, left 12 pixel
+
+  buf[0] |= map2[p[0]>>4];
+  buf[1] |= map2[p[0] & 0x0f];
+  buf[2] |= map2[p[1]>>4];
+  
+ // second row, right 12 pixel
+
+  buf[3] |= map2[p[1] & 0x0f];
+  buf[4] |= map2[p[2]>>4];
+  buf[5] |= map2[p[2] & 0x0f];
+  return buf;
+}
+
+
+
+
+/*===================================================*/
+/* 
+  see also:
+  https://github.com/zhcong/st7302-for-arduino/blob/c9390fabcacefe7c36a113cd3e62959418c13b97/libraries/st7305SPI/st7305SPI.cpp#L21
+*/
+static const uint8_t u8x8_d_st7305_122x250_init_seq[] = {
+    
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  
+  U8X8_C(0x01),                                 // software resets
+  U8X8_DLY(100),
+  U8X8_C(0x28), 				// display off
+  U8X8_CAA(0xC7, 0x26, 0xE9), 			// disable OSC
+  U8X8_CA(0xD1, 0x00), 			// Booster disable
+  U8X8_DLY(20),
+  U8X8_C(0x10),                                 // sleep in: enter sleep mode
+  U8X8_DLY(20),
+  U8X8_C(0x01),                                 // software reset
+  U8X8_DLY(20),                                 // wait
+  //U8X8_C(0x38), 				// High Power Mode
+  //U8X8_CA(0xEB, 0x02), 			// Disable NVM Load
+  //U8X8_CA(0xD7, 0x68), 			// NVM Load Control: Enable ID1 ID2 ID3 Load
+  //U8X8_CA(0xD1, 0x01), 			// Booster Enable
+  //U8X8_CA(0xC0, 0x80), 			// Gate Voltage Setting VGH=12V (upper 4 bit, 8V-15V); VGL=-5V (lower 4 bit, -5V .. -10V)
+  U8X8_CAA(0xD6, 0x17, 0x02),
+  U8X8_CA(0xD1, 0x01), 
+  U8X8_CAA(0xC0, 0x12, 0x0a),//chen.x
+  U8X8_C(0x0C1),                                // Source Voltage Control 1
+  U8X8_A4(115,0x3E,0x3C,0x3C), 
+  U8X8_C(0x0C2),                                // Source Voltage Control 1
+  U8X8_A4(0,0x21,0x23,0x23),       // Source low voltage in reflective and transmissive mode 
+  U8X8_C(0x0C4),    //ischen.x
+  U8X8_A4(50,0x5C,0x5A,0x5A), 
+  U8X8_C(0x0C5),    //ischen.x
+  U8X8_A4(50,0x35,0x37,0x37),
+  U8X8_CAA(0xD8, 0x80, 0xE9),
+  
+  //U8X8_CA(0xCB, 0x14), 			// VCOMH: 0x14 = 4V (0x28 = 5V)
+  U8X8_CA(0xB2, 0x12),
+  U8X8_CAA(0xB3, 0xE5, 0xF6), 			// Update Period Gate EQ Control, why 0x77??? it should be 0x66 according to the datasheet
+  U8X8_A8(0x17, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x71),
+  U8X8_CAA(0xB4, 0x05, 0x46), 			// Update Period Gate EQ Control, why 0x77??? it should be 0x66 according to the datasheet
+  U8X8_A6(0x77, 0x77, 0x77, 0x77, 0x76, 0x45),
+  U8X8_CAAA(0x62, 0x32, 0x03, 0x1f),                                
+  U8X8_CA(0xB7, 0x13),
+  U8X8_CA(0xB0, 0x32), 			// Duty Cycle... this must be before sleep out, 200x200 display: 0x64 --> 0x32
+  
+  U8X8_C(0x11),                                 // sleep out: furn off sleep mode
+  U8X8_DLY(120),
+  U8X8_CA(0xC9, 0x00),
+  U8X8_CA(0x36, 0xa4), 			// Memory Control, 0xa4 for the 200x200 display
+  
+  U8X8_CA(0x3A, 0x11), 			// Data Format 
+  U8X8_CA(0xB9, 0x20), 			// Source Setting: Clear RAM off *******<-----
+  U8X8_CA(0xB8, 0x29), 			// Panel Setting / Panel Layout 
+  U8X8_CAA(0x2A, 0x16, 0x27), 			// col addr
+  U8X8_CAA(0x2B, 0x00, 0x63), 			// row addr
+  U8X8_CA(0x35, 0x00),
+  U8X8_CA(0xD0, 0xFF), 			// Not in datasheet
+  //U8X8_CA(0x72, 0x00), 			// Not in datasheet
+  //U8X8_CAA(0xB2,1, 5),                  // Frame Rate for High and Low Power Mode (hier: 32Hz and 8Hz) 
+  U8X8_C(0x38), 				// enable Low Power Mode...: 8Hz, see above
+  U8X8_C(0x29), 				// display on
+  U8X8_C(0x20),
+  U8X8_CA(0xBB, 0x4F),
+  U8X8_DLY(100),
+ 
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()           			/* end of sequence */
+};
+
+
+
+static const u8x8_display_info_t u8x8_st7305_122x250_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 20,
+  /* reset_pulse_width_ms = */ 3, 	
+  /* post_reset_wait_ms = */ 3, 		/**/
+  /* sda_setup_time_ns = */ 10,		/* */
+  /* sck_pulse_width_ns = */ 30,	/*  */
+  /* sck_clock_hz = */ 2000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 15,
+  /* write_pulse_width_ns = */ 70,	
+  /* tile_width = */ 16,
+  /* tile_height = */ 32,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 122,
+  /* pixel_height = */ 250
+};
+
+uint8_t u8x8_d_st7305_122x250(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint16_t x;
+  uint8_t c, i, y;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_init_seq);    
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7305_122x250_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_powersave1_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x081 );
+      u8x8_cad_SendArg(u8x8, arg_int<<2 );	
+      u8x8_cad_SendArg(u8x8, arg_int>>6 );	
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+      x += u8x8->x_offset;
+      y= (((u8x8_tile_t *)arg_ptr)->y_pos);
+      y*=4;
+    
+      y+=115;           // specific for the 122x250 LCD
+
+      u8x8_cad_StartTransfer(u8x8);
+
+      for( i = 0; i < 4; i++ )
+      {
+        
+        u8x8_cad_SendCmd(u8x8, 0x2a);
+        u8x8_cad_SendArg(u8x8, 0x19);   // specific for the 122x250 LCD
+        u8x8_cad_SendArg(u8x8, 0x3a );
+      
+        u8x8_cad_SendCmd(u8x8, 0x2b ); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendCmd(u8x8, 0x02c );		// write data 
+      
+        c = ((u8x8_tile_t *)arg_ptr)->cnt;
+        ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+        
+        ptr += u8x8->display_info->tile_width*i*2;
+        
+        c = (c+2)/3;          // calculate the number of 24 bit blocks to send
+        
+        
+        while( c > 0 )
+        {
+          u8x8_cad_SendData(u8x8, 6, u8x8_st7305_convert_a0(u8x8, ptr)); 	
+          ptr+=3;
+          --c;
+        }
+      }
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+
+/*=====================================================================*/
+/* 200x200, https://admin.osptek.com/uploads/YDP_154_H008_V3_c24b455ff9.pdf */
+
+
+static const u8x8_display_info_t u8x8_st7305_200x200_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 20,
+  /* reset_pulse_width_ms = */ 3, 	
+  /* post_reset_wait_ms = */ 3, 		/**/
+  /* sda_setup_time_ns = */ 10,		/* */
+  /* sck_pulse_width_ns = */ 30,	/*  */
+  /* sck_clock_hz = */ 2000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 15,
+  /* write_pulse_width_ns = */ 70,	
+  /* tile_width = */ 26,   /* tile width is 26*8=208, because this display requires 12 bit blocks, which would be 204 pixel, so next tile is at 208 */
+  /* tile_height = */ 25,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 200,              /* not 100% sure, whether this works with the tile_width of 26... */
+  /* pixel_height = */ 200
+};
+
+uint8_t u8x8_d_st7305_200x200(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint16_t x;
+  uint8_t c, i, y;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_init_seq);    
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7305_200x200_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_powersave1_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x081 );
+      u8x8_cad_SendArg(u8x8, arg_int<<2 );	
+      u8x8_cad_SendArg(u8x8, arg_int>>6 );	
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+      x += u8x8->x_offset;
+      y= (((u8x8_tile_t *)arg_ptr)->y_pos);
+      y*=4;
+    
+      y+=0;           // 200x200 display
+
+      u8x8_cad_StartTransfer(u8x8);
+
+      for( i = 0; i < 4; i++ )
+      {
+        
+        u8x8_cad_SendCmd(u8x8, 0x2a);   // column address set
+        u8x8_cad_SendArg(u8x8, 0x16);   // 0x019 for the 122x250 LCD --> 0x016 for the 200x200 display
+        u8x8_cad_SendArg(u8x8, 0x27 );  // 204 pixel for the 200x200 display
+      
+        u8x8_cad_SendCmd(u8x8, 0x2b ); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendCmd(u8x8, 0x02c );		// write data 
+      
+        c = ((u8x8_tile_t *)arg_ptr)->cnt;
+        ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+        
+        ptr += u8x8->display_info->tile_width*i*2;
+        
+        c = (c+2)/3;          // calculate the number of 24 bit blocks to send
+        
+        
+        while( c > 0 )
+        {
+          u8x8_cad_SendData(u8x8, 6, u8x8_st7305_convert_a0(u8x8, ptr)); 	
+          ptr+=3;
+          --c;
+        }
+      }
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+
+/*=====================================================================*/
+/* 168x384, https://github.com/olikraus/u8g2/issues/2661 */
+
+
+#ifdef NOT_USED
+static const uint8_t u8x8_d_st7305_168x384_powersave0_seq[] = {
+    U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
+    U8X8_C(0x29),          // display on
+    U8X8_END_TRANSFER(),   /* disable chip */
+    U8X8_END()             /* end of sequence */
+};
+
+
+static const uint8_t u8x8_d_st7305_168x384_powersave1_seq[] = {
+    U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
+    U8X8_C(0x028),         /* display off */
+    U8X8_END_TRANSFER(),   /* disable chip */
+    U8X8_END()             /* end of sequence */
+};
+
+
+static const uint8_t u8x8_d_st7305_168x384_flip0_seq[] = {
+    U8X8_START_TRANSFER(), /* enable chip, delay is part of the transfer start */
+    // U8X8_CA(0x36, 0x60), 			// Memory Control
+    U8X8_END_TRANSFER(), /* disable chip */
+    U8X8_END()           /* end of sequence */
+};
+#endif
+
+
+static const uint8_t u8x8_d_st7305_168x384_init_seq[] = {
+    U8X8_START_TRANSFER(),
+
+
+    /* Software Reset */
+    U8X8_C(0x01),
+    U8X8_DLY(100),
+
+
+    /* Settings */
+    // 以下在芯片手册基础上,按照显示屏厂家给的示例代码调整
+    U8X8_CAA(0xD6, 0x13, 0x02), // NVM Load Control
+    U8X8_CA(0xD1, 0x01),        // Booster Enable
+    U8X8_CAA(0xC0, 0x12, 0x0A), // Gate Voltage Setting: VGH=15V, VGL=-10V
+
+
+    U8X8_CAAAA(0xC1, 0x3C, 0x3E, 0x3C, 0x3C), // VSHP Setting: VSHP1~4 = 4.8V
+    U8X8_CAAAA(0xC2, 0x23, 0x21, 0x23, 0x23), // VSLP Setting: VSHP1~4 = 0.98V
+    U8X8_CAAAA(0xC4, 0x5A, 0x5C, 0x5A, 0x5A), // VSHN Setting: VSHP1~4 = -3.6V
+    U8X8_CAAAA(0xC5, 0x37, 0x35, 0x37, 0x37), // VSLN Setting: VSHP1~4 = 0.22V
+
+
+    U8X8_CAA(0xD8, 0xA6, 0xE9), // OSC Setting
+    U8X8_CA(0xB2, 0x12),        // Frame Rate Control: HPM=32Hz, LPM=1Hz
+
+
+    U8X8_CAAAA(0xB3, 0xE5, 0xF6, 0x17, 0x77), // Update Period Gate EQ Control in HPM
+    U8X8_A6(0x77, 0x77, 0x77, 0x77, 0x77, 0x71),
+
+
+    U8X8_CAA(0xB4, 0x05, 0x46), // Update Period Gate EQ Control in LPM
+    U8X8_A6(0x77, 0x77, 0x77, 0x77, 0x76, 0x45),
+
+
+    U8X8_CAAA(0x62, 0x32, 0x03, 0x1F), // Gate Timing Control
+    U8X8_CA(0xB7, 0x13),               // Source EQ Enable
+    U8X8_CA(0xB0, 0x60),               // Gate Line Setting: 384 line
+
+
+    U8X8_C(0x11), // Sleep Out
+    U8X8_DLY(10),
+
+
+    U8X8_CA(0xC9, 0x00), // Source Voltage Select: VSHP1; VSLP1 ; VSHN1 ; VSLN1
+    U8X8_CA(0x36, 0x48), // Memory Data Access Control
+    U8X8_CA(0x3A, 0x11), // Data Format Select
+    U8X8_CA(0xB9, 0x20), // Gamma Mode Setting: Mono 00:4GS
+    U8X8_CA(0xB8, 0x29), // Panel Setting, 1-Dot inversion, Frame inversion, One Line Interlace
+
+
+    U8X8_CAA(0x2A, 0x17, 0x24), // Column Address Setting: 0X24-0X16=14, 14*12=168
+    U8X8_CAA(0x2B, 0x00, 0xBF), // Row Address Setting: 192*2=384
+    U8X8_CA(0x35, 0x00),        // TE Setting
+    U8X8_CA(0xD0, 0xFF),        // Enable Auto Power down
+    U8X8_C(0x38),               // High Power Mode ON
+    // U8X8_C(0x39),               // Low Power Mode ON
+
+
+    /* Display ON */
+    U8X8_C(0x29),        // Display ON
+    U8X8_C(0x20),        // Display Inversion Off
+    U8X8_CA(0xBB, 0x4F), // Enable Clear RAM to 0
+
+
+    U8X8_END_TRANSFER(),
+    U8X8_END()
+
+
+};
+
+
+static const u8x8_display_info_t u8x8_st7305_168x384_display_info =
+    {
+        /* chip_enable_level = */ 0,
+        /* chip_disable_level = */ 1,
+
+
+        /* post_chip_enable_wait_ns = */ 20,
+        /* pre_chip_disable_wait_ns = */ 20,
+        /* reset_pulse_width_ms = */ 3,
+        /* post_reset_wait_ms = */ 3,   /**/
+        /* sda_setup_time_ns = */ 10,   /* */
+        /* sck_pulse_width_ns = */ 30,  /*  */
+        /* sck_clock_hz = */ 2000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+        /* spi_mode = */ 0,             /* active high, rising edge */
+        /* i2c_bus_clock_100kHz = */ 4, /* 400KHz */
+        /* data_setup_time_ns = */ 15,
+        /* write_pulse_width_ns = */ 70,
+        /* tile_width = */ 21, /* tile width is 21*8=168, because this display requires 12 bit blocks, which would be 168 pixel, so next tile is at 168 */
+        /* tile_height = */ 48,
+        /* default_x_offset = */ 0,
+        /* flipmode_x_offset = */ 0,
+        /* pixel_width = */ 168, /* not 100% sure, whether this works with the tile_width of 21... */
+        /* pixel_height = */ 384};
+
+
+uint8_t u8x8_d_st7305_168x384(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint16_t x;
+  uint8_t c, i, y;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_168x384_init_seq);    
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7305_168x384_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_powersave0_seq);
+      else
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_powersave1_seq);
+      break;
+    case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+      if ( arg_int == 0 )
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_flip0_seq);
+	u8x8->x_offset = u8x8->display_info->default_x_offset;
+      }
+      else
+      {
+	u8x8_cad_SendSequence(u8x8, u8x8_d_st7305_122x250_flip1_seq);
+	u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+      }
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+      u8x8_cad_StartTransfer(u8x8);
+      u8x8_cad_SendCmd(u8x8, 0x081 );
+      u8x8_cad_SendArg(u8x8, arg_int<<2 );	
+      u8x8_cad_SendArg(u8x8, arg_int>>6 );	
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+      x += u8x8->x_offset;
+      y= (((u8x8_tile_t *)arg_ptr)->y_pos);
+      y*=4;
+    
+      y+=0;         // specific for the 168x384 LCD
+
+
+      u8x8_cad_StartTransfer(u8x8);
+
+
+      for( i = 0; i < 4; i++ )
+      {
+        
+        u8x8_cad_SendCmd(u8x8, 0x2a);   // column address set
+        u8x8_cad_SendArg(u8x8, 0x17);   // 0x019 for the 122x250 LCD --> 0x016 for the 200x200 display
+        u8x8_cad_SendArg(u8x8, 0x24);  // 204 pixel for the 200x200 display
+      
+        u8x8_cad_SendCmd(u8x8, 0x2b); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendArg(u8x8, y+i); 
+        u8x8_cad_SendCmd(u8x8, 0x2c);		// write data 
+      
+        c = ((u8x8_tile_t *)arg_ptr)->cnt;
+        ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+        
+        ptr += u8x8->display_info->tile_width*i*2;
+        
+        c = (c+2)/3;          // calculate the number of 24 bit blocks to send
+        
+        
+        while( c > 0 )
+        {
+          u8x8_cad_SendData(u8x8, 6, u8x8_st7305_convert_a0(u8x8, ptr)); 	
+          ptr+=3;
+          --c;
+        }
+      }
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}

+ 428 - 0
components/u8g2/u8x8_d_st75161.c

@@ -0,0 +1,428 @@
+/*
+
+  u8x8_d_st75161.c
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2024, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+  https://github.com/olikraus/u8g2/issues/2481
+
+
+  0x030	ext 00
+  0x031	ext 01
+  0x038	ext 10
+  0x039	ext 11
+  
+  cad 011
+  
+  
+  normal mode:
+	0x00c	bit format
+  U8X8_CA( 0xbc, 0x00 ),	data scan dir 
+  U8X8_A( 0xa6 ),				
+  y: 0 offset
+  
+  flip mode:
+	0x008	bit format
+  U8X8_CA( 0xbc, 0x03 ),	data scan dir 
+  U8X8_A( 0xa6 ),				
+  y: 5 offset
+	
+  
+*/
+
+
+#include "u8x8.h"
+
+
+/* not a real power down for the st75256... just a display off */
+static const uint8_t u8x8_d_st75256_256x128_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */  
+  U8X8_C( 0x94 ),				/* sleep out */
+  U8X8_DLY(10),
+  U8X8_C( 0xaf ),				/* display on */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st75256_256x128_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0xae ),				/* display off */
+  U8X8_C( 0x95 ),				/* sleep in */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+/* marked as unused to avoid compiler warning, issue 1802 */
+#ifdef NOT_USED
+static const uint8_t u8x8_d_st75256_jlx256128_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0xbc, 0x00 ),			/* data scan dir */
+  U8X8_A( 0xa6 ),				/* ??? */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x00c ),				/* data format LSB top */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st75256_jlx256128_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0xbc, 0x03 ),			/* data scan dir */
+  U8X8_A( 0xa6 ),				/* ??? */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x008 ),				/* data format MSB top */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+#endif
+
+static const uint8_t u8x8_d_st75161_jlx160160_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0xbc, 0x00 ),			/* data scan dir */
+  U8X8_A( 0xa6 ),				/* ??? */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x00c ),				/* data format LSB top */
+  U8X8_CA( 0x0AB, 0 ),				/* start line */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st75161_jlx160160_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0xbc, 0x03 ),			/* data scan dir */
+  U8X8_A( 0xa6 ),				/* ??? */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x008 ),				/* data format MSB top */
+  U8X8_CA( 0x0AB, 0 ),				/* start line */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+/* marked as unused to avoid compiler warning, issue 1802 */
+#ifdef NOT_USED
+static const uint8_t u8x8_d_st75256_jlx256160_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0xbc, 0x00 ),			/* data scan dir */
+  U8X8_A( 0xa6 ),				/* ??? */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x00c ),				/* data format LSB top */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st75256_jlx256160_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0xbc, 0x03 ),			/* data scan dir */
+  U8X8_A( 0xa6 ),				/* ??? */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x008 ),				/* data format MSB top */
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+#endif
+
+
+/*=============================================*/
+/* jlx160160  https://github.com/olikraus/u8g2/issues/1642 */
+
+static const u8x8_display_info_t u8x8_st75161_jlx160160_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 20,
+  /* reset_pulse_width_ms = */ 5, 	
+  /* post_reset_wait_ms = */ 5, 		/**/
+  /* sda_setup_time_ns = */ 20,		/* */
+  /* sck_pulse_width_ns = */ 40,	/*  */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 15,
+  /* write_pulse_width_ns = */ 70,	
+  /* tile_width = */ 20,
+  /* tile_height = */ 20,
+  /* default_x_offset = */ 0,	/*  y (!) offset in flipmode 0 */
+  /* flipmode_x_offset = */ 1,		/* y (!) offset in flipmode 0 */
+  /* pixel_width = */ 160,
+  /* pixel_height = */ 160
+};
+
+
+/*
+from the JLX160160 datasheet:
+
+transfer_command_lcd(0x30);//EXT=0
+transfer_command_lcd(0x94);//Sleep out
+transfer_command_lcd(0x31);//EXT=1
+transfer_command_lcd(0xD7);//Autoread disable
+transfer_data_lcd(0X9F);//
+transfer_command_lcd(0x32);//Analog SET
+transfer_data_lcd(0x00);//OSC Frequency adjustment
+transfer_data_lcd(0x01);//Frequency on booster capacitors->6KHz
+transfer_data_lcd(0x00);//Bias=1/14
+transfer_command_lcd(0x20);// Gray Level
+transfer_data_lcd(0x01);
+transfer_data_lcd(0x03);
+transfer_data_lcd(0x05);
+transfer_data_lcd(0x07);
+transfer_data_lcd(0x09);
+transfer_data_lcd(0x0b);
+transfer_data_lcd(0x0d);
+transfer_data_lcd(0x10);
+transfer_data_lcd(0x11);
+transfer_data_lcd(0x13);
+transfer_data_lcd(0x15);
+transfer_data_lcd(0x17);
+transfer_data_lcd(0x19);
+transfer_data_lcd(0x1b);
+transfer_data_lcd(0x1d);
+transfer_data_lcd(0x1f);
+transfer_command_lcd(0x31);//EXT=1
+transfer_command_lcd(0xf0);//Without this instruction, the voltage will be increased slowly. 0.5s
+transfer_data_lcd(0x0f);
+transfer_data_lcd(0x0f);
+transfer_data_lcd(0x0f);
+transfer_data_lcd(0x0f);
+transfer_command_lcd(0x30);//EXT=0
+transfer_command_lcd(0x75);//Page Address setting
+transfer_data_lcd(0X00);// XS=0
+transfer_data_lcd(0X28);// XE=159 0x28
+transfer_command_lcd(0x15);//Clumn Address setting
+transfer_data_lcd(0X00);// XS=0
+transfer_data_lcd(0Xff);// XE=256
+transfer_command_lcd(0xBC);//Data scan direction
+transfer_data_lcd(0x00);//MX.MY=Normal
+transfer_ command_lcd (0xA6);
+transfer_command_lcd(0xCA);//Display Control
+transfer_data_lcd(0X00);//
+transfer_data_lcd(0X9F);//Duty=160
+transfer_data_lcd(0X20);//Nline=off
+transfer_command_lcd(0xF0);//Display Mode
+transfer_data_lcd(0X10);//10=Monochrome Mode,11=4Gray
+transfer_command_lcd(0x81);//EV control
+transfer_data_lcd(0x1d);//Fine-tune the contrast value, 0x00~0x3f
+transfer_data_lcd(0x04);//Coarse contrast adjustment 0x00~0x07
+transfer_command_lcd(0x20);//Power control
+transfer_data_lcd(0x0B);//D0=regulator ; D1=follower ; D3=booste,
+on:1 off:0
+delay(20);
+transfer_command_lcd(0xAF);     //Display on
+
+*/
+
+static const uint8_t u8x8_d_st75161_jlx160160_init_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  
+  U8X8_DLY(20),
+  
+/*  
+U8X8_C( 0x030 ), // Extension Command 1
+U8X8_C( 0x06E ),
+
+U8X8_C( 0x031 ), // Extension Command 2
+U8X8_CA( 0x0d7, 0x09f), // Set auto-read instruction, Disable Auto Read
+
+U8X8_CA( 0x0e0 ,0x000), // Enable OTP Read
+U8X8_DLY(10),
+
+U8X8_C( 0x0e3 ), // OTP Read
+U8X8_DLY(20),
+U8X8_C(0xe1), // OTP Control Out
+*/
+  
+  
+  
+  
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x094 ),				/* sleep out */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x0ae ),				/* display off */
+
+  U8X8_C( 0x031 ),				/* select 01 commands */
+  U8X8_CA( 0x0d7, 0x09f ),		/* disable auto read */  
+
+  //U8X8_C( 0x031 ),				/* select 01 commands */
+  U8X8_C( 0x032 ),				/* analog circuit set */
+  U8X8_A( 0x000 ),				/* code example: OSC Frequency adjustment */
+  U8X8_A( 0x001 ),				/* Frequency on booster capacitors 1 = 6KHz? */
+  U8X8_A( 0x000 ),				/* Bias: 0: 1/14, 1: 1/13, 2: 1/12, 3: 1/11, 4:1/10, 5:1/9 */
+    
+  U8X8_C( 0x031 ),				/* select 01 commands */
+  U8X8_C( 0x020 ),				/* gray levels */
+  U8X8_A( 0x01 ),
+  U8X8_A( 0x03 ),
+  U8X8_A( 0x05 ),
+  U8X8_A( 0x07 ),
+  U8X8_A( 0x09),
+  U8X8_A( 0x0b ),
+  U8X8_A( 0x0d ),
+  U8X8_A( 0x10 ),
+  U8X8_A( 0x11 ),
+  U8X8_A( 0x13 ),
+  U8X8_A( 0x15 ),
+  U8X8_A( 0x17 ),
+  U8X8_A( 0x19 ),
+  U8X8_A( 0x1b ),
+  U8X8_A( 0x1d ),
+  U8X8_A( 0x1f ),
+ 
+ 
+  U8X8_C( 0x031 ),				/* select 01 commands */
+  U8X8_CA(0x51, 0xfb), // Booster Level x10
+  U8X8_CAAAA(0xf0, 15, 15, 15, 15),		/* Frame Rate Temparature Range */
+  
+  
+  U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CAA(0x75, 0, 0x28),		/* row range 0..159*/
+  U8X8_CAA(0x15, 0, 255),		/* col range */
+  
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0xbc, 0x00 ),			/* data scan dir */
+  U8X8_A( 0xa6 ),				/* ??? */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_C( 0x00c ),				/* data format LSB top */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */ 
+  U8X8_C( 0xca ),				/* display control, 3 args follow  */
+  U8X8_A( 0x00 ),				/* 0x00: no clock division, 0x04: devide clock */
+  U8X8_A( 0x9f ),				/* 1/160 duty */
+  U8X8_A( 0x20 ),				/* nline off */ 
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */ 
+  U8X8_CA( 0x0f0, 0x010 ),		/* monochrome mode  = 0x010, graylevel = 0x011*/
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CAA( 0x81, 0x1d, 0x04 ),	/* Volume control */
+
+  //U8X8_C( 0x030 ),				/* select 00 commands */
+  U8X8_CA( 0x020, 0x00b ),		/* Power control: Regulator, follower & booster on */
+  U8X8_DLY(100),
+
+  //U8X8_C( 0xaf ),
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+uint8_t u8x8_d_st75161_jlx160160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t x, c;
+  uint8_t *ptr;
+
+  switch(msg)
+  {
+            case U8X8_MSG_DISPLAY_DRAW_TILE:
+              
+              u8x8_cad_StartTransfer(u8x8);
+              x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+              x *= 8;
+              
+              u8x8_cad_SendCmd(u8x8, 0x030 );	/* select command set */
+              u8x8_cad_SendCmd(u8x8, 0x075 );	/* row */
+              u8x8_cad_SendArg(u8x8, (((u8x8_tile_t *)arg_ptr)->y_pos+u8x8->x_offset));         // x offset is reused as y offset
+            
+              u8x8_cad_SendArg(u8x8, 0x027);
+              u8x8_cad_SendCmd(u8x8, 0x015 );	/* col */
+              u8x8_cad_SendArg(u8x8, x);
+              u8x8_cad_SendArg(u8x8, 0x9f);
+              u8x8_cad_SendCmd(u8x8, 0x05c );	
+              
+              do
+              {
+                c = ((u8x8_tile_t *)arg_ptr)->cnt;
+                ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+                c *= 8;
+                u8x8_cad_SendData(u8x8, c, ptr); 	
+                arg_int--;
+              } while( arg_int > 0 );
+              
+              u8x8_cad_EndTransfer(u8x8);
+              return 1;
+        case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+            //u8x8_SetI2CAddress(u8x8, 0x078);		/* lowest I2C adr of the ST75161 */
+	    u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st75161_jlx160160_display_info);
+            return 1;
+        case U8X8_MSG_DISPLAY_INIT:
+	    u8x8_d_helper_display_init(u8x8);
+	    u8x8_cad_SendSequence(u8x8, u8x8_d_st75161_jlx160160_init_seq);    
+            return 1;
+          case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+              if ( arg_int == 0 )
+                u8x8_cad_SendSequence(u8x8, u8x8_d_st75256_256x128_powersave0_seq);
+              else
+                u8x8_cad_SendSequence(u8x8, u8x8_d_st75256_256x128_powersave1_seq);
+
+              return 1;
+	case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+	    if ( arg_int == 0 )
+	    {
+	      u8x8_cad_SendSequence(u8x8, u8x8_d_st75161_jlx160160_flip0_seq);
+	      u8x8->x_offset = u8x8->display_info->default_x_offset;
+	    }
+	    else
+	    {
+	      u8x8_cad_SendSequence(u8x8, u8x8_d_st75161_jlx160160_flip1_seq);
+	      u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+	    }
+	    return 1;
+		
+#ifdef U8X8_WITH_SET_CONTRAST
+        case U8X8_MSG_DISPLAY_SET_CONTRAST:
+              u8x8_cad_StartTransfer(u8x8);
+              
+              u8x8_cad_SendCmd(u8x8, 0x030 );
+              u8x8_cad_SendCmd(u8x8, 0x081 );  /* there are 9 bit for the volume control */
+              u8x8_cad_SendArg(u8x8, (arg_int & 0x1f)<<1 );	/* lower 6 bit */
+              u8x8_cad_SendArg(u8x8, (arg_int>>5));		/* upper 3 bit */
+              
+              u8x8_cad_EndTransfer(u8x8);
+              return 1;
+#endif
+  }
+  return 0;
+}
+

+ 114 - 0
components/u8g2/u8x8_d_st75256.c

@@ -1987,3 +1987,117 @@ uint8_t u8x8_d_st75256_jlx16080(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void
   return 0;
 }
 
+/*=============================================*/
+/* 128x128  issue https://github.com/olikraus/u8g2/issues/2702*/
+
+static const u8x8_display_info_t u8x8_st75256_128x128_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,
+  /* pre_chip_disable_wait_ns = */ 20,
+  /* reset_pulse_width_ms = */ 5, 	
+  /* post_reset_wait_ms = */ 5, 		/**/
+  /* sda_setup_time_ns = */ 20,		/* */
+  /* sck_pulse_width_ns = */ 40,	/*  */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 15,
+  /* write_pulse_width_ns = */ 70,	
+  /* tile_width = */ 16,
+  /* tile_height = */ 16,
+  /* default_x_offset = */ 0,	/* must be 0, because this is checked also for normal mode */
+  /* flipmode_x_offset = */ 0,		/* used as y offset */
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 128
+};
+
+
+static const uint8_t u8x8_d_st75256_128x128_init_seq[] = {
+    U8X8_START_TRANSFER(),
+    U8X8_DLY(10),               // 10ms delay
+
+    U8X8_C(0x30),               // Extension command 1
+    U8X8_C(0x6E),               // Enable Master
+
+    U8X8_C(0x31),               // Extension command 2
+    U8X8_C(0xD7), U8X8_A(0x9F), // Disable Auto Read
+    U8X8_C(0xE0), U8X8_A(0x00), // Enable OTP Read
+    U8X8_DLY(10),
+    U8X8_C(0xE3),               // OTP Up-Load
+    U8X8_DLY(20),               // 20ms delay
+    U8X8_C(0xE1),               // OTP Control End
+
+    U8X8_C(0x30),               // Extension command 1
+    U8X8_C(0x94),               // Sleep Out
+    U8X8_C(0xAE),               // Display Off
+    U8X8_DLY(50),               // 50ms delay
+
+    U8X8_C(0x20),               // Power Control  
+    U8X8_A(0x0B),               // VB, VR, VF All on
+    U8X8_C(0x81), U8X8_A(0x1D), U8X8_A(0x04), // Set Vop (15.0V)
+
+    U8X8_C(0x31),               // Extension command 2
+    U8X8_C(0x32), U8X8_A(0x00), // Analog Set
+    U8X8_A(0x01),               // Booster efficiency level 1
+    U8X8_A(0x02),               // Bias 1/12
+    U8X8_C(0x51), U8X8_A(0xFA), // Booster Level x 8
+
+    U8X8_C(0x30),               // Extension command 1
+    U8X8_C(0xF0), U8X8_A(0x10), // Display Mode = Monochrome
+    U8X8_C(0xCA),               // Display Control
+    U8X8_A(0x00),               // CL Dividing Ratio = Not divided
+    U8X8_A(0x7F),               // Duty Set = 128
+    U8X8_A(0x3F),               
+    U8X8_C(0xBC), U8X8_A(0x00), // Data Scan Direction
+    U8X8_C(0xA6),               // Normal Display
+    U8X8_C(0x0C),               // Data Format = LSB on Top
+    U8X8_CAA(0x75, 0x00, 0x7F), // row range for 128 rows
+    U8X8_CAA(0x15, 0x00, 0x7F), // col range for 128 cols
+
+    U8X8_C(0x31),               // Extension command 2
+    U8X8_C(0x40),               // Internal Power Supply
+
+    U8X8_C(0x30),               // Extension command 1
+    U8X8_C(0xaf),               // Display On
+    U8X8_END_TRANSFER(),
+    U8X8_END()
+};
+
+
+uint8_t u8x8_d_st75256_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  if ( u8x8_d_st75256_256x128_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+  if ( msg == U8X8_MSG_DISPLAY_SETUP_MEMORY )
+  {
+    //u8x8_SetI2CAddress(u8x8, 0x078);		/* lowest I2C adr of the ST75256 */
+    u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st75256_128x128_display_info);
+    return 1;
+  }
+  else if ( msg == U8X8_MSG_DISPLAY_INIT )
+  {
+    u8x8_d_helper_display_init(u8x8);
+    u8x8_cad_SendSequence(u8x8, u8x8_d_st75256_128x128_init_seq);    
+    return 1;
+  }
+  else if  ( msg == U8X8_MSG_DISPLAY_SET_FLIP_MODE )
+  {
+    if ( arg_int == 0 )
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st75256_jlx256128_flip0_seq);
+      u8x8->x_offset = u8x8->display_info->default_x_offset;
+    }
+    else
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st75256_jlx256128_flip1_seq);
+      u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+    }
+    return 1;
+  }
+  return 0;
+}
+
+

Fișier diff suprimat deoarece este prea mare
+ 304 - 156
components/u8g2/u8x8_d_st7567.c


+ 76 - 0
components/u8g2/u8x8_d_st7571.c

@@ -36,6 +36,7 @@
   
   https://github.com/olikraus/u8g2/issues/921
   https://github.com/olikraus/u8g2/issues/1575          128x96
+  https://github.com/olikraus/u8g2/issues/2575          another 128x96 display
 
 */
 
@@ -361,3 +362,78 @@ uint8_t u8x8_d_st7571_128x96(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
   }
   return 1;
 }
+
+
+/*===================================================*/
+/*
+  ccsb4736w g12896 display
+
+  https://github.com/olikraus/u8g2/issues/2575
+
+  reusing u8x8_st7571_128x96_display_info
+
+*/
+static const uint8_t u8x8_d_st7571_g12896_init_seq[] = {
+    
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+
+  
+  U8X8_C(0xAE), 				// Display OFF
+  U8X8_C(0x38), 				// Mode Set  
+  //U8X8_C(0xB8), 				// FR=1011 (85Hz), BE[1:0]=10, level 3 booster
+  U8X8_C(0x94),                                 // 128x96: 75 Hz 
+  
+  U8X8_C(0xA0), 				// ADC select
+  U8X8_C(0xC8), 				// SHL select
+  U8X8_CA(0x44, 0x00), 		// 128x96: COM0 register  https://github.com/olikraus/u8g2/issues/2575
+  U8X8_CA(0x40, 0x00), 		// 128x96 datasheet
+  
+  U8X8_C(0xAB), 				// OSC ON  
+  U8X8_C(0x27), 				// 128x96: Voltage regulator
+  U8X8_CA(0x81, 0x28), 		// 128x96: Volume
+  U8X8_C(0x57), 				// 128x96: LCD Bias: 1/12 
+  U8X8_CA(0x48, 0x61), 		// 128x96: Duty 1/96
+  
+  U8X8_C(0x2C), 				// Power Control, VC: ON, VR: OFF, VF: OFF
+  U8X8_DLY(200),
+  U8X8_C(0x2E), 				// Power Control, VC: ON, VR: ON, VF: OFF
+  U8X8_DLY(200),
+  U8X8_C(0x2F), 				// Power Control, VC: ON, VR: ON, VF: ON
+  U8X8_DLY(10),
+
+  U8X8_C(0x7B), 				// command set 3
+  U8X8_C(0x11), 				// black white mode
+  U8X8_C(0x00), 				// exit command set 3
+
+
+  U8X8_C(0xA6), 				// Display Inverse OFF
+  U8X8_C(0xA4), 				// Disable Display All Pixel ON
+
+  //U8X8_C(0xAF), 				// Display on
+
+
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()           			/* end of sequence */
+};
+
+
+uint8_t u8x8_d_st7571_g12896(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+    
+  if ( u8x8_d_st7571_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+  
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7571_g12896_init_seq); 
+      break;
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7571_128x96_display_info);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}

+ 243 - 0
components/u8g2/u8x8_d_st7586s_md240128.c

@@ -0,0 +1,243 @@
+/*
+  u8x8_d_st7586s_md240128.c 
+
+  Display: 240x128 pixel, 
+  ST7586s: 384 x 160 x 2
+
+  takeover from https://github.com/olikraus/u8g2/issues/2363
+  
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+  
+  Copyright (c) 2024, olikraus@gmail.com
+    
+  All rights reserved.
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+  
+*/
+
+#include "u8g2.h"
+
+
+static const uint8_t u8x8_d_st7586s_sleep_on[] = {
+  U8X8_START_TRANSFER(),  /* enable chip, delay is part of the transfer start */
+  U8X8_C(0x010), /* set power save mode */
+  U8X8_END_TRANSFER(),  /* disable chip */
+  U8X8_END()                  /* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7586s_sleep_off[] = {
+  U8X8_START_TRANSFER(),  /* enable chip, delay is part of the transfer start */
+  U8X8_C(0x011), //Sleep out
+  U8X8_DLY(50), /* delay 50 ms */
+  U8X8_END_TRANSFER(),  /* disable chip */
+  U8X8_END()                  /* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7586s_ymc240160_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x036),  /* Scan Direction Setting */
+  U8X8_A(0x000),	/* COM0 -> COM159 SEG0 -> SEG383 */
+  U8X8_C(0x037),	/* Start line 0 */
+  U8X8_A(0x000),
+  U8X8_END_TRANSFER(),  /* disable chip */
+  U8X8_END()           	/* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7586s_ymc240160_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C(0x036),  /* Scan Direction Setting */
+  U8X8_A(0x080),  /* COM0 -> COM159 SEG383 -> SEG0 */
+  U8X8_C(0x037),  /* Start line 0 */
+  U8X8_A(0x020),
+  U8X8_END_TRANSFER(),  /* disable chip */
+  U8X8_END()            /* end of sequence */
+};
+
+static const uint8_t u8x8_d_st7586s_ymc240160_init_seq[] = {
+  U8X8_START_TRANSFER(),/* enable chip */
+  U8X8_END_TRANSFER(),/* disable chip */
+ // U8G_ESC_RST(1), /* hardware reset */
+  U8X8_DLY(60),   /* Delay 60 ms */
+  U8X8_START_TRANSFER(),/* enable chip */
+
+  U8X8_C(0x001), // Soft reset
+  U8X8_DLY(60), // Delay 120 ms
+
+  U8X8_C(0x011), // Sleep Out
+  U8X8_C(0x028), // Display OFF
+  U8X8_DLY(25), // Delay 50 ms
+
+  U8X8_CAA(0x0C0,0x036,0x01),// Vop = 136h data sheet suggested 0x0145 but this caused streaks
+
+  U8X8_CA(0x0C3,0x000), // BIAS = 1/14
+
+  U8X8_CA(0x0C4,0x007), // Booster = x8
+
+  U8X8_CA(0x0D0,0x01D), // Enable Analog Circuit
+
+  U8X8_CA(0x0B3,0x000), // Set FOSC divider
+
+  U8X8_CA(0x0B5,0x000), // N-Line = 0
+
+  U8X8_C(0x039), // 0x39 Monochrome mode. 0x38 - gray Mode
+
+  U8X8_C(0x03A), // Enable DDRAM Interface
+  U8X8_A(0x002), // monochrome and 4-level
+
+  U8X8_C(0x036), // Scan Direction Setting
+  U8X8_A(0x000), // COM:C0->C159   SEG: SEG0->SEG383
+
+  U8X8_C(0x0B1), // First output COM
+  U8X8_A(0x000), // 
+  
+  U8X8_C(0x0B0), // Duty Setting (num rows - 1)
+  U8X8_A(0x07F), 
+
+  U8X8_C(0x020), // Display inversion off
+
+  U8X8_C(0x02A), // Column Address Setting
+  U8X8_A(0x000), // COL0 -> COL127
+  U8X8_A(0x000), // 
+  U8X8_A(0x000), //
+  U8X8_A(0x04F), // 80*3=240 pixels
+
+  U8X8_C(0x02B), // Row Address Setting
+  U8X8_A(0x000), // ROW0 -> ROW127
+  U8X8_A(0x000), //
+  U8X8_A(0x000), //
+  U8X8_A(0x07F), // 128 pixels
+
+  U8X8_C(0x029), // Display ON
+  U8X8_END_TRANSFER(),/* disable chip */
+  U8X8_END()  /* end of sequence */
+};
+
+static const u8x8_display_info_t u8x8_st7586s_ymc240160_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+
+  /* post_chip_enable_wait_ns = */ 5,
+  /* pre_chip_disable_wait_ns = */ 5,
+  /* reset_pulse_width_ms = */ 1,
+  /* post_reset_wait_ms = */ 6,
+  /* sda_setup_time_ns = */ 20,
+  /* sck_pulse_width_ns = */  100,  /* datasheet ST7586S */
+  /* sck_clock_hz = */ 8000000UL, /* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* ST7586+Atmega128RFA1 works with 8MHz */
+  /* spi_mode = */ 3,   /* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 20, /* datasheet suggests min 20 */
+  /* write_pulse_width_ns = */ 40,
+  /* tile_width = */ 30,
+  /* tile_height = */ 16,
+  /* default_x_offset = */ 0,  /* abused as flag to know if we are flipped */
+  /* flipmode_x_offset = */ 1, /* as pixel order different for normal/flipped  */
+  /* pixel_width = */ 240,
+  /* pixel_height = */ 128
+};
+
+/*  takeover from https://github.com/olikraus/u8g2/issues/2363 */
+uint8_t u8x8_d_st7586s_md240128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) 
+{  
+  uint8_t c;
+  uint8_t *ptr;
+  uint8_t i, byte;
+  uint32_t input;
+  uint8_t output[8];
+//  uint8_t output[4];
+  switch (msg) {
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+    u8x8_cad_StartTransfer(u8x8); // OK Start transfer
+    u8x8_cad_SendCmd(u8x8, 0x02B);  /* Row Address Setting */
+    u8x8_cad_SendArg(u8x8, 0x000);
+    u8x8_cad_SendArg(u8x8, 0x008 * ((u8x8_tile_t *)arg_ptr)->y_pos);
+    u8x8_cad_SendArg(u8x8, 0x000);
+//    u8x8_cad_SendArg(u8x8, 0x09F); // should set end row based on display dimensions
+    u8x8_cad_SendArg(u8x8, u8x8->display_info->pixel_height - 1);  /* should this be u8x8->display_info->pixel_height - 1 */
+    u8x8_cad_SendCmd(u8x8, 0x02C);  /* cmd write display data to ram */
+    c = ((u8x8_tile_t *) arg_ptr)->cnt; //
+    c *= 8;
+    ptr = ((u8x8_tile_t *) arg_ptr)->tile_ptr;  //
+
+    while (c > 0) 
+    {
+      input = (((uint32_t)ptr[0] << 16) | ((uint32_t)ptr[1] << 8) | (uint32_t)ptr[2]);
+      for (i=0; i<8; i++)
+      {
+        byte = 0;
+        if (input & 0x800000)          // if bit 23
+            byte = byte | 0xC0;  //set pixel 1
+        if (input & 0x400000)          // if bit 22
+            byte = byte | 0x18;  //set pixel 2
+        if (input & 0x200000)          // if bit 22
+            byte = byte | 0x3;  //set pixel 3
+        output[i] = byte;
+        input <<= 3;
+      }
+      u8x8_cad_SendData(u8x8, 8, output);
+      ptr += 3;
+      c -= 3;
+    }
+    u8x8_cad_EndTransfer(u8x8); 
+    break;
+  case U8X8_MSG_DISPLAY_INIT:
+    u8x8_d_helper_display_init(u8x8);
+    u8x8_cad_SendSequence(u8x8, u8x8_d_st7586s_ymc240160_init_seq);
+    break;
+  case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+    u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7586s_ymc240160_display_info);
+    break;
+  case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
+  	if ( arg_int == 0 )
+    {
+       u8x8_cad_SendSequence(u8x8, u8x8_d_st7586s_ymc240160_flip0_seq);
+       u8x8->x_offset = u8x8->display_info->default_x_offset;
+    }
+    else
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7586s_ymc240160_flip1_seq);
+      u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+    }	
+    break;
+  case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+    if (arg_int == 0)
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7586s_sleep_off);
+    else
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st7586s_sleep_on);
+    break;
+#ifdef U8X8_WITH_SET_CONTRAST
+  case U8X8_MSG_DISPLAY_SET_CONTRAST:
+    u8x8_cad_StartTransfer(u8x8);
+    u8x8_cad_SendCmd(u8x8, 0x0C0);
+    u8x8_cad_SendArg(u8x8, arg_int);
+    u8x8_cad_SendArg(u8x8, 1);
+    u8x8_cad_EndTransfer(u8x8);
+    break;
+#endif
+  default:
+    return 0;
+  }
+  return 1;
+}
+

+ 44 - 10
components/u8g2/u8x8_d_st7920.c

@@ -52,7 +52,7 @@ static const uint8_t u8x8_d_st7920_init_seq[] = {
   U8X8_C(0x006),		                /* Entry mode: Cursor move to right ,DDRAM address counter (AC) plus 1, no shift  */  
   U8X8_C(0x002),		                /* disable scroll, enable CGRAM adress  */
   U8X8_C(0x001),		                /* clear RAM, needs 1.6 ms */
-  U8X8_DLY(4),					/* delay 2ms */
+  U8X8_DLY(10),					/* delay 10ms */
 
   
   U8X8_END_TRANSFER(),             	/* disable chip */
@@ -153,6 +153,49 @@ uint8_t u8x8_d_st7920_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
 }
 
 
+/*=== 128x32 === */
+/* https://github.com/olikraus/u8g2/issues/2241 */
+
+static const u8x8_display_info_t u8x8_st7920_128x32_display_info =
+{
+  /* chip_enable_level = */ 1,
+  /* chip_disable_level = */ 0,
+  
+  /* post_chip_enable_wait_ns = */ 5,
+  /* pre_chip_disable_wait_ns = */ 5,
+  /* reset_pulse_width_ms = */ 1, 
+  /* post_reset_wait_ms = */ 6, 
+  /* sda_setup_time_ns = */ 20,		
+  /* sck_pulse_width_ns = */  140,	/* datasheet ST7920 */
+  /* sck_clock_hz = */ 1000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 3,		/* old: sck_takeover_edge, new: active high (bit 1), rising edge (bit 0), 18 Aug 16: changed from 1 to 3 which works for 101 */
+	/* Arduino mode 3: aktive low clock, but use rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 30,
+  /* write_pulse_width_ns = */ 40,
+  /* tile_width = */ 16,
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 32
+};
+
+
+uint8_t u8x8_d_st7920_128x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st7920_128x32_display_info);
+      break;
+    default:
+      return u8x8_d_st7920_common(u8x8, msg, arg_int, arg_ptr);
+  }
+  return 1;
+}
+
+
 /*=== 144x32 === */
 /* https://github.com/olikraus/u8g2/issues/209 */
 
@@ -196,13 +239,6 @@ uint8_t u8x8_d_st7920_144x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
 }
 
 
-
-
-
-
-
-
-
 /*=== 160x32 === */
 /* https://github.com/olikraus/u8g2/issues/1873, POWERTIP PG-16032LRU-BWH-H-P2 */
 
@@ -231,7 +267,6 @@ static const u8x8_display_info_t u8x8_st7920_160x32_display_info =
   /* pixel_height = */ 32
 };
 
-
 uint8_t u8x8_d_st7920_160x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 {
   switch(msg)
@@ -356,7 +391,6 @@ static const u8x8_display_info_t u8x8_st7920_256x32_display_info =
   /* pixel_width = */ 256,
   /* pixel_height = */ 32
 };
-  
 
 uint8_t u8x8_d_st7920_256x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
 {

+ 82 - 0
components/u8g2/u8x8_d_t6963.c

@@ -642,4 +642,86 @@ uint8_t u8x8_d_t6963_128x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
 }
   
 
+/*=============================================*/
+
+static const u8x8_display_info_t u8x8_t6963_128x160_display_info =
+{
+  /* chip_enable_level = */ 1,
+  /* chip_disable_level = */ 0,
+  
+  /* post_chip_enable_wait_ns = */ 10,	/* T6963 Datasheet p30 */
+  /* pre_chip_disable_wait_ns = */ 100,	/* T6963 Datasheet p30 */
+  /* reset_pulse_width_ms = */ 1, 
+  /* post_reset_wait_ms = */ 6, 
+  /* sda_setup_time_ns = */ 20,		
+  /* sck_pulse_width_ns = */  140,	
+  /* sck_clock_hz = */ 1000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 80,
+  /* write_pulse_width_ns = */ 80,
+  /* tile_width = */ 16,
+  /* tile_height = */ 20,
+  /* default_x_offset = */ 0,
+  /* flipmode_x_offset = */ 0,
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 160
+};
+
+/* 128x160 */
+static const uint8_t u8x8_d_t6963_128x160_init_seq[] = {
+  U8X8_DLY(100),
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_DLY(100),
+  
+  U8X8_AAC(0x00,0x00,0x021),	/* low, high, set cursor pos */
+  U8X8_AAC(0x00,0x00,0x022),	/* low, high, set offset */
+  U8X8_AAC(0x00,0x00,0x040),	/* low, high, set text home */
+  U8X8_AAC(128/8,0x00,0x041),	/* low, high, set text columns */
+  U8X8_AAC(0x00,0x00,0x042),	/* low, high, graphics home */  
+  U8X8_AAC(128/8,0x00,0x043),	/* low, high, graphics columns */
+  U8X8_DLY(2),					/* delay 2ms */
+  // mode set
+  // 0x080: Internal CG, OR Mode
+  // 0x081: Internal CG, EXOR Mode
+  // 0x083: Internal CG, AND Mode
+  // 0x088: External CG, OR Mode
+  // 0x089: External CG, EXOR Mode
+  // 0x08B: External CG, AND Mode
+  U8X8_C(0x080),            			/* mode register: OR Mode, Internal Character Mode */
+  // display mode
+  // 0x090: Display off
+  // 0x094: Graphic off, text on, cursor off, blink off
+  // 0x096: Graphic off, text on, cursor on, blink off
+  // 0x097: Graphic off, text on, cursor on, blink on
+  // 0x098: Graphic on, text off, cursor off, blink off
+  // 0x09a: Graphic on, text off, cursor on, blink off
+  // ...
+  // 0x09c: Graphic on, text on, cursor off, blink off
+  // 0x09f: Graphic on, text on, cursor on, blink on
+  U8X8_C(0x090),                             /* All Off */
+  U8X8_AAC(0x00,0x00,0x024),	/* low, high, set adr pointer */
+  
+  U8X8_DLY(100),
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_DLY(100),
+};
+
+uint8_t u8x8_d_t6963_128x160(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  switch(msg)
+  {
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_t6963_128x160_display_info);
+      break;
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_t6963_128x160_init_seq);
+      break;
+    default:
+      return u8x8_d_t6963_common(u8x8, msg, arg_int, arg_ptr);
+  }
+  return 1;
+}
+  
   

+ 93 - 0
components/u8g2/u8x8_d_uc1604.c

@@ -144,6 +144,99 @@ uint8_t u8x8_d_uc1604_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a
   return 1;
 }
 
+/*================================================*/
+/* JLX12864 */
+
+/* 
+  timings from uc1604 
+
+  UC1604 has two chip select inputs (CS0 and CS1).
+  CS0 is low active, CS1 is high active. It will depend on the display
+  module whether the display has a is low or high active chip select.
+
+*/
+static const u8x8_display_info_t u8x8_uc1604_128x64_display_info =
+{
+  /* chip_enable_level = */ 0,	/* JLX12864G uses CS0, which is low active CS*/
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 20,	
+  /* pre_chip_disable_wait_ns = */ 20,	
+  /* reset_pulse_width_ms = */ 1, 	
+  /* post_reset_wait_ms = */ 10, 	
+  /* sda_setup_time_ns = */ 30,		
+  /* sck_pulse_width_ns = */ 65,	/* half of cycle time  */
+  /* sck_clock_hz = */ 8000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,
+  /* data_setup_time_ns = */ 30,	
+  /* write_pulse_width_ns = */ 35,	
+  /* tile_width = */ 16,		/* width of 24*8=192 pixel */
+  /* tile_height = */ 8,
+  /* default_x_offset = */ 0,	/* reused as y page offset */
+  /* flipmode_x_offset = */ 0,	/* reused as y page offset */
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 64
+};
+
+static const uint8_t u8x8_d_uc1604_jlx12864_init_seq[] = {
+    
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+
+  U8X8_C(0x0e2),            			/* soft reset */
+  U8X8_DLY(200),
+  U8X8_DLY(200),
+
+  U8X8_C(0x02f),            			/* power on, Bit 2 PC2=1 (internal charge pump), Bits 0/1: cap of panel */
+  U8X8_DLY(200),
+  U8X8_DLY(200),
+  
+  U8X8_CA(0x081, 0x038),		/* set contrast, JLX19264G suggestion: 0x045 */
+  U8X8_C(0x0eb),            			/* LCD bias Bits 0/1: 00=6 01=7, 10=8, 11=9 */
+
+  
+  //U8X8_C(0x023),            			/* Bit 0/1: Temp compenstation, Bit 2: Multiplex Rate 0=96, 1=128 */
+  //U8X8_C(0x027),            			/* Bit 0/1: Temp compenstation, Bit 2: Multiplex Rate 0=96, 1=128 */
+
+  U8X8_C(0x0c2),            			/* Map control, Bit 2: MY=1, Bit 1: MX=0 */
+  U8X8_C(0x0a0),            			/* 0xa0: 76Hz FPS, controller default: 0x0a1: 95Hz FPS */
+  
+  
+  U8X8_C(0x040),            			/* set scroll line to 0 */
+  U8X8_C(0x089),            			/* RAM access control (controller default: 0x089)*/
+  
+  
+  U8X8_C(0x000),		                /* column low nibble */
+  U8X8_C(0x010),		                /* column high nibble */  
+  U8X8_C(0x0b0),		                /* page adr  */
+  
+  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+uint8_t u8x8_d_uc1604_jlx12864(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  /* call common procedure first and handle messages there */
+  if ( u8x8_d_uc1604_common(u8x8, msg, arg_int, arg_ptr) == 0 )
+  {
+    /* msg not handled, then try here */
+    switch(msg)
+    {
+      case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+	u8x8_d_helper_display_setup_memory(u8x8, &u8x8_uc1604_128x64_display_info);
+	break;
+      case U8X8_MSG_DISPLAY_INIT:
+	u8x8_d_helper_display_init(u8x8);
+	u8x8_cad_SendSequence(u8x8, u8x8_d_uc1604_jlx12864_init_seq);
+	break;
+      default:
+	return 0;		/* msg unknown */
+    }
+  }
+  return 1;
+}
+
 /*================================================*/
 /* JLX19264 */
 

+ 457 - 0
components/u8g2/u8x8_d_uc1628.c

@@ -0,0 +1,457 @@
+/*
+
+  u8x8_d_uc1628.c
+
+  Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
+
+  Copyright (c) 2017, olikraus@gmail.com
+  All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without modification, 
+  are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this list 
+    of conditions and the following disclaimer.
+    
+  * Redistributions in binary form must reproduce the above copyright notice, this 
+    list of conditions and the following disclaimer in the documentation and/or other 
+    materials provided with the distribution.
+
+  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
+  CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
+  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
+  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
+  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
+  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
+  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
+
+  UC1628: Monochrome 163x256 driver
+
+  CAD: 011
+
+*/
+
+#include "u8x8.h"
+
+static const uint8_t u8x8_d_uc1628_powersave0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_CA( 0x0c9, 0x0ad ),				/* display enable */  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_uc1628_powersave1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_CA( 0x0c9, 0x0ac ),				/* display disable */  
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+static const uint8_t u8x8_d_uc1628_flip0_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x0c4 ),	
+  U8X8_END_TRANSFER(),             	
+  U8X8_END()             			/* end of sequence */
+};
+
+static const uint8_t u8x8_d_uc1628_flip1_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  U8X8_C( 0x0c2 ),				
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+static uint8_t u8x8_d_uc1628_generic(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  uint8_t x, c;
+  uint8_t *ptr;
+  switch(msg)
+  {
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_SETUP_MEMORY:
+      u8x8_d_helper_display_setup_memory(u8x8, &u8x8_st75256_256x128_display_info);
+      break;
+    */
+    /* handled by the calling function
+    case U8X8_MSG_DISPLAY_INIT:
+      u8x8_d_helper_display_init(u8x8);
+      u8x8_cad_SendSequence(u8x8, u8x8_d_st75256_256x128_init_seq);    
+      break;
+    */
+    case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
+      if ( arg_int == 0 )
+        u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_powersave0_seq);
+      else
+        u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_powersave1_seq);
+
+      break;
+#ifdef U8X8_WITH_SET_CONTRAST
+    case U8X8_MSG_DISPLAY_SET_CONTRAST:
+
+      u8x8_cad_StartTransfer(u8x8);
+      
+      u8x8_cad_SendCmd(u8x8, 0x081 );  /* volume control */
+      u8x8_cad_SendArg(u8x8, 0 );	/* always 0 */
+      u8x8_cad_SendArg(u8x8, arg_int);		/* 8 bit */
+      
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+#endif
+    case U8X8_MSG_DISPLAY_DRAW_TILE:
+      
+      u8x8_cad_StartTransfer(u8x8);
+      x = ((u8x8_tile_t *)arg_ptr)->x_pos;    
+      x *= 8;
+    
+      // TODO: u8x8->x_offset IS MISSING here
+
+      u8x8_cad_SendCmd(u8x8, 0x004 );	/* col */
+      u8x8_cad_SendArg(u8x8, x);
+    
+      u8x8_cad_SendCmd(u8x8, 0x060 );	/* row */
+      u8x8_cad_SendArg(u8x8, (((u8x8_tile_t *)arg_ptr)->y_pos));	
+    
+      u8x8_cad_SendCmd(u8x8, 0x001 );	        // write data
+          
+      do
+      {
+        c = ((u8x8_tile_t *)arg_ptr)->cnt;
+        ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
+        /* SendData can not handle more than 255 bytes, treat c > 31 correctly  */
+        if ( c > 31 )
+        {
+          u8x8_cad_SendData(u8x8, 248, ptr); 	/* 31*8=248 */
+          ptr+=248;
+          c -= 31;
+        }
+        
+        u8x8_cad_SendData(u8x8, c*8, ptr); 	
+        arg_int--;
+      } while( arg_int > 0 );
+      
+      u8x8_cad_EndTransfer(u8x8);
+      break;
+    default:
+      return 0;
+  }
+  return 1;
+}
+
+/*=============================================*/
+/* 256x128, https://github.com/olikraus/u8g2/issues/2260 */
+
+static const u8x8_display_info_t u8x8_uc1628_256x128_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 10,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 5, 	
+  /* post_reset_wait_ms = */ 5, 		/**/
+  /* sda_setup_time_ns = */ 25,		/* */
+  /* sck_pulse_width_ns = */ 100,	/*  */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 45,
+  /* write_pulse_width_ns = */ 125,	
+  /* tile_width = */ 32,
+  /* tile_height = */ 16,
+  /* default_x_offset = */ 0,	/*  */
+  /* flipmode_x_offset = */ 0,		/*  */
+  /* pixel_width = */ 256,
+  /* pixel_height = */ 128
+};
+
+static const uint8_t u8x8_d_uc1628_256x128_init_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  
+  U8X8_DLY(20),
+
+  U8X8_C( 0x010 ),				/* Termp.: Reset default */
+  U8X8_C( 0x012 ),				/* Termp.: Reset default */
+  U8X8_C( 0x014 ),				/* Termp.: Reset default  */
+  
+  /* assign temperature independent framerate */
+  /* 0x00d = 81,9Hz (reset default) */
+  /* 0x000 = 40.0 Hz (min) */
+  /* 0x01f = 140.0 Hz (max) */
+  
+  U8X8_CAA( 0x016, 0x000, 0x00d ),				/* 1st arg: temp. point, 2nd arg: frame rate */
+
+  U8X8_CA( 0x040, 0x000 ),				/*  scroll line */
+
+  U8X8_C( 0x020 ),				/* temp compensation */
+  U8X8_C( 0x02d ),				/* charge pump control */
+  U8X8_C( 0x0eb ),				/* LCD Bias: 0xe8=6, ... 0xeb=12 ... 0xed=14  */
+
+  U8X8_CAA( 0x081, 0x000, 0x048 ),	        /*  Contrast, 1st arg is always 0 */
+
+  U8X8_CA( 0x0b8, 0x000 ),				/*  OTP control: Idle & Ignore */
+
+  U8X8_CA( 0x0f1, 0x07f ),				/*  set COM end */
+  U8X8_CA( 0x0f2, 0x000 ),				/*  set partial display start */
+  U8X8_CA( 0x0f3, 0x07f ),				/*  set partial display end */
+  
+  U8X8_C( 0x088 ),				/*  auto increment control */
+
+  U8X8_C( 0x0c4 ),                      /* XY mirror in bit 1 & 2 */	
+
+  U8X8_DLY(100),
+
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+uint8_t u8x8_d_uc1628_256x128(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  if ( u8x8_d_uc1628_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+  if ( msg == U8X8_MSG_DISPLAY_SETUP_MEMORY )
+  {
+    u8x8_SetI2CAddress(u8x8, 0x070);		/* lowest I2C adr of the UC1628 */
+    u8x8_d_helper_display_setup_memory(u8x8, &u8x8_uc1628_256x128_display_info);
+    return 1;
+  }
+  else if ( msg == U8X8_MSG_DISPLAY_INIT )
+  {
+    u8x8_d_helper_display_init(u8x8);
+    u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_256x128_init_seq);    
+    return 1;
+  }
+  else if  ( msg == U8X8_MSG_DISPLAY_SET_FLIP_MODE )
+  {
+    if ( arg_int == 0 )
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_flip0_seq);
+      u8x8->x_offset = u8x8->display_info->default_x_offset;
+    }
+    else
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_flip1_seq);
+      u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+    }
+    return 1;
+  }
+  return 0;
+}
+
+
+/*=============================================*/
+/* 256x32, https://github.com/olikraus/u8g2/issues/2260 */
+
+static const u8x8_display_info_t u8x8_uc1628_256x32_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 10,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 5, 	
+  /* post_reset_wait_ms = */ 5, 		/**/
+  /* sda_setup_time_ns = */ 25,		/* */
+  /* sck_pulse_width_ns = */ 100,	/*  */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 45,
+  /* write_pulse_width_ns = */ 125,	
+  /* tile_width = */ 32,
+  /* tile_height = */ 4,
+  /* default_x_offset = */ 0,	/*  */
+  /* flipmode_x_offset = */ 0,		/*  */
+  /* pixel_width = */ 256,
+  /* pixel_height = */ 32
+};
+
+static const uint8_t u8x8_d_uc1628_256x32_init_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  
+  U8X8_DLY(20),
+
+  U8X8_C( 0x010 ),				/* Termp.: Reset default */
+  U8X8_C( 0x012 ),				/* Termp.: Reset default */
+  U8X8_C( 0x014 ),				/* Termp.: Reset default  */
+  
+  /* assign temperature independent framerate */
+  /* 0x00d = 81,9Hz (reset default) */
+  /* 0x000 = 40.0 Hz (min) */
+  /* 0x01f = 140.0 Hz (max) */
+  
+  U8X8_CAA( 0x016, 0x000, 0x00d ),				/* 1st arg: temp. point, 2nd arg: frame rate */
+
+  U8X8_CA( 0x040, 0x000 ),				/*  scroll line */
+
+  U8X8_C( 0x020 ),				/* temp compensation */
+  U8X8_C( 0x02d ),				/* charge pump control */
+  U8X8_C( 0x0e8 ),				/* LCD Bias: 0xe8=6, ... 0xeb=12 ... 0xed=14  */
+
+  U8X8_CAA( 0x081, 0x000, 0x048 ),	        /*  Contrast, 1st arg is always 0 */
+
+  U8X8_CA( 0x0b8, 0x000 ),				/*  OTP control: Idle & Ignore */
+
+  U8X8_CA( 0x0f1, 0x01f ),				/*  set COM end */
+  U8X8_CA( 0x0f2, 0x000 ),				/*  set partial display start */
+  U8X8_CA( 0x0f3, 0x07f ),				/*  set partial display end */
+  
+  U8X8_C( 0x088 ),				/*  auto increment control */
+
+  U8X8_C( 0x0c4 ),                      /* XY mirror in bit 1 & 2 */	
+
+  U8X8_DLY(100),
+
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+uint8_t u8x8_d_uc1628_256x32(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  if ( u8x8_d_uc1628_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+  if ( msg == U8X8_MSG_DISPLAY_SETUP_MEMORY )
+  {
+    u8x8_SetI2CAddress(u8x8, 0x070);		/* lowest I2C adr of the UC1628 */
+    u8x8_d_helper_display_setup_memory(u8x8, &u8x8_uc1628_256x32_display_info);
+    return 1;
+  }
+  else if ( msg == U8X8_MSG_DISPLAY_INIT )
+  {
+    u8x8_d_helper_display_init(u8x8);
+    u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_256x32_init_seq);    
+    return 1;
+  }
+  else if  ( msg == U8X8_MSG_DISPLAY_SET_FLIP_MODE )
+  {
+    if ( arg_int == 0 )
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_flip0_seq);
+      u8x8->x_offset = u8x8->display_info->default_x_offset;
+    }
+    else
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_flip1_seq);
+      u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+    }
+    return 1;
+  }
+  return 0;
+}
+
+
+/*=============================================*/
+/* 128x64, https://github.com/olikraus/u8g2/issues/2260 
+
+  2 Oct 2023: Probably the LCD Bias is wrong, it should be reduced, maybe 0xea or so
+  Moreover the COM end should be halfed (0x03f) --> Done, but not tested
+
+*/
+
+static const u8x8_display_info_t u8x8_uc1628_128x64_display_info =
+{
+  /* chip_enable_level = */ 0,
+  /* chip_disable_level = */ 1,
+  
+  /* post_chip_enable_wait_ns = */ 10,
+  /* pre_chip_disable_wait_ns = */ 10,
+  /* reset_pulse_width_ms = */ 5, 	
+  /* post_reset_wait_ms = */ 5, 		/**/
+  /* sda_setup_time_ns = */ 25,		/* */
+  /* sck_pulse_width_ns = */ 100,	/*  */
+  /* sck_clock_hz = */ 4000000UL,	/* since Arduino 1.6.0, the SPI bus speed in Hz. Should be  1000000000/sck_pulse_width_ns */
+  /* spi_mode = */ 0,		/* active high, rising edge */
+  /* i2c_bus_clock_100kHz = */ 4,	/* 400KHz */
+  /* data_setup_time_ns = */ 45,
+  /* write_pulse_width_ns = */ 125,	
+  /* tile_width = */ 16,
+  /* tile_height = */ 8,
+  /* default_x_offset = */ 0,	/*  */
+  /* flipmode_x_offset = */ 0,		/*  */
+  /* pixel_width = */ 128,
+  /* pixel_height = */ 64
+};
+
+static const uint8_t u8x8_d_uc1628_128x64_init_seq[] = {
+  U8X8_START_TRANSFER(),             	/* enable chip, delay is part of the transfer start */
+  
+  U8X8_DLY(20),
+
+  U8X8_C( 0x010 ),				/* Termp.: Reset default */
+  U8X8_C( 0x012 ),				/* Termp.: Reset default */
+  U8X8_C( 0x014 ),				/* Termp.: Reset default  */
+  
+  /* assign temperature independent framerate */
+  /* 0x00d = 81,9Hz (reset default) */
+  /* 0x000 = 40.0 Hz (min) */
+  /* 0x01f = 140.0 Hz (max) */
+  
+  U8X8_CAA( 0x016, 0x000, 0x00d ),				/* 1st arg: temp. point, 2nd arg: frame rate */
+
+  U8X8_CA( 0x040, 0x000 ),				/*  scroll line */
+
+  U8X8_C( 0x020 ),				/* temp compensation */
+  U8X8_C( 0x02d ),				/* charge pump control */
+  U8X8_C( 0x0eb ),				/* LCD Bias: 0xe8=6, ... 0xeb=12 ... 0xed=14  */
+
+  U8X8_CAA( 0x081, 0x000, 0x048 ),	        /*  Contrast, 1st arg is always 0 */
+
+  U8X8_CA( 0x0b8, 0x000 ),				/*  OTP control: Idle & Ignore */
+
+  U8X8_CA( 0x0f1, 0x03f ),				/*  set COM end */
+  U8X8_CA( 0x0f2, 0x000 ),				/*  set partial display start */
+  U8X8_CA( 0x0f3, 0x07f ),				/*  set partial display end */
+  
+  U8X8_C( 0x088 ),				/*  auto increment control */
+
+  U8X8_C( 0x0c4 ),                      /* XY mirror in bit 1 & 2 */	
+
+  U8X8_DLY(100),
+
+  U8X8_END_TRANSFER(),             	/* disable chip */
+  U8X8_END()             			/* end of sequence */
+};
+
+
+uint8_t u8x8_d_uc1628_128x64(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
+{
+  if ( u8x8_d_uc1628_generic(u8x8, msg, arg_int, arg_ptr) != 0 )
+    return 1;
+  if ( msg == U8X8_MSG_DISPLAY_SETUP_MEMORY )
+  {
+    u8x8_SetI2CAddress(u8x8, 0x070);		/* lowest I2C adr of the UC1628 */
+    u8x8_d_helper_display_setup_memory(u8x8, &u8x8_uc1628_128x64_display_info);
+    return 1;
+  }
+  else if ( msg == U8X8_MSG_DISPLAY_INIT )
+  {
+    u8x8_d_helper_display_init(u8x8);
+    u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_128x64_init_seq);    
+    return 1;
+  }
+  else if  ( msg == U8X8_MSG_DISPLAY_SET_FLIP_MODE )
+  {
+    if ( arg_int == 0 )
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_flip0_seq);
+      u8x8->x_offset = u8x8->display_info->default_x_offset;
+    }
+    else
+    {
+      u8x8_cad_SendSequence(u8x8, u8x8_d_uc1628_flip1_seq);
+      u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
+    }
+    return 1;
+  }
+  return 0;
+}
+
+

+ 3 - 3
components/u8g2/u8x8_display.c

@@ -64,7 +64,7 @@ void u8x8_d_helper_display_setup_memory(u8x8_t *u8x8, const u8x8_display_info_t
 void u8x8_d_helper_display_init(u8x8_t *u8x8)
 {
       /* 2) apply port directions to the GPIO lines and apply default values for the IO lines*/
-      u8x8_gpio_Init(u8x8);
+      u8x8_gpio_Init(u8x8);             /* macro, which calls gpio_and_delay_cb with U8X8_MSG_GPIO_AND_DELAY_INIT */
       u8x8_cad_Init(u8x8);              /* this will also call U8X8_MSG_BYTE_INIT, byte init will NOT call GPIO_INIT */
 
       /* 3) do reset */
@@ -108,8 +108,8 @@ void u8x8_SetupMemory(u8x8_t *u8x8)
 */
 void u8x8_InitInterface(u8x8_t *u8x8)
 {
-  u8x8_gpio_Init(u8x8);
-  u8x8_cad_Init(u8x8);              /* this will also call U8X8_MSG_BYTE_INIT, byte init will NOT call GPIO_INIT */
+  u8x8_gpio_Init(u8x8);          /* macro, which calls gpio_and_delay_cb with U8X8_MSG_GPIO_AND_DELAY_INIT */
+  u8x8_cad_Init(u8x8);              /* this will also call U8X8_MSG_BYTE_INIT, byte init will NOT call GPIO_INIT, which alread is called in the prev step */
 }
 
 /*

+ 42 - 0
components/u8g2/u8x8_u8toa.c

@@ -65,3 +65,45 @@ const char *u8x8_u8toa(uint8_t v, uint8_t d)
   return u8x8_u8toap(buf, v) + d;
 }
 
+const char *u8x8_s8toa(int8_t v, uint8_t d)
+{
+  static char buf[5];
+  uint16_t u = v;
+  buf[0] = '+';
+  if ( v < 0 )
+  {
+    buf[0] = '-';
+    u = -v;
+  }
+  u8x8_u8toap(buf+1, (uint8_t)u);
+  if ( d == 1 )
+  {
+    buf[1] = buf[3];
+    buf[2] = '\0';
+  }
+  else if ( d == 2 )
+  {
+    buf[1] = buf[2];
+    buf[2] = buf[3];
+    buf[3] = '\0';
+  }
+  return buf;
+}
+ 
+const char *u8x8_u8tox(uint8_t v, uint8_t d)
+{
+  const char hexdigit[]="0123456789ABCDEF";
+  static char buf[3];
+  if ( d == 1 )
+  {
+    buf[0] = hexdigit[v & 0xF];
+    buf[1] = '\0';
+  }
+  else if ( d == 2 )
+  {
+    buf[0] = hexdigit[v >> 4 & 0xF];
+    buf[1] = hexdigit[v & 0xF];
+    buf[2] = '\0';
+  }
+  return buf;
+}

+ 1 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/main.lua

@@ -10,7 +10,7 @@
     (1) 普通的http get请求功能演示;
 2、netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(四选一)
     (1) netdrv_4g:socket.LWIP_GP,4G网卡;
-    (2) netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+    (2) netdrv_eth_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
     (3) netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
     (4) netdrv_pc:pc模拟器上的网卡
 更多说明参考本目录下的readme.md文件

+ 31 - 45
module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_eth_spi.lua

@@ -17,22 +17,38 @@
 
 local exnetif = require "exnetif"
 
-local function ip_ready_func(ip, adapter)
+local function ip_ready_func(ip, adapter)    
     if adapter == socket.LWIP_ETH then
+        -- 在位置1和2设置自定义的DNS服务器ip地址:
+        -- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
+        -- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
+        -- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
+        -- 如果使用专网卡,不要使用这两行代码;
+        -- 如果使用国外的网络,不要使用这两行代码;
+        socket.setDNS(adapter, 1, "223.5.5.5")
+        socket.setDNS(adapter, 2, "114.114.114.114")
+
         log.info("netdrv_eth_spi.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_ETH))
     end
 end
 
-local function ip_lose_func(adapter)
+local function ip_lose_func(adapter)    
     if adapter == socket.LWIP_ETH then
         log.warn("netdrv_eth_spi.ip_lose_func", "IP_LOSE")
     end
 end
 
+-- 以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
+-- 各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
+
+-- 以太网断网后,内核固件会产生一个"IP_LOSE"消息
+-- 各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
 
--- 此处订阅"IP_READY"和"IP_LOSE"两种消息
--- 在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
--- 也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
+--此处订阅"IP_READY"和"IP_LOSE"两种消息
+--在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
+--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
 sys.subscribe("IP_READY", ip_ready_func)
 sys.subscribe("IP_LOSE", ip_lose_func)
 
@@ -44,47 +60,17 @@ socket.dft(socket.LWIP_ETH)
 -- GPIO20为CH390H以太网芯片的供电使能控制引脚
 gpio.setup(20, 1, gpio.PULLUP)
 
--- 这个task的核心业务逻辑是:初始化SPI,初始化以太网卡,并在以太网卡上开启动态主机配置协议
-local function netdrv_eth_spi_task_func()
-    local result = exnetif.set_priority_order({
+-- 配置SPI外接以太网芯片CH390H的单网卡,exnetif.set_priority_order使用的网卡编号为socket.LWIP_ETH
+-- 本demo使用Air780EPM核心板测试,开发板上的硬件配置为:
+-- GPIO20为CH390H以太网芯片的供电使能控制引脚
+-- 使用spi0,片选引脚使用GPIO8
+-- 如果使用的硬件不是Air780EPM核心板,根据自己的硬件配置修改以下参数
+exnetif.set_priority_order({
     {
-        ETHUSER1 = {
-                    -- 供电使能GPIO
-                    pwrpin = 20,
-                    -- 设置的多个“已经IP READY,但是还没有ping通”网卡,循环执行ping动作的间隔(单位毫秒,可选)
-                    -- 如果没有传入此参数,exnetif会使用默认值10秒
-                    ping_time = 3000,
-
-                    -- 连通性检测ip(选填参数);
-                    -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
-                    -- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
-                    -- ping_ip = "填入可靠的并且可以ping通的ip地址",
-
-                    -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
-                    tp = netdrv.CH390,
-                    opts = {spi=0, cs=8}
+        ETHERNET = {
+            pwrpin = 20, 
+            tp = netdrv.CH390,
+            opts = {spi = 0, cs = 8}
         }
     }
 })
-    --初始化以太网卡
-
-    --以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
-    --各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
-    --也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-
-    --以太网断网后,内核固件会产生一个"IP_LOSE"消息
-    --各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
-    --也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-
-    -- socket.LWIP_ETH 指定网络适配器编号
-    -- netdrv.CH390外挂CH390
-    -- SPI ID 0, 片选 GPIO8
-    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spi=0, cs=8})
-
-    -- 在以太网上开启动态主机配置协议
-    netdrv.dhcp(socket.LWIP_ETH, true)
-end
-
--- 创建并且启动一个task
--- task的处理函数为netdrv_eth_spi_task_func
-sys.taskInit(netdrv_eth_spi_task_func)

+ 9 - 0
module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_multiple.lua

@@ -24,6 +24,15 @@ local exnetif = require "exnetif"
 --     net_type:为nil
 --     adapter:number类型,为-1
 local function netdrv_multiple_notify_cbfunc(net_type,adapter)
+    -- 在位置1和2设置自定义的DNS服务器ip地址:
+    -- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
+    -- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
+    -- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
+    -- 如果使用专网卡,不要使用这两行代码;
+    -- 如果使用国外的网络,不要使用这两行代码;
+    socket.setDNS(adapter, 1, "223.5.5.5")
+    socket.setDNS(adapter, 2, "114.114.114.114")
+    
     if type(net_type)=="string" then
         log.info("netdrv_multiple_notify_cbfunc", "use new adapter", net_type, adapter)
     elseif type(net_type)=="nil" then

+ 1 - 1
module/Air780EHM_Air780EHV_Air780EGH/demo/accessory_board/AirETH_1000/http/netdrv_device.lua

@@ -7,7 +7,7 @@
 @usage
 本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
 1、netdrv_4g:socket.LWIP_GP,4G网卡;
-2、netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+2、netdrv_eth_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
 3、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
 4、netdrv_pc:pc模拟器上的网卡
 

+ 6 - 5
module/Air780EHM_Air780EHV_Air780EGH/project/sms_call_forward/main.lua

@@ -7,11 +7,12 @@
 @usage
 1. 详细逻辑请看cc_forward文件和sms_forward文件
 2. netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(四选一)
-   (1) netdrv_4g:4G网卡
-   (2) netdrv_wifi:WIFI STA网卡
-   (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
-   (4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
-   (5) netdrv_pc:pc模拟器上的网卡
+    (1) netdrv_4g:4G网卡
+    (2) netdrv_wifi:WIFI STA网卡
+    (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
+    (4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
+    (5) netdrv_pc: pc模拟器网卡
+3. sntp_app:启动sntp时间同步功能模块,同步网络时间
 
 ]]
 

+ 0 - 37
module/Air780EHM_Air780EHV_Air780EGH/project/sms_call_forward/netdrv/netdrv_device.lua

@@ -1,37 +0,0 @@
---[[
-@module  netdrv_device
-@summary 网络驱动设备功能模块 
-@version 1.0
-@date    2025.07.24
-@author  朱天华
-@usage
-本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
-1、netdrv_4g:socket.LWIP_GP,4G网卡;
-2、netdrv_wifi:socket.LWIP_STA,WIFI STA网卡;
-3、netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
-4、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
-5、netdrv_pc:pc模拟器上的网卡
-
-根据自己的项目需求,只需要require以上四种中的一种即可;
-
-
-本文件没有对外接口,直接在main.lua中require "netdrv_device"就可以加载运行;
-]]
-
-
--- 根据自己的项目需求,只需要require以下四种中的一种即可;
-
--- 加载“4G网卡”驱动模块
-require "netdrv_4g"
-
--- 加载“WIFI STA网卡”驱动模块
--- require "netdrv_wifi"
-
--- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
--- require "netdrv_eth_spi"
-
--- 加载“可以配置优先级的多种网卡”驱动模块
--- require "netdrv_multiple"
-
--- 加载“pc模拟器网卡”驱动模块
--- require "netdrv_pc"

+ 21 - 11
module/Air780EHM_Air780EHV_Air780EGH/project/sms_call_forward/readme.md

@@ -4,7 +4,7 @@
 
 1、main.lua:主程序入口文件,加载以下 4个文件运行。
 
-2、netdrv_multiple.lua:网卡驱动配置文件,可以配置以太网卡,wifi 网卡,单 4g 网卡,pc模拟器网卡,多网卡五种网卡的使用优先级
+2、netdrv_device.lua:网卡驱动设备,可以配置使用netdrv文件夹内的四种网卡(单4g网卡,单wifi网卡,单spi以太网卡,多网卡)中的任何一种网卡;
 
 3、sms_forward.lua: 短信转发功能模块文件
 
@@ -34,6 +34,18 @@
 
 4、cc_forward(),来电号码信息转发到指定机器人
 
+**netdrv_device:**
+
+短信通过http转发到企业微信/钉钉/飞书平台时,配置连接外网使用的网卡,目前支持以下四种选择(四选一)
+
+(1) netdrv_4g:4G网卡
+
+(2) netdrv_wifi:WIFI STA网卡
+
+(3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
+
+(4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
+
 ## 演示硬件环境:
 
 ![8000w](https://docs.openluat.com/air780ehv/luatos/common/hwenv/image/Air780EHV.png)
@@ -55,15 +67,14 @@ TYPE-C USB数据线直接插到开发板的TYPE-C USB座子,另外一端连接
 3、可选 AirETH_1000 配件板一块,Air780EHV/EHM/EGH 核心板和 AirETH_1000 配件板的硬件接线方式为:
 
 | **Air780EHV/EHM/EGH核心板** | **AirETH_1000配件板** |
-| ---------------- |:------------------:|
-| 3V3              | 3.3v               |
-| GND              | GND                |
-| 86/SPI0CLK       | SCK                |
-| 83/SPI0CS        | CSS                |
-| 84/SPI0MISO      | SDO                |
-| 85/SPI0MOSI      | SDI                |
-| 107/GPIO21       | INT                |
-
+| ------------------------ |:------------------:|
+| 3V3                      | 3.3v               |
+| GND                      | GND                |
+| 86/SPI0CLK               | SCK                |
+| 83/SPI0CS                | CSS                |
+| 84/SPI0MISO              | SDO                |
+| 85/SPI0MOSI              | SDI                |
+| 107/GPIO21               | INT                |
 
 
 
@@ -76,7 +87,6 @@ LuatOS-SoC_V2016_Air780EHV_1,固件地址,如有最新固件请用最新 [[h
 
 LuatOS-SoC_V2016_Air780EHM_1,固件地址,如有最新固件请用最新 [https://docs.openluat.com/Air780EHM/luatos/firmware/](https://docs.openluat.com/Air780EHM/luatos/firmware/)
 
-
 LuatOS-SoC_V2016_Air780EGH_1,固件地址,如有最新固件请用最新 [[https://docs.openluat.com/air780egh/luatos/firmware/version/](https://docs.openluat.com/air780egh/luatos/firmware/version/)]
 
 3、 脚本文件:

+ 33 - 51
module/Air780EPM/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_eth_spi.lua

@@ -17,74 +17,56 @@
 
 local exnetif = require "exnetif"
 
-local function ip_ready_func(ip, adapter)
+-- GPIO20为CH390H以太网芯片的供电使能控制引脚
+gpio.setup(20, 1, gpio.PULLUP)
+
+local function ip_ready_func(ip, adapter)    
     if adapter == socket.LWIP_ETH then
+        -- 在位置1和2设置自定义的DNS服务器ip地址:
+        -- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
+        -- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
+        -- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
+        -- 如果使用专网卡,不要使用这两行代码;
+        -- 如果使用国外的网络,不要使用这两行代码;
+        socket.setDNS(adapter, 1, "223.5.5.5")
+        socket.setDNS(adapter, 2, "114.114.114.114")
+
         log.info("netdrv_eth_spi.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_ETH))
     end
 end
 
-local function ip_lose_func(adapter)
+local function ip_lose_func(adapter)    
     if adapter == socket.LWIP_ETH then
         log.warn("netdrv_eth_spi.ip_lose_func", "IP_LOSE")
     end
 end
 
+-- 以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
+-- 各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
+
+-- 以太网断网后,内核固件会产生一个"IP_LOSE"消息
+-- 各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
 
--- 此处订阅"IP_READY"和"IP_LOSE"两种消息
--- 在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
--- 也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
+--此处订阅"IP_READY"和"IP_LOSE"两种消息
+--在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
+--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
 sys.subscribe("IP_READY", ip_ready_func)
 sys.subscribe("IP_LOSE", ip_lose_func)
 
 
--- 设置默认网卡为socket.LWIP_ETH
-socket.dft(socket.LWIP_ETH)
-
-
+-- 配置SPI外接以太网芯片CH390H的单网卡,exnetif.set_priority_order使用的网卡编号为socket.LWIP_ETH
+-- 本demo使用Air780EPM核心板测试,开发板上的硬件配置为:
 -- GPIO20为CH390H以太网芯片的供电使能控制引脚
-gpio.setup(20, 1, gpio.PULLUP)
-
--- 这个task的核心业务逻辑是:初始化SPI,初始化以太网卡,并在以太网卡上开启动态主机配置协议
-local function netdrv_eth_spi_task_func()
-    local result = exnetif.set_priority_order({
+-- 使用spi0,片选引脚使用GPIO8
+-- 如果使用的硬件不是Air780EPM核心板,根据自己的硬件配置修改以下参数
+exnetif.set_priority_order({
     {
-        ETHUSER1 = {
-                    -- 供电使能GPIO
-                    pwrpin = 20,
-                    -- 设置的多个“已经IP READY,但是还没有ping通”网卡,循环执行ping动作的间隔(单位毫秒,可选)
-                    -- 如果没有传入此参数,exnetif会使用默认值10秒
-                    ping_time = 3000,
-
-                    -- 连通性检测ip(选填参数);
-                    -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
-                    -- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
-                    -- ping_ip = "填入可靠的并且可以ping通的ip地址",
-
-                    -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
-                    tp = netdrv.CH390,
-                    opts = {spi=0, cs=8}
+        ETHERNET = {
+            pwrpin = 20, 
+            tp = netdrv.CH390,
+            opts = {spi = 0, cs = 8}
         }
     }
 })
-    --初始化以太网卡
-
-    --以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
-    --各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
-    --也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-
-    --以太网断网后,内核固件会产生一个"IP_LOSE"消息
-    --各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
-    --也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
-
-    -- socket.LWIP_ETH 指定网络适配器编号
-    -- netdrv.CH390外挂CH390
-    -- SPI ID 0, 片选 GPIO8
-    netdrv.setup(socket.LWIP_ETH, netdrv.CH390, {spi=0, cs=8})
-
-    -- 在以太网上开启动态主机配置协议
-    netdrv.dhcp(socket.LWIP_ETH, true)
-end
-
--- 创建并且启动一个task
--- task的处理函数为netdrv_eth_spi_task_func
-sys.taskInit(netdrv_eth_spi_task_func)

+ 9 - 0
module/Air780EPM/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_multiple.lua

@@ -24,6 +24,15 @@ local exnetif = require "exnetif"
 --     net_type:为nil
 --     adapter:number类型,为-1
 local function netdrv_multiple_notify_cbfunc(net_type,adapter)
+    -- 在位置1和2设置自定义的DNS服务器ip地址:
+    -- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
+    -- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
+    -- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
+    -- 如果使用专网卡,不要使用这两行代码;
+    -- 如果使用国外的网络,不要使用这两行代码;
+    socket.setDNS(adapter, 1, "223.5.5.5")
+    socket.setDNS(adapter, 2, "114.114.114.114")
+    
     if type(net_type)=="string" then
         log.info("netdrv_multiple_notify_cbfunc", "use new adapter", net_type, adapter)
     elseif type(net_type)=="nil" then

+ 1 - 1
module/Air780EPM/demo/accessory_board/AirETH_1000/http/netdrv_device.lua

@@ -7,7 +7,7 @@
 @usage
 本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
 1、netdrv_4g:socket.LWIP_GP,4G网卡;
-2、netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+2、netdrv_eth_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
 3、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
 4、netdrv_pc:socket.LWIP_PC,PC模拟器网卡;
 根据自己的项目需求,只需要require以上其中的一种即可;

+ 1 - 1
module/Air780EPM/demo/accessory_board/AirETH_1000/network_routing/4g_out_ethernet_in/netif_app.lua

@@ -41,7 +41,7 @@ function netif_app_task_func()
     --     local code, headers, body = http.request("GET", "https://httpbin.air32.cn/bytes/2048", nil, nil,
     --         { adapter = socket.LWIP_GP, timeout = 5000, debug = false }).wait()
     --     log.info("http执行结果", code, headers, body and #body)
-    --     sys.wait(10000)
+    --     sys.wait(5000)
     -- end
 end
 

+ 1 - 1
module/Air8000/demo/accessory_board/AirETH_1000/http/main.lua

@@ -10,7 +10,7 @@
 2、netdrv_device:配置连接外网使用的网卡,目前支持以下五种选择(五选一)
     (1) netdrv_4g:socket.LWIP_GP,4G网卡;
     (2) netdrv_wifi:socket.LWIP_STA,WIFI STA网卡;
-    (3) netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+    (3) netdrv_eth_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
     (4) netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
     (5) netdrv_pc:pc模拟器上的网卡
 更多说明参考本目录下的readme.md文件

+ 1 - 1
module/Air8000/demo/accessory_board/AirETH_1000/http/netdrv_device.lua

@@ -8,7 +8,7 @@
 本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
 1、netdrv_4g:socket.LWIP_GP,4G网卡;
 2、netdrv_wifi:socket.LWIP_STA,WIFI STA网卡;
-3、netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+3、netdrv_eth_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
 4、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
 5、netdrv_pc:pc模拟器上的网卡
 

+ 1 - 1
module/Air8000/demo/accessory_board/AirSPINAND_1000/lf_fs.lua

@@ -7,7 +7,7 @@
 @usage
 本demo演示的功能为:使用Air8000核心板通过SPI核心库/lf核心库/io核心库实现对 NAND Flash的操作,演示读数据写数据、删除数据等操作。
 以 Air8000核心板为例, 接线如下:
-Air8000       AirSPINAND配件板
+Air8000       AirSPINAND_1000配件板
 GND(任意)          GND
 VDD_EXT            VCC
 GPIO12/SPI1_CS     CS,片选

+ 3 - 3
module/Air8000/demo/accessory_board/AirSPINAND_1000/readme.md

@@ -42,7 +42,7 @@
 
 1. 合宙 Air8000 核心板一块
 
-2. 合宙 AirSPINAND配件板 一块
+2. 合宙 AirSPINAND_1000配件板 一块
 
 3. TYPE-C USB 数据线一根 ,Air8000 核心板和数据线的硬件接线方式为:
 - Air8000 核心板通过 TYPE-C USB 口供电;(外部供电/USB 供电 拨动开关 拨到 USB 供电一端)
@@ -50,11 +50,11 @@
 - TYPE-C USB 数据线直接插到开发板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
 4. 杜邦线 6 根
 
-    Air8000 核心板与 AirSPINAND配件板 按以下方式接线:
+    Air8000 核心板与 AirSPINAND_1000配件板 按以下方式接线:
 
 <table>
 <tr>
-<td>Air8000核心板<br/></td><td>AirSPINAND配件板<br/></td></tr>
+<td>Air8000核心板<br/></td><td>AirSPINAND_1000配件板<br/></td></tr>
 <tr>
 <td>GND(任意)          <br/></td><td>GND<br/></td></tr>
 <tr>

+ 98 - 0
module/Air8000/demo/socket/server/main.lua

@@ -0,0 +1,98 @@
+--[[
+@module  main
+@summary LuatOS用户应用脚本文件入口,总体调度应用逻辑 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本demo演示的核心功能为:
+1、分别创建tcp server和udp server;
+2、等待client的连接;
+3、tcp/udp server按照以下几种逻辑发送数据给client
+- 串口应用功能模块uart_app.lua,通过uart1接收到串口数据,将串口数据增加send from uart: 前缀后发送给client;
+- 定时器应用功能模块timer_app.lua,定时产生数据,将数据增加send from timer: 前缀后发送给client;
+
+4、netdrv_device:配置连接外网使用的网卡,目前支持以下三种选择(三选一)
+        (1) netdrv_wifi_ap:WIFI AP网卡
+        (2) netdrv_wifi_sta:WIFI STA网卡
+        (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
+
+注意:
+一个tcp server仅支持一路client连接;
+UDP 协议本身是无连接的,这意味着任何在同一局域网下的客户端都可以向服务器的 IP 和端口发送数据包;
+目前只能支持局域网内的client连接,不支持公网ip连接。
+
+更多说明参考本目录下的readme.md文件
+]]
+
+
+--[[
+必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
+PROJECT:项目名,ascii string类型
+        可以随便定义,只要不使用,就行
+VERSION:项目版本号,ascii string类型
+        如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
+                X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
+                因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
+        如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
+]]
+PROJECT = "tcp_udp_server_demo"
+VERSION = "001.000.000"
+
+
+-- 在日志中打印项目名和项目版本号
+log.info("main", PROJECT, VERSION)
+
+
+-- -- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
+-- -- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
+-- if wdt then
+--     --配置喂狗超时时间为9秒钟
+--     wdt.init(9000)
+--     --启动一个循环定时器,每隔3秒钟喂一次狗
+--     sys.timerLoopStart(wdt.feed, 3000)
+-- end
+
+
+-- 如果内核固件支持errDump功能,此处进行配置,【强烈建议打开此处的注释】
+-- 因为此功能模块可以记录并且上传脚本在运行过程中出现的语法错误或者其他自定义的错误信息,可以初步分析一些设备运行异常的问题
+-- 以下代码是最基本的用法,更复杂的用法可以详细阅读API说明文档
+-- 启动errDump日志存储并且上传功能,600秒上传一次
+-- if errDump then
+--     errDump.config(true, 600)
+-- end
+
+
+-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
+-- 可以使用合宙的iot.openluat.com平台进行远程升级
+-- 也可以使用客户自己搭建的平台进行远程升级
+-- 远程升级的详细用法,可以参考fota的demo进行使用
+
+
+-- 启动一个循环定时器
+-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
+-- 方便分析内存使用是否有异常
+-- sys.timerLoopStart(function()
+--     log.info("mem.lua", rtos.meminfo())
+--     log.info("mem.sys", rtos.meminfo("sys"))
+-- end, 3000)
+
+-- -- 加载网络驱动设备功能模块
+require "netdrv_device"
+
+-- -- -- 加载串口应用功能模块
+require "uart_app"
+
+-- -- -- 加载定时器应用功能模块
+require "timer_app"
+
+-- -- 加载tcp server socket主应用功能模块
+require "tcp_server_main"
+
+-- -- 加载udp server socket主应用功能模块
+-- require "udp_server_main"
+
+-- 用户代码已结束---------------------------------------------
+-- 结尾总是这一句
+sys.run()
+-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行

+ 68 - 0
module/Air8000/demo/socket/server/netdrv/netdrv_eth_spi.lua

@@ -0,0 +1,68 @@
+--[[
+@module  netdrv_eth_spi
+@summary “通过SPI外挂CH390H芯片的以太网卡”驱动模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为“通过SPI外挂CH390H芯片的以太网卡”驱动模块 ,核心业务逻辑为:
+1、打开CH390H芯片供电开关;
+2、初始化spi1,初始化以太网卡,并且在以太网卡上开启DHCP(动态主机配置协议);
+3、以太网卡的连接状态发生变化时,在日志中进行打印;
+
+直接使用Air8000开发板硬件测试即可;
+
+本文件没有对外接口,直接在其他功能模块中require "netdrv_eth_spi"就可以加载运行;
+]]
+
+local exnetif = require "exnetif"
+
+local function ip_ready_func(adapter)
+    if adapter == socket.LWIP_ETH then
+        log.info("netdrv_eth_spi.ip_ready_func", "IP_READY: ", socket.localIP(socket.LWIP_ETH))
+    end
+end
+
+local function ip_lose_func(adapter)
+    if adapter == socket.LWIP_ETH then
+        log.warn("netdrv_eth_spi.ip_lose_func", "IP_LOSE")
+        sys.publish(SERVER_TOPIC, "SOCKET_CLOSED")
+    end
+end
+
+--此处订阅"IP_READY"和"IP_LOSE"两种消息
+--在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
+--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
+sys.subscribe("IP_READY", ip_ready_func)
+sys.subscribe("IP_LOSE", ip_lose_func)
+
+
+-- 以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
+-- 各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
+
+-- 以太网断网后,内核固件会产生一个"IP_LOSE"消息
+-- 各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
+
+--此处订阅"IP_READY"和"IP_LOSE"两种消息
+--在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
+--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
+sys.subscribe("IP_READY", ip_ready_func)
+sys.subscribe("IP_LOSE", ip_lose_func)
+
+
+-- 配置SPI外接以太网芯片CH390H的单网卡,exnetif.set_priority_order使用的网卡编号为socket.LWIP_ETH
+-- 本demo使用Air8000开发板测试,开发板上的硬件配置为:
+-- GPIO140为CH390H以太网芯片的供电使能控制引脚
+-- 使用spi1,片选引脚使用GPIO12
+-- 如果使用的硬件不是Air8000开发板,根据自己的硬件配置修改以下参数
+exnetif.set_priority_order({
+    {
+        ETHERNET = {
+            pwrpin = 140, 
+            tp = netdrv.CH390,
+            opts = {spi = 1, cs = 12}
+        }
+    }
+})

+ 81 - 0
module/Air8000/demo/socket/server/netdrv/netdrv_wifi_ap.lua

@@ -0,0 +1,81 @@
+--[[
+@module  netdrv_wifi_ap
+@summary "WIFI AP网卡"驱动模块
+@version 1.0
+@date    2025.10.16
+@author  王世豪
+@usage
+本文件为WIFI AP网卡驱动模块,核心业务逻辑为:
+1、初始化WiFi AP功能;
+2、配置热点名称、密码等参数;
+3、启动接入点供其他设备连接;
+
+本文件没有对外接口,直接在其他功能模块中require "netdrv_wifi_ap"就可以加载运行;
+]]
+
+dnsproxy = require("dnsproxy")
+dhcpsrv = require("dhcpsrv")
+
+
+local function ip_ready_func(ip,adapter)
+    if adapter == socket.LWIP_AP then
+        log.info("netdrv_wifi.ip_ready_func", "IP_READY: ", ip)
+    end
+end
+
+local function ip_lose_func(ip,adapter)
+    if adapter == socket.LWIP_AP then
+        log.warn("netdrv_wifi.ip_lose_func", "IP_LOSE")
+        sys.publish(SERVER_TOPIC, "SOCKET_CLOSED")
+    end
+end
+
+-- 监听WLAN_AP_INC消息,处理WiFi接入点相关事件
+local function ap_ready_func(evt, data)
+    -- evt 可能的值有: "CONNECTED", "DISCONNECTED"
+    -- 当evt=CONNECTED, data是连接的AP的新STA的MAC地址
+    -- 当evt=DISCONNECTED, data是断开与AP连接的STA的MAC地址
+    log.info("收到AP事件", evt, data and data:toHex())
+end
+
+-- 订阅系统网络相关消息,实现事件驱动的网络状态管理
+sys.subscribe("IP_READY", ip_ready_func)
+sys.subscribe("IP_LOSE", ip_lose_func)
+sys.subscribe("WLAN_AP_INC", ap_ready_func)
+
+
+-- 设置默认网卡为socket.LWIP_AP
+socket.dft(socket.LWIP_AP)
+
+--这个task的核心业务逻辑是:执行WiFi AP初始化和配置流程
+local function netdrv_wifi_ap_task_func()
+    -- wlan初始化
+    wlan.init()
+    -- 创建热点,SSID=LuatOS+IMEI,密码=12345678
+    wlan.createAP("LuatOS" .. mobile.imei(), "12345678")
+    -- 为AP网卡分配静态IPv4地址、子网掩码、网关
+    netdrv.ipv4(socket.LWIP_AP, "192.168.4.1", "255.255.255.0", "0.0.0.0")
+
+    -- 等待AP接口就绪
+    while netdrv.ready(socket.LWIP_AP) ~= true do
+        sys.wait(100)
+    end
+    -- 配置DNS代理
+    dnsproxy.setup(socket.LWIP_AP, socket.LWIP_GP)
+    -- 在AP接口上创建DHCP服务器,为连接到热点的设备自动分配IP地址
+    dhcpsrv.create({adapter=socket.LWIP_AP})
+    -- 配置网络共享(NAPT),使用4G网络作为主网关出口
+    while 1 do
+        if netdrv.ready(socket.LWIP_GP) then
+            netdrv.napt(socket.LWIP_GP)
+            log.info("AP 创建成功,如果无法连接,需要将按照https://docs.openluat.com/air8000/luatos/app/updatwifi/update/ 升级固件")
+            log.info("AP 创建成功,如果无法连接,请升级本仓库的最新core")
+            break
+        end
+        sys.wait(1000)
+    end
+end
+
+--创建并且启动一个task
+--task的处理函数为netdrv_wifi_ap_task_func
+sys.taskInit(netdrv_wifi_ap_task_func)

+ 59 - 0
module/Air8000/demo/socket/server/netdrv/netdrv_wifi_sta.lua

@@ -0,0 +1,59 @@
+--[[
+@module  netdrv_wifi
+@summary “WIFI STA网卡”驱动模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为WIFI STA网卡驱动模块,核心业务逻辑为:
+1、初始化WIFI网络;
+2、连接WIFI路由器;
+3、和WIFI路由器之间的连接状态发生变化时,在日志中进行打印;
+
+本文件没有对外接口,直接在其他功能模块中require "netdrv_wifi"就可以加载运行;
+]]
+
+local exnetif = require "exnetif"
+
+local function ip_ready_func(ip, adapter)
+    if adapter == socket.LWIP_STA then
+        log.info("netdrv_wifi.ip_ready_func", "IP_READY: ", ip, json.encode(wlan.getInfo()))
+    end
+end
+
+local function ip_lose_func(adapter)
+    if adapter == socket.LWIP_STA then
+        log.warn("netdrv_wifi.ip_lose_func", "IP_LOSE")
+        sys.publish(SERVER_TOPIC, "SOCKET_CLOSED")
+    end
+end
+
+--WIFI联网成功(做为STATION成功连接AP,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
+--各个功能模块可以订阅"IP_READY"消息实时处理WIFI联网成功的事件
+--也可以在任何时刻调用socket.adapter(socket.LWIP_STA)来获取WIFI网络是否连接成功
+
+--WIFI断网后,内核固件会产生一个"IP_LOSE"消息
+--各个功能模块可以订阅"IP_LOSE"消息实时处理WIFI断网的事件
+--也可以在任何时刻调用socket.adapter(socket.LWIP_STA)来获取WIFI网络是否连接成功
+
+--此处订阅"IP_READY"和"IP_LOSE"两种消息
+--在消息的处理函数中,仅仅打印了一些信息,便于实时观察WIFI的连接状态
+--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
+sys.subscribe("IP_READY", ip_ready_func)
+sys.subscribe("IP_LOSE", ip_lose_func)
+
+-- 配置WiFi设备模式的单网卡,exnetif.set_priority_order使用的网卡编号为socket.LWIP_STA
+-- ssid为要连接的WiFi路由器名称;
+-- password为要连接的WiFi路由器密码;
+-- 注意:仅支持2.4G的WiFi,不支持5G的WiFi;
+-- 实际测试时,根据自己要连接的WiFi热点信息修改以下参数
+exnetif.set_priority_order({
+    {
+        WIFI = {
+            -- ssid = "茶室-降功耗,找合宙!", 
+            -- password = "Air123456"
+            ssid = "xiaomi15",
+            password = "wsh123456"
+        }
+    }
+})

+ 29 - 0
module/Air8000/demo/socket/server/netdrv_device.lua

@@ -0,0 +1,29 @@
+--[[
+@module  netdrv_device
+@summary 网络驱动设备功能模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
+1、netdrv_wifi_sta:socket.LWIP_STA,WIFI STA网卡;
+2、netdrv_wifi_ap:socket.LWIP_AP,WIFI AP网卡;
+3、netdrv_ethernet_spi:socket.LWIP_USER1,通过SPI外挂CH390H芯片的以太网卡;
+
+根据自己的项目需求,只需要require以上三种中的一种即可;
+
+
+本文件没有对外接口,直接在main.lua中require "netdrv_device"就可以加载运行;
+]]
+
+
+-- 根据自己的项目需求,只需要require以下三种中的一种即可;
+
+-- 加载“WIFI STA网卡”驱动模块
+require "netdrv_wifi_sta"
+
+-- 加载“WIFI AP网卡”驱动模块
+-- require "netdrv_wifi_ap"
+
+-- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
+-- require "netdrv_eth_spi"

+ 187 - 0
module/Air8000/demo/socket/server/readme.md

@@ -0,0 +1,187 @@
+## 功能模块介绍
+
+1、main.lua:主程序入口;
+
+2、netdrv_device.lua:网卡驱动设备,可以配置使用netdrv文件夹内的三种网卡(单wifi ap网卡,单wifi sta网卡,单spi以太网卡)中的任何一种网卡;
+
+3、tcp文件夹:tcp server以及数据收发处理逻辑;
+
+4、udp文件夹:udp server以及数据收发处理逻辑;
+
+5、timer_app.lua:通知server定时发送数据给client;
+
+6、uart_app.lua:server和uart外设之间透传数据;
+
+> 注意:
+> 
+> 一个tcp server仅支持一路client连接;
+> 
+> UDP 协议本身是无连接的,这意味着任何在同一局域网下的客户端都可以向服务器的 IP 和端口发送数据包;
+
+## 系统消息介绍
+
+1、"IP_READY":某种网卡已经获取到ip信息,仅仅获取到了ip信息,能否和外网连通还不确认;
+
+2、"IP_LOSE":某种网卡已经掉网;
+
+## 用户消息介绍
+
+1、"RECV_DATA_FROM_CLIENT":tcp/udp server收到客户端上发的数据后,通过此消息发布出去,给其他应用模块处理;
+
+2、"SEND_DATA_REQ":其他应用模块发布此消息,通知tcp/udp server发送数据给客户端;
+
+## 演示功能概述
+
+1、创建tcp/udp server,在目录中对应两个文件夹详情如下
+
+- TCP文件夹功能为创建一个tcp server,等待tcp client连接;
+
+- UDP文件夹功能为创建一个udp server,等待udp client连接;
+
+2、tcp/udp server 与client连接成功后,server按照以下几种逻辑发送数据给client
+
+- 串口应用功能模块uart_app.lua,通过uart1接收到串口数据,将串口数据增加send from uart: 前缀后发送给client;
+
+- 定时器应用功能模块timer_app.lua,定时产生数据,将数据增加send from timer:前缀后发送给client;
+
+3、netdrv_device:配置连接外网使用的网卡,目前支持以下三种选择(三选一)
+
+   (1) netdrv_wifi_ap:WIFI AP网卡
+
+   (2) netdrv_wifi_sta:WIFI STA网卡
+
+   (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air8000/luatos/app/image/netdrv_multi.jpg)
+
+1、Air8000开发板一块+wifi天线一根+网线一根:
+
+- 天线装到开发板上
+
+- 网线一端插入开发板网口,另外一端连接可以上外网的路由器网口
+
+2、TYPE-C USB数据线一根 + USB转串口数据线一根,Air8000开发板和数据线的硬件接线方式为:
+
+- Air8000开发板通过TYPE-C USB口供电;(外部供电/USB供电 拨动开关 拨到 USB供电一端)
+
+- TYPE-C USB数据线直接插到开发板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+- USB转串口数据线,一般来说,白线连接开发板的UART1_TX,绿线连接开发板的UART1_RX,黑线连接开发板的GND,另外一端连接电脑USB口;
+
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8000 V2016版本固件](https://docs.openluat.com/air8000/luatos/firmware/)(理论上,2025年7月26日之后发布的固件都可以)
+
+3、PC端的串口工具,建议使用SSCOM(SSCOM可以创建TCP客户端或UDP客户端,测试TCP/UDP 通信功能)
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、demo脚本代码netdrv_device.lua中,按照自己的网卡需求启用对应的Lua文件
+
+- 如果需要单WIFI AP网卡,打开require "netdrv_wifi_ap",其余注释掉;同时netdrv_wifi_ap.lua中的wlan.createAP("LuatOS" .. mobile.imei(), "12345678"),表示创建wifi的名称和密码,根据自己需求改动即可;
+
+- 如果需要单WIFI STA网卡,打开require "netdrv_wifi_sta",其余注释掉;同时netdrv_wifi_sta.lua中的wlan.connect("茶室-降功耗,找合宙!", "Air123456", 1),前两个参数,修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
+
+- 如果需要以太网卡,打开require "netdrv_eth_spi",其余注释掉
+
+
+3、demo脚本代码中,测试TCP server和UDP server时,需要修改的地方如下:
+
+- 测试TCP server时,main.lua打开 require "tcp_server_main",注释掉 require "udp_server_main";同时timer_app.lua和uart_app.lua中的enable_tcp设为true,enable_udp设为false。
+
+- 测试UDP server时,main.lua打开 require "udp_server_main",注释掉 require "tcp_server_main";同时timer_app.lua和uart_app.lua中的enable_udp设为true,enable_tcp设为false。
+
+4、Luatools烧录内核固件和修改后的demo脚本代码
+
+5、烧录成功后,自动开机运行
+
+6、TCP演示:
+
+(1)根据烧录日志,找到TCP server的ip,此外 port 在示例代码中默认是50003
+
+ip获取方式,是在每个netdrv网卡文件中的 ip_ready_func接口中,此处演示WIFI_STA网卡的情况下,如何找到创建的TCP server的ip
+
+```lua
+local function ip_ready_func(ip, adapter)
+    if adapter == socket.LWIP_STA then
+        log.info("netdrv_wifi.ip_ready_func", "IP_READY: ", ip, json.encode(wlan.getInfo()))
+    end
+end
+```
+luatools日志打印如下:
+
+![image](https://docs.openLuat.com/cdn/image/socket/tcp_ip_ready.png)
+
+(2)PC 端打开一个TCP客户端,连接到Air8000开发板创建的TCP server (本例使用SSCOM打开一个TCP客户端):
+
+端口号:选择TCPCLient
+
+远程:填写TCP server的ip地址 和TCP监听的port ,默认是50003
+
+本地:填写本地PC端的IP地址
+
+![image](https://docs.openLuat.com/cdn/image/socket/tcp_client.png)
+
+成功连接之后,即可收到TCP server主动发送的第一条消息:
+
+![image](https://docs.openLuat.com/cdn/image/socket/tcp_client1.png)
+
+(3)另外再打开一个PC端的串口工具连接到Air8000开发板的uart1, 做串口收发,选择对应的端口,配置波特率115200,数据位8,停止位1,无奇偶校验位
+
+(4)PC端的串口工具输入一段数据 "hello client!",点击发送,在作为TCP客户端的SSCOM上可以收到此数据;在作为TCP 客户端的SSCOM输入一段数据 "i am tcp client",点击发送,在PC端的串口工具上可以收到此数据,如下所示:
+
+![image](https://docs.openLuat.com/cdn/image/socket/tcp_client2.png)
+
+
+7、UDP演示:
+
+(1)根据烧录日志,找到UDP server的ip,此外 port 在示例代码中默认是50003
+
+ip获取方式,是在每个netdrv网卡文件中的 ip_ready_func接口中,此处演示WIFI_STA网卡的情况下,如何找到创建的UDP server的ip
+
+```lua
+local function ip_ready_func(ip, adapter)
+    if adapter == socket.LWIP_STA then
+        log.info("netdrv_wifi.ip_ready_func", "IP_READY: ", ip, json.encode(wlan.getInfo()))
+    end
+end
+```
+luatools日志打印如下:
+
+![image](https://docs.openLuat.com/cdn/image/socket/udp_ip_ready.png)
+
+(2)PC 端打开一个UDP客户端,连接到Air8000开发板创建的UDP server (本例使用SSCOM打开一个UDP客户端):
+
+端口号:选择UDP
+
+远程:填写UDP server的ip地址 和UDP监听的port ,默认是50003
+
+本地:填写本地PC端的IP地址, 本例填写的port是50000
+
+![image](https://docs.openLuat.com/cdn/image/socket/udp_client.png)
+
+成功连接之后,即可收到UDP server主动发送的第一条消息:
+
+![image](https://docs.openLuat.com/cdn/image/socket/udp_client1.png)
+
+(3)另外再打开一个PC端的串口工具连接到Air8000开发板的uart1, 做串口收发,选择对应的端口,配置波特率115200,数据位8,停止位1,无奇偶校验位
+
+(4)PC端的串口工具输入一段数据 "hello udp server!",点击发送,在作为UDP客户端的SSCOM上可以收到此数据;在作为UDP 客户端的SSCOM输入一段数据 "i am udp client",点击发送,在PC端的串口工具上可以收到此数据,如下所示: 
+
+![image](https://docs.openLuat.com/cdn/image/socket/udp_client2.png)
+
+8、注意事项
+
+UDP server 在未收到 client发的数据时,会每隔15秒向255.255.255.255 发送一条心跳广播消息,同时timer_app定时发送功能 由于无法确定客户端的ip和port, 会打印 "尚未收到客户端数据, 无法确定目标IP和端口" 的错误提示;
+
+UDP server 在收到client 发的数据后,会记录下来发送消息的client的ip和port,然后通过timer_app 每隔5秒向client发送数据。
+
+目前只能支持局域网内的client连接,不支持公网ip连接。

+ 332 - 0
module/Air8000/demo/socket/server/tcp/tcp_server_main.lua

@@ -0,0 +1,332 @@
+--[[
+@module  tcp_server_main
+@summary tcp server主应用功能模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage  
+本文件为tcp server主应用功能模块,核心业务逻辑为:
+1、创建一个tcp server ,等待client连接;
+2、处理连接异常,出现异常后,关闭当前连接,等待下一个client连接;
+3、调用tcp_server_receiver和tcp_server_sender中的外部接口,进行数据收发处理;
+
+本文件没有对外接口,直接在main.lua中require "tcp_server_main"就可以加载运行;
+]]
+
+local libnet = require "libnet"
+
+-- 加载TCP服务器数据接收功能模块
+local tcp_server_receiver = require "tcp_server_receiver"
+-- 加载TCP服务器数据发送功能模块
+local tcp_server_sender = require "tcp_server_sender"
+
+-- tcp_server_main的任务名
+local TASK_NAME = tcp_server_sender.TASK_NAME
+
+-- 处理未识别的消息
+local function tcp_server_main_cbfunc(msg)
+	log.info("tcp_server_main_cbfunc", msg[1], msg[2], msg[3], msg[4])
+end
+
+-- tcp server socket的任务处理函数
+local function tcp_server_main_task_func()
+    local netc = nil
+    local result, param
+    local listen_port = 50003 -- tcp server监听的端口号
+
+    while true do
+        -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
+        while not socket.adapter(socket.dft()) do
+            log.warn("tcp_server_main_task_func", "wait IP_READY", socket.dft())
+            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
+            -- 或者等待1秒超时退出阻塞等待状态;
+            -- 注意:此处的1000毫秒超时不要修改的更长;
+            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
+            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
+            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
+            sys.waitUntil("IP_READY", 1000)
+        end
+
+        -- 检测到了IP_READY消息
+        log.info("tcp_server_main_task_func", "recv IP_READY", socket.dft())
+
+        netc = socket.create(socket.dft(), TASK_NAME)
+        if not netc then
+            log.error("tcp_server_task_func", "socket.create失败")
+            goto EXCEPTION_PROC
+        end
+
+        socket.debug(netc, true)
+        -- 配置socker server 对象为tcp server
+        result = socket.config(netc, listen_port)
+        -- 如果配置失败
+        if not result then
+            log.error("tcp_server_task_func", "socket.config失败")
+            goto EXCEPTION_PROC
+        end
+
+        -- 监听tcp server端口
+        result = libnet.listen(TASK_NAME, 0, netc)
+        -- 如果监听失败
+        if not result then
+            log.error("tcp_server_task_func", "监听失败")
+            goto EXCEPTION_PROC
+        end
+
+        -- 客户端连上了, 发一条数据给客户端
+        libnet.tx(TASK_NAME, 0, netc, "TCP server is UP!")
+
+        -- 数据收发以及网络连接异常事件总处理逻辑
+        while true do
+            -- 数据接收处理
+            if not tcp_server_receiver.proc(netc) then
+                log.info("tcp_server_task_func", "tcp_server_receiver.proc error")
+                break
+            end
+            
+            -- 数据发送处理
+            if not tcp_server_sender.proc(TASK_NAME, netc) then
+                log.info("tcp_server_task_func", "tcp_server_sender.proc error")
+                break
+            end
+
+            -- 阻塞等待socket.EVENT事件或者15秒钟超时
+            result, param = libnet.wait(TASK_NAME, 15000, netc)
+            log.info("tcp_server_task_func", "wait result", result, param)
+
+            -- 如果连接异常,则退出循环
+            if not result then
+                log.info("tcp_server_task_func", "客户端断开")
+                break
+            end
+        end
+
+        -- 出现异常    
+        ::EXCEPTION_PROC::
+
+        -- 数据发送应用模块对来不及发送的数据做清空和通知失败处理
+        tcp_server_sender.exception_proc()
+
+        -- 如果存在socket server对象
+        if netc then
+            -- 关闭socket server连接
+            libnet.close(TASK_NAME, 5000, netc)
+
+            -- 释放socket server对象
+            socket.release(netc)
+            netc = nil  
+        end
+
+        -- 等待5秒后,再次尝试创建新的连接
+        sys.wait(5000)
+    end
+end
+
+--创建并且启动一个task
+--运行这个task的主函数tcp_server_main_task_func
+sys.taskInitEx(tcp_server_main_task_func, TASK_NAME, tcp_server_main_cbfunc)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+-- --[[
+-- @module  tcp_server_main
+-- @summary TCP服务器主应用功能模块
+-- @version 1.0
+-- @date    2025.07.01
+-- @author  AI Assistant
+-- @usage
+-- 本文件为TCP服务器主应用功能模块,核心业务逻辑为:
+-- 1、创建一个TCP服务器,监听指定端口;
+-- 2、持续监听并接受客户端连接;
+-- 3、为每个客户端连接创建独立的任务处理数据收发;
+
+-- 本文件没有对外接口,直接在main.lua中require "tcp_server_main"就可以加载运行;
+-- ]]
+
+-- local libnet = require "libnet"
+
+-- -- 加载TCP服务器数据接收功能模块
+-- local tcp_server_receiver = require "tcp_server_receiver"
+-- -- 加载TCP服务器数据发送功能模块
+-- local tcp_server_sender = require "tcp_server_sender"
+
+-- -- 任务名称
+-- local TASK_NAME = "TCP_SERVER_TASK"
+
+-- -- 客户端连接处理任务
+-- local function client_handler_task(client_socket, client_ip, client_port)
+--     log.info("client_handler_task", "开始处理客户端连接", client_ip, client_port)
+    
+--     local tx_buff = zbuff.create(1024)
+--     local rx_buff = zbuff.create(1024)
+    
+--     -- 发送欢迎消息
+--     sys.publish("TCP_SERVER_SEND", "欢迎连接到服务器", client_socket)
+    
+--     -- 数据收发循环
+--     while true do
+--         -- 数据接收处理
+--         local recv_result, data = tcp_server_receiver.proc(client_socket, rx_buff)
+--         if not recv_result then
+--             log.info("client_handler_task", "客户端断开", client_ip, client_port)
+--             break
+--         end
+        
+--         -- 数据发送处理
+--         if not tcp_server_sender.proc(client_socket, tx_buff) then
+--             log.info("client_handler_task", "发送失败", client_ip, client_port)
+--             break
+--         end
+        
+--         -- 等待网络事件
+--         local result, param = libnet.wait("CLIENT_"..client_port, 5000, client_socket)
+--         if not result then
+--             log.info("client_handler_task", "客户端超时或断开", client_ip, client_port, result, param)
+--             break
+--         end
+--     end
+    
+--     -- 关闭客户端连接
+--     libnet.close("CLIENT_"..client_port, 5000, client_socket)
+--     log.info("client_handler_task", "客户端连接处理结束", client_ip, client_port)
+-- end
+
+-- -- 处理接收到的数据
+-- local function tcp_data_handler(_, data, remote_ip, remote_port, client_socket)
+--     log.info("tcp_data_handler", "收到数据", data, remote_ip, remote_port)
+    
+--     -- 示例:回声功能,将接收到的数据原样发送回去
+--     sys.publish("TCP_SERVER_SEND", data, client_socket)
+-- end
+
+-- -- 处理未识别的消息
+-- local function netCB(msg)
+--     log.info("未处理消息", msg[1], msg[2], msg[3], msg[4])
+-- end
+
+-- -- TCP服务器监听任务函数
+-- local function tcp_server_listener_task(port, adapter)
+--     log.info("tcp_server_listener_task", "准备监听端口", socket.localIP(adapter), port)
+    
+--     -- 创建监听socket
+--     local listen_socket = socket.create(adapter, TASK_NAME)
+    
+--     if not listen_socket then
+--         log.error("tcp_server_listener_task", "创建监听socket失败")
+--         return
+--     end
+    
+--     socket.debug(listen_socket, true)
+--     socket.config(listen_socket, port)
+    
+--     -- 等待网络连接
+--     local result = libnet.waitLink(TASK_NAME, 0, listen_socket)
+--     if not result then
+--         log.error("tcp_server_listener_task", "等待网络连接失败")
+--         socket.release(listen_socket)
+--         return
+--     end
+    
+--     -- 开始监听
+--     result = libnet.listen(TASK_NAME, 0, listen_socket)
+--     if not result then
+--         log.error("tcp_server_listener_task", "监听失败")
+--         socket.release(listen_socket)
+--         return
+--     end
+    
+--     log.info("tcp_server_listener_task", "开始监听端口", port)
+    
+--     -- 主监听循环
+--     while true do
+--         -- 接受客户端连接
+--         local client_socket, client_info = socket.accept(listen_socket, nil)
+        
+--         if client_socket then
+--             local client_ip, client_port = socket.getpeerip(client_socket)
+--             log.info("tcp_server_listener_task", "接受客户端连接", client_ip, client_port)
+            
+--             -- 为每个客户端创建独立的任务
+--             sys.taskInit(client_handler_task, client_socket, client_ip, client_port)
+--         else
+--             -- 接受连接失败,等待一段时间后重试
+--             log.warn("tcp_server_listener_task", "接受连接失败")
+--             sys.wait(1000)
+--         end
+        
+--         -- 检查监听socket是否仍然有效
+--         if not socket.isValid(listen_socket) then
+--             log.error("tcp_server_listener_task", "监听socket无效,重新创建")
+--             socket.release(listen_socket)
+            
+--             -- 重新创建监听socket
+--             listen_socket = socket.create(adapter, TASK_NAME)
+--             if not listen_socket then
+--                 log.error("tcp_server_listener_task", "重新创建监听socket失败")
+--                 break
+--             end
+            
+--             socket.config(listen_socket, port)
+--             libnet.listen(TASK_NAME, 0, listen_socket)
+--         end
+        
+--         sys.wait(100)  -- 短暂等待,避免忙循环
+--     end
+    
+--     -- 关闭监听socket
+--     socket.release(listen_socket)
+-- end
+
+-- -- TCP服务器演示函数
+-- function tcp_server_demo(port, adapter)
+--     sysplus.taskInitEx(tcp_server_listener_task, TASK_NAME, netCB, port, adapter)
+-- end
+
+-- -- 订阅接收到的数据
+-- sys.subscribe("TCP_SERVER_RECV", tcp_data_handler)
+
+-- -- 启动TCP服务器(默认端口和适配器)
+-- sys.taskInit(function()
+--     sys.wait(3000)  -- 等待系统初始化
+--     tcp_server_demo(8080, socket.LWIP_ETH)  -- 监听8080端口,使用以太网适配器
+-- end)

+ 87 - 0
module/Air8000/demo/socket/server/tcp/tcp_server_receiver.lua

@@ -0,0 +1,87 @@
+--[[
+@module  tcp_server_receiver
+@summary tcp server socket数据接收应用功能模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为tcp server 数据接收应用功能模块,核心业务逻辑为:
+从内核读取接收到的数据,然后将数据发送给其他应用功能模块做进一步处理;
+
+本文件的对外接口有2个:
+1、tcp_server_receiver.proc(netc):数据接收应用逻辑处理入口,在tcp_server_main.lua中调用;
+2、sys.publish("RECV_DATA_FROM_CLIENT", "recv from tcp server: ", data):
+    将接收到的数据通过消息"RECV_DATA_FROM_CLIENT"发布出去;
+    需要处理数据的应用功能模块订阅处理此消息即可,本demo项目中uart_app.lua中订阅处理了本消息;
+]]
+
+local tcp_server_receiver = {}
+
+-- socket数据接收缓冲区
+local recv_buff = nil
+
+--[[
+检查socket server是否收到数据,如果收到数据,读取并且处理完所有数据
+@api tcp_server_receiver.proc(netc)
+
+@param1 netc userdata
+表示由socket.create接口创建的socket server对象;
+必须传入,不允许为空或者nil;
+
+@return1 result bool
+表示处理结果,成功为true,失败为false
+
+@usage
+-- 示例:处理tcp server接收数据
+tcp_server_receiver.proc(netc)
+]]
+function tcp_server_receiver.proc(netc)
+    -- 如果socket数据接收缓冲区还没有申请过空间,则先申请内存空间
+    if recv_buff==nil then
+        recv_buff = zbuff.create(1024)
+        -- 当recv_buff不再使用时,不需要主动调用recv_buff:free()去释放
+        -- 因为Lua的垃圾处理器会自动释放recv_buff所申请的内存空间
+        -- 如果等不及垃圾处理器自动处理,在确定以后不会再使用recv_buff时,则可以主动调用recv_buff:free()释放内存空间
+    end
+
+    -- 循环从内核的缓冲区读取接收到的数据
+    -- 如果读取失败,返回false,退出循环
+    -- 如果读取成功,处理数据,并且继续循环读取
+    -- 如果读取成功,并且读出来的数据为空,表示已经没有数据可读,返回true,退出循环
+    while true do
+        -- 从内核的缓冲区中读取数据到recv_buff中
+        local succ, param = socket.rx(netc, recv_buff)
+
+        -- 读取数据失败
+        -- 有两种情况:
+        -- 1、recv_buff扩容失败
+        -- 2、socket server和client之间的连接断开
+        if not succ then
+            log.info("tcp_server_receiver.proc", "socket.rx error", param)
+            return false
+        end
+
+        -- 如果读取到了数据, used()就必然大于0, 进行处理
+        if recv_buff:used() > 0 then
+            log.info("tcp_server_receiver.proc", "recv data len", recv_buff:used())
+            
+            -- 读取socket数据接收缓冲区中的数据,赋值给data
+            local data = recv_buff:query()
+
+            log.info("tcp_server_receiver.proc", "recv data", data)
+
+            -- 将数据通过"RECV_DATA_FROM_CLIENT"消息publish出去,给其他应用模块处理
+            sys.publish("RECV_DATA_FROM_CLIENT", data)
+
+            -- 清空socket数据接收缓冲区中的数据
+            recv_buff:del()
+        else
+            -- 读取成功,但是读出来的数据为空,表示已经没有数据可读,可以退出循环了
+            break
+        end
+    end
+
+    return true
+end
+
+return tcp_server_receiver

+ 136 - 0
module/Air8000/demo/socket/server/tcp/tcp_server_sender.lua

@@ -0,0 +1,136 @@
+--[[
+@module  tcp_server_sender
+@summary tcp server socket数据发送应用功能模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为tcp server socket数据发送应用功能模块,核心业务逻辑为:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
+2、tcp_server_main主任务调用tcp_server_sender.proc接口,遍历队列send_queue,逐条发送数据到server;
+3、tcp server socket和server之间的连接如果出现异常,tcp_server_main主任务调用tcp_server_sender.exception_proc接口,丢弃掉队列send_queue中未发送的数据;
+4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
+
+本文件的对外接口有3个:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
+   其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
+   本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
+2、tcp_server_sender.proc:数据发送应用逻辑处理入口,在tcp_server_main.lua中调用;
+3、tcp_server_sender.exception_proc:数据发送应用逻辑异常处理入口,在tcp_server_main.lua中调用;
+]]
+
+local tcp_server_sender = {}
+
+local libnet = require "libnet"
+
+--[[
+数据发送队列,数据结构为:
+{
+    [1] = {data="send from tag: data1", cb=callback_struct1},
+    [2] = {data="send from tag: data2", cb=callback_struct2},
+}
+data的内容为带发送方标识前缀的实际数据,必须存在;
+ip为目标IP地址,可以不存在;
+port为目标端口号,可以不存在;
+cb为用户回调函数结构,可以不存在;
+]]
+local send_queue = {}
+
+-- tcp_server_main的任务名
+tcp_server_sender.TASK_NAME = "tcp_server_main"
+
+-- "SEND_DATA_REQ"消息的处理函数
+local function send_data_req_proc_func(tag, data, cb)
+    -- 将原始数据增加前缀,然后插入到发送队列send_queue中
+    table.insert(send_queue, {data="send from "..tag..": "..data, cb=cb})
+    -- 通知tcp_server_main主任务有数据需要发送
+    -- tcp_server_main主任务如果处在libnet.wait调用的阻塞等待状态,就会退出阻塞状态
+    sys.sendMsg(tcp_server_sender.TASK_NAME, socket.EVENT, 0)
+end
+
+--[[
+检查socket server是否需要发送数据,如果需要发送数据,读取并且发送完发送队列中的所有数据
+
+@api tcp_server_sender.proc(task_name, socket_server)
+
+@param1 task_name string
+表示socket.create接口创建socket server对象时所处的task的name;
+必须传入,不允许为空或者nil;
+
+@param2 socket_server userdata
+表示由socket.create接口创建的socket server对象;
+必须传入,不允许为空或者nil;
+
+@return1 result bool
+表示处理结果,成功为true,失败为false
+
+@usage
+tcp_server_sender.proc("tcp_server_main", socket_server)
+]]
+function tcp_server_sender.proc(task_name, netc)
+    local send_item
+    local result, buff_full
+
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        -- 取出来第一条数据赋值给send_item
+        -- 同时从队列send_queue中删除这一条数据
+        send_item = table.remove(send_queue,1)
+
+        -- 发送这条数据,超时时间15秒钟
+        result, buff_full = libnet.tx(task_name, 15000, netc, send_item.data)
+
+        -- 检查发送结果
+        if not result then
+            log.error("tcp_server_sender.proc", "libnet.tx error")
+            
+            -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
+            if send_item.cb and send_item.cb.func then
+                send_item.cb.func(false, send_item.cb.para)
+            end
+            
+            return false
+        end
+        
+        -- 如果内核固件中缓冲区满了,则将send_item再次插入到send_queue的队首位置,等待下次尝试发送
+        if buff_full then
+            log.error("tcp_client_sender.proc", "buffer is full, wait for the next time")
+            table.insert(send_queue, 1, send_item)
+            return true
+        end
+
+        log.info("tcp_server_sender.proc", "send success")
+        -- 发送成功,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(true, send_item.cb.para)
+        end
+    end
+
+    return true
+end
+
+--[[
+socket server连接出现异常时,清空等待发送的数据,并且执行发送方的回调函数
+
+@api tcp_server_sender.exception_proc()
+
+@usage
+tcp_server_sender.exception_proc()
+]]
+function tcp_server_sender.exception_proc()
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        local send_item = table.remove(send_queue,1)
+        -- 发送失败,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(false, send_item.cb.para)
+        end
+    end
+end
+
+-- 订阅"SEND_DATA_REQ"消息;
+-- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
+-- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
+sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
+
+return tcp_server_sender

+ 71 - 0
module/Air8000/demo/socket/server/timer_app.lua

@@ -0,0 +1,71 @@
+--[[
+@module  timer_app
+@summary 定时器应用功能模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为定时器应用功能模块,核心业务逻辑为:
+创建一个5秒的循环定时器,每次产生一段数据,通知TCP或UDP server进行处理;
+
+本文件的对外接口有一个:
+1、sys.publish("SEND_DATA_REQ", "timer", data, ip, port, {func=send_data_cbfunc, para="timer"..data}),通过publish通知TCP或UDP server数据发送功能模块发送data数据;
+    数据发送结果通过执行回调函数send_data_cbfunc通知本功能模块;
+]]
+
+local config = {
+    enable_udp = true,            -- 是否启用UDP发送
+    enable_tcp = false             -- 是否启用TCP发送
+}
+
+local data = 1
+
+local udp_server_receiver = require "udp_server_receiver"
+
+-- 数据发送结果回调函数
+-- result:发送结果,true为发送成功,false为发送失败
+-- para:回调参数,sys.publish("SEND_DATA_REQ", "timer", data, ip, port, {func=send_data_cbfunc, para="timer"..data})中携带的para
+local function send_data_cbfunc(result, para)
+    log.info("send_data_cbfunc", result, para)
+    -- 无论上一次发送成功还是失败,启动一个5秒的定时器,5秒后发送下次数据
+    sys.timerStart(send_data_req_timer_cbfunc, 5000)
+end
+
+-- 定时器回调函数
+function send_data_req_timer_cbfunc()
+    -- 发布消息"SEND_DATA_REQ"
+    -- 携带的第一个参数"timer"表示是定时器应用模块发布的消息
+    -- 携带的第二个参数data为要发送的原始数据
+    -- 携带的第三个参数client_ip为目标IP地址
+    -- 携带的第四个参数port为目标端口号
+    -- 携带的第五个参数cb为发送结果回调(可以为空,如果为空,表示不关心TCP或UDP server发送数据成功还是失败),其中:
+    --       cb.func为回调函数(可以为空,如果为空,表示不关心TCP或UDP server发送数据成功还是失败)
+    --       cb.para为回调函数的第二个参数(可以为空),回调函数的第一个参数为发送结果(true表示成功,false表示失败)
+
+    -- UDP发送处理
+    if config.enable_udp then
+        -- 获取客户端信息
+        local client_info = udp_server_receiver.get_client_info()
+        
+        -- 检查是否有客户端IP和端口
+        if client_info.ip and client_info.port then
+            -- 使用记录的客户端信息发送
+            sys.publish("SEND_DATA_REQ", "timer", data, client_info.ip, client_info.port, {func=send_data_cbfunc, para="udp_timer"..data})
+        else
+            -- 未收到过客户端数据,提示错误
+            log.error("timer_app", "尚未收到客户端数据, 无法确定目标IP和端口")
+            sys.timerStart(send_data_req_timer_cbfunc, 5000)
+        end
+        -- TCP发送处理
+    elseif config.enable_tcp then
+        -- 当前TCP server与client是一对一连接,publish的消息可忽略ip和port参数
+        sys.publish("SEND_DATA_REQ", "timer", data, {func=send_data_cbfunc, para="tcp_timer"..data})  
+    end
+
+    data = data + 1
+    log.info("send_data_req_timer_cbfunc", data)
+end
+
+-- 启动一个5秒的单次定时器
+-- 时间到达后,执行一次send_data_req_timer_cbfunc函数
+sys.timerStart(send_data_req_timer_cbfunc, 5000)

+ 101 - 0
module/Air8000/demo/socket/server/uart_app.lua

@@ -0,0 +1,101 @@
+--[[
+@module  uart_app
+@summary 串口应用功能模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为串口应用功能模块,核心业务逻辑为:
+1、打开uart1,波特率115200,数据位8,停止位1,无奇偶校验位;
+2、uart1和pc端的串口工具相连;
+3、从uart1接收到pc端串口工具发送的数据后,通知TCP或UDP server进行处理;
+4、收到TCP或UDP server从client接收到的数据后,将数据通过uart1发送到pc端串口工具;
+
+本文件的对外接口有两个:
+1、sys.publish("SEND_DATA_REQ", "uart", read_buf, client_ip, port),通过publish通知TCP或UDP server数据发送功能模块发送read_buf数据,不关心数据发送成功还是失败;
+2、sys.subscribe("RECV_DATA_FROM_CLIENT", recv_data_from_client_proc),订阅RECV_DATA_FROM_CLIENT消息,处理消息携带的数据;
+]]
+
+
+-- 使用UART1
+local UART_ID = 1
+-- 串口接收数据缓冲区
+local read_buf = ""
+
+local config = {
+    enable_udp = true,              -- 是否启用UDP发送
+    enable_tcp = false               -- 是否启用TCP发送
+}
+
+-- 加载UDP服务器数据接收功能模块
+local udp_server_receiver = require "udp_server_receiver"
+
+-- 将前缀prefix和数据data拼接
+-- 然后末尾增加回车换行两个字符,通过uart发送出去,方便在PC端换行显示查看
+local function recv_data_from_client_proc(data)
+    log.info("uart_app.recv_data_from_client_proc", data)
+    uart.write(UART_ID, data.."\r\n")
+end
+
+local function concat_timeout_func()
+    -- 如果存在尚未处理的串口缓冲区数据;
+    -- 将数据通过publish通知其他应用功能模块处理;
+    -- 然后清空本文件的串口缓冲区数据
+    if read_buf:len() > 0 then
+        if config.enable_udp then
+            -- 获取客户端信息
+            local client_info = udp_server_receiver.get_client_info()
+            -- 检查是否有客户端IP和端口
+            if client_info.ip and client_info.port then
+                -- 使用记录的客户端信息
+                sys.publish("SEND_DATA_REQ", "uart", read_buf, client_info.ip, client_info.port)
+            else
+                -- 未收到过客户端数据,提示错误
+                log.error("uart_app", "尚未收到客户端数据,无法确定目标IP和端口")
+            end
+        elseif config.enable_tcp then
+            -- 当前TCP server与client是一对一连接,publish的消息可忽略ip和port参数
+            sys.publish("SEND_DATA_REQ", "uart", read_buf)
+        end
+
+        read_buf = ""
+    end
+end
+
+
+-- UART1的数据接收中断处理函数,UART1接收到数据时,会执行此函数
+local function read()
+    local s
+    while true do
+        -- 非阻塞读取UART1接收到的数据,最长读取1024字节
+        s = uart.read(UART_ID, 1024)
+        
+        -- 如果从串口没有读到数据
+        if not s or s:len() == 0 then
+            -- 启动50毫秒的定时器,如果50毫秒内没收到新的数据,则处理当前收到的所有数据
+            -- 这样处理是为了防止将一大包数据拆分成多个小包来处理
+            -- 例如pc端串口工具下发1100字节的数据,可能会产生将近20次的中断进入到read函数,才能读取完整
+            -- 此处的50毫秒可以根据自己项目的需求做适当修改,在满足整包拼接完整的前提下,时间越短,处理越及时
+            sys.timerStart(concat_timeout_func, 50)
+            -- 跳出循环,退出本函数
+            break
+        end
+
+        log.info("uart_app.read len", s:len())
+        -- log.info("uart_app.read", s)
+
+        -- 将本次从串口读到的数据拼接到串口缓冲区read_buf中
+        read_buf = read_buf..s
+    end
+end
+
+-- 初始化UART1,波特率115200,数据位8,停止位1
+uart.setup(UART_ID, 115200, 8, 1)
+
+-- 注册UART1的数据接收中断处理函数,UART1接收到数据时,会执行read函数
+uart.on(UART_ID, "receive", read)
+
+-- 订阅"RECV_DATA_FROM_CLIENT"消息的处理函数recv_data_from_client_proc
+-- 收到"RECV_DATA_FROM_CLIENT"消息后,会执行函数recv_data_from_client_proc   
+sys.subscribe("RECV_DATA_FROM_CLIENT", recv_data_from_client_proc)
+

+ 112 - 0
module/Air8000/demo/socket/server/udp/udp_server_main.lua

@@ -0,0 +1,112 @@
+--[[
+@module  udp_server_main
+@summary udp server 主应用功能模块 
+@version 1.0
+@date    2025.09.16
+@author  王世豪
+@usage
+本文件为udp server 主应用功能模块,核心业务逻辑为:
+1、创建一个udp server,监听指定端口;
+2、处理通信异常,出现异常后,重新初始化UDP服务以恢复正常数据接收;
+3、调用udp_server_receiver和udp_server_sender中的外部接口,进行数据收发处理;
+
+本文件没有对外接口,直接在main.lua中require "udp_server_main"就可以加载运行;
+]]
+
+local udpsrv = require "udpsrv"
+
+-- 加载UDP服务器数据接收功能模块
+local udp_server_receiver = require "udp_server_receiver"
+-- 加载UDP服务器数据发送功能模块
+local udp_server_sender = require "udp_server_sender"
+
+-- 服务器监听端口
+local SERVER_PORT = 50003
+-- 服务器主题(用于接收消息)
+SERVER_TOPIC = "udp_server"
+
+-- udp server socket的任务处理函数
+local function udp_server_main_task_func() 
+    local udp_server
+    local ret, data, remote_ip, remote_port
+
+    while true do
+        -- 如果当前时间点设置的网卡还没有连接成功,一直在这里循环等待
+        while not socket.adapter(socket.dft()) do
+            log.warn("udp_client_main_task_func", "wait IP_READY", socket.dft())
+            -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
+            -- 或者等待1秒超时退出阻塞等待状态;
+            -- 注意:此处的1000毫秒超时不要修改的更长;
+            -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
+            -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
+            -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
+            sys.waitUntil("IP_READY", 1000)
+        end
+
+        -- 检测到了IP_READY消息
+        log.info("udp_server_main_task_func", "recv IP_READY", socket.dft())
+
+        -- 创建UDP服务器对象
+        -- 注意:udpsrv.create有3个参数,最后一个参数是网络适配器编号
+        udp_server = udpsrv.create(SERVER_PORT, SERVER_TOPIC, socket.dft())
+
+        if not udp_server then
+            log.error("udp_server_main_task_func", "udpsrv.create error")
+            goto EXCEPTION_PROC
+        end
+
+        log.info("udp_server_main_task_func", "UDP server started on port", SERVER_PORT)
+
+        -- 发送一条广播消息,通知端口号为50000的客户端,UDP服务器已启动
+        udp_server:send("UDP Server is UP", "255.255.255.255", 50000)
+
+        -- 数据收发以及网络连接异常事件总处理逻辑
+        while true do
+            -- 数据发送处理
+            if not udp_server_sender.proc(udp_server) then
+                log.error("udp_server_main_task_func", "udp_server_sender.proc error")
+            end
+
+            -- 等待接收数据事件
+            ret, data, remote_ip, remote_port = sys.waitUntil(SERVER_TOPIC, 15000)
+
+            if ret then
+                -- 判断是否是发送就绪事件(通过 data 内容或 remote_ip 是否为 nil)
+                if data == "SEND_READY" and remote_ip == nil then
+                    -- 这是发送就绪事件,无需处理接收数据,直接继续循环以发送数据
+                    log.info("udp_server_main_task_func", "send ready event received")
+                -- 网络异常事件
+                elseif data == "SOCKET_CLOSED" then
+                    goto EXCEPTION_PROC
+                else
+                    -- 真实接收到的数据
+                    if not udp_server_receiver.proc(data, remote_ip, remote_port) then
+                        log.error("udp_server_main_task_func", "udp_server_receiver.proc error")
+                    end
+                end
+            else
+                -- 超时,发送一条心跳广播
+                log.info("udp_server_main_task_func", "No data received, sending broadcast heartbeat")
+                udp_server:send("UDP Server Heartbeat", "255.255.255.255", 50000)
+            end
+        end
+
+        ::EXCEPTION_PROC::
+
+        -- 数据发送应用模块对来不及发送的数据做清空和通知失败处理
+        udp_server_sender.exception_proc()
+
+        -- 关闭UDP服务器
+        if udp_server then
+            udp_server:close()
+            udp_server = nil
+        end
+        
+        -- 5秒后跳转到循环体开始位置,重建udp server
+        sys.wait(5000)
+    end
+end
+
+--创建并且启动一个task
+--运行这个task的主函数udp_server_main_task_func
+sys.taskInit(udp_server_main_task_func)

+ 83 - 0
module/Air8000/demo/socket/server/udp/udp_server_receiver.lua

@@ -0,0 +1,83 @@
+--[[
+@module  udp_server_receiver
+@summary udp server socket数据接收应用功能模块 
+@version 1.0
+@date    2025.09.16
+@author  王世豪
+@usage
+本文件为udp server socket数据接收应用功能模块,核心业务逻辑为:
+从内核读取接收到的数据,然后将数据发送给其他应用功能模块做进一步处理;
+
+本文件的对外接口有2个:
+1、udp_server_receiver.proc(socket_server):数据接收应用逻辑处理入口,在udp_server_main.lua中调用;
+2、sys.publish("RECV_DATA_FROM_CLIENT", data, remote_ip, remote_port):
+    将接收到的数据通过消息"RECV_DATA_FROM_CLIENT"发布出去;
+    需要处理数据的应用功能模块订阅处理此消息即可;
+]]
+
+local udp_server_receiver = {}
+
+-- 客户端信息
+local client_info = {}
+-- 标记是否已经通知过客户端信息更新
+local client_info_notified = false
+
+-- 获取客户端信息
+function udp_server_receiver.get_client_info()
+    return client_info
+end
+
+-- 重置客户端信息
+function udp_server_receiver.reset_client_info()
+    client_info.ip = nil
+    client_info.port = nil
+    -- 重置通知标记,以便下次收到客户端信息时可以重新通知
+    client_info_notified = false
+end
+
+-- 初始化客户端信息
+udp_server_receiver.reset_client_info()
+
+--[[
+检查udp server是否收到数据,如果收到数据,读取并且处理完所有数据
+
+@api udp_server_receiver.proc(data, remote_ip, remote_port)
+
+@param1 data string
+表示接收到的数据;
+
+@param2 remote_ip string
+表示发送数据的client的IP地址;
+
+@param3 remote_port number
+表示发送数据的client的端口号;
+
+@return1 result bool
+表示处理结果,成功为true,失败为false
+
+@usage
+udp_server_receiver.proc(data, remote_ip, remote_port)
+]]
+function udp_server_receiver.proc(data, remote_ip, remote_port)
+    log.info("udp_server_receiver.proc", "收到数据", data, "来自", remote_ip, remote_port)
+    
+    -- -- 更新客户端信息
+    -- local info_changed = (client_info.ip ~= remote_ip or client_info.port ~= remote_port)
+    client_info.ip = remote_ip
+    client_info.port = remote_port
+    -- -- 在客户端信息发生变化时发布通知
+    -- if info_changed and not client_info_notified then
+    --     -- 发布消息通知其他模块客户端信息已更新
+    --     sys.publish("UDP_CLIENT_INFO_UPDATED")
+    --     client_info_notified = true
+    -- end
+
+    log.info("client_info", client_info.ip, client_info.port)
+
+    -- 将接收到的数据通过消息发布出去
+    sys.publish("RECV_DATA_FROM_CLIENT", data, remote_ip, remote_port)
+    
+    return true
+end
+
+return udp_server_receiver

+ 115 - 0
module/Air8000/demo/socket/server/udp/udp_server_sender.lua

@@ -0,0 +1,115 @@
+--[[
+@module  udp_server_sender
+@summary udp server socket数据发送应用功能模块 
+@version 1.0
+@date    2025.09.15
+@author  王世豪
+@usage
+本文件为udp server socket数据发送应用功能模块,核心业务逻辑为:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)订阅"SEND_DATA_REQ"消息,将其他应用模块需要发送的数据存储到队列send_queue中;
+2、udp_server_main主任务调用udp_server_sender.proc接口,遍历队列send_queue,逐条发送数据到client;
+3、udp server socket如果出现异常,udp_server_main主任务调用udp_server_sender.exception_proc接口,丢弃掉队列send_queue中未发送的数据;
+4、任何一条数据无论发送成功还是失败,只要这条数据有回调函数,都会通过回调函数通知数据发送方;
+
+本文件的对外接口有3个:
+1、sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func):订阅"SEND_DATA_REQ"消息;
+   其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据、目标IP、目标端口以及回调函数和回调参数一起publish出去;
+2、udp_server_sender.proc:数据发送应用逻辑处理入口,在udp_server_main.lua中调用;
+3、udp_server_sender.exception_proc:数据发送应用逻辑异常处理入口,在udp_server_main.lua中调用;
+]]
+
+local udp_server_sender = {}
+
+--[[
+数据发送队列,数据结构为:
+{
+    [1] = {data="data1", ip="127.0.0.1", port=8888, cb={func=callback_function1, para=callback_para1}},
+    [2] = {data="data2", ip="127.0.0.1", port=8888, cb={func=callback_function2, para=callback_para2}},
+}
+data的内容为真正要发送的数据,必须存在;
+ip的内容为目标IP,必须存在;
+port的内容为目标端口,必须存在;
+func的内容为数据发送结果的用户回调函数,可以不存在
+para的内容为数据发送结果的用户回调函数的回调参数,可以不存在;
+]]
+local send_queue = {}
+
+-- "SEND_DATA_REQ"消息的处理函数
+local function send_data_req_proc_func(tag, data, ip, port, cb)
+    -- 将原始数据增加前缀,然后插入到发送队列send_queue中
+    table.insert(send_queue, {data="send from "..tag..": "..data, ip=ip, port=port, cb=cb}) 
+    log.info("send_queue", #send_queue)
+    -- 通知主任务:有数据待发送,唤醒阻塞
+    sys.publish("udp_server", "SEND_READY", nil, nil)  -- 后两个参数为 remote_ip 和 remote_port,这里置为 nil
+end
+
+--[[
+检查udp server是否需要发送数据,如果需要发送数据,读取并且发送完发送队列中的所有数据
+
+@api udp_server_sender.proc(udp_server)
+
+@param 
+表示由udpsrv.create接口创建的udp_server对象;
+必须传入,不允许为空或者nil;
+
+@return1 result bool
+表示处理结果,成功为true,失败为false
+
+@usage
+udp_server_sender.proc(udp_server)
+]]
+function udp_server_sender.proc(udp_server)
+    local send_item
+    local result
+
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        -- 取出来第一条数据赋值给send_item
+        -- 同时从队列send_queue中删除这一条数据
+        send_item = table.remove(send_queue,1)
+
+        result = udp_server:send(send_item.data, send_item.ip, send_item.port)
+
+        -- 发送失败
+        if not result then
+            log.error("udp_server_sender.proc", "udp_server:send error")
+
+            -- 如果当前发送的数据有用户回调函数,则执行用户回调函数
+            if send_item.cb and send_item.cb.func then
+                send_item.cb.func(false, send_item.cb.para)
+            end
+
+            return false
+        end
+
+        log.info("udp_server_sender.proc", "send success", send_item.ip, send_item.port)
+        -- 发送成功,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(true, send_item.cb.para)
+        end
+    end
+
+    return true
+end
+
+-- UDP服务器出现异常时,清空等待发送的数据,并且执行发送方的回调函数
+function udp_server_sender.exception_proc()
+    -- 遍历数据发送队列send_queue
+    while #send_queue>0 do
+        local send_item = table.remove(send_queue,1)
+        -- 发送失败,如果当前发送的数据有用户回调函数,则执行用户回调函数
+        if send_item.cb and send_item.cb.func then
+            send_item.cb.func(false, send_item.cb.para)
+        end
+    end
+end
+
+-- 订阅"SEND_DATA_REQ"消息;
+-- 其他应用模块如果需要发送数据,直接sys.publish这个消息即可,将需要发送的数据以及回调函数和回调参数一起publish出去;
+-- 参数格式: sys.publish("SEND_DATA_REQ", tag, data, ip, port, cb)
+-- tag: 发送方标识, data: 要发送的数据, ip: 目标IP, port: 目标端口, cb: 回调函数
+-- 例如: sys.publish("SEND_DATA_REQ", "app1", "hello client", "192.168.1.100", 50000)
+-- 本demo项目中uart_app.lua和timer_app.lua中publish了这个消息;
+sys.subscribe("SEND_DATA_REQ", send_data_req_proc_func)
+
+return udp_server_sender

+ 6 - 5
module/Air8000/project/sms_call_forward/main.lua

@@ -7,11 +7,12 @@
 @usage
 1. 详细逻辑请看cc_forward文件和sms_forward文件
 2. netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(四选一)
-   (1) netdrv_4g:4G网卡
-   (2) netdrv_wifi:WIFI STA网卡
-   (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
-   (4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
-   (5) netdrv_pc:pc模拟器上的网卡
+    (1) netdrv_4g:4G网卡
+    (2) netdrv_wifi:WIFI STA网卡
+    (3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
+    (4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
+    (5) netdrv_pc: pc模拟器网卡
+3. sntp_app:启动sntp时间同步功能模块,同步网络时间
 
 ]]
 

+ 17 - 3
module/Air8000/project/sms_call_forward/readme.md

@@ -4,7 +4,7 @@
 
 1、main.lua:主程序入口文件,加载以下 4个文件运行。
 
-2、netdrv_multiple.lua:网卡驱动配置文件,可以配置以太网卡,wifi 网卡,单 4g 网卡三种网卡的使用优先级
+2、netdrv_device.lua:网卡驱动设备,可以配置使用netdrv文件夹内的四种网卡(单4g网卡,单wifi网卡,单spi以太网卡,多网卡)中的任何一种网卡;
 
 3、sms_forward.lua: 短信转发功能模块文件
 
@@ -34,6 +34,22 @@
 
 4、cc_forward(),来电号码信息转发到指定机器人
 
+**netdrv_device:**
+
+短信通过http转发到企业微信/钉钉/飞书平台时,配置连接外网使用的网卡,目前支持以下四种选择(四选一)
+
+(1) netdrv_4g:4G网卡
+
+(2) netdrv_wifi:WIFI STA网卡
+
+(3) netdrv_eth_spi:通过SPI外挂CH390H芯片的以太网卡
+
+(4) netdrv_multiple:支持以上三种网卡,可以配置三种网卡的优先级
+
+
+
+
+
 ## 演示硬件环境:
 
 ![8000w](https://docs.openluat.com/air8000/luatos/app/image/netdrv_multi.jpg)
@@ -352,5 +368,3 @@ netdrv文件夹
 [2025-10-24 18:55:23.764][000000078.694] D/mobile LUAT_MOBILE_EVENT_CC status 10
 
 ```
-
-

+ 1 - 1
module/Air8101/demo/accessory_board/AirETH_1000/http/main.lua

@@ -9,7 +9,7 @@
 1、http_app:普通的http get请求功能演示
 2、netdrv_device:配置连接外网使用的网卡,目前支持以下四种选择(四选一)
     (1) netdrv_wifi:socket.LWIP_STA,WIFI STA网卡;
-    (2) netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+    (2) netdrv_eth_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
     (3) netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
     (4) netdrv_pc:pc模拟器上的网卡
 更多说明参考本目录下的readme.md文件

+ 39 - 59
module/Air8101/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_eth_spi.lua

@@ -28,30 +28,27 @@ Air8101核心板通过TYPE-C USB口供电(核心板背面的功耗测试开关
 
 local exnetif = require "exnetif"
 
-local function ip_ready_func(ip, adapter)
-    if adapter == socket.LWIP_USER1 then
-        log.info("netdrv_eth_spi.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_USER1))
+local function ip_ready_func(ip, adapter)    
+    if adapter == socket.LWIP_ETH then
+        -- 在位置1和2设置自定义的DNS服务器ip地址:
+        -- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
+        -- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
+        -- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
+        -- 如果使用专网卡,不要使用这两行代码;
+        -- 如果使用国外的网络,不要使用这两行代码;
+        socket.setDNS(adapter, 1, "223.5.5.5")
+        socket.setDNS(adapter, 2, "114.114.114.114")
+
+        log.info("netdrv_eth_spi.ip_ready_func", "IP_READY", socket.localIP(socket.LWIP_ETH))
     end
 end
 
-local function ip_lose_func(adapter)
-    if adapter == socket.LWIP_USER1 then
+local function ip_lose_func(adapter)    
+    if adapter == socket.LWIP_ETH then
         log.warn("netdrv_eth_spi.ip_lose_func", "IP_LOSE")
     end
 end
 
-
--- 此处订阅"IP_READY"和"IP_LOSE"两种消息
--- 在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
--- 也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
-sys.subscribe("IP_READY", ip_ready_func)
-sys.subscribe("IP_LOSE", ip_lose_func)
-
-
--- 设置默认网卡为socket.LWIP_USER1
-socket.dft(socket.LWIP_USER1)
-
-
 -- 本demo测试使用的是核心板的VDD 3V3引脚对AirETH_1000配件板进行供电
 -- VDD 3V3引脚是Air8101内部的LDO输出引脚,最大输出电流300mA
 -- GPIO13在Air8101内部使能控制这个LDO的输出
@@ -59,49 +56,32 @@ socket.dft(socket.LWIP_USER1)
 gpio.setup(13, 1, gpio.PULLUP)
 
 
--- 这个task的核心业务逻辑是:初始化SPI,初始化以太网卡,并在以太网卡上开启动态主机配置协议
-local function netdrv_eth_spi_task_func()
-    -- 初始化SPI0
-    local result = exnetif.set_priority_order({
-    {
-        ETHUSER1 = {
-                    -- 供电使能GPIO
-                    pwrpin = 140,
-                    -- 设置的多个“已经IP READY,但是还没有ping通”网卡,循环执行ping动作的间隔(单位毫秒,可选)
-                    -- 如果没有传入此参数,exnetif会使用默认值10秒
-                    ping_time = 3000,
-
-                    -- 连通性检测ip(选填参数);
-                    -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;
-                    -- 如果传入,一定要传入可靠的并且可以ping通的ip地址;
-                    -- ping_ip = "填入可靠的并且可以ping通的ip地址",
-
-                    -- 网卡芯片型号(选填参数),仅spi方式外挂以太网时需要填写。
-                    tp = netdrv.CH390,
-                    opts = {spi=0, cs=15}
-        }
-    }
-})
-
-    -- 初始化以太网卡
+-- 以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
+-- 各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
 
-    -- 以太网联网成功(成功连接路由器,并且获取到了IP地址)后,内核固件会产生一个"IP_READY"消息
-    -- 各个功能模块可以订阅"IP_READY"消息实时处理以太网联网成功的事件
-    -- 也可以在任何时刻调用socket.adapter(socket.LWIP_USER1)来获取以太网是否连接成功
+-- 以太网断网后,内核固件会产生一个"IP_LOSE"消息
+-- 各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
+-- 也可以在任何时刻调用socket.adapter(socket.LWIP_ETH)来获取以太网是否连接成功
 
-    -- 以太网断网后,内核固件会产生一个"IP_LOSE"消息
-    -- 各个功能模块可以订阅"IP_LOSE"消息实时处理以太网断网的事件
-    -- 也可以在任何时刻调用socket.adapter(socket.LWIP_USER1)来获取以太网是否连接成功
-
-    -- socket.LWIP_USER1 指定网络适配器编号
-    -- netdrv.CH390外挂CH390
-    -- SPI ID 0, 片选 GPIO15
-    netdrv.setup(socket.LWIP_USER1, netdrv.CH390, {spi=0, cs=15})
+--此处订阅"IP_READY"和"IP_LOSE"两种消息
+--在消息的处理函数中,仅仅打印了一些信息,便于实时观察“通过SPI外挂CH390H芯片的以太网卡”的连接状态
+--也可以根据自己的项目需求,在消息处理函数中增加自己的业务逻辑控制,例如可以在连网状态发生改变时更新网络图标
+sys.subscribe("IP_READY", ip_ready_func)
+sys.subscribe("IP_LOSE", ip_lose_func)
 
-    -- 在以太上开启动态主机配置协议
-    netdrv.dhcp(socket.LWIP_USER1, true)
-end
 
--- 创建并且启动一个task
--- task的处理函数为netdrv_eth_spi_task_func
-sys.taskInit(netdrv_eth_spi_task_func)
+-- 配置SPI外接以太网芯片CH390H的单网卡,exnetif.set_priority_order使用的网卡编号为socket.LWIP_ETH
+-- 本demo使用Air8101核心板测试,开发板上的硬件配置为:
+-- GPIO13为CH390H以太网芯片的供电使能控制引脚
+-- 使用spi0,片选引脚使用GPIO15
+-- 如果使用的硬件不是Air8101核心板,根据自己的硬件配置修改以下参数
+exnetif.set_priority_order({
+    {
+        ETHUSER1  = {
+            pwrpin = 13, 
+            tp = netdrv.CH390,
+            opts = {spi = 0, cs = 15}
+        }
+    }
+})

+ 13 - 11
module/Air8101/demo/accessory_board/AirETH_1000/http/netdrv/netdrv_multiple.lua

@@ -1,6 +1,6 @@
 --[[
 @module  netdrv_multiple
-@summary 多网卡(WIFI STA网卡、通过MAC层的rmii接口外挂PHY芯片(LAN8720Ai)的以太网卡、通过SPI外挂CH390H芯片的以太网卡、通过SPI外挂4G模组的4G网卡)驱动模块
+@summary 多网卡(WIFI STA网卡、通过SPI外挂CH390H芯片的以太网卡)驱动模块 
 @version 1.0
 @date    2025.07.24
 @author  王城钧
@@ -22,15 +22,9 @@ Air8101核心板通过TYPE-C USB口供电(核心板背面的功耗测试开关
 | 57/DE           | SDI               |
 | 14/GPIO8        | INT               |
 
-
-通过SPI接口外挂4G模组(Air780EHM/Air780EHV/Air780EGH/Air780EPM)的4G网卡:
-Air8101核心板和Air780EHM/Air780EHV/Air780EGH/Air780EPM核心板或者开发板的硬件接线方式,参考netdrv_4g.lua的文件头注释;
-
-
 本文件没有对外接口,直接在其他功能模块中require "netdrv_multiple"就可以加载运行;
 ]]
 
-
 local exnetif = require "exnetif"
 
 -- 网卡状态变化通知回调函数
@@ -42,6 +36,14 @@ local exnetif = require "exnetif"
 --     net_type:为nil
 --     adapter:number类型,为-1
 local function netdrv_multiple_notify_cbfunc(net_type,adapter)
+    -- 在位置1和2设置自定义的DNS服务器ip地址:
+    -- "223.5.5.5",这个DNS服务器IP地址是阿里云提供的DNS服务器IP地址;
+    -- "114.114.114.114",这个DNS服务器IP地址是国内通用的DNS服务器IP地址;
+    -- 可以加上以下两行代码,在自动获取的DNS服务器工作不稳定的情况下,这两个新增的DNS服务器会使DNS服务更加稳定可靠;
+    -- 如果使用专网卡,不要使用这两行代码;
+    -- 如果使用国外的网络,不要使用这两行代码;
+    socket.setDNS(adapter, 1, "223.5.5.5")
+    socket.setDNS(adapter, 2, "114.114.114.114")
     if type(net_type)=="string" then
         log.info("netdrv_multiple_notify_cbfunc", "use new adapter", net_type, adapter)
     elseif type(net_type)=="nil" then
@@ -52,11 +54,11 @@ local function netdrv_multiple_notify_cbfunc(net_type,adapter)
 end
 
 
+
 local function netdrv_multiple_task_func()
     --设置网卡优先级
     exnetif.set_priority_order(
         {
-
             -- “通过SPI外挂CH390H芯片”的以太网卡,可以使用Air8101核心板+AirETH_1000配件板验证
             {
                 ETHUSER1 = {
@@ -77,13 +79,13 @@ local function netdrv_multiple_task_func()
                 }
             },
 
-            -- WIFI STA网卡
+            -- -- WIFI STA网卡
             {
                 WIFI = {
                     -- 要连接的WIFI路由器名称
-                    ssid = "iPhone",
+                    ssid = "茶室-降功耗,找合宙!",
                     -- 要连接的WIFI路由器密码
-                    password = "HZ88888888", 
+                    password = "Air123456", 
 
                     -- 连通性检测ip(选填参数);
                     -- 如果没有传入ip地址,exnetif中会默认使用httpdns能否成功获取baidu.com的ip作为是否连通的判断条件;

+ 2 - 2
module/Air8101/demo/accessory_board/AirETH_1000/http/netdrv_device.lua

@@ -7,7 +7,7 @@
 @usage
 本文件为网络驱动设备功能模块,核心业务逻辑为:根据项目需求,选择并且配置合适的网卡(网络适配器)
 1、netdrv_wifi:socket.LWIP_STA,WIFI STA网卡;
-2、netdrv_ethernet_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
+2、netdrv_eth_spi:socket.LWIP_ETH,通过SPI外挂CH390H芯片的以太网卡;
 3、netdrv_multiple:可以配置多种网卡的优先级,按照优先级配置,使用其中一种网卡连接外网;
 4、netdrv_pc:pc模拟器上的网卡
 
@@ -24,7 +24,7 @@
 -- require "netdrv_wifi"
 
 -- 加载“通过SPI外挂CH390H芯片的以太网卡”驱动模块
-require "netdrv_eth_spi"
+require "netdrv_eth_spi" 
 
 -- 加载“可以配置优先级的多种网卡”驱动模块
 -- require "netdrv_multiple"

+ 9 - 11
module/Air8101/demo/accessory_board/AirETH_1000/http/readme.md

@@ -26,15 +26,15 @@
 
 3、Air8101核心板和AirETH_1000配件板的硬件接线方式为:
 
-| Air8101核心板 | AirETH_1000配件板 |
-| ---------- | -------------- |
-| vdd        | 3.3v           |
-| gnd        | gnd            |
-| spi1_sclk  | SCK            |
-| spi1_cs    | CSS            |
-| spi1_miso  | SDO            |
-| spi1_mosi  | SDI            |
-| gpio21     | INT            |
+| Air8101核心板 | AirETH_1000配件板                  |
+| ---------- | ------------------------------- |
+| 59/3V3     | 3.3v                            |
+| gnd        | gnd                             |
+| 28/DCLK    | SCK                             |
+| 54/DISP    | CSS                             |
+| 55/HSYN    | SDO                             |
+| 57/DE      | SDI                             |
+| 14/GPIO8   | INT |
 
 演示软件环境
 
@@ -76,5 +76,3 @@
 
 
 ```
-
-

+ 5 - 5
module/Air8101/demo/accessory_board/AirETH_1000/network_routing/wifi_out_ethernet_in_wifi_in/netif_app.lua

@@ -56,11 +56,11 @@ function netif_app_task_func()
         log.info("开启失败,请检查配置项是否正确,日志中是否打印了错误信息")
     end
     -- 每5秒进行HTTPS连接测试,实时监测wifi网络连接状态, 仅供测试需要,量产不需要,用来判断当前网络是否可用,需要的话可以打开注释
-    while 1 do
-        local code, headers, body = http.request("GET", "https://httpbin.air32.cn/bytes/2048", nil, nil, {adapter=socket.LWIP_STA,timeout=5000,debug=false}).wait()
-        log.info("http执行结果", code, headers, body and #body)
-        sys.wait(5000)
-    end
+    -- while 1 do
+    --     local code, headers, body = http.request("GET", "https://httpbin.air32.cn/bytes/2048", nil, nil, {adapter=socket.LWIP_STA,timeout=5000,debug=false}).wait()
+    --     log.info("http执行结果", code, headers, body and #body)
+    --     sys.wait(5000)
+    -- end
 end
 
 sys.taskInit(netif_app_task_func)

+ 3 - 5
module/Air8101/demo/accessory_board/AirETH_1000/network_routing/wifi_out_ethernet_in_wifi_in/readme.md

@@ -52,15 +52,13 @@
 ssid = "WIFI名称"
 password = "WiFi密码"
 
-3、如果使用spi方式外挂网卡,打开SPI方式外挂网卡的代码,注释掉RMII方式外挂网卡的代码
+3、内核固件和本项目的Lua脚本:main.lua:主程序入口,netif_app.lua:网络管理模块
 
-4、内核固件和本项目的Lua脚本:main.lua:主程序入口,netif_app.lua:网络管理模块
-
-5、启动设备,观察日志输出:
+4、启动设备,观察日志输出:
 
 ```lua
 [INFO] exnetif setproxy success
 [INFO] http执行结果 200 ... 
 ```
 
-6、其他设备通过wifi或以太网接入Air8101,其他设备都能正常上网,则表示验证成功。
+5、其他设备通过wifi或以太网接入Air8101,其他设备都能正常上网,则表示验证成功。

+ 1 - 1
module/Air8101/demo/accessory_board/AirETH_1000/readme.md

@@ -6,4 +6,4 @@
 
 2、network_routing:
 
-(1)使用网络路由功能,以太网提供网络供以太网和wifi设备上网
+(1)使用网络路由功能,wifi提供网络供以太网和wifi设备上网

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff