Go Down

Topic: Arduino based Palm portable keyboard (USB) (Read 3648 times) previous topic - next topic

Gatt427

Hello,
I had an old Palm portable keyboard lying around my house and I have been trying to modify it to work over USB so that I can use it with my phone. 
Instead of writing a driver which I do not have the expertise to do, I am trying to build an Arduino interface to go between the keyboard and phone. 
I am having an issue getting the keyboard to send it's initiation pulse, saying that it is powered. I do not even know if I am reading the data properly.   I have everything wired as stated on page six of this manual.http://www.splorp.com/pdf/stowawayhwref.pdf
This document also describes the base requirements for the keyboard interface. 
Can you guys please help me figure out what I am doing wrong?
I have been working on this for over a year and would really like to get it working before September!
Code written for Arduino Micro but tested on Arduino Uno (No keyboard emulation)
Code: [Select]
#include <SoftwareSerial.h>;
#include <Keyboard.h>;

char KEY_LEFT_CTRL =128;
char KEY_LEFT_SHIFT =129;
char KEY_LEFT_ALT =130;
char KEY_LEFT_GUI =131;
char KEY_RIGHT_CTRL =132;
char KEY_RIGHT_SHIFT =133;
char KEY_RIGHT_ALT =134;
char KEY_RIGHT_GUI =135;
char KEY_UP_ARROW =218;
char KEY_DOWN_ARROW =217;
char KEY_LEFT_ARROW =216;
char KEY_RIGHT_ARROW =215;
char KEY_BACKSPACE =178;
char KEY_TAB         =179;
char KEY_RETURN         =176;
char KEY_ESC         =177;
char KEY_INSERT         =209;
char KEY_DELETE         =212;
char KEY_PAGE_UP        =211;
char KEY_PAGE_DOWN      =214;
char KEY_HOME           =210;
char KEY_END         =213;
char KEY_CAPS_LOCK      =193;
char KEY_F1         =194;
char KEY_F2         =195;
char KEY_F3         =196;
char KEY_F4         =197;
char KEY_F5         =198;
char KEY_F6         =199;
char KEY_F7         =200;
char KEY_F8         =201;
char KEY_F9         =202;
char KEY_F10         =203;

char keys[8][12] = {{'1',KEY_LEFT_GUI,'x',KEY_CAPS_LOCK,0,0,'-','[','\\',0,KEY_DELETE,KEY_LEFT_SHIFT},
                    {'2','q','a',KEY_TAB,0,0,'=',']',KEY_RETURN,KEY_UP_ARROW,KEY_LEFT_ARROW,KEY_RIGHT_SHIFT},
                    {'3','w','s',KEY_LEFT_CTRL,0,0,KEY_BACKSPACE,'/',0,0,KEY_DOWN_ARROW,0},
                    {'z','e','d',0,KEY_LEFT_ALT,0,0,0,0,0,KEY_RIGHT_ARROW,0},
                    {'4','r','f',0,0,'c','8','u','j','m',0,0},
                    {'5','t','g',0,0,'v','9','i','k',',',0},
                    {'6','y','h',0,0,'b','0','o','l','.',0,0},
                    {'7','`',' ',0,0,'n',' ','p',';',0,0,0}};  //This is the full keymatrix from the manufacturer.
/*char capitolKeys[8][12] = {{'!',KEY_LEFT_GUI,'X',KEY_CAPS_LOCK,0,0,'_','{','\"','?',KEY_DELETE,KEY_LEFT_SHIFT},
                    {'@','Q','A',KEY_TAB,0,0,'+','}',KEY_RETURN,KEY_UP_ARROW,KEY_LEFT_ARROW,KEY_TRIGHT_SHIFT},
                    {'#','W','S',KEY_LEFT_CTRL,0,0,KEY_BACKSPACE,'|',0,0,KEY_DOWN_ARROW,0},
                    {'Z','E','D',0,KEY_LEFT_ALT,0,0,0,0,0,KEY_RIGHT_ARROW,0},
                    {'$','R','F',0,0,'C','8','U','J','M',0,0},
                    {'%','T','G',0,0,'V','9','I','K','<',0,0},
                    {'^','Y','H',0,0,'B','0','O','L','>',0,0},
                    {'&','~',' ',0,0,'N',' ','P',':',0,0,0}};  //capitols unused at the moment because I think that sending shift and a key in conjunction will cover that, and this was causing other errors.*/
