Kiibohd Controller
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.

scan_loop.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /* Copyright (C) 2012,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/ScanLib.h>
  24. // Project Includes
  25. #include <led.h>
  26. #include <print.h>
  27. // Local Includes
  28. #include "scan_loop.h"
  29. // ----- Defines -----
  30. // Pinout Defines
  31. #define REQUEST_PORT PORTD
  32. #define REQUEST_DDR DDRD
  33. #define REQUEST_PIN 3
  34. #define DATA_READ PIND
  35. #define DATA_PORT PORTD
  36. #define DATA_DDR DDRD
  37. #define DATA_PIN 2
  38. #define MAX_SAMPLES 10
  39. #define MAX_FAILURES 3731
  40. #define PACKET_STORAGE 24 // At worst only 8 packets, but with you keypresses you can get more
  41. // ----- Macros -----
  42. #define READ_DATA DATA_READ & (1 << DATA_PIN) ? 0 : 1
  43. #define REQUEST_DATA() REQUEST_DDR &= ~(1 << REQUEST_PIN) // Start incoming keyboard transfer
  44. #define STOP_DATA() REQUEST_DDR |= (1 << REQUEST_PIN) // Stop incoming keyboard data
  45. // ----- Variables -----
  46. // Buffer used to inform the macro processing module which keys have been detected as pressed
  47. volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER];
  48. volatile uint8_t KeyIndex_BufferUsed;
  49. // ----- Function Declarations -----
  50. void processPacketValue( uint16_t packetValue );
  51. // ----- Interrupt Functions -----
  52. // XXX - None Required
  53. // ----- Functions -----
  54. // Setup
  55. // This setup is very simple, as there is no extra hardware used in this scan module, other than GPIOs.
  56. // To be nice, we wait a little bit after powering on, and dump any of the pending keyboard data.
  57. // Afterwards (as long as no keys were being held), the keyboard should have a clean buffer, and be ready to go.
  58. // (Even if keys were held down, everything should probably still work...)
  59. inline void Scan_setup()
  60. {
  61. // Setup the DATA pin
  62. DATA_DDR &= ~(1 << DATA_PIN); // Set to input
  63. DATA_PORT |= (1 << DATA_PIN); // Set to pull-up resistor
  64. // Setup the REQUEST pin
  65. REQUEST_PORT |= (1 << REQUEST_PIN); // Set to output
  66. STOP_DATA(); // Set the line high to stop incoming data
  67. REQUEST_DATA();
  68. DDRD |= (1 << 4);
  69. PORTD &= ~(1 << 4);
  70. // Message
  71. info_print("Pins Setup");
  72. // Reset the keyboard before scanning, we might be in a wierd state
  73. _delay_ms( 50 );
  74. //Scan_resetKeyboard();
  75. // Message
  76. info_print("Keyboard Buffer Flushed");
  77. }
  78. // Main Detection Loop
  79. // The Univac-Sperry F3W9 has a convenient feature, an internal 8 key buffer
  80. // This buffer is only emptied (i.e. sent over the bus) when the REQUEST line is held high
  81. // Because of this, we can utilize the Scan_loop to do all of the critical processing,
  82. // without having to resort to interrupts, giving the data reading 100% of the CPU.
  83. // This is because the USB interrupts can wait until the Scan_loop is finished to continue.
  84. //
  85. // Normally, this approach isn't taken, as it's easier/faster/safer to use Teensy hardware shift registers
  86. // for serial data transfers.
  87. // However, since the Univac-Sperry F3W9 sends 20 bit packets (including the start bit), the Teensy
  88. // doesn't have a shift register large enough (9 bit max), to hold the data.
  89. // So the line must be polled manually using CPU cycles
  90. //
  91. // Another interesting feature is that there are 2 data lines.
  92. // Output and /Output (NOT'ted version).
  93. // Not really useful here, but could be used for error checking, or eliminating an external NOT gate if
  94. // we were using (but can't...) a hardware decoder like a USART.
  95. inline uint8_t Scan_loop()
  96. {
  97. return 0;
  98. // Protocol Notes:
  99. // - Packets are 20 bits long, including the start bit
  100. // - Each bit is ~105 usecs in length
  101. // - Thus the average packet length is 2.205 msecs
  102. // - Each packet is separated by at least 240 usecs (during a buffer unload)
  103. // - While holding the key down, each packet has a space of about 910 usecs
  104. // - A max of 8 keys can be sent at once (note, the arrow keys seem use 2 packets each, and thus take up twice as much buffer)
  105. // - There is no timing danger for holding the request line, just that data may come in when you don't want it
  106. // Now that the scan loop has been entered, we don't have to worry about interrupts stealing
  107. // precious cycles.
  108. REQUEST_DATA();
  109. // = Delays =
  110. //
  111. // For these calculations to work out properly, then Teensy should be running at 16 MHz
  112. // - 1 bit : 105 usecs is 16 000 000 * 0.000105 = 1680 instructions
  113. // - Bit centering : 52.5 usecs is 16 000 000 * 0.0000525 = 840 instructions
  114. // - Delay : 5 msecs is 16 000 000 * 0.005 = 80 000 instructions
  115. // - Microsecond : 1 usec is 16 000 000 * 0.000001 = 16 instructions
  116. //
  117. // Now, either I can follow these exactly, or based upon the fact that I have >840 tries to find the
  118. // the start bit, and >1680 tries to read the subsequent bits, I have some "flex" time.
  119. // Knowing this, I can make some assumptions that because I'm only reading a total of 20 bits, and will
  120. // be re-centering for each packet.
  121. // This will allow for less worrying about compiler optimizations (and porting!).
  122. // The basic idea is to find a "reliable" value for the start bit, e.g. read it ~10 times.
  123. // Using a for-loop and some addition counters, this should eat up approximately 20-30 instructions per read
  124. // (very loose estimation).
  125. // So reading 10 * 30 instructions = 300 instructions, which is much less than 840 instructions to where the
  126. // bit center is, but is close enough that further delays of ~>1680 instructions will put the next read
  127. // within the next bit period.
  128. // This is all possible because interrupts are disabled at this point, otherwise, all of this reasoning
  129. // would fall apart.
  130. // _delay_us is available to use, fortunately.
  131. // Input Packet Storage (before being processed)
  132. uint16_t incomingPacket[PACKET_STORAGE];
  133. uint8_t numberOfIncomingPackets = 0;
  134. // Sample the data line for ~5 ms, looking for a start bit
  135. // - Sampling every 1 usecs, looking for 10 good samples
  136. // - Accumulated samples will dumped if a high is detected
  137. uint8_t samples = 0;
  138. uint16_t failures = 0;
  139. // Continue waiting for a start bit until MAX_FAILURES has been reached (~5ms of nothing)
  140. while ( failures <= MAX_FAILURES )
  141. {
  142. // Attempt to find the start bit
  143. while ( samples < MAX_SAMPLES )
  144. {
  145. // Delay first
  146. _delay_us( 1 );
  147. // If data is valid, increment
  148. if ( READ_DATA )
  149. {
  150. samples++;
  151. }
  152. // Reset
  153. else
  154. {
  155. samples = 0;
  156. failures++;
  157. // After ~5ms of failures, break the loop
  158. // Each failure is approx 5 instructions + 1 usec, or approximately 1.34 usec)
  159. // So ~3731 failures for ~5ms
  160. // Being exact doesn't matter, as this is just to let the other parts of the
  161. // controller do some processing
  162. if ( failures > MAX_FAILURES )
  163. break;
  164. }
  165. }
  166. // If 10 valid samples of the start bit were obtained,
  167. if ( samples >= MAX_SAMPLES )
  168. {
  169. // Clean out the old packet memory
  170. incomingPacket[numberOfIncomingPackets] = 0;
  171. // Read the next 19 bits into memory (bit 0 is the start bit, which is always 0)
  172. for ( uint8_t c = 1; c < 20; c++ )
  173. {
  174. // Wait until the middle of the next bit
  175. _delay_us( 105 );
  176. // Append the current bit value
  177. incomingPacket[numberOfIncomingPackets] |= (READ_DATA << c);
  178. }
  179. // Packet finished, increment counter
  180. numberOfIncomingPackets++;
  181. }
  182. }
  183. // Stop the keyboard input
  184. STOP_DATA();
  185. // Finished receiving data from keyboard, start packet processing
  186. for ( uint8_t packet = 0; packet < numberOfIncomingPackets; packet++ )
  187. processPacketValue( incomingPacket[packet] );
  188. return 0;
  189. }
  190. // Read in the Packet Data, and decide what to do with it
  191. void processPacketValue( uint16_t packetValue )
  192. {
  193. // = Packet Layout =
  194. //
  195. // A is the first bit received (bit 0), T is the last
  196. //
  197. // | Modifier? | ?? | Scan Code |
  198. // A B C D E F G H I J K L M N O P Q R S T
  199. //
  200. // A - Start bit
  201. // - Always Low
  202. // B -> H - Modifier enabled bits
  203. // - Each bit represents a different modifier "mode"
  204. // - B -> Shift/Lock
  205. // - C -> ??
  206. // - D -> Func
  207. // - E -> ??
  208. // - F -> ??
  209. // - G -> ??
  210. // - H -> ??
  211. // I -> L - ?? No idea yet...
  212. // - The bits change for some combinations, but not pattern has been found yet...
  213. // - I -> ??
  214. // - J -> ??
  215. // - K -> ??
  216. // - L -> ??
  217. // M -> T - Scan Code
  218. // - Bits are organized from low to high (8 bit value)
  219. // - M -> Bit 1
  220. // - N -> Bit 2
  221. // - O -> Bit 3
  222. // - P -> Bit 4
  223. // - Q -> Bit 5
  224. // - R -> Bit 6
  225. // - S -> Bit 7
  226. // - T -> Bit 8
  227. // Separate packet into sections
  228. uint8_t scanCode = (packetValue & 0xFF000) << 12;
  229. uint8_t modifiers = (packetValue & 0x000FE);
  230. uint8_t extra = (packetValue & 0x00F00) << 8;
  231. // Debug Info
  232. char tmpStr1[3];
  233. char tmpStr2[3];
  234. char tmpStr3[3];
  235. hexToStr_op( scanCode, tmpStr1, 2 );
  236. hexToStr_op( modifiers, tmpStr2, 2 );
  237. hexToStr_op( extra, tmpStr3, 2 );
  238. dbug_dPrint( "Scancode: 0x", tmpStr1, " Modifiers: 0x", tmpStr2, " Extra: 0x", tmpStr3 );
  239. dbug_dPrint( "Packet: 0x", tmpStr2, tmpStr3, tmpStr1 );
  240. // TODO List
  241. // - Modifier keys
  242. // - Key Release mechanism
  243. // Compute Modifier keys
  244. // TODO
  245. // Deal with special scan codes
  246. switch ( scanCode )
  247. {
  248. default:
  249. //Macro_bufferAdd( scanCode ); TODO - Uncomment when ready for USB output
  250. break;
  251. }
  252. }
  253. // Send data
  254. // NOTE: Does nothing with the Univac-Sperry F3W9
  255. uint8_t Scan_sendData( uint8_t dataPayload )
  256. {
  257. return 0;
  258. }
  259. // Signal KeyIndex_Buffer that it has been properly read
  260. inline void Scan_finishedWithBuffer( uint8_t sentKeys )
  261. {
  262. return;
  263. }
  264. // Signal that the keys have been properly sent over USB
  265. // TODO
  266. inline void Scan_finishedWithUSBBuffer( uint8_t sentKeys )
  267. {
  268. /*
  269. uint8_t foundModifiers = 0;
  270. // Look for all of the modifiers present, there is a max of 8 (but only keys for 5 on the HASCI version)
  271. for ( uint8_t c = 0; c < KeyIndex_BufferUsed; c++ )
  272. {
  273. // The modifier range is from 0x80 to 0x8F (well, the last bit is the ON/OFF signal, but whatever...)
  274. if ( KeyIndex_Buffer[c] <= 0x8F && KeyIndex_Buffer[c] >= 0x80 )
  275. {
  276. // Add the modifier back into the the Key Buffer
  277. KeyIndex_Buffer[foundModifiers] = KeyIndex_Buffer[c];
  278. foundModifiers++;
  279. }
  280. }
  281. // Adjust the size of the new Key Buffer
  282. KeyIndex_BufferUsed = foundModifiers;
  283. */
  284. }
  285. // Reset/Hold keyboard
  286. // NOTE: Does nothing with the Univac-Sperry F3W9
  287. void Scan_lockKeyboard( void )
  288. {
  289. }
  290. // NOTE: Does nothing with the Univac-Sperry F3W9
  291. void Scan_unlockKeyboard( void )
  292. {
  293. }
  294. // Reset Keyboard
  295. // - Holds the input read line high to flush the buffer
  296. // - This does not actually reset the keyboard, but always seems brings it to a sane state
  297. // - Won't work fully if keys are being pressed done at the same time
  298. void Scan_resetKeyboard( void )
  299. {
  300. // Initiate data request line, but don't read the incoming data
  301. REQUEST_DATA();
  302. // We shouldn't be receiving more than 8 packets (and maybe +1 error signal)
  303. // This is around 22 ms of data, so a delay of 50 ms should be sufficient.
  304. _delay_ms( 50 );
  305. // Stop request line
  306. STOP_DATA();
  307. }