Kiibohd Controller
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
Ce dépôt est archivé. Vous pouvez voir les fichiers et le cloner, mais vous ne pouvez pas pousser ni ouvrir de ticket/demande d'ajout.

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. }