2012-11-15 09:28:31 +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-11-15 09:28:31 +00:00
// Project Includes
# include <led.h>
# include <print.h>
// Local Includes
# include "scan_loop.h"
// ----- Defines -----
// Pinout Defines
# define DATA_PORT PORTC
# define DATA_DDR DDRC
# define DATA_PIN 7
2012-11-17 10:13:06 +00:00
# define DATA_OUT PINC
2012-11-15 09:28:31 +00:00
# define CLOCK_PORT PORTC
# define CLOCK_DDR DDRC
# define CLOCK_PIN 6
# define RESET_PORT PORTF
# define RESET_DDR DDRF
# define RESET_PIN 7
// ----- 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 currentWaveState = 0 ;
2012-11-17 10:13:06 +00:00
volatile uint8_t positionCounter = 0 ;
2012-11-15 09:28:31 +00:00
2012-11-19 08:55:30 +00:00
volatile uint8_t statePositionCounter = 0 ;
volatile uint16_t stateSamplesTotal = 0 ;
volatile uint16_t stateSamples = 0 ;
2012-11-15 09:28:31 +00:00
// Buffer Signals
volatile uint8_t BufferReadyToClear ;
// ----- Function Declarations -----
void processKeyValue ( uint8_t keyValue ) ;
void removeKeyValue ( uint8_t keyValue ) ;
// ----- Interrupt Functions -----
// Generates a constant external clock
ISR ( TIMER1_COMPA_vect )
{
if ( currentWaveState )
{
CLOCK_PORT & = ~ ( 1 < < CLOCK_PIN ) ;
2012-11-17 10:13:06 +00:00
currentWaveState - - ; // Keeps track of the clock value (for direct clock output)
2012-11-19 08:55:30 +00:00
statePositionCounter = positionCounter ;
2012-11-17 10:13:06 +00:00
positionCounter + + ; // Counts the number of falling edges, reset is done by the controlling section (reset, or main scan)
2012-11-15 09:28:31 +00:00
}
else
{
CLOCK_PORT | = ( 1 < < CLOCK_PIN ) ;
currentWaveState + + ;
}
}
// ----- Functions -----
// Setup
inline void scan_setup ( )
{
// Setup Timer Pulse (16 bit)
// TODO Clock can be adjusted to whatever (read chip datasheets for limits)
2012-11-17 10:13:06 +00:00
// This seems like a good scan speed, as there don't seem to be any periodic
// de-synchronization events, and is fast enough for scanning keys
// Anything much more (100k baud), tends to cause a lot of de-synchronization
// 16 MHz / (2 * Prescaler * (1 + OCR1A)) = 10k baud
2012-11-15 09:28:31 +00:00
// Prescaler is 1
cli ( ) ;
TCCR1B = 0x09 ;
2012-11-17 10:13:06 +00:00
OCR1AH = 0x03 ;
OCR1AL = 0x1F ;
2012-11-15 09:28:31 +00:00
TIMSK1 = ( 1 < < OCIE1A ) ;
2012-11-19 08:55:30 +00:00
CLOCK_DDR | = ( 1 < < CLOCK_PIN ) ; // Set the clock pin as an output
DATA_PORT | = ( 1 < < DATA_PIN ) ; // Pull-up resistor for input the data line
2012-11-15 09:28:31 +00:00
sei ( ) ;
// Initially buffer doesn't need to be cleared (it's empty...)
BufferReadyToClear = 0 ;
// Reset the keyboard before scanning, we might be in a wierd state
scan_resetKeyboard ( ) ;
}
// Main Detection Loop
// Since this function is non-interruptable, we can do checks here on what stage of the
// output clock we are at (0 or 1)
// We are looking for a start of packet
// If detected, all subsequent bits are then logged into a variable
// Once the end of the packet has been detected (always the same length), decode the pressed keys
inline uint8_t scan_loop ( )
{
2012-11-19 08:55:30 +00:00
// Only use as a valid signal
// Check if there was a position change
if ( positionCounter ! = statePositionCounter )
2012-11-15 09:28:31 +00:00
{
2012-11-19 08:55:30 +00:00
// At least 80% of the samples must be valid
if ( stateSamples * 100 / stateSamplesTotal > = 80 )
2012-11-15 09:28:31 +00:00
{
2012-11-17 10:13:06 +00:00
// Reset the scan counter, all the keys have been iterated over
// Ideally this should reset at 128, however
// due to noise in the cabling, this often moves around
// The minimum this can possibly set to is 124 as there
// are keys to service at 123 (0x78)
// Usually, unless there is lots of interference,
// this should limit most of the noise.
if ( positionCounter > = 124 )
2012-11-15 09:28:31 +00:00
{
2012-11-17 10:13:06 +00:00
positionCounter = 0 ;
2012-11-15 09:28:31 +00:00
}
2012-11-17 10:13:06 +00:00
// Key Press Detected
2012-11-19 08:55:30 +00:00
// - Skip 0x00 to 0x0B (11) for better jitter immunity (as there are no keys mapped to those scancodes)
else if ( positionCounter > 0x0B )
2012-11-17 10:13:06 +00:00
{
char tmp [ 15 ] ;
hexToStr ( positionCounter , tmp ) ;
dPrintStrsNL ( " Key: " , tmp ) ;
2012-11-15 09:28:31 +00:00
2012-11-19 08:55:30 +00:00
// Make sure there aren't any duplicate keys
uint8_t c ;
for ( c = 0 ; c < KeyIndex_BufferUsed ; c + + )
if ( KeyIndex_Buffer [ c ] = = positionCounter )
break ;
// No duplicate keys, add it to the buffer
if ( c = = KeyIndex_BufferUsed )
bufferAdd ( positionCounter ) ;
}
}
// Remove the key from the buffer
else if ( positionCounter < 124 & & positionCounter > 0x0B )
{
// 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
if ( KeyIndex_Buffer [ c ] = = positionCounter )
{
// 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 ;
}
2012-11-17 10:13:06 +00:00
}
2012-11-15 09:28:31 +00:00
}
2012-11-17 10:13:06 +00:00
2012-11-19 08:55:30 +00:00
// Clear the state counters
stateSamples = 0 ;
stateSamplesTotal = 0 ;
statePositionCounter = positionCounter ;
2012-11-15 09:28:31 +00:00
}
2012-11-19 08:55:30 +00:00
// Pull in a data sample for this read instance
if ( DATA_OUT & ( 1 < < DATA_PIN ) )
stateSamples + + ;
stateSamplesTotal + + ;
2012-11-17 10:13:06 +00:00
// Check if the clock de-synchronized
// And reset
if ( positionCounter > 128 )
2012-11-15 09:28:31 +00:00
{
2012-11-17 10:13:06 +00:00
char tmp [ 15 ] ;
hexToStr ( positionCounter , tmp ) ;
erro_dPrint ( " De-synchronization detected at: " , tmp ) ;
errorLED ( 1 ) ;
2012-11-15 09:28:31 +00:00
2012-11-17 10:13:06 +00:00
positionCounter = 0 ;
KeyIndex_BufferUsed = 0 ;
2012-11-15 09:28:31 +00:00
2012-11-19 08:55:30 +00:00
// Clear the state counters
stateSamples = 0 ;
stateSamplesTotal = 0 ;
2012-11-17 10:13:06 +00:00
// A keyboard reset requires interrupts to be enabled
sei ( ) ;
scan_resetKeyboard ( ) ;
cli ( ) ;
2012-11-15 09:28:31 +00:00
}
2012-11-17 10:13:06 +00:00
// Regardless of what happens, always return 0
return 0 ;
2012-11-15 09:28:31 +00:00
}
// Send data
uint8_t scan_sendData ( uint8_t dataPayload )
{
return 0 ;
}
// Signal KeyIndex_Buffer that it has been properly read
2013-01-21 03:36:05 +00:00
void scan_finishedWithBuffer ( uint8_t sentKeys )
2012-11-15 09:28:31 +00:00
{
}
// Signal that the keys have been properly sent over USB
2013-01-21 03:36:05 +00:00
void scan_finishedWithUSBBuffer ( uint8_t sentKeys )
2012-11-15 09:28:31 +00:00
{
}
// Reset/Hold keyboard
2012-11-17 10:13:06 +00:00
// NOTE: Does nothing with the HP150
2012-11-15 09:28:31 +00:00
void scan_lockKeyboard ( void )
{
}
2012-11-17 10:13:06 +00:00
// NOTE: Does nothing with the HP150
2012-11-15 09:28:31 +00:00
void scan_unlockKeyboard ( void )
{
}
// Reset Keyboard
void scan_resetKeyboard ( void )
{
2012-11-17 10:13:06 +00:00
info_print ( " Attempting to synchronize the keyboard, do not press any keys... " ) ;
errorLED ( 1 ) ;
// Do a proper keyboard reset (flushes the ripple counters)
RESET_PORT | = ( 1 < < RESET_PIN ) ;
_delay_us ( 10 ) ;
RESET_PORT & = ~ ( 1 < < RESET_PIN ) ;
// Delay main keyboard scanning, until the bit counter is synchronized
uint8_t synchronized = 0 ;
while ( ! synchronized )
{
2012-11-19 08:55:30 +00:00
// Only use as a valid signal
// Check if there was a position change
if ( positionCounter ! = statePositionCounter )
2012-11-17 10:13:06 +00:00
{
2012-11-19 08:55:30 +00:00
// At least 80% of the samples must be valid
if ( stateSamples * 100 / stateSamplesTotal > = 80 )
2012-11-17 10:13:06 +00:00
{
2012-11-19 08:55:30 +00:00
// Read the current data value
if ( DATA_OUT & ( 1 < < DATA_PIN ) )
{
// Check if synchronized
// There are 128 positions to scan for with the HP150 keyboard protocol
if ( positionCounter = = 128 )
synchronized = 1 ;
positionCounter = 0 ;
}
2012-11-17 10:13:06 +00:00
}
2012-11-19 08:55:30 +00:00
// Clear the state counters
stateSamples = 0 ;
stateSamplesTotal = 0 ;
statePositionCounter = positionCounter ;
2012-11-17 10:13:06 +00:00
}
}
info_print ( " Keyboard Synchronized! " ) ;
2012-11-15 09:28:31 +00:00
}