//const int VCC = 0; //power //wired to 5v out instead
const int RXD = 4; //output signal of keyboard (RX)
const int RTS = 5; //input signal to keyboard  (TX)
const int HotSync = 2;//output used for handshake (bi directional?)(NOT BIDIRECTOIONAL)
const int VCC = 3; //power line for keyboard;
SoftwareSerial softSerial = SoftwareSerial(RXD, RTS);
boolean on = false;
boolean isLast = false;
int keyCount = 0;
int LSB = 0;
int YADD = 0;
int XADD = 0;
int lastKey = 0;
int data[2];
char buffer[8];
int RTSState = LOW;

void setup(){
  pinMode(RXD, INPUT);
  pinMode(RTS, OUTPUT);
  pinMode(HotSync, INPUT);
  pinMode(VCC, OUTPUT);
  Serial.begin(9600);
  softSerial.begin(9600);
  //Keyboard.begin();
  keyCount=0;
}

void loop(){
  while(!on){ //on preboot
    Serial.println("Checking for initiation pulse");
    digitalWrite(VCC, HIGH); //poke it for sync
    while(digitalRead(HotSync)==LOW){}//wait for initiation pulse
    Serial.println("Pulse recieved");
    Serial.println("Checking for keyboard");
    checkForKeyboard();
  }
  //start detecting key presses
  if(keyCount==10){
    Serial.println("10 keys, checking for keyboard");
    checkForKeyboard();//safety, check for keyboard every 10 keys
    keyCount=0;
  }
  Serial.print("reading next byte: ");
  if(softSerial.available()){
    int data = softSerial.read(); //this reads ONLY the next byte
    Serial.println(data);
    LSB=0; //last bit
    YADD=0; //four bits after first three
    XADD=0;//first three bits
    sprintf(buffer, "%03i", data);
    LSB = buffer[7]; //split all the bits into their respective chunks
    for(int x=3;x<7;x++)
      YADD =+ buffer[x];
    for(int x=0;x<3;x++)
      XADD =+ buffer[x];
      Serial.print("LSB: ");Serial.println(LSB,BIN);
      Serial.print("YADD: ");Serial.println(YADD,BIN);
      Serial.print("XADD: ");Serial.println(XADD,BIN);
    if(lastKey==data){ //double release is keyboard code for last key in stream, this is when you are supposed to kill all modifiers
    Serial.println("Last key, releasing all keys");
      //Keyboard.releaseAll();
    }
    if(LSB==0){//if the key state is pressed
      Serial.print("Press: ");
      Serial.println(keys[XADD][YADD]);
      //Keyboard.release(keys[XADD][YADD]);  //press the key
    }else{ //if key state is released
      Serial.print("Release: ");
      Serial.println(keys[XADD][YADD]);
      //Keyboard.press(keys[XADD][YADD]); //release the key
    }
    lastKey=data; //store current key for last key check
    keyCount++;//add until 10 keys for keyboard check
  }else{Serial.println("overflow/not available");}
}

