nitial commit.

This commit is contained in:
Manfred Amann 2019-05-10 15:39:26 +02:00
parent cf3222d4a4
commit 86dcaee84d
165 changed files with 38338 additions and 267 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -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();
}

179
II_Encoder.cpp Normal file
View File

@ -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);
}

27
II_Encoder.h Normal file
View File

@ -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);
};

191
backlog.cpp Normal file
View File

@ -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;
}
}

35
backlog.h Normal file
View File

@ -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);
};

96
layoutmemory.cpp Normal file
View File

@ -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;
}

26
layoutmemory.h Normal file
View File

@ -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
};

BIN
libraries/.DS_Store vendored Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -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.