2011-12-11 06:48:53 +00:00
/* Copyright (C) 2011 by Jacob Alexander
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
// ----- Includes -----
2013-01-26 20:05:28 +00:00
// Compiler Includes
# include <Lib/ScanLib.h>
2011-12-11 06:48:53 +00:00
// Project Includes
# include <led.h>
# include <print.h>
// Local Includes
# include "scan_loop.h"
// ----- Defines -----
// Pinout Defines
# define CLOCK_PORT PORTB
# define CLOCK_DDR DDRB
# define CLOCK_PIN 0
// ----- Macros -----
// Make sure we haven't overflowed the buffer
# define bufferAdd(byte) \
if ( KeyIndex_BufferUsed < KEYBOARD_BUFFER ) \
KeyIndex_Buffer [ KeyIndex_BufferUsed + + ] = byte
# define setLED(id, status) \
status = status ? 0 : 1 ; \
scan_setLED ( id , status )
// ----- Variables -----
// Buffer used to inform the macro processing module which keys have been detected as pressed
volatile uint8_t KeyIndex_Buffer [ KEYBOARD_BUFFER ] ;
volatile uint8_t KeyIndex_BufferUsed ;
volatile uint8_t currentWaveState = 0 ;
volatile uint8_t calcLED = 0 ;
volatile uint8_t insertLED = 0 ;
volatile uint8_t shiftLockLED = 0 ;
volatile uint8_t schedLED = 0 ;
volatile uint8_t drawLED = 0 ;
// ----- Function Declarations -----
void scan_diagnostics ( void ) ;
void processKeyValue ( uint8_t keyValue ) ;
void scan_diagnostics ( void ) ;
void scan_setRepeatStart ( uint8_t n ) ;
void scan_readSwitchStatus ( void ) ;
void scan_repeatControl ( uint8_t on ) ;
void scan_enableKeyboard ( uint8_t enable ) ;
void scan_setRepeatRate ( uint8_t n ) ;
void scan_setLED ( uint8_t ledNumber , uint8_t on ) ;
void scan_readLED ( void ) ;
// ----- Interrupt Functions -----
// Generates a constant external clock
ISR ( TIMER1_COMPA_vect )
{
if ( currentWaveState )
{
CLOCK_PORT & = ~ ( 1 < < CLOCK_PIN ) ;
currentWaveState - - ;
}
else
{
CLOCK_PORT | = ( 1 < < CLOCK_PIN ) ;
currentWaveState + + ;
}
}
// USART Receive Buffer Full Interrupt
ISR ( USART1_RX_vect )
{
cli ( ) ; // Disable Interrupts
uint8_t keyValue = 0x00 ;
// Read the raw packet from the USART
keyValue = UDR1 ;
// Debug
char tmpStr [ 6 ] ;
hexToStr ( keyValue , tmpStr ) ;
dPrintStrs ( tmpStr , " " ) ;
// Process the scancode
if ( keyValue ! = 0x00 )
processKeyValue ( keyValue ) ;
sei ( ) ; // Re-enable Interrupts
}
// ----- Functions -----
// Setup
inline void scan_setup ( )
{
// Setup Timer Pulse (16 bit)
// 16 MHz / (2 * Prescaler * (1 + OCR1A)) = 1204.8 baud (820 us)
// Prescaler is 1
/*
TCCR1B = 0x09 ;
OCR1AH = 0x19 ;
OCR1AL = 0xEF ;
TIMSK1 = ( 1 < < OCIE1A ) ;
CLOCK_DDR = ( 1 < < CLOCK_PIN ) ;
*/
// 16 MHz / (2 * Prescaler * (1 + OCR1A)) = 1200.1 baud
// Prescaler is 1
// Twice every 1200 baud (actually 1200.1, timer isn't accurate enough)
// This is close to 820 us, but a bit slower
2011-12-11 08:06:49 +00:00
cli ( ) ;
2011-12-11 06:48:53 +00:00
TCCR1B = 0x09 ;
OCR1AH = 0x1A ;
OCR1AL = 0x09 ;
TIMSK1 = ( 1 < < OCIE1A ) ;
CLOCK_DDR = ( 1 < < CLOCK_PIN ) ;
// Setup the the USART interface for keyboard data input
// Setup baud rate
// 16 MHz / ( 16 * Baud ) = UBRR
// Baud <- 1200 as per the spec (see datasheet archives), rounding to 1200.1 (as that's as accurate as the timer can be)
// Thus UBRR = 833.26 -> round to 833
uint16_t baud = 833 ; // Max setting of 4095
UBRR1H = ( uint8_t ) ( baud > > 8 ) ;
UBRR1L = ( uint8_t ) baud ;
// Enable the receiver, transitter, and RX Complete Interrupt
UCSR1B = 0x98 ;
// Set frame format: 8 data, no stop bits or parity
// Synchrounous USART mode
// Tx Data on Falling Edge, Rx on Rising
UCSR1C = 0x47 ;
2011-12-11 08:06:49 +00:00
sei ( ) ;
2011-12-11 06:48:53 +00:00
// Reset the keyboard before scanning, we might be in a wierd state
2011-12-11 08:06:49 +00:00
_delay_ms ( 50 ) ;
2011-12-11 06:48:53 +00:00
scan_resetKeyboard ( ) ;
2011-12-11 08:06:49 +00:00
_delay_ms ( 5000 ) ; // Wait for the reset command to finish enough for new settings to take hold afterwards
2011-12-11 06:48:53 +00:00
scan_setRepeatRate ( 0x00 ) ; // Set the fastest repeat rate
}
// Main Detection Loop
2011-12-11 08:06:49 +00:00
// Nothing is required here with the Epson QX-10 Keyboards as the interrupts take care of the inputs
2011-12-11 06:48:53 +00:00
inline uint8_t scan_loop ( )
{
return 0 ;
}
// TODO
void processKeyValue ( uint8_t keyValue )
{
// Detect LED Status
uint8_t inputType = keyValue & 0xC0 ;
// Determine the input type
switch ( inputType )
{
// LED Status
case 0xC0 :
// Binary Representation: 1100 llln
// Hex Range: 0xC0 to 0xCF
// - First 3 bits determine which LED (0 to 7)
// - Last bit is whether the LED is On (1) or Off (0)
// 000 - N/A (A)
// 001 - N/A (B)
// 010 - INSERT
// 011 - SHIFT LOCK
// 100 - N/A (C)
// 101 - DRAW
// 110 - SCHED
// 111 - CALC
break ;
// SW (Switch) Status
case 0x80 :
{
// Binary Representation: 1000 dddn
// Hex Range: 0x80 to 0x8F
// - First 3 bits determine which DB (KRTN) (See datasheet)
// - Last bit is whether the key is enabled
// 000 - N/A?
// 001 - N/A?
// 010 - Right SHIFT
// 011 - Left SHIFT
// 100 - N/A?
// 101 - Left CTRL
// 110 - GRPH SHIFT
// 111 - Right CTRL
// Detect Modifier Press/Release
uint8_t press = keyValue & 0x01 ;
// Modifier Press Detected
if ( press )
{
// Make sure the key isn't already in the buffer
for ( uint8_t c = 0 ; c < KeyIndex_BufferUsed + 1 ; c + + )
{
// Key isn't in the buffer yet
if ( c = = KeyIndex_BufferUsed )
{
bufferAdd ( keyValue ) ;
break ;
}
// Key already in the buffer
if ( KeyIndex_Buffer [ c ] = = keyValue )
break ;
}
}
// Modifier Release Detected
else
{
2011-12-11 08:06:49 +00:00
uint8_t actualKeyValue = keyValue | 0x01 ;
2011-12-11 06:48:53 +00:00
// Check for the released key, and shift the other keys lower on the buffer
uint8_t c ;
for ( c = 0 ; c < KeyIndex_BufferUsed ; c + + )
{
// Key to release found
2011-12-11 08:06:49 +00:00
if ( KeyIndex_Buffer [ c ] = = actualKeyValue )
2011-12-11 06:48:53 +00:00
{
// Shift keys from c position
for ( uint8_t k = c ; k < KeyIndex_BufferUsed - 1 ; k + + )
KeyIndex_Buffer [ k ] = KeyIndex_Buffer [ k + 1 ] ;
// Decrement Buffer
KeyIndex_BufferUsed - - ;
break ;
}
}
// Error case (no key to release)
if ( c = = KeyIndex_BufferUsed + 1 )
{
errorLED ( 1 ) ;
char tmpStr [ 6 ] ;
hexToStr ( keyValue , tmpStr ) ;
erro_dPrint ( " Could not find key to release: " , tmpStr ) ;
}
}
break ;
}
// Key code
default :
// Binary Representation: 0ddd pppp
// Hex Range: 0x00 to 0x7F
// - First 3 bits determine which DB (KRTN) (See datasheet)
// - Last 4 bits corresond to the KSC signals (P13, P12, P11, P10 respectively)
// Or, that can be read as, each key has it's own keycode (with NO release code)
// Modifiers are treated differently
// Add the key to the buffer, if it isn't already in the current Key Buffer
for ( uint8_t c = 0 ; c < KeyIndex_BufferUsed + 1 ; c + + )
{
// Key isn't in the buffer yet
if ( c = = KeyIndex_BufferUsed )
{
bufferAdd ( keyValue ) ;
break ;
}
// Key already in the buffer
if ( KeyIndex_Buffer [ c ] = = keyValue )
break ;
}
// Special Internal Key Mapping/Functions
switch ( keyValue )
{
// LED Test
case 0x0A : // CALC
setLED ( 0x07 , calcLED ) ; // 0x4F
break ;
case 0x0B : // SCHED
setLED ( 0x0E , schedLED ) ; // 0x5D
break ;
case 0x0C : // DRAW
setLED ( 0x0D , drawLED ) ; // 0x5B
break ;
case 0x42 : // SHIFT LOCK
setLED ( 0x0B , shiftLockLED ) ; // 0x57
break ;
case 0x5E : // INSERT
setLED ( 0x02 , insertLED ) ; // 0x45
break ;
/*
// TEST
case 0x51 :
scan_resetKeyboard ( ) ;
break ;
case 0x52 :
scan_diagnostics ( ) ;
break ;
case 0x53 :
scan_setRepeatStart ( 0x00 ) ;
break ;
case 0x54 :
scan_readSwitchStatus ( ) ;
break ;
case 0x55 :
scan_repeatControl ( 0x00 ) ;
break ;
case 0x56 :
scan_repeatControl ( 0x01 ) ;
break ;
case 0x57 :
scan_enableKeyboard ( 0x00 ) ;
break ;
case 0x58 :
scan_enableKeyboard ( 0x01 ) ;
break ;
case 0x59 :
scan_setRepeatRate ( 0x00 ) ;
break ;
case 0x5A :
scan_readLED ( ) ;
break ;
*/
}
break ;
}
}
// Send data
// See below functions for the input sequences for the Epson QX-10 Keyboard
uint8_t scan_sendData ( uint8_t dataPayload )
{
// Debug
char tmpStr [ 6 ] ;
hexToStr ( dataPayload , tmpStr ) ;
info_dPrint ( tmpStr , " " ) ;
UDR1 = dataPayload ;
return 0 ;
}
// Signal KeyIndex_Buffer that it has been properly read
2013-01-21 03:36:05 +00:00
inline void scan_finishedWithBuffer ( uint8_t sentKeys )
2011-12-11 08:06:49 +00:00
{
return ;
}
// Signal that the keys have been properly sent over USB
2011-12-11 06:48:53 +00:00
// For the Epson QX-10 only the modifier keys have release signals
// Therefore, only 5 keys could possibly be assigned as a modifiers
// The rest of the keys are single press (like the Kaypro keyboards)
//
// However, this differentiation causes complications on how the key signals are discarded and used
// The single keypresses must be discarded immediately, while the modifiers must be kept
2013-01-21 03:36:05 +00:00
inline void scan_finishedWithUSBBuffer ( uint8_t sentKeys )
2011-12-11 06:48:53 +00:00
{
uint8_t foundModifiers = 0 ;
// Look for all of the modifiers present, there is a max of 8 (but only keys for 5 on the HASCI version)
for ( uint8_t c = 0 ; c < KeyIndex_BufferUsed ; c + + )
{
// The modifier range is from 0x80 to 0x8F (well, the last bit is the ON/OFF signal, but whatever...)
if ( KeyIndex_Buffer [ c ] < = 0x8F & & KeyIndex_Buffer [ c ] > = 0x80 )
{
// Add the modifier back into the the Key Buffer
KeyIndex_Buffer [ foundModifiers ] = KeyIndex_Buffer [ c ] ;
foundModifiers + + ;
}
}
// Adjust the size of the new Key Buffer
KeyIndex_BufferUsed = foundModifiers ;
2011-12-11 08:06:49 +00:00
/* Non-working, too slow (too much traffic on the bus)
// Poll the modifiers using an input command
uint8_t oldBuffer = KeyIndex_BufferUsed ;
KeyIndex_BufferUsed = 0 ;
if ( oldBuffer )
scan_readSwitchStatus ( ) ;
*/
2011-12-11 06:48:53 +00:00
}
// Reset/Hold keyboard
// Warning! This will cause the keyboard to not send any data, so you can't disable with a keypress
// The Epson QX-10 Keyboards have a command used to lock the keyboard output
void scan_lockKeyboard ( void )
{
scan_enableKeyboard ( 0x00 ) ;
}
void scan_unlockKeyboard ( void )
{
scan_enableKeyboard ( 0x01 ) ;
}
// Reset Keyboard
// Does the following
// - Clears the keycode buffer (32 characters)
// - Validates repeat function (what does this do?)
// - Sets repeat start time (500 ms)
// - Sets repeat interval (50 ms)
// - Turns off all LEDs
void scan_resetKeyboard ( void )
{
// Reset command for the QX-10 Keyboard
scan_sendData ( 0xE0 ) ;
// Empty buffer, now that keyboard has been reset
KeyIndex_BufferUsed = 0 ;
}
// TODO Check
// Runs Diagnostics on the keyboard
// - First does a reset (see scan_resetKeyboard)
// - Blinks all of the LEDs one after another
// - Outputs 0x00 if no keys are pressed
// - Outputs 0xFF if any keys are being pressed
void scan_diagnostics ( void )
{
// Send reset command with diagnositics
scan_sendData ( 0xE7 ) ;
}
// TODO Check
// Set Repeat Interval Start
// 300 ms + n * 25 ms
// Interval after which to start the repeated keys
void scan_setRepeatStart ( uint8_t n )
{
// Send command
// Binary Representation: 000n nnnn
// Hex boundaries 0x00 to 0x1F
// 300 ms to 1075 ms (intervals of 25 ms)
scan_sendData ( n ) ;
}
// Read Switch Status (preferential to actual keypress outputs)
// 000 - N/A?
// 001 - N/A?
// 010 - Right SHIFT
// 011 - Left SHIFT
// 100 - N/A?
// 101 - Left CTRL
// 110 - GRPH SHIFT
// 111 - Right CTRL
void scan_readSwitchStatus ( void )
{
scan_sendData ( 0x80 ) ;
}
// TODO Check
// Repeat Control
// 0x00 Stops repeat function
// 0x01 Enables repeat function
void scan_repeatControl ( uint8_t on )
{
// Send command
// Binary Representation: 101X XXXn
// Hex options: 0xA0 or 0xA1
scan_sendData ( 0xA0 | on ) ;
}
// TODO Check
// Enable Sending Keyboard Data
// 0x00 Stops keycode transmission
// 0x01 Enables keycode transmission
void scan_enableKeyboard ( uint8_t enable )
{
// Send command
// Binary Representation: 110X XXXn
// Hex options: 0xC0 or 0xC1
scan_sendData ( 0xC0 | enable ) ;
}
// Set Repeat Interval
// 30 ms + n * 5 ms
// Period between sending each repeated key after the initial interval
void scan_setRepeatRate ( uint8_t n )
{
// Send command
// Binary Representation: 001n nnnn
// Hex options: 0x00 to 0x1F
// 30 ms to 185 ms (intervals of 5 ms)
scan_sendData ( 0x20 | n ) ;
}
// Turn On/Off LED
// 0x00 LED Off
// 0x01 LED On
//
// 8 LEDs max (Note: 5 connected on my board, there is 1 position empty on the PCB for a total of 6)
// 0 to 7 (0x0 to 0x7)
void scan_setLED ( uint8_t ledNumber , uint8_t on )
{
// Send command
// Binary Representation: 010l llln
// Hex options: 0x40 to 0x4F
// The spec is NOT accurate (especially about the "don't care" bit)
// llll n - Usage
// 0000 X - N/A (1)
// 0001 X - N/A (2)
// 0010 1 - INSERT On
// 0011 0 - SHIFT LOCK Off
// 0100 X - N/A (3)
// 0101 0 - DRAW Off
// 0110 0 - SCHED Off
// 0111 1 - CALC On
// 1000 X - N/A (1)
// 1001 X - N/A (2)
// 1010 0 - INSERT Off
// 1011 1 - SHIFT LOCK On
// 1100 X - N/A (3)
// 1101 1 - DRAW On
// 1110 1 - SCHED On
// 1111 0 - CALC Off
uint8_t off = 0 ;
if ( ! on )
{
off = 0x10 ;
}
scan_sendData ( ( 0x40 | ( ledNumber < < 1 ) | on ) ^ off ) ;
}
// Read LED Status
// High priority data output (may overwrite some keycode data)
void scan_readLED ( void )
{
scan_sendData ( 0x7F ) ;
}