root/wiimote/connect.c @ 00aa4948876dc0530d8a1e5ab8170a9befa9f14c

Revision 00aa4948876dc0530d8a1e5ab8170a9befa9f14c, 7.4 KB (checked in by dsmith <dsmith@…>, 6 years ago)

wiimote: error checking, comment updates

git-svn-id: http://abstrakraft.org/cwiid/svn/trunk@35 918edb2d-ff29-0410-9de2-eb38e7f22bc7

  • Property mode set to 100644
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 *  03/14/2007: L. Donnie Smith <cwiid@abstrakraft.org>
19 *  * changed memcpy to bacmp
20 *  * audited error checking (coda and error handler sections)
21 *  * updated comments
22 *
23 *  03/06/2007: L. Donnie Smith <cwiid@abstrakraft.org>
24 *  * added wiimote parameter to wiimote_err calls
25 *
26 *  03/01/2007: L. Donnie Smith <cwiid@abstrakraft.org>
27 *  * Initial ChangeLog
28 */
29
30#include <pthread.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <unistd.h>
36#include <bluetooth/bluetooth.h>
37#include <bluetooth/l2cap.h>
38#include "wiimote_internal.h"
39#include "queue.h"
40
41pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
42static int wiimote_id = 0;
43
44wiimote_t *wiimote_connect(bdaddr_t bdaddr,
45                           wiimote_mesg_callback_t *mesg_callback, int *id)
46{
47        struct wiimote *wiimote = NULL;
48        struct sockaddr_l2 ctl_remote_addr, int_remote_addr;
49
50        /* Allocate wiimote */
51        if ((wiimote = malloc(sizeof *wiimote)) == NULL) {
52                wiimote_err(NULL, "Error allocating wiimote");
53                goto ERR_HND;
54        }
55
56        /* Set wiimote members for proper error detection */
57        wiimote->ctl_socket = -1;
58        wiimote->int_socket = -1;
59        wiimote->dispatch_queue = NULL;
60
61        /* Global Lock, Store and Increment wiimote_id */
62        if (pthread_mutex_lock(&global_mutex)) {
63                wiimote_err(NULL, "Error locking global lock");
64                goto ERR_HND;
65        }
66        wiimote->id = wiimote_id++;
67        if (pthread_mutex_unlock(&global_mutex)) {
68                wiimote_err(wiimote, "Error unlocking global lock");
69                goto ERR_HND;
70        }
71        /* Return the id in a pointer, if desired */
72        if (id) {
73                *id = wiimote->id;
74        }
75
76        /* Store mesg callback */
77        wiimote->mesg_callback = mesg_callback;
78
79        /* If BDADDR_ANY is given, find available wiimote */
80        if (bacmp(&bdaddr, BDADDR_ANY) == 0) {
81                if (wiimote_findfirst(&bdaddr)) {
82                        /* TODO: wiimote functions should print their own errors */
83                        wiimote_err(wiimote, "Unable to find wiimote");
84                        goto ERR_HND;
85                }
86        }
87
88        /* Clear address structs, fill address family, address, and ports */
89        memset(&ctl_remote_addr, 0, sizeof(ctl_remote_addr));
90        ctl_remote_addr.l2_family = AF_BLUETOOTH;
91        ctl_remote_addr.l2_bdaddr = bdaddr;
92        ctl_remote_addr.l2_psm = htobs(CTL_PSM);
93
94        memset(&int_remote_addr, 0, sizeof(int_remote_addr));
95        int_remote_addr.l2_family = AF_BLUETOOTH;
96        int_remote_addr.l2_bdaddr = bdaddr;
97        int_remote_addr.l2_psm = htobs(INT_PSM);
98
99        /* Get Bluetooth Sockets */
100        if ((wiimote->ctl_socket =
101          socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
102                wiimote_err(wiimote, "Error opening control socket");
103                goto ERR_HND;
104        }
105        if ((wiimote->int_socket =
106          socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) {
107                wiimote_err(wiimote, "Error opening interrupt socket");
108                goto ERR_HND;
109        }
110
111        /* Connect to Wiimote */
112        if (connect(wiimote->ctl_socket, (struct sockaddr *)&ctl_remote_addr,
113                        sizeof(ctl_remote_addr))) {
114                wiimote_err(wiimote, "Error opening control channel");
115                goto ERR_HND;
116        }
117        if (connect(wiimote->int_socket, (struct sockaddr *)&int_remote_addr,
118                        sizeof(int_remote_addr))) {
119                wiimote_err(wiimote, "Error opening interrupt channel");
120                goto ERR_HND;
121        }
122
123        /* Create Dispatch Queue */
124        if ((wiimote->dispatch_queue = queue_new()) == NULL) {
125                wiimote_err(wiimote, "Error creating dispatch queue");
126                goto ERR_HND;
127        }
128
129        /* TODO: backout logic (pthread_*_destroy) */
130        /* Mutex and cond init */
131        if (pthread_mutex_init(&wiimote->wiimote_mutex, NULL) ||
132          pthread_mutex_init(&wiimote->rw_mutex, NULL) ||
133          pthread_cond_init(&wiimote->rw_cond, NULL) ||
134          pthread_mutex_init(&wiimote->rw_cond_mutex, NULL)) {
135                wiimote_err(wiimote,
136                            "Error initializing synchronization variables");
137                goto ERR_HND;
138        }
139
140        /* Set rw_status before interrupt thread */
141        wiimote->rw_status = RW_NONE;
142
143        /* Launch interrupt channel listener and dispatch threads */
144        if (pthread_create(&wiimote->int_listen_thread, NULL,
145                           (void *(*)(void *))&int_listen, wiimote)) {
146                wiimote_err(wiimote,
147                            "Error creating interrupt channel listener thread");
148                goto ERR_HND;
149        }
150        if (pthread_create(&wiimote->dispatch_thread, NULL,
151                           (void *(*)(void *))&dispatch, wiimote)) {
152                pthread_cancel(wiimote->int_listen_thread);
153                pthread_join(wiimote->int_listen_thread, NULL);
154                wiimote_err(wiimote, "Error creating dispatch thread");
155                goto ERR_HND;
156        }
157
158        /* Success!  Update state */
159        wiimote->buttons = 0;
160        wiimote->rpt_mode_flags = 0;
161        wiimote->extension = WIIMOTE_EXT_NONE;
162        wiimote->led_rumble_state = 0;
163        wiimote_command(wiimote, WIIMOTE_CMD_LED, 0);
164        wiimote_command(wiimote, WIIMOTE_CMD_STATUS, 0);
165
166        return wiimote;
167
168ERR_HND:
169        if (wiimote) {
170                if (wiimote->dispatch_queue) {
171                        queue_free(wiimote->dispatch_queue,
172                                   (free_func_t *)free_mesg_array);
173                }
174                if (wiimote->int_socket != -1) {
175                        if (close(wiimote->int_socket)) {
176                                wiimote_err(wiimote, "Error closing interrupt channel");
177                        }
178                }
179                if (wiimote->ctl_socket != -1) {
180                        if (close(wiimote->ctl_socket)) {
181                                wiimote_err(wiimote, "Error closing control channel");
182                        }
183                }
184                free(wiimote);
185        }
186        return NULL;
187}
188
189int wiimote_disconnect(struct wiimote *wiimote)
190{
191        void *pthread_ret;
192
193        /* Cancel and join int_thread */
194        if (pthread_cancel(wiimote->int_listen_thread)) {
195                wiimote_err(wiimote, "Error canceling int_listen_thread");
196        }
197        else {
198                if (pthread_join(wiimote->int_listen_thread, &pthread_ret)) {
199                        wiimote_err(wiimote, "Error joining int_listen_thread");
200                }
201                else if (pthread_ret != PTHREAD_CANCELED) {
202                        wiimote_err(wiimote,
203                                    "Invalid return value from int_listen_thread");
204                }
205        }
206        /* TODO: cancel RW operations if they are in progress */
207        /* Cancel and detach dispatch_thread */
208        /* We detach to decouple dispatch (which runs the callback) from wiimote
209         * code - specifically, a race condition exists for gtk apps */
210        if (pthread_cancel(wiimote->dispatch_thread)) {
211                wiimote_err(wiimote, "Error canceling dispatch_thread");
212        }
213        if (pthread_detach(wiimote->dispatch_thread)) {
214                wiimote_err(wiimote, "Error detaching dispatch_thread");
215        }
216
217        /* Close sockets */
218        if (close(wiimote->int_socket)) {
219                wiimote_err(wiimote, "Error closing interrupt channel");
220        }
221        if (close(wiimote->ctl_socket)) {
222                wiimote_err(wiimote, "Error closing control channel");
223        }
224
225        /* Destroy sync variables */
226        if (pthread_mutex_destroy(&wiimote->wiimote_mutex)) {
227                wiimote_err(wiimote, "Error destroying wiimote_mutex");
228        }
229        if (pthread_mutex_destroy(&wiimote->rw_mutex)) {
230                wiimote_err(wiimote, "Error destroying rw_mutex");
231        }
232        if (pthread_cond_destroy(&wiimote->rw_cond)) {
233                wiimote_err(wiimote, "Error destroying rw_cond");
234        }
235        if (pthread_mutex_destroy(&wiimote->rw_cond_mutex)) {
236                wiimote_err(wiimote, "Error destroying rw_cond_mutex");
237        }
238
239        free(wiimote);
240
241        return 0;
242}
243
Note: See TracBrowser for help on using the browser.