Pages: [1]   Go Down
Author Topic: PS/2 Keyboard Emulator Issues  (Read 1495 times)
0 Members and 1 Guest are viewing this topic.
Folsom, CA
Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes, I've searched the forums.  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 http://www.computer-engineering.org/. Yes, I have this working, kinda.  I need some ideas for making the leap to fully working.  smiley

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 forum post, http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1247772275/15) 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?

Code:
#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);
    }
  }
}
Logged

Folsom, CA
Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm, I may be able to make that happen.  I don't really have access to an o-scope at home, but at work I do.

I agree, the protocol should be the same for both manufacturers--or else it wouldn't be a protocol. smiley That's the exact same reason which has led me to believe that the ps2dev library needs to be re-coded to be more robust--I just don't want to reinvent the wheel on that one if someone has done it already.
Logged

Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Starting with royboy's code and pictures
http://siliconrepublic.blogspot.com/2010/08/arduino-based-human-interface-device.html
it tried my luck to implement a keyboard
emulator to send the results from my PSC barcode
scanner to the pc via a simple PS/2 plug.
Platform was an Arduino Nano and Win XP.

Good news is: It works.
But the project took me two days to reach the
"usable" status.

According to my quick research many others had
problems getting their project to run:

http://arduino.cc/forum/index.php/topic,19224.15.html
http://arduino.cc/forum/index.php/topic,60574.0.html

In my case the stumbling blocks were numerous:

1) The ps2dev library documentation is very basic. No hint
is given where to start when the emulator doesn't work.
The included sample code just covers a PS/2 mouse.
2) Pull-up resistors were somewhere suggested but
unnecessary.
3) At the moment the project only works if you use
a PS/2-USB converter. Any attempt to use it directly
with a normal PS/2 port of the PC failed, even on
different machines.
4) The library is sensitive concerning timing. The
use of the standard Serial library (to get debug information)
 caused an invisible, but serious problem.
5) I tried various sketches published but in the end
only royboy's worked. At the moment I can't say why.
6) The initialization of the PS/2 interface is not perfect.
I have to insert to USB plug twice to get the emulator to
transmit keyboard codes.
7) In my case I had to take the power from the PS/2 plug
not just the ground signal. That means that all four PS/2 signals
are connected (Power, Ground, Data, Clock).

To sum things up here is my way that proved passable:
- Start with the mouse sample  code using an USB-converter.
- Don't include timing relevant debugging messages via Serial.
- Unplug and plug the USB-PS/2 connector.
- Let the Arduino be powered via PS/2 and unplug the standard Arduino USB connector.

The next steps form me will be
1) Take a look at the PS/2 directly with a SUMP logic analyzer.
2) Fix the initialization
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

 my sketch smiley

it's work!

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

int enabled = 0; // pseudo variable for state of "keyboard"
int CLKpin = 3;
int DATApin = 5;
PS2dev keyboard(CLKpin, DATApin); // PS2dev object (2:data, 3:clock)
int todel=1;

String smbls="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`-=\\[];',./ ";
byte codes[49]={0x1C,0x32,0x21,0x23,0x24,0x2B,0x34,0x33,0x43,0x3B,0x42,0x4B,0x3A,0x31,0x44,0x4D,0x15,0x2D,0x1B,0x2C,0x3C,0x2A,0x1D,0x22,0x35,
0x1A,0x45,0x16,0x1E,0x26,0x25,0x2E,0x36,0x3D,0x3E,0x46,0x0E,0x4E,0x55,0x5D,0x54,0x5B,0x4C,0x52,0x41,0x49,0x4A,0x29};

void SendString(String str)
{
  //str=(str.toUpperCase());
  str.toUpperCase();
  int i=0;
  int n=0;//subarrays index
  while (str[i]!=0)
  {
    while ((str[i]!=smbls[n]) && smbls[n]!=0) n++;
    keyboard.write(codes[n]);
    delay(20);
    keyboard.write(0xF0); // send smbl
    delay(20);
    keyboard.write(codes[n]);
    delay(20);
    n=0;
    i++;
  }
 
};

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

int keyboardcommand(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
    Serial.println('Val = '+val);
    ack();
    break;
  }
}

void setup() {
  // send the keyboard start up
  while(keyboard.write(0xAA)!=0);
  delay(10);
}

void loop() {
  unsigned char c;
  //if host device wants to send a command:
  if( (digitalRead(CLKpin)==LOW) || (digitalRead(DATApin) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  }
  else{ //send keypresses accordingly using scancodes
  // secancodes: http://www.computer-engineering.org/ps2keyboard/scancodes2.html
  
  delay(5000);
  if (todel==1)
    {
    SendString("Karinka  ; ");
    todel=0;
    } // wait 1 second
  }
}
Logged

Pages: [1]   Go Up
Jump to: