root/branches/dev/libcwiid/connect.c

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