Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
371 lines (282 sloc) 7.985 kb
#include <Adafruit_PS2_Trackpad.h>
/*
* an arduino sketch to interface with a ps/2 mouse.
* Also uses serial protocol to talk back to the host
* and report what it finds.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1251398431
*/
// protocol version 2 http://www.mjmwired.net/kernel/Documentation/input/alps.txt
Adafruit_PS2::Adafruit_PS2() {
}
Adafruit_PS2::Adafruit_PS2(uint8_t c, uint8_t d) {
constructor(c, d);
}
void Adafruit_PS2::constructor(uint8_t c, uint8_t d) {
_clk = c;
_data = d;
}
Adafruit_PS2_Mouse::Adafruit_PS2_Mouse(void) {
}
Adafruit_PS2_Mouse::Adafruit_PS2_Mouse(uint8_t c, uint8_t d) {
constructor(c, d);
}
Adafruit_PS2_Trackpad::Adafruit_PS2_Trackpad(uint8_t c, uint8_t d) {
constructor(c, d);
}
boolean Adafruit_PS2_Mouse::begin(void) {
if (! reset()) return false;
idle();
write(ADAFRUIT_PS2_SETPOLL); // we will poll the mouse
read();
delayMicroseconds(100);
inhibit();
}
boolean Adafruit_PS2_Mouse::reset(void) {
idle();
if (!command(ADAFRUIT_PS2_RESET)) return false;
if (read() != 0xAA) return false;
if (read() != 0x00) return false;
inhibit();
return true;
}
boolean Adafruit_PS2_Trackpad::begin(void) {
if (! reset()) return false;
// see http://www.win.tue.nl/~aeb/linux/kbd/scancodes-13.html sec 13.7
uint32_t e6 = E6Report();
uint8_t s1, s2, s3;
s1 = e6 >> 16;
s2 = e6 >> 8;
s3 = e6;
if (s3 != 0x64) return false; // not a trackpad?
if (s2 == 0) return false; // not a trackpad?
Serial.print("Trackpad found with ");
Serial.print(s2, DEC);
Serial.println(" buttons");
if (s1 & 0x80) // supports the e7 command report
E7Report();
if (!tapMode(false)) return false;
Serial.println("Tap mode set");
getStatus();
if (! absoluteMode()) return false;
Serial.println("Absolute mode set");
//if (!command(ADAFRUIT_PS2_SETPOLL)) return false;
//delay(1);
//if (!command(ADAFRUIT_PS2_SETSTREAMMODE)) return false;
inhibit();
return true;
}
uint32_t Adafruit_PS2_Trackpad::getStatus(void) {
uint8_t info[3];
Serial.print("Status: ");
if (!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_GETINFO))
return 0;
info[0] = read();
Serial.print(" 0x"); Serial.print(info[0], HEX);
info[1] = read();
Serial.print(" 0x"); Serial.print(info[1], HEX);
info[2] = read();
Serial.print(" 0x"); Serial.println(info[2], HEX);
return 1;
}
boolean Adafruit_PS2_Trackpad::tapMode(boolean enable) {
uint8_t cmd, arg;
if (enable) {
cmd = ADAFRUIT_PS2_SETRATE;
arg = 0x0A;
} else {
cmd = ADAFRUIT_PS2_SETRES;
arg = 0;
}
uint8_t info[3];
if (!command(ADAFRUIT_PS2_GETINFO)) return false;
info[0] = read();
Serial.println(info[0], HEX);
info[1] = read();
Serial.println(info[1], HEX);
info[2] = read();
Serial.println(info[2], HEX);
if (!command(ADAFRUIT_PS2_DISABLE)) return false;
if (!command(ADAFRUIT_PS2_DISABLE)) return false;
write(cmd);
write(arg);
//if (read() != ADAFRUIT_PS2_ACK) return false;
Serial.println(read(), HEX);
read();
return true;
}
uint32_t Adafruit_PS2_Trackpad::E6Report(void) {
write(ADAFRUIT_PS2_SETRES);
write(0x0); // argument for setres
write(ADAFRUIT_PS2_SETSCALE11);
write(ADAFRUIT_PS2_SETSCALE11);
write(ADAFRUIT_PS2_SETSCALE11);
if (!command(ADAFRUIT_PS2_GETINFO)) return 0x0;
uint8_t reply0, reply1, reply2;
reply0 = read();
reply1 = read();
reply2 = read();
Serial.print("E6 Reply: 0x"); Serial.print(reply0, HEX);
Serial.print(" 0x"); Serial.print(reply1, HEX);
Serial.print(" 0x"); Serial.println(reply2, HEX);
uint32_t reply = reply0;
reply <<= 8;
reply |= reply1;
reply <<= 8;
reply |= reply2;
return reply;
}
uint32_t Adafruit_PS2_Trackpad::E7Report(void) {
write(ADAFRUIT_PS2_SETRES);
write(0x0); // argument for setres
write(ADAFRUIT_PS2_SETSCALE21);
write(ADAFRUIT_PS2_SETSCALE21);
write(ADAFRUIT_PS2_SETSCALE21);
if (!command(ADAFRUIT_PS2_GETINFO)) return 0x0;
read();
uint8_t reply0, reply1, reply2;
reply0 = read();
reply1 = read();
reply2 = read();
Serial.print("E7 Reply: 0x"); Serial.print(reply0, HEX);
Serial.print(" 0x"); Serial.print(reply1, HEX);
Serial.print(" 0x"); Serial.println(reply2, HEX);
uint32_t reply = reply0;
reply <<= 8;
reply |= reply1;
reply <<= 8;
reply |= reply2;
return reply;
}
boolean Adafruit_PS2_Trackpad::absoluteMode(void) {
// alps magic knock, 4 disables before an enable
if (!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_DISABLE) ||
!command(ADAFRUIT_PS2_ENABLE))
return false;
if (! command(ADAFRUIT_PS2_SETPOLL)) return false;
delayMicroseconds(100);
return true;
}
boolean Adafruit_PS2_Trackpad::readData(void) {
//write(0x0F);
uint8_t packet[6];
for (uint8_t x=0; x<6; x++) {
packet[x] = read();
//Serial.print("0x"); Serial.print(packet[x], HEX); Serial.print("\t");
}
if (packet[0] != 0xF8) return false;
gesture = finger = left = right = middle = false;
if (packet[3] & 0x1) left = true;
if (packet[3] & 0x2) right = true;
if (packet[3] & 0x4) middle = true;
if (packet[2] & 0x2) finger = true;
if (packet[2] & 0x1) gesture = true;
if (gesture) {
//http://marc.info/?l=linux-kernel&m=110708138225873
//Serial.print(" Gesture! ");
}
x = packet[1] | ((packet[2] & 0x78) << 4);
y = packet[4] | ((packet[3] & 0x70) << 3);
z = packet[5];
// Serial.println();
return true;
}
boolean Adafruit_PS2_Mouse::readData(void) {
if (!command(ADAFRUIT_PS2_READDATA)) return false;
status = read();
middle = right = left = false;
if (status & 0x04) middle = true;
if (status & 0x02) right = true;
if (status & 0x01) left = true;
x = read();
y = read();
}
uint8_t Adafruit_PS2_Mouse::readID(void) {
if (!command(ADAFRUIT_PS2_GETDEVICEID)) return -1;
return read();
}
boolean Adafruit_PS2::command(uint8_t cmd) {
write(cmd);
return (read() == ADAFRUIT_PS2_ACK);
}
uint8_t Adafruit_PS2::read(void) {
uint16_t d = 0;
idle();
delayMicroseconds(50);
// wait for clock line to drop
// start bit + 8 bits data + parity + stop = 11 bits
for (uint8_t i=0; i<11; i++) {
while (digitalRead(_clk));
if (digitalRead(_data))
d |= _BV(i);
while (!digitalRead(_clk));
}
inhibit();
// drop start bit
d >>= 1;
//Serial.print("d = 0x");
//Serial.println(d, HEX);
// check parity & stop bit later?
return d & 0xFF;
}
void Adafruit_PS2::write(uint8_t x) {
uint16_t tosend = x;
uint8_t parity = 1;
for (uint8_t i=0; i<8; i++) {
parity ^= (tosend >> i);
}
if (parity & 0x1)
tosend |= 0x100;
idle();
delayMicroseconds(300);
low(_clk);
delayMicroseconds(100);
low(_data);
delayMicroseconds(10);
// we pull the clock line up to indicate we're ready
high(_clk);
// wait for the device to acknowledge by pulling it down
while (digitalRead(_clk));
for (uint8_t i=0; i < 9; i++) {
if (tosend & 0x1)
high(_data);
else
low(_data);
// the clock lines are driven by the -DEVICE- so we wait
while (!digitalRead(_clk));
while (digitalRead(_clk));
tosend >>= 1;
}
// send stop bit (high)
high(_data);
delayMicroseconds(50);
while (digitalRead(_clk));
// wait for mouse to switch modes
while (!digitalRead(_clk) || !digitalRead(_data));
// inhibit any more data (we will poll!)
inhibit();
}
void Adafruit_PS2::inhibit(void) {
high(_data);
low(_clk);
}
void Adafruit_PS2::idle(void) {
high(_clk);
high(_data);
}
// pull high
void Adafruit_PS2::high(uint8_t p) {
pinMode(p, INPUT);
digitalWrite(p, HIGH);
}
// drive low
void Adafruit_PS2::low(uint8_t p) {
digitalWrite(p, LOW);
pinMode(p, OUTPUT);
}
Jump to Line
Something went wrong with that request. Please try again.