121 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Copyright 2021 Chris Tanaka <https://github.com/christanaka>
 | |
|  *
 | |
|  * This program is free software: you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation, either version 2 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * This program is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| #include "bongo_graphics.h"
 | |
| #include QMK_KEYBOARD_H
 | |
| 
 | |
| #define _IDLE_FRAMES         5
 | |
| #define _PREP_FRAMES         1
 | |
| #define _TAP_FRAMES          2
 | |
| #define _ANIM_BYTES          512   // Number of bytes in array (max is 1024)
 | |
| #define _IDLE_FRAME_DURATION 175
 | |
| #define _TAP_FRAME_DURATION  75
 | |
| #define _PREP_TIMEOUT        750
 | |
| 
 | |
| enum anim_states
 | |
| {
 | |
|     Idle,
 | |
|     Prep,
 | |
|     Tap
 | |
| };
 | |
| 
 | |
| static uint8_t anim_state = Idle;
 | |
| static uint8_t anim_duration = _IDLE_FRAME_DURATION;
 | |
| static uint32_t anim_timer = 0;
 | |
| 
 | |
| static uint8_t idle_frame = 0;
 | |
| static uint8_t tap_frame = 0;
 | |
| 
 | |
| static uint32_t prep_timer = 0;
 | |
| 
 | |
| // Decompress and write a precompressed bitmap frame to the OLED.
 | |
| // Documentation and python compression script available at:
 | |
| // https://github.com/nullbitsco/squeez-o
 | |
| #ifdef USE_OLED_BITMAP_COMPRESSION
 | |
| static void oled_write_compressed_P(const char* input_block_map, const char* input_block_list) {
 | |
|     uint16_t block_index = 0;
 | |
|     for (uint16_t i = 0; i < NUM_OLED_BYTES; i++) {
 | |
|         uint8_t bit          = i % 8;
 | |
|         uint8_t map_index    = i / 8;
 | |
|         uint8_t _block_map   = (uint8_t)pgm_read_byte_near(input_block_map + map_index);
 | |
|         uint8_t nonzero_byte = (_block_map & (1 << bit));
 | |
|         if (nonzero_byte) {
 | |
|             const char data = (const char)pgm_read_byte_near(input_block_list + block_index++);
 | |
|             oled_write_raw_byte(data, i);
 | |
|         } else {
 | |
|             const char data = (const char)0x00;
 | |
|             oled_write_raw_byte(data, i);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| #endif
 | |
| 
 | |
| static void animate(uint8_t x, uint8_t y) {
 | |
|   oled_set_cursor(x, y);
 | |
| 
 | |
|   // Update frame
 | |
|   switch (anim_state) {
 | |
|     case Idle:
 | |
|       idle_frame = (idle_frame + 1) % _IDLE_FRAMES;
 | |
|       #ifdef USE_OLED_BITMAP_COMPRESSION
 | |
|           oled_write_compressed_P(idle_block_map[abs(1 - idle_frame)], idle[abs(1 - idle_frame)]);
 | |
|       #else
 | |
|           oled_write_raw_P(idle[abs(1 - idle_frame)], sizeof(idle[abs(1 - idle_frame)]));
 | |
|       #endif
 | |
|       break;
 | |
|     case Prep:
 | |
|       #ifdef USE_OLED_BITMAP_COMPRESSION
 | |
|           oled_write_compressed_P(prep_block_map[0], prep[0]);
 | |
|       #else
 | |
|           oled_write_raw_P(prep[0], sizeof(prep[0]));
 | |
|       #endif
 | |
|       break;
 | |
|     case Tap:
 | |
|       tap_frame = (tap_frame + 1) % _TAP_FRAMES;
 | |
|       #ifdef USE_OLED_BITMAP_COMPRESSION
 | |
|           oled_write_compressed_P(tap_block_map[abs(1 - tap_frame)], tap[abs(1 - tap_frame)]);
 | |
|       #else
 | |
|           oled_write_raw_P(tap[abs(1 - tap_frame)], sizeof(tap[abs(1 - tap_frame)]));
 | |
|       #endif
 | |
|       break;
 | |
|     default:
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void bongo_render(uint8_t x, uint8_t y) {
 | |
|   if (timer_elapsed32(anim_timer) > anim_duration) {
 | |
|     anim_timer = timer_read32();
 | |
|     animate(x, y);
 | |
|   }
 | |
| 
 | |
|   if (anim_state == Prep && timer_elapsed32(prep_timer) > _PREP_TIMEOUT) {
 | |
|     anim_state = Idle;
 | |
|     anim_duration = _IDLE_FRAME_DURATION;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void bongo_process_record(keyrecord_t *record) {
 | |
|   if (record->event.pressed) {
 | |
|     anim_state = Tap;
 | |
|     anim_duration = _TAP_FRAME_DURATION;
 | |
|   } else {
 | |
|     if (anim_state == Tap) {
 | |
|       anim_state = Prep;
 | |
|       prep_timer = timer_read32();
 | |
|     }
 | |
|   }
 | |
| }
 | 
