changeset 55:4da33d34ec64

Adding more robust detection for the HP150 - All spare cycles are used to get a more accurate data line sample (waaaay more than actually needed, but this helps against noise) - Switched to a pre/release (add/remove) rather than an add->clear mechanism (or a buffer+debounce/add->clear) - Note that a pull-down resistor is NEEDED on the data line
author Jacob Alexander <triplehaata@gmail.com>
date Mon, 19 Nov 2012 00:55:30 -0800
parents 613743bf5bdd
children 5359c8357d19
files Scan/HP150/scan_loop.c
diffstat 1 files changed, 77 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/Scan/HP150/scan_loop.c	Sat Nov 17 02:13:06 2012 -0800
+++ b/Scan/HP150/scan_loop.c	Mon Nov 19 00:55:30 2012 -0800
@@ -69,9 +69,12 @@
 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 currentWaveDone = 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;
@@ -94,7 +97,7 @@
 	{
 		CLOCK_PORT &= ~(1 << CLOCK_PIN);
 		currentWaveState--; // Keeps track of the clock value (for direct clock output)
-		currentWaveDone--;  // Keeps track of whether the current falling edge has been processed
+		statePositionCounter = positionCounter;
 		positionCounter++;  // Counts the number of falling edges, reset is done by the controlling section (reset, or main scan)
 	}
 	else
@@ -124,7 +127,9 @@
 	OCR1AH = 0x03;
 	OCR1AL = 0x1F;
 	TIMSK1 = (1 << OCIE1A);
-	CLOCK_DDR = (1 << CLOCK_PIN);
+
+	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();
 
 
@@ -144,25 +149,12 @@
 // Once the end of the packet has been detected (always the same length), decode the pressed keys
 inline uint8_t scan_loop()
 {
-	// Read on each falling edge/after the falling edge of the clock
-	if ( !currentWaveDone )
+	// Only use as a valid signal
+	// Check if there was a position change
+	if ( positionCounter != statePositionCounter )
 	{
-		// Sample the current value 50 times
-		// If there is a signal for 40/50 of the values, then it is active
-		// This works as a very simple debouncing mechanism
-		// XXX Could be done more intelligently:
-		//  Take into account the frequency of the clock + overhead, and space out the reads
-		//  Or do something like "dual edge" statistics, where you query the stats from both rising and falling edges
-		//   then make a decision (probably won't do much better against the last source of noise, but would do well for debouncing)
-		uint8_t total = 0;
-		uint8_t c = 0;
-		for ( ; c < 50; c++ )
-			if ( DATA_OUT & (1 << DATA_PIN) )
-				total++;
-
-
-		// Only use as a valid signal
-		if ( total >= 40 )
+		// 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
@@ -174,25 +166,60 @@
 			if ( positionCounter >= 124 )
 			{
 				positionCounter = 0;
-
-				// Clear key buffer
-				KeyIndex_BufferUsed = 0;
 			}
 			// Key Press Detected
-			else
+			//  - 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 );
 
-				bufferAdd( positionCounter );
+				// 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;
+				}
 			}
 		}
 
-		// Wait until the next falling clock edge for the next DATA scan
-		currentWaveDone++;
+
+		// 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 )
@@ -205,6 +232,10 @@
 		positionCounter = 0;
 		KeyIndex_BufferUsed = 0;
 
+		// Clear the state counters
+		stateSamples = 0;
+		stateSamplesTotal = 0;
+
 		// A keyboard reset requires interrupts to be enabled
 		sei();
 		scan_resetKeyboard();
@@ -257,22 +288,29 @@
 	uint8_t synchronized = 0;
 	while ( !synchronized )
 	{
-		// Read on each falling edge/after the falling edge of the clock
-		if ( !currentWaveDone )
+		// Only use as a valid signal
+		// Check if there was a position change
+		if ( positionCounter != statePositionCounter )
 		{
-			// Read the current data value
-			if ( DATA_OUT & (1 << DATA_PIN) )
+			// At least 80% of the samples must be valid
+			if ( stateSamples * 100 / stateSamplesTotal >= 80 )
 			{
-				// Check if synchronized
-				// There are 128 positions to scan for with the HP150 keyboard protocol
-				if ( positionCounter == 128 )
-					synchronized = 1;
+				// 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;
+					positionCounter = 0;
+				}
 			}
 
-			// Wait until the next falling clock edge for the next DATA scan
-			currentWaveDone++;
+			// Clear the state counters
+			stateSamples = 0;
+			stateSamplesTotal = 0;
+			statePositionCounter = positionCounter;
 		}
 	}