Archived
1
0
This repo is archived. You can view files and clone it, but cannot push or open issues or pull requests.
controller/Scan/SonyOA-S3400/scan_loop.c
Jacob Alexander fa68d61792 Completing Sony OA-S3400 adapter.
- Fixed final bug regarding key release
- Added LED support calls
- Fixed minor keymapping bug for TAB
- Changed default keymap to Colemak
2012-05-07 13:00:29 -04:00

559 lines
13 KiB
C

/* 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 -----
// AVR Includes
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
// 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;
}
}
// TODO Move to Macro Section
switch ( keyValue )
{
case 0xD3: // F11
scan_sendData( 0x01 );
break;
case 0xD4: // F12
scan_sendData( 0x02 );
break;
}
// 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--;
// Start at this position again for the next loop
c--;
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...
// Using this function for LED enable/disable
uint8_t scan_sendData( uint8_t dataPayload )
{
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;
}
return 0;
}
// Signal KeyIndex_Buffer that it has been properly read
// Not needed as a signal is sent to remove key-presses
void scan_finishedWithBuffer( void )
{
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
void scan_finishedWithUSBBuffer( void )
{
return;
}