PS/2 keyboard reader and Gradiente Expert 1.1 MSX keyboard adapter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* ABNT2 PS/2 keyboard to Gradiente Expert 1.1 keyboard mapper | |
* (c) 2014 Tiago Rezende | |
*/ | |
static const uint8_t ps2data = 2; | |
static const uint8_t ps2clk = 3; | |
//#define K(x) (uint8_t)((x>=0x80)?(x+0x8):((x<=0x07)?(x+0x80):(x-0x10))) | |
#define K(x) x | |
const PROGMEM uint8_t keymap_ABNT2[] = { | |
K(0xb7), | |
K(0xb7), // F9 | |
K(0xb7), | |
K(0x71), // F5 | |
K(0x67), // F3 | |
K(0x65), // F1 | |
K(0x66), // F2 | |
K(0xb7), // F12 | |
K(0xb7), | |
K(0xb7), // F10 | |
K(0xb7), // F8 | |
K(0xb7), // F6 | |
K(0x70), // F4 | |
K(0x73), // TAB | |
K(0xb7), // ` | |
K(0xb7), | |
K(0xb7), | |
K(0x64), // L ALT | |
K(0x60), // L SHIFT | |
K(0xb7), | |
K(0x61), // L CTRL | |
K(0x46), // Q | |
K(0x01), // 1 | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x57), // Z | |
K(0x50), // S | |
K(0x26), // A | |
K(0x54), // W | |
K(0x02), // 2 | |
K(0xb7), // L WIN | |
K(0xb7), | |
K(0x30), // C | |
K(0x55), // X | |
K(0x31), // D | |
K(0x32), // E | |
K(0x04), // 4 | |
K(0x03), // 3 | |
K(0xb7), | |
K(0xb7), | |
K(0x80), // SPACE | |
K(0x53), // V | |
K(0x33), // F | |
K(0x51), // T | |
K(0x47), // R | |
K(0x05), // 5 | |
K(0xb7), | |
K(0xb7), | |
K(0x43), // N | |
K(0x27), // B | |
K(0x35), // H | |
K(0x34), // G | |
K(0x56), // Y | |
K(0x06), // 6 | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x42), // M | |
K(0x37), // J | |
K(0x52), // U | |
K(0x07), // 7 | |
K(0x10), // 8 | |
K(0xb7), | |
K(0xb7), | |
K(0x22), // , | |
K(0x40), // K | |
K(0x36), // I | |
K(0x44), // O | |
K(0x00), // 0 | |
K(0x11), // 9 | |
K(0xb7), | |
K(0xb7), | |
K(0x23), // . | |
K(0x24), // ; | |
K(0x41), // L | |
K(0x21), // Ç | |
K(0x45), // P | |
K(0x12), // - | |
K(0xb7), | |
K(0xb7), | |
K(0x25), // / | |
K(0x17), // ~ | |
K(0xb7), | |
K(0x15), // ´ | |
K(0x13), // = | |
K(0xb7), | |
K(0xb7), | |
K(0x63), // CAPS | |
K(0x60), // R SHIFT | |
K(0x77), // ENTER | |
K(0x16), // [ | |
K(0xb7), | |
K(0x21), // ] | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x14), // \ | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x75), // BACKSPACE | |
K(0xb7), | |
K(0xb7), | |
K(0x01), // KEYPAD 1, | |
K(0xb7), | |
K(0x04), // KEYPAD 4, | |
K(0x07), // KEYPAD 7, | |
K(0x23), // KEYPAD . | |
K(0xb7), | |
K(0xb7), | |
K(0x00), // KEYPAD 0 | |
K(0x22), // KEYPAD , | |
K(0x02), // KEYPAD 2 | |
K(0x05), // KEYPAD 5 | |
K(0x06), // KEYPAD 6 | |
K(0x10), // KEYPAD 8 | |
K(0x72), // ESCAPE | |
K(0xb7), // NUMLOCK | |
K(0xb7), // F11 | |
K(0x90), // KEYPAD + | |
K(0x03), // KEYPAD 3 | |
K(0x91), // KEYPAD - | |
K(0x92), // KEYPAD * | |
K(0x11), // KEYPAD 9, | |
K(0xb7), // SCROLL LOCK | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // F7 | |
}; | |
const PROGMEM uint8_t keymap_ext_ABNT2[] = { | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // WWW SEARCH | |
K(0x62), // R ALT | |
K(0xb7), // PRINT SCREEN | |
K(0xb7), | |
K(0x42), // R CTRL | |
K(0xb7), // PREV TRACK | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x62), // L WIN | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // MESSENGER | |
K(0xb7), | |
K(0xb7), // R WIN | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // CALC | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x80), // CONTEXT | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // PLAY/PAUSE | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // WWW HOME | |
K(0xb7), // STOP | |
K(0xb7), // LOG OFF | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // SLEEP | |
K(0xb7), // MY COMPUTER | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // EMAIL | |
K(0xb7), | |
K(0x94), // KEYPAD / | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // NEXT TRACK | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // MEDIA SELECT | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x77), // KP EN | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // WAKE | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // END | |
K(0xb7), | |
K(0x84), // L ARROW | |
K(0x81), // HOME | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x82), // INSERT | |
K(0x83), // DELETE | |
K(0x86), // D ARROW | |
K(0xb7), | |
K(0x87), // R ARROW | |
K(0x85), // U ARROW | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0x76), // PAGE DOWN | |
K(0xb7), | |
K(0xb7), | |
K(0x74), // PAGE UP | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), | |
K(0xb7), // F7 | |
}; | |
uint8_t msx_buffer[16]; | |
#define CO_BEGIN static int _co_state = 0; switch(_co_state) { case 0: | |
#define CO_WAIT(x) case __LINE__: if((x)) { _co_state = __LINE__; return; }; | |
#define CO_YIELD do {_co_state = __LINE__; return; } while(0); case __LINE__: ; | |
#define CO_END }; | |
#define CO_WAIT_HIGH(x) CO_WAIT(digitalRead(x) == 0) | |
#define CO_WAIT_LOW(x) CO_WAIT(digitalRead(x) != 0) | |
static inline void ps2kbd_interrupt(void) { | |
static uint8_t bitcount = 0, incoming = 0; | |
static uint32_t prev_ms = 0; | |
static boolean release_key, use_extended; | |
uint32_t now_ms; | |
uint8_t n, val; | |
val = digitalRead(ps2data); | |
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?0x80:0)|(incoming >> 1); | |
} | |
bitcount ++; | |
if(bitcount == 11) { | |
if(incoming == 0xf0) { | |
release_key = true; | |
} else if(incoming == 0xe0) { | |
use_extended = true; | |
} else { | |
uint8_t msx_scancode = pgm_read_byte(use_extended?(keymap_ext_ABNT2+incoming):(keymap_ABNT2+incoming)); | |
if(release_key) { | |
msx_buffer[msx_scancode>>4] |= (1 << (msx_scancode & 0xf)); | |
} else { | |
msx_buffer[msx_scancode>>4] &= ~(1 << (msx_scancode & 0xf)); | |
} | |
/* | |
Serial.println(incoming); | |
/* | |
for(int i = 0; i < 16; i++) { | |
Serial.print(msx_buffer[i]>>4,HEX); | |
Serial.print(msx_buffer[i]&0xf,HEX); | |
} | |
Serial.println(); | |
//*/ | |
use_extended = false; | |
release_key = false; | |
} | |
bitcount = 0; | |
incoming = 0; | |
} | |
} | |
void ps2kbd_poll() { | |
static uint8_t incoming, i, outgoing, parity; | |
CO_BEGIN; | |
/* | |
pinMode(ps2data, OUTPUT); | |
digitalWrite(ps2data, 0); | |
pinMode(ps2clk, INPUT_PULLUP); | |
CO_WAIT_LOW(ps2clk); | |
outgoing = 0xff; | |
parity = 0; | |
for(i = 0; i < 8; i++) { | |
parity += outgoing & 1; | |
digitalWrite(ps2data, outgoing & 1); | |
CO_WAIT_HIGH(ps2clk); | |
CO_WAIT_LOW(ps2clk); | |
outgoing >>= 1; | |
} | |
digitalWrite(ps2data, parity & 1); | |
CO_WAIT_HIGH(ps2clk); | |
CO_WAIT_LOW(ps2clk); | |
digitalWrite(ps2data, 1); | |
CO_WAIT_HIGH(ps2clk); | |
CO_WAIT_LOW(ps2clk); | |
delayMicroseconds(50); | |
//CO_WAIT_LOW(ps2clk); | |
pinMode(ps2data, INPUT_PULLUP); | |
*/ | |
while(true) { | |
CO_WAIT_HIGH(ps2clk); | |
CO_WAIT_LOW(ps2clk); | |
ps2kbd_interrupt(); | |
} | |
CO_END; | |
} | |
void setup() { | |
//Serial.begin(9600); | |
//while(!Serial) {;} | |
pinMode(ps2data, INPUT_PULLUP); | |
pinMode(ps2clk, INPUT_PULLUP); | |
pinMode(4, INPUT_PULLUP); | |
pinMode(5, INPUT_PULLUP); | |
pinMode(6, INPUT_PULLUP); | |
pinMode(7, INPUT_PULLUP); | |
pinMode(A0, OUTPUT); | |
pinMode(A1, OUTPUT); | |
pinMode(A2, OUTPUT); | |
pinMode(A3, OUTPUT); | |
pinMode(8, OUTPUT); | |
pinMode(9, OUTPUT); | |
pinMode(10, OUTPUT); | |
pinMode(11, OUTPUT); | |
pinMode(13, OUTPUT); | |
digitalWrite(13, HIGH); | |
for(uint8_t i = 0; i < 16; i++) { | |
msx_buffer[i] = 255; | |
} | |
attachInterrupt(1, ps2kbd_interrupt, FALLING); | |
} | |
void loop() { | |
uint8_t last_keys_index = 20; | |
uint8_t current; | |
uint8_t keys = 0; | |
PORTC &= 0xf0; | |
PORTB &= 0xf0; | |
while(true) { | |
while(last_keys_index == (current = __builtin_avr_swap(PIND)&0xf)) { | |
sei(); | |
delayMicroseconds(1); | |
cli(); | |
} | |
keys = msx_buffer[current]; | |
PORTC = keys; | |
PORTB = __builtin_avr_swap(keys); | |
last_keys_index = current; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment