Keyboard firmwares for Atmel AVR and Cortex-M
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.

пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
пре 13 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  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 "util.h"
  23. #include "debug.h"
  24. #include "ps2.h"
  25. #include "matrix.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. /*
  33. * Matrix usage:
  34. * "PS/2 Scan Codes Set 2" is assigned to 256(32x8)cells matrix.
  35. * Hmm, It is very sparse and not efficient :(
  36. *
  37. * 8bit
  38. * ---------
  39. * 0| |
  40. * :| XX | 00-7F for normal codes(without E0-prefix)
  41. * f|_________|
  42. * 10| |
  43. * :| E0 XX | 80-FF for E0-prefix codes(use (XX|0x80) as code)
  44. * 1f| |
  45. * ---------
  46. * exceptions:
  47. * 83: F8[0x83](normal codes but > 0x7F)
  48. * FC: PrintScreen[E0 7C or 84]
  49. * FE: Puause
  50. */
  51. #define F8 (0x83)
  52. #define PRINT_SCREEN (0xFC)
  53. #define PAUSE (0xFE)
  54. #define ROW(code) (code>>3)
  55. #define COL(code) (code&0x07)
  56. static bool is_modified = false;
  57. // matrix state buffer(1:on, 0:off)
  58. #if (MATRIX_COLS <= 8)
  59. static uint8_t matrix[MATRIX_ROWS];
  60. #else
  61. static uint16_t matrix[MATRIX_ROWS];
  62. #endif
  63. #ifdef MATRIX_HAS_GHOST
  64. static bool matrix_has_ghost_in_row(uint8_t row);
  65. #endif
  66. static void matrix_make(uint8_t code);
  67. static void matrix_break(uint8_t code);
  68. inline
  69. uint8_t matrix_rows(void)
  70. {
  71. return MATRIX_ROWS;
  72. }
  73. inline
  74. uint8_t matrix_cols(void)
  75. {
  76. return MATRIX_COLS;
  77. }
  78. void matrix_init(void)
  79. {
  80. ps2_host_init();
  81. // initialize matrix state: all keys off
  82. for (uint8_t i=0; i < MATRIX_ROWS; i++) matrix[i] = 0x00;
  83. return;
  84. }
  85. /*
  86. * PS/2 Scan Code Set 2: Exceptional Handling
  87. *
  88. * There are several keys to be handled exceptionally.
  89. * The scan code for these keys are varied or prefix/postfix'd
  90. * depending on modifier key state.
  91. *
  92. * References:
  93. * http://www.microsoft.com/whdc/archive/scancode.mspx
  94. * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc
  95. *
  96. *
  97. * Insert, Delete, Home, End, PageUp, PageDown, Up, Down, Right, Left:
  98. * Num Lock: off
  99. * modifiers | make | break
  100. * ----------+---------------------------+----------------------
  101. * Ohter | <make> | <break>
  102. * LShift | E0 F0 12 <make> | <break> E0 12
  103. * RShift | E0 F0 59 <make> | <break> E0 59
  104. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  105. *
  106. * Num Lock: on
  107. * modifiers | make | break
  108. * ----------+---------------------------+----------------------
  109. * Other | E0 12 <make> | <break> E0 F0 12
  110. * Shift'd | <make> | <break>
  111. *
  112. * Handling: ignore these prefix/postfix codes
  113. *
  114. *
  115. * Keypad-/:
  116. * modifiers | make | break
  117. * ----------+---------------------------+----------------------
  118. * Ohter | <make> | <break>
  119. * LShift | E0 F0 12 <make> | <break> E0 12
  120. * RShift | E0 F0 59 <make> | <break> E0 59
  121. * L+RShift | E0 F0 12 E0 F0 59 <make> | <break> E0 59 E0 12
  122. *
  123. * Handling: ignore these prefix/postfix codes
  124. *
  125. *
  126. * PrintScreen:
  127. * With hoding down modifiers, the scan code is sent as following:
  128. *
  129. * modifiers | make | break
  130. * ----------+--------------+-----------------------------------
  131. * Other | E0 12 E0 7C | E0 F0 7C E0 F0 12
  132. * Shift'd | E0 7C | E0 F0 7C
  133. * Control'd | E0 7C | E0 F0 7C
  134. * Alt'd | 84 | F0 84
  135. *
  136. * Handling: ignore prefix/postfix codes and treat both scan code
  137. * E0 7C and 84 as PrintScreen.
  138. *
  139. * Pause:
  140. * With hoding down modifiers, the scan code is sent as following:
  141. *
  142. * modifiers | make(no break code)
  143. * ----------+--------------------------------------------------
  144. * no mods | E1 14 77 E1 F0 14 F0 77
  145. * Control'd | E0 7E E0 F0 7E
  146. *
  147. * Handling: treat these two code sequence as Pause
  148. *
  149. */
  150. uint8_t matrix_scan(void)
  151. {
  152. static enum {
  153. INIT,
  154. F0,
  155. E0,
  156. E0_F0,
  157. // states for Pause/Break
  158. E1,
  159. E1_14,
  160. E1_14_77,
  161. E1_14_77_E1,
  162. E1_14_77_E1_F0,
  163. E1_14_77_E1_F0_14,
  164. E1_14_77_E1_F0_14_F0,
  165. } state = INIT;
  166. is_modified = false;
  167. // Pause/Break off(PS/2 has no break for this key)
  168. if (matrix_is_on(ROW(PAUSE), COL(PAUSE))) {
  169. matrix_break(PAUSE);
  170. }
  171. uint8_t code;
  172. while ((code = ps2_host_recv())) {
  173. switch (state) {
  174. case INIT:
  175. switch (code) {
  176. case 0xE0: // 2byte make
  177. state = E0;
  178. break;
  179. case 0xF0: // break code
  180. state = F0;
  181. break;
  182. case 0xE1: // Pause/Break
  183. state = E1;
  184. break;
  185. case 0x83: // F8
  186. matrix_make(F8);
  187. state = INIT;
  188. break;
  189. case 0x84: // PrintScreen
  190. matrix_make(PRINT_SCREEN);
  191. state = INIT;
  192. break;
  193. default: // normal key make
  194. if (code < 0x80) {
  195. matrix_make(code);
  196. } else {
  197. debug("unexpected scan code at INIT: "); debug_hex(code); debug("\n");
  198. }
  199. state = INIT;
  200. }
  201. break;
  202. case E0:
  203. switch (code) {
  204. case 0x12: // postfix/postfix code for exceptional keys
  205. case 0x59: // postfix/postfix code for exceptional keys
  206. // ignore
  207. state = INIT;
  208. break;
  209. case 0x7E: // former part of Control-Pause[E0 7E E0 F0 7E]
  210. matrix_make(PAUSE);
  211. state = INIT;
  212. break;
  213. case 0xF0: // E0 break
  214. state = E0_F0;
  215. break;
  216. default: // E0 make
  217. if (code < 0x80) {
  218. matrix_make(code|0x80);
  219. } else {
  220. debug("unexpected scan code at E0: "); debug_hex(code); debug("\n");
  221. }
  222. state = INIT;
  223. }
  224. break;
  225. case F0:
  226. switch (code) {
  227. case 0x83:
  228. matrix_break(F8);
  229. state = INIT;
  230. break;
  231. case 0x84:
  232. matrix_break(PRINT_SCREEN);
  233. state = INIT;
  234. break;
  235. default:
  236. if (code < 0x80) {
  237. matrix_break(code);
  238. } else {
  239. debug("unexpected scan code at F0: "); debug_hex(code); debug("\n");
  240. }
  241. state = INIT;
  242. }
  243. break;
  244. case E0_F0: // E0 break
  245. switch (code) {
  246. case 0x12: // postfix/postfix code for exceptional keys
  247. case 0x59: // postfix/postfix code for exceptional keys
  248. case 0x7E: // latter part of Control-Pause[E0 7E E0 F0 7E]
  249. // ignore
  250. state = INIT;
  251. break;
  252. default:
  253. if (code < 0x80) {
  254. matrix_break(code|0x80);
  255. } else {
  256. debug("unexpected scan code at E0_F0: "); debug_hex(code); debug("\n");
  257. }
  258. state = INIT;
  259. }
  260. break;
  261. /* Pause */
  262. case E1:
  263. switch (code) {
  264. case 0x14:
  265. state = E1_14;
  266. break;
  267. default:
  268. state = INIT;
  269. }
  270. break;
  271. case E1_14:
  272. switch (code) {
  273. case 0x77:
  274. state = E1_14_77;
  275. break;
  276. default:
  277. state = INIT;
  278. }
  279. break;
  280. case E1_14_77:
  281. switch (code) {
  282. case 0xE1:
  283. state = E1_14_77_E1;
  284. break;
  285. default:
  286. state = INIT;
  287. }
  288. break;
  289. case E1_14_77_E1:
  290. switch (code) {
  291. case 0xF0:
  292. state = E1_14_77_E1_F0;
  293. break;
  294. default:
  295. state = INIT;
  296. }
  297. break;
  298. case E1_14_77_E1_F0:
  299. switch (code) {
  300. case 0x14:
  301. state = E1_14_77_E1_F0_14;
  302. break;
  303. default:
  304. state = INIT;
  305. }
  306. break;
  307. case E1_14_77_E1_F0_14:
  308. switch (code) {
  309. case 0xF0:
  310. state = E1_14_77_E1_F0_14_F0;
  311. break;
  312. default:
  313. state = INIT;
  314. }
  315. break;
  316. case E1_14_77_E1_F0_14_F0:
  317. switch (code) {
  318. case 0x77:
  319. matrix_make(PAUSE);
  320. state = INIT;
  321. break;
  322. default:
  323. state = INIT;
  324. }
  325. break;
  326. default:
  327. state = INIT;
  328. }
  329. }
  330. return 1;
  331. }
  332. bool matrix_is_modified(void)
  333. {
  334. return is_modified;
  335. }
  336. inline
  337. bool matrix_has_ghost(void)
  338. {
  339. #ifdef MATRIX_HAS_GHOST
  340. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  341. if (matrix_has_ghost_in_row(i))
  342. return true;
  343. }
  344. #endif
  345. return false;
  346. }
  347. inline
  348. bool matrix_is_on(uint8_t row, uint8_t col)
  349. {
  350. return (matrix[row] & (1<<col));
  351. }
  352. inline
  353. #if (MATRIX_COLS <= 8)
  354. uint8_t matrix_get_row(uint8_t row)
  355. #else
  356. uint16_t matrix_get_row(uint8_t row)
  357. #endif
  358. {
  359. return matrix[row];
  360. }
  361. void matrix_print(void)
  362. {
  363. #if (MATRIX_COLS <= 8)
  364. print("\nr/c 01234567\n");
  365. #else
  366. print("\nr/c 0123456789ABCDEF\n");
  367. #endif
  368. for (uint8_t row = 0; row < matrix_rows(); row++) {
  369. phex(row); print(": ");
  370. #if (MATRIX_COLS <= 8)
  371. pbin_reverse(matrix_get_row(row));
  372. #else
  373. pbin_reverse16(matrix_get_row(row));
  374. #endif
  375. #ifdef MATRIX_HAS_GHOST
  376. if (matrix_has_ghost_in_row(row)) {
  377. print(" <ghost");
  378. }
  379. #endif
  380. print("\n");
  381. }
  382. }
  383. uint8_t matrix_key_count(void)
  384. {
  385. uint8_t count = 0;
  386. for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
  387. #if (MATRIX_COLS <= 8)
  388. count += bitpop(matrix[i]);
  389. #else
  390. count += bitpop16(matrix[i]);
  391. #endif
  392. }
  393. return count;
  394. }
  395. #ifdef MATRIX_HAS_GHOST
  396. inline
  397. static bool matrix_has_ghost_in_row(uint8_t row)
  398. {
  399. // no ghost exists in case less than 2 keys on
  400. if (((matrix[row] - 1) & matrix[row]) == 0)
  401. return false;
  402. // ghost exists in case same state as other row
  403. for (uint8_t i=0; i < MATRIX_ROWS; i++) {
  404. if (i != row && (matrix[i] & matrix[row]) == matrix[row])
  405. return true;
  406. }
  407. return false;
  408. }
  409. #endif
  410. inline
  411. static void matrix_make(uint8_t code)
  412. {
  413. if (!matrix_is_on(ROW(code), COL(code))) {
  414. matrix[ROW(code)] |= 1<<COL(code);
  415. is_modified = true;
  416. }
  417. }
  418. inline
  419. static void matrix_break(uint8_t code)
  420. {
  421. if (matrix_is_on(ROW(code), COL(code))) {
  422. matrix[ROW(code)] &= ~(1<<COL(code));
  423. is_modified = true;
  424. }
  425. }