You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. Copyright 2011 Jun Wako <[email protected]>
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /*
  15. * scan matrix
  16. */
  17. #include <stdint.h>
  18. #include <stdbool.h>
  19. #include <avr/io.h>
  20. #include <util/delay.h>
  21. #include "print.h"
  22. #include "debug.h"
  23. #include "util.h"
  24. #include "matrix.h"
  25. #include "led.h"
  26. #if (MATRIX_COLS > 16)
  27. # error "MATRIX_COLS must not exceed 16"
  28. #endif
  29. #if (MATRIX_ROWS > 255)
  30. # error "MATRIX_ROWS must not exceed 255"
  31. #endif
  32. #ifndef DEBOUNCE
  33. # define DEBOUNCE 0
  34. #endif
  35. static uint8_t debouncing = DEBOUNCE;
  36. // matrix state buffer(1:on, 0:off)
  37. #if (MATRIX_COLS <= 8)
  38. static uint8_t *matrix;
  39. static uint8_t *matrix_prev;
  40. static uint8_t _matrix0[MATRIX_ROWS];
  41. static uint8_t _matrix1[MATRIX_ROWS];
  42. #else
  43. static uint16_t *matrix;
  44. static uint16_t *matrix_prev;
  45. static uint16_t _matrix0[MATRIX_ROWS];
  46. static uint16_t _matrix1[MATRIX_ROWS];
  47. #endif
  48. #ifdef MATRIX_HAS_GHOST
  49. static bool matrix_has_ghost_in_row(uint8_t row);
  50. #endif
  51. static uint8_t read_col(uint8_t row);
  52. static void unselect_rows(void);
  53. static void select_row(uint8_t row);
  54. inline
  55. uint8_t matrix_rows(void)
  56. {
  57. return MATRIX_ROWS;
  58. }
  59. inline
  60. uint8_t matrix_cols(void)
  61. {
  62. return MATRIX_COLS;
  63. }
  64. void matrix_init(void)
  65. {
  66. // initialize row and col
  67. unselect_rows();
  68. // Input with pull-up(DDR:0, PORT:1)
  69. // Column C1 ~ C7 (PortC0-6)
  70. // Column C0(Port E1)
  71. DDRC &= ~0b01111111;
  72. PORTC |= 0b01111111;
  73. DDRE &= ~0b00000010;
  74. PORTE |= 0b00000010;
  75. //DDRB &= ~0b00000100;
  76. //PORTB |= 0b00000100;
  77. // modifier B3/4,F4/5,E4 always input
  78. // A0
  79. //DDRA |= 0b00000001;
  80. //PORTA &= 0b00000001;
  81. //DDRB |= 0b00011000;
  82. //PORTB &= 0b00011000;
  83. //DDRF |= ~0b00110000;
  84. //PORTF &= 0b00110000;
  85. //DDRB &= ~0b00011000;
  86. //PORTB |= 0b00011000;
  87. //DDRF &= ~0b00110000;
  88. //PORTF |= 0b00110000;
  89. //DDRE &= ~0b00010000;
  90. //PORTE |= 0b00010000;
  91. // initialize matrix state: all keys off
  92. for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
  93. for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
  94. matrix = _matrix0;
  95. matrix_prev = _matrix1;
  96. }
  97. uint8_t matrix_scan(void)
  98. {
  99. if (!debouncing) {
  100. uint8_t *tmp = matrix_prev;
  101. matrix_prev = matrix;
  102. matrix = tmp;
  103. }
  104. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  105. unselect_rows();
  106. select_row(i);
  107. _delay_us(30); // without this wait read unstable value.
  108. if ( i == ( MATRIX_ROWS - 1 ) ) { // CHECK CAPS LOCK
  109. if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) { // CAPS LOCK is ON on HOST
  110. if ( ~read_col(i) & (1<< 4) ) { // CAPS LOCK is still DOWN ( 0bXXX1_XXXX)
  111. matrix[i] = ~read_col(i) & 0b11101111; // change CAPS LOCK as released
  112. } else { // CAPS LOCK in UP
  113. matrix[i] = ~read_col(i) | 0b00010000; // send fake caps lock down
  114. }
  115. } else { // CAPS LOCK is OFF on HOST
  116. if (matrix[i] != (uint8_t)~read_col(i)) {
  117. matrix[i] = (uint8_t)~read_col(i);
  118. if (debouncing) {
  119. debug("bounce!: "); debug_hex(debouncing); print("\n");
  120. }
  121. debouncing = DEBOUNCE;
  122. }
  123. }
  124. } else {
  125. if (matrix[i] != (uint8_t)~read_col(i)) {
  126. matrix[i] = (uint8_t)~read_col(i);
  127. if (debouncing) {
  128. debug("bounce!: "); debug_hex(debouncing); print("\n");
  129. }
  130. debouncing = DEBOUNCE;
  131. }
  132. }
  133. }
  134. unselect_rows();
  135. if (debouncing) {
  136. debouncing--;
  137. }
  138. return 1;
  139. }
  140. bool matrix_is_modified(void)
  141. {
  142. if (debouncing) return false;
  143. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  144. if (matrix[i] != matrix_prev[i]) {
  145. return true;
  146. }
  147. }
  148. return false;
  149. }
  150. inline
  151. bool matrix_has_ghost(void)
  152. {
  153. #ifdef MATRIX_HAS_GHOST
  154. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  155. if (matrix_has_ghost_in_row(i))
  156. return true;
  157. }
  158. #endif
  159. return false;
  160. }
  161. inline
  162. bool matrix_is_on(uint8_t row, uint8_t col)
  163. {
  164. // if ( row == ( MATRIX_ROWS - 1 ) && col == 4) { // CHECK CAPS LOCK
  165. // if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) { // CAPS LOCK is ON on HOST
  166. // if ((matrix_prev[row] & 0b00010000) && (~matrix[row] & 0b00010000)) {
  167. // debug("CapsLock Reverse:");debug_hex(matrix[row]);
  168. // matrix[row] |= 0b00010000;
  169. // matrix_prev[row] &= ~0b00010000;
  170. // debug("->");debug_hex(matrix[row]);debug("\n");
  171. // }
  172. // }
  173. // }
  174. return (matrix[row] & (1<<col));
  175. }
  176. inline
  177. #if (MATRIX_COLS <= 8)
  178. uint8_t matrix_get_row(uint8_t row)
  179. #else
  180. uint16_t matrix_get_row(uint8_t row)
  181. #endif
  182. {
  183. return matrix[row];
  184. }
  185. void matrix_print(void)
  186. {
  187. print("\nr/c 01234567\n");
  188. for (uint8_t row = 0; row < matrix_rows(); row++) {
  189. phex(row); print(": ");
  190. #if (MATRIX_COLS <= 8)
  191. pbin_reverse(matrix_get_row(row));
  192. #else
  193. pbin_reverse16(matrix_get_row(row));
  194. #endif
  195. #ifdef MATRIX_HAS_GHOST
  196. if (matrix_has_ghost_in_row(row)) {
  197. print(" <ghost");
  198. }
  199. #endif
  200. print("\n");
  201. }
  202. }
  203. uint8_t matrix_key_count(void)
  204. {
  205. uint8_t count = 0;
  206. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  207. #if (MATRIX_COLS <= 8)
  208. count += bitpop(matrix[i]);
  209. #else
  210. count += bitpop16(matrix[i]);
  211. #endif
  212. }
  213. return count;
  214. }
  215. #ifdef MATRIX_HAS_GHOST
  216. inline
  217. static bool matrix_has_ghost_in_row(uint8_t row)
  218. {
  219. // no ghost exists in case less than 2 keys on
  220. if (((matrix[row] - 1) & matrix[row]) == 0)
  221. return false;
  222. // ghost exists in case same state as other row
  223. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  224. if (i != row && (matrix[i] & matrix[row]) == matrix[row])
  225. return true;
  226. }
  227. return false;
  228. }
  229. #endif
  230. inline
  231. static uint8_t read_col(uint8_t row)
  232. {
  233. // For normal : Column C1 ~ C7 (PortC0-6), C0(Port E1)
  234. // For modifier : B3(CNTRL)/4(SHIFT),F4(CMD/GUI)/5(OPTION,ALT)
  235. // Modifier would be copied to report->mods except E4(CAPSLOCK)
  236. uint8_t tmp;
  237. if ( row == 10 ) {
  238. tmp = 0xC0;
  239. tmp |= (PINB >> 3 ) & 0b00000011; // LEFT CTRL is 0bit in modifier (HID Spec)
  240. // LEFT SHIFT is 1bit in modifier (HID Spec)
  241. tmp |= (PINF >> 3 ) & 0b00000100; // LEFT ALT is 2bit in modifier (HID Spec)
  242. tmp |= (PINF >> 1 ) & 0b00001000; // LEFT GUI is 3bit in modifier (HID Spec)
  243. tmp |= (PINA << 4 ) & 0b00010000; // CAPSLOCK
  244. tmp |= (PINB << 3 ) & 0b00100000; // POWER
  245. } else {
  246. tmp = 0x00;
  247. tmp = (PINE >> 1)&0b00000001;
  248. tmp |= PINC << 1 ;
  249. }
  250. return tmp;
  251. }
  252. inline
  253. static void unselect_rows(void)
  254. {
  255. // Hi-Z(DDR:0, PORT:0) to unselect
  256. // DDR : 1, output 0, input
  257. DDRB &= ~0b00000011; // PB: 1,0
  258. PORTB &= ~0b00000011;
  259. DDRD &= ~0b00010000; // PD: 4
  260. PORTD &= ~0b00010000;
  261. DDRE &= ~0b11000000; // PE: 7,6
  262. PORTE &= ~0b11000000;
  263. DDRF &= ~0b11000111; // PF: 7,6,2,1,0
  264. PORTF &= ~0b11000111;
  265. // to unselect virtual row(modifier), set port to output with low
  266. DDRA |= 0b00000001; // PA: 0 for CAPSLOCK
  267. PORTA &= ~0b00000001;
  268. DDRB |= 0b00011100; // PB: 3,4 for modifier(row10)
  269. PORTB &= ~0b00011100; // PB: 2 for power
  270. DDRF |= 0b00110000; // PF: 4,5 for modifier
  271. PORTF &= ~0b00110000;
  272. }
  273. inline
  274. static void select_row(uint8_t row)
  275. {
  276. // Output low(DDR:1, PORT:0) to select
  277. // with row enable, column could send low to AVR when pressed
  278. // row: 0 1 2 3 4 5 6 7 8 9
  279. // pin: PB1, PB0, PE7, PE6, PD4, PF2, PF0, PF1, PF6 PF7
  280. switch (row) {
  281. case 0:
  282. DDRB |= (1<<1);
  283. PORTB &= ~(1<<1);
  284. break;
  285. case 1:
  286. DDRB |= (1<<0);
  287. PORTB &= ~(1<<0);
  288. break;
  289. case 2:
  290. DDRE |= (1<<7);
  291. PORTE &= ~(1<<7);
  292. break;
  293. case 3:
  294. DDRE |= (1<<6);
  295. PORTE &= ~(1<<6);
  296. break;
  297. case 4:
  298. DDRD |= (1<<4);
  299. PORTD &= ~(1<<4);
  300. break;
  301. case 5:
  302. DDRF |= (1<<2);
  303. PORTF &= ~(1<<2);
  304. break;
  305. case 6:
  306. DDRF |= (1<<0);
  307. PORTF &= ~(1<<0);
  308. break;
  309. case 7:
  310. DDRF |= (1<<1);
  311. PORTF &= ~(1<<1);
  312. break;
  313. case 8:
  314. DDRF |= (1<<6);
  315. PORTF &= ~(1<<6);
  316. break;
  317. case 9:
  318. DDRF |= (1<<7);
  319. PORTF &= ~(1<<7);
  320. break;
  321. case 10:
  322. // modifier has no row enable
  323. // to select virtual row, set port as input
  324. DDRA &= ~0b00000001;
  325. PORTA |= 0b00000001;
  326. DDRB &= ~0b00011100;
  327. PORTB |= 0b00011100;
  328. DDRF &= ~0b00110000;
  329. PORTF |= 0b00110000;
  330. break;
  331. }
  332. }