changeset 45:8a09c4d30e16

Adding inital outline for Univac-Sperry F3W9 keyboard. - Not tested yet - Packet size is large so it's not possible to use Teensy hardware
author Jacob Alexander <triplehaata@gmail.com>
date Sat, 03 Mar 2012 21:16:41 -0500
parents 511d7ad5b38e
children 4427da7db226
files CMakeLists.txt Keymap/keymap.h Keymap/univacf3w9.h Scan/UnivacF3W9/scan_loop.c Scan/UnivacF3W9/scan_loop.h Scan/UnivacF3W9/setup.cmake USB/pjrc/usb_keyboard_debug.c setup.cmake
diffstat 8 files changed, 820 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Mon Feb 13 14:04:53 2012 -0500
+++ b/CMakeLists.txt	Sat Mar 03 21:16:41 2012 -0500
@@ -64,8 +64,8 @@
 #| "atmega32u4"       # Teensy   2.0
 #| "at90usb646"       # Teensy++ 1.0
 #| "at90usb1286"      # Teensy++ 2.0
-set( MCU "atmega32u4" )
-#set( MCU "at90usb1286" )
+#set( MCU "atmega32u4" )
+set( MCU "at90usb1286" )
 
 
 #| Compiler flag to set the C Standard level.
--- a/Keymap/keymap.h	Mon Feb 13 14:04:53 2012 -0500
+++ b/Keymap/keymap.h	Sat Mar 03 21:16:41 2012 -0500
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011 by Jacob Alexander
+/* Copyright (C) 2011-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
@@ -48,6 +48,7 @@
 #include "microswitch8304.h"
 #include "sonynews.h"
 #include "tandy1000.h"
+#include "univacf3w9.h"
 
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Keymap/univacf3w9.h	Sat Mar 03 21:16:41 2012 -0500
@@ -0,0 +1,329 @@
+/* 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.
+ */
+
+#ifndef __UNIVACF3W9_H
+#define __UNIVACF3W9_H
+
+// This file contains various key layouts for the Univac F3W9 keyboard
+
+
+
+// ----- Variables -----
+static uint8_t univacf3w9_ModifierMask[] = { 0x81, 0x83, 0x85, 0x87, 0x89, 0x8B, 0x8D, 0x8F };
+
+static uint8_t univacf3w9_DefaultMap[] = { 
+				0x00, // 0x00
+				KEY_F4, // 0x01
+				0, // 0x02
+				KEY_F5, // 0x03
+				KEY_F6, // 0x04
+				KEY_F7, // 0x05
+				KEY_F8, // 0x06
+				KEY_F9, // 0x07
+				0, // 0x08
+				KEY_F10, // 0x09
+				KEY_F11, // 0x0A
+				KEY_F12, // 0x0B
+				KEY_F13, // 0x0C
+				0, // 0x0D
+				KEY_F14, // 0x0E
+				KEY_F15, // 0x0F
+				0, // 0x10
+				0, // 0x11
+				0, // 0x12
+				0, // 0x13
+				0, // 0x14
+				KEYPAD_ENTER, // 0x15
+				KEYPAD_PERIOD, // 0x16
+				KEYPAD_0, // 0x17
+				KEYPAD_EQUAL, // 0x18
+				KEYPAD_6, // 0x19
+				KEYPAD_5, // 0x1A
+				KEYPAD_4, // 0x1B
+				0, // 0x1C
+				0, // 0x1D
+				KEY_F17, // 0x1E
+				KEY_F16, // 0x1F
+				0, // 0x20
+				0, // 0x21
+				0, // 0x22
+				0, // 0x23
+				0, // 0x24
+				KEYPAD_3, // 0x25
+				KEYPAD_2, // 0x26
+				KEYPAD_1, // 0x27
+				KEYPAD_PLUS, // 0x28
+				KEYPAD_9, // 0x29
+				KEYPAD_8, // 0x2A
+				KEYPAD_7, // 0x2B
+				KEYPAD_MINUS, // 0x2C
+				KEYPAD_ASTERIX, // 0x2D
+				KEYPAD_SLASH, // 0x2E
+				KEY_NUM_LOCK, // 0x2F
+				0, // 0x30
+				0, // 0x31
+				KEY_SPACE, // 0x32
+				KEY_Z, // 0x33
+				KEY_X, // 0x34
+				KEY_C, // 0x35
+				KEY_V, // 0x36
+				KEY_B, // 0x37
+				KEY_N, // 0x38
+				KEY_M, // 0x39
+				KEY_COMMA, // 0x3A
+				KEY_PERIOD, // 0x3B
+				KEY_UP, // 0x3C
+				KEY_LEFT, // 0x3D
+				KEY_RIGHT, // 0x3E
+				KEY_DOWN, // 0x3F
+				0, // 0x40
+				KEY_F19, // 0x41
+				KEY_CAPS_LOCK, // 0x42
+				KEY_A, // 0x43
+				KEY_S, // 0x44
+				KEY_D, // 0x45
+				KEY_F, // 0x46
+				KEY_G, // 0x47
+				KEY_H, // 0x48
+				KEY_J, // 0x49
+				KEY_K, // 0x4A
+				KEY_L, // 0x4B
+				KEY_SEMICOLON, // 0x4C
+				KEY_QUOTE, // 0x4D
+				KEY_ENTER, // 0x4E
+				KEY_SLASH, // 0x4F
+				0, // 0x50
+				KEY_Q, // 0x51
+				KEY_W, // 0x52
+				KEY_E, // 0x53
+				KEY_R, // 0x54
+				KEY_T, // 0x55
+				KEY_Y, // 0x56
+				KEY_U, // 0x57
+				KEY_I, // 0x58
+				KEY_O, // 0x59
+				KEY_P, // 0x5A
+				KEY_LEFT_BRACE, // 0x5B
+				KEY_RIGHT_BRACE, // 0x5C
+				KEY_BACKSLASH, // 0x5D
+				KEY_INSERT, // 0x5E
+				KEY_PAGE_DOWN, // 0x5F
+				0, // 0x60
+				KEY_2, // 0x61
+				KEY_3, // 0x62
+				KEY_4, // 0x63
+				KEY_5, // 0x64
+				KEY_6, // 0x65
+				KEY_7, // 0x66
+				KEY_8, // 0x67
+				KEY_9, // 0x68
+				KEY_0, // 0x69
+				KEY_MINUS, // 0x6A
+				KEY_EQUAL, // 0x6B
+				KEY_TILDE, // 0x6C
+				KEY_BACKSPACE, // 0x6D
+				KEY_DELETE, // 0x6E
+				KEY_PAGE_UP, // 0x6F
+				0, // 0x70
+				KEY_F3, // 0x71
+				KEY_F2, // 0x72
+				KEY_F1, // 0x73
+				KEY_F18, // 0x74
+				KEY_ESC, // 0x75
+				KEY_1, // 0x76
+				KEY_TAB, // 0x77
+				KEY_F19, // 0x78
+				0, // 0x79
+				0, // 0x7A
+				0, // 0x7B
+				0, // 0x7C
+				0, // 0x7D
+				0, // 0x7E
+				0, // 0x7F
+				0, // 0x80
+				0, // 0x81
+				0, // 0x82
+				0, // 0x83
+				0, // 0x84
+				KEY_RIGHT_SHIFT, // 0x85
+				0, // 0x86
+				KEY_LEFT_SHIFT, // 0x87
+				0, // 0x88
+				0, // 0x89
+				0, // 0x8A
+				KEY_LEFT_CTRL, // 0x8B
+				0, // 0x8C
+				KEY_GUI, // 0x8D
+				0, // 0x8E
+				KEY_RIGHT_CTRL, // 0x8F
+};
+
+static uint8_t univacf3w9_ColemakMap[] = {
+				0x00, // 0x00
+				KEY_F4, // 0x01
+				0, // 0x02
+				KEY_F5, // 0x03
+				KEY_F6, // 0x04
+				KEY_F7, // 0x05
+				KEY_F8, // 0x06
+				KEY_F9, // 0x07
+				0, // 0x08
+				KEY_F10, // 0x09
+				KEY_F11, // 0x0A
+				KEY_F12, // 0x0B
+				KEY_F13, // 0x0C
+				0, // 0x0D
+				KEY_F14, // 0x0E
+				KEY_F15, // 0x0F
+				0, // 0x10
+				0, // 0x11
+				0, // 0x12
+				0, // 0x13
+				0, // 0x14
+				KEYPAD_ENTER, // 0x15
+				KEYPAD_PERIOD, // 0x16
+				KEYPAD_0, // 0x17
+				KEYPAD_EQUAL, // 0x18
+				KEYPAD_6, // 0x19
+				KEYPAD_5, // 0x1A
+				KEYPAD_4, // 0x1B
+				0, // 0x1C
+				0, // 0x1D
+				KEY_F17, // 0x1E
+				KEY_F16, // 0x1F
+				0, // 0x20
+				0, // 0x21
+				0, // 0x22
+				0, // 0x23
+				0, // 0x24
+				KEYPAD_3, // 0x25
+				KEYPAD_2, // 0x26
+				KEYPAD_1, // 0x27
+				KEYPAD_PLUS, // 0x28
+				KEYPAD_9, // 0x29
+				KEYPAD_8, // 0x2A
+				KEYPAD_7, // 0x2B
+				KEYPAD_MINUS, // 0x2C
+				KEYPAD_ASTERIX, // 0x2D
+				KEYPAD_SLASH, // 0x2E
+				KEY_NUM_LOCK, // 0x2F
+				0, // 0x30
+				0, // 0x31
+				KEY_SPACE, // 0x32
+				KEY_Z, // 0x33
+				KEY_X, // 0x34
+				KEY_C, // 0x35
+				KEY_V, // 0x36
+				KEY_B, // 0x37
+				KEY_K, // 0x38
+				KEY_M, // 0x39
+				KEY_COMMA, // 0x3A
+				KEY_PERIOD, // 0x3B
+				KEY_UP, // 0x3C
+				KEY_LEFT, // 0x3D
+				KEY_RIGHT, // 0x3E
+				KEY_DOWN, // 0x3F
+				0, // 0x40
+				KEY_F19, // 0x41
+				KEY_CAPS_LOCK, // 0x42
+				KEY_A, // 0x43
+				KEY_R, // 0x44
+				KEY_S, // 0x45
+				KEY_T, // 0x46
+				KEY_D, // 0x47
+				KEY_H, // 0x48
+				KEY_N, // 0x49
+				KEY_E, // 0x4A
+				KEY_I, // 0x4B
+				KEY_O, // 0x4C
+				KEY_QUOTE, // 0x4D
+				KEY_ENTER, // 0x4E
+				KEY_SLASH, // 0x4F
+				0, // 0x50
+				KEY_Q, // 0x51
+				KEY_W, // 0x52
+				KEY_F, // 0x53
+				KEY_P, // 0x54
+				KEY_G, // 0x55
+				KEY_J, // 0x56
+				KEY_L, // 0x57
+				KEY_U, // 0x58
+				KEY_Y, // 0x59
+				KEY_SEMICOLON, // 0x5A
+				KEY_LEFT_BRACE, // 0x5B
+				KEY_RIGHT_BRACE, // 0x5C
+				KEY_BACKSLASH, // 0x5D
+				KEY_INSERT, // 0x5E
+				KEY_PAGE_DOWN, // 0x5F
+				0, // 0x60
+				KEY_2, // 0x61
+				KEY_3, // 0x62
+				KEY_4, // 0x63
+				KEY_5, // 0x64
+				KEY_6, // 0x65
+				KEY_7, // 0x66
+				KEY_8, // 0x67
+				KEY_9, // 0x68
+				KEY_0, // 0x69
+				KEY_MINUS, // 0x6A
+				KEY_EQUAL, // 0x6B
+				KEY_TILDE, // 0x6C
+				KEY_BACKSPACE, // 0x6D
+				KEY_DELETE, // 0x6E
+				KEY_PAGE_UP, // 0x6F
+				0, // 0x70
+				KEY_F3, // 0x71
+				KEY_F2, // 0x72
+				KEY_F1, // 0x73
+				KEY_F18, // 0x74
+				KEY_ESC, // 0x75
+				KEY_1, // 0x76
+				KEY_TAB, // 0x77
+				KEY_F19, // 0x78
+				0, // 0x79
+				0, // 0x7A
+				0, // 0x7B
+				0, // 0x7C
+				0, // 0x7D
+				0, // 0x7E
+				0, // 0x7F
+				0, // 0x80
+				0, // 0x81
+				0, // 0x82
+				0, // 0x83
+				0, // 0x84
+				KEY_RIGHT_SHIFT, // 0x85
+				0, // 0x86
+				KEY_LEFT_SHIFT, // 0x87
+				0, // 0x88
+				0, // 0x89
+				0, // 0x8A
+				KEY_LEFT_CTRL, // 0x8B
+				0, // 0x8C
+				KEY_GUI, // 0x8D
+				0, // 0x8E
+				KEY_ALT, // 0x8F
+};
+
+
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Scan/UnivacF3W9/scan_loop.c	Sat Mar 03 21:16:41 2012 -0500
@@ -0,0 +1,371 @@
+/* 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
+#define REQUEST_PORT PORTD
+#define REQUEST_DDR  DDRD
+#define REQUEST_PIN  3
+#define DATA_READ    PIND
+#define DATA_PORT    PORTD
+#define DATA_DDR     DDRD
+#define DATA_PIN     2
+
+#define MAX_SAMPLES    10
+#define MAX_FAILURES   3731
+#define PACKET_STORAGE 24   // At worst only 8 packets, but with you keypresses you can get more
+
+
+// ----- Macros -----
+
+#define READ_DATA         DATA_READ &   (1 << DATA_PIN) ? 0 : 1
+
+#define REQUEST_DATA()  REQUEST_DDR &= ~(1 << REQUEST_PIN) // Start incoming keyboard transfer
+#define    STOP_DATA()  REQUEST_DDR |=  (1 << REQUEST_PIN) // Stop incoming keyboard data
+
+// 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;
+
+
+
+// ----- Function Declarations -----
+
+void processPacketValue( uint16_t packetValue );
+
+
+
+// ----- Interrupt Functions -----
+
+// XXX - None Required
+
+
+
+// ----- Functions -----
+
+// Setup
+// This setup is very simple, as there is no extra hardware used in this scan module, other than GPIOs.
+// To be nice, we wait a little bit after powering on, and dump any of the pending keyboard data.
+// Afterwards (as long as no keys were being held), the keyboard should have a clean buffer, and be ready to go.
+// (Even if keys were held down, everything should probably still work...)
+inline void scan_setup()
+{
+	// Setup the DATA pin
+	DATA_DDR  &= ~(1 << DATA_PIN); // Set to input
+	DATA_PORT |=  (1 << DATA_PIN); // Set to pull-up resistor
+
+	// Setup the REQUEST pin
+	REQUEST_DDR |= (1 << REQUEST_PIN); // Set to output
+	STOP_DATA(); // Set the line high to stop incoming data
+
+	// Reset the keyboard before scanning, we might be in a wierd state
+	_delay_ms( 50 );
+	scan_resetKeyboard();
+}
+
+
+// Main Detection Loop
+// The Univac-Sperry F3W9 has a convenient feature, an internal 8 key buffer
+// This buffer is only emptied (i.e. sent over the bus) when the REQUEST line is held high
+// Because of this, we can utilize the scan_loop to do all of the critical processing,
+//  without having to resort to interrupts, giving the data reading 100% of the CPU.
+// This is because the USB interrupts can wait until the scan_loop is finished to continue.
+//
+// Normally, this approach isn't taken, as it's easier/faster/safer to use Teensy hardware shift registers
+//  for serial data transfers.
+// However, since the Univac-Sperry F3W9 sends 20 bit packets (including the start bit), the Teensy
+//  doesn't have a shift register large enough (9 bit max), to hold the data.
+// So the line must be polled manually using CPU cycles
+//
+// Another interesting feature is that there are 2 data lines.
+// Output and /Output (NOT'ted version).
+// Not really useful here, but could be used for error checking, or eliminating an external NOT gate if
+//  we were using (but can't...) a hardware decoder like a USART.
+inline uint8_t scan_loop()
+{
+	// Protocol Notes:
+	// - Packets are 20 bits long, including the start bit
+	// - Each bit is ~105 usecs in length
+	// - Thus the average packet length is 2.205 msecs
+	// - Each packet is separated by at least 240 usecs (during a buffer unload)
+	// - While holding the key down, each packet has a space of about 910 usecs
+	// - A max of 8 keys can be sent at once (note, the arrow keys seem use 2 packets each, and thus take up twice as much buffer)
+	// - There is no timing danger for holding the request line, just that data may come in when you don't want it
+
+	// Now that the scan loop has been entered, we don't have to worry about interrupts stealing
+	//  precious cycles.
+	REQUEST_DATA();
+
+	// = Delays =
+	//
+	// For these calculations to work out properly, then Teensy should be running at 16 MHz
+	// - 1 bit         : 105   usecs is 16 000 000 * 0.000105  =   1680 instructions
+	// - Bit centering :  52.5 usecs is 16 000 000 * 0.0000525 =    840 instructions
+	// - Delay         :   5   msecs is 16 000 000 * 0.005     = 80 000 instructions
+	// - Microsecond   :   1   usec  is 16 000 000 * 0.000001  =     16 instructions
+	//
+	// Now, either I can follow these exactly, or based upon the fact that I have >840 tries to find the
+	//  the start bit, and >1680 tries to read the subsequent bits, I have some "flex" time.
+	// Knowing this, I can make some assumptions that because I'm only reading a total of 20 bits, and will
+	//  be re-centering for each packet.
+	// This will allow for less worrying about compiler optimizations (and porting!).
+
+	// The basic idea is to find a "reliable" value for the start bit, e.g. read it ~10 times.
+	// Using a for-loop and some addition counters, this should eat up approximately 20-30 instructions per read
+	//  (very loose estimation).
+	// So reading 10 * 30 instructions = 300 instructions, which is much less than 840 instructions to where the
+	//  bit center is, but is close enough that further delays of ~>1680 instructions will put the next read
+	//  within the next bit period.
+	// This is all possible because interrupts are disabled at this point, otherwise, all of this reasoning
+	//  would fall apart.
+	// _delay_us is available to use, fortunately.
+
+	// Input Packet Storage (before being processed)
+	uint16_t incomingPacket[PACKET_STORAGE];
+	uint8_t  numberOfIncomingPackets = 0;
+
+	// Sample the data line for ~5 ms, looking for a start bit
+	//  - Sampling every 1 usecs, looking for 10 good samples
+	//  - Accumulated samples will dumped if a high is detected
+	uint8_t  samples  = 0;
+	uint16_t failures = 0;
+
+	// Continue waiting for a start bit until MAX_FAILURES has been reached (~5ms of nothing)
+	while ( failures <= MAX_FAILURES )
+	{
+		// Attempt to find the start bit
+		while ( samples < MAX_SAMPLES )
+		{
+			// Delay first
+			_delay_us( 1 );
+
+			// If data is valid, increment
+			if ( READ_DATA )
+			{
+				samples++;
+			}
+			// Reset
+			else
+			{
+				samples = 0;
+				failures++;
+
+				// After ~5ms of failures, break the loop
+				// Each failure is approx 5 instructions + 1 usec, or approximately 1.34 usec)
+				// So ~3731 failures for ~5ms
+				// Being exact doesn't matter, as this is just to let the other parts of the
+				//  controller do some processing
+				if ( failures > MAX_FAILURES )
+					break;
+			}
+		}
+
+		// If 10 valid samples of the start bit were obtained, 
+		if ( samples >= MAX_SAMPLES )
+		{
+			// Clean out the old packet memory
+			incomingPacket[numberOfIncomingPackets] = 0;
+
+			// Read the next 19 bits into memory (bit 0 is the start bit, which is always 0)
+			for ( uint8_t c = 1; c < 20; c++ )
+			{
+				// Wait until the middle of the next bit
+				_delay_us( 105 );
+
+				// Append the current bit value
+				incomingPacket[numberOfIncomingPackets] |= (READ_DATA << c);
+			}
+
+			// Packet finished, increment counter
+			numberOfIncomingPackets++;
+		}
+	}
+
+	// Stop the keyboard input
+	STOP_DATA();
+
+	// Finished receiving data from keyboard, start packet processing
+	for ( uint8_t packet = 0; packet < numberOfIncomingPackets; packet++ )
+		processPacketValue( incomingPacket[packet] );
+
+	return 0;
+}
+
+// Read in the Packet Data, and decide what to do with it
+void processPacketValue( uint16_t packetValue )
+{
+	// = Packet Layout =
+	//
+	// A is the first bit received (bit 0), T is the last
+	//
+	//   |  Modifier?  |  ??   |   Scan Code   |
+	//  A B C D E F G H I J K L M N O P Q R S T
+	//
+	// A      - Start bit
+	//          - Always Low
+	// B -> H - Modifier enabled bits
+	//          - Each bit represents a different modifier "mode"
+	//          - B -> Shift/Lock
+	//          - C -> ??
+	//          - D -> Func
+	//          - E -> ??
+	//          - F -> ??
+	//          - G -> ??
+	//          - H -> ??
+	// I -> L - ?? No idea yet...
+	//          - The bits change for some combinations, but not pattern has been found yet...
+	//          - I -> ??
+	//          - J -> ??
+	//          - K -> ??
+	//          - L -> ??
+	// M -> T - Scan Code
+	//          - Bits are organized from low to high (8 bit value)
+	//          - M -> Bit 1
+	//          - N -> Bit 2
+	//          - O -> Bit 3
+	//          - P -> Bit 4
+	//          - Q -> Bit 5
+	//          - R -> Bit 6
+	//          - S -> Bit 7
+	//          - T -> Bit 8
+
+	// Separate packet into sections
+	uint8_t scanCode  = (packetValue & 0xFF000) << 12;
+	uint8_t modifiers = (packetValue & 0x000FE);
+	uint8_t extra     = (packetValue & 0x00F00) << 8;
+
+	// Debug Info
+	char tmpStr1[3];
+	char tmpStr2[3];
+	char tmpStr3[3];
+	hexToStr_op( scanCode, tmpStr1, 2 );
+	hexToStr_op( modifiers, tmpStr2, 2 );
+	hexToStr_op( extra, tmpStr3, 2 );
+	dbug_dPrint( "Scancode: 0x", tmpStr1, " Modifiers: 0x", tmpStr2, " Extra: 0x", tmpStr3 );
+	dbug_dPrint( "Packet: 0x", tmpStr2, tmpStr3, tmpStr1 );
+
+	// TODO List
+	// - Modifier keys
+	// - Key Release mechanism
+
+	// Compute Modifier keys
+	// TODO
+
+	// Deal with special scan codes
+	switch ( scanCode )
+	{
+	default:
+		//bufferAdd( scanCode ); TODO - Uncomment when ready for USB output
+		break;
+	}
+}
+
+// Send data
+// NOTE: Does nothing with the Univac-Sperry F3W9
+uint8_t scan_sendData( uint8_t dataPayload )
+{
+	return 0;
+}
+
+// Signal KeyIndex_Buffer that it has been properly read
+inline void scan_finishedWithBuffer( void )
+{
+	return;
+}
+
+// Signal that the keys have been properly sent over USB
+// TODO
+inline void scan_finishedWithUSBBuffer( void )
+{
+	/*
+	uint8_t foundModifiers = 0;
+
+	// Look for all of the modifiers present, there is a max of 8 (but only keys for 5 on the HASCI version)
+	for ( uint8_t c = 0; c < KeyIndex_BufferUsed; c++ )
+	{
+		// The modifier range is from 0x80 to 0x8F (well, the last bit is the ON/OFF signal, but whatever...)
+		if ( KeyIndex_Buffer[c] <= 0x8F && KeyIndex_Buffer[c] >= 0x80 )
+		{
+			// Add the modifier back into the the Key Buffer
+			KeyIndex_Buffer[foundModifiers] = KeyIndex_Buffer[c];
+			foundModifiers++;
+		}
+	}
+
+	// Adjust the size of the new Key Buffer
+	KeyIndex_BufferUsed = foundModifiers;
+	*/
+}
+
+// Reset/Hold keyboard
+// NOTE: Does nothing with the Univac-Sperry F3W9
+void scan_lockKeyboard( void )
+{
+}
+
+// NOTE: Does nothing with the Univac-Sperry F3W9
+void scan_unlockKeyboard( void )
+{
+}
+
+// Reset Keyboard
+// - Holds the input read line high to flush the buffer
+// - This does not actually reset the keyboard, but always seems brings it to a sane state
+// - Won't work fully if keys are being pressed done at the same time
+void scan_resetKeyboard( void )
+{
+	// Initiate data request line, but don't read the incoming data
+	REQUEST_DATA();
+
+	// We shouldn't be receiving more than 8 packets (and maybe +1 error signal)
+	// This is around 22 ms of data, so a delay of 50 ms should be sufficient.
+	_delay_ms( 50 );
+
+	// Stop request line
+	STOP_DATA();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Scan/UnivacF3W9/scan_loop.h	Sat Mar 03 21:16:41 2012 -0500
@@ -0,0 +1,66 @@
+/* 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.
+ */
+
+#ifndef __SCAN_LOOP_H
+#define __SCAN_LOOP_H
+
+// ----- Includes -----
+
+// Compiler Includes
+#include <stdint.h>
+
+// Local Includes
+
+
+
+// ----- Defines -----
+
+#define KEYBOARD_SIZE 0x68 // 104 - Size of the array space for the keyboard(max index)
+#define KEYBOARD_BUFFER 24 // Max number of key signals to buffer
+
+
+
+// ----- Variables -----
+
+extern volatile     uint8_t KeyIndex_Buffer[KEYBOARD_BUFFER];
+extern volatile     uint8_t KeyIndex_BufferUsed;
+
+
+
+// ----- Functions -----
+
+// Functions used by main.c
+void scan_setup( void );
+uint8_t scan_loop( void );
+
+
+// Functions available to macro.c
+uint8_t scan_sendData( uint8_t dataPayload );
+
+void scan_finishedWithBuffer( void );
+void scan_finishedWithUSBBuffer( void );
+void scan_lockKeyboard( void );
+void scan_unlockKeyboard( void );
+void scan_resetKeyboard( void );
+
+
+#endif // __SCAN_LOOP_H
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Scan/UnivacF3W9/setup.cmake	Sat Mar 03 21:16:41 2012 -0500
@@ -0,0 +1,46 @@
+###| CMake Kiibohd Controller Scan Module |###
+#
+# Written by Jacob Alexander in 2012 for the Kiibohd Controller
+#
+# Released into the Public Domain
+#
+###
+
+
+###
+# Module C files
+#
+
+set( SCAN_SRCS
+	scan_loop.c
+)
+
+
+###
+# Module H files
+#
+set( SCAN_HDRS
+	scan_loop.h
+)
+
+
+###
+# File Dependency Setup
+#
+ADD_FILE_DEPENDENCIES( scan_loop.c ${SCAN_HDRS} )
+#add_file_dependencies( scan_loop.c ${SCAN_HDRS} )
+#add_file_dependencies( macro.c keymap.h epsonqx10.h )
+
+
+###
+# Module Specific Options
+#
+add_definitions( -I${HEAD_DIR}/Keymap )
+
+#| Keymap Settings
+add_definitions(
+	-DMODIFIER_MASK=univacf3w9_ModifierMask
+	-DKEYINDEX_MASK=univacf3w9_ColemakMap
+	#-DKEYINDEX_MASK=univacf3w9_DefaultMap
+)
+
--- a/USB/pjrc/usb_keyboard_debug.c	Mon Feb 13 14:04:53 2012 -0500
+++ b/USB/pjrc/usb_keyboard_debug.c	Sat Mar 03 21:16:41 2012 -0500
@@ -135,8 +135,8 @@
 };
 
 static const uint8_t PROGMEM debug_hid_report_desc[] = {
-	//0x06, 0x30, 0xFF,			// Usage Page 0xFF31 (vendor defined)
-	0x06, 0x31, 0xFF,			// Usage Page 0xFF31 (vendor defined)
+	0x06, 0x30, 0xFF,			// Usage Page 0xFF31 (vendor defined)
+	//0x06, 0x31, 0xFF,			// Usage Page 0xFF31 (vendor defined)
 	0x09, 0x74,				// Usage 0x74
 	0xA1, 0x53,				// Collection 0x53
 	0x75, 0x08,				// report size = 8 bits
--- a/setup.cmake	Mon Feb 13 14:04:53 2012 -0500
+++ b/setup.cmake	Sat Mar 03 21:16:41 2012 -0500
@@ -1,6 +1,6 @@
 ###| CMAKE Kiibohd Controller Source Configurator |###
 #
-# Written by Jacob Alexander in 2011 for the Kiibohd Controller
+# Written by Jacob Alexander in 2011-2012 for the Kiibohd Controller
 #
 # Released into the Public Domain
 #
@@ -20,7 +20,7 @@
 #| Please the {Scan,Macro,USB,Debug}/module.txt for information on the modules and how to create new ones
 
 ##| Deals with acquiring the keypress information and turning it into a key index
-set(  ScanModule  "BudKeypad" )
+set(  ScanModule  "UnivacF3W9" )
 
 ##| Uses the key index and potentially applies special conditions to it, mapping it to a usb key code
 set( MacroModule  "buffer"  )