1 | /*********************************************************************
|
---|
2 | // created: 2012/03/01 - 14:06
|
---|
3 | // filename: controller.cpp
|
---|
4 | //
|
---|
5 | // author: Pierre Hudelaine
|
---|
6 | // Copyright Heudiasyc UMR UTC/CNRS 7253
|
---|
7 | //
|
---|
8 | // version: $Id: $
|
---|
9 | //
|
---|
10 | // purpose: Read the dualshock 3 button using bluetooth
|
---|
11 | //
|
---|
12 | *********************************************************************/
|
---|
13 |
|
---|
14 | #include "controller.h"
|
---|
15 |
|
---|
16 | using namespace pacpus;
|
---|
17 |
|
---|
18 | DualshockAPI::DualshockAPI()
|
---|
19 | {
|
---|
20 | uid_t uid = getuid();
|
---|
21 | if(uid)
|
---|
22 | throw "Run as root and you will be happy :)";
|
---|
23 | bdaddr_t any = {{0, 0, 0, 0, 0, 0}};
|
---|
24 | csk = l2cap_listen(&any, L2CAP_PSM_HIDP_CTRL);
|
---|
25 | isk = l2cap_listen(&any, L2CAP_PSM_HIDP_INTR);
|
---|
26 | if(csk < 0 || isk < 0)
|
---|
27 | throw "Unable to listen on l2cap socket";
|
---|
28 | quit = 0;
|
---|
29 | controller.paired = 0;
|
---|
30 | shmem = new ShMem("dualshock", sizeof(struct dualshockButtons_s));
|
---|
31 | struct dualshockButtons_s d;
|
---|
32 | d.available = 0;
|
---|
33 | d.time = road_time();
|
---|
34 | shmem->write((void*)&d, sizeof(struct dualshockButtons_s), 0);
|
---|
35 | }
|
---|
36 |
|
---|
37 | int DualshockAPI::l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm)
|
---|
38 | {
|
---|
39 | int sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
|
---|
40 | if(sk < 0)
|
---|
41 | throw "Unable to open a socket";
|
---|
42 | struct sockaddr_l2 addr;
|
---|
43 | memset(&addr, 0, sizeof(addr));
|
---|
44 | addr.l2_family = AF_BLUETOOTH;
|
---|
45 | addr.l2_bdaddr = *bdaddr;//(bdaddr_t) {{0, 0, 0, 0, 0, 0}};
|
---|
46 | addr.l2_psm = htobs(psm);
|
---|
47 | if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
---|
48 | close(sk);
|
---|
49 | throw "Bind error";
|
---|
50 | }
|
---|
51 | if (listen(sk, 5) < 0)
|
---|
52 | throw "Listen error";
|
---|
53 | return sk;
|
---|
54 | }
|
---|
55 |
|
---|
56 | void DualshockAPI::update_shared_memory()
|
---|
57 | {
|
---|
58 | struct dualshockButtons_s d;
|
---|
59 | d.available = controller.paired;
|
---|
60 | d.timeout = controller.timeout;
|
---|
61 | d.buttons = controller.buttons;
|
---|
62 | d.time = road_time();
|
---|
63 | shmem->write((void*)&d, sizeof(struct dualshockButtons_s), 0);
|
---|
64 | dbtFile.writeRecord(d.time, 0, (const char*)&d,
|
---|
65 | sizeof(struct dualshockButtons_s));
|
---|
66 | }
|
---|
67 |
|
---|
68 | void DualshockAPI::main_loop()
|
---|
69 | {
|
---|
70 | //std::cerr << "Main loop\n";
|
---|
71 | while(!quit) {
|
---|
72 | fd_set fds;
|
---|
73 | FD_ZERO(&fds);
|
---|
74 | FD_SET(STDIN_FILENO, &fds);
|
---|
75 | int fdmax = 0;
|
---|
76 | FD_SET(csk, &fds);
|
---|
77 | FD_SET(isk, &fds);
|
---|
78 | fdmax = csk > isk ? csk : isk;
|
---|
79 | if(controller.paired) {
|
---|
80 | FD_SET(controller.csk, &fds);
|
---|
81 | if (controller.csk > fdmax)
|
---|
82 | fdmax = controller.csk;
|
---|
83 | FD_SET(controller.isk, &fds);
|
---|
84 | if (controller.isk > fdmax)
|
---|
85 | fdmax = controller.isk;
|
---|
86 | }
|
---|
87 | //std::cerr << " elem\n";
|
---|
88 | //std::cerr << "Select\n";
|
---|
89 | struct timeval tv = {0, 500 * 1000}; //timeout = 0.5s
|
---|
90 | int ret = 0;
|
---|
91 | ret = select(fdmax + 1, &fds, NULL, NULL, &tv);
|
---|
92 | if (ret < 0)
|
---|
93 | throw "Select";
|
---|
94 |
|
---|
95 | controller.timeout = (ret == 0 && controller.paired);
|
---|
96 |
|
---|
97 | if (FD_ISSET(csk, &fds))
|
---|
98 | handle_connection();
|
---|
99 | if (controller.paired && FD_ISSET(controller.isk, &fds)) {
|
---|
100 | unsigned char report[256];
|
---|
101 | int nr = recv(controller.isk, report, sizeof(report), 0);
|
---|
102 | if (nr <= 0)
|
---|
103 | handle_disconnection();
|
---|
104 | else
|
---|
105 | handle_report(report, nr);
|
---|
106 | }
|
---|
107 | update_shared_memory();
|
---|
108 | }
|
---|
109 | quit = 2;
|
---|
110 | }
|
---|
111 |
|
---|
112 | void DualshockAPI::stop()
|
---|
113 | {
|
---|
114 | quit = 1;
|
---|
115 | while(quit != 2) //avoid a race condition
|
---|
116 | ;
|
---|
117 | dbtFile.close();
|
---|
118 | }
|
---|
119 |
|
---|
120 | void DualshockAPI::handle_connection()
|
---|
121 | {
|
---|
122 | std::cerr << "Connection !\n";
|
---|
123 | static int currentIndex = 0;
|
---|
124 | int cs, is;
|
---|
125 | bdaddr_t baddr;
|
---|
126 |
|
---|
127 | if((cs = accept(csk, NULL, NULL)) < 0)
|
---|
128 | throw "Accept";
|
---|
129 | if((is = accept(isk, NULL, NULL)) < 0)
|
---|
130 | throw "Accept";
|
---|
131 |
|
---|
132 | struct sockaddr_l2 addr;
|
---|
133 | socklen_t addrlen = sizeof(addr);
|
---|
134 | if (getpeername(is, (struct sockaddr *)&addr, &addrlen) < 0)
|
---|
135 | throw "Getpeername";
|
---|
136 | baddr = addr.l2_bdaddr;
|
---|
137 | unsigned char resp[64];
|
---|
138 | char get03f2[] = { HIDP_TRANS_GET_REPORT | HIDP_DATA_RTYPE_FEATURE | 8,
|
---|
139 | '\xf2', sizeof(resp), sizeof(resp)>>8 };
|
---|
140 | (void)send(cs, get03f2, sizeof(get03f2), 0);
|
---|
141 | (void)recv(cs, resp, sizeof(resp), 0);
|
---|
142 |
|
---|
143 | if(controller.paired == 1) {
|
---|
144 | close(controller.csk);
|
---|
145 | close(controller.isk);
|
---|
146 | }
|
---|
147 | controller.index = currentIndex++;
|
---|
148 | controller.addr = baddr;
|
---|
149 | controller.paired = 1;
|
---|
150 | controller.timeout = 0;
|
---|
151 | controller.csk = cs;
|
---|
152 | controller.isk = is;
|
---|
153 | setup_device(controller.csk);
|
---|
154 | }
|
---|
155 |
|
---|
156 | void DualshockAPI::setup_device(int sk)
|
---|
157 | {
|
---|
158 | int index = 1; //FIXME
|
---|
159 | char set03f4[] = { HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE,
|
---|
160 | '\xf4', '\x42', '\x03', '\00', '\00' };
|
---|
161 | send(sk, set03f4, sizeof(set03f4), 0);
|
---|
162 | unsigned char ack;
|
---|
163 | int nr = recv(sk, &ack, sizeof(ack), 0);
|
---|
164 | if (nr != 1 || ack != 0)
|
---|
165 | throw "Device is not responding";
|
---|
166 | static const char ledmask[10] = { 1, 2, 4, 8, 6, 7, 11, 13, 14, 15 };
|
---|
167 | #define LED_PERMANENT '\xff', '\x27', '\00', '\00', '\x32'
|
---|
168 | char set0201[] = {
|
---|
169 | HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUTPUT, 0x01,
|
---|
170 | '\00', '\00', '\00', '\00', '\00', '\00', '\00', '\00',
|
---|
171 | '\00', static_cast<char>(index << 1),
|
---|
172 | LED_PERMANENT,
|
---|
173 | LED_PERMANENT,
|
---|
174 | LED_PERMANENT,
|
---|
175 | LED_PERMANENT,
|
---|
176 | '\00', '\00', '\00', '\00', '\00', '\00', '\00', '\00', '\00', '\00'
|
---|
177 | };
|
---|
178 | set0201[3] = set0201[5] = 4;
|
---|
179 | set0201[5] = 0;
|
---|
180 | set0201[6] = 0x70;
|
---|
181 | send(sk, set0201, sizeof(set0201), 0);
|
---|
182 | nr = recv(sk, &ack, sizeof(ack), 0);
|
---|
183 | if (nr != 1 || ack != 0)
|
---|
184 | throw "Device is not responding";
|
---|
185 | }
|
---|
186 |
|
---|
187 | void DualshockAPI::handle_disconnection()
|
---|
188 | {
|
---|
189 | std::cerr << "Disconnection\n";
|
---|
190 | controller.paired = 0;
|
---|
191 | }
|
---|
192 |
|
---|
193 | void DualshockAPI::handle_report(unsigned char buf[], int len)
|
---|
194 | {
|
---|
195 | //std::cerr << "Data\n";
|
---|
196 | (void)len;
|
---|
197 | if (buf[0] != 0xa1)
|
---|
198 | return;
|
---|
199 |
|
---|
200 | /* Digital */
|
---|
201 | controller.buttons.digital.select = (buf[3] & 0x01) >> 0;
|
---|
202 | controller.buttons.digital.l3 = (buf[3] & 0x02) >> 1;
|
---|
203 | controller.buttons.digital.r3 = (buf[3] & 0x04) >> 2;
|
---|
204 | controller.buttons.digital.start = (buf[3] & 0x08) >> 3;
|
---|
205 | controller.buttons.digital.up = (buf[3] & 0x10) >> 4;
|
---|
206 | controller.buttons.digital.right = (buf[3] & 0x20) >> 5;
|
---|
207 | controller.buttons.digital.down = (buf[3] & 0x40) >> 6;
|
---|
208 | controller.buttons.digital.left = (buf[3] & 0x80) >> 7;
|
---|
209 | controller.buttons.digital.l2 = (buf[4] & 0x01) >> 1;
|
---|
210 | controller.buttons.digital.r2 = (buf[4] & 0x02) >> 2;
|
---|
211 | controller.buttons.digital.l1 = (buf[4] & 0x04) >> 3;
|
---|
212 | controller.buttons.digital.r1 = (buf[4] & 0x08) >> 4;
|
---|
213 | controller.buttons.digital.triangle = (buf[4] & 0x10) >> 5;
|
---|
214 | controller.buttons.digital.circle = (buf[4] & 0x20) >> 6;
|
---|
215 | controller.buttons.digital.cross = (buf[4] & 0x40) >> 7;
|
---|
216 | controller.buttons.digital.square = (buf[4] & 0x80) >> 8;
|
---|
217 |
|
---|
218 | /* Sticks */
|
---|
219 | controller.buttons.stick.leftStick_x = buf[7];
|
---|
220 | controller.buttons.stick.leftStick_y = buf[8];
|
---|
221 | controller.buttons.stick.rightStick_x = buf[9];
|
---|
222 | controller.buttons.stick.rightStick_y = buf[10];
|
---|
223 |
|
---|
224 | /* Analog */
|
---|
225 | controller.buttons.analog.l2 = buf[19];
|
---|
226 | controller.buttons.analog.r2 = buf[20];
|
---|
227 | controller.buttons.analog.l1 = buf[21];
|
---|
228 | controller.buttons.analog.r1 = buf[22];
|
---|
229 | controller.buttons.analog.triangle = buf[23];
|
---|
230 | controller.buttons.analog.circle = buf[24];
|
---|
231 | controller.buttons.analog.cross = buf[25];
|
---|
232 | controller.buttons.analog.square = buf[26];
|
---|
233 |
|
---|
234 | /* Axis */
|
---|
235 | controller.buttons.axis.x = buf[43];
|
---|
236 | controller.buttons.axis.y = buf[45];
|
---|
237 | controller.buttons.axis.z = buf[47];
|
---|
238 | controller.buttons.axis.gZ = buf[47];
|
---|
239 | }
|
---|
240 |
|
---|
241 | void DualshockAPI::run()
|
---|
242 | {
|
---|
243 | dbtFile.open("dualshock.dbt", WriteMode, FILE_DBT_UNKNOWN,
|
---|
244 | sizeof(struct dualshockButtons_s));
|
---|
245 | quit = 0;
|
---|
246 | main_loop();
|
---|
247 | }
|
---|
248 |
|
---|
249 | DualshockAPI::~DualshockAPI()
|
---|
250 | {
|
---|
251 | delete(shmem);
|
---|
252 | }
|
---|