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.

426 lines
15 KiB

  1. // Copyright 2023 Kyle McCreery
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "sugarglider.h"
  4. #ifndef GLIDEPOINT_DPI_OPTIONS
  5. # define GLIDEPOINT_DPI_OPTIONS \
  6. { 400, 800, 1200, 1600, 2000, 2400, 2800, 3200, 3600, 4000 }
  7. #endif
  8. #ifndef GLIDEPOINT_DPI_DEFAULT
  9. # define GLIDEPOINT_DPI_DEFAULT 1
  10. #endif
  11. keyboard_config_t keyboard_config;
  12. uint16_t dpi_array[] = GLIDEPOINT_DPI_OPTIONS;
  13. #define DPI_OPTION_SIZE (sizeof(dpi_array) / sizeof(uint16_t))
  14. void board_init(void) {
  15. // B9 is configured as I2C1_SDA in the board file; that function must be
  16. // disabled before using B7 as I2C1_SDA.
  17. gpio_set_pin_input_high(B9);
  18. gpio_set_pin_output(B12);
  19. gpio_set_pin_output(B13);
  20. gpio_set_pin_output(B14);
  21. gpio_write_pin_low(B12);
  22. gpio_write_pin_low(B13);
  23. gpio_write_pin_low(B14);
  24. gpio_set_pin_output(C13);
  25. }
  26. #ifdef DYNAMIC_TAPPING_TERM_ENABLE
  27. void tap_modify(int change_value, bool tap_status) {
  28. if (keyboard_config.dt_term_config < 0) {
  29. keyboard_config.dt_term_config *= -1;
  30. }
  31. keyboard_config.dt_term_config += change_value;
  32. if (tap_status == false ) {
  33. keyboard_config.dt_term_config *= -1;
  34. g_tapping_term = 0;
  35. } else {
  36. g_tapping_term = keyboard_config.dt_term_config;
  37. }
  38. eeconfig_update_kb(keyboard_config.raw);
  39. }
  40. void tap_toggle(void) {
  41. keyboard_config.dt_term_config *= -1;
  42. if (keyboard_config.dt_term_config > 0) {
  43. g_tapping_term = keyboard_config.dt_term_config;
  44. } else {
  45. g_tapping_term = 0;
  46. }
  47. eeconfig_update_kb(keyboard_config.raw);
  48. }
  49. #endif // ifdef DYNAMIC_TAPPING_TERM_ENABLE
  50. #ifdef DIP_SWITCH_ENABLE
  51. bool dip_switch_update_kb(uint8_t index, bool active) {
  52. if (!dip_switch_update_user(index, active)) { return false; }
  53. switch (index) {
  54. case 0:
  55. if(active != host_keyboard_led_state().caps_lock) { tap_code(KC_CAPS); }
  56. break;
  57. break;
  58. }
  59. return true;
  60. }
  61. #endif
  62. #if defined(ENCODER_ENABLE) && ! defined(ENCODER_MAP_ENABLE)
  63. bool encoder_update_kb(uint8_t index, bool clockwise) {
  64. if (!encoder_update_user(index, clockwise)) { return false; }
  65. switch (index) {
  66. case 0:
  67. if (clockwise) {
  68. tap_code(KC_VOLU);
  69. } else {
  70. tap_code(KC_VOLD);
  71. }
  72. break;
  73. case 1:
  74. if (clockwise) {
  75. tap_code(KC_VOLU);
  76. } else {
  77. tap_code(KC_VOLD);
  78. }
  79. break;
  80. case 2:
  81. if (clockwise) {
  82. tap_code(KC_PGUP);
  83. } else {
  84. tap_code(KC_PGDN);
  85. }
  86. break;
  87. case 3:
  88. if (clockwise) {
  89. tap_code(KC_WH_U);
  90. } else {
  91. tap_code(KC_WH_D);
  92. }
  93. break;
  94. }
  95. return true;
  96. }
  97. #endif
  98. bool led_update_kb(led_t led_state) {
  99. bool res = led_update_user(led_state);
  100. if(res) {
  101. gpio_write_pin(B12, led_state.num_lock); // Updates status LEDs
  102. gpio_write_pin(B13, led_state.caps_lock); // Updates status LEDs
  103. gpio_write_pin(B14, led_state.scroll_lock); // Updates status LEDs
  104. gpio_write_pin(C13, !led_state.caps_lock); // Updates status LEDs, this is the LED on the blackpill itself
  105. }
  106. return res;
  107. }
  108. #ifdef OLED_ENABLE
  109. static void render_logo(void) { // Render MechWild "MW" Logo
  110. static const char PROGMEM logo_1[] = {0xCC, 0xCD, 0xCE, 0xCF, 0x00};
  111. static const char PROGMEM logo_2[] = {0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00};
  112. static const char PROGMEM logo_3[] = {0xD5, 0xD6, 0xD7, 0xD8, 0x00};
  113. static const char PROGMEM logo_4[] = {0xDE, 0xD9, 0xDA, 0xDB, 0x00};
  114. oled_write_P(logo_1, false);
  115. oled_set_cursor(0,1);
  116. oled_write_P(logo_2, false);
  117. oled_set_cursor(0,2);
  118. oled_write_P(logo_3, false);
  119. oled_set_cursor(0,3);
  120. oled_write_P(logo_4, false);
  121. }
  122. #ifdef OLED_DISPLAY_128X64 // Wide OLED Functionality
  123. oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
  124. return OLED_ROTATION_180; // flips the display 180 degrees
  125. }
  126. bool clear_screen = true; // used to manage singular screen clears to prevent display glitch
  127. bool clear_screen_art = true; // used to manage singular screen clears to prevent display glitch
  128. static void render_sugarglider_wide(void) { // Render sugarglider logo
  129. static const char PROGMEM sgl_1[] = {0xDE, 0xDE, 0xDE, 0x98, 0x99, 0xDE, 0x9A, 0x9B, 0x9C, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xCC, 0xCD, 0xCE, 0xCF, 0x00};
  130. static const char PROGMEM sgl_2[] = {0x9D, 0x9E, 0xDE, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xDE, 0xDE, 0xDE, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0x00};
  131. static const char PROGMEM sgl_3[] = {0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xDE, 0xDE, 0xDE, 0xD5, 0xD6, 0xD7, 0xD8, 0x00};
  132. static const char PROGMEM sgl_4[] = {0xDE, 0xB2, 0xDE, 0xB3, 0xB4, 0xB5, 0xB6, 0xDE, 0xDE, 0xB7, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xD9, 0xDA, 0xDB, 0x00};
  133. static const char PROGMEM sgl_5[] = {0xDE, 0xB8, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xB9, 0x00};
  134. static const char PROGMEM sgl_6[] = {0xDE, 0xBA, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xBB, 0xBC, 0x00};
  135. static const char PROGMEM sgl_7[] = {0xDE, 0xBD, 0xBE, 0xDE, 0xDE, 0xBF, 0xDE, 0xDE, 0xC0, 0xC1, 0x00};
  136. static const char PROGMEM sgl_8[] = {0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0x00};
  137. oled_write_P(sgl_1, false);
  138. oled_set_cursor(0,1);
  139. oled_write_P(sgl_2, false);
  140. oled_set_cursor(0,2);
  141. oled_write_P(sgl_3, false);
  142. oled_set_cursor(0,3);
  143. oled_write_P(sgl_4, false);
  144. oled_set_cursor(0,4);
  145. oled_write_P(sgl_5, false);
  146. oled_set_cursor(0,5);
  147. oled_write_P(sgl_6, false);
  148. oled_set_cursor(0,6);
  149. oled_write_P(sgl_7, false);
  150. oled_set_cursor(0,7);
  151. oled_write_P(sgl_8, false);
  152. }
  153. bool oled_task_kb(void) {
  154. if(!oled_task_user()) {
  155. return false;
  156. }
  157. if ( !(host_keyboard_led_state().num_lock || host_keyboard_led_state().caps_lock || host_keyboard_led_state().scroll_lock ) && get_highest_layer(layer_state) == 0 ) { // If none of the status LEDs are active and also the active layer is the base layer
  158. if (clear_screen_art == true) {
  159. oled_clear();
  160. oled_render();
  161. clear_screen_art = false;
  162. }
  163. render_sugarglider_wide();
  164. #ifdef POINTING_DEVICE_ENABLE // only display dpi and tap info if pointing devices are active
  165. oled_set_cursor(10,5);
  166. oled_write_P(PSTR(" DPI:"), false);
  167. oled_write(get_u16_str(dpi_array[keyboard_config.dpi_config], ' '), false);
  168. #ifdef DYNAMIC_TAPPING_TERM_ENABLE // only display tap info if it is being configured dynamically
  169. oled_set_cursor(10,6);
  170. oled_write_P(PSTR(" TAP:"), false);
  171. if (keyboard_config.dt_term_config < 0) {
  172. oled_write_P(PSTR("Off "), false);
  173. } else {
  174. oled_write(get_u16_str(g_tapping_term, ' '), false);
  175. }
  176. #endif
  177. #endif
  178. clear_screen = true;
  179. } else { // If any of the status LEDs are active or if the active layer is not the base layer
  180. if (clear_screen == true) {
  181. oled_clear();
  182. oled_render();
  183. clear_screen = false;
  184. }
  185. render_logo();
  186. oled_set_cursor(8,1);
  187. switch (get_highest_layer(layer_state)) {
  188. case 0:
  189. oled_write_P(PSTR("Base "), false);
  190. break;
  191. case 1:
  192. oled_write_P(PSTR("Lower "), false);
  193. break;
  194. case 2:
  195. oled_write_P(PSTR("Raise "), false);
  196. break;
  197. case 3:
  198. oled_write_P(PSTR("Adjust"), false);
  199. break;
  200. case 4:
  201. oled_write_P(PSTR("Mouse "), false);
  202. break;
  203. #ifdef STENO_ENABLE
  204. case 5:
  205. oled_write_P(PSTR("Steno Layer"), false);
  206. break;
  207. #endif
  208. default:
  209. oled_write_P(PSTR("Layer ?"), false); // Should never display, here as a catchall
  210. }
  211. led_t led_state = host_keyboard_led_state();
  212. oled_set_cursor(8,0);
  213. oled_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR(" "), false);
  214. oled_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR(" "), false);
  215. oled_write_P(led_state.scroll_lock ? PSTR("SCR") : PSTR(" "), false);
  216. #ifdef POINTING_DEVICE_ENABLE // only display dpi and tap info if pointing devices are active
  217. oled_set_cursor(8,2);
  218. oled_write_P(PSTR("DPI:"), false);
  219. oled_write(get_u16_str(dpi_array[keyboard_config.dpi_config], ' '), false);
  220. #ifdef DYNAMIC_TAPPING_TERM_ENABLE // only display tap info if it is being configured dynamically
  221. oled_set_cursor(8,3);
  222. oled_write_P(PSTR("TAP:"), false);
  223. if (keyboard_config.dt_term_config < 0) {
  224. oled_write_P(PSTR("Off "), false);
  225. } else {
  226. oled_write(get_u16_str(g_tapping_term, ' '), false);
  227. }
  228. #endif
  229. #endif
  230. clear_screen_art = true;
  231. }
  232. return true;
  233. }
  234. #else // Using an OLED but not the wide OLED
  235. oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
  236. return OLED_ROTATION_270; // flips the display 270 degrees
  237. }
  238. bool oled_task_kb(void) {
  239. if(!oled_task_user()) {
  240. return false;
  241. }
  242. render_logo();
  243. oled_set_cursor(0,5);
  244. switch (get_highest_layer(layer_state)) {
  245. case 0:
  246. oled_write_P(PSTR("Base "), false);
  247. break;
  248. case 1:
  249. oled_write_P(PSTR("Lower"), false);
  250. break;
  251. case 2:
  252. oled_write_P(PSTR("Raise"), false);
  253. break;
  254. case 3:
  255. oled_write_P(PSTR("Adjst"), false);
  256. break;
  257. case 4:
  258. oled_write_P(PSTR("Mouse"), false);
  259. break;
  260. #ifdef STENO_ENABLE
  261. case 5:
  262. oled_write_P(PSTR("Steno"), false);
  263. break;
  264. #endif
  265. default:
  266. oled_write_P(PSTR("?????"), false); // Should never display, here as a catchall
  267. }
  268. led_t led_state = host_keyboard_led_state();
  269. oled_set_cursor(0,6);
  270. oled_write_P(led_state.num_lock ? PSTR("NUM ") : PSTR(" "), false);
  271. oled_write_P(led_state.caps_lock ? PSTR("CAP ") : PSTR(" "), false);
  272. oled_write_P(led_state.scroll_lock ? PSTR("SCR ") : PSTR(" "), false);
  273. #ifdef POINTING_DEVICE_ENABLE
  274. oled_set_cursor(0,11);
  275. oled_write_P(PSTR("DPI: "), false);
  276. oled_write(get_u16_str(dpi_array[keyboard_config.dpi_config], ' '), false);
  277. #endif
  278. #ifdef DYNAMIC_TAPPING_TERM_ENABLE // only display tap info if it is being configured dynamically
  279. oled_set_cursor(0,13);
  280. oled_write_P(PSTR("TAP: "), false);
  281. if (keyboard_config.dt_term_config < 0) {
  282. oled_write_P(PSTR("Off "), false);
  283. } else {
  284. oled_write(get_u16_str(g_tapping_term, ' '), false);
  285. }
  286. #endif
  287. return true;
  288. }
  289. #endif // Not using wide OLED
  290. #endif // ifdef OLED_ENABLE
  291. bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
  292. switch(keycode) {
  293. #ifdef POINTING_DEVICE_ENABLE
  294. case DPI_UP:
  295. if (record->event.pressed) {
  296. keyboard_config.dpi_config = (keyboard_config.dpi_config + 1) % DPI_OPTION_SIZE;
  297. eeconfig_update_kb(keyboard_config.raw);
  298. pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
  299. }
  300. return false;
  301. case DPI_DN:
  302. if (record->event.pressed) {
  303. if (keyboard_config.dpi_config > 0) {
  304. keyboard_config.dpi_config = (keyboard_config.dpi_config - 1) % DPI_OPTION_SIZE;
  305. } else {
  306. keyboard_config.dpi_config = DPI_OPTION_SIZE - 1;
  307. }
  308. eeconfig_update_kb(keyboard_config.raw);
  309. pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
  310. }
  311. return false;
  312. case DPI_FINE:
  313. if (record->event.pressed) {
  314. pointing_device_set_cpi(dpi_array[0]);
  315. } else {
  316. pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
  317. }
  318. return false;
  319. #endif
  320. #ifdef DYNAMIC_TAPPING_TERM_ENABLE // only include tap info keycodes if it is being configured dynamically
  321. case TAP_UP:
  322. if (record->event.pressed) {
  323. if (keyboard_config.dt_term_config < 5000) {
  324. tap_modify(DYNAMIC_TAPPING_TERM_INCREMENT, true);
  325. }
  326. }
  327. return false;
  328. case TAP_DN:
  329. if (record->event.pressed) {
  330. if (keyboard_config.dt_term_config > 0) {
  331. tap_modify(-1 * DYNAMIC_TAPPING_TERM_INCREMENT, true);
  332. }
  333. }
  334. return false;
  335. case TAP_ON:
  336. if (record->event.pressed) {
  337. tap_modify(0, true);
  338. }
  339. return false;
  340. case TAP_OFF:
  341. if (record->event.pressed) {
  342. tap_modify(0, false);
  343. }
  344. return false;
  345. case TAP_TOG:
  346. if (record->event.pressed) {
  347. tap_toggle();
  348. }
  349. return false;
  350. #endif // ifdef
  351. }
  352. return process_record_user(keycode, record);
  353. }
  354. void pointing_device_init_kb(void) {
  355. #ifdef POINTING_DEVICE_ENABLE
  356. pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
  357. #endif
  358. }
  359. void eeconfig_init_kb(void) {
  360. #ifdef POINTING_DEVICE_ENABLE
  361. keyboard_config.dpi_config = GLIDEPOINT_DPI_DEFAULT;
  362. #endif
  363. #ifdef DYNAMIC_TAPPING_TERM_ENABLE // only set tap term from eeprom if it is being configured dynamically
  364. keyboard_config.dt_term_config = TAPPING_TERM;
  365. #endif
  366. eeconfig_update_kb(keyboard_config.raw);
  367. #ifdef STENO_ENABLE
  368. steno_set_mode(STENO_MODE_GEMINI); // or STENO_MODE_BOLT
  369. #endif
  370. eeconfig_init_user();
  371. }
  372. void matrix_init_kb(void) {
  373. // is safe to just read DPI setting since matrix init
  374. // comes before pointing device init.
  375. keyboard_config.raw = eeconfig_read_kb();
  376. #ifdef POINTING_DEVICE_ENABLE
  377. if (keyboard_config.dpi_config > DPI_OPTION_SIZE) {
  378. eeconfig_init_kb();
  379. }
  380. #endif
  381. matrix_init_user();
  382. }
  383. void keyboard_post_init_kb(void) {
  384. #ifdef POINTING_DEVICE_ENABLE
  385. pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
  386. #endif
  387. #ifdef RGBLIGHT_ENABLE
  388. rgblight_toggle_noeeprom(); //double toggle post init removes the weirdness with rgb strips having a yellow first LED
  389. rgblight_toggle_noeeprom();
  390. #endif
  391. #ifdef DYNAMIC_TAPPING_TERM_ENABLE
  392. tap_toggle(); // Need it to reevaluate this setting after initiating so that it is current after init
  393. tap_toggle();
  394. #endif
  395. keyboard_post_init_user();
  396. #ifdef OLED_ENABLE // purposefully after user post init to allow the RGB to startup first
  397. wait_ms(200); // Avoids a startup issue where the oled renders and then turns off with blackpill
  398. oled_on();
  399. #endif
  400. }