Add proper multimatrix support
This commit is contained in:
		
							parent
							
								
									f9c61b1bbe
								
							
						
					
					
						commit
						6c68cccd90
					
				
					 5 changed files with 195 additions and 97 deletions
				
			
		| 
						 | 
				
			
			@ -220,15 +220,32 @@ void layer_debug(void)
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
 | 
			
		||||
uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS * MAX_LAYER_BITS + 7) / 8] = {0};
 | 
			
		||||
static const uint8_t layer_cache_mask = (1u << MAX_LAYER_BITS) - 1;
 | 
			
		||||
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
uint8_t* multimatrix_get_source_layers_cache(uint8_t matrix) {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t* get_source_layers_cache(keymatrix_t key) {
 | 
			
		||||
  if (key.matrix == 0) {
 | 
			
		||||
    static uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS * MAX_LAYER_BITS + 7) / 8] = {0};
 | 
			
		||||
    return source_layers_cache;
 | 
			
		||||
  } else {
 | 
			
		||||
    return multimatrix_get_source_layers_cache(key.matrix - 1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void update_source_layers_cache(keymatrix_t key, uint8_t layer)
 | 
			
		||||
{
 | 
			
		||||
  const uint16_t key_number = key.pos.col + (key.pos.row * MATRIX_COLS);
 | 
			
		||||
  const uint8_t num_cols = keyboard_get_num_cols(key.matrix);
 | 
			
		||||
  const uint8_t num_rows = keyboard_get_num_rows(key.matrix);
 | 
			
		||||
  const uint16_t num_cache_bytes = get_source_layers_cache_size(num_cols, num_rows);
 | 
			
		||||
  uint8_t* cache = get_source_layers_cache(key);
 | 
			
		||||
  const uint16_t key_number = key.pos.col + (key.pos.row * num_cols);
 | 
			
		||||
  const uint32_t bit_number = key_number * MAX_LAYER_BITS;
 | 
			
		||||
  const uint16_t byte_number = bit_number / 8;
 | 
			
		||||
  if (byte_number >= sizeof(source_layers_cache)) {
 | 
			
		||||
  if (byte_number >= num_cache_bytes) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  const uint8_t bit_position = bit_number % 8;
 | 
			
		||||
| 
						 | 
				
			
			@ -239,9 +256,9 @@ void update_source_layers_cache(keymatrix_t key, uint8_t layer)
 | 
			
		|||
    shift -= 8;
 | 
			
		||||
    const uint8_t mask = layer_cache_mask << shift;
 | 
			
		||||
    const uint8_t shifted_layer = layer << shift;
 | 
			
		||||
    source_layers_cache[byte_number] = (shifted_layer & mask) | (source_layers_cache[byte_number] & (~mask));
 | 
			
		||||
    cache[byte_number] = (shifted_layer & mask) | (cache[byte_number] & (~mask));
 | 
			
		||||
  } else {
 | 
			
		||||
    if (byte_number + 1 >= sizeof(source_layers_cache)) {
 | 
			
		||||
    if (byte_number + 1 >= num_cache_bytes) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    // We need to write two bytes
 | 
			
		||||
| 
						 | 
				
			
			@ -254,19 +271,23 @@ void update_source_layers_cache(keymatrix_t key, uint8_t layer)
 | 
			
		|||
    uint16_t inverse_mask = ~mask;
 | 
			
		||||
 | 
			
		||||
    // This could potentially be done with a single write, but then we have to assume the endian
 | 
			
		||||
    source_layers_cache[byte_number + 1] = masked_value | (source_layers_cache[byte_number + 1] & (inverse_mask));
 | 
			
		||||
    cache[byte_number + 1] = masked_value | (cache[byte_number + 1] & (inverse_mask));
 | 
			
		||||
    masked_value >>= 8;
 | 
			
		||||
    inverse_mask >>= 8;
 | 
			
		||||
    source_layers_cache[byte_number] = masked_value | (source_layers_cache[byte_number] & (inverse_mask));
 | 
			
		||||
    cache[byte_number] = masked_value | (cache[byte_number] & (inverse_mask));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t read_source_layers_cache(keymatrix_t key)
 | 
			
		||||
{
 | 
			
		||||
  const uint16_t key_number = key.pos.col + (key.pos.row * MATRIX_COLS);
 | 
			
		||||
  const uint8_t num_cols = keyboard_get_num_cols(key.matrix);
 | 
			
		||||
  const uint8_t num_rows = keyboard_get_num_rows(key.matrix);
 | 
			
		||||
  const uint16_t num_cache_bytes = get_source_layers_cache_size(num_cols, num_rows);
 | 
			
		||||
  uint8_t* cache = get_source_layers_cache(key);
 | 
			
		||||
  const uint16_t key_number = key.pos.col + (key.pos.row * num_cols);
 | 
			
		||||
  const uint32_t bit_number = key_number * MAX_LAYER_BITS;
 | 
			
		||||
  const uint16_t byte_number = bit_number / 8;
 | 
			
		||||
  if (byte_number >= sizeof(source_layers_cache)) {
 | 
			
		||||
  if (byte_number >= num_cache_bytes) {
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  const uint8_t bit_position = bit_number % 8;
 | 
			
		||||
| 
						 | 
				
			
			@ -276,17 +297,21 @@ uint8_t read_source_layers_cache(keymatrix_t key)
 | 
			
		|||
  if (shift > 8 ) {
 | 
			
		||||
    // We need to read only one byte
 | 
			
		||||
    shift -= 8;
 | 
			
		||||
    return (source_layers_cache[byte_number] >> shift) & layer_cache_mask;
 | 
			
		||||
    return (cache[byte_number] >> shift) & layer_cache_mask;
 | 
			
		||||
  } else {
 | 
			
		||||
    if (byte_number + 1 >= sizeof(source_layers_cache)) {
 | 
			
		||||
    if (byte_number + 1 >= num_cache_bytes) {
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
    // Otherwise read two bytes
 | 
			
		||||
    // This could potentially be done with a single read, but then we have to assume the endian
 | 
			
		||||
    uint16_t value = source_layers_cache[byte_number] << 8 | source_layers_cache[byte_number + 1];
 | 
			
		||||
    uint16_t value = cache[byte_number] << 8 | cache[byte_number + 1];
 | 
			
		||||
    return (value >> shift) & layer_cache_mask;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t get_source_layers_cache_size(uint8_t num_cols, uint8_t num_rows) {
 | 
			
		||||
  return (num_rows * num_cols * MAX_LAYER_BITS + 7) / 8;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** \brief Store or get action (FIXME: Needs better summary)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,6 +93,8 @@ uint32_t layer_state_set_kb(uint32_t state);
 | 
			
		|||
#define MAX_LAYER_BITS 5
 | 
			
		||||
void update_source_layers_cache(keymatrix_t key, uint8_t layer);
 | 
			
		||||
uint8_t read_source_layers_cache(keymatrix_t key);
 | 
			
		||||
 | 
			
		||||
uint8_t get_source_layers_cache_size(uint8_t num_cols, uint8_t num_rows);
 | 
			
		||||
#endif
 | 
			
		||||
action_t store_or_get_action(bool pressed, keymatrix_t key);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -145,6 +145,82 @@ bool is_keyboard_master(void) {
 | 
			
		|||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
uint8_t multimatrix_get_num_matrices(void) {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
uint8_t multimatrix_get_num_cols(uint8_t matrix) {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
uint8_t multimatrix_get_num_rows(uint8_t matrix) {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
uint32_t multimatrix_get_row(uint8_t matrix, uint8_t row) {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
uint32_t multimatrix_get_row_cache(uint8_t matrix, uint8_t row) {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__attribute__((weak))
 | 
			
		||||
void multimatrix_set_row_cache(uint8_t matrix, uint8_t row, uint32_t value) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t get_num_matrices(void) {
 | 
			
		||||
    return 1 + multimatrix_get_num_matrices();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t keyboard_get_num_cols(uint8_t matrix) {
 | 
			
		||||
    if (matrix == 0) {
 | 
			
		||||
      return MATRIX_COLS;
 | 
			
		||||
    } else {
 | 
			
		||||
      return multimatrix_get_num_cols(matrix - 1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t keyboard_get_num_rows(uint8_t matrix) {
 | 
			
		||||
    if (matrix == 0) {
 | 
			
		||||
      return MATRIX_ROWS;
 | 
			
		||||
    } else {
 | 
			
		||||
      return multimatrix_get_num_rows(matrix - 1);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t get_row(uint8_t matrix, uint8_t row) {
 | 
			
		||||
    if (matrix == 0) {
 | 
			
		||||
      return matrix_get_row(row);
 | 
			
		||||
    } else {
 | 
			
		||||
      return multimatrix_get_row(matrix - 1, row);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static matrix_row_t matrix_prev[MATRIX_ROWS];
 | 
			
		||||
 | 
			
		||||
static uint32_t get_row_cache(uint8_t matrix, uint8_t row) {
 | 
			
		||||
    if (matrix == 0) {
 | 
			
		||||
      return matrix_prev[row];
 | 
			
		||||
    } else {
 | 
			
		||||
      return multimatrix_get_row_cache(matrix - 1, row);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void set_row_cache(uint8_t matrix, uint8_t row, uint32_t value) {
 | 
			
		||||
    if (matrix == 0) {
 | 
			
		||||
      matrix_prev[row] = value;
 | 
			
		||||
    } else {
 | 
			
		||||
      return multimatrix_set_row_cache(matrix - 1, row, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** \brief keyboard_init
 | 
			
		||||
 *
 | 
			
		||||
 * FIXME: needs doc
 | 
			
		||||
| 
						 | 
				
			
			@ -203,54 +279,57 @@ void keyboard_init(void) {
 | 
			
		|||
 */
 | 
			
		||||
void keyboard_task(void)
 | 
			
		||||
{
 | 
			
		||||
    static matrix_row_t matrix_prev[MATRIX_ROWS];
 | 
			
		||||
#ifdef MATRIX_HAS_GHOST
 | 
			
		||||
  //  static matrix_row_t matrix_ghost[MATRIX_ROWS];
 | 
			
		||||
#endif
 | 
			
		||||
    static uint8_t led_status = 0;
 | 
			
		||||
    matrix_row_t matrix_row = 0;
 | 
			
		||||
    matrix_row_t matrix_change = 0;
 | 
			
		||||
    uint32_t matrix_row = 0;
 | 
			
		||||
    uint32_t matrix_change = 0;
 | 
			
		||||
#ifdef QMK_KEYS_PER_SCAN
 | 
			
		||||
    uint8_t keys_processed = 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    matrix_scan();
 | 
			
		||||
    if (is_keyboard_master()) {
 | 
			
		||||
        for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
 | 
			
		||||
            matrix_row = matrix_get_row(r);
 | 
			
		||||
            matrix_change = matrix_row ^ matrix_prev[r];
 | 
			
		||||
            if (matrix_change) {
 | 
			
		||||
        for (uint8_t m = 0; m < get_num_matrices(); m++) {
 | 
			
		||||
            uint8_t num_cols = keyboard_get_num_cols(m);
 | 
			
		||||
            uint8_t num_rows = keyboard_get_num_rows(m);
 | 
			
		||||
            for (uint8_t r = 0; r < num_rows; r++) {
 | 
			
		||||
                matrix_row = get_row(m, r);
 | 
			
		||||
                uint32_t row_cache = get_row_cache(m, r);
 | 
			
		||||
                matrix_change = matrix_row ^ row_cache;
 | 
			
		||||
                if (matrix_change) {
 | 
			
		||||
#ifdef MATRIX_HAS_GHOST
 | 
			
		||||
                if (has_ghost_in_row(r, matrix_row)) {
 | 
			
		||||
                    /* Keep track of whether ghosted status has changed for
 | 
			
		||||
                    * debugging. But don't update matrix_prev until un-ghosted, or
 | 
			
		||||
                    * the last key would be lost.
 | 
			
		||||
                    */
 | 
			
		||||
                    //if (debug_matrix && matrix_ghost[r] != matrix_row) {
 | 
			
		||||
                    //    matrix_print();
 | 
			
		||||
                    //}
 | 
			
		||||
                    //NOTE: The we support ghosting only for the main matrix, since it's only useful for old keyboards without diodes
 | 
			
		||||
                    if (has_ghost_in_row(r, matrix_row)) {
 | 
			
		||||
                        /* Keep track of whether ghosted status has changed for
 | 
			
		||||
                        * debugging. But don't update matrix_prev until un-ghosted, or
 | 
			
		||||
                        * the last key would be lost.
 | 
			
		||||
                        */
 | 
			
		||||
                        //if (debug_matrix && matrix_ghost[r] != matrix_row) {
 | 
			
		||||
                        //    matrix_print();
 | 
			
		||||
                        //}
 | 
			
		||||
                        //matrix_ghost[r] = matrix_row;
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                    //matrix_ghost[r] = matrix_row;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                //matrix_ghost[r] = matrix_row;
 | 
			
		||||
#endif
 | 
			
		||||
                if (debug_matrix) matrix_print();
 | 
			
		||||
                for (uint8_t c = 0; c < MATRIX_COLS; c++) {
 | 
			
		||||
                    if (matrix_change & ((matrix_row_t)1<<c)) {
 | 
			
		||||
                        action_exec((keyevent_t){
 | 
			
		||||
                            // The main matrix is always 0
 | 
			
		||||
                            .key = (keymatrix_t){.pos = (keypos_t){ .row = r, .col = c }, .matrix = 0},
 | 
			
		||||
                            .pressed = (matrix_row & ((matrix_row_t)1<<c)),
 | 
			
		||||
                            .time = (timer_read() | 1) /* time should not be 0 */
 | 
			
		||||
                        });
 | 
			
		||||
                        // record a processed key
 | 
			
		||||
                        matrix_prev[r] ^= ((matrix_row_t)1<<c);
 | 
			
		||||
                    if (debug_matrix) matrix_print();
 | 
			
		||||
                    for (uint8_t c = 0; c < num_cols; c++) {
 | 
			
		||||
                        if (matrix_change & (uint32_t)(1u<<c)) {
 | 
			
		||||
                            action_exec((keyevent_t){
 | 
			
		||||
                                // The main matrix is always 0
 | 
			
		||||
                                .key = (keymatrix_t){.pos = (keypos_t){ .row = r, .col = c }, .matrix = m},
 | 
			
		||||
                                .pressed = (matrix_row & ((uint32_t)1u<<c)),
 | 
			
		||||
                                .time = (timer_read() | 1) /* time should not be 0 */
 | 
			
		||||
                            });
 | 
			
		||||
                            // record a processed key
 | 
			
		||||
                            row_cache ^= (uint32_t)(1u<<c);
 | 
			
		||||
                            set_row_cache(m, r, row_cache);
 | 
			
		||||
#ifdef QMK_KEYS_PER_SCAN
 | 
			
		||||
                        // only jump out if we have processed "enough" keys.
 | 
			
		||||
                        if (++keys_processed >= QMK_KEYS_PER_SCAN)
 | 
			
		||||
                            // only jump out if we have processed "enough" keys.
 | 
			
		||||
                            if (++keys_processed >= QMK_KEYS_PER_SCAN)
 | 
			
		||||
#endif
 | 
			
		||||
                        // process a key per task call
 | 
			
		||||
                        goto MATRIX_LOOP_END;
 | 
			
		||||
                            // process a key per task call
 | 
			
		||||
                            goto MATRIX_LOOP_END;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,6 +72,9 @@ void keyboard_task(void);
 | 
			
		|||
/* it runs when host LED status is updated */
 | 
			
		||||
void keyboard_set_leds(uint8_t leds);
 | 
			
		||||
 | 
			
		||||
uint8_t keyboard_get_num_cols(uint8_t matrix);
 | 
			
		||||
uint8_t keyboard_get_num_rows(uint8_t matrix);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue