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 65366a4e7a Adding initial version of Sony OA-S3400 converter.
- Not fully reading for usage, but 90% of the way there for typing.
- Some soldering is required for 2 keys to work properly (Shift and Shift Lock)
- Even when complete, be careful when doing multiple key combos, as the key buffer is only cleared when all general keys are released (all except Shift, Shift Lock, and Code)
2012-05-07 02:32:56 -04:00

532 lines
12 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;
}
}
// 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--;
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...
uint8_t scan_sendData( uint8_t dataPayload )
{
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;
}