logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

qp_oled_panel.c (10060B)


  1. // Copyright 2023 Nick Brassel (@tzarc)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "color.h"
  4. #include "qp_internal.h"
  5. #include "qp_comms.h"
  6. #include "qp_draw.h"
  7. #include "qp_oled_panel.h"
  8. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  9. // Quantum Painter API implementations
  10. // Power control
  11. bool qp_oled_panel_power(painter_device_t device, bool power_on) {
  12. painter_driver_t * driver = (painter_driver_t *)device;
  13. oled_panel_painter_driver_vtable_t *vtable = (oled_panel_painter_driver_vtable_t *)driver->driver_vtable;
  14. qp_comms_command(device, power_on ? vtable->opcodes.display_on : vtable->opcodes.display_off);
  15. return true;
  16. }
  17. // Screen clear
  18. bool qp_oled_panel_clear(painter_device_t device) {
  19. painter_driver_t *driver = (painter_driver_t *)device;
  20. driver->driver_vtable->init(device, driver->rotation); // Re-init the display
  21. return true;
  22. }
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. // Surface passthru
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. bool qp_oled_panel_passthru_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) {
  27. oled_panel_painter_device_t *driver = (oled_panel_painter_device_t *)device;
  28. return driver->surface.base.validate_ok && driver->surface.base.driver_vtable->pixdata(&driver->surface.base, pixel_data, native_pixel_count);
  29. }
  30. bool qp_oled_panel_passthru_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
  31. oled_panel_painter_device_t *driver = (oled_panel_painter_device_t *)device;
  32. return driver->surface.base.validate_ok && driver->surface.base.driver_vtable->viewport(&driver->surface.base, left, top, right, bottom);
  33. }
  34. bool qp_oled_panel_passthru_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) {
  35. oled_panel_painter_device_t *driver = (oled_panel_painter_device_t *)device;
  36. return driver->surface.base.validate_ok && driver->surface.base.driver_vtable->palette_convert(&driver->surface.base, palette_size, palette);
  37. }
  38. bool qp_oled_panel_passthru_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) {
  39. oled_panel_painter_device_t *driver = (oled_panel_painter_device_t *)device;
  40. return driver->surface.base.validate_ok && driver->surface.base.driver_vtable->append_pixels(&driver->surface.base, target_buffer, palette, pixel_offset, pixel_count, palette_indices);
  41. }
  42. bool qp_oled_panel_passthru_append_pixdata(painter_device_t device, uint8_t *target_buffer, uint32_t pixdata_offset, uint8_t pixdata_byte) {
  43. oled_panel_painter_device_t *driver = (oled_panel_painter_device_t *)device;
  44. return driver->surface.base.validate_ok && driver->surface.base.driver_vtable->append_pixdata(&driver->surface.base, target_buffer, pixdata_offset, pixdata_byte);
  45. }
  46. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  47. // Flush helpers
  48. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  49. void qp_oled_panel_page_column_flush_rot0(painter_device_t device, surface_dirty_data_t *dirty, const uint8_t *framebuffer) {
  50. painter_driver_t * driver = (painter_driver_t *)device;
  51. oled_panel_painter_driver_vtable_t *vtable = (oled_panel_painter_driver_vtable_t *)driver->driver_vtable;
  52. // TODO: account for offset_x/y in base driver
  53. int min_page = dirty->t / 8;
  54. int max_page = dirty->b / 8;
  55. int min_column = dirty->l;
  56. int max_column = dirty->r;
  57. for (int page = min_page; page <= max_page; ++page) {
  58. int cols_required = max_column - min_column + 1;
  59. uint8_t column_data[cols_required];
  60. memset(column_data, 0, cols_required);
  61. for (int x = min_column; x <= max_column; ++x) {
  62. uint16_t data_offset = x - min_column;
  63. for (int y = 0; y < 8; ++y) {
  64. uint32_t pixel_num = ((page * 8) + y) * driver->panel_width + x;
  65. uint32_t byte_offset = pixel_num / 8;
  66. uint8_t bit_offset = pixel_num % 8;
  67. column_data[data_offset] |= ((framebuffer[byte_offset] & (1 << bit_offset)) >> bit_offset) << y;
  68. }
  69. }
  70. int actual_page = page;
  71. int start_column = min_column;
  72. qp_comms_command(device, vtable->opcodes.set_page | actual_page);
  73. qp_comms_command(device, vtable->opcodes.set_column_lsb | (start_column & 0x0F));
  74. qp_comms_command(device, vtable->opcodes.set_column_msb | (start_column & 0xF0) >> 4);
  75. qp_comms_send(device, column_data, cols_required);
  76. }
  77. }
  78. void qp_oled_panel_page_column_flush_rot90(painter_device_t device, surface_dirty_data_t *dirty, const uint8_t *framebuffer) {
  79. painter_driver_t * driver = (painter_driver_t *)device;
  80. oled_panel_painter_driver_vtable_t *vtable = (oled_panel_painter_driver_vtable_t *)driver->driver_vtable;
  81. // TODO: account for offset_x/y in base driver
  82. int num_columns = driver->panel_width;
  83. int min_page = dirty->l / 8;
  84. int max_page = dirty->r / 8;
  85. int min_column = dirty->t;
  86. int max_column = dirty->b;
  87. for (int page = min_page; page <= max_page; ++page) {
  88. int cols_required = max_column - min_column + 1;
  89. uint8_t column_data[cols_required];
  90. memset(column_data, 0, cols_required);
  91. for (int y = min_column; y <= max_column; ++y) {
  92. uint16_t data_offset = cols_required - 1 - (y - min_column);
  93. for (int x = 0; x < 8; ++x) {
  94. uint32_t pixel_num = y * driver->panel_height + ((page * 8) + x);
  95. uint32_t byte_offset = pixel_num / 8;
  96. uint8_t bit_offset = pixel_num % 8;
  97. column_data[data_offset] |= ((framebuffer[byte_offset] & (1 << bit_offset)) >> bit_offset) << x;
  98. }
  99. }
  100. int actual_page = page;
  101. int start_column = num_columns - 1 - max_column;
  102. qp_comms_command(device, vtable->opcodes.set_page | actual_page);
  103. qp_comms_command(device, vtable->opcodes.set_column_lsb | (start_column & 0x0F));
  104. qp_comms_command(device, vtable->opcodes.set_column_msb | (start_column & 0xF0) >> 4);
  105. qp_comms_send(device, column_data, cols_required);
  106. }
  107. }
  108. void qp_oled_panel_page_column_flush_rot180(painter_device_t device, surface_dirty_data_t *dirty, const uint8_t *framebuffer) {
  109. painter_driver_t * driver = (painter_driver_t *)device;
  110. oled_panel_painter_driver_vtable_t *vtable = (oled_panel_painter_driver_vtable_t *)driver->driver_vtable;
  111. // TODO: account for offset_x/y in base driver
  112. int num_pages = driver->panel_height / 8;
  113. int num_columns = driver->panel_width;
  114. int min_page = dirty->t / 8;
  115. int max_page = dirty->b / 8;
  116. int min_column = dirty->l;
  117. int max_column = dirty->r;
  118. for (int page = min_page; page <= max_page; ++page) {
  119. int cols_required = max_column - min_column + 1;
  120. uint8_t column_data[cols_required];
  121. memset(column_data, 0, cols_required);
  122. for (int x = min_column; x <= max_column; ++x) {
  123. uint16_t data_offset = cols_required - 1 - (x - min_column);
  124. for (int y = 0; y < 8; ++y) {
  125. uint32_t pixel_num = ((page * 8) + y) * driver->panel_width + x;
  126. uint32_t byte_offset = pixel_num / 8;
  127. uint8_t bit_offset = pixel_num % 8;
  128. column_data[data_offset] |= ((framebuffer[byte_offset] & (1 << bit_offset)) >> bit_offset) << (7 - y);
  129. }
  130. }
  131. int actual_page = num_pages - 1 - page;
  132. int start_column = num_columns - 1 - max_column;
  133. qp_comms_command(device, vtable->opcodes.set_page | actual_page);
  134. qp_comms_command(device, vtable->opcodes.set_column_lsb | (start_column & 0x0F));
  135. qp_comms_command(device, vtable->opcodes.set_column_msb | (start_column & 0xF0) >> 4);
  136. qp_comms_send(device, column_data, cols_required);
  137. }
  138. }
  139. void qp_oled_panel_page_column_flush_rot270(painter_device_t device, surface_dirty_data_t *dirty, const uint8_t *framebuffer) {
  140. painter_driver_t * driver = (painter_driver_t *)device;
  141. oled_panel_painter_driver_vtable_t *vtable = (oled_panel_painter_driver_vtable_t *)driver->driver_vtable;
  142. // TODO: account for offset_x/y in base driver
  143. int num_pages = driver->panel_height / 8;
  144. int min_page = dirty->l / 8;
  145. int max_page = dirty->r / 8;
  146. int min_column = dirty->t;
  147. int max_column = dirty->b;
  148. for (int page = min_page; page <= max_page; ++page) {
  149. int cols_required = max_column - min_column + 1;
  150. uint8_t column_data[cols_required];
  151. memset(column_data, 0, cols_required);
  152. for (int y = min_column; y <= max_column; ++y) {
  153. uint16_t data_offset = y - min_column;
  154. for (int x = 0; x < 8; ++x) {
  155. uint32_t pixel_num = y * driver->panel_height + ((page * 8) + x);
  156. uint32_t byte_offset = pixel_num / 8;
  157. uint8_t bit_offset = pixel_num % 8;
  158. column_data[data_offset] |= ((framebuffer[byte_offset] & (1 << bit_offset)) >> bit_offset) << (7 - x);
  159. }
  160. }
  161. int actual_page = num_pages - 1 - page;
  162. int start_column = min_column;
  163. qp_comms_command(device, vtable->opcodes.set_page | actual_page);
  164. qp_comms_command(device, vtable->opcodes.set_column_lsb | (start_column & 0x0F));
  165. qp_comms_command(device, vtable->opcodes.set_column_msb | (start_column & 0xF0) >> 4);
  166. qp_comms_send(device, column_data, cols_required);
  167. }
  168. }