commit 4323eec9365c7033f7313f8fa989f6399a17971d Author: Tomek Rękawek Date: Thu Nov 24 13:54:25 2016 +0100 first commit diff --git a/PS2Keyboard.cpp b/PS2Keyboard.cpp new file mode 100644 index 0000000..c1b03b1 --- /dev/null +++ b/PS2Keyboard.cpp @@ -0,0 +1,156 @@ +/* + PS2Keyboard.cpp - PS2Keyboard library + Copyright (c) 2007 Free Software Foundation. All right reserved. + Written by Christian Weichel + + ** Mostly rewritten Paul Stoffregen 2010, 2011 + ** Modified for use beginning with Arduino 13 by L. Abraham Smith, * + ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan ** + ** Custom version modifed by Tomasz Rękawek to only provide scancodes. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "PS2Keyboard.h" + +#define BUFFER_SIZE 45 +static volatile uint8_t buffer[BUFFER_SIZE]; +static volatile uint8_t head, tail; +static uint8_t DataPin; + +// The ISR for the external interrupt +void ps2interrupt(void) +{ + static uint8_t bitcount=0; + static uint8_t incoming=0; + static uint32_t prev_ms=0; + uint32_t now_ms; + uint8_t n, val; + + val = digitalRead(DataPin); + now_ms = millis(); + if (now_ms - prev_ms > 250) { + bitcount = 0; + incoming = 0; + } + prev_ms = now_ms; + n = bitcount - 1; + if (n <= 7) { + incoming |= (val << n); + } + bitcount++; + if (bitcount == 11) { + uint8_t i = head + 1; + if (i >= BUFFER_SIZE) i = 0; + if (i != tail) { + buffer[i] = incoming; + head = i; + } + bitcount = 0; + incoming = 0; + } +} + +static inline uint8_t getScanCode(void) +{ + uint8_t c, i; + + i = tail; + if (i == head) return 0; + i++; + if (i >= BUFFER_SIZE) i = 0; + c = buffer[i]; + tail = i; + return c; +} + +PS2Keyboard::PS2Keyboard() { + // nothing to do here, begin() does it all +} + +void PS2Keyboard::begin(uint8_t data_pin, uint8_t irq_pin) { + uint8_t irq_num=255; + + DataPin = data_pin; + + // initialize the pins +#ifdef INPUT_PULLUP + pinMode(irq_pin, INPUT_PULLUP); + pinMode(data_pin, INPUT_PULLUP); +#else + pinMode(irq_pin, INPUT); + digitalWrite(irq_pin, HIGH); + pinMode(data_pin, INPUT); + digitalWrite(data_pin, HIGH); +#endif + +#ifdef CORE_INT_EVERY_PIN + irq_num = irq_pin; + +#else + switch(irq_pin) { + #ifdef CORE_INT0_PIN + case CORE_INT0_PIN: + irq_num = 0; + break; + #endif + #ifdef CORE_INT1_PIN + case CORE_INT1_PIN: + irq_num = 1; + break; + #endif + #ifdef CORE_INT2_PIN + case CORE_INT2_PIN: + irq_num = 2; + break; + #endif + #ifdef CORE_INT3_PIN + case CORE_INT3_PIN: + irq_num = 3; + break; + #endif + #ifdef CORE_INT4_PIN + case CORE_INT4_PIN: + irq_num = 4; + break; + #endif + #ifdef CORE_INT5_PIN + case CORE_INT5_PIN: + irq_num = 5; + break; + #endif + #ifdef CORE_INT6_PIN + case CORE_INT6_PIN: + irq_num = 6; + break; + #endif + #ifdef CORE_INT7_PIN + case CORE_INT7_PIN: + irq_num = 7; + break; + #endif + } +#endif + + head = 0; + tail = 0; + if (irq_num < 255) { + attachInterrupt(irq_num, ps2interrupt, FALLING); + } +} + +uint8_t PS2Keyboard::getScanCode() { + return getScanCode(); +} diff --git a/PS2Keyboard.h b/PS2Keyboard.h new file mode 100644 index 0000000..b3bca86 --- /dev/null +++ b/PS2Keyboard.h @@ -0,0 +1,60 @@ +/* + PS2Keyboard.h - PS2Keyboard library + Copyright (c) 2007 Free Software Foundation. All right reserved. + Written by Christian Weichel + + ** Mostly rewritten Paul Stoffregen , June 2010 + ** Modified for use with Arduino 13 by L. Abraham Smith, * + ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan ** + ** Custom version modifed by Tomasz Rękawek to only provide scancodes. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +#ifndef PS2Keyboard_h +#define PS2Keyboard_h + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" // for attachInterrupt, FALLING +#else +#include "WProgram.h" +#endif + +#include "utility/int_pins.h" + +/** + * Purpose: Provides an easy access to PS2 keyboards + * Author: Christian Weichel + */ +class PS2Keyboard { + public: + /** + * This constructor does basically nothing. Please call the begin(int,int) + * method before using any other method of this class. + */ + PS2Keyboard(); + + /** + * Starts the keyboard "service" by registering the external interrupt. + * setting the pin modes correctly and driving those needed to high. + * The propably best place to call this method is in the setup routine. + */ + static void begin(uint8_t dataPin, uint8_t irq_pin); + + static uint8_t getScanCode(); +}; + +#endif diff --git a/macplus-keyboard.ino b/macplus-keyboard.ino new file mode 100644 index 0000000..6014e5a --- /dev/null +++ b/macplus-keyboard.ino @@ -0,0 +1,123 @@ +#include "PS2Keyboard.h" + +#define PS2_DATA_PIN 2 +#define PS2_CLOCK_PIN 3 + +#define MAC_DATA_PIN 5 +#define MAC_CLOCK_PIN 6 + +#define NULL_TRANSITION 0x7b + +PS2Keyboard keyboard; +byte scanCodesTable[256]; +byte extScanCodesTable[256]; + +void setup() { + initScancodes(); + + keyboard.begin(PS2_DATA_PIN, PS2_CLOCK_PIN); + + pinMode(LED_BUILTIN, OUTPUT); + pinMode(MAC_CLOCK_PIN, OUTPUT); + pinMode(MAC_DATA_PIN, INPUT_PULLUP); + + while (digitalRead(MAC_DATA_PIN) != LOW); + + delayMicroseconds(180); +} + +void loop() { + digitalWrite(LED_BUILTIN, LOW); + byte cmd = readByte(); + digitalWrite(LED_BUILTIN, HIGH); + + switch (cmd) { + case 0x10: + inquiry(); + break; + + case 0x14: // instant + sendByte(getKeyTransition()); + break; + + case 0x16: // model number + sendByte(B00000011); + break; + + case 0x36: // test + sendByte(0x7d); + break; + } +} + +void inquiry() { + unsigned long start = millis(); + while ((millis() - start) < 250) { + byte key = getKeyTransition(); + if (key != NULL_TRANSITION) { + sendByte(key); + return; + } + } + sendByte(NULL_TRANSITION); +} + +byte readByte() { + pinMode(MAC_DATA_PIN, INPUT_PULLUP); + byte b = 0; + for (byte i = 0; i < 8; i++) { + digitalWrite(MAC_CLOCK_PIN, LOW); + delayMicroseconds(180); + digitalWrite(MAC_CLOCK_PIN, HIGH); + delayMicroseconds(40); + b = (b << 1) | digitalRead(MAC_DATA_PIN); + delayMicroseconds(180); + } + + return b; +} + +void sendByte(byte b) { + pinMode(MAC_DATA_PIN, OUTPUT); + for (byte m = 128; m > 0; m >>= 1) { + digitalWrite(MAC_DATA_PIN, b & m == 0 ? HIGH : LOW); + delayMicroseconds(40); + digitalWrite(MAC_CLOCK_PIN, LOW); + delayMicroseconds(160); + digitalWrite(MAC_CLOCK_PIN, HIGH); + delayMicroseconds(130); + } +} + +byte getKeyTransition() { + byte c = keyboard.getScanCode(); + if (c == 0) { + return NULL_TRANSITION; + } else if (c == 0xf0) { + return translate(keyboard.getScanCode(), false, true); + } else if (c == 0xe0) { + return getExtendedTransition(); + } else { + return translate(c, false, false); + } +} + +byte getExtendedTransition() { + byte c = keyboard.getScanCode(); + if (c == 0xf0) { + return translate(keyboard.getScanCode(), true, true); + } else { + return translate(c, true, false); + } +} + +byte translate(byte scanCode, boolean extended, boolean released) { + byte translated = extended ? extScanCodesTable[scanCode] : scanCodesTable[scanCode]; + if (translated == NULL_TRANSITION) { + return NULL_TRANSITION; + } else if (released) { + return translated & 0x80; + } else { + return translated; + } +} diff --git a/scancodes.ino b/scancodes.ino new file mode 100644 index 0000000..4dc9540 --- /dev/null +++ b/scancodes.ino @@ -0,0 +1,103 @@ +void initScancodes() { + for (byte i = 0; i < 256; i++) { + scanCodesTable[i] = NULL_TRANSITION; + extScanCodesTable[i] = NULL_TRANSITION; + } + + scanCodesTable[0x0e] = 0x32; // ~` + scanCodesTable[0x16] = 0x12; // 1! + scanCodesTable[0x1e] = 0x13; // 2@ + scanCodesTable[0x26] = 0x14; // 3# + scanCodesTable[0x25] = 0x15; // 4$ + scanCodesTable[0x2e] = 0x17; // 5% + scanCodesTable[0x36] = 0x16; // 6^ + scanCodesTable[0x3d] = 0x1a; // 7& + scanCodesTable[0x3e] = 0x1c; // 8* + scanCodesTable[0x46] = 0x19; // 9( + scanCodesTable[0x45] = 0x1d; // 0) + scanCodesTable[0x4e] = 0x1b; // -_ + scanCodesTable[0x55] = 0x18; // += + scanCodesTable[0x5d] = 0x2a; // |\ + scanCodesTable[0x66] = 0x33; // backspace + + scanCodesTable[0x0d] = 0x30; // tab + scanCodesTable[0x15] = 0x0c; // q + scanCodesTable[0x1d] = 0x0d; // w + scanCodesTable[0x24] = 0x0e; // e + scanCodesTable[0x2d] = 0x0f; // r + scanCodesTable[0x2c] = 0x10; // t + scanCodesTable[0x35] = 0x11; // y + scanCodesTable[0x3c] = 0x20; // u + scanCodesTable[0x43] = 0x22; // i + scanCodesTable[0x44] = 0x1f; // o + scanCodesTable[0x4d] = 0x23; // p + scanCodesTable[0x54] = 0x21; // [{ + scanCodesTable[0x5b] = 0x1e; // }] + scanCodesTable[0x5a] = 0x24; // enter + + scanCodesTable[0x58] = 0x39; // caps lock + scanCodesTable[0x1c] = 0x00; // a + scanCodesTable[0x1b] = 0x01; // s + scanCodesTable[0x23] = 0x02; // d + scanCodesTable[0x2b] = 0x03; // f + scanCodesTable[0x34] = 0x05; // g + scanCodesTable[0x33] = 0x04; // h + scanCodesTable[0x3b] = 0x26; // j + scanCodesTable[0x42] = 0x28; // k + scanCodesTable[0x4b] = 0x25; // l + scanCodesTable[0x4c] = 0x29; // :; + scanCodesTable[0x52] = 0x27; // "' + + scanCodesTable[0x12] = 0x38; // left shift + scanCodesTable[0x1a] = 0x06; // z + scanCodesTable[0x22] = 0x07; // x + scanCodesTable[0x21] = 0x08; // c + scanCodesTable[0x2a] = 0x09; // v + scanCodesTable[0x32] = 0x0b; // b + scanCodesTable[0x31] = 0x2d; // n + scanCodesTable[0x3a] = 0x2e; // m + scanCodesTable[0x41] = 0x2b; // <, + scanCodesTable[0x49] = 0x2f; // >. + scanCodesTable[0x4a] = 0x2c; // ?/ + scanCodesTable[0x59] = 0x38; // right shift + + scanCodesTable[0x14] = 0x3a; // left ctrl -> option + scanCodesTable[0x11] = 0x3a; // left alt -> option + scanCodesTable[0x29] = 0x31; // space + + extScanCodesTable[0x11] = 0x3a; // right alt -> option + extScanCodesTable[0x14] = 0x3a; // right ctrl -> option + + extScanCodesTable[0x5b] = 0x37; // left windows -> cmd + extScanCodesTable[0x1f] = 0x37; // left windows -> cmd + extScanCodesTable[0x8b] = 0x37; // left windows -> cmd + + extScanCodesTable[0x5c] = 0x37; // right windows + extScanCodesTable[0x27] = 0x37; // right windows + extScanCodesTable[0x8c] = 0x37; // right windows + + extScanCodesTable[0x75] = 0x4d; // up arrow + extScanCodesTable[0x6b] = 0x46; // left arrow + extScanCodesTable[0x72] = 0x48; // down arrow + extScanCodesTable[0x74] = 0x42; // right arrow + + extScanCodesTable[0x77] = 0x47; // numlock -> numpad clear + extScanCodesTable[0x71] = 0x47; // delete -> numpad clear + extScanCodesTable[0x4a] = 0x6d; // numpad / + extScanCodesTable[0x5a] = 0x4c; // numpad enter + + scanCodesTable[0x7c] = 0x62; // numpad * + scanCodesTable[0x7b] = 0x4e; // numpad - + scanCodesTable[0x70] = 0x52; // numpad 0 + scanCodesTable[0x71] = 0x41; // numpad . + scanCodesTable[0x69] = 0x53; // numpad 1 + scanCodesTable[0x72] = 0x54; // numpad 2 + scanCodesTable[0x7a] = 0x55; // numpad 3 + scanCodesTable[0x6b] = 0x56; // numpad 4 + scanCodesTable[0x73] = 0x57; // numpad 5 + scanCodesTable[0x74] = 0x58; // numpad 6 + scanCodesTable[0x79] = 0x66; // numpad + + scanCodesTable[0x6c] = 0x59; // numpad 7 + scanCodesTable[0x75] = 0x5b; // numpad 8 + scanCodesTable[0x7d] = 0x5c; // numpad 9 +} diff --git a/utility/int_pins.h b/utility/int_pins.h new file mode 100644 index 0000000..4f882da --- /dev/null +++ b/utility/int_pins.h @@ -0,0 +1,65 @@ +// interrupt pins for known boards + +// Teensy and maybe others automatically define this info +#if !defined(CORE_INT0_PIN) + +// Arduino Mega +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Arduino Mega + #define CORE_INT0_PIN 2 + #define CORE_INT1_PIN 3 + #define CORE_INT2_PIN 21 + #define CORE_INT3_PIN 20 + #define CORE_INT4_PIN 19 + #define CORE_INT5_PIN 18 + +// Arduino Due (untested) +#elif defined(__SAM3X8E__) + #define CORE_INT_EVERY_PIN + #ifndef PROGMEM + #define PROGMEM + #endif + #ifndef pgm_read_byte + #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) + #endif + +// Arduino Leonardo (untested) +#elif defined(__AVR_ATmega32U4__) && !defined(CORE_TEENSY) + #define CORE_INT0_PIN 3 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 0 + #define CORE_INT3_PIN 1 + +// Sanguino (untested) +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino + #define CORE_INT0_PIN 10 + #define CORE_INT1_PIN 11 + #define CORE_INT2_PIN 2 + +// Chipkit Uno32 (untested) +#elif defined(__PIC32MX__) && defined(_BOARD_UNO_) + #define CORE_INT0_PIN 38 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 7 + #define CORE_INT3_PIN 8 + #define CORE_INT4_PIN 35 + +// Chipkit Mega32 (untested) +#elif defined(__PIC32MX__) && defined(_BOARD_MEGA_) + #define CORE_INT0_PIN 3 + #define CORE_INT1_PIN 2 + #define CORE_INT2_PIN 7 + #define CORE_INT3_PIN 21 + #define CORE_INT4_PIN 20 + +// http://hlt.media.mit.edu/?p=1229 +#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + #define CORE_INT0_PIN 2 + +// Arduino Uno, Duemilanove, LilyPad, Mini, Fio, etc... +#else + #define CORE_INT0_PIN 2 + #define CORE_INT1_PIN 3 + +#endif +#endif +