nitial commit.
parent
cf3222d4a4
commit
86dcaee84d
|
@ -1,299 +1,254 @@
|
|||
#define IIKEYB_D0 4
|
||||
#define IIKEYB_D1 5
|
||||
#define IIKEYB_D2 6
|
||||
#define IIKEYB_D3 7
|
||||
#define IIKEYB_D4 8
|
||||
#define IIKEYB_D5 9
|
||||
#define IIKEYB_D6 10
|
||||
#include "II_Encoder.h"
|
||||
#include <hidboot.h>
|
||||
#include <usbhub.h>
|
||||
// Satisfy the IDE, which needs to see the include statment in the ino too.
|
||||
#ifdef dobogusinclude
|
||||
#include <spi4teensy3.h>
|
||||
#endif
|
||||
#include <SPI.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include "layoutmemory.h"
|
||||
#include "backlog.h"
|
||||
|
||||
#define IIKEYB_RESET 11
|
||||
#define IIKEYB_STRB 12
|
||||
const char string_0[] PROGMEM = " .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------. ";
|
||||
const char string_1[] PROGMEM = "| .--------------. || .--------------. || .--------------. || .--------------. || .--------------. | | .--------------. || .--------------. |";
|
||||
const char string_2[] PROGMEM = "| | __ | || | ______ | || | ______ | || | _____ | || | _________ | | | | _____ | || | _____ | |";
|
||||
const char string_3[] PROGMEM = "| | / \\ | || | |_ __ \\ | || | |_ __ \\ | || | |_ _| | || | |_ ___ | | | | | |_ _| | || | |_ _| | |";
|
||||
const char string_4[] PROGMEM = "| | / /\\ \\ | || | | |__) | | || | | |__) | | || | | | | || | | |_ \\_| | | | | | | | || | | | | |";
|
||||
const char string_5[] PROGMEM = "| | / ____ \\ | || | | ___/ | || | | ___/ | || | | | _ | || | | _| _ | | | | | | | || | | | | |";
|
||||
const char string_6[] PROGMEM = "| | _/ / \\ \\_ | || | _| |_ | || | _| |_ | || | _| |__/ | | || | _| |___/ | | | | | _| |_ | || | _| |_ | |";
|
||||
const char string_7[] PROGMEM = "| ||____| |____|| || | |_____| | || | |_____| | || | |________| | || | |_________| | | | | |_____| | || | |_____| | |";
|
||||
const char string_8[] PROGMEM = "| | | || | | || | | || | | || | | | | | | || | | |";
|
||||
const char string_9[] PROGMEM = "| '--------------' || '--------------' || '--------------' || '--------------' || '--------------' | | '--------------' || '--------------' |";
|
||||
const char string_A[] PROGMEM = "'----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------' ";
|
||||
|
||||
void setupIO()
|
||||
const char *const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5, string_6, string_7, string_8, string_9, string_A};
|
||||
char buffer[145]; // make sure this is large enough for the largest string it must hold
|
||||
|
||||
II_Encoder KeyEncoder;
|
||||
KeyLayout CurrLayout;
|
||||
Backlog StringBackLog;
|
||||
|
||||
class KbdRptParser : public KeyboardReportParser
|
||||
{ void PrintKey(uint8_t mod, uint8_t key);
|
||||
|
||||
protected:
|
||||
void OnControlKeysChanged(uint8_t before, uint8_t after);
|
||||
|
||||
void OnKeyDown (uint8_t mod, uint8_t key);
|
||||
void OnKeyUp (uint8_t mod, uint8_t key);
|
||||
void OnKeyPressed(uint8_t key);
|
||||
|
||||
public:
|
||||
bool bDebugPrint;
|
||||
};
|
||||
|
||||
void KbdRptParser::PrintKey(uint8_t m, uint8_t key)
|
||||
{
|
||||
pinMode(IIKEYB_D0, OUTPUT);
|
||||
pinMode(IIKEYB_D1, OUTPUT);
|
||||
pinMode(IIKEYB_D2, OUTPUT);
|
||||
pinMode(IIKEYB_D3, OUTPUT);
|
||||
pinMode(IIKEYB_D4, OUTPUT);
|
||||
pinMode(IIKEYB_D5, OUTPUT);
|
||||
pinMode(IIKEYB_D6, OUTPUT);
|
||||
|
||||
pinMode(IIKEYB_RESET, INPUT_PULLUP);
|
||||
pinMode(IIKEYB_STRB, OUTPUT);
|
||||
|
||||
|
||||
digitalWrite(IIKEYB_D0, LOW);
|
||||
digitalWrite(IIKEYB_D1, LOW);
|
||||
digitalWrite(IIKEYB_D2, LOW);
|
||||
digitalWrite(IIKEYB_D3, LOW);
|
||||
digitalWrite(IIKEYB_D4, LOW);
|
||||
digitalWrite(IIKEYB_D5, LOW);
|
||||
digitalWrite(IIKEYB_D6, LOW);
|
||||
|
||||
digitalWrite(IIKEYB_RESET, HIGH);
|
||||
digitalWrite(IIKEYB_STRB, HIGH);
|
||||
|
||||
}
|
||||
|
||||
void II_Reset(void)
|
||||
{
|
||||
pinMode(IIKEYB_RESET, OUTPUT);
|
||||
pinMode(IIKEYB_RESET, LOW);
|
||||
delay(10);
|
||||
pinMode(IIKEYB_RESET, INPUT_PULLUP);
|
||||
digitalWrite(IIKEYB_RESET, HIGH);
|
||||
|
||||
}
|
||||
|
||||
int II_putchar(int bOutput)
|
||||
{
|
||||
if (10 == bOutput)
|
||||
bOutput = '\r';
|
||||
|
||||
if (0x0D == bOutput)
|
||||
bOutput = '\r';
|
||||
|
||||
|
||||
if (bOutput & 0b00000001)
|
||||
digitalWrite(IIKEYB_D0, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D0, LOW);
|
||||
|
||||
if (bOutput & 0b00000010)
|
||||
digitalWrite(IIKEYB_D1, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D1, LOW);
|
||||
|
||||
if (bOutput & 0b00000100)
|
||||
digitalWrite(IIKEYB_D2, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D2, LOW);
|
||||
|
||||
if (bOutput & 0b00001000)
|
||||
digitalWrite(IIKEYB_D3, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D3, LOW);
|
||||
|
||||
if (bOutput & 0b00010000)
|
||||
digitalWrite(IIKEYB_D4, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D4, LOW);
|
||||
|
||||
if (bOutput & 0b00100000)
|
||||
digitalWrite(IIKEYB_D5, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D5, LOW);
|
||||
|
||||
if (bOutput & 0b01000000)
|
||||
digitalWrite(IIKEYB_D6, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D6, LOW);
|
||||
|
||||
pinMode(IIKEYB_STRB, HIGH);
|
||||
delay(1);
|
||||
pinMode(IIKEYB_STRB, LOW);
|
||||
|
||||
delay(10);
|
||||
return (bOutput);
|
||||
}
|
||||
|
||||
int II_puts(const char *string)
|
||||
{
|
||||
int i = 0;
|
||||
while (string[i]) //standard c idiom for looping through a null-terminated string
|
||||
MODIFIERKEYS mod;
|
||||
*((uint8_t*)&mod) = m;
|
||||
if (bDebugPrint)
|
||||
{
|
||||
if ( II_putchar(string[i]) == EOF) //if we got the EOF value from writing the char
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
i++;
|
||||
Serial.print((mod.bmLeftCtrl == 1) ? "C" : " ");
|
||||
Serial.print((mod.bmLeftShift == 1) ? "S" : " ");
|
||||
Serial.print((mod.bmLeftAlt == 1) ? "A" : " ");
|
||||
Serial.print((mod.bmLeftGUI == 1) ? "G" : " ");
|
||||
|
||||
Serial.print(" >");
|
||||
PrintHex<uint8_t>(key, 0x80);
|
||||
Serial.print("< ");
|
||||
|
||||
Serial.print((mod.bmRightCtrl == 1) ? "C" : " ");
|
||||
Serial.print((mod.bmRightShift == 1) ? "S" : " ");
|
||||
Serial.print((mod.bmRightAlt == 1) ? "A" : " ");
|
||||
Serial.println((mod.bmRightGUI == 1) ? "G" : " ");
|
||||
}
|
||||
};
|
||||
|
||||
void KbdRptParser::OnKeyDown(uint8_t mod, uint8_t key)
|
||||
{
|
||||
//Serial.print("DN ");
|
||||
//PrintKey(mod, key);
|
||||
uint8_t c = OemToAscii(mod, key);
|
||||
if (bDebugPrint)
|
||||
{
|
||||
Serial.print("MOD: ");
|
||||
Serial.print(mod, HEX);
|
||||
Serial.print(" KEY: ");
|
||||
Serial.println(key, HEX);
|
||||
}
|
||||
|
||||
if (II_putchar('\r') == EOF) //this will occur right after we quit due to the null terminated character.
|
||||
if (0x52 == key) //Arrow UP
|
||||
{
|
||||
return EOF;
|
||||
StringBackLog.OneBack();
|
||||
}
|
||||
else if (0x51 == key) //Arrow DOWN
|
||||
{
|
||||
StringBackLog.OneForeward();
|
||||
}
|
||||
else if (c)
|
||||
{
|
||||
OnKeyPressed(c);
|
||||
}
|
||||
return 1; //to meet spec.
|
||||
}
|
||||
|
||||
char *convert(unsigned int num, int base)
|
||||
void KbdRptParser::OnControlKeysChanged(uint8_t before, uint8_t after)
|
||||
{
|
||||
static char Representation[] = "0123456789ABCDEF";
|
||||
static char buffer[50];
|
||||
char *ptr;
|
||||
|
||||
ptr = &buffer[49];
|
||||
*ptr = '\0';
|
||||
MODIFIERKEYS beforeMod;
|
||||
*((uint8_t*)&beforeMod) = before;
|
||||
|
||||
do
|
||||
{
|
||||
*--ptr = Representation[num % base];
|
||||
num /= base;
|
||||
} while (num != 0);
|
||||
MODIFIERKEYS afterMod;
|
||||
*((uint8_t*)&afterMod) = after;
|
||||
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
void II_printf(char* format, ...)
|
||||
{
|
||||
char *traverse;
|
||||
unsigned int i;
|
||||
char *s;
|
||||
|
||||
//Module 1: Initializing Myprintf's arguments
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
|
||||
for (traverse = format; *traverse != '\0'; traverse++)
|
||||
{
|
||||
while ( *traverse != '%' )
|
||||
{
|
||||
II_putchar(*traverse);
|
||||
traverse++;
|
||||
}
|
||||
|
||||
traverse++;
|
||||
|
||||
//Module 2: Fetching and executing arguments
|
||||
switch (*traverse)
|
||||
{
|
||||
case 'c' : i = va_arg(arg, int); //Fetch char argument
|
||||
II_putchar(i);
|
||||
break;
|
||||
|
||||
case 'd' : i = va_arg(arg, int); //Fetch Decimal/Integer argument
|
||||
if (i < 0)
|
||||
{
|
||||
i = -i;
|
||||
II_putchar('-');
|
||||
}
|
||||
II_puts(convert(i, 10));
|
||||
break;
|
||||
|
||||
case 'o': i = va_arg(arg, unsigned int); //Fetch Octal representation
|
||||
II_puts(convert(i, 8));
|
||||
break;
|
||||
|
||||
case 's': s = va_arg(arg, char *); //Fetch string
|
||||
II_puts(s);
|
||||
break;
|
||||
|
||||
case 'x': i = va_arg(arg, unsigned int); //Fetch Hexadecimal representation
|
||||
II_puts(convert(i, 16));
|
||||
break;
|
||||
}
|
||||
if (beforeMod.bmLeftCtrl != afterMod.bmLeftCtrl) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("LeftCtrl changed");
|
||||
}
|
||||
if (beforeMod.bmLeftShift != afterMod.bmLeftShift) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("LeftShift changed");
|
||||
}
|
||||
if (beforeMod.bmLeftAlt != afterMod.bmLeftAlt) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("LeftAlt changed");
|
||||
}
|
||||
if (beforeMod.bmLeftGUI != afterMod.bmLeftGUI) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("LeftGUI changed");
|
||||
}
|
||||
|
||||
if (beforeMod.bmRightCtrl != afterMod.bmRightCtrl) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("RightCtrl changed");
|
||||
}
|
||||
if (beforeMod.bmRightShift != afterMod.bmRightShift) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("RightShift changed");
|
||||
}
|
||||
if (beforeMod.bmRightAlt != afterMod.bmRightAlt) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("RightAlt changed");
|
||||
}
|
||||
if (beforeMod.bmRightGUI != afterMod.bmRightGUI) {
|
||||
if (bDebugPrint)
|
||||
Serial.println("RightGUI changed");
|
||||
}
|
||||
|
||||
//Module 3: Closing argument list to necessary clean-up
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
void KbdRptParser::OnKeyUp(uint8_t mod, uint8_t key)
|
||||
{
|
||||
//Serial.print("UP ");
|
||||
//PrintKey(mod, key);
|
||||
}
|
||||
|
||||
void KbdRptParser::OnKeyPressed(uint8_t key)
|
||||
{
|
||||
if (bDebugPrint)
|
||||
{
|
||||
Serial.print("ASCII: ");
|
||||
Serial.print((char)key);
|
||||
Serial.print(" ");
|
||||
Serial.println((char)key, HEX);
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBackLog.addchar((char)key);
|
||||
|
||||
if (0x0D == key)
|
||||
Serial.println();
|
||||
else
|
||||
Serial.print((char)key);
|
||||
}
|
||||
|
||||
if (0x11 == key)
|
||||
{
|
||||
if (bDebugPrint)
|
||||
Serial.print("Reset");
|
||||
KeyEncoder.Reset();
|
||||
}
|
||||
else if (0x12 == key)
|
||||
{
|
||||
CurrLayout.Toggle();
|
||||
SetLayout(CurrLayout.Get());
|
||||
}
|
||||
else
|
||||
KeyEncoder.IIputchar((char)key);
|
||||
};
|
||||
|
||||
USB Usb;
|
||||
//USBHub Hub(&Usb);
|
||||
HIDBoot<USB_HID_PROTOCOL_KEYBOARD> HidKeyboard(&Usb);
|
||||
|
||||
KbdRptParser Prs;
|
||||
|
||||
/*! \brief Wrapper for callback use.
|
||||
|
||||
*/
|
||||
int IIputsWrapper(const char *string)
|
||||
{
|
||||
KeyEncoder.IIputchar(string);
|
||||
}
|
||||
|
||||
/*! \brief Print a welcome message
|
||||
|
||||
Prints some nice ASCII art through the arduino terminal as a welcome.
|
||||
*/
|
||||
void print_welcome_msg(void)
|
||||
{
|
||||
Serial.println("");
|
||||
Serial.println("Welcome to:");
|
||||
Serial.println("");
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
strcpy_P(buffer, (char *)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
|
||||
Serial.println(buffer);
|
||||
}
|
||||
|
||||
Serial.println("");
|
||||
Serial.println("USB-Keyboard interface.");
|
||||
Serial.println("");
|
||||
};
|
||||
|
||||
/*! \brief The Arduino setup functiopn.
|
||||
|
||||
Called once at startup.
|
||||
*/
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
setupIO();
|
||||
Serial.println("Apple II Keyboard started");
|
||||
Prs.bDebugPrint = false;
|
||||
|
||||
II_puts(" ");
|
||||
Serial.begin( 115200 );
|
||||
#if !defined(__MIPSEL__)
|
||||
while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
|
||||
#endif
|
||||
print_welcome_msg();
|
||||
|
||||
while (Serial.available() == 0) {}
|
||||
CurrLayout.Init();
|
||||
|
||||
if (Usb.Init() == -1)
|
||||
Serial.println("OSC did not start.c");
|
||||
|
||||
delay( 200 );
|
||||
|
||||
HidKeyboard.SetReportParser(0, &Prs);
|
||||
|
||||
KeyEncoder.begin();
|
||||
//KeyEncoder.IIputs(" ");
|
||||
|
||||
Prs.SetLayout(CurrLayout.Get());
|
||||
|
||||
StringBackLog.SetPuts(&IIputsWrapper);
|
||||
|
||||
//II_monitor();
|
||||
}
|
||||
|
||||
char* monitorcode[40];
|
||||
|
||||
void II_monitor(void)
|
||||
{
|
||||
II_puts("call -151");
|
||||
delay(500);
|
||||
|
||||
monitorcode[0] = "0: 00 0A 00 40 00 00 00 00";
|
||||
monitorcode[1] = "8: 00 00 00 00 00 00 00 00";
|
||||
monitorcode[2] = "800: A9 00 85 07 A9 00 A8 AA";
|
||||
monitorcode[3] = "808: 85 06 A5 00 85 04 A5 01";
|
||||
monitorcode[4] = "810: 85 05 C0 04 D0 04 A5 04";
|
||||
monitorcode[5] = "818: 85 06 C0 05 D0 04 A5 05";
|
||||
monitorcode[6] = "820: 85 06 A5 06 81 04 A1 04";
|
||||
monitorcode[7] = "828: C5 06 D0 2E E6 04 D0 02";
|
||||
monitorcode[8] = "830: E6 05 A5 02 C5 04 D0 04";
|
||||
monitorcode[9] = "838: A5 03 C5 05 D0 D4 A5 00";
|
||||
monitorcode[10] = "840: 85 04 A5 01 85 05 C0 04";
|
||||
monitorcode[11] = "848: D0 04 A5 04 85 06 C0 05";
|
||||
monitorcode[12] = "850: D0 04 A5 05 85 06 A1 04";
|
||||
monitorcode[13] = "858: C5 06 D0 69 E6 04 D0 02";
|
||||
monitorcode[14] = "860: E6 05 A5 02 C5 04 D0 04";
|
||||
monitorcode[15] = "868: A5 03 C5 05 D0 D8 C0 00";
|
||||
monitorcode[16] = "870: D0 08 A9 FF 85 06 C8 4C";
|
||||
monitorcode[17] = "878: 0A 08 C0 01 D0 04 A9 01";
|
||||
monitorcode[18] = "880: D0 F2 C0 02 D0 08 06 06";
|
||||
monitorcode[19] = "888: 90 ED A9 7F D0 E6 C0 03";
|
||||
monitorcode[20] = "890: D0 08 38 66 06 B0 E0 C8";
|
||||
monitorcode[21] = "898: D0 DD C0 04 F0 F9 A9 50";
|
||||
monitorcode[22] = "8A0: 20 EC 08 A9 41 20 EC 08";
|
||||
monitorcode[23] = "8A8: A9 53 20 EC 08 A9 53 20";
|
||||
monitorcode[24] = "8B0: EC 08 20 1E 09 E6 07 A5";
|
||||
monitorcode[25] = "8B8: 07 20 F2 08 20 13 09 EA";
|
||||
monitorcode[26] = "8C0: EA EA 4C 04 08 48 98 20";
|
||||
monitorcode[27] = "8C8: F2 08 20 1E 09 A5 05 20";
|
||||
monitorcode[28] = "8D0: F2 08 A5 04 20 F2 08 20";
|
||||
monitorcode[29] = "8D8: 1E 09 A5 06 20 F2 08 20";
|
||||
monitorcode[30] = "8E0: 1E 09 68 20 F2 08 20 13";
|
||||
monitorcode[31] = "8E8: 09 00 EA EA 09 80 20 F0";
|
||||
monitorcode[32] = "8F0: FD 60 48 4A 4A 4A 4A 29";
|
||||
monitorcode[33] = "8F8: 0F 09 30 C9 3A 90 02 69";
|
||||
monitorcode[34] = "900: 06 20 EC 08 68 29 0F 09";
|
||||
monitorcode[35] = "908: 30 C9 3A 90 02 69 06 20";
|
||||
monitorcode[36] = "910: EC 08 60 A9 0D 20 EC 08";
|
||||
monitorcode[37] = "918: A9 0A 20 EC 08 60 A9 20";
|
||||
monitorcode[38] = "920: 20 EC 08 60";
|
||||
//monitorcode[39] = "0: 00 E0 00 F0"; //Setup E000 to EFFF
|
||||
monitorcode[39] = "0: 00 40 00 40"; //Setup 4000 to 7FFF
|
||||
|
||||
for (int i = 0; i < 40; i++)
|
||||
{
|
||||
II_puts(monitorcode[i]);
|
||||
delay(50);
|
||||
}
|
||||
}
|
||||
/*! \brief The Arduino mainloop.
|
||||
|
||||
Only the USB Task is polled here.
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
int incomingByte = 0;
|
||||
int II_Byte = 0;
|
||||
|
||||
while (Serial.available() == 0) {}
|
||||
incomingByte = Serial.read();
|
||||
|
||||
II_Byte = incomingByte;
|
||||
|
||||
if (10 == incomingByte)
|
||||
II_Byte = '\r';
|
||||
|
||||
if (0x0D == incomingByte)
|
||||
II_Byte = '\r';
|
||||
|
||||
if (28 == incomingByte)
|
||||
II_Byte = 0x08;
|
||||
|
||||
if (29 == incomingByte)
|
||||
II_Byte = 0x15;
|
||||
|
||||
#if 0
|
||||
Serial.print("Received Value: 0x");
|
||||
Serial.print(incomingByte, HEX);
|
||||
Serial.print(" Wich shows as '");
|
||||
Serial.write(incomingByte);
|
||||
Serial.print("'. Sent as: 0x");
|
||||
Serial.print(II_Byte, HEX);
|
||||
Serial.println("' to Apple II");
|
||||
#endif
|
||||
Serial.write(II_Byte);
|
||||
|
||||
II_putchar(II_Byte);
|
||||
|
||||
Usb.Task();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
/*! \file II_Encoder.cpp
|
||||
* \brief Output ASCII in parallel form to Apple II keyboard connector.
|
||||
*
|
||||
* Takes a ASCII character or string and sets the IO Pins accordingly for APPLE II keayboard Input.
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "II_Encoder.h"
|
||||
|
||||
void II_Encoder::begin(void)
|
||||
{
|
||||
pinMode(IIKEYB_D0, OUTPUT);
|
||||
pinMode(IIKEYB_D1, OUTPUT);
|
||||
pinMode(IIKEYB_D2, OUTPUT);
|
||||
pinMode(IIKEYB_D3, OUTPUT);
|
||||
pinMode(IIKEYB_D4, OUTPUT);
|
||||
pinMode(IIKEYB_D5, OUTPUT);
|
||||
pinMode(IIKEYB_D6, OUTPUT);
|
||||
|
||||
pinMode(IIKEYB_RESET, INPUT_PULLUP);
|
||||
pinMode(IIKEYB_STRB, OUTPUT);
|
||||
|
||||
digitalWrite(IIKEYB_D0, LOW);
|
||||
digitalWrite(IIKEYB_D1, LOW);
|
||||
digitalWrite(IIKEYB_D2, LOW);
|
||||
digitalWrite(IIKEYB_D3, LOW);
|
||||
digitalWrite(IIKEYB_D4, LOW);
|
||||
digitalWrite(IIKEYB_D5, LOW);
|
||||
digitalWrite(IIKEYB_D6, LOW);
|
||||
|
||||
digitalWrite(IIKEYB_RESET, HIGH);
|
||||
digitalWrite(IIKEYB_STRB, HIGH);
|
||||
|
||||
}
|
||||
|
||||
void II_Encoder::Reset(void)
|
||||
{
|
||||
pinMode(IIKEYB_RESET, OUTPUT);
|
||||
digitalWrite(IIKEYB_RESET, LOW);
|
||||
delay(10);
|
||||
pinMode(IIKEYB_RESET, INPUT_PULLUP);
|
||||
digitalWrite(IIKEYB_RESET, HIGH);
|
||||
|
||||
}
|
||||
|
||||
int II_Encoder::IIputchar(int bOutput)
|
||||
{
|
||||
if (bOutput & 0b00000001)
|
||||
digitalWrite(IIKEYB_D0, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D0, LOW);
|
||||
|
||||
if (bOutput & 0b00000010)
|
||||
digitalWrite(IIKEYB_D1, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D1, LOW);
|
||||
|
||||
if (bOutput & 0b00000100)
|
||||
digitalWrite(IIKEYB_D2, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D2, LOW);
|
||||
|
||||
if (bOutput & 0b00001000)
|
||||
digitalWrite(IIKEYB_D3, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D3, LOW);
|
||||
|
||||
if (bOutput & 0b00010000)
|
||||
digitalWrite(IIKEYB_D4, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D4, LOW);
|
||||
|
||||
if (bOutput & 0b00100000)
|
||||
digitalWrite(IIKEYB_D5, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D5, LOW);
|
||||
|
||||
if (bOutput & 0b01000000)
|
||||
digitalWrite(IIKEYB_D6, HIGH);
|
||||
else
|
||||
digitalWrite(IIKEYB_D6, LOW);
|
||||
|
||||
pinMode(IIKEYB_STRB, HIGH);
|
||||
delay(1);
|
||||
pinMode(IIKEYB_STRB, LOW);
|
||||
|
||||
delay(10);
|
||||
return (bOutput);
|
||||
}
|
||||
|
||||
int II_Encoder::IIputs(const char *string)
|
||||
{
|
||||
int i = 0;
|
||||
while (string[i]) //standard c idiom for looping through a null-terminated string
|
||||
{
|
||||
if (IIputchar(string[i]) == EOF) //if we got the EOF value from writing the char
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (IIputchar('\r') == EOF) //this will occur right after we quit due to the null terminated character.
|
||||
{
|
||||
return EOF;
|
||||
}
|
||||
return 1; //to meet spec.
|
||||
}
|
||||
|
||||
char *II_Encoder::convert(unsigned int num, const int base, char *ptr)
|
||||
{
|
||||
static char Representation[] = "0123456789ABCDEF";
|
||||
*ptr = '\0';
|
||||
|
||||
do
|
||||
{
|
||||
*--ptr = Representation[num % base];
|
||||
num /= base;
|
||||
} while (num != 0);
|
||||
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
void II_Encoder::IIprintf(char* format, ...)
|
||||
{
|
||||
char *traverse;
|
||||
unsigned int i;
|
||||
char *s;
|
||||
char pBuffer[25];
|
||||
|
||||
//Module 1: Initializing Myprintf's arguments
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
|
||||
for (traverse = format; *traverse != '\0'; traverse++)
|
||||
{
|
||||
while ( *traverse != '%' )
|
||||
{
|
||||
IIputchar(*traverse);
|
||||
traverse++;
|
||||
}
|
||||
|
||||
traverse++;
|
||||
|
||||
//Module 2: Fetching and executing arguments
|
||||
switch (*traverse)
|
||||
{
|
||||
case 'c' : i = va_arg(arg, int); //Fetch char argument
|
||||
IIputchar(i);
|
||||
break;
|
||||
|
||||
case 'd' : i = va_arg(arg, int); //Fetch Decimal/Integer argument
|
||||
if (i < 0)
|
||||
{
|
||||
i = -i;
|
||||
IIputchar('-');
|
||||
}
|
||||
IIputs(convert(i, 10, pBuffer));
|
||||
break;
|
||||
|
||||
case 'o': i = va_arg(arg, unsigned int); //Fetch Octal representation
|
||||
IIputs(convert(i, 8, pBuffer));
|
||||
break;
|
||||
|
||||
case 's': s = va_arg(arg, char *); //Fetch string
|
||||
IIputs(s);
|
||||
break;
|
||||
|
||||
case 'x': i = va_arg(arg, unsigned int); //Fetch Hexadecimal representation
|
||||
|
||||
IIputs(convert(i, 16, pBuffer));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Module 3: Closing argument list to necessary clean-up
|
||||
va_end(arg);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
//Arduino Pin definitioin for Keyboard Interface
|
||||
#define IIKEYB_D0 A2
|
||||
#define IIKEYB_D1 A3
|
||||
#define IIKEYB_D2 A0
|
||||
#define IIKEYB_D3 A1
|
||||
#define IIKEYB_D4 7
|
||||
#define IIKEYB_D5 6
|
||||
#define IIKEYB_D6 8
|
||||
|
||||
#define IIKEYB_RESET 5
|
||||
#define IIKEYB_STRB 4
|
||||
|
||||
|
||||
class II_Encoder
|
||||
{
|
||||
public:
|
||||
void begin(void);
|
||||
void Reset(void);
|
||||
int IIputchar(int bOutput);
|
||||
int IIputs(const char *string);
|
||||
void IIprintf(char* format, ...);
|
||||
|
||||
char *convert(unsigned int num, const int base, char *ptr);
|
||||
};
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
#include "Arduino.h"
|
||||
|
||||
#include "backlog.h"
|
||||
|
||||
/*! \brief Constructor, init everything to zero.
|
||||
|
||||
*/
|
||||
Backlog::Backlog()
|
||||
{
|
||||
pCurrentInputString = NULL;
|
||||
pputs = NULL;
|
||||
BacklogOutputPointer = 0;
|
||||
|
||||
for (int i = 0; i < BACKLOG_STEPS; i++)
|
||||
StringBacklog[i] = NULL;
|
||||
}
|
||||
|
||||
/*! \brief Set the puts callback.
|
||||
|
||||
Set the puts callback function, in our case the output to the II keyb interface.
|
||||
*/
|
||||
void Backlog::SetPuts(int (*pputs_funcp)(const char *string))
|
||||
{
|
||||
pputs = pputs_funcp;
|
||||
}
|
||||
|
||||
/*! \brief Erase the current input on the screen.
|
||||
|
||||
The current typed input is erased with backspaces.
|
||||
*/
|
||||
void Backlog::EraseCurrent(void)
|
||||
{
|
||||
uint16_t bufferlen = strlen(pCurrentInputString);
|
||||
|
||||
for (int i = 0; i < bufferlen; i++)
|
||||
{
|
||||
if (pputs)
|
||||
{
|
||||
pputs(0x08); //Backspace
|
||||
delay(CHAR_OUT_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Output the current string vie puts.
|
||||
|
||||
The current active string ist typed to the screen via puts.
|
||||
*/
|
||||
void Backlog::OutputCurrent(void)
|
||||
{
|
||||
uint16_t bufferlen = strlen(pCurrentInputString);
|
||||
|
||||
for (int i = 0; i < bufferlen; i++)
|
||||
{
|
||||
if (pputs)
|
||||
{
|
||||
pputs(pCurrentInputString[i]);
|
||||
delay(CHAR_OUT_DELAY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Go one string back in the backlog.
|
||||
|
||||
Erases the current input from the screen and goes one back ion the log.
|
||||
*/
|
||||
void Backlog::OneBack(void)
|
||||
{
|
||||
uint8_t uiNewIndex = BacklogOutputPointer;
|
||||
|
||||
ChangeToIndex(uiNewIndex);
|
||||
|
||||
uiNewIndex++;
|
||||
|
||||
if (uiNewIndex > BACKLOG_STEPS - 1)
|
||||
uiNewIndex = BACKLOG_STEPS - 1;
|
||||
|
||||
BacklogOutputPointer = uiNewIndex;
|
||||
}
|
||||
|
||||
/*! \brief Go one string forward in the backlog.
|
||||
|
||||
Erases the current input from the screen and goes one foreward ion the log.
|
||||
*/
|
||||
void Backlog::OneForeward(void)
|
||||
{
|
||||
uint8_t uiNewIndex = BacklogOutputPointer;
|
||||
|
||||
if (uiNewIndex)
|
||||
uiNewIndex--;
|
||||
|
||||
ChangeToIndex(uiNewIndex);
|
||||
|
||||
BacklogOutputPointer = uiNewIndex;
|
||||
}
|
||||
|
||||
/*! \brief Change the screen to a specific index from the backlog.
|
||||
|
||||
Changes the active display to a specific string from the backlog.
|
||||
*/
|
||||
void Backlog::ChangeToIndex(uint8_t uiNewIndex)
|
||||
{
|
||||
EraseCurrent();
|
||||
delete pCurrentInputString;
|
||||
if (StringBacklog[uiNewIndex])
|
||||
{
|
||||
pCurrentInputString = new char[BUFFER_STEPS + (BUFFER_STEPS * (strlen(StringBacklog[uiNewIndex]) / BUFFER_STEPS)) ];
|
||||
strcpy(pCurrentInputString, StringBacklog[uiNewIndex]);
|
||||
OutputCurrent();
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Stores the current string in the backlog.
|
||||
|
||||
The current string is stored in the backlog and the log is advanced one step.
|
||||
*/
|
||||
void Backlog::BacklogCurrString(void)
|
||||
{
|
||||
BacklogOutputPointer = 0;
|
||||
|
||||
if (StringBacklog[BACKLOG_STEPS - 1])
|
||||
delete StringBacklog[BACKLOG_STEPS - 1];
|
||||
|
||||
for (int i = BACKLOG_STEPS - 1; i > 0; i--)
|
||||
{
|
||||
StringBacklog[i] = StringBacklog[i - 1];
|
||||
}
|
||||
|
||||
StringBacklog[0] = pCurrentInputString;
|
||||
pCurrentInputString = NULL;
|
||||
#if 0
|
||||
Serial.println("Current Backlog:");
|
||||
for (int i = 0; i < BACKLOG_STEPS; i++)
|
||||
{
|
||||
if (StringBacklog[i])
|
||||
Serial.println(StringBacklog[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! \brief If the current typed string exceeds BUFFER_STEPS the buffer is increased.
|
||||
*
|
||||
If the current string gets bigger than BUFFER_STEPS another BUFFER_STEPS is added.
|
||||
*/
|
||||
void Backlog::IncreaseBuffer(void)
|
||||
{
|
||||
if (NULL == pCurrentInputString)
|
||||
{
|
||||
pCurrentInputString = new char[BUFFER_STEPS];
|
||||
memset(pCurrentInputString, 0, BUFFER_STEPS);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t bufferlen = strlen(pCurrentInputString);
|
||||
if (((bufferlen % BUFFER_STEPS) == (BUFFER_STEPS - 2)) && (bufferlen > 0))
|
||||
{
|
||||
char *pnewCurrentInputString = new char[bufferlen + BUFFER_STEPS];
|
||||
memcpy(pnewCurrentInputString, pCurrentInputString, bufferlen + 1);
|
||||
delete [] pCurrentInputString;
|
||||
pCurrentInputString = pnewCurrentInputString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Add one typed char to the current input string.
|
||||
*
|
||||
On char is added, or if 0x0d is received, the string is stored and the backlog advanced.
|
||||
*/
|
||||
void Backlog::addchar(char c)
|
||||
{
|
||||
|
||||
IncreaseBuffer();
|
||||
|
||||
if (0x0d == c) // Finished
|
||||
{
|
||||
BacklogCurrString();
|
||||
}
|
||||
else if (0x08 == c) // Backspace)
|
||||
{
|
||||
uint16_t bufferlen = strlen(pCurrentInputString);
|
||||
if (bufferlen)
|
||||
pCurrentInputString[bufferlen - 1] = 0x00;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint16_t bufferlen = strlen(pCurrentInputString);
|
||||
|
||||
pCurrentInputString[bufferlen] = c;
|
||||
pCurrentInputString[bufferlen + 1] = 0x00;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*! \file backlog.h
|
||||
* \brief Provides BASH like command backlog.
|
||||
*
|
||||
* With the Arrow Up / Down keys the last commands can be recalled and used.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define BUFFER_STEPS 40
|
||||
#define BACKLOG_STEPS 10
|
||||
#define CHAR_OUT_DELAY 10
|
||||
|
||||
class Backlog
|
||||
{
|
||||
private:
|
||||
uint8_t BacklogOutputPointer;
|
||||
|
||||
char* StringBacklog[BACKLOG_STEPS];
|
||||
char* pCurrentInputString;
|
||||
void IncreaseBuffer(void);
|
||||
void BacklogCurrString(void);
|
||||
|
||||
int (*pputs)(const char *string);
|
||||
|
||||
void EraseCurrent(void);
|
||||
void OutputCurrent(void);
|
||||
|
||||
void ChangeToIndex(uint8_t uiNewIndex);
|
||||
|
||||
public:
|
||||
Backlog();
|
||||
void addchar(char c);
|
||||
void SetPuts(int (*pputs_funcp)(const char *string));
|
||||
void OneBack(void);
|
||||
void OneForeward(void);
|
||||
};
|
|
@ -0,0 +1,96 @@
|
|||
#include "Arduino.h"
|
||||
#include <EEPROM.h>
|
||||
#include "layoutmemory.h"
|
||||
|
||||
#define MAX_KEYB_LAYOUT_ID 1
|
||||
|
||||
/*! \brief Only init variables
|
||||
|
||||
*/
|
||||
KeyLayout::KeyLayout()
|
||||
{
|
||||
uiCurrentKeyboardLayout = 0xFF;
|
||||
}
|
||||
|
||||
/*! \brief Init function, not to be called from constructor.
|
||||
|
||||
Restores settings from eeprom.
|
||||
*/
|
||||
void KeyLayout::Init(void)
|
||||
{
|
||||
Restore();
|
||||
}
|
||||
|
||||
/*! \brief Print current selected layout namew.
|
||||
|
||||
*/
|
||||
void KeyLayout::Print(void)
|
||||
{
|
||||
Serial.print("Keyboard Layout is: ");
|
||||
|
||||
switch (uiCurrentKeyboardLayout)
|
||||
{
|
||||
case 0:
|
||||
Serial.println("US");
|
||||
break;
|
||||
case 1:
|
||||
Serial.println("DE");
|
||||
break;
|
||||
default:
|
||||
Serial.println(uiCurrentKeyboardLayout, HEX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Stores current active layout to eeprom.
|
||||
|
||||
*/
|
||||
void KeyLayout::Store(void)
|
||||
{
|
||||
EEPROM.write(0, uiCurrentKeyboardLayout);
|
||||
}
|
||||
|
||||
/*! \brief Restores active layout from eeprom.
|
||||
|
||||
*/
|
||||
void KeyLayout::Restore(void)
|
||||
{
|
||||
Set(EEPROM.read(0));
|
||||
}
|
||||
|
||||
/*! \brief Select new layout.
|
||||
|
||||
Switch to the next layout and back to 0 if the MAX_KEYB_LAYOUT_ID is reached.
|
||||
*/
|
||||
void KeyLayout::Toggle(void)
|
||||
{
|
||||
Set(uiCurrentKeyboardLayout + 1);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Set the active layout direct..
|
||||
|
||||
Sets the active layout and thecks the range.
|
||||
*/
|
||||
void KeyLayout::Set(uint8_t uiLayoutID)
|
||||
{
|
||||
if (uiLayoutID > MAX_KEYB_LAYOUT_ID)
|
||||
uiLayoutID = 0;
|
||||
|
||||
if (uiCurrentKeyboardLayout != uiLayoutID)
|
||||
{
|
||||
uiCurrentKeyboardLayout = uiLayoutID;
|
||||
Store();
|
||||
Print();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Returns the current active layout.
|
||||
|
||||
*/
|
||||
uint8_t KeyLayout::Get(void)
|
||||
{
|
||||
return uiCurrentKeyboardLayout;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*! \file layoutmemory.h
|
||||
* \brief Handles selection of multiple keyboard layout.
|
||||
*
|
||||
* Toggles the keyboard layout WIN+SPace as a trigger e.g. and stores the current layout in eeprom.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
class KeyLayout
|
||||
{
|
||||
public:
|
||||
KeyLayout();
|
||||
void Init(void);
|
||||
void Restore(void);
|
||||
void Store(void);
|
||||
|
||||
void Print(void);
|
||||
|
||||
void Toggle(void);
|
||||
void Set(uint8_t uiLayoutID);
|
||||
uint8_t Get(void);
|
||||
|
||||
private:
|
||||
uint8_t uiCurrentKeyboardLayout;//ID of the current active keyboard Layout
|
||||
|
||||
};
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,624 @@
|
|||
/* Copyright (C) 2012 Kristian Lauszus, TKJ Electronics. All rights reserved.
|
||||
|
||||
This software may be distributed and modified under the terms of the GNU
|
||||
General Public License version 2 (GPL2) as published by the Free Software
|
||||
Foundation and appearing in the file GPL2.TXT included in the packaging of
|
||||
this file. Please note that GPL2 Section 2[b] requires that all works based
|
||||
on this software must also be made publicly available under the terms of
|
||||
the GPL2 ("Copyleft").
|
||||
|
||||
Contact information
|
||||
-------------------
|
||||
|
||||
Kristian Lauszus, TKJ Electronics
|
||||
Web : http://www.tkjelectronics.com
|
||||
e-mail : kristianl@tkjelectronics.com
|
||||
*/
|
||||
|
||||
#ifndef _btd_h_
|
||||
#define _btd_h_
|
||||
|
||||
#include "Usb.h"
|
||||
#include "usbhid.h"
|
||||
|
||||
//PID and VID of the Sony PS3 devices
|
||||
#define PS3_VID 0x054C // Sony Corporation
|
||||
#define PS3_PID 0x0268 // PS3 Controller DualShock 3
|
||||
#define PS3NAVIGATION_PID 0x042F // Navigation controller
|
||||
#define PS3MOVE_PID 0x03D5 // Motion controller
|
||||
|
||||
// These dongles do not present themselves correctly, so we have to check for them manually
|
||||
#define IOGEAR_GBU521_VID 0x0A5C
|
||||
#define IOGEAR_GBU521_PID 0x21E8
|
||||
#define BELKIN_F8T065BF_VID 0x050D
|
||||
#define BELKIN_F8T065BF_PID 0x065A
|
||||
|
||||
/* Bluetooth dongle data taken from descriptors */
|
||||
#define BULK_MAXPKTSIZE 64 // Max size for ACL data
|
||||
|
||||
// Used in control endpoint header for HCI Commands
|
||||
#define bmREQ_HCI_OUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_DEVICE
|
||||
|
||||
/* Bluetooth HCI states for hci_task() */
|
||||
#define HCI_INIT_STATE 0
|
||||
#define HCI_RESET_STATE 1
|
||||
#define HCI_CLASS_STATE 2
|
||||
#define HCI_BDADDR_STATE 3
|
||||
#define HCI_LOCAL_VERSION_STATE 4
|
||||
#define HCI_SET_NAME_STATE 5
|
||||
#define HCI_CHECK_DEVICE_SERVICE 6
|
||||
|
||||
#define HCI_INQUIRY_STATE 7 // These three states are only used if it should pair and connect to a device
|
||||
#define HCI_CONNECT_DEVICE_STATE 8
|
||||
#define HCI_CONNECTED_DEVICE_STATE 9
|
||||
|
||||
#define HCI_SCANNING_STATE 10
|
||||
#define HCI_CONNECT_IN_STATE 11
|
||||
#define HCI_REMOTE_NAME_STATE 12
|
||||
#define HCI_CONNECTED_STATE 13
|
||||
#define HCI_DISABLE_SCAN_STATE 14
|
||||
#define HCI_DONE_STATE 15
|
||||
#define HCI_DISCONNECT_STATE 16
|
||||
|
||||
/* HCI event flags*/
|
||||
#define HCI_FLAG_CMD_COMPLETE (1UL << 0)
|
||||
#define HCI_FLAG_CONNECT_COMPLETE (1UL << 1)
|
||||
#define HCI_FLAG_DISCONNECT_COMPLETE (1UL << 2)
|
||||
#define HCI_FLAG_REMOTE_NAME_COMPLETE (1UL << 3)
|
||||
#define HCI_FLAG_INCOMING_REQUEST (1UL << 4)
|
||||
#define HCI_FLAG_READ_BDADDR (1UL << 5)
|
||||
#define HCI_FLAG_READ_VERSION (1UL << 6)
|
||||
#define HCI_FLAG_DEVICE_FOUND (1UL << 7)
|
||||
#define HCI_FLAG_CONNECT_EVENT (1UL << 8)
|
||||
|
||||
/* Macros for HCI event flag tests */
|
||||
#define hci_check_flag(flag) (hci_event_flag & (flag))
|
||||
#define hci_set_flag(flag) (hci_event_flag |= (flag))
|
||||
#define hci_clear_flag(flag) (hci_event_flag &= ~(flag))
|
||||
|
||||
/* HCI Events managed */
|
||||
#define EV_INQUIRY_COMPLETE 0x01
|
||||
#define EV_INQUIRY_RESULT 0x02
|
||||
#define EV_CONNECT_COMPLETE 0x03
|
||||
#define EV_INCOMING_CONNECT 0x04
|
||||
#define EV_DISCONNECT_COMPLETE 0x05
|
||||
#define EV_AUTHENTICATION_COMPLETE 0x06
|
||||
#define EV_REMOTE_NAME_COMPLETE 0x07
|
||||
#define EV_ENCRYPTION_CHANGE 0x08
|
||||
#define EV_CHANGE_CONNECTION_LINK 0x09
|
||||
#define EV_ROLE_CHANGED 0x12
|
||||
#define EV_NUM_COMPLETE_PKT 0x13
|
||||
#define EV_PIN_CODE_REQUEST 0x16
|
||||
#define EV_LINK_KEY_REQUEST 0x17
|
||||
#define EV_LINK_KEY_NOTIFICATION 0x18
|
||||
#define EV_DATA_BUFFER_OVERFLOW 0x1A
|
||||
#define EV_MAX_SLOTS_CHANGE 0x1B
|
||||
#define EV_READ_REMOTE_VERSION_INFORMATION_COMPLETE 0x0C
|
||||
#define EV_QOS_SETUP_COMPLETE 0x0D
|
||||
#define EV_COMMAND_COMPLETE 0x0E
|
||||
#define EV_COMMAND_STATUS 0x0F
|
||||
#define EV_LOOPBACK_COMMAND 0x19
|
||||
#define EV_PAGE_SCAN_REP_MODE 0x20
|
||||
|
||||
/* Bluetooth states for the different Bluetooth drivers */
|
||||
#define L2CAP_WAIT 0
|
||||
#define L2CAP_DONE 1
|
||||
|
||||
/* Used for HID Control channel */
|
||||
#define L2CAP_CONTROL_CONNECT_REQUEST 2
|
||||
#define L2CAP_CONTROL_CONFIG_REQUEST 3
|
||||
#define L2CAP_CONTROL_SUCCESS 4
|
||||
#define L2CAP_CONTROL_DISCONNECT 5
|
||||
|
||||
/* Used for HID Interrupt channel */
|
||||
#define L2CAP_INTERRUPT_SETUP 6
|
||||
#define L2CAP_INTERRUPT_CONNECT_REQUEST 7
|
||||
#define L2CAP_INTERRUPT_CONFIG_REQUEST 8
|
||||
#define L2CAP_INTERRUPT_DISCONNECT 9
|
||||
|
||||
/* Used for SDP channel */
|
||||
#define L2CAP_SDP_WAIT 10
|
||||
#define L2CAP_SDP_SUCCESS 11
|
||||
|
||||
/* Used for RFCOMM channel */
|
||||
#define L2CAP_RFCOMM_WAIT 12
|
||||
#define L2CAP_RFCOMM_SUCCESS 13
|
||||
|
||||
#define L2CAP_DISCONNECT_RESPONSE 14 // Used for both SDP and RFCOMM channel
|
||||
|
||||
/* Bluetooth states used by some drivers */
|
||||
#define TURN_ON_LED 17
|
||||
#define PS3_ENABLE_SIXAXIS 18
|
||||
#define WII_CHECK_MOTION_PLUS_STATE 19
|
||||
#define WII_CHECK_EXTENSION_STATE 20
|
||||
#define WII_INIT_MOTION_PLUS_STATE 21
|
||||
|
||||
/* L2CAP event flags for HID Control channel */
|
||||
#define L2CAP_FLAG_CONNECTION_CONTROL_REQUEST (1UL << 0)
|
||||
#define L2CAP_FLAG_CONFIG_CONTROL_SUCCESS (1UL << 1)
|
||||
#define L2CAP_FLAG_CONTROL_CONNECTED (1UL << 2)
|
||||
#define L2CAP_FLAG_DISCONNECT_CONTROL_RESPONSE (1UL << 3)
|
||||
|
||||
/* L2CAP event flags for HID Interrupt channel */
|
||||
#define L2CAP_FLAG_CONNECTION_INTERRUPT_REQUEST (1UL << 4)
|
||||
#define L2CAP_FLAG_CONFIG_INTERRUPT_SUCCESS (1UL << 5)
|
||||
#define L2CAP_FLAG_INTERRUPT_CONNECTED (1UL << 6)
|
||||
#define L2CAP_FLAG_DISCONNECT_INTERRUPT_RESPONSE (1UL << 7)
|
||||
|
||||
/* L2CAP event flags for SDP channel */
|
||||
#define L2CAP_FLAG_CONNECTION_SDP_REQUEST (1UL << 8)
|
||||
#define L2CAP_FLAG_CONFIG_SDP_SUCCESS (1UL << 9)
|
||||
#define L2CAP_FLAG_DISCONNECT_SDP_REQUEST (1UL << 10)
|
||||
|
||||
/* L2CAP event flags for RFCOMM channel */
|
||||
#define L2CAP_FLAG_CONNECTION_RFCOMM_REQUEST (1UL << 11)
|
||||
#define L2CAP_FLAG_CONFIG_RFCOMM_SUCCESS (1UL << 12)
|
||||
#define L2CAP_FLAG_DISCONNECT_RFCOMM_REQUEST (1UL << 13)
|
||||
|
||||
#define L2CAP_FLAG_DISCONNECT_RESPONSE (1UL << 14)
|
||||
|
||||
/* Macros for L2CAP event flag tests */
|
||||
#define l2cap_check_flag(flag) (l2cap_event_flag & (flag))
|
||||
#define l2cap_set_flag(flag) (l2cap_event_flag |= (flag))
|
||||
#define l2cap_clear_flag(flag) (l2cap_event_flag &= ~(flag))
|
||||
|
||||
/* L2CAP signaling commands */
|
||||
#define L2CAP_CMD_COMMAND_REJECT 0x01
|
||||
#define L2CAP_CMD_CONNECTION_REQUEST 0x02
|
||||
#define L2CAP_CMD_CONNECTION_RESPONSE 0x03
|
||||
#define L2CAP_CMD_CONFIG_REQUEST 0x04
|
||||
#define L2CAP_CMD_CONFIG_RESPONSE 0x05
|
||||
#define L2CAP_CMD_DISCONNECT_REQUEST 0x06
|
||||
#define L2CAP_CMD_DISCONNECT_RESPONSE 0x07
|
||||
#define L2CAP_CMD_INFORMATION_REQUEST 0x0A
|
||||
#define L2CAP_CMD_INFORMATION_RESPONSE 0x0B
|
||||
|
||||
// Used For Connection Response - Remember to Include High Byte
|
||||
#define PENDING 0x01
|
||||
#define SUCCESSFUL 0x00
|
||||
|
||||
/* Bluetooth L2CAP PSM - see http://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm */
|
||||
#define SDP_PSM 0x01 // Service Discovery Protocol PSM Value
|
||||
#define RFCOMM_PSM 0x03 // RFCOMM PSM Value
|
||||
#define HID_CTRL_PSM 0x11 // HID_Control PSM Value
|
||||
#define HID_INTR_PSM 0x13 // HID_Interrupt PSM Value
|
||||
|
||||
// Used to determine if it is a Bluetooth dongle
|
||||
#define WI_SUBCLASS_RF 0x01 // RF Controller
|
||||
#define WI_PROTOCOL_BT 0x01 // Bluetooth Programming Interface
|
||||
|
||||
#define BTD_MAX_ENDPOINTS 4
|
||||
#define BTD_NUM_SERVICES 4 // Max number of Bluetooth services - if you need more than 4 simply increase this number
|
||||
|
||||
#define PAIR 1
|
||||
|
||||
class BluetoothService;
|
||||
|
||||
/**
|
||||
* The Bluetooth Dongle class will take care of all the USB communication
|
||||
* and then pass the data to the BluetoothService classes.
|
||||
*/
|
||||
class BTD : public USBDeviceConfig, public UsbConfigXtracter {
|
||||
public:
|
||||
/**
|
||||
* Constructor for the BTD class.
|
||||
* @param p Pointer to USB class instance.
|
||||
*/
|
||||
BTD(USB *p);
|
||||
|
||||
/** @name USBDeviceConfig implementation */
|
||||
/**
|
||||
* Address assignment and basic initialization is done here.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
uint8_t ConfigureDevice(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Initialize the Bluetooth dongle.
|
||||
* @param parent Hub number.
|
||||
* @param port Port number on the hub.
|
||||
* @param lowspeed Speed of the device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
uint8_t Init(uint8_t parent, uint8_t port, bool lowspeed);
|
||||
/**
|
||||
* Release the USB device.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
uint8_t Release();
|
||||
/**
|
||||
* Poll the USB Input endpoints and run the state machines.
|
||||
* @return 0 on success.
|
||||
*/
|
||||
uint8_t Poll();
|
||||
|
||||
/**
|
||||
* Get the device address.
|
||||
* @return The device address.
|
||||
*/
|
||||
virtual uint8_t GetAddress() {
|
||||
return bAddress;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to check if the dongle has been initialized.
|
||||
* @return True if it's ready.
|
||||
*/
|
||||
virtual bool isReady() {
|
||||
return bPollEnable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* @param klass The device's USB class.
|
||||
* @return Returns true if the device's USB class matches this driver.
|
||||
*/
|
||||
virtual bool DEVCLASSOK(uint8_t klass) {
|
||||
return (klass == USB_CLASS_WIRELESS_CTRL);
|
||||
};
|
||||
|
||||
/**
|
||||
* Used by the USB core to check what this driver support.
|
||||
* Used to set the Bluetooth address into the PS3 controllers.
|
||||
* @param vid The device's VID.
|
||||
* @param pid The device's PID.
|
||||
* @return Returns true if the device's VID and PID matches this driver.
|
||||
*/
|
||||
virtual bool VIDPIDOK(uint16_t vid, uint16_t pid) {
|
||||
if((vid == IOGEAR_GBU521_VID && pid == IOGEAR_GBU521_PID) || (vid == BELKIN_F8T065BF_VID && pid == BELKIN_F8T065BF_PID))
|
||||
return true;
|
||||
if(my_bdaddr[0] != 0x00 || my_bdaddr[1] != 0x00 || my_bdaddr[2] != 0x00 || my_bdaddr[3] != 0x00 || my_bdaddr[4] != 0x00 || my_bdaddr[5] != 0x00) { // Check if Bluetooth address is set
|
||||
if(vid == PS3_VID && (pid == PS3_PID || pid == PS3NAVIGATION_PID || pid == PS3MOVE_PID))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**@}*/
|
||||
|
||||
/** @name UsbConfigXtracter implementation */
|
||||
/**
|
||||
* UsbConfigXtracter implementation, used to extract endpoint information.
|
||||
* @param conf Configuration value.
|
||||
* @param iface Interface number.
|
||||
* @param alt Alternate setting.
|
||||
* @param proto Interface Protocol.
|
||||
* @param ep Endpoint Descriptor.
|
||||
*/
|
||||
void EndpointXtract(uint8_t conf, uint8_t iface, uint8_t alt, uint8_t proto, const USB_ENDPOINT_DESCRIPTOR *ep);
|
||||
/**@}*/
|
||||
|
||||
/** Disconnects both the L2CAP Channel and the HCI Connection for all Bluetooth services. */
|
||||
void disconnect();
|
||||
|
||||
/**
|
||||
* Register Bluetooth dongle members/services.
|
||||
* @param pService Pointer to BluetoothService class instance.
|
||||
* @return The service ID on success or -1 on fail.
|
||||
*/
|
||||
int8_t registerBluetoothService(BluetoothService *pService) {
|
||||
for(uint8_t i = 0; i < BTD_NUM_SERVICES; i++) {
|
||||
if(!btService[i]) {
|
||||
btService[i] = pService;
|
||||
return i; // Return ID
|
||||
}
|
||||
}
|
||||
return -1; // Error registering BluetoothService
|
||||
};
|
||||
|
||||
/** @name HCI Commands */
|
||||
/**
|
||||
* Used to send a HCI Command.
|
||||
* @param data Data to send.
|
||||
* @param nbytes Number of bytes to send.
|
||||
*/
|
||||
void HCI_Command(uint8_t* data, uint16_t nbytes);
|
||||
/** Reset the Bluetooth dongle. */
|
||||
void hci_reset();
|
||||
/** Read the Bluetooth address of the dongle. */
|
||||
void hci_read_bdaddr();
|
||||
/** Read the HCI Version of the Bluetooth dongle. */
|
||||
void hci_read_local_version_information();
|
||||
/**
|
||||
* Set the local name of the Bluetooth dongle.
|
||||
* @param name Desired name.
|
||||
*/
|
||||
void hci_set_local_name(const char* name);
|
||||
/** Enable visibility to other Bluetooth devices. */
|
||||
void hci_write_scan_enable();
|
||||
/** Disable visibility to other Bluetooth devices. */
|
||||
void hci_write_scan_disable();
|
||||
/** Read the remote devices name. */
|
||||
void hci_remote_name();
|
||||
/** Accept the connection with the Bluetooth device. */
|
||||
void hci_accept_connection();
|
||||
/**
|
||||
* Disconnect the HCI connection.
|
||||
* @param handle The HCI Handle for the connection.
|
||||
*/
|
||||
void hci_disconnect(uint16_t handle);
|
||||
/**
|
||||
* Respond with the pin for the connection.
|
||||
* The pin is automatically set for the Wii library,
|
||||
* but can be customized for the SPP library.
|
||||
*/
|
||||
void hci_pin_code_request_reply();
|
||||
/** Respons when no pin was set. */
|
||||
void hci_pin_code_negative_request_reply();
|
||||
/**
|
||||
* Command is used to reply to a Link Key Request event from the BR/EDR Controller
|
||||
* if the Host does not have a stored Link Key for the connection.
|
||||
*/
|
||||
void hci_link_key_request_negative_reply();
|
||||
/** Used to try to authenticate with the remote device. */
|
||||
void hci_authentication_request();
|
||||
/** Start a HCI inquiry. */
|
||||
void hci_inquiry();
|
||||
/** Cancel a HCI inquiry. */
|
||||
void hci_inquiry_cancel();
|
||||
/** Connect to last device communicated with. */
|
||||
void hci_connect();
|
||||
/**
|
||||
* Connect to device.
|
||||
* @param bdaddr Bluetooth address of the device.
|
||||
*/
|
||||
void hci_connect(uint8_t *bdaddr);
|
||||
/** Used to a set the class of the device. */
|
||||
void hci_write_class_of_device();
|
||||
/**@}*/
|
||||
|
||||
/** @name L2CAP Commands */
|
||||
/**
|
||||
* Used to send L2CAP Commands.
|
||||
* @param handle HCI Handle.
|
||||
* @param data Data to send.
|
||||
* @param nbytes Number of bytes to send.
|
||||
* @param channelLow,channelHigh Low and high byte of channel to send to.
|
||||
* If argument is omitted then the Standard L2CAP header: Channel ID (0x01) for ACL-U will be used.
|
||||
*/
|
||||
void L2CAP_Command(uint16_t handle, uint8_t* data, uint8_t nbytes, uint8_t channelLow = 0x01, uint8_t channelHigh = 0x00);
|
||||
/**
|
||||
* L2CAP Connection Request.
|
||||
* @param handle HCI handle.
|
||||
* @param rxid Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
* @param psm Protocol/Service Multiplexer - see: https://www.bluetooth.org/Technical/AssignedNumbers/logical_link.htm.
|
||||
*/
|
||||
void l2cap_connection_request(uint16_t handle, uint8_t rxid, uint8_t* scid, uint16_t psm);
|
||||
/**
|
||||
* L2CAP Connection Response.
|
||||
* @param handle HCI handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Destination Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
* @param result Result - First send ::PENDING and then ::SUCCESSFUL.
|
||||
*/
|
||||
void l2cap_connection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid, uint8_t result);
|
||||
/**
|
||||
* L2CAP Config Request.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Destination Channel Identifier.
|
||||
*/
|
||||
void l2cap_config_request(uint16_t handle, uint8_t rxid, uint8_t* dcid);
|
||||
/**
|
||||
* L2CAP Config Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_config_response(uint16_t handle, uint8_t rxid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Disconnection Request.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Device Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_disconnection_request(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Disconnection Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param dcid Device Channel Identifier.
|
||||
* @param scid Source Channel Identifier.
|
||||
*/
|
||||
void l2cap_disconnection_response(uint16_t handle, uint8_t rxid, uint8_t* dcid, uint8_t* scid);
|
||||
/**
|
||||
* L2CAP Information Response.
|
||||
* @param handle HCI Handle.
|
||||
* @param rxid Identifier.
|
||||
* @param infoTypeLow,infoTypeHigh Infotype.
|
||||
*/
|
||||
void l2cap_information_response(uint16_t handle, uint8_t rxid, uint8_t infoTypeLow, uint8_t infoTypeHigh);
|
||||
/**@}*/
|
||||