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/HP150/scan_loop.c
Rowan Decker 1392571bd7 Fix whitespace
Use a consistent standard - Tabs in front for indenting, spaces after for anything else. This way everything stays nice and lined up while also letting users change there prefered indent level. Most of the new files from Haata where already in this format.
2015-03-08 18:40:01 -07:00

313 lines
8.0 KiB
C

/* Copyright (C) 2012,2014 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 -----
// Compiler Includes
#include <Lib/ScanLib.h>
// 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
#define DATA_OUT PINC
#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 -----
// ----- 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;
volatile uint8_t positionCounter = 0;
volatile uint8_t statePositionCounter = 0;
volatile uint16_t stateSamplesTotal = 0;
volatile uint16_t stateSamples = 0;
// 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);
currentWaveState--; // Keeps track of the clock value (for direct clock output)
statePositionCounter = positionCounter;
positionCounter++; // Counts the number of falling edges, reset is done by the controlling section (reset, or main scan)
}
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)
// 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
// Prescaler is 1
cli();
TCCR1B = 0x09;
OCR1AH = 0x03;
OCR1AL = 0x1F;
TIMSK1 = (1 << OCIE1A);
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
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()
{
// Only use as a valid signal
// Check if there was a position change
if ( positionCounter != statePositionCounter )
{
// At least 80% of the samples must be valid
if ( stateSamples * 100 / stateSamplesTotal >= 80 )
{
// 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 )
{
positionCounter = 0;
}
// Key Press Detected
// - Skip 0x00 to 0x0B (11) for better jitter immunity (as there are no keys mapped to those scancodes)
else if ( positionCounter > 0x0B )
{
char tmp[15];
hexToStr( positionCounter, tmp );
dPrintStrsNL( "Key: ", tmp );
// 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 )
Macro_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;
}
}
}
// Clear the state counters
stateSamples = 0;
stateSamplesTotal = 0;
statePositionCounter = positionCounter;
}
// Pull in a data sample for this read instance
if ( DATA_OUT & (1 <<DATA_PIN) )
stateSamples++;
stateSamplesTotal++;
// Check if the clock de-synchronized
// And reset
if ( positionCounter > 128 )
{
char tmp[15];
hexToStr( positionCounter, tmp );
erro_dPrint( "De-synchronization detected at: ", tmp );
errorLED( 1 );
positionCounter = 0;
KeyIndex_BufferUsed = 0;
// Clear the state counters
stateSamples = 0;
stateSamplesTotal = 0;
// A keyboard reset requires interrupts to be enabled
sei();
scan_resetKeyboard();
cli();
}
// Regardless of what happens, always return 0
return 0;
}
// Send data
uint8_t Scan_sendData( uint8_t dataPayload )
{
return 0;
}
// Signal KeyIndex_Buffer that it has been properly read
void Scan_finishedWithBuffer( uint8_t sentKeys )
{
}
// Signal that the keys have been properly sent over USB
void Scan_finishedWithUSBBuffer( uint8_t sentKeys )
{
}
// Reset/Hold keyboard
// NOTE: Does nothing with the HP150
void Scan_lockKeyboard( void )
{
}
// NOTE: Does nothing with the HP150
void Scan_unlockKeyboard( void )
{
}
// Reset Keyboard
void Scan_resetKeyboard( void )
{
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 )
{
// Only use as a valid signal
// Check if there was a position change
if ( positionCounter != statePositionCounter )
{
// At least 80% of the samples must be valid
if ( stateSamples * 100 / stateSamplesTotal >= 80 )
{
// 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;
}
}
// Clear the state counters
stateSamples = 0;
stateSamplesTotal = 0;
statePositionCounter = positionCounter;
}
}
info_print("Keyboard Synchronized!");
}