Kiibohd Controller
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

main.c 13KB

13 år sedan
13 år sedan
13 år sedan
13 år sedan
13 år sedan
13 år sedan
13 år sedan
13 år sedan
13 år sedan
13 år sedan
13 år sedan
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /* Copyright (C) 2011-2014 by Jacob Alexander
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. // ----- Includes -----
  22. // Compiler Includes
  23. #include <Lib/MainLib.h>
  24. // Project Includes
  25. #include <macro.h>
  26. #include <scan_loop.h>
  27. #include <output_com.h>
  28. #include <cli.h>
  29. #include <led.h>
  30. #include <print.h>
  31. // ----- Defines -----
  32. // Verified Keypress Defines
  33. #define USB_TRANSFER_DIVIDER 10 // 1024 == 1 Send of keypresses per second, 1 == 1 Send of keypresses per ~1 millisecond
  34. // ----- Macros -----
  35. #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_)
  36. #define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
  37. #endif
  38. // ----- Function Declarations -----
  39. void cliFunc_distRead ( char* args );
  40. void cliFunc_free ( char* args );
  41. void cliFunc_gaugeHelp ( char* args );
  42. void cliFunc_single ( char* args );
  43. void cliFunc_start ( char* args );
  44. void cliFunc_stop ( char* args );
  45. void cliFunc_zeroForce ( char* args );
  46. void cliFunc_zeroPosition( char* args );
  47. char receiveUART0Char();
  48. void transmitUART0String( char* str );
  49. uint32_t readDistanceGauge();
  50. // ----- Variables -----
  51. // Timer Interrupt for flagging a send of the sampled key detection data to the USB host
  52. uint16_t sendKeypressCounter = 0;
  53. // Flag generated by the timer interrupt
  54. volatile uint8_t sendKeypresses = 0;
  55. // ----- Functions -----
  56. // Initial Pin Setup, make sure they are sane
  57. inline void pinSetup(void)
  58. {
  59. // AVR
  60. #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_)
  61. // For each pin, 0=input, 1=output
  62. #if defined(__AVR_AT90USB1286__)
  63. DDRA = 0x00;
  64. #endif
  65. DDRB = 0x00;
  66. DDRC = 0x00;
  67. DDRD = 0x00;
  68. DDRE = 0x00;
  69. DDRF = 0x00;
  70. // Setting pins to either high or pull-up resistor
  71. #if defined(__AVR_AT90USB1286__)
  72. PORTA = 0x00;
  73. #endif
  74. PORTB = 0x00;
  75. PORTC = 0x00;
  76. PORTD = 0x00;
  77. PORTE = 0x00;
  78. PORTF = 0x00;
  79. // ARM
  80. #elif defined(_mk20dx128_)
  81. // TODO - Should be cleared, but not that necessary due to the pin layout
  82. #endif
  83. }
  84. inline void usbTimerSetup(void)
  85. {
  86. // AVR
  87. #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_)
  88. // Setup with 16 MHz clock
  89. CPU_PRESCALE( 0 );
  90. // Setup ISR Timer for flagging a kepress send to USB
  91. // Set to 256 * 1024 (8 bit timer with Clock/1024 prescalar) timer
  92. TCCR0A = 0x00;
  93. TCCR0B = 0x03;
  94. TIMSK0 = (1 << TOIE0);
  95. // ARM
  96. #elif defined(_mk20dx128_)
  97. // 48 MHz clock by default
  98. // System Clock Gating Register Disable
  99. SIM_SCGC6 |= SIM_SCGC6_PIT;
  100. // Enable Timers
  101. PIT_MCR = 0x00;
  102. // Setup ISR Timer for flagging a kepress send to USB
  103. // 1 ms / (1 / 48 MHz) - 1 = 47999 cycles -> 0xBB7F
  104. PIT_LDVAL0 = 0x0000BB7F;
  105. PIT_TCTRL0 = 0x3; // Enable Timer 0 interrupts, and Enable Timer 0
  106. // Insert the required vector for Timer 0
  107. NVIC_ENABLE_IRQ( IRQ_PIT_CH0 );
  108. #endif
  109. }
  110. int main(void)
  111. {
  112. // Configuring Pins
  113. pinSetup();
  114. init_errorLED();
  115. // Setup Output Module
  116. output_setup();
  117. // Enable CLI
  118. init_cli();
  119. // Setup ISR Timer for flagging a kepress send to USB
  120. usbTimerSetup();
  121. // Main Detection Loop
  122. uint8_t ledTimer = F_CPU / 1000000; // Enable LED for a short time
  123. while ( 1 )
  124. {
  125. // Setup the scanning module
  126. scan_setup();
  127. while ( 1 )
  128. {
  129. // Acquire Key Indices
  130. // Loop continuously until scan_loop returns 0
  131. cli();
  132. while ( scan_loop() );
  133. sei();
  134. // Run Macros over Key Indices and convert to USB Keys
  135. process_macros();
  136. // Send keypresses over USB if the ISR has signalled that it's time
  137. if ( !sendKeypresses )
  138. continue;
  139. // Send USB Data
  140. usb_send();
  141. // Clear sendKeypresses Flag
  142. sendKeypresses = 0;
  143. // Indicate Error, if valid
  144. errorLED( ledTimer );
  145. if ( ledTimer > 0 )
  146. ledTimer--;
  147. }
  148. // Loop should never get here (indicate error)
  149. ledTimer = 255;
  150. // HID Debug Error message
  151. erro_print("Detection loop error, this is very bad...bug report!");
  152. }
  153. }
  154. // ----- Interrupts -----
  155. // USB Keyboard Data Send Counter Interrupt
  156. #if defined(_at90usb162_) || defined(_atmega32u4_) || defined(_at90usb646_) || defined(_at90usb1286_) // AVR
  157. ISR( TIMER0_OVF_vect )
  158. #elif defined(_mk20dx128_) // ARM
  159. void pit0_isr(void)
  160. #endif
  161. {
  162. sendKeypressCounter++;
  163. if ( sendKeypressCounter > USB_TRANSFER_DIVIDER ) {
  164. sendKeypressCounter = 0;
  165. sendKeypresses = 1;
  166. }
  167. #if defined(_mk20dx128_) // ARM
  168. // Clear the interrupt flag
  169. PIT_TFLG0 = 1;
  170. #endif
  171. }
  172. // ----- CLI Command Functions -----
  173. uint32_t readDistanceGauge()
  174. {
  175. // Setup distance read parameters for iGaging Distance Scale
  176. // freq = 9kHz
  177. // duty_cycle = 20%
  178. // high_delay = (1/freq) * (duty_cycle/100)
  179. // low_delay = (1/freq) * ((100-duty_cycle)/100)
  180. uint8_t bits = 21; // 21 clock pulses, for 21 bits
  181. uint32_t high_delay = 22; // Clock high time per pulse
  182. uint32_t low_delay = 89; // Clock low time per pulse
  183. // Data
  184. uint32_t distInput = 0;
  185. // Make sure clock is low initially
  186. GPIOC_PCOR |= (1<<2); // Set Clock low
  187. // Scan each of the bits
  188. for ( uint8_t bit = 0; bit < bits; bit++ )
  189. {
  190. // Begin clock pulse
  191. GPIOC_PSOR |= (1<<2); // Set Clock high
  192. // Delay for duty cycle
  193. delayMicroseconds( high_delay );
  194. // End clock pulse
  195. GPIOC_PCOR |= (1<<2); // Set Clock low
  196. // Read Data Bit
  197. distInput |= GPIOC_PDIR & (1<<1) ? (1 << bit) : 0;
  198. // Delay for duty cycle
  199. delayMicroseconds( low_delay );
  200. }
  201. return distInput;
  202. }
  203. void cliFunc_distRead( char* args )
  204. {
  205. // Parse number from argument
  206. // NOTE: Only first argument is used
  207. char* arg1Ptr;
  208. char* arg2Ptr;
  209. argumentIsolation_cli( args, &arg1Ptr, &arg2Ptr );
  210. // Convert the argument into an int
  211. int read_count = decToInt( arg1Ptr ) + 1;
  212. // If no argument specified, default to 1 read
  213. if ( *arg1Ptr == '\0' )
  214. {
  215. read_count = 2;
  216. }
  217. // Repeat reading as many times as specified in the argument
  218. print( NL );
  219. while ( --read_count > 0 )
  220. {
  221. // Prepare to print output
  222. info_msg("Distance: ");
  223. // Data
  224. uint32_t distInput = readDistanceGauge() - distanceOffset;
  225. // Output result
  226. printInt32( distInput );
  227. // Convert to mm
  228. // As per http://www.shumatech.com/web/21bit_protocol?page=0,1
  229. // 21 bits is 2560 CPI (counts per inch) (C/inch)
  230. // 1 inch is 25.4 mm
  231. // 2560 / 25.4 = 100.7874016... CPMM (C/mm)
  232. // Or
  233. // 1 count is 1/2560 = 0.000390625... inches
  234. // 1 count is (1/2560) * 25.4 = 0.00992187500000000 mm = 9.92187500000000 um = 9921.87500000000 nm
  235. // Since there are 21 bits (2 097 152 positions) converting to um is possible by multiplying by 1000
  236. // which is 2 097 152 000, and within 32 bits (4 294 967 295).
  237. // However, um is still not convenient, so 64 bits (18 446 744 073 709 551 615) is a more accurate alternative.
  238. // For each nm there are 2 097 152 000 000 positions.
  239. // And for shits:
  240. // mm is 2 097 152 : 0.009 921 875 000 mm : 32 bit
  241. // um is 2 097 152 000 : 9.921 875 000 um : 32 bit (ideal acc. for 32 bit)
  242. // nm is 2 097 152 000 000 : 9 921.875 000 nm : 64 bit
  243. // pm is 2 097 152 000 000 000 : 9 921 875.000 pm : 64 bit (ideal acc. for 64 bit)
  244. // XXX Apparently shumatech was sorta wrong about the 21 bits of usage
  245. // Yes there are 21 bits, but the values only go from ~338 to ~30681 which is less than 16 bits...
  246. // This means that the conversion at NM can use 32 bits :D
  247. // It's been noted that the multiplier should be 100.6 (and that it could vary from scale to scale)
  248. uint32_t distNM = distInput * 9921;;
  249. uint32_t distUM = distNM / 1000;
  250. uint32_t distMM = distUM / 1000;
  251. print(" ");
  252. printInt32( distMM );
  253. print(" mm ");
  254. printInt32( distUM );
  255. print(" um ");
  256. printInt32( distNM );
  257. print(" nm ");
  258. print( NL );
  259. // Only delay if still counting
  260. if ( read_count > 1 )
  261. delay( 50 );
  262. }
  263. }
  264. void cliFunc_free( char* args )
  265. {
  266. // Set the forceDistanceRead to 1, which will read until start has passed twice
  267. forceDistanceRead = 1;
  268. }
  269. void cliFunc_gaugeHelp( char* args )
  270. {
  271. print( NL
  272. "\033[1;32mForce Curve Gauge Help\033[0m" NL
  273. " \033[1;33mUsage Overview\033[0m" NL
  274. " TODO" NL
  275. " \033[1;33mAdditional Command Details\033[0m" NL
  276. " \033[1;35mdistRead\033[0m" NL
  277. " Reads the current value from the distance gauge." NL
  278. " If specified it will N repeated reads with a delay after each read. Useful for testing the distance gauge." NL
  279. " e.g. \033[35mdistRead 250\033[0m" NL
  280. " \033[1;35mfree\033[0m" NL
  281. " Start free scanning force/distance reads." NL
  282. " Will continue until the [start] distance point has been past twice." NL
  283. " \033[1;35mimadaComm\033[0m" NL
  284. " Sends a command to the Imada force gauge." NL
  285. " e.g. \033[35mimadaComm D\033[0m" NL
  286. " The commands supported by the gauge depends on the model. Listed below is for the DS2." NL
  287. " K Select g units (default)" NL
  288. " N Select N units" NL
  289. " O Select oz units" NL
  290. " P Select peak mode" NL
  291. " T Select real time mode (default)" NL
  292. " Z Zero out display/reading" NL
  293. " Q Turn off power" NL
  294. " E Read high/low set points" NL
  295. " D Read data from force gauge" NL
  296. " E\033[35mHHHHLLLL\033[0m" NL
  297. " Set the high/low setpoints, ignore decimals" NL
  298. " \033[35mHHHH\033[0m is 4 digit high, \033[35mLLLL\033[0m is 4 digit low" NL
  299. " Responses from the above commands." NL
  300. " R Command successful" NL
  301. " E Error/Invalid Command" NL
  302. " E\033[35mHHHHLLLL\033[0m" NL
  303. " Current high/low setpoints" NL
  304. " \033[35mHHHH\033[0m is 4 digit high, \033[35mLLLL\033[0m is 4 digit low" NL
  305. " \033[35m[value][units][mode]\033[0m" NL
  306. " Data read response" NL
  307. " \033[35m[value]\033[0m is force currently showing on the display (peak or realtime)" NL
  308. " \033[35m[units]\033[0m is the configured force units" NL
  309. " \033[35m[mode]\033[0m is the current mode (peak or realtime)" NL
  310. " \033[1;35mread\033[0m" NL
  311. " Read the current force/distance value." NL
  312. " If specified it will N repeated reads with a delay after each read." NL
  313. " e.g. \033[35mread 125\033[0m" NL
  314. " \033[1;35mstart\033[0m" NL
  315. " Distance marker \033[35m[start]\033[0m for the start/end of a force curve measurement." NL
  316. " While in free running mode, a special message is displayed when reaching the \033[35m[start]\033[0m point." NL
  317. " \033[35m[start]\033[0m is defined by positioning the distance sensor at the position to start and running this command." NL
  318. );
  319. }
  320. void cliFunc_read( char* args )
  321. {
  322. // Parse number from argument
  323. // NOTE: Only first argument is used
  324. char* arg1Ptr;
  325. char* arg2Ptr;
  326. argumentIsolation_cli( args, &arg1Ptr, &arg2Ptr );
  327. // Convert the argument into an int
  328. int read_count = decToInt( arg1Ptr ) + 1;
  329. // If no argument specified, default to 1 read
  330. if ( *arg1Ptr == '\0' )
  331. {
  332. read_count = 2;
  333. }
  334. // Set the overall read count to read_count
  335. forceDistanceReadCount = read_count;
  336. }
  337. void cliFunc_start( char* args )
  338. {
  339. // Read the current distance and set the new start/end position
  340. distanceStart = readDistanceGauge();
  341. print( NL );
  342. info_msg("New start/end position: ");
  343. printInt32( distanceStart - distanceOffset );
  344. }
  345. void cliFunc_stop( char* args )
  346. {
  347. // Reset the forceDistanceRead and forceDistanceReadCount
  348. forceDistanceRead = 0;
  349. forceDistanceReadCount = 0;
  350. }
  351. void cliFunc_zeroForce( char* args )
  352. {
  353. // Just use the imadaComm command sending the needed argument
  354. char* commandArg = "Z";
  355. imadaVerboseRead( commandArg );
  356. }
  357. void cliFunc_zeroPosition( char* args )
  358. {
  359. // Read the current distance and set the new offset
  360. distanceOffset = readDistanceGauge();
  361. print( NL );
  362. info_msg("New distance offset: ");
  363. printInt32( distanceOffset );
  364. }