void checkForKeyboard(){ //this is hardware spec
    if(RTSState==LOW){ //if board is is sleep state
      digitalWrite(RTS, HIGH);  //send wake pulse
      RTSState=HIGH;
    }else{
      digitalWrite(RTS, LOW);
      digitalWrite(RTS, HIGH);//if you see low (keyboard went into low power mode) wake it up with a high
      RTSState=HIGH;
    }
    while(softSerial.available()>0){
        int x=0;
        data[x] = softSerial.read(); //read the return message
        x++;
    }
      Serial.print(data[0], HEX);Serial.println(data[1], HEX);
      if((data[0] == (int)0xFA) &&(data[1] == (int)0xFD)){ //identify return key (ID), if it is the keyboard, allow key read operations
       on=true;
       Serial.println("Found it!");
      }else{
        digitalWrite(RTS, LOW); //if it does not return a valid ID, shut everything down, the board is disconnected.
        RTSState=LOW; 
        //Keyboard.end();
        Serial.println("no keyboard, shutting down");
      }
      //delay(1000); //no idea why I need this, I think it is for buffer overload or board catchup. (seems to help)
    delay(1000);
}

Grumpy_Mike

Quote
Can you guys please help me figure out what I am doing wrong?
Page 15 says that the Palm keyboard uses RS232. Have you attached this directly to the Arduino? If so that is your problem. You need an RS232 to TTL converter chip before the Arduino can read it.

Gatt427

your problem. You need an RS232 to TTL converter chip before the Arduino can read it.
So, currently I am trying to send/read data of the wrong type?  That would explain why the keyboard is ignoring my connection requests.  I will get a RS232 chip and give you an update.

Two questions before I do:  
Is it possible that I hurt the board by giving it signals that where not RS232?
Am I handling the data correctly from the converter chip, or do I need to modify my code a bit? (If changes are required, can you give me a hint as to what?)

Thanks

Gatt427

Ok, so I made a MAX232 using this diagram
that I found on http://www.scienceprog.com/alternatives-of-max232-in-low-budget-projects/

Now, the circuit sends power to the keyboard, get's the Hotsync return pulse, then starts the keyboard authentication phase.   The authentication key is supposed to be 0xFAFD, the keyboard is actually sending 0xFC00 and 0xF800 randomly alternating between the two choices with each iteration.  If I tweak the code to accept the 0xFC00 combination it runs to the byte reading section (determining keys), then determines that the SoftwareSerial is not available and "crashes" (the first step).

Any ideas?

Grumpy_Mike

Note that your handshaking lines like DCD and RTS are also RS232 standards. So you will need a converter for those signals if you want or read or write them. Note that on RS232 there is no logic inversion on the signals but the voltage range is still outside the Arduino's signal range. You can compensate for the voltage inversion in the software.

Quote
Is it possible that I hurt the board by giving it signals that where not RS232?
You will not damage the keyboard if you send it signals that are not RS232, but you might very well damage the Arduino if you feed RS232 signals into it. This is because an RS232 has a voltage range of +/- 5V to +/- 12V and it is not only the excessive +ve voltage but also any -ve voltage is potentially going to damage the Arduino.


Quote
The authentication key is supposed to be 0xFAFD, the keyboard is actually sending 0xFC00 and 0xF800
I think this is where you might need a scope to see what is actually happening. It looks to me as if the baud rate is wrong although the data sheet seems to say you have it right.

Gatt427

I don't understand.  The DCD line (Hotsync) is just sending low/high values, and the board seems to be reading those appropriately.  If the DCD line is RS232, how would I go about wiring that in?  

So, negative voltage on the Arduino could have damaged the components, is there a way to test for that?
(That could explain the faulty Hex values).

I will try to check the baud rate, on the two devices.  The Arduino is also outputting to virtual serial, so is it possible that is interfering (They share a rate if I remember correctly)

Grumpy_Mike

Quote
The DCD line (Hotsync) is just sending low/high values,
Yes but RS232 HIGH and LOW, which is +12V for HIGH and -12V for LOW. This can damage the Arduino.

Quote
is there a way to test for that?
Yes, remove the line from the Arduino and directly measure the voltage with a meter.

Quote
The Arduino is also outputting to virtual serial, so is it possible that is interfering
Where is that connected to?

Gatt427

Yes but RS232 HIGH and LOW, which is +12V for HIGH and -12V for LOW. This can damage the Arduino.
I am only feeding it 5v, is that an issue?  

