2012-05-07 06:32:56 +00:00
/* Copyright (C) 2012 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>
2012-05-07 06:32:56 +00:00
// Project Includes
# include <led.h>
# include <print.h>
// Local Includes
# include "scan_loop.h"
// ----- Defines -----
// - Pinout Defines -
// Scan Bit Pins (from keyboard)
// - Reads in the ASCII scancode
// - Shift and ShiftLock are handled internally
# define READSCAN_PORT PORTC
# define READSCAN_DDR DDRC
# define READSCAN_PIN PINC
// Interrupt Pins (from keyboard)
// - CODEINT (Code key signal interrupt/press)
// - Normally high, low when "Code" key is pressed; separate from all other key presses
// - PRESSINT (Press signal interrupt/press)
// - Normally high, low when any key (or multiple except "Code") is pressed, returns to high once all keys are released
// - Signal is changed BEFORE the Scan Bits are updated
// - PULSEINT (Key action pulse interrupt/press)
// - Normally high, low pulses of 147us on key presses (depending on the combination of mode control pins)
// - Pulse is guarranteed to sent after the Scan Bits are updated
# define CODEINT_PORT PORTE
# define CODEINT_DDR DDRE
# define CODEINT_PIN PINE
# define CODEINT_POS 7
# define PRESSINT_PORT PORTE
# define PRESSINT_DDR DDRE
# define PRESSINT_POS 6
# define PULSEINT_PORT PORTD
# define PULSEINT_DDR DDRD
# define PULSEINT_POS 3
// LED Pins (to keyboard)
// - 1 disable LED
// - 1 enable LED
# define LED1_PORT PORTF // [Pin 19]
# define LED1_DDR DDRF
# define LED1_POS 6
# define LED2_PORT PORTF // [Pin 20]
# define LED2_DDR DDRF
# define LED2_POS 7
// Mode Control Pins (to keyboard)
// - Repeat [Pin 14]
// - 1 Single pulse mode (PULSEINT)
// - 0 Repeated pulse mode (PULSEINT) (1 pulse, pause, then constant pulses)
// - Multi [Pin 15]
// - 1 1KRO mode (typewriter compatibility mode)
// - 0 NKRO mode (new pulse on each keypress - PULSEINT)
// - Signal [Pin 18]
// - 1 disables pulse interrupt (PULSEINT)
// - 0 enables pulse interrupt (PULSEINT)
# define REPEAT_PORT PORTF
# define REPEAT_DDR DDRF
# define REPEAT_POS 3
# define MULTI_PORT PORTF
# define MULTI_DDR DDRF
# define MULTI_POS 4
# define SIGNAL_PORT PORTF
# define SIGNAL_DDR DDRF
# define SIGNAL_POS 5
// Manually Scanned Keys
// Keys that the controller screws up, requiring a separate wire to be brought to the controller
// Note: Safer to route these through a NOT gate to boost the signal strength
// Values below are AFTER NOT gate
// - Shift (both shift keys are on the same scan line)
// - 0 Released
// - 1 Pressed
// - Shift Lock
// - 0 Released
// - 1 Pressed
# define MANUAL_SCAN_KEYS 2
# define SHIFT_KEY 0
# define SHIFT_PORT PORTF
# define SHIFT_DDR DDRF
# define SHIFT_PIN PINF
# define SHIFT_POS 0
# define SHIFTLOCK_KEY 1
# define SHIFTLOCK_PORT PORTF
# define SHIFTLOCK_DDR DDRF
# define SHIFTLOCK_PIN PINF
# define SHIFTLOCK_POS 1
// ----- Macros -----
// Make sure we haven't overflowed the buffer
# define bufferAdd(byte) \
if ( KeyIndex_BufferUsed < KEYBOARD_BUFFER ) \
KeyIndex_Buffer [ KeyIndex_BufferUsed + + ] = byte
// ----- 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 KeyIndex_Add_InputSignal ; // Used to pass the (click/input value) to the keyboard for the clicker
volatile uint8_t KeyScan_Table [ MANUAL_SCAN_KEYS ] ; // Used for tracking key status of manually scanned keys
volatile uint8_t KeyScan_Prev [ MANUAL_SCAN_KEYS ] ; // Keeps track of key state changes
volatile uint8_t KeyScan_Count ;
// ----- Functions -----
// Pre-declarations
void processKeyValue ( uint8_t keyValue ) ;
// Setup
inline void scan_setup ( )
{
// Setup the external interrupts for
// - General keypresses (INT6/E6) -> rising edge (to detect key release)
// - "Code" key (INT7/E7) -> falling/rising edge (to detect key press/release)
// - General keypress pulse (INT3/D3) -> falling edge (to detect key press )
EICRA = 0x80 ;
EICRB = 0x70 ;
EIMSK = 0xC8 ;
// Setup Interrupt Pins
CODEINT_PORT | = ( 1 < < CODEINT_POS ) ;
CODEINT_DDR & = ~ ( 1 < < CODEINT_POS ) ;
PRESSINT_PORT | = ( 1 < < PRESSINT_POS ) ;
PRESSINT_DDR & = ~ ( 1 < < PRESSINT_POS ) ;
PULSEINT_PORT | = ( 1 < < PULSEINT_POS ) ;
PULSEINT_DDR & = ~ ( 1 < < PULSEINT_POS ) ;
// Setup LED Pins (default off)
LED1_PORT | = ( 1 < < LED1_POS ) ;
LED1_DDR | = ( 1 < < LED1_POS ) ;
LED2_PORT | = ( 1 < < LED2_POS ) ;
LED2_DDR | = ( 1 < < LED2_POS ) ;
// Setup READSCAN pins to read out scancode
READSCAN_PORT = 0xFF ;
READSCAN_DDR = 0x00 ;
// Setup Mode Control Pins
// Note: These can be changed at any time, but there is no real reason too for a USB converter
REPEAT_PORT | = ( 1 < < REPEAT_POS ) ; // Setting high for single press mode
REPEAT_DDR | = ( 1 < < REPEAT_POS ) ;
MULTI_PORT & = ~ ( 1 < < MULTI_POS ) ; // Setting low for multi press mode (NKRO)
MULTI_DDR | = ( 1 < < MULTI_POS ) ;
SIGNAL_PORT & = ~ ( 1 < < SIGNAL_POS ) ; // Setting low to enable PULSEINT
SIGNAL_DDR | = ( 1 < < SIGNAL_POS ) ;
// Setup Troublesome Key Pins
SHIFT_PORT & = ~ ( 1 < < SHIFT_POS ) ;
SHIFT_DDR & = ~ ( 1 < < SHIFT_POS ) ;
SHIFTLOCK_PORT & = ~ ( 1 < < SHIFTLOCK_POS ) ;
SHIFTLOCK_DDR & = ~ ( 1 < < SHIFTLOCK_POS ) ;
// Reset the keyboard before scanning, we might be in a wierd state
scan_resetKeyboard ( ) ;
}
// Main Detection Loop
// Not needed for the Sony OA-S3400 as signals are interrupt based, thus this is a busy loop
// XXX Function is used for scanning troublesome keys, technically this is not needed for a pure converter
// I just want proper use of the shift and shift lock keys, without having to do major rework to attach to the entire matrix
inline uint8_t scan_loop ( )
{
// Loop through known keys
for ( uint8_t key = 0 ; key < MANUAL_SCAN_KEYS ; key + + ) switch ( key )
{
case SHIFT_KEY :
if ( SHIFT_PIN & ( 1 < < SHIFT_POS ) )
{
KeyScan_Table [ SHIFT_KEY ] + + ;
}
break ;
case SHIFTLOCK_KEY :
if ( SHIFTLOCK_PIN & ( 1 < < SHIFTLOCK_POS ) )
{
KeyScan_Table [ SHIFTLOCK_KEY ] + + ;
}
break ;
default :
erro_print ( " Invalid key scan index " ) ;
break ;
}
// Increment vote instance
KeyScan_Count + + ;
// Loop function again if not enough votes have been tallied
if ( KeyScan_Count < 255 )
return 1 ;
// Clear vote data
KeyScan_Count = 0 ;
// Loop through known keys
for ( uint8_t key = 0 ; key < MANUAL_SCAN_KEYS ; key + + )
{
// Key scanned as pressed (might have been held from a previous vote)
if ( KeyScan_Table [ key ] > 127 )
{
// Keypress detected
if ( ! KeyScan_Prev [ key ] )
{
processKeyValue ( 0x90 + key ) ; // Arbitrary key mapping starts at 0x90
KeyScan_Prev [ key ] = 1 ;
}
}
// Key scanned as released
else
{
// Keypress detected
if ( KeyScan_Prev [ key ] )
{
processKeyValue ( 0xA0 + key ) ; // Arbitrary key mapping release starts at 0xA0
KeyScan_Prev [ key ] = 0 ;
}
}
// Clear votes
KeyScan_Table [ key ] = 0 ;
}
// End loop, process macros and USB data
return 0 ;
}
void processKeyValue ( uint8_t keyValue )
{
// - Convert Shifted Value to non-shifted ASCII code -
// Alphabetic
if ( keyValue > = 0x61 & & keyValue < = 0x7A )
{
keyValue - = 0x20 ;
}
// Other keys with ASCII shift codes
else
{
switch ( keyValue )
{
case 0x21 : // 1
case 0x23 : // 3
case 0x24 : // 4
case 0x25 : // 5
keyValue + = 0x10 ;
break ;
case 0x26 : // 7
case 0x28 : // 9
keyValue + = 0x11 ;
break ;
case 0x81 : // 1/2
case 0x3A : // ;
keyValue + = 0x01 ;
break ;
case 0x29 : // 0
keyValue = 0x30 ;
break ;
case 0x40 : // 2
keyValue = 0x32 ;
break ;
case 0x80 : // 6
keyValue = 0x36 ;
break ;
case 0x2A : // 8
keyValue = 0x38 ;
break ;
case 0x5F : // -
keyValue = 0x2D ;
break ;
case 0x2B : // +
keyValue = 0x3D ;
break ;
case 0x22 : // "
keyValue = 0x27 ;
break ;
case 0x3F : // ?
keyValue = 0x2F ;
break ;
}
}
2012-05-07 17:00:29 +00:00
// TODO Move to Macro Section
switch ( keyValue )
{
case 0xD3 : // F11
scan_sendData ( 0x01 ) ;
break ;
case 0xD4 : // F12
scan_sendData ( 0x02 ) ;
break ;
}
2012-05-07 06:32:56 +00:00
// Scan code is now finalized, and ready to add to buffer
// Note: Scan codes come from 3 different interrupts and a manual key scan into this function
// Debug
char tmpStr [ 6 ] ;
hexToStr ( keyValue , tmpStr ) ;
dPrintStrs ( tmpStr , " " ) ;
// Detect release condition
uint8_t release = 0 ;
switch ( keyValue )
{
case 0xA0 :
case 0xA1 :
case 0xA2 :
keyValue - = 0x10 ;
case 0xB0 :
release = 1 ;
break ;
}
// Key Release
if ( release )
{
// Check for the released key, and shift the other keys lower on the buffer
uint8_t c ;
for ( c = 0 ; c < KeyIndex_BufferUsed ; c + + )
{
// General key buffer clear
if ( keyValue = = 0xB0 )
{
switch ( KeyIndex_Buffer [ c ] )
{
// Ignore these keys on general key release (have their own release codes)
case 0x90 :
case 0x91 :
case 0x92 :
break ;
// Remove key from buffer
default :
// 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 - - ;
2012-05-07 17:00:29 +00:00
// Start at this position again for the next loop
c - - ;
2012-05-07 06:32:56 +00:00
break ;
}
}
// Key to release found
else if ( KeyIndex_Buffer [ c ] = = keyValue )
{
// 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 ) ;
}
}
// Press or Repeated Key
else
{
// 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 ;
}
}
}
// Key Press Detected Interrupt
ISR ( INT3_vect )
{
cli ( ) ; // Disable Interrupts
uint8_t keyValue = 0x00 ;
// Bits are flipped coming in from the keyboard
keyValue = ~ READSCAN_PIN ;
// Process the scancode
processKeyValue ( keyValue ) ;
sei ( ) ; // Re-enable Interrupts
}
// Key Release Detected Interrupt
ISR ( INT6_vect )
{
cli ( ) ; // Disable Interrupts
// Send release code for general keys, 0xB0
processKeyValue ( 0xB0 ) ;
sei ( ) ; // Re-enable Interrupts
}
// Code Key Interrupt
ISR ( INT7_vect )
{
cli ( ) ; // Disable Interrupts
// Code Key Released (send scancode)
if ( CODEINT_PIN & ( 1 < < CODEINT_POS ) )
{
processKeyValue ( 0xA2 ) ;
}
// Code Key Pressed (send scancode)
else
{
processKeyValue ( 0x92 ) ;
}
sei ( ) ; // Re-enable Interrupts
}
// Send data to keyboard
// Sony OA-S3400 has no serial/parallel dataport to send data too...
2012-05-07 17:00:29 +00:00
// Using this function for LED enable/disable
2012-05-07 06:32:56 +00:00
uint8_t scan_sendData ( uint8_t dataPayload )
{
2012-05-07 17:00:29 +00:00
switch ( dataPayload )
{
case 0x01 :
LED1_PORT ^ = ( 1 < < LED1_POS ) ;
break ;
case 0x02 :
LED2_PORT ^ = ( 1 < < LED2_POS ) ;
break ;
default :
erro_print ( " Invalid data send attempt " ) ;
break ;
}
2012-05-07 06:32:56 +00:00
return 0 ;
}
// Signal KeyIndex_Buffer that it has been properly read
// Not needed as a signal is sent to remove key-presses
2013-01-21 03:36:05 +00:00
void scan_finishedWithBuffer ( uint8_t sentKeys )
2012-05-07 06:32:56 +00:00
{
return ;
}
// Reset/Hold keyboard
// Sony OA-S3400 has no locking signals
void scan_lockKeyboard ( void )
{
}
void scan_unlockKeyboard ( void )
{
}
// Reset Keyboard
void scan_resetKeyboard ( void )
{
// Empty buffer, now that keyboard has been reset
KeyIndex_BufferUsed = 0 ;
// Clear the KeyScan table and count
for ( uint8_t key = 0 ; key < MANUAL_SCAN_KEYS ; key + + )
{
KeyScan_Table [ key ] = 0 ;
KeyScan_Prev [ key ] = 0 ;
}
KeyScan_Count = 0 ;
}
// USB module is finished with buffer
// Not needed as a signal is sent to remove key-presses
2013-01-21 03:36:05 +00:00
void scan_finishedWithUSBBuffer ( uint8_t sentKeys )
2012-05-07 06:32:56 +00:00
{
return ;
}