root/trunk/libcwiid/command.c

Revision 116, 9.3 kB (checked in by dsmith, 2 years ago)

deprecated cwiid_{connect,disconnect,command}, added cwiid_{open,close,request_status,set_led,set_rumble,set_rpt_mode}

Line 
1 /* Copyright (C) 2007 L. Donnie Smith <cwiid@abstrakraft.org>
2  *
3  *  This program is free software; you can redistribute it and/or modify
4  *  it under the terms of the GNU General Public License as published by
5  *  the Free Software Foundation; either version 2 of the License, or
6  *  (at your option) any later version.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  *
17  *  ChangeLog:
18  *  2007-05-16 L. Donnie Smith <cwiid@abstrakraft.org>
19  *  * added cwiid_request_status, cwiid_set_let, cwiid_set_rumble,
20  *    cwiid_set_rpt_mode
21  *
22  *  2007-04-24 L. Donnie Smith <cwiid@abstrakraft.org>
23  *  * rewrite for API overhaul
24  *  * added rw and beep functions from rw.c
25  *
26  *  2007-04-09 L. Donnie Smith <cwiid@abstrakraft.org>
27  *  * renamed wiimote to libcwiid, renamed structures accordingly
28  *
29  *  2007-04-04 L. Donnie Smith <cwiid@abstrakraft.org>
30  *  * updated cwiid_read and cwiid_write to trigger and detect rw_error
31  *
32  *  2007-03-14 L. Donnie Smith <cwiid@abstrakraft.org>
33  *  * audited error checking (coda and error handler sections)
34  *  * updated comments
35  *  * cwiid_read - changed to obey decode flag only for register read
36  *
37  *  2007-03-06 L. Donnie Smith <cwiid@abstrakraft.org>
38  *  * added wiimote parameter to cwiid_err calls
39  *
40  *  2007-03-01 L. Donnie Smith <cwiid@abstrakraft.org>
41  *  * Initial ChangeLog
42  *  * type audit (stdint, const, char booleans)
43  */
44
45 #include <stdint.h>
46 #include <time.h>
47 #include <pthread.h>
48 #include <unistd.h>
49 #include "cwiid_internal.h"
50
51 int cwiid_command(struct wiimote *wiimote, enum cwiid_command command,
52                   int flags) {
53         int ret;
54
55         switch (command) {
56         case CWIID_CMD_STATUS:
57                 ret = cwiid_request_status(wiimote);
58                 break;
59         case CWIID_CMD_LED:
60                 ret = cwiid_set_led(wiimote, flags);
61                 break;
62         case CWIID_CMD_RUMBLE:
63                 ret = cwiid_set_rumble(wiimote, flags);
64                 break;
65         case CWIID_CMD_RPT_MODE:
66                 ret = cwiid_set_rpt_mode(wiimote, flags);
67                 break;
68         default:
69                 ret = -1;
70                 break;
71         }
72
73         return ret;
74 }
75
76 int cwiid_request_status(cwiid_wiimote_t *wiimote)
77 {
78         unsigned char data;
79
80         data = 0;
81         if (send_report(wiimote, 0, RPT_STATUS_REQ, 1, &data)) {
82                 cwiid_err(wiimote, "Status request error");
83                 return -1;
84         }
85
86         return 0;
87 }
88
89 int cwiid_set_led(cwiid_wiimote_t *wiimote, uint8_t led)
90 {
91         unsigned char data;
92
93         /* TODO: assumption: char assignments are atomic, no mutex lock needed */
94         wiimote->state.led = led & 0x0F;
95         data = wiimote->state.led << 4;
96         if (send_report(wiimote, 0, RPT_LED_RUMBLE, 1, &data)) {
97                 cwiid_err(wiimote, "Report send error (led)");
98                 return -1;
99         }
100
101         return 0;
102 }
103
104 int cwiid_set_rumble(cwiid_wiimote_t *wiimote, uint8_t rumble)
105 {
106         unsigned char data;
107
108         /* TODO: assumption: char assignments are atomic, no mutex lock needed */
109         wiimote->state.rumble = rumble ? 1 : 0;
110         data = wiimote->state.led << 4;
111         if (send_report(wiimote, 0, RPT_LED_RUMBLE, 1, &data)) {
112                 cwiid_err(wiimote, "Report send error (led)");
113                 return -1;
114         }
115
116         return 0;
117 }
118
119 int cwiid_set_rpt_mode(cwiid_wiimote_t *wiimote, uint8_t rpt_mode)
120 {
121         return update_rpt_mode(wiimote, rpt_mode);
122 }
123
124 #define RPT_READ_REQ_LEN 6
125 int cwiid_read(struct wiimote *wiimote, uint8_t flags, uint32_t offset,
126                uint16_t len, void *data)
127 {
128         unsigned char buf[RPT_READ_REQ_LEN];
129         struct rw_mesg mesg;
130         unsigned char *cursor;
131         int ret = 0;
132         int i;
133
134         /* Compose read request packet */
135         buf[0]=flags & (CWIID_RW_EEPROM | CWIID_RW_REG);
136         buf[1]=(unsigned char)((offset>>16) & 0xFF);
137         buf[2]=(unsigned char)((offset>>8) & 0xFF);
138         buf[3]=(unsigned char)(offset & 0xFF);
139         buf[4]=(unsigned char)((len>>8) & 0xFF);
140         buf[5]=(unsigned char)(len & 0xFF);
141
142         /* Lock wiimote rw access */
143         if (pthread_mutex_lock(&wiimote->rw_mutex)) {
144                 cwiid_err(wiimote, "Mutex lock error (rw_mutex)");
145                 return -1;
146         }
147
148         /* Setup read info */
149         wiimote->rw_status = RW_READ;
150
151         /* TODO: Document: user is responsible for ensuring that read/write
152          * operations are not in flight while disconnecting.  Nothing serious,
153          * just accesses to freed memory */
154         /* Send read request packet */
155         if (send_report(wiimote, 0, RPT_READ_REQ, RPT_READ_REQ_LEN, buf)) {
156                 cwiid_err(wiimote, "Report send error (read)");
157                 ret = -1;
158                 goto CODA;
159         }
160
161         /* TODO:Better sanity checks (offset) */
162         /* Read packets */
163         for (cursor = data; cursor - (unsigned char *)data < len;
164              cursor += mesg.len) {
165                 if (full_read(wiimote->rw_pipe[0], &mesg, sizeof mesg)) {
166                         cwiid_err(wiimote, "Pipe read error (rw pipe)");
167                         ret = -1;
168                         goto CODA;
169                 }
170
171                 if (mesg.type == RW_CANCEL) {
172                         ret = -1;
173                         goto CODA;
174                 }
175                 else if (mesg.type != RW_READ) {
176                         cwiid_err(wiimote, "Unexpected write message");
177                         ret = -1;
178                         goto CODA;
179                 }
180
181                 if (mesg.error) {
182                         cwiid_err(wiimote, "Wiimote read error");
183                         ret = -1;
184                         goto CODA;
185                 }
186
187                 memcpy(cursor, &mesg.data, mesg.len);
188         }
189
190 CODA:
191         /* Clear rw_status */
192         wiimote->rw_status = RW_IDLE;
193
194         /* Unlock rw_mutex */
195         if (pthread_mutex_unlock(&wiimote->rw_mutex)) {
196                 cwiid_err(wiimote, "Mutex unlock error (rw_mutex) - deadlock warning");
197         }
198
199         /* Decode (only for register reads) */
200         if ((ret == 0) && (flags & CWIID_RW_DECODE) && (flags & CWIID_RW_REG)) {
201                 for (i=0; i < len; i++) {
202                         ((unsigned char *)data)[i] = DECODE(((unsigned char *)data)[i]);
203                 }
204         }
205
206         return ret;
207 }
208
209 #define RPT_WRITE_LEN 21
210 int cwiid_write(struct wiimote *wiimote, uint8_t flags, uint32_t offset,
211                   uint16_t len, const void *data)
212 {
213         unsigned char buf[RPT_WRITE_LEN];
214         uint16_t sent=0;
215         struct rw_mesg mesg;
216         int ret = 0;
217
218         /* Compose write packet header */
219         buf[0]=flags;
220
221         /* Lock wiimote rw access */
222         if (pthread_mutex_lock(&wiimote->rw_mutex)) {
223                 cwiid_err(wiimote, "Mutex lock error (rw mutex)");
224                 return -1;
225         }
226
227         /* Send packets */
228         wiimote->rw_status = RW_WRITE;
229         while (sent<len) {
230                 /* Compose write packet */
231                 buf[1]=(unsigned char)(((offset+sent)>>16) & 0xFF);
232                 buf[2]=(unsigned char)(((offset+sent)>>8) & 0xFF);
233                 buf[3]=(unsigned char)((offset+sent) & 0xFF);
234                 if (len-sent >= 0x10) {
235                         buf[4]=(unsigned char)0x10;
236                 }
237                 else {
238                         buf[4]=(unsigned char)(len-sent);
239                 }
240                 memcpy(buf+5, data+sent, buf[4]);
241
242                 if (send_report(wiimote, 0, RPT_WRITE, RPT_WRITE_LEN, buf)) {
243                         cwiid_err(wiimote, "Report send error (write)");
244                         ret = -1;
245                         goto CODA;
246                 }
247
248                 /* Read packets from pipe */
249                 if (read(wiimote->rw_pipe[0], &mesg, sizeof mesg) != sizeof mesg) {
250                         cwiid_err(wiimote, "Pipe read error (rw pipe)");
251                         ret = -1;
252                         goto CODA;
253                 }
254
255                 if (mesg.type == RW_CANCEL) {
256                         ret = -1;
257                         goto CODA;
258                 }
259                 else if (mesg.type != RW_WRITE) {
260                         cwiid_err(wiimote, "Unexpected read message");
261                         ret = -1;
262                         goto CODA;
263                 }
264
265                 if (mesg.error) {
266                         cwiid_err(wiimote, "Wiimote write error");
267                         ret = -1;
268                         goto CODA;
269                 };
270
271                 sent+=buf[4];
272         }
273
274 CODA:
275         /* Clear rw_status */
276         wiimote->rw_status = RW_IDLE;
277
278         /* Unlock rw_mutex */
279         if (pthread_mutex_unlock(&wiimote->rw_mutex)) {
280                 cwiid_err(wiimote, "Mutex unlock error (rw_mutex) - deadlock warning");
281         }
282
283         return ret;
284 }
285
286
287 struct write_seq speaker_enable_seq[] = {
288         {WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x04", 1, 0},
289         {WRITE_SEQ_RPT,   RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0},
290         {WRITE_SEQ_MEM, 0xA20009, (const void *)"\x01", 1, CWIID_RW_REG},
291         {WRITE_SEQ_MEM, 0xA20001, (const void *)"\x08", 1, CWIID_RW_REG},
292         {WRITE_SEQ_MEM, 0xA20001, (const void *)"\x00\x00\x00\x0C\x40\x00\x00",
293                                   7, CWIID_RW_REG},
294         {WRITE_SEQ_MEM, 0xA20008, (const void *)"\x01", 1, CWIID_RW_REG},
295         {WRITE_SEQ_RPT,   RPT_SPEAKER_MUTE, (const void *)"\x00", 1, 0}
296 };
297
298 struct write_seq speaker_disable_seq[] = {
299         {WRITE_SEQ_RPT,   RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0},
300         {WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x00", 1, 0}
301 };
302
303 #define SOUND_BUF_LEN   21
304 int cwiid_beep(cwiid_wiimote_t *wiimote)
305 {
306         /* unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xCC, 0x33, 0xCC, 0x33,
307             0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33,
308             0xCC, 0x33, 0xCC, 0x33}; */
309         unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xC3, 0xC3, 0xC3, 0xC3,
310             0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
311             0xC3, 0xC3, 0xC3, 0xC3};
312         int i;
313         int ret = 0;
314         pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
315         pthread_cond_t timer_cond = PTHREAD_COND_INITIALIZER;
316         struct timespec t;
317
318         if (exec_write_seq(wiimote, SEQ_LEN(speaker_enable_seq),
319                            speaker_enable_seq)) {
320                 cwiid_err(wiimote, "Speaker enable error");
321                 ret = -1;
322         }
323
324         pthread_mutex_lock(&timer_mutex);
325
326         for (i=0; i<100; i++) {
327                 clock_gettime(CLOCK_REALTIME, &t);
328                 t.tv_nsec += 10204081;
329                 /* t.tv_nsec += 7000000; */
330                 if (send_report(wiimote, 0, RPT_SPEAKER_DATA, SOUND_BUF_LEN, buf)) {
331                         printf("%d\n", i);
332                         cwiid_err(wiimote, "Report send error (speaker data)");
333                         ret = -1;
334                         break;
335                 }
336                 /* TODO: I should be shot for this, but hey, it works.
337                  * longterm - find a better wait */
338                 pthread_cond_timedwait(&timer_cond, &timer_mutex, &t);
339         }
340
341         pthread_mutex_unlock(&timer_mutex);
342
343         if (exec_write_seq(wiimote, SEQ_LEN(speaker_disable_seq),
344                            speaker_disable_seq)) {
345                 cwiid_err(wiimote, "Speaker disable error");
346                 ret = -1;
347         }
348
349         return ret;
350 }
Note: See TracBrowser for help on using the browser.