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 }