-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathps2.cpp
150 lines (140 loc) · 2.9 KB
/
ps2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* ps2.cpp - an interface library for ps2 devices. Common devices are
* mice, keyboard, barcode scanners etc. See the examples for mouse and
* keyboard interfacing.
* limitations:
* we do not handle parity errors.
* The timing constants are hard coded from the spec. Data rate is
* not impressive.
* probably lots of room for optimization.
*/
#include "ps2.h"
/*
* the clock and data pins can be wired directly to the clk and data pins
* of the PS2 connector. No external parts are needed.
*/
PS2::PS2(int clk, int data)
{
_ps2clk = clk;
_ps2data = data;
gohi(_ps2clk);
gohi(_ps2data);
}
/*
* according to some code I saw, these functions will
* correctly set the clock and data pins for
* various conditions. It's done this way so you don't need
* pullup resistors.
*/
void
PS2::gohi(int pin)
{
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
}
void
PS2::golo(int pin)
{
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
/* write a byte to the PS2 device */
void
PS2::write(unsigned char data)
{
unsigned char i;
unsigned char parity = 1;
gohi(_ps2data);
gohi(_ps2clk);
delayMicroseconds(300);
golo(_ps2clk);
delayMicroseconds(300);
golo(_ps2data);
delayMicroseconds(10);
gohi(_ps2clk); // start bit
/* wait for device to take control of clock */
while (digitalRead(_ps2clk) == HIGH)
; // this loop intentionally left blank
// clear to send data
for (i=0; i < 8; i++)
{
if (data & 0x01)
{
gohi(_ps2data);
} else {
golo(_ps2data);
}
// wait for clock
while (digitalRead(_ps2clk) == LOW)
;
while (digitalRead(_ps2clk) == HIGH)
;
parity = parity ^ (data & 0x01);
data = data >> 1;
}
// parity bit
if (parity)
{
gohi(_ps2data);
} else {
golo(_ps2data);
}
// clock cycle - like ack.
while (digitalRead(_ps2clk) == LOW)
;
while (digitalRead(_ps2clk) == HIGH)
;
// stop bit
gohi(_ps2data);
delayMicroseconds(50);
while (digitalRead(_ps2clk) == HIGH)
;
// mode switch
while ((digitalRead(_ps2clk) == LOW) || (digitalRead(_ps2data) == LOW))
;
// hold up incoming data
golo(_ps2clk);
}
/*
* read a byte of data from the ps2 device. Ignores parity.
*/
unsigned char
PS2::read(void)
{
unsigned char data = 0x00;
unsigned char i;
unsigned char bit = 0x01;
// start clock
gohi(_ps2clk);
gohi(_ps2data);
delayMicroseconds(50);
while (digitalRead(_ps2clk) == HIGH)
;
delayMicroseconds(5); // not sure why.
while (digitalRead(_ps2clk) == LOW)
; // eat start bit
for (i=0; i < 8; i++)
{
while (digitalRead(_ps2clk) == HIGH)
;
if (digitalRead(_ps2data) == HIGH)
{
data = data | bit;
}
while (digitalRead(_ps2clk) == LOW)
;
bit = bit << 1;
}
// eat parity bit, ignore it.
while (digitalRead(_ps2clk) == HIGH)
;
while (digitalRead(_ps2clk) == LOW)
;
// eat stop bit
while (digitalRead(_ps2clk) == HIGH)
;
while (digitalRead(_ps2clk) == LOW)
;
golo(_ps2clk); // hold incoming data
return data;
}