matrix.c (11496B)
1 /* 2 3 Copyright 2013 Oleg Kostyuk <cub.uanic@gmail.com> 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include "matrix.h" 20 #include "wait.h" 21 #include "debug.h" 22 #include "util.h" 23 #include "debounce.h" 24 #include "gergo.h" 25 26 #ifdef BALLER 27 # include <avr/interrupt.h> 28 # include "pointing_device.h" 29 #endif 30 31 #ifndef DEBOUNCE 32 # define DEBOUNCE 5 33 #endif 34 35 // MCP Pin Defs 36 #define RROW1 (1u << 3) 37 #define RROW2 (1u << 2) 38 #define RROW3 (1u << 1) 39 #define RROW4 (1u << 0) 40 #define COL0 (1u << 0) 41 #define COL1 (1u << 1) 42 #define COL2 (1u << 2) 43 #define COL3 (1u << 3) 44 #define COL4 (1u << 4) 45 #define COL5 (1u << 5) 46 #define COL6 (1u << 6) 47 48 // ATmega pin defs 49 #define ROW1 (1u << 6) 50 #define ROW2 (1u << 5) 51 #define ROW3 (1u << 4) 52 #define ROW4 (1u << 1) 53 #define COL7 (1u << 0) 54 #define COL8 (1u << 1) 55 #define COL9 (1u << 2) 56 #define COL10 (1u << 3) 57 #define COL11 (1u << 2) 58 #define COL12 (1u << 3) 59 #define COL13 (1u << 6) 60 61 // Trackball pin defs 62 #define TRKUP (1u << 4) 63 #define TRKDN (1u << 5) 64 #define TRKLT (1u << 6) 65 #define TRKRT (1u << 7) 66 #define TRKBTN (1u << 6) 67 68 // Multiple for mouse moves 69 #ifndef TRKSTEP 70 # define TRKSTEP 20 71 #endif 72 73 // multiple for mouse scroll 74 #ifndef SCROLLSTEP 75 # define SCROLLSTEP 5 76 #endif 77 78 // bit masks 79 #define BMASK (COL7 | COL8 | COL9 | COL10) 80 #define CMASK (COL13) 81 #define DMASK (COL11 | COL12) 82 #define FMASK (ROW1 | ROW2 | ROW3 | ROW4) 83 #define RROWMASK (RROW1 | RROW2 | RROW3 | RROW4) 84 #define MCPMASK (COL0 | COL1 | COL2 | COL3 | COL4 | COL5 | COL6) 85 #define TRKMASK (TRKUP | TRKDN | TRKRT | TRKLT) 86 87 // Trackball interrupts accumulate over here. Processed on scan 88 // Stores prev state of mouse, high bits store direction 89 uint8_t trkState = 0; 90 uint8_t trkBtnState = 0; 91 92 volatile uint8_t tbUpCnt = 0; 93 volatile uint8_t tbDnCnt = 0; 94 volatile uint8_t tbLtCnt = 0; 95 volatile uint8_t tbRtCnt = 0; 96 97 /* matrix state(1:on, 0:off) */ 98 static matrix_row_t matrix[MATRIX_ROWS]; 99 /* 100 * matrix state(1:on, 0:off) 101 * contains the raw values without debounce filtering of the last read cycle. 102 */ 103 static matrix_row_t raw_matrix[MATRIX_ROWS]; 104 105 // Debouncing: store for each key the number of scans until it's eligible to 106 // change. When scanning the matrix, ignore any changes in keys that have 107 // already changed in the last DEBOUNCE scans. 108 109 static matrix_row_t read_cols(uint8_t row); 110 static void init_cols(void); 111 static void unselect_rows(void); 112 static void select_row(uint8_t row); 113 static void enableInterrupts(void); 114 115 static uint8_t mcp23018_reset_loop; 116 // static uint16_t mcp23018_reset_loop; 117 118 __attribute__((weak)) void matrix_init_user(void) {} 119 120 __attribute__((weak)) void matrix_scan_user(void) {} 121 122 __attribute__((weak)) void matrix_init_kb(void) { 123 matrix_init_user(); 124 } 125 126 __attribute__((weak)) void matrix_scan_kb(void) { 127 matrix_scan_user(); 128 } 129 130 inline uint8_t matrix_rows(void) { 131 return MATRIX_ROWS; 132 } 133 134 inline uint8_t matrix_cols(void) { 135 return MATRIX_COLS; 136 } 137 138 void matrix_init(void) { 139 // initialize row and col 140 mcp23018_status = init_mcp23018(); 141 unselect_rows(); 142 init_cols(); 143 144 // initialize matrix state: all keys off 145 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 146 matrix[i] = 0; 147 raw_matrix[i] = 0; 148 } 149 150 debounce_init(); 151 matrix_init_kb(); 152 } 153 154 void matrix_power_up(void) { 155 mcp23018_status = init_mcp23018(); 156 157 unselect_rows(); 158 init_cols(); 159 160 // initialize matrix state: all keys off 161 for (uint8_t i = 0; i < MATRIX_ROWS; i++) { 162 matrix[i] = 0; 163 } 164 } 165 166 // Reads and stores a row, returning 167 // whether a change occurred. 168 static inline bool store_raw_matrix_row(uint8_t index) { 169 matrix_row_t temp = read_cols(index); 170 if (raw_matrix[index] != temp) { 171 raw_matrix[index] = temp; 172 return true; 173 } 174 return false; 175 } 176 177 uint8_t matrix_scan(void) { 178 // TODO: Find what is trashing interrupts 179 enableInterrupts(); 180 181 // First we handle the mouse inputs 182 #ifdef BALLER 183 uint8_t pBtn = PINE & TRKBTN; 184 185 # ifdef DEBUG_BALLER 186 // Compare to previous, mod report 187 if (tbUpCnt + tbDnCnt + tbLtCnt + tbRtCnt != 0) xprintf("U: %d D: %d L: %d R: %d B: %d\n", tbUpCnt, tbDnCnt, tbLtCnt, tbRtCnt, (trkBtnState >> 6)); 188 # endif 189 190 // Modify the report 191 report_mouse_t pRprt = pointing_device_get_report(); 192 193 // Scroll by default, move on layer 194 if (layer_state == 0) { 195 pRprt.h += tbLtCnt * SCROLLSTEP; 196 tbLtCnt = 0; 197 pRprt.h -= tbRtCnt * SCROLLSTEP; 198 tbRtCnt = 0; 199 pRprt.v -= tbUpCnt * SCROLLSTEP; 200 tbUpCnt = 0; 201 pRprt.v += tbDnCnt * SCROLLSTEP; 202 tbDnCnt = 0; 203 } else { 204 pRprt.x -= tbLtCnt * TRKSTEP * (layer_state - 1); 205 tbLtCnt = 0; 206 pRprt.x += tbRtCnt * TRKSTEP * (layer_state - 1); 207 tbRtCnt = 0; 208 pRprt.y -= tbUpCnt * TRKSTEP * (layer_state - 1); 209 tbUpCnt = 0; 210 pRprt.y += tbDnCnt * TRKSTEP * (layer_state - 1); 211 tbDnCnt = 0; 212 } 213 214 # ifdef DEBUG_BALLER 215 if (pRprt.x != 0 || pRprt.y != 0) xprintf("X: %d Y: %d\n", pRprt.x, pRprt.y); 216 # endif 217 218 if ((pBtn != trkBtnState) && ((pBtn >> 6) == 0)) pRprt.buttons |= MOUSE_BTN1; 219 if ((pBtn != trkBtnState) && ((pBtn >> 6) == 1)) pRprt.buttons &= ~MOUSE_BTN1; 220 221 // Save state, push update 222 if (pRprt.x != 0 || pRprt.y != 0 || pRprt.h != 0 || pRprt.v != 0 || (trkBtnState != pBtn)) pointing_device_set_report(pRprt); 223 224 trkBtnState = pBtn; 225 #endif 226 227 // Then the keyboard 228 if (mcp23018_status) { // if there was an error 229 if (++mcp23018_reset_loop == 0) { 230 // if (++mcp23018_reset_loop >= 1300) { 231 // since mcp23018_reset_loop is 8 bit - we'll try to reset once in 255 matrix scans 232 // this will be approx bit more frequent than once per second 233 print("trying to reset mcp23018\n"); 234 mcp23018_status = init_mcp23018(); 235 if (mcp23018_status) { 236 print("left side not responding\n"); 237 } else { 238 print("left side attached\n"); 239 } 240 } 241 } 242 243 bool changed = false; 244 for (uint8_t i = 0; i < MATRIX_ROWS_PER_SIDE; i++) { 245 // select rows from left and right hands 246 uint8_t left_index = i; 247 uint8_t right_index = i + MATRIX_ROWS_PER_SIDE; 248 select_row(left_index); 249 select_row(right_index); 250 251 // we don't need a 30us delay anymore, because selecting a 252 // left-hand row requires more than 30us for i2c. 253 254 changed |= store_raw_matrix_row(left_index); 255 changed |= store_raw_matrix_row(right_index); 256 257 unselect_rows(); 258 } 259 260 debounce(raw_matrix, matrix, changed); 261 matrix_scan_kb(); 262 263 enableInterrupts(); 264 265 #ifdef DEBUG_MATRIX 266 for (uint8_t c = 0; c < MATRIX_COLS; c++) 267 for (uint8_t r = 0; r < MATRIX_ROWS; r++) 268 if (matrix_is_on(r, c)) xprintf("r:%d c:%d \n", r, c); 269 #endif 270 271 return 1; 272 } 273 274 inline bool matrix_is_on(uint8_t row, uint8_t col) { 275 return (matrix[row] & ((matrix_row_t)1 << col)); 276 } 277 278 inline matrix_row_t matrix_get_row(uint8_t row) { 279 return matrix[row]; 280 } 281 282 void matrix_print(void) { 283 print("\nr/c 0123456789ABCDEF\n"); 284 for (uint8_t row = 0; row < MATRIX_ROWS; row++) { 285 print_hex8(row); 286 print(": "); 287 print_bin_reverse16(matrix_get_row(row)); 288 print("\n"); 289 } 290 } 291 292 // Remember this means ROWS 293 static void init_cols(void) { 294 // init on mcp23018 295 // not needed, already done as part of init_mcp23018() 296 297 // Input with pull-up(DDR:0, PORT:1) 298 DDRF &= ~FMASK; 299 PORTF |= FMASK; 300 } 301 302 static matrix_row_t read_cols(uint8_t row) { 303 if (row < 7) { 304 if (mcp23018_status) { // if there was an error 305 return 0; 306 } else { 307 uint8_t data = 0; 308 mcp23018_status = i2c_read_register(I2C_ADDR, GPIOB, &data, 1, I2C_TIMEOUT); 309 310 #ifdef DEBUG_MATRIX 311 if (~data != 0x00) xprintf("I2C: %d\n", ~data); 312 #endif 313 return ~data; 314 } 315 } else { 316 /* read from teensy 317 * bitmask is 0b0111001, but we want the lower four 318 * we'll return 1s for the top two, but that's harmless. 319 */ 320 // So I need to confuckulate all this 321 // return ~(((PIND & DMASK) >> 1 | ((PINC & CMASK) >> 6) | (PIN))); 322 // return ~((PINF & 0x03) | ((PINF & 0xF0) >> 2)); 323 return ~((((PINF & ROW4) >> 1) | ((PINF & (ROW1 | ROW2 | ROW3)) >> 3)) & 0xF); 324 } 325 } 326 327 // Row pin configuration 328 static void unselect_rows(void) { 329 // no need to unselect on mcp23018, because the select step sets all 330 // the other row bits high, and it's not changing to a different 331 // direction 332 // Hi-Z(DDR:0, PORT:0) to unselect 333 DDRB &= ~(BMASK | TRKMASK); 334 PORTB &= ~(BMASK); 335 DDRC &= ~CMASK; 336 PORTC &= ~CMASK; 337 DDRD &= ~DMASK; 338 PORTD &= ~DMASK; 339 340 // Fix trashing of DDRB for TB 341 PORTB |= TRKMASK; 342 } 343 344 static void select_row(uint8_t row) { 345 if (row < 7) { 346 // select on mcp23018 347 if (mcp23018_status) { // do nothing on error 348 } else { // set active row low : 0 // set other rows hi-Z : 1 349 uint8_t data = 0xFF & ~(1 << row); 350 mcp23018_status = i2c_write_register(I2C_ADDR, GPIOA, &data, 1, I2C_TIMEOUT); 351 } 352 } else { 353 // Output low(DDR:1, PORT:0) to select 354 switch (row) { 355 case 7: 356 DDRB |= COL7; 357 PORTB &= ~COL7; 358 break; 359 case 8: 360 DDRB |= COL8; 361 PORTB &= ~COL8; 362 break; 363 case 9: 364 DDRB |= COL9; 365 PORTB &= ~COL9; 366 break; 367 case 10: 368 DDRB |= COL10; 369 PORTB &= ~COL10; 370 break; 371 case 11: 372 DDRD |= COL11; 373 PORTD &= ~COL11; 374 break; 375 case 12: 376 DDRD |= COL12; 377 PORTD &= ~COL12; 378 break; 379 case 13: 380 DDRC |= COL13; 381 PORTC &= ~COL13; 382 break; 383 } 384 } 385 } 386 387 // Trackball Interrupts 388 static void enableInterrupts(void) { 389 #ifdef BALLER 390 // Set interrupt mask 391 // Set port defs 392 DDRB &= ~TRKMASK; 393 PORTB |= TRKMASK; 394 DDRE &= ~TRKBTN; 395 PORTE |= TRKBTN; 396 397 // Interrupt shenanigans 398 // EIMSK |= (1 << PCIE0); 399 PCMSK0 |= TRKMASK; 400 PCICR |= (1 << PCIE0); 401 sei(); 402 #endif 403 404 return; 405 } 406 #ifdef BALLER 407 ISR(PCINT0_vect) { 408 // Don't get fancy, we're in a interrupt here 409 // PCINT reports a interrupt for a change on the bus 410 // We hand the button at scantime for debounce 411 volatile uint8_t pState = PINB & TRKMASK; 412 if ((pState & TRKUP) != (trkState & TRKUP)) tbUpCnt++; 413 if ((pState & TRKDN) != (trkState & TRKDN)) tbDnCnt++; 414 if ((pState & TRKLT) != (trkState & TRKLT)) tbLtCnt++; 415 if ((pState & TRKRT) != (trkState & TRKRT)) tbRtCnt++; 416 trkState = pState; 417 } 418 #endif