You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

286 lines
7.8 KiB

  1. // Copyright 2023 Andrew Kannan
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "satisfaction_core.h"
  4. #include "action_layer.h"
  5. #include "action_util.h"
  6. #include "timer.h"
  7. #include "matrix.h"
  8. #include "led.h"
  9. #include "host.h"
  10. #include "oled_driver.h"
  11. #include "progmem.h"
  12. #include <stdio.h>
  13. void draw_default(void);
  14. void draw_clock(void);
  15. #ifdef OLED_ENABLE
  16. oled_rotation_t oled_init_kb(oled_rotation_t rotation) { return OLED_ROTATION_0; }
  17. bool oled_task_kb(void) {
  18. if (!oled_task_user()) { return false; }
  19. if (!oled_task_needs_to_repaint()) {
  20. return false;
  21. }
  22. oled_clear();
  23. if (clock_set_mode) {
  24. draw_clock();
  25. return false;
  26. }
  27. switch (oled_mode) {
  28. default:
  29. case OLED_DEFAULT:
  30. draw_default();
  31. break;
  32. case OLED_TIME:
  33. draw_clock();
  34. break;
  35. }
  36. return false;
  37. }
  38. // Request a repaint of the OLED image without resetting the OLED sleep timer.
  39. // Used for things like clock updates that should not keep the OLED turned on
  40. // if there is no other activity.
  41. void oled_request_repaint(void) {
  42. if (is_oled_on()) {
  43. oled_repaint_requested = true;
  44. }
  45. }
  46. // Request a repaint of the OLED image and reset the OLED sleep timer.
  47. // Needs to be called after any activity that should keep the OLED turned on.
  48. void oled_request_wakeup(void) {
  49. oled_wakeup_requested = true;
  50. }
  51. // Check whether oled_task_user() needs to repaint the OLED image. This
  52. // function should be called at the start of oled_task_user(); it also handles
  53. // the OLED sleep timer and the OLED_OFF mode.
  54. bool oled_task_needs_to_repaint(void) {
  55. // In the OLED_OFF mode the OLED is kept turned off; any wakeup requests
  56. // are ignored.
  57. if ((oled_mode == OLED_OFF) && !clock_set_mode) {
  58. oled_wakeup_requested = false;
  59. oled_repaint_requested = false;
  60. oled_off();
  61. return false;
  62. }
  63. // If OLED wakeup was requested, reset the sleep timer and do a repaint.
  64. if (oled_wakeup_requested) {
  65. oled_wakeup_requested = false;
  66. oled_repaint_requested = false;
  67. oled_sleep_timer = timer_read32() + CUSTOM_OLED_TIMEOUT;
  68. oled_on();
  69. return true;
  70. }
  71. // If OLED repaint was requested, just do a repaint without touching the
  72. // sleep timer.
  73. if (oled_repaint_requested) {
  74. oled_repaint_requested = false;
  75. return true;
  76. }
  77. // If the OLED is currently off, skip the repaint (which would turn the
  78. // OLED on if the image is changed in any way).
  79. if (!is_oled_on()) {
  80. return false;
  81. }
  82. // If the sleep timer has expired while the OLED was on, turn the OLED off.
  83. if (timer_expired32(timer_read32(), oled_sleep_timer)) {
  84. oled_off();
  85. return false;
  86. }
  87. // Always perform a repaint if the OLED is currently on. (This can
  88. // potentially be optimized to avoid unneeded repaints if all possible
  89. // state changes are covered by oled_request_repaint() or
  90. // oled_request_wakeup(), but then any missed calls to these functions
  91. // would result in displaying a stale image.)
  92. return true;
  93. }
  94. static void draw_line_h(uint8_t x, uint8_t y, uint8_t len) {
  95. for (uint8_t i = 0; i < len; i++) {
  96. oled_write_pixel(i + x, y, true);
  97. }
  98. }
  99. static void draw_line_v(uint8_t x, uint8_t y, uint8_t len) {
  100. for (uint8_t i = 0; i < len; i++) {
  101. oled_write_pixel(x, i + y, true);
  102. }
  103. }
  104. static char* get_enc_mode(void) {
  105. switch (encoder_mode) {
  106. default:
  107. case ENC_MODE_VOLUME:
  108. return "VOL";
  109. case ENC_MODE_MEDIA:
  110. return "MED";
  111. case ENC_MODE_SCROLL:
  112. return "SCR";
  113. case ENC_MODE_BRIGHTNESS:
  114. return "BRT";
  115. case ENC_MODE_BACKLIGHT:
  116. return "BKL";
  117. case ENC_MODE_CLOCK_SET:
  118. return "CLK";
  119. case ENC_MODE_CUSTOM0:
  120. return "CS0";
  121. case ENC_MODE_CUSTOM1:
  122. return "CS1";
  123. case ENC_MODE_CUSTOM2:
  124. return "CS2";
  125. }
  126. }
  127. static char* get_time(void) {
  128. uint8_t hour = last_minute / 60;
  129. uint16_t minute = last_minute % 60;
  130. if (encoder_mode == ENC_MODE_CLOCK_SET) {
  131. hour = hour_config;
  132. minute = minute_config;
  133. }
  134. bool is_pm = (hour / 12) > 0;
  135. hour = hour % 12;
  136. if (hour == 0) {
  137. hour = 12;
  138. }
  139. static char time_str[8] = "";
  140. snprintf(time_str, sizeof(time_str), "%02hhu:%02hu%s", hour, minute, is_pm ? "pm" : "am");
  141. return time_str;
  142. }
  143. static char* get_date(void) {
  144. int16_t year = last_timespec.year + 1980;
  145. int8_t month = last_timespec.month;
  146. int8_t day = last_timespec.day;
  147. if (encoder_mode == ENC_MODE_CLOCK_SET) {
  148. year = year_config + 1980;
  149. month = month_config;
  150. day = day_config;
  151. }
  152. static char date_str[11] = "";
  153. snprintf(date_str, sizeof(date_str), "%04hd-%02hhd-%02hhd", year, month, day);
  154. return date_str;
  155. }
  156. void draw_default(void) {
  157. oled_write_P(PSTR("LAYER "), false);
  158. oled_write_char(get_highest_layer(layer_state) + 0x30, true);
  159. oled_write_P(PSTR(" ENC "), false);
  160. oled_write(get_enc_mode(), true);
  161. led_t led_state = host_keyboard_led_state();
  162. oled_set_cursor(18, 0);
  163. oled_write_P(PSTR("CAP"), led_state.caps_lock);
  164. oled_set_cursor(18, 1);
  165. oled_write_P(PSTR("SCR"), led_state.scroll_lock);
  166. uint8_t mod_state = get_mods();
  167. oled_set_cursor(6, 3);
  168. oled_write_P(PSTR("S"), mod_state & MOD_MASK_SHIFT);
  169. oled_advance_char();
  170. oled_write_P(PSTR("C"), mod_state & MOD_MASK_CTRL);
  171. oled_advance_char();
  172. oled_write_P(PSTR("A"), mod_state & MOD_MASK_ALT);
  173. oled_advance_char();
  174. oled_write_P(PSTR("G"), mod_state & MOD_MASK_GUI);
  175. oled_advance_char();
  176. oled_write(get_time(), false);
  177. /* Matrix display is 12 x 12 pixels */
  178. #define MATRIX_DISPLAY_X 0
  179. #define MATRIX_DISPLAY_Y 18
  180. // matrix
  181. for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
  182. for (uint8_t y = 0; y < MATRIX_COLS; y++) {
  183. bool on = (matrix_get_row(x) & (1 << y)) > 0;
  184. oled_write_pixel(MATRIX_DISPLAY_X + y + 2, MATRIX_DISPLAY_Y + x + 2, on);
  185. }
  186. }
  187. // outline
  188. draw_line_h(MATRIX_DISPLAY_X, MATRIX_DISPLAY_Y, 19);
  189. draw_line_h(MATRIX_DISPLAY_X, MATRIX_DISPLAY_Y + 9, 19);
  190. draw_line_v(MATRIX_DISPLAY_X, MATRIX_DISPLAY_Y, 9);
  191. draw_line_v(MATRIX_DISPLAY_X + 19, MATRIX_DISPLAY_Y, 9);
  192. // oled location
  193. draw_line_h(MATRIX_DISPLAY_X + 14, MATRIX_DISPLAY_Y + 2, 3);
  194. // bodge extra lines for invert layer and enc mode
  195. draw_line_v(35, 0, 8);
  196. draw_line_v(71, 0, 8);
  197. }
  198. void draw_clock(void) {
  199. oled_set_cursor(0, 0);
  200. oled_write(get_date(), false);
  201. oled_set_cursor(0, 2);
  202. oled_write(get_time(), false);
  203. oled_set_cursor(12, 0);
  204. oled_write_P(PSTR(" ENC "), false);
  205. oled_write(get_enc_mode(), true);
  206. oled_set_cursor(13, 1);
  207. oled_write_P(PSTR("LAYER "), false);
  208. oled_write_char(get_highest_layer(layer_state) + 0x30, true);
  209. led_t led_state = host_keyboard_led_state();
  210. oled_set_cursor(15, 3);
  211. oled_write_P(PSTR("CAPS"), led_state.caps_lock);
  212. if (clock_set_mode) {
  213. switch (time_config_idx) {
  214. case 0: // hour
  215. default:
  216. draw_line_h(0, 25, 10);
  217. break;
  218. case 1: // minute
  219. draw_line_h(18, 25, 10);
  220. break;
  221. case 2: // year
  222. draw_line_h(0, 9, 24);
  223. break;
  224. case 3: // month
  225. draw_line_h(30, 9, 10);
  226. break;
  227. case 4: // day
  228. draw_line_h(48, 9, 10);
  229. break;
  230. }
  231. }
  232. // bodge extra lines for invert layer and enc mode
  233. draw_line_v(101, 0, 8);
  234. draw_line_v(113, 8, 8);
  235. }
  236. #else
  237. void oled_request_repaint(void){
  238. }
  239. void oled_request_wakeup(void){
  240. }
  241. #endif