Yes, remove the line from the Arduino and directly measure the voltage with a meter.
sends out 4.9v-5v perfectly fine.

Where is that connected to?
Hardware serial is connected to PC and gives me my console output,
Software serial is what the RS232 is feeding into.


As far as the baud rate, both are the same, confirmed with my scope.  

I realized that I was missing a wire in the RS232 to TTL circuit... It was the lead going from the RD/R2 junction to Q2.  Placing that wire changes the return serial from 0xFC00/0xF800 to 0x0000 consistently.  I wish there was a way for me to post a picture of my circuit.


Grumpy_Mike

While it sends out 5V for high what does it send for low?

Have you looked at the output on your scope when it is disconnected from the Arduino?

If you use the reply button there is an option triangle in the left hand lower corner that will allow to attach a photograph.

Gatt427

#9
Aug 17, 2015, 03:13 pm Last Edit: Aug 17, 2015, 03:16 pm by Gatt427
pin 5 (RTS) seems to be dead, it is not sending any voltage.
I was using quick reply before, thanks for the tip.

Here is my circuit, On the right hand side the middle yellow wire is the one that I had omitted before.

nickjb

#10
Nov 12, 2015, 01:56 pm Last Edit: Nov 12, 2015, 05:49 pm by nickjb
A bit of a thread resurrection. No idea if you are still working on this or finished or given up...

I have the same keyboard and have been thinking about a similar project when I stumbled on this. One moring wasted and I have some success. Rather than build a circuit with transistors I have bought a max232 module, it was cheap from ebay. Rather than use the TX circuit as you seem to be doing this chip has  CTS and RTS which is what I think the keyboard uses on pin 4.  Using a meter I get -9v for low and +9v for high. I did wonder about trying 0 and 5v straight from the Arduino but this is working for me. I've rigged it all up a bit ad-hoc but it now works.

I've had to change a few things, firstly I couldn't get RX to work on pin4, I don't know if this is a Leonardo thing or if I killed it while tinkering.
Secondly I've skipped the handshaking. I'm getting The hex ID string FA FD, which is correct but I'm just ignoring it for now to get it working.
Finally your parsing of the string didn't work for me. I've used >> and << to shift the bytes around to get the LSB etc. I'm sure a professional coder will look at this in horror but it works :)

Pretty happy with it now! Thanks for your help getting me started, hope this helps you

Here's my modified version of your code
Code: [Select]
#include <SoftwareSerial.h>;
#include <Keyboard.h>;

/*char KEY_LEFT_CTRL =128;
 char KEY_LEFT_SHIFT =129;
 char KEY_LEFT_ALT =130;
 char KEY_LEFT_GUI =131;
 char KEY_RIGHT_CTRL =132;
 char KEY_RIGHT_SHIFT =133;
 char KEY_RIGHT_ALT =134;
 char KEY_RIGHT_GUI =135;
 char KEY_UP_ARROW =218;
 char KEY_DOWN_ARROW =217;
 char KEY_LEFT_ARROW =216;
 char KEY_RIGHT_ARROW =215;
 char KEY_BACKSPACE =178;
 char KEY_TAB        =179;
 char KEY_RETUR         =176;
 char KEY_ESC        =177;
 char KEY_INSERT         =209;
 char KEY_DELETE         =212;
 char KEY_PAGE_UP        =211;
 char KEY_PAGE_DOWN      =214;
 char KEY_HOME           =210;
 char KEY_END        =213;
 char KEY_CAPS_LOCK      =193;
 char KEY_F1        =194;
 char KEY_F2        =195;
 char KEY_F3        =196;
 char KEY_F4        =197;
 char KEY_F5        =198;
 char KEY_F6        =199;
 char KEY_F7        =200;
 char KEY_F8        =201;
 char KEY_F9        =202;
 char KEY_F10        =203; */ //Won't compile with this for some reason

char keys[8][12] = {
  {
    '1',KEY_LEFT_GUI,'x',KEY_CAPS_LOCK,0,0,'-','[','\\',0,KEY_DELETE,KEY_LEFT_SHIFT  }
  ,
  {
    '2','q','a',KEY_TAB,0,0,'=',']',KEY_RETURN,KEY_UP_ARROW,KEY_LEFT_ARROW,KEY_RIGHT_SHIFT  }
  ,
  {
    '3','w','s',KEY_LEFT_CTRL,0,0,KEY_BACKSPACE,'/',0,0,KEY_DOWN_ARROW,0  }
  ,
  {
    'z','e','d',0,KEY_LEFT_ALT,0,0,0,0,0,KEY_RIGHT_ARROW,0  }
  ,
  {
    '4','r','f',0,0,'c','8','u','j','m',0,0  }
  ,
  {
    '5','t','g',0,0,'v','9','i','k',',',0  }
  ,
  {
    '6','y','h',0,0,'b','0','o','l','.',0,0  }
  ,
  {
    '7','`',' ',0,0,'n',' ','p',';',0,0,0  }
};  //This is the full keymatrix from the manufacturer.
/*char capitolKeys[8][12] = {{'!',KEY_LEFT_GUI,'X',KEY_CAPS_LOCK,0,0,'_','{','\"','?',KEY_DELETE,KEY_LEFT_SHIFT},
 {'@','Q','A',KEY_TAB,0,0,'+','}',KEY_RETURN,KEY_UP_ARROW,KEY_LEFT_ARROW,KEY_TRIGHT_SHIFT},
 {'#','W','S',KEY_LEFT_CTRL,0,0,KEY_BACKSPACE,'|',0,0,KEY_DOWN_ARROW,0},
 {'Z','E','D',0,KEY_LEFT_ALT,0,0,0,0,0,KEY_RIGHT_ARROW,0},
 {'$','R','F',0,0,'C','8','U','J','M',0,0},
 {'%','T','G',0,0,'V','9','I','K','<',0,0},
 {'^','Y','H',0,0,'B','0','O','L','>',0,0},
 {'&','~',' ',0,0,'N',' ','P',':',0,0,0}};  //capitols unused at the moment because I think that sending shift and a key in conjunction will cover that, and this was causing other errors.*/
//const int VCC = 0; //power //wired to 5v out instead
const int RXD = 8; //output signal of keyboard (RX)
const int RTS = 5; //input signal to keyboard  (CTS)  CTS on rs232 chip to RTS on keyboard
const int HotSync = 2;//output used for handshake (bi directional?)(NOT BIDIRECTOIONAL)
const int VCC = 3; //power line for keyboard;
SoftwareSerial softSerial = SoftwareSerial(RXD, RTS);
boolean on = false;
boolean isLast = false;
int keyCount = 0;
byte LSB = 0;
byte YADD = 0;
byte XADD = 0;
int lastKey = 0;
int data[2];
char buffer[8];
int RTSState = LOW;

int testmode = 0;

void setup(){
  delay(3000); //delay to allpow me start serial monitor
  Serial.println("I am starting");
  pinMode(RXD, INPUT);
  pinMode(RTS, OUTPUT);
  pinMode(HotSync, INPUT);
  pinMode(VCC, OUTPUT);
  Serial.begin(9600);
  softSerial.begin(9600);
  //Keyboard.begin();
  keyCount=0;
      digitalWrite(VCC, HIGH);
}

void loop(){
  if (testmode < 3)testmode = 2;

  if (testmode ==1){
    int xx = digitalRead(HotSync);

    Serial.print("hotsync = ");
    Serial.println(xx);

    if (xx == 1){
      Serial.println("keyboard detected");

      Serial.println("RTS Low");
      digitalWrite(RTS, HIGH);  //send wake pulse
      delay(100);
      Serial.println("RTS High");
      digitalWrite(RTS, LOW);

    }

    while(softSerial.available()>0){
      Serial.println("I am here");
      int x=0;
      data[x] = softSerial.read(); //read the return message
      x++;
      Serial.print(data[0], HEX);
      Serial.println(data[1], HEX);
    }

    delay(100);
  } //testmode 1

  if (testmode == 2){ 

    Serial.println("RTS Low");
    digitalWrite(RTS, HIGH);  //send wake pulse


    delay (3000);

    Serial.println("RTS High");
    digitalWrite(RTS, LOW);
    delay (500);
    testmode=4;
  }//testmode 2


  if (testmode == 3){ 

    while(softSerial.available()>0){

      int x=0;
      data[x] = softSerial.read(); //read the return message
      x++;
      Serial.print("+");
      Serial.print(data[0], HEX);
      Serial.print(" ");
      Serial.println(data[1], HEX);
    }
  }

  if (testmode == 4){ 

    if(softSerial.available()){
      int data = softSerial.read(); //this reads ONLY the next byte
     
      LSB=data >> 7; //last bit
      YADD=(data >> 3) - (LSB << 4); //four bits after first three
      XADD=data << 5;
      XADD=XADD >> 5;//first three bits
      Serial.print("RAW = ");
      Serial.print(data,BIN);
      Serial.print(" LSB: ");
      Serial.print(LSB,BIN);
      Serial.print(" YADD: ");
      Serial.print(YADD,DEC);
      Serial.print(" XADD: ");
      Serial.println(XADD,DEC);
      if(lastKey==data){ //double release is keyboard code for last key in stream, this is when you are supposed to kill all modifiers
        Serial.println("Last key, releasing all keys");
        //Keyboard.releaseAll();
      }
      if(LSB==0){//if the key state is pressed
        Serial.print("Press: ");
        Serial.println(keys[XADD][YADD]);
        //Keyboard.release(keys[XADD][YADD]);  //press the key
      }
      else{ //if key state is released
        Serial.print("Release: ");
        Serial.println(keys[XADD][YADD]);
        //Keyboard.press(keys[XADD][YADD]); //release the key
      }
      lastKey=data; //store current key for last key check
      keyCount++;//add until 10 keys for keyboard check
    }
  }


void checkForKeyboard(){ //this is hardware spec
  if(RTSState==LOW){ //if board is is sleep state
    Serial.println("RTS Low");
    digitalWrite(RTS, HIGH);  //send wake pulse
    RTSState=HIGH;
  }
  else{
    Serial.println("RTS High");
    digitalWrite(RTS, LOW);
    digitalWrite(RTS, HIGH);//if you see low (keyboard went into low power mode) wake it up with a high
    RTSState=HIGH;
  }
  while(softSerial.available()>0){
    Serial.println("I am here");
    int x=0;
    data[x] = softSerial.read(); //read the return message
    x++;
  }
  Serial.print(data[0], HEX);
  Serial.println(data[1], HEX);
  if((data[0] == (int)0xFA) &&(data[1] == (int)0xFD)){ //identify return key (ID), if it is the keyboard, allow key read operations
    on=true;
    Serial.println("Found it!");
  }
  else{
    digitalWrite(RTS, LOW); //if it does not return a valid ID, shut everything down, the board is disconnected.
    RTSState=LOW; 
    //Keyboard.end();
    Serial.println("no keyboard, shutting down");
  }
  //delay(1000); //no idea why I need this, I think it is for buffer overload or board catchup. (seems to help)
  delay(1000);
}


This is the circuit


Just bodged together for now:


Here is the output from the serial port:


PS The LSB is actually the MSB but I've kept it as your original code

nickjb

#11
Nov 12, 2015, 05:00 pm Last Edit: Nov 12, 2015, 05:58 pm by nickjb
Here is a version of the code that works as a keyboard when plugged into a PC. In fact I'm typing this on it. Still need to remap some of the keys £.#~ etc all seem to be in the wrong place (US/UK keyboard issue which might be easier to fix with stickers) but basic typing is fine.

Code: [Select]
#include <SoftwareSerial.h>;
#include <Keyboard.h>;

char keys[8][12] = {
  {
    '1',KEY_LEFT_GUI,'x',KEY_CAPS_LOCK,0,0,'-','[','\\',0,KEY_DELETE,KEY_LEFT_SHIFT    }
  ,
  {
    '2','q','a',KEY_TAB,0,0,'=',']',KEY_RETURN,KEY_UP_ARROW,KEY_LEFT_ARROW,KEY_RIGHT_SHIFT    }
  ,
  {
    '3','w','s',KEY_LEFT_CTRL,0,0,KEY_BACKSPACE,'/',0,0,KEY_DOWN_ARROW,0    }
  ,
  {
    'z','e','d',0,KEY_LEFT_ALT,0,0,0,0,0,KEY_RIGHT_ARROW,0    }
  ,
  {
    '4','r','f',0,0,'c','8','u','j','m',0,0    }
  ,
  {
    '5','t','g',0,0,'v','9','i','k',',',0    }
  ,
  {
    '6','y','h',0,0,'b','0','o','l','.',0,0    }
  ,
  {
    '7','`',' ',0,0,'n',' ','p',';',0,0,0    }
};  //This is the full keymatrix from the manufacturer.
/*char capitolKeys[8][12] = {{'!',KEY_LEFT_GUI,'X',KEY_CAPS_LOCK,0,0,'_','{','\"','?',KEY_DELETE,KEY_LEFT_SHIFT},
 {'@','Q','A',KEY_TAB,0,0,'+','}',KEY_RETURN,KEY_UP_ARROW,KEY_LEFT_ARROW,KEY_TRIGHT_SHIFT},
 {'#','W','S',KEY_LEFT_CTRL,0,0,KEY_BACKSPACE,'|',0,0,KEY_DOWN_ARROW,0},
 {'Z','E','D',0,KEY_LEFT_ALT,0,0,0,0,0,KEY_RIGHT_ARROW,0},
 {'$','R','F',0,0,'C','8','U','J','M',0,0},
 {'%','T','G',0,0,'V','9','I','K','<',0,0},
 {'^','Y','H',0,0,'B','0','O','L','>',0,0},
 {'&','~',' ',0,0,'N',' ','P',':',0,0,0}};  //capitols unused at the moment because I think that sending shift and a key in conjunction will cover that, and this was causing other errors.*/
//const int VCC = 0; //power //wired to 5v out instead
const int RXD = 8; //output signal of keyboard (RX)
const int RTS = 5; //input signal to keyboard  (CTS)  CTS on rs232 chip to RTS on keyboard
const int HotSync = 2;//output used for handshake (bi directional?)(NOT BIDIRECTOIONAL)
const int VCC = 3; //power line for keyboard;
SoftwareSerial softSerial = SoftwareSerial(RXD, RTS);
boolean on = false;
boolean isLast = false;
int keyCount = 0;
byte MSB = 0;
byte YADD = 0;
byte XADD = 0;
int lastKey = 0;
int data[2];
char buffer[8];
int RTSState = LOW;

int testmode = 0;

void setup(){
  //delay(3000); //delay to allow me start serial monitor
  //Serial.println("I am starting");
  pinMode(RXD, INPUT);
  pinMode(RTS, OUTPUT);
  pinMode(HotSync, INPUT);
  pinMode(VCC, OUTPUT);
  //Serial.begin(9600);
  softSerial.begin(9600);
  Keyboard.begin();
  keyCount=0;
  digitalWrite(VCC, HIGH);
}

void loop(){
  if (testmode < 3)testmode = 2;

  if (testmode ==1){
    int xx = digitalRead(HotSync);

    //Serial.print("hotsync = ");
    //Serial.println(xx);

    if (xx == 1){
      //Serial.println("keyboard detected");

      //Serial.println("RTS Low");
      digitalWrite(RTS, HIGH);  //send wake pulse
      //delay(100);
      //Serial.println("RTS High");
      digitalWrite(RTS, LOW);

    }

    while(softSerial.available()>0){
      //Serial.println("I am here");
      int x=0;
      data[x] = softSerial.read(); //read the return message
      x++;
      //Serial.print(data[0], HEX);
      //Serial.println(data[1], HEX);
    }

    delay(100);
  } //testmode 1

  if (testmode == 2){ 

    //Serial.println("RTS Low");
    digitalWrite(RTS, HIGH);  //send wake pulse


    delay (1500);

    //Serial.println("RTS High");
    digitalWrite(RTS, LOW);
    delay (100);
    testmode=4;
  }//testmode 2


  if (testmode == 3){ 

    while(softSerial.available()>0){

      int x=0;
      data[x] = softSerial.read(); //read the return message
      x++;
      //Serial.print("+");
      //Serial.print(data[0], HEX);
      //Serial.print(" ");
      //Serial.println(data[1], HEX);
    }
  }// end of 3

  if (testmode == 4){ 

    if(softSerial.available()){
      int data = softSerial.read(); //this reads ONLY the next byte

      MSB=data >> 7; //first bit
      YADD=(data >> 3) - (MSB << 4); //four bits after first three
      XADD=data << 5;
      XADD=XADD >> 5;//first three bits
      //Serial.print("RAW = ");
      //Serial.print(data,BIN);
      //Serial.print(" MSB: ");
      //Serial.print(MSB,BIN);
      //Serial.print(" YADD: ");
      //Serial.print(YADD,DEC);
      //Serial.print(" XADD: ");
      //Serial.println(XADD,DEC);
      if(lastKey==data){ //double release is keyboard code for last key in stream, this is when you are supposed to kill all modifiers
        //Serial.println("Last key, releasing all keys");
        Keyboard.releaseAll();
      }
      if(MSB==0){//if the key state is pressed
        //Serial.print("Press: ");
        //Serial.println(keys[XADD][YADD]);
        Keyboard.press(keys[XADD][YADD]);//press the key
      }
      else{ //if key state is released
        //Serial.print("Release: ");
        //Serial.println(keys[XADD][YADD]);
        Keyboard.release(keys[XADD][YADD]);  //release the key
      }
      lastKey=data; //store current key for last key check
      keyCount++;//add until 10 keys for keyboard check
    }
  }// end of 4
}

DuaneDegn

Thanks for sharing this nickjb. I have one of these keyboards and I'll likely try your code.

st2000

Lot's of good stuff in this thread....  Except, I'm confused about why there is talk that the voltages out of the keyboard are at RS232 levels (that is, as high as +12 to -12 volts).  @Grumpy_Mike stated that on page 15 of the keyboard manual it says the keyboard uses RS232.  Which is followed by a lot of (unnecessary??) posts about RS232 level converters. 

What page 15 actually says is: "Data is sent in TTL format, not RS-232 format.  For example, logic level 1 is HIGH for this transmission, whereas in a full fledge RS-232 serial transmission the data is sent inverted and the RS-232 transceiver at in the device handles it. "

I'll go one further.  Since the keyboard is leaching power from a host device that normally runs at 3V, I expect the output of the keyboard doesn't even reach TTL (usually 0V and 5V) level.  But rather swings between 0V to 3V levels.  If so, the hardware should just work as is.  Which would explain @nickjb success as his post infers he has all this working with out mentioning any additional hardware.

I know this thread is old.  But I'd like to hear back from some of the participants as I'm close to trying this same project out  my self.


marcsulf

st2000:

Please note that the quote you are referring to on page 15 is for the Handspring Keyboard ONLY.  On page 14, for the Palm and PocketPC Keyboards it states:

Palm and PocketPC Keyboards
Data is sent at RS-232 level.

I had thought this was odd, as well, based on the fact that the keyboard draws power from the device, which runs at 3.3V.  It would be possible using appropriate boosting/charge pumping, though, so I would definitely check the signals out on a scope before proceeding.

Note, also, that in nickjb's first post (#10) he does show that he is indeed using a MAX232 to convert between RS-232 and TTL.

Go Up