root/libcwiid/thread.c

Revision b54bd057fe6b258d6e0a99047f839891ab3bc2df, 7.9 kB (checked in by L. Donnie Smith <donnie.smith@…>, 2 years ago)

Fixed an issue of incorrectly interpreting Balance Board as MotionPlus.

Previous extension identifiers were only one byte long (just considering
the byte 0xA400FE) and that byte of Balance Board and MotionPlus
happens to be identical (0x04).

In reality, extension identifier is six byte long, but as long as GHWT Drums
are not supported, checking the last two bytes is enough.

See http://wiibrew.org/wiki/Wiimote#The_New_Way for more information on
identifying extensions.

  • Property mode set to 100644
Line 
1/* Copyright (C) 2007 L. Donnie Smith <donnie.smith@gatech.edu>
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 */
18
19#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22#include <pthread.h>
23#include <time.h>
24#include <unistd.h>
25#include "cwiid_internal.h"
26
27#define READ_BUF_LEN 23
28void *router_thread(struct wiimote *wiimote)
29{
30        unsigned char buf[READ_BUF_LEN];
31        ssize_t len;
32        struct mesg_array ma;
33        char err, print_clock_err = 1;
34
35        while (1) {
36                /* Read packet */
37                len = read(wiimote->int_socket, buf, READ_BUF_LEN);
38                ma.count = 0;
39                if (clock_gettime(CLOCK_REALTIME, &ma.timestamp)) {
40                        if (print_clock_err) {
41                                cwiid_err(wiimote, "clock_gettime error");
42                                print_clock_err = 0;
43                        }
44                }
45                err = 0;
46                if ((len == -1) || (len == 0)) {
47                        process_error(wiimote, len, &ma);
48                        write_mesg_array(wiimote, &ma);
49                        /* Quit! */
50                        break;
51                }
52                else {
53                        /* Verify first byte (DATA/INPUT) */
54                        if (buf[0] != (BT_TRANS_DATA | BT_PARAM_INPUT)) {
55                                cwiid_err(wiimote, "Invalid packet type");
56                        }
57
58                        /* Main switch */
59                        /* printf("%.2X %.2X %.2X %.2X  %.2X %.2X %.2X %.2X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
60                        printf("%.2X %.2X %.2X %.2X  %.2X %.2X %.2X %.2X\n", buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
61                        printf("%.2X %.2X %.2X %.2X  %.2X %.2X %.2X %.2X\n", buf[16], buf[17], buf[18], buf[19], buf[20], buf[21], buf[22], buf[23]);
62                        printf("\n"); */
63                        switch (buf[1]) {
64                        case RPT_STATUS:
65                                err = process_status(wiimote, &buf[2], &ma);
66                                break;
67                        case RPT_BTN:
68                                err = process_btn(wiimote, &buf[2], &ma);
69                                break;
70                        case RPT_BTN_ACC:
71                                err = process_btn(wiimote, &buf[2], &ma) ||
72                                      process_acc(wiimote, &buf[4], &ma);
73                                break;
74                        case RPT_BTN_EXT8:
75                                err = process_btn(wiimote, &buf[2], &ma) ||
76                                      process_ext(wiimote, &buf[4], 8, &ma);
77                                break;
78                        case RPT_BTN_ACC_IR12:
79                                err = process_btn(wiimote, &buf[2], &ma) ||
80                                      process_acc(wiimote, &buf[4], &ma) ||
81                                      process_ir12(wiimote, &buf[7], &ma);
82                                break;
83                        case RPT_BTN_EXT19:
84                                err = process_btn(wiimote, &buf[2], &ma) ||
85                                      process_ext(wiimote, &buf[4], 19, &ma);
86                                break;
87                        case RPT_BTN_ACC_EXT16:
88                                err = process_btn(wiimote, &buf[2], &ma) ||
89                                      process_acc(wiimote, &buf[4], &ma) ||
90                                      process_ext(wiimote, &buf[7], 16, &ma);
91                                break;
92                        case RPT_BTN_IR10_EXT9:
93                                err = process_btn(wiimote, &buf[2], &ma)  ||
94                                      process_ir10(wiimote, &buf[4], &ma) ||
95                                      process_ext(wiimote, &buf[14], 9, &ma);
96                                break;
97                        case RPT_BTN_ACC_IR10_EXT6:
98                                err = process_btn(wiimote, &buf[2], &ma)  ||
99                                      process_acc(wiimote, &buf[4], &ma)  ||
100                                      process_ir10(wiimote, &buf[7], &ma) ||
101                                      process_ext(wiimote, &buf[17], 6, &ma);
102                                break;
103                        case RPT_EXT21:
104                                err = process_ext(wiimote, &buf[2], 21, &ma);
105                                break;
106                        case RPT_BTN_ACC_IR36_1:
107                        case RPT_BTN_ACC_IR36_2:
108                                cwiid_err(wiimote, "Unsupported report type received "
109                                                   "(interleaved data)");
110                                err = 1;
111                                break;
112                        case RPT_READ_DATA:
113                                err = process_read(wiimote, &buf[4]) ||
114                                      process_btn(wiimote, &buf[2], &ma);
115                                break;
116                        case RPT_WRITE_ACK:
117                                err = process_write(wiimote, &buf[2]);
118                                break;
119                        default:
120                                cwiid_err(wiimote, "Unknown message type");
121                                err = 1;
122                                break;
123                        }
124
125                        if (!err && (ma.count > 0)) {
126                                if (update_state(wiimote, &ma)) {
127                                        cwiid_err(wiimote, "State update error");
128                                }
129                                if (wiimote->flags & CWIID_FLAG_MESG_IFC) {
130                                        /* prints its own errors */
131                                        write_mesg_array(wiimote, &ma);
132                                }
133                        }
134                }
135        }
136
137        return NULL;
138}
139
140void *status_thread(struct wiimote *wiimote)
141{
142        struct mesg_array ma;
143        struct cwiid_status_mesg *status_mesg;
144        unsigned char buf[2];
145
146        ma.count = 1;
147        status_mesg = &ma.array[0].status_mesg;
148
149        while (1) {
150                if (full_read(wiimote->status_pipe[0], status_mesg,
151                              sizeof *status_mesg)) {
152                        cwiid_err(wiimote, "Pipe read error (status)");
153                        /* Quit! */
154                        break;
155                }
156
157                if (status_mesg->type != CWIID_MESG_STATUS) {
158                        cwiid_err(wiimote, "Bad message on status pipe");
159                        continue;
160                }
161
162                if (status_mesg->ext_type == CWIID_EXT_UNKNOWN) {
163                        /* Read extension ID */
164                        if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 2, &buf)) {
165                                cwiid_err(wiimote, "Read error (extension error)");
166                                status_mesg->ext_type = CWIID_EXT_UNKNOWN;
167                        }
168                        /* If the extension didn't change, or if the extension is a
169                         * MotionPlus, no init necessary */
170                        switch ((buf[0] << 8) | buf[1]) {
171                        case EXT_NONE:
172                                status_mesg->ext_type = CWIID_EXT_NONE;
173                                break;
174                        case EXT_NUNCHUK:
175                                status_mesg->ext_type = CWIID_EXT_NUNCHUK;
176                                break;
177                        case EXT_CLASSIC:
178                                status_mesg->ext_type = CWIID_EXT_CLASSIC;
179                                break;
180                        case EXT_BALANCE:
181                                status_mesg->ext_type = CWIID_EXT_BALANCE;
182                                break;
183                        case EXT_MOTIONPLUS:
184                                status_mesg->ext_type = CWIID_EXT_MOTIONPLUS;
185                                break;
186                        case EXT_PARTIAL:
187                                /* Everything (but MotionPlus) shows up as partial until initialized */
188                                buf[0] = 0x55;
189                                buf[1] = 0x00;
190                                /* Initialize extension register space */
191                                if (cwiid_write(wiimote, CWIID_RW_REG, 0xA400F0, 1, &buf[0])) {
192                                        cwiid_err(wiimote, "Extension initialization error");
193                                        status_mesg->ext_type = CWIID_EXT_UNKNOWN;
194                                }
195                                else if (cwiid_write(wiimote, CWIID_RW_REG, 0xA400FB, 1, &buf[1])) {
196                                                cwiid_err(wiimote, "Extension initialization error");
197                                                status_mesg->ext_type = CWIID_EXT_UNKNOWN;
198                                }
199                                /* Read extension ID */
200                                else if (cwiid_read(wiimote, CWIID_RW_REG, 0xA400FE, 2, &buf)) {
201                                        cwiid_err(wiimote, "Read error (extension error)");
202                                        status_mesg->ext_type = CWIID_EXT_UNKNOWN;
203                                }
204                                else {
205                                        switch ((buf[0] << 8) | buf[1]) {
206                                        case EXT_NONE:
207                                        case EXT_PARTIAL:
208                                                status_mesg->ext_type = CWIID_EXT_NONE;
209                                                break;
210                                        case EXT_NUNCHUK:
211                                                status_mesg->ext_type = CWIID_EXT_NUNCHUK;
212                                                break;
213                                        case EXT_CLASSIC:
214                                                status_mesg->ext_type = CWIID_EXT_CLASSIC;
215                                                break;
216                                        case EXT_BALANCE:
217                                                status_mesg->ext_type = CWIID_EXT_BALANCE;
218                                                break;
219                                        default:
220                                                status_mesg->ext_type = CWIID_EXT_UNKNOWN;
221                                                break;
222                                        }
223                                }
224                                break;
225                        }
226                }
227
228                if (update_state(wiimote, &ma)) {
229                        cwiid_err(wiimote, "State update error");
230                }
231                if (update_rpt_mode(wiimote, -1)) {
232                        cwiid_err(wiimote, "Error reseting report mode");
233                }
234                if ((wiimote->state.rpt_mode & CWIID_RPT_STATUS) &&
235                  (wiimote->flags & CWIID_FLAG_MESG_IFC)) {
236                        if (write_mesg_array(wiimote, &ma)) {
237                                /* prints its own errors */
238                        }
239                }
240        }
241
242        return NULL;
243}
244
245void *mesg_callback_thread(struct wiimote *wiimote)
246{
247        int mesg_pipe = wiimote->mesg_pipe[0];
248        cwiid_mesg_callback_t *callback = wiimote->mesg_callback;
249        struct mesg_array ma;
250        int cancelstate;
251
252        while (1) {
253                if (read_mesg_array(mesg_pipe, &ma)) {
254                        cwiid_err(wiimote, "Mesg pipe read error");
255                        continue;
256                }
257
258                /* TODO: The callback can still be called once after disconnect,
259                 * although it's very unlikely.  User must keep track and avoid
260                 * accessing the wiimote struct after disconnect. */
261                if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate)) {
262                        cwiid_err(wiimote, "Cancel state disable error (callback thread)");
263                }
264                callback(wiimote, ma.count, ma.array, &ma.timestamp);
265                if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate)) {
266                        cwiid_err(wiimote, "Cancel state restore error (callback thread)");
267                }
268        }
269
270        return NULL;
271}
Note: See TracBrowser for help on using the browser.