usbkeyboard.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. * USB keyboard library
  3. * Contains functions to read a generic USB keybaord from USB1 (SPI2)
  4. * And writes the resulting characters to the HID fifo
  5. */
  6. // uses stdlib.c
  7. // uses hidfifo.c
  8. // uses USBSCANCODES.c
  9. #define USBKEYBOARD_CMD_SET_USB_SPEED 0x04
  10. #define USBKEYBOARD_CMD_RESET_ALL 0x05
  11. #define USBKEYBOARD_CMD_GET_STATUS 0x22
  12. #define USBKEYBOARD_CMD_SET_USB_MODE 0x15
  13. #define USBKEYBOARD_MODE_HOST_0 0x05
  14. #define USBKEYBOARD_MODE_HOST_1 0x07
  15. #define USBKEYBOARD_MODE_HOST_2 0x06
  16. #define USBKEYBOARD_ANSW_USB_INT_CONNECT 0x15
  17. #define USBKEYBOARD_POLLING_RATE 30
  18. #define USBKEYBOARD_HOLD_COUNTS 20
  19. // These are in stdlib.c already
  20. // #define TIMER2_VAL 0xC0273B
  21. // #define TIMER2_CTRL 0xC0273C
  22. #define USBKEYBOARD_SPI2_INTERRUPT 0xC02730
  23. #define USBKEYBOARD_DATA_OFFSET 3
  24. /*
  25. * Global Variables
  26. */
  27. word USBkeyboard_endp_mode = 0x80;
  28. word USBkeyboard_buffer[8];
  29. word USBkeyboard_buffer_parsed[8];
  30. word USBkeyboard_buffer_prev[8];
  31. word USBkeyboard_holdCounter = 0;
  32. word USBkeyboard_holdButton = 0;
  33. word USBkeyboard_holdButtonDataOrig = 0;
  34. /*
  35. * Functions
  36. */
  37. // Workaround for defines in ASM
  38. void USBkeyboard_asmDefines()
  39. {
  40. asm(
  41. "define USBkeyboard_SPI2_CS_ADDR = 0xC0272F ; address of SPI2_CS\n"
  42. "define USBkeyboard_SPI2_ADDR = 0xC0272E ; address of SPI2\n"
  43. );
  44. }
  45. // Sets SPI2_CS low
  46. void USBkeyboard_spiBeginTransfer()
  47. {
  48. asm(
  49. "; backup regs\n"
  50. "push r1\n"
  51. "push r2\n"
  52. "load32 USBkeyboard_SPI2_CS_ADDR r2 ; r2 = USBkeyboard_SPI2_CS_ADDR\n"
  53. "load 0 r1 ; r1 = 0 (enable)\n"
  54. "write 0 r2 r1 ; write to SPI2_CS\n"
  55. "; restore regs\n"
  56. "pop r2\n"
  57. "pop r1\n"
  58. );
  59. }
  60. // Sets SPI2_CS high
  61. void USBkeyboard_spiEndTransfer()
  62. {
  63. asm(
  64. "; backup regs\n"
  65. "push r1\n"
  66. "push r2\n"
  67. "load32 USBkeyboard_SPI2_CS_ADDR r2 ; r2 = USBkeyboard_SPI2_CS_ADDR\n"
  68. "load 1 r1 ; r1 = 1 (disable)\n"
  69. "write 0 r2 r1 ; write to SPI2_CS\n"
  70. "; restore regs\n"
  71. "pop r2\n"
  72. "pop r1\n"
  73. );
  74. }
  75. // write dataByte and return read value
  76. // write 0x00 for a read
  77. // Writes byte over SPI2 to CH376
  78. word USBkeyboard_spiTransfer(word dataByte)
  79. {
  80. word retval = 0;
  81. asm(
  82. "load32 USBkeyboard_SPI2_ADDR r2 ; r2 = USBkeyboard_SPI2_ADDR\n"
  83. "write 0 r2 r4 ; write r4 over SPI2\n"
  84. "read 0 r2 r2 ; read return value\n"
  85. "write -4 r14 r2 ; write to stack to return\n"
  86. );
  87. return retval;
  88. }
  89. // Get status after waiting for an interrupt
  90. word USBkeyboard_WaitGetStatus() {
  91. word intValue = 1;
  92. while(intValue)
  93. {
  94. word *i = (word *) USBKEYBOARD_SPI2_INTERRUPT;
  95. intValue = *i;
  96. }
  97. USBkeyboard_spiBeginTransfer();
  98. USBkeyboard_spiTransfer(USBKEYBOARD_CMD_GET_STATUS);
  99. USBkeyboard_spiEndTransfer();
  100. //delay(1);
  101. USBkeyboard_spiBeginTransfer();
  102. word retval = USBkeyboard_spiTransfer(0x00);
  103. USBkeyboard_spiEndTransfer();
  104. return retval;
  105. }
  106. // Get status without using interrupts
  107. word USBkeyboard_noWaitGetStatus() {
  108. USBkeyboard_spiBeginTransfer();
  109. USBkeyboard_spiTransfer(USBKEYBOARD_CMD_GET_STATUS);
  110. word retval = USBkeyboard_spiTransfer(0x00);
  111. USBkeyboard_spiEndTransfer();
  112. return retval;
  113. }
  114. // Sets USB mode to mode, returns status code
  115. // Which should be 0x51 when successful
  116. word USBkeyboard_setUSBmode(word mode)
  117. {
  118. USBkeyboard_spiBeginTransfer();
  119. USBkeyboard_spiTransfer(USBKEYBOARD_CMD_SET_USB_MODE);
  120. USBkeyboard_spiEndTransfer();
  121. USBkeyboard_spiBeginTransfer();
  122. USBkeyboard_spiTransfer(mode);
  123. USBkeyboard_spiEndTransfer();
  124. word i;
  125. for(i = 0; i < 20000; i++); // non-interrupt wait
  126. USBkeyboard_spiBeginTransfer();
  127. word status = USBkeyboard_spiTransfer(0x00);
  128. USBkeyboard_spiEndTransfer();
  129. return status;
  130. }
  131. // Sets USB speed (0 = USB2, 2 = USB1)
  132. void USBkeyboard_setUSBspeed(word speed)
  133. {
  134. USBkeyboard_spiBeginTransfer();
  135. USBkeyboard_spiTransfer( USBKEYBOARD_CMD_SET_USB_SPEED );
  136. USBkeyboard_spiTransfer( speed );
  137. USBkeyboard_spiEndTransfer();
  138. }
  139. // resets and initializes CH376
  140. void USBkeyboard_init()
  141. {
  142. USBkeyboard_asmDefines(); // workaround to prevent deletion by optimizer
  143. USBkeyboard_spiEndTransfer(); // start with cs high
  144. delay(10);
  145. USBkeyboard_spiBeginTransfer();
  146. USBkeyboard_spiTransfer(USBKEYBOARD_CMD_RESET_ALL);
  147. USBkeyboard_spiEndTransfer();
  148. delay(100); // wait after reset
  149. USBkeyboard_setUSBmode(USBKEYBOARD_MODE_HOST_0);
  150. // set polling interrupt
  151. // set timer
  152. word *p = (word *) TIMER2_VAL;
  153. *p = USBKEYBOARD_POLLING_RATE;
  154. // start timer
  155. word *q = (word *) TIMER2_CTRL;
  156. *q = 1;
  157. }
  158. // Sets USB mode to 2
  159. // Checks again if the device connected in new USB mode
  160. void USBkeyboard_connectDevice()
  161. {
  162. USBkeyboard_setUSBmode(USBKEYBOARD_MODE_HOST_1);
  163. USBkeyboard_setUSBmode(USBKEYBOARD_MODE_HOST_2);
  164. while (USBkeyboard_WaitGetStatus() != USBKEYBOARD_ANSW_USB_INT_CONNECT); // Wait for reconnection of device
  165. }
  166. // I think this is required to start receiving data from USB
  167. void USBkeyboard_toggle_recv()
  168. {
  169. USBkeyboard_spiBeginTransfer();
  170. USBkeyboard_spiTransfer( 0x1C );
  171. USBkeyboard_spiTransfer( USBkeyboard_endp_mode );
  172. USBkeyboard_spiEndTransfer();
  173. USBkeyboard_endp_mode = USBkeyboard_endp_mode ^0x40;
  174. }
  175. // Set endpoint and pid
  176. void USBkeyboard_issue_token(word endp_and_pid)
  177. {
  178. USBkeyboard_spiBeginTransfer();
  179. USBkeyboard_spiTransfer( 0x4F );
  180. USBkeyboard_spiTransfer( endp_and_pid ); // Bit7~4 for EndPoint No, Bit3~0 for Token PID
  181. USBkeyboard_spiEndTransfer();
  182. }
  183. // Read data from USB, and do something with it
  184. // First byte is the length, which should be 8 for an HID keyboard
  185. // The other bytes are the data indicating which keys are pressed
  186. void USBkeyboard_receive_data(char* usbBuf)
  187. {
  188. USBkeyboard_spiBeginTransfer();
  189. USBkeyboard_spiTransfer(0x28);
  190. word len = USBkeyboard_spiTransfer(0x00);
  191. // check for 8 bytes
  192. if (len != 8)
  193. {
  194. USBkeyboard_spiEndTransfer();
  195. return;
  196. }
  197. word i;
  198. for (i = 0; i < len; i++)
  199. {
  200. usbBuf[i] = USBkeyboard_spiTransfer(0x00);
  201. // also put the parsed button into a separate buffer
  202. // convert to ascii/code using table
  203. // add new ascii/code to fifo
  204. word *tableNomal = (word*) &DATA_USBSCANCODE_NORMAL;
  205. tableNomal += USBKEYBOARD_DATA_OFFSET; // set offset to data in function
  206. USBkeyboard_buffer_parsed[i] = *(tableNomal+usbBuf[i]);
  207. }
  208. USBkeyboard_spiEndTransfer();
  209. }
  210. void USBkeyboard_set_addr(word addr) {
  211. USBkeyboard_spiBeginTransfer();
  212. USBkeyboard_spiTransfer( 0x45 );
  213. USBkeyboard_spiTransfer( addr );
  214. USBkeyboard_spiEndTransfer();
  215. USBkeyboard_WaitGetStatus();
  216. USBkeyboard_spiBeginTransfer();
  217. USBkeyboard_spiTransfer( 0x13 );
  218. USBkeyboard_spiTransfer( addr );
  219. USBkeyboard_spiEndTransfer();
  220. }
  221. void USBkeyboard_set_config(word cfg) {
  222. USBkeyboard_spiBeginTransfer();
  223. USBkeyboard_spiTransfer( 0x49 );
  224. USBkeyboard_spiTransfer( cfg );
  225. USBkeyboard_spiEndTransfer();
  226. USBkeyboard_WaitGetStatus();
  227. }
  228. void USBkeyboard_sendToFifo(char usbCode, char* usbBuf)
  229. {
  230. // check first byte for both shift key bits
  231. if ((usbBuf[0] & 0x2) || (usbBuf[0] & 0x20))
  232. {
  233. // convert to ascii/code using table
  234. // add new ascii/code to fifo
  235. word *tableShifted = (word*) &DATA_USBSCANCODE_SHIFTED;
  236. tableShifted += USBKEYBOARD_DATA_OFFSET; // set offset to data in function
  237. HID_FifoWrite(*(tableShifted+usbCode));
  238. }
  239. else // non-shifted
  240. {
  241. // convert to ascii/code using table
  242. // add new ascii/code to fifo
  243. word *tableNomal = (word*) &DATA_USBSCANCODE_NORMAL;
  244. tableNomal += USBKEYBOARD_DATA_OFFSET; // set offset to data in function
  245. HID_FifoWrite(*(tableNomal+usbCode));
  246. }
  247. }
  248. // Returns if a button value is present in a USB buffer
  249. word USBkeyboard_buttonInBuffer(char button, char* buffer)
  250. {
  251. word i;
  252. for (i = 0; i < 8; i++)
  253. {
  254. if (button == buffer[i])
  255. {
  256. return 1;
  257. }
  258. }
  259. return 0;
  260. }
  261. // Parses USB keyboard buffer and writes result to HID FIFO
  262. void USBkeyboard_parse_buffer(char* usbBuf, char* usbBufPrev)
  263. {
  264. // detect which keys are pressed:
  265. // compare byte 2-7 with previous buffer
  266. word i;
  267. for (i = 2; i < 8; i++)
  268. {
  269. // if new byte != 0 and not in previous buffer, then new byte is new keypress
  270. if (usbBuf[i] != 0 && !USBkeyboard_buttonInBuffer(usbBuf[i], usbBufPrev))
  271. {
  272. //uprintlnDec(usbBuf[i]); // usefull for adding new keys
  273. USBkeyboard_holdButton = i;
  274. USBkeyboard_sendToFifo(usbBuf[i], usbBuf);
  275. }
  276. }
  277. // copy buffer to previous buffer
  278. memcpy(usbBufPrev, usbBuf, 8);
  279. }
  280. // Poll for USB
  281. void USBkeyboard_poll()
  282. {
  283. word status = USBkeyboard_noWaitGetStatus();
  284. if (status == 0x14)
  285. {
  286. USBkeyboard_receive_data(USBkeyboard_buffer);
  287. USBkeyboard_parse_buffer(USBkeyboard_buffer, USBkeyboard_buffer_prev);
  288. USBkeyboard_toggle_recv();
  289. USBkeyboard_issue_token(0x19); // result of endp 1 and pid 9 ( 1 << 4 ) | 0x09
  290. }
  291. // If reconnection TODO: move this to main loop, since we do not want to keep the interrupt occupied for so long
  292. else if (status == USBKEYBOARD_ANSW_USB_INT_CONNECT)
  293. {
  294. word x;
  295. for (x = 0; x < 100000; x++); // delay without interrupt, to make sure connection is stable
  296. USBkeyboard_connectDevice();
  297. USBkeyboard_setUSBspeed(0);
  298. USBkeyboard_set_addr(1); // endpoint 1 IN
  299. USBkeyboard_set_config(1);
  300. USBkeyboard_toggle_recv();
  301. USBkeyboard_issue_token(0x19); // result of endp 1 and pid 9 ( 1 << 4 ) | 0x09
  302. }
  303. char* usbBuf = USBkeyboard_buffer;
  304. // Button hold detection
  305. if (USBkeyboard_holdButton != 0)
  306. {
  307. if (usbBuf[USBkeyboard_holdButton] != 0)
  308. {
  309. if (USBkeyboard_holdCounter == 0)
  310. {
  311. USBkeyboard_holdButtonDataOrig = usbBuf[USBkeyboard_holdButton];
  312. USBkeyboard_holdCounter++;
  313. }
  314. else // check if it is still the same button that is being held
  315. {
  316. if (usbBuf[USBkeyboard_holdButton] == USBkeyboard_holdButtonDataOrig)
  317. {
  318. if (USBkeyboard_holdCounter < USBKEYBOARD_HOLD_COUNTS)
  319. USBkeyboard_holdCounter++;
  320. }
  321. else
  322. {
  323. USBkeyboard_holdButton = 0;
  324. USBkeyboard_holdCounter = 0;
  325. }
  326. }
  327. }
  328. else
  329. {
  330. USBkeyboard_holdButton = 0;
  331. USBkeyboard_holdCounter = 0;
  332. }
  333. // Send repetitive code to HID FIFO when holding a button for a certain amount of time
  334. if (USBkeyboard_holdCounter >= USBKEYBOARD_HOLD_COUNTS)
  335. {
  336. USBkeyboard_sendToFifo(usbBuf[USBkeyboard_holdButton], usbBuf);
  337. }
  338. }
  339. }
  340. void USBkeyboard_HandleInterrupt()
  341. {
  342. // poll the USB keyboard
  343. USBkeyboard_poll();
  344. // set timer to polling rate
  345. word *p = (word *) TIMER2_VAL;
  346. *p = USBKEYBOARD_POLLING_RATE;
  347. // start timer
  348. word *q = (word *) TIMER2_CTRL;
  349. *q = 1;
  350. }