root/trunk/libcwiid/connect.c

Revision 126, 10.3 kB (checked in by dsmith, 2 years ago)

added delay hack to fix wiimote find issue

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-06-14 L. Donnie Smith <cwiid@abstrakraft.org>
19  *  * added sleep after cwiid_find_wiimote call
20  *
21  *  2007-05-16 L. Donnie Smith <cwiid@abstrakraft.org>
22  *  * remove error_pipe init and destruct
23  *  * renamed connect and disconnect to open and close
24  *
25  *  2007-04-24 L. Donnie Smith <cwiid@abstrakraft.org>
26  *  * rewrite for API overhaul
27  *
28  *  2007-04-09 L. Donnie Smith <cwiid@abstrakraft.org>
29  *  * renamed wiimote to libcwiid, renamed structures accordingly
30  *
31  *  2007-04-04 L. Donnie Smith <cwiid@abstrakraft.org>
32  *  * cancel rw operations from cwiid_disconnect
33  *
34  *  2007-04-01 L. Donnie Smith <cwiid@abstrakraft.org>
35  *  * cwiid_connect now takes a pointer to bdaddr_t
36  *  * changed cwiid_findfirst to cwiid_find_wiimote
37  *
38  *  2007-03-14 L. Donnie Smith <cwiid@abstrakraft.org>
39  *  * changed memcpy to bacmp
40  *  * audited error checking (coda and error handler sections)
41  *  * updated comments
42  *
43  *  2007-03-06 L. Donnie Smith <cwiid@abstrakraft.org>
44  *  * added wiimote parameter to cwiid_err calls
45  *
46  *  2007-03-01 L. Donnie Smith <cwiid@abstrakraft.org>
47  *  * Initial ChangeLog
48  */
49
50 #include <stdlib.h>
51 #include <string.h>
52 #include <fcntl.h>
53 #include <pthread.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <unistd.h>
57 #include <bluetooth/bluetooth.h>
58 #include <bluetooth/l2cap.h>
59 #include "cwiid_internal.h"
60
61 pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
62 static int wiimote_id = 0;
63
64 cwiid_wiimote_t *cwiid_open(bdaddr_t *bdaddr, int flags)
65 {
66         struct wiimote *wiimote = NULL;
67         struct sockaddr_l2 remote_addr;
68         char mesg_pipe_init = 0, status_pipe_init = 0, rw_pipe_init = 0,
69              state_mutex_init = 0, rw_mutex_init = 0, rpt_mutex_init = 0,
70              router_thread_init = 0, status_thread_init = 0;
71         void *pthread_ret;
72
73         /* Allocate wiimote */
74         if ((wiimote = malloc(sizeof *wiimote)) == NULL) {
75                 cwiid_err(NULL, "Memory allocation error (cwiid_wiimote_t)");
76                 goto ERR_HND;
77         }
78
79         /* set flags */
80         wiimote->flags = flags;
81
82         /* For error detection */
83         wiimote->ctl_socket = wiimote->int_socket = -1;
84
85         /* Global Lock, Store and Increment wiimote_id */
86         if (pthread_mutex_lock(&global_mutex)) {
87                 cwiid_err(NULL, "Mutex lock error (global mutex)");
88                 goto ERR_HND;
89         }
90         wiimote->id = wiimote_id++;
91         if (pthread_mutex_unlock(&global_mutex)) {
92                 cwiid_err(wiimote, "Mutex unlock error (global mutex) - "
93                                    "deadlock warning");
94                 goto ERR_HND;
95         }
96
97         /* If BDADDR_ANY is given, find available wiimote */
98         if (bacmp(bdaddr, BDADDR_ANY) == 0) {
99                 if (cwiid_find_wiimote(bdaddr, 5)) {
100                         goto ERR_HND;
101                 }
102                 sleep(1);
103         }
104
105         /* Connect to Wiimote */
106         /* Control Channel */
107         memset(&remote_addr, 0, sizeof remote_addr);
108         remote_addr.l2_family = AF_BLUETOOTH;
109         remote_addr.l2_bdaddr = *bdaddr;
110         remote_addr.l2_psm = htobs(CTL_PSM);
111         if ((wiimote->ctl_socket =
112           socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
113                 cwiid_err(wiimote, "Socket creation error (control socket)");
114                 goto ERR_HND;
115         }
116         if (connect(wiimote->ctl_socket, (struct sockaddr *)&remote_addr,
117                         sizeof remote_addr)) {
118                 cwiid_err(wiimote, "Socket connect error (control channel)");
119                 goto ERR_HND;
120         }
121
122         /* Interrupt Channel */
123         remote_addr.l2_psm = htobs(INT_PSM);
124         if ((wiimote->int_socket =
125           socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
126                 cwiid_err(wiimote, "Socket creation error (interrupt socket)");
127                 goto ERR_HND;
128         }
129         if (connect(wiimote->int_socket, (struct sockaddr *)&remote_addr,
130                         sizeof remote_addr)) {
131                 cwiid_err(wiimote, "Socket connect error (interrupt channel)");
132                 goto ERR_HND;
133         }
134
135         /* Create pipes */
136         if (pipe(wiimote->mesg_pipe)) {
137                 cwiid_err(wiimote, "Pipe creation error (mesg pipe)");
138                 goto ERR_HND;
139         }
140         mesg_pipe_init = 1;
141         if (pipe(wiimote->status_pipe)) {
142                 cwiid_err(wiimote, "Pipe creation error (status pipe)");
143                 goto ERR_HND;
144         }
145         status_pipe_init = 1;
146         if (pipe(wiimote->rw_pipe)) {
147                 cwiid_err(wiimote, "Pipe creation error (rw pipe)");
148                 goto ERR_HND;
149         }
150         rw_pipe_init = 1;
151
152         /* Setup blocking */
153         if (fcntl(wiimote->mesg_pipe[1], F_SETFL, O_NONBLOCK)) {
154                 cwiid_err(wiimote, "File control error (mesg write pipe)");
155                 goto ERR_HND;
156         }
157         if (wiimote->flags & CWIID_FLAG_NONBLOCK) {
158                 if (fcntl(wiimote->mesg_pipe[0], F_SETFL, O_NONBLOCK)) {
159                         cwiid_err(wiimote, "File control error (mesg read pipe)");
160                         goto ERR_HND;
161                 }
162         }
163
164         /* Init mutexes */
165         if (pthread_mutex_init(&wiimote->state_mutex, NULL)) {
166                 cwiid_err(wiimote, "Mutex initialization error (state mutex)");
167                 goto ERR_HND;
168         }
169         state_mutex_init = 1;
170         if (pthread_mutex_init(&wiimote->rw_mutex, NULL)) {
171                 cwiid_err(wiimote, "Mutex initialization error (rw mutex)");
172                 goto ERR_HND;
173         }
174         rw_mutex_init = 1;
175         if (pthread_mutex_init(&wiimote->rpt_mutex, NULL)) {
176                 cwiid_err(wiimote, "Mutex initialization error (rpt mutex)");
177                 goto ERR_HND;
178         }
179         rpt_mutex_init = 1;
180
181         /* Set rw_status before starting router thread */
182         wiimote->rw_status = RW_IDLE;
183
184         /* Launch interrupt channel listener and dispatch threads */
185         if (pthread_create(&wiimote->router_thread, NULL,
186                            (void *(*)(void *))&router_thread, wiimote)) {
187                 cwiid_err(wiimote, "Thread creation error (router thread)");
188                 goto ERR_HND;
189         }
190         router_thread_init = 1;
191         if (pthread_create(&wiimote->status_thread, NULL,
192                            (void *(*)(void *))&status_thread, wiimote)) {
193                 cwiid_err(wiimote, "Thread creation error (status thread)");
194                 goto ERR_HND;
195         }
196         status_thread_init = 1;
197
198         /* Success!  Update state */
199         memset(&wiimote->state, 0, sizeof wiimote->state);
200         wiimote->mesg_callback = NULL;
201         cwiid_set_led(wiimote, 0);
202         cwiid_request_status(wiimote);
203
204         return wiimote;
205
206 ERR_HND:
207         if (wiimote) {
208                 /* Close threads */
209                 if (router_thread_init) {
210                         pthread_cancel(wiimote->router_thread);
211                         if (pthread_join(wiimote->router_thread, &pthread_ret)) {
212                                 cwiid_err(wiimote, "Thread join error (router thread)");
213                         }
214                         else if (!((pthread_ret == PTHREAD_CANCELED) &&
215                                  (pthread_ret == NULL))) {
216                                 cwiid_err(wiimote, "Bad return value from router thread");
217                         }
218                 }
219
220                 if (status_thread_init) {
221                         pthread_cancel(wiimote->status_thread);
222                         if (pthread_join(wiimote->status_thread, &pthread_ret)) {
223                                 cwiid_err(wiimote, "Thread join error (status thread)");
224                         }
225                         else if (!((pthread_ret == PTHREAD_CANCELED) && (pthread_ret == NULL))) {
226                                 cwiid_err(wiimote, "Bad return value from status thread");
227                         }
228                 }
229
230                 /* Close Sockets */
231                 if (wiimote->int_socket != -1) {
232                         if (close(wiimote->int_socket)) {
233                                 cwiid_err(wiimote, "Socket close error (interrupt channel)");
234                         }
235                 }
236                 if (wiimote->ctl_socket != -1) {
237                         if (close(wiimote->ctl_socket)) {
238                                 cwiid_err(wiimote, "Socket close error (control channel)");
239                         }
240                 }
241                 /* Close Pipes */
242                 if (mesg_pipe_init) {
243                         if (close(wiimote->mesg_pipe[0]) || close(wiimote->mesg_pipe[1])) {
244                                 cwiid_err(wiimote, "Pipe close error (mesg pipe)");
245                         }
246                 }
247                 if (status_pipe_init) {
248                         if (close(wiimote->status_pipe[0]) ||
249                           close(wiimote->status_pipe[1])) {
250                                 cwiid_err(wiimote, "Pipe close error (status pipe)");
251                         }
252                 }
253                 if (rw_pipe_init) {
254                         if (close(wiimote->rw_pipe[0]) || close(wiimote->rw_pipe[1])) {
255                                 cwiid_err(wiimote, "Pipe close error (rw pipe)");
256                         }
257                 }
258                 /* Destroy Mutexes */
259                 if (state_mutex_init) {
260                         if (pthread_mutex_destroy(&wiimote->state_mutex)) {
261                                 cwiid_err(wiimote, "Mutex destroy error (state mutex)");
262                         }
263                 }
264                 if (rw_mutex_init) {
265                         if (pthread_mutex_destroy(&wiimote->rw_mutex)) {
266                                 cwiid_err(wiimote, "Mutex destroy error (rw mutex)");
267                         }
268                 }
269                 if (rpt_mutex_init) {
270                         if (pthread_mutex_destroy(&wiimote->rpt_mutex)) {
271                                 cwiid_err(wiimote, "Mutex destroy error (rpt mutex)");
272                         }
273                 }
274                 free(wiimote);
275         }
276         return NULL;
277 }
278
279 int cwiid_close(struct wiimote *wiimote)
280 {
281         void *pthread_ret;
282
283         /* Cancel and join router_thread and status_thread */
284         if (pthread_cancel(wiimote->router_thread)) {
285                 /* if thread quit abnormally, would have printed it's own error */
286         }
287         if (pthread_join(wiimote->router_thread, &pthread_ret)) {
288                 cwiid_err(wiimote, "Thread join error (router thread)");
289         }
290         else if (!((pthread_ret == PTHREAD_CANCELED) || (pthread_ret == NULL))) {
291                 cwiid_err(wiimote, "Bad return value from router thread");
292         }
293
294         if (pthread_cancel(wiimote->status_thread)) {
295                 /* if thread quit abnormally, would have printed it's own error */
296         }
297         if (pthread_join(wiimote->status_thread, &pthread_ret)) {
298                 cwiid_err(wiimote, "Thread join error (status thread)");
299         }
300         else if (!((pthread_ret == PTHREAD_CANCELED) || (pthread_ret == NULL))) {
301                 cwiid_err(wiimote, "Bad return value from status thread");
302         }
303
304         if (wiimote->mesg_callback) {
305                 if (cancel_mesg_callback(wiimote)) {
306                         /* prints it's own errors */
307                 }
308         }
309
310         if (cancel_rw(wiimote)) {
311                 /* prints it's own errors */
312         }
313
314         /* Close sockets */
315         if (close(wiimote->int_socket)) {
316                 cwiid_err(wiimote, "Socket close error (interrupt channel)");
317         }
318         if (close(wiimote->ctl_socket)) {
319                 cwiid_err(wiimote, "Socket close error (control channel)");
320         }
321         /* Close Pipes */
322         if (close(wiimote->mesg_pipe[0]) || close(wiimote->mesg_pipe[1])) {
323                 cwiid_err(wiimote, "Pipe close error (mesg pipe)");
324         }
325         if (close(wiimote->status_pipe[0]) || close(wiimote->status_pipe[1])) {
326                 cwiid_err(wiimote, "Pipe close error (status pipe)");
327         }
328         if (close(wiimote->rw_pipe[0]) || close(wiimote->rw_pipe[1])) {
329                 cwiid_err(wiimote, "Pipe close error (rw pipe)");
330         }
331         /* Destroy mutexes */
332         if (pthread_mutex_destroy(&wiimote->state_mutex)) {
333                 cwiid_err(wiimote, "Mutex destroy error (state)");
334         }
335         if (pthread_mutex_destroy(&wiimote->rw_mutex)) {
336                 cwiid_err(wiimote, "Mutex destroy error (rw)");
337         }
338         if (pthread_mutex_destroy(&wiimote->rpt_mutex)) {
339                 cwiid_err(wiimote, "Mutex destroy error (rpt)");
340         }
341
342         free(wiimote);
343
344         return 0;
345 }
Note: See TracBrowser for help on using the browser.