1 /* Copyright (C) 2011,2014 by Jacob Alexander
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:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
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
22 // ----- Includes -----
25 #include <Lib/ScanLib.h>
32 #include "scan_loop.h"
36 // ----- Defines -----
39 #define CLOCK_PORT PORTB
40 #define CLOCK_DDR DDRB
46 #define setLED(id, status) \
47 status = status ? 0 : 1; \
48 scan_setLED( id, status )
52 // ----- Variables -----
54 // Buffer used to inform the macro processing module which keys have been detected as pressed
55 volatile uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER];
56 volatile uint8_t KeyIndex_BufferUsed;
58 volatile uint8_t currentWaveState = 0;
60 volatile uint8_t calcLED = 0;
61 volatile uint8_t insertLED = 0;
62 volatile uint8_t shiftLockLED = 0;
63 volatile uint8_t schedLED = 0;
64 volatile uint8_t drawLED = 0;
68 // ----- Function Declarations -----
70 void Scan_diagnostics( void );
71 void processKeyValue( uint8_t keyValue );
72 void Scan_diagnostics( void );
73 void Scan_setRepeatStart( uint8_t n );
74 void Scan_readSwitchStatus( void );
75 void Scan_repeatControl( uint8_t on );
76 void Scan_enableKeyboard( uint8_t enable );
77 void Scan_setRepeatRate( uint8_t n );
78 void Scan_setLED( uint8_t ledNumber, uint8_t on );
79 void Scan_readLED( void );
83 // ----- Interrupt Functions -----
85 // Generates a constant external clock
86 ISR( TIMER1_COMPA_vect )
88 if ( currentWaveState )
90 CLOCK_PORT &= ~(1 << CLOCK_PIN);
95 CLOCK_PORT |= (1 << CLOCK_PIN);
100 // USART Receive Buffer Full Interrupt
103 cli(); // Disable Interrupts
105 uint8_t keyValue = 0x00;
107 // Read the raw packet from the USART
112 hexToStr( keyValue, tmpStr );
113 dPrintStrs( tmpStr, " " );
115 // Process the scancode
116 if ( keyValue != 0x00 )
117 processKeyValue( keyValue );
119 sei(); // Re-enable Interrupts
124 // ----- Functions -----
127 inline void Scan_setup()
129 // Setup Timer Pulse (16 bit)
130 // 16 MHz / (2 * Prescaler * (1 + OCR1A)) = 1204.8 baud (820 us)
136 TIMSK1 = (1 << OCIE1A);
137 CLOCK_DDR = (1 << CLOCK_PIN);
139 // 16 MHz / (2 * Prescaler * (1 + OCR1A)) = 1200.1 baud
141 // Twice every 1200 baud (actually 1200.1, timer isn't accurate enough)
142 // This is close to 820 us, but a bit slower
147 TIMSK1 = (1 << OCIE1A);
148 CLOCK_DDR = (1 << CLOCK_PIN);
151 // Setup the the USART interface for keyboard data input
154 // 16 MHz / ( 16 * Baud ) = UBRR
155 // Baud <- 1200 as per the spec (see datasheet archives), rounding to 1200.1 (as that's as accurate as the timer can be)
156 // Thus UBRR = 833.26 -> round to 833
157 uint16_t baud = 833; // Max setting of 4095
158 UBRR1H = (uint8_t)(baud >> 8);
159 UBRR1L = (uint8_t)baud;
161 // Enable the receiver, transitter, and RX Complete Interrupt
164 // Set frame format: 8 data, no stop bits or parity
165 // Synchrounous USART mode
166 // Tx Data on Falling Edge, Rx on Rising
170 // Reset the keyboard before scanning, we might be in a wierd state
172 scan_resetKeyboard();
174 _delay_ms( 5000 ); // Wait for the reset command to finish enough for new settings to take hold afterwards
175 scan_setRepeatRate( 0x00 ); // Set the fastest repeat rate
179 // Main Detection Loop
180 // Nothing is required here with the Epson QX-10 Keyboards as the interrupts take care of the inputs
181 inline uint8_t Scan_loop()
187 void processKeyValue( uint8_t keyValue )
190 uint8_t inputType = keyValue & 0xC0;
192 // Determine the input type
197 // Binary Representation: 1100 llln
198 // Hex Range: 0xC0 to 0xCF
199 // - First 3 bits determine which LED (0 to 7)
200 // - Last bit is whether the LED is On (1) or Off (0)
211 // SW (Switch) Status
214 // Binary Representation: 1000 dddn
215 // Hex Range: 0x80 to 0x8F
216 // - First 3 bits determine which DB (KRTN) (See datasheet)
217 // - Last bit is whether the key is enabled
227 // Detect Modifier Press/Release
228 uint8_t press = keyValue & 0x01;
230 // Modifier Press Detected
233 // Make sure the key isn't already in the buffer
234 for ( uint8_t c = 0; c < KeyIndex_BufferUsed + 1; c++ )
236 // Key isn't in the buffer yet
237 if ( c == KeyIndex_BufferUsed )
239 Macro_bufferAdd( keyValue );
243 // Key already in the buffer
244 if ( KeyIndex_Buffer[c] == keyValue )
248 // Modifier Release Detected
251 uint8_t actualKeyValue = keyValue | 0x01;
253 // Check for the released key, and shift the other keys lower on the buffer
255 for ( c = 0; c < KeyIndex_BufferUsed; c++ )
257 // Key to release found
258 if ( KeyIndex_Buffer[c] == actualKeyValue )
260 // Shift keys from c position
261 for ( uint8_t k = c; k < KeyIndex_BufferUsed - 1; k++ )
262 KeyIndex_Buffer[k] = KeyIndex_Buffer[k + 1];
265 KeyIndex_BufferUsed--;
271 // Error case (no key to release)
272 if ( c == KeyIndex_BufferUsed + 1 )
276 hexToStr( keyValue, tmpStr );
277 erro_dPrint( "Could not find key to release: ", tmpStr );
285 // Binary Representation: 0ddd pppp
286 // Hex Range: 0x00 to 0x7F
287 // - First 3 bits determine which DB (KRTN) (See datasheet)
288 // - Last 4 bits corresond to the KSC signals (P13, P12, P11, P10 respectively)
289 // Or, that can be read as, each key has it's own keycode (with NO release code)
290 // Modifiers are treated differently
292 // Add the key to the buffer, if it isn't already in the current Key Buffer
293 for ( uint8_t c = 0; c < KeyIndex_BufferUsed + 1; c++ )
295 // Key isn't in the buffer yet
296 if ( c == KeyIndex_BufferUsed )
298 Macro_bufferAdd( keyValue );
302 // Key already in the buffer
303 if ( KeyIndex_Buffer[c] == keyValue )
306 // Special Internal Key Mapping/Functions
311 setLED( 0x07, calcLED ); // 0x4F
314 setLED( 0x0E, schedLED ); // 0x5D
317 setLED( 0x0D, drawLED ); // 0x5B
319 case 0x42: // SHIFT LOCK
320 setLED( 0x0B, shiftLockLED ); // 0x57
323 setLED( 0x02, insertLED ); // 0x45
329 scan_resetKeyboard();
335 scan_setRepeatStart( 0x00 );
338 scan_readSwitchStatus();
341 scan_repeatControl( 0x00 );
344 scan_repeatControl( 0x01 );
347 scan_enableKeyboard( 0x00 );
350 scan_enableKeyboard( 0x01 );
353 scan_setRepeatRate( 0x00 );
365 // See below functions for the input sequences for the Epson QX-10 Keyboard
366 uint8_t Scan_sendData( uint8_t dataPayload )
370 hexToStr( dataPayload, tmpStr );
371 info_dPrint( tmpStr, " " );
377 // Signal KeyIndex_Buffer that it has been properly read
378 inline void Scan_finishedWithBuffer( uint8_t sentKeys )
383 // Signal that the keys have been properly sent over USB
384 // For the Epson QX-10 only the modifier keys have release signals
385 // Therefore, only 5 keys could possibly be assigned as a modifiers
386 // The rest of the keys are single press (like the Kaypro keyboards)
388 // However, this differentiation causes complications on how the key signals are discarded and used
389 // The single keypresses must be discarded immediately, while the modifiers must be kept
390 inline void Scan_finishedWithUSBBuffer( uint8_t sentKeys )
392 uint8_t foundModifiers = 0;
394 // Look for all of the modifiers present, there is a max of 8 (but only keys for 5 on the HASCI version)
395 for ( uint8_t c = 0; c < KeyIndex_BufferUsed; c++ )
397 // The modifier range is from 0x80 to 0x8F (well, the last bit is the ON/OFF signal, but whatever...)
398 if ( KeyIndex_Buffer[c] <= 0x8F && KeyIndex_Buffer[c] >= 0x80 )
400 // Add the modifier back into the the Key Buffer
401 KeyIndex_Buffer[foundModifiers] = KeyIndex_Buffer[c];
406 // Adjust the size of the new Key Buffer
407 KeyIndex_BufferUsed = foundModifiers;
409 /* Non-working, too slow (too much traffic on the bus)
410 // Poll the modifiers using an input command
411 uint8_t oldBuffer = KeyIndex_BufferUsed;
412 KeyIndex_BufferUsed = 0;
414 scan_readSwitchStatus();
418 // Reset/Hold keyboard
419 // Warning! This will cause the keyboard to not send any data, so you can't disable with a keypress
420 // The Epson QX-10 Keyboards have a command used to lock the keyboard output
421 void Scan_lockKeyboard( void )
423 scan_enableKeyboard( 0x00 );
426 void Scan_unlockKeyboard( void )
428 scan_enableKeyboard( 0x01 );
432 // Does the following
433 // - Clears the keycode buffer (32 characters)
434 // - Validates repeat function (what does this do?)
435 // - Sets repeat start time (500 ms)
436 // - Sets repeat interval (50 ms)
437 // - Turns off all LEDs
438 void Scan_resetKeyboard( void )
440 // Reset command for the QX-10 Keyboard
441 scan_sendData( 0xE0 );
443 // Empty buffer, now that keyboard has been reset
444 KeyIndex_BufferUsed = 0;
448 // Runs Diagnostics on the keyboard
449 // - First does a reset (see Scan_resetKeyboard)
450 // - Blinks all of the LEDs one after another
451 // - Outputs 0x00 if no keys are pressed
452 // - Outputs 0xFF if any keys are being pressed
453 void Scan_diagnostics( void )
455 // Send reset command with diagnositics
456 scan_sendData( 0xE7 );
460 // Set Repeat Interval Start
461 // 300 ms + n * 25 ms
462 // Interval after which to start the repeated keys
463 void Scan_setRepeatStart( uint8_t n )
466 // Binary Representation: 000n nnnn
467 // Hex boundaries 0x00 to 0x1F
468 // 300 ms to 1075 ms (intervals of 25 ms)
472 // Read Switch Status (preferential to actual keypress outputs)
481 void Scan_readSwitchStatus( void )
483 scan_sendData( 0x80 );
488 // 0x00 Stops repeat function
489 // 0x01 Enables repeat function
490 void Scan_repeatControl( uint8_t on )
493 // Binary Representation: 101X XXXn
494 // Hex options: 0xA0 or 0xA1
495 scan_sendData( 0xA0 | on );
499 // Enable Sending Keyboard Data
500 // 0x00 Stops keycode transmission
501 // 0x01 Enables keycode transmission
502 void Scan_enableKeyboard( uint8_t enable )
505 // Binary Representation: 110X XXXn
506 // Hex options: 0xC0 or 0xC1
507 scan_sendData( 0xC0 | enable );
510 // Set Repeat Interval
512 // Period between sending each repeated key after the initial interval
513 void Scan_setRepeatRate( uint8_t n )
516 // Binary Representation: 001n nnnn
517 // Hex options: 0x00 to 0x1F
518 // 30 ms to 185 ms (intervals of 5 ms)
519 scan_sendData( 0x20 | n );
526 // 8 LEDs max (Note: 5 connected on my board, there is 1 position empty on the PCB for a total of 6)
527 // 0 to 7 (0x0 to 0x7)
528 void Scan_setLED( uint8_t ledNumber, uint8_t on )
531 // Binary Representation: 010l llln
532 // Hex options: 0x40 to 0x4F
533 // The spec is NOT accurate (especially about the "don't care" bit)
537 // 0010 1 - INSERT On
538 // 0011 0 - SHIFT LOCK Off
541 // 0110 0 - SCHED Off
545 // 1010 0 - INSERT Off
546 // 1011 1 - SHIFT LOCK On
557 scan_sendData( ( 0x40 | (ledNumber << 1) | on ) ^ off );
561 // High priority data output (may overwrite some keycode data)
562 void Scan_readLED( void )
564 scan_sendData( 0x7F );