Monday, 15 February 2016

Arduino PS/2 Keyboard Emulator Issues


Yes, I've searched the Arduino.cc forums and here.  Yes, I've found the articles regarding the ps2dev library.  Yes, I've read (okay, some I skimmed) the definitive PS/2 interface article at this website. Yes, I have this working, kinda.  I need some ideas for making the leap to fully working.  :)


No, I can't just emulate a USB HID Keyboard and leave it at that--it needs to be PS/2 Keyboard emulation.  Yes, I am sending proper make and break signals--it even handles very complicated keystroke combinations.  As it stands right now, I have code written for my Arduino as posted below (technically a Freeduino 1.22), and I've sent keystrokes via the Serial Monitor or PuTTY terminal, as well as with a handy Python wrapper/driver which sends actual PS/2 scancode information--and generally makes my life much easier--also taking some of the load off the Arduino.



Right now, I have a sketch running on the Arduino which emulates a PS/2 Keyboard.  Naturally, I have to boot my "target" machine (machine that PS/2 Plug goes into), and I see the "handshake" take place.  Boot to WinDoze, open notepad, and drive keystrokes to the screen (succesfully) using my Python "driver".  (The driver simply takes place of the Serial Monitor/PuTTY terminal and reads/writes to the serial port using a module called PySerial.)  This is all done on a AMD in ASUS motherboard "target".


Now, the goal is to get it working on my Intel in Intel motherboard based "target", I plug it in, boot, and no dice.  So, I modified the sketch a bit to try and give myself a heads-up of what's actually going on on my little Ardy friend.  The version after the mods is displayed below.  As I understand it (code was "borrowed" from another Arduino.cc forum post, here) It will try and establish a connection with the "target" over PS/2 first, blinking the onboard LED at a .5 second period until the connection is established.  The Intel target doesn't get past the .5 second period blinks and the Serial Connection is never established with the "host".


My question is this: is there a major difference in the way ps/2 keyboards establish communication with their target machine?  Is it really a design difference or should I be looking for something more basic that's the issue here?  I've heard something about needing pull-up resistors on the data/clock inputs, but that should be handled in the code, especially because it's WORKING on another target, just not the one I need it to work on.


Any ideas?  I'd love to get this working ASAP--I'm going to keep doing debug, any pointers or suggestions would be greatly appreciated.  They will all be given full consideration because I need some fresh eyes on this issue.  Perhaps better implementation in the ps2dev library is needed?


#include "ps2dev.h" // to emulate a PS/2 device

// Orange = 2
// Blue = 3
// Red = 5V (3 in)
// Black = GND (4 in)

// EXT Power, USB for COM only

PS2dev keyboard(3,2); // PS2dev object (2:data, 3:clock)
int enabled = 0; // pseudo variable for state of "keyboard"
boolean serialConnected = false;
int incomingByte = 0;

void ack() {
//acknowledge commands
while(keyboard.write(0xFA));

}

int kbdCmd(int command) {
unsigned char val;
switch (command) {
case 0xFF: //reset
ack();
//the while loop lets us wait for the host to be ready
while(keyboard.write(0xAA)!=0);
break;

case 0xFE: //resend
ack();
break;
case 0xF6: //set defaults
//enter stream mode
ack();
break;
case 0xF5: //disable data reporting
//FM
enabled = 0;

ack();
break;
case 0xF4: //enable data reporting
//FM
enabled = 1;
ack();
break;
case 0xF3: //set typematic rate
ack();
keyboard.read(&val); //do nothing with the rate

ack();
break;
case 0xF2: //get device id
ack();
keyboard.write(0xAB);
keyboard.write(0x83);
break;
case 0xF0: //set scan code set
ack();
keyboard.read(&val); //do nothing with the rate

ack();
break;
case 0xEE: //echo
//ack();
keyboard.write(0xEE);
break;
case 0xED: //set/reset LEDs
ack();
keyboard.read(&val); //do nothing with the rate
ack();

break;
}
}

void connectHost() {
while (Serial.available() <= 0) {
Serial.print('A'); // send a capital A
delay(300);
}
}


void setup() {
pinMode(13, OUTPUT);
//establish serial connection with host
Serial.begin(9600);
// establish ps/2 connection with target
while(keyboard.write(0xAA)!=0){
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);

delay(500);
}
delay(100);

connectHost();
Serial.println("\nSerial Host Connected");
Serial.flush();
}

void loop() {

unsigned char c;
if( (digitalRead(3)==LOW) || (digitalRead(2) == LOW)) {
if(digitalRead(3)==LOW){
Serial.println("pin 3 is LOW");
} else {
Serial.println("pin 2 is LOW");
}
while(keyboard.read(&c));
kbdCmd(c);
Serial.print("Target: 0x");

Serial.println(c, HEX);
}
else {//if host device wants to send a command:
//echo ASCII code from terminal and write to ps/2
if(Serial.available() > 0) {
incomingByte = Serial.read();
keyboard.write(incomingByte);
Serial.print("Host: 0x");
Serial.print(incomingByte, HEX);
Serial.print(" ");

Serial.print(incomingByte);
Serial.print(" ");
Serial.println(incomingByte, BIN);
}
}
}


No comments:

Post a Comment

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...