bongo.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /* Copyright 2021 Chris Tanaka <https://github.com/christanaka>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "bongo_graphics.h"
  17. #include QMK_KEYBOARD_H
  18. #define _IDLE_FRAMES 5
  19. #define _PREP_FRAMES 1
  20. #define _TAP_FRAMES 2
  21. #define _ANIM_BYTES 512 // Number of bytes in array (max is 1024)
  22. #define _IDLE_FRAME_DURATION 175
  23. #define _TAP_FRAME_DURATION 75
  24. #define _PREP_TIMEOUT 750
  25. enum anim_states
  26. {
  27. Idle,
  28. Prep,
  29. Tap
  30. };
  31. static uint8_t anim_state = Idle;
  32. static uint8_t anim_duration = _IDLE_FRAME_DURATION;
  33. static uint32_t anim_timer = 0;
  34. static uint8_t idle_frame = 0;
  35. static uint8_t tap_frame = 0;
  36. static uint32_t prep_timer = 0;
  37. // Decompress and write a precompressed bitmap frame to the OLED.
  38. // Documentation and python compression script available at:
  39. // https://github.com/nullbitsco/squeez-o
  40. #ifdef USE_OLED_BITMAP_COMPRESSION
  41. static void oled_write_compressed_P(const char* input_block_map, const char* input_block_list) {
  42. uint16_t block_index = 0;
  43. for (uint16_t i = 0; i < NUM_OLED_BYTES; i++) {
  44. uint8_t bit = i % 8;
  45. uint8_t map_index = i / 8;
  46. uint8_t _block_map = (uint8_t)pgm_read_byte_near(input_block_map + map_index);
  47. uint8_t nonzero_byte = (_block_map & (1 << bit));
  48. if (nonzero_byte) {
  49. const char data = (const char)pgm_read_byte_near(input_block_list + block_index++);
  50. oled_write_raw_byte(data, i);
  51. } else {
  52. const char data = (const char)0x00;
  53. oled_write_raw_byte(data, i);
  54. }
  55. }
  56. }
  57. #endif
  58. static void animate(uint8_t x, uint8_t y) {
  59. oled_set_cursor(x, y);
  60. // Update frame
  61. switch (anim_state) {
  62. case Idle:
  63. idle_frame = (idle_frame + 1) % _IDLE_FRAMES;
  64. #ifdef USE_OLED_BITMAP_COMPRESSION
  65. oled_write_compressed_P(idle_block_map[abs(1 - idle_frame)], idle[abs(1 - idle_frame)]);
  66. #else
  67. oled_write_raw_P(idle[abs(1 - idle_frame)], sizeof(idle[abs(1 - idle_frame)]));
  68. #endif
  69. break;
  70. case Prep:
  71. #ifdef USE_OLED_BITMAP_COMPRESSION
  72. oled_write_compressed_P(prep_block_map[0], prep[0]);
  73. #else
  74. oled_write_raw_P(prep[0], sizeof(prep[0]));
  75. #endif
  76. break;
  77. case Tap:
  78. tap_frame = (tap_frame + 1) % _TAP_FRAMES;
  79. #ifdef USE_OLED_BITMAP_COMPRESSION
  80. oled_write_compressed_P(tap_block_map[abs(1 - tap_frame)], tap[abs(1 - tap_frame)]);
  81. #else
  82. oled_write_raw_P(tap[abs(1 - tap_frame)], sizeof(tap[abs(1 - tap_frame)]));
  83. #endif
  84. break;
  85. default:
  86. break;
  87. }
  88. }
  89. void bongo_render(uint8_t x, uint8_t y) {
  90. if (timer_elapsed32(anim_timer) > anim_duration) {
  91. anim_timer = timer_read32();
  92. animate(x, y);
  93. }
  94. if (anim_state == Prep && timer_elapsed32(prep_timer) > _PREP_TIMEOUT) {
  95. anim_state = Idle;
  96. anim_duration = _IDLE_FRAME_DURATION;
  97. }
  98. }
  99. void bongo_process_record(keyrecord_t *record) {
  100. if (record->event.pressed) {
  101. anim_state = Tap;
  102. anim_duration = _TAP_FRAME_DURATION;
  103. } else {
  104. if (anim_state == Tap) {
  105. anim_state = Prep;
  106. prep_timer = timer_read32();
  107. }
  108. }
  109. }