From e409fb47f27f9cf56479928ed86eb2eb346eec54 Mon Sep 17 00:00:00 2001 From: DennyTom Date: Tue, 7 Apr 2020 04:13:17 -0700 Subject: DennyTom's buttery_engine (#8138) * Selectively adding pieces * Adding georgi keymap * Adding more files, fixing make * Smaller makefiles * Fixing make rules * README more inline with QMK's guidelines * Turning off buggy assert * Improving documentation based on a user feedback. * Slightly better schema * Resurrected state machine diagram --- users/dennytom/chording_engine/engine.part.3 | 404 +++++++++++++++++++++++++++ 1 file changed, 404 insertions(+) create mode 100644 users/dennytom/chording_engine/engine.part.3 (limited to 'users/dennytom/chording_engine/engine.part.3') diff --git a/users/dennytom/chording_engine/engine.part.3 b/users/dennytom/chording_engine/engine.part.3 new file mode 100644 index 0000000000..cf19008abc --- /dev/null +++ b/users/dennytom/chording_engine/engine.part.3 @@ -0,0 +1,404 @@ +bool are_hashed_keycodes_in_sound(HASH_TYPE keycodes_hash, HASH_TYPE sound) { + return (keycodes_hash & sound) == keycodes_hash; +} + +uint8_t keycode_to_index(uint16_t keycode) { + return keycode - FIRST_INTERNAL_KEYCODE; +} + +void sound_keycode_array(uint16_t keycode) { + uint8_t index = keycode_to_index(keycode); + keycode_index++; + keycodes_buffer_array[index] = keycode_index; +} + +void silence_keycode_hash_array(HASH_TYPE keycode_hash) { + for (int i = 0; i < NUMBER_OF_KEYS; i++) { + bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash; + if (index_in_hash) { + uint8_t current_val = keycodes_buffer_array[i]; + keycodes_buffer_array[i] = 0; + for (int j = 0; j < NUMBER_OF_KEYS; j++) { + if (keycodes_buffer_array[j] > current_val) { + keycodes_buffer_array[j]--; + } + } + keycode_index--; + } + } +} + +bool are_hashed_keycodes_in_array(HASH_TYPE keycode_hash) { + for (int i = 0; i < NUMBER_OF_KEYS; i++) { + bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash; + bool index_in_array = (bool) keycodes_buffer_array[i]; + if (index_in_hash && !index_in_array) { + return false; + } + } + return true; +} + +void kill_one_shots(void) { + struct Chord chord_storage; + struct Chord* chord_ptr; + struct Chord* chord; + + for (int i = 0; i < NUMBER_OF_CHORDS; i++) { + chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); + memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); + chord = &chord_storage; + + if (*chord->state == IN_ONE_SHOT) { + *chord->state = RESTART; + chord->function(chord); + if (*chord->state == RESTART) { + *chord->state = IDLE; + } + } + } +} + +void process_finished_dances(void) { + struct Chord chord_storage; + struct Chord* chord_ptr; + struct Chord* chord; + + for (int i = 0; i < NUMBER_OF_CHORDS; i++) { + chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); + memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); + chord = &chord_storage; + + if (*chord->state == ACTIVATED) { + *chord->state = PRESS_FROM_ACTIVE; + chord->function(chord); + if (a_key_went_through) { + kill_one_shots(); + } + dance_timer = timer_read(); + } else if (*chord->state == IDLE_IN_DANCE) { + *chord->state = FINISHED; + chord->function(chord); + if (*chord->state == FINISHED) { + *chord->state = RESTART; + if (*chord->state == RESTART) { + *chord->state = IDLE; + } + } + } else if (*chord->state == PRESS_FROM_ACTIVE) { + *chord->state = FINISHED_FROM_ACTIVE; + chord->function(chord); + if (a_key_went_through) { + kill_one_shots(); + } + dance_timer = timer_read(); + } + } +} + +uint8_t keycodes_buffer_array_min(uint8_t* first_keycode_index) { + for (int i = 0; i < NUMBER_OF_KEYS; i++) { + if (keycodes_buffer_array[i] == 1) { + if (first_keycode_index != NULL) { + *first_keycode_index = (uint8_t) i; + } + return 1; + } + } + return 0; +} + +void remove_subchords(void) { + struct Chord chord_storage; + struct Chord* chord_ptr; + struct Chord* chord; + + for (int i = 0; i < NUMBER_OF_CHORDS; i++) { + chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); + memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); + chord = &chord_storage; + + if (!(*chord->state == READY || *chord->state == READY_IN_DANCE || *chord->state == READY_LOCKED)) { + continue; + } + + struct Chord chord_storage_2; + struct Chord* chord_ptr_2; + struct Chord* chord_2; + for (int j = 0; j < NUMBER_OF_CHORDS; j++) { + if (i == j) {continue;} + + chord_ptr_2 = (struct Chord*) pgm_read_word (&list_of_chords[j]); + memcpy_P(&chord_storage_2, chord_ptr_2, sizeof(struct Chord)); + chord_2 = &chord_storage_2; + + if (are_hashed_keycodes_in_sound(chord_2->keycodes_hash, chord->keycodes_hash)) { + if (*chord_2->state == READY) { + *chord_2->state = IDLE; + } + if (*chord_2->state == READY_IN_DANCE) { + *chord_2->state = IDLE_IN_DANCE; + } + if (*chord_2->state == READY_LOCKED) { + *chord_2->state = LOCKED; + } + } + } + } +} + +void process_ready_chords(void) { + uint8_t first_keycode_index = 0; + while (keycodes_buffer_array_min(&first_keycode_index)) { + // find ready chords + struct Chord chord_storage; + struct Chord* chord_ptr; + struct Chord* chord; + + for (int i = 0; i < NUMBER_OF_CHORDS; i++) { + chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); + memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); + chord = &chord_storage; + + // if the chord does not contain the first keycode + bool contains_first_keycode = ((uint32_t) 1 << first_keycode_index) & chord->keycodes_hash; + if (!contains_first_keycode) { + continue; + } + + if (!are_hashed_keycodes_in_array(chord->keycodes_hash)){ + continue; + } + + if (*chord->state == LOCKED) { + *chord->state = READY_LOCKED; + continue; + } + + if (!(chord->pseudolayer == current_pseudolayer || chord->pseudolayer == ALWAYS_ON)) { + continue; + } + + if (*chord->state == IDLE) { + *chord->state = READY; + continue; + } + + if (*chord->state == IDLE_IN_DANCE) { + *chord->state = READY_IN_DANCE; + } + } + + // remove subchords + remove_subchords(); + + // execute logic + // this should be only one chord + for (int i = 0; i < NUMBER_OF_CHORDS; i++) { + chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); + memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); + chord = &chord_storage; + + if (*chord->state == READY_LOCKED) { + *chord->state = RESTART; + chord->function(chord); + if (*chord->state == RESTART) { + *chord->state = IDLE; + } + break; + } + + if (*chord->state == READY || *chord->state == READY_IN_DANCE) { + if (last_chord && last_chord != chord) { + process_finished_dances(); + } + + bool lock_next_prev_state = lock_next; + + *chord->state = ACTIVATED; + chord->function(chord); + dance_timer = timer_read(); + + if (lock_next && lock_next == lock_next_prev_state) { + lock_next = false; + *chord->state = PRESS_FROM_ACTIVE; + chord->function(chord); + if (*chord->state == PRESS_FROM_ACTIVE) { + *chord->state = LOCKED; + } + if (a_key_went_through) { + kill_one_shots(); + } + } + break; + } + } + + // silence notes + silence_keycode_hash_array(chord->keycodes_hash); + } +} + +void deactivate_active_chords(uint16_t keycode) { + HASH_TYPE hash = (HASH_TYPE)1 << (keycode - SAFE_RANGE); + bool broken; + struct Chord chord_storage; + struct Chord* chord_ptr; + struct Chord* chord; + + for (int i = 0; i < NUMBER_OF_CHORDS; i++) { + chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); + memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); + chord = &chord_storage; + + broken = are_hashed_keycodes_in_sound(hash, chord->keycodes_hash); + if (!broken) { + continue; + } + + switch (*chord->state) { + case ACTIVATED: + *chord->state = DEACTIVATED; + chord->function(chord); + + if (*chord->state == DEACTIVATED) { + dance_timer = timer_read(); + *chord->state = IDLE_IN_DANCE; + } + if (*chord->state != IN_ONE_SHOT) { + kill_one_shots(); + } + break; + case PRESS_FROM_ACTIVE: + case FINISHED_FROM_ACTIVE: + *chord->state = RESTART; + chord->function(chord); + if (*chord->state == RESTART) { + *chord->state = IDLE; + } + kill_one_shots(); + break; + default: + break; + } + } + +} + +void process_command(void) { + command_mode = 0; + for (int i = 0; i < COMMAND_MAX_LENGTH; i++) { + if (command_buffer[i]) { + register_code(command_buffer[i]); + } + send_keyboard_report(); + } + wait_ms(TAP_TIMEOUT); + for (int i = 0; i < COMMAND_MAX_LENGTH; i++) { + if (command_buffer[i]) { + unregister_code(command_buffer[i]); + } + send_keyboard_report(); + } + for (int i = 0; i < COMMAND_MAX_LENGTH; i++) { + command_buffer[i] = 0; + } + command_ind = 0; +} + +void process_leader(void) { + in_leader_mode = false; + for (int i = 0; i < NUMBER_OF_LEADER_COMBOS; i++) { + uint16_t trigger[LEADER_MAX_LENGTH]; + memcpy_P(trigger, leader_triggers[i], LEADER_MAX_LENGTH * sizeof(uint16_t)); + + if (identical(leader_buffer, trigger)) { + (*leader_functions[i])(); + break; + } + } + for (int i = 0; i < LEADER_MAX_LENGTH; i++) { + leader_buffer[i] = 0; + } +} + +bool process_record_user(uint16_t keycode, keyrecord_t *record) { + if (keycode < FIRST_INTERNAL_KEYCODE || keycode > LAST_INTERNAL_KEYCODE) { + return true; + } + + if (record->event.pressed) { + sound_keycode_array(keycode); + } else { + process_ready_chords(); + deactivate_active_chords(keycode); + } + chord_timer = timer_read(); + leader_timer = timer_read(); + + return false; +} + +void matrix_scan_user(void) { + bool chord_timer_expired = timer_elapsed(chord_timer) > CHORD_TIMEOUT; + if (chord_timer_expired && keycodes_buffer_array_min(NULL)) { + process_ready_chords(); + } + + bool dance_timer_expired = timer_elapsed(dance_timer) > DANCE_TIMEOUT; + if (dance_timer_expired) { // would love to have && in_dance but not sure how + process_finished_dances(); + } + + bool in_command_mode = command_mode == 2; + if (in_command_mode) { + process_command(); + } + + bool leader_timer_expired = timer_elapsed(leader_timer) > LEADER_TIMEOUT; + if (leader_timer_expired && in_leader_mode) { + process_leader(); + } + +} + +void clear(const struct Chord* self) { + if (*self->state == ACTIVATED) { + // kill all chords + struct Chord chord_storage; + struct Chord* chord_ptr; + struct Chord* chord; + + for (int i = 0; i < NUMBER_OF_CHORDS; i++) { + chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); + memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); + chord = &chord_storage; + + *chord->state = IDLE; + + if (chord->counter) { + *chord->counter = 0; + } + } + + // clear keyboard + clear_keyboard(); + send_keyboard_report(); + + // switch to default pseudolayer + current_pseudolayer = DEFAULT_PSEUDOLAYER; + + // clear all keyboard states + lock_next = false; + autoshift_mode = true; + command_mode = 0; + in_leader_mode = false; + leader_ind = 0; + dynamic_macro_mode = false; + a_key_went_through = false; + + for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) { + dynamic_macro_buffer[i] = 0; + } + } +} \ No newline at end of file -- cgit v1.2.3