qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

djinn_portscan_matrix.c (4224B)


      1 // Copyright 2018-2022 Nick Brassel (@tzarc)
      2 // SPDX-License-Identifier: GPL-2.0-or-later
      3 #include "djinn.h"
      4 
      5 #define GPIOB_BITMASK (1 << 13 | 1 << 14 | 1 << 15) // B13, B14, B15
      6 #define GPIOB_OFFSET 13
      7 #define GPIOB_COUNT 3
      8 #define GPIOC_BITMASK (1 << 6 | 1 << 7 | 1 << 8) // C6, C7, C8
      9 #define GPIOC_OFFSET 6
     10 
     11 // Pin definitions
     12 static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
     13 static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
     14 
     15 void matrix_wait_for_pin(pin_t pin, uint8_t target_state) {
     16     rtcnt_t start = chSysGetRealtimeCounterX();
     17     rtcnt_t end   = start + 5000;
     18     while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
     19         if (gpio_read_pin(pin) == target_state) {
     20             break;
     21         }
     22     }
     23 }
     24 
     25 void matrix_wait_for_port(stm32_gpio_t *port, uint32_t target_bitmask) {
     26     rtcnt_t start = chSysGetRealtimeCounterX();
     27     rtcnt_t end   = start + 5000;
     28     while (chSysIsCounterWithinX(chSysGetRealtimeCounterX(), start, end)) {
     29         if ((palReadPort(port) & target_bitmask) == target_bitmask) {
     30             break;
     31         }
     32     }
     33 }
     34 
     35 static void dummy_vt_callback(virtual_timer_t *vtp, void *p) {}
     36 
     37 void matrix_init_custom(void) {
     38     for (int i = 0; i < MATRIX_ROWS; ++i) {
     39         gpio_set_pin_input_high(row_pins[i]);
     40     }
     41     for (int i = 0; i < MATRIX_COLS; ++i) {
     42         gpio_set_pin_input_high(col_pins[i]);
     43     }
     44 
     45     // Start a virtual timer so we'll still get periodic wakeups, now that USB SOF doesn't wake up the main loop
     46     static virtual_timer_t vt;
     47     chVTObjectInit(&vt);
     48     chVTSetContinuous(&vt, TIME_MS2I(10), dummy_vt_callback, NULL);
     49 }
     50 
     51 bool matrix_scan_custom(matrix_row_t current_matrix[]) {
     52     static matrix_row_t temp_matrix[MATRIX_ROWS] = {0};
     53 
     54     for (int current_col = 0; current_col < MATRIX_COLS; ++current_col) {
     55         // Keep track of the pin we're working with
     56         pin_t curr_col_pin = col_pins[current_col];
     57 
     58         // Setup the output column pin
     59         gpio_set_pin_output(curr_col_pin);
     60         gpio_write_pin_low(curr_col_pin);
     61         matrix_wait_for_pin(curr_col_pin, 0);
     62 
     63         // Read the row ports
     64         uint32_t gpio_b = palReadPort(GPIOB);
     65         uint32_t gpio_c = palReadPort(GPIOC);
     66 
     67         // Unselect the row pin
     68         gpio_set_pin_input_high(curr_col_pin);
     69 
     70         // Construct the packed bitmask for the pins
     71         uint32_t readback = ~(((gpio_b & GPIOB_BITMASK) >> GPIOB_OFFSET) | (((gpio_c & GPIOC_BITMASK) >> GPIOC_OFFSET) << GPIOB_COUNT));
     72 
     73         // Inject values into the matrix
     74         for (int i = 0; i < MATRIX_ROWS; ++i) {
     75             if (readback & (1 << i)) {
     76                 temp_matrix[i] |= (1ul << current_col);
     77             } else {
     78                 temp_matrix[i] &= ~(1ul << current_col);
     79             }
     80         }
     81 
     82         // Wait for readback of the unselected column to go high
     83         matrix_wait_for_pin(curr_col_pin, 1);
     84 
     85         // Wait for readback of each port to go high -- unselecting the row would have been completed
     86         matrix_wait_for_port(GPIOB, GPIOB_BITMASK);
     87         matrix_wait_for_port(GPIOC, GPIOC_BITMASK);
     88     }
     89 
     90     // Check if we've changed, return the last-read data
     91     bool changed = memcmp(current_matrix, temp_matrix, sizeof(temp_matrix)) != 0;
     92     if (changed) {
     93         memcpy(current_matrix, temp_matrix, sizeof(temp_matrix));
     94     }
     95     return changed;
     96 }
     97 
     98 void matrix_wait_for_interrupt(void) {
     99     // Set up row/col pins and attach callback
    100     for (int i = 0; i < ARRAY_SIZE(col_pins); ++i) {
    101         gpio_set_pin_output(col_pins[i]);
    102         gpio_write_pin_low(col_pins[i]);
    103     }
    104     for (int i = 0; i < ARRAY_SIZE(row_pins); ++i) {
    105         gpio_set_pin_input_high(row_pins[i]);
    106         palEnableLineEvent(row_pins[i], PAL_EVENT_MODE_BOTH_EDGES);
    107     }
    108 
    109     // Wait for an interrupt
    110     __WFI();
    111 
    112     // Now that the interrupt has woken us up, reset all the row/col pins back to defaults
    113     for (int i = 0; i < ARRAY_SIZE(row_pins); ++i) {
    114         palDisableLineEvent(row_pins[i]);
    115         gpio_write_pin_high(row_pins[i]);
    116         gpio_set_pin_input_high(row_pins[i]);
    117     }
    118     for (int i = 0; i < ARRAY_SIZE(col_pins); ++i) {
    119         gpio_write_pin_high(col_pins[i]);
    120         gpio_set_pin_input_high(col_pins[i]);
    121     }
    122 }