root/trunk/libcwiid/util.c

Revision 143, 6.2 kB (checked in by dsmith, 1 year ago)

stifled cwiid_connect errors on wminput reconnect

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  *  2008-08-14 L. Donnie Smith <cwiid@abstrakraft.org>
19  *  * make cwiid_err_default public
20  *  * clean up cwiid_err
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-08 Petter Reinholdtsen <pere@hungry.com>
29  *  * fixed signed/unsigned comparison warning in send_report and
30  *    exec_write_seq
31  *
32  *  2007-04-01 L. Donnie Smith <cwiid@abstrakraft.org>
33  *  * removed cwiid_findfirst (moved to bluetooth.c)
34  *
35  *  2007-03-27 L. Donnie Smith <cwiid@abstrakraft.org>
36  *  * moved cwiid_findfirst to bluetooth.c
37  *
38  *  2007-03-14 L. Donnie Smith <cwiid@abstrakraft.org>
39  *  * audited error checking (coda and error handler sections)
40  *
41  *  2007-03-05 L. Donnie Smith <cwiid@abstrakraft.org>
42  *  * created cwiid_err_func variable
43  *  * created cwiid_err_default
44  *  * added wiimote parameter to cwiid_err definition and calls
45  *
46  *  2007-03-01 L. Donnie Smith <cwiid@abstrakraft.org>
47  *  * Initial ChangeLog
48  *  * type audit (stdint, const, char booleans)
49  */
50
51 #include <errno.h>
52 #include <stdarg.h>
53 #include <stdint.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <fcntl.h>
58 #include <unistd.h>
59 #include "cwiid_internal.h"
60
61 cwiid_err_t cwiid_err_default;
62
63 static cwiid_err_t *cwiid_err_func = &cwiid_err_default;
64
65 int cwiid_set_err(cwiid_err_t *err)
66 {
67         /* TODO: assuming pointer assignment is atomic operation */
68         /* if it is, and the user doesn't care about race conditions, we don't
69          * either */
70         cwiid_err_func = err;
71         return 0;
72 }
73
74 void cwiid_err_default(struct wiimote *wiimote, const char *str, va_list ap)
75 {
76         vfprintf(stderr, str, ap);
77         fprintf(stderr, "\n");
78 }
79
80 void cwiid_err(struct wiimote *wiimote, const char *str, ...)
81 {
82         va_list ap;
83
84         if (cwiid_err_func) {
85                 va_start(ap, str);
86                 (*cwiid_err_func)(wiimote, str, ap);
87                 va_end(ap);
88         }
89 }
90
91 int verify_handshake(struct wiimote *wiimote)
92 {
93         unsigned char handshake;
94         if (read(wiimote->ctl_socket, &handshake, 1) != 1) {
95                 cwiid_err(wiimote, "Socket read error (handshake)");
96                 return -1;
97         }
98         else if ((handshake & BT_TRANS_MASK) != BT_TRANS_HANDSHAKE) {
99                 cwiid_err(wiimote, "Handshake expected, non-handshake received");
100                 return -1;
101         }
102         else if ((handshake & BT_PARAM_MASK) != BT_PARAM_SUCCESSFUL) {
103                 cwiid_err(wiimote, "Non-successful handshake");
104                 return -1;
105         }
106
107         return 0;
108 }
109
110 #define SEND_RPT_BUF_LEN        23
111 int send_report(struct wiimote *wiimote, uint8_t flags, uint8_t report,
112                 size_t len, const void *data)
113 {
114         unsigned char buf[SEND_RPT_BUF_LEN];
115
116         if ((len+2) > SEND_RPT_BUF_LEN) {
117                 return -1;
118         }
119
120         buf[0] = BT_TRANS_SET_REPORT | BT_PARAM_OUTPUT;
121         buf[1] = report;
122         memcpy(buf+2, data, len);
123         if (!(flags & SEND_RPT_NO_RUMBLE)) {
124                 buf[2] |= wiimote->state.rumble;
125         }
126
127         if (write(wiimote->ctl_socket, buf, len+2) != (ssize_t)(len+2)) {
128                 return -1;
129         }
130         else if (verify_handshake(wiimote)) {
131                 return -1;
132         }
133
134         return 0;
135 }
136
137 int exec_write_seq(struct wiimote *wiimote, unsigned int len,
138                    struct write_seq *seq)
139 {
140         unsigned int i;
141
142         for (i=0; i < len; i++) {
143                 switch (seq[i].type) {
144                 case WRITE_SEQ_RPT:
145                         if (send_report(wiimote, seq[i].flags, seq[i].report_offset,
146                                         seq[i].len, seq[i].data)) {
147                                 return -1;
148                         }
149                         break;
150                 case WRITE_SEQ_MEM:
151                         if (cwiid_write(wiimote, seq[i].flags, seq[i].report_offset,
152                                         seq[i].len, seq[i].data)) {
153                                 return -1;
154                         }
155                         break;
156                 }
157         }
158
159         return 0;
160 }
161
162 int full_read(int fd, void *buf, size_t len)
163 {
164         ssize_t last_len = 0;
165
166         do {
167                 if ((last_len = read(fd, buf, len)) == -1) {
168                         return -1;
169                 }
170                 len -= last_len;
171                 buf += last_len;
172         } while (len > 0);
173
174         return 0;
175 }
176
177 int write_mesg_array(struct wiimote *wiimote, struct mesg_array *ma)
178 {
179         ssize_t len = (void *)&ma->array[ma->count] - (void *)ma;
180         int ret = 0;
181
182         /* This must remain a single write operation to ensure atomicity,
183          * which is required to avoid mutexes and cancellation issues */
184         if (write(wiimote->mesg_pipe[1], ma, len) != len) {
185                 if (errno == EAGAIN) {
186                         cwiid_err(wiimote, "Mesg pipe overflow");
187                         if (fcntl(wiimote->mesg_pipe[1], F_SETFL, 0)) {
188                                 cwiid_err(wiimote, "File control error (mesg pipe)");
189                                 ret = -1;
190                         }
191                         else {
192                                 if (write(wiimote->mesg_pipe[1], ma, len) != len) {
193                                         cwiid_err(wiimote, "Pipe write error (mesg pipe)");
194                                         ret = -1;
195                                 }
196                                 if (fcntl(wiimote->mesg_pipe[1], F_SETFL, O_NONBLOCK)) {
197                                         cwiid_err(wiimote, "File control error (mesg pipe");
198                                 }
199                         }
200                 }
201                 else {
202                         cwiid_err(wiimote, "Pipe write error (mesg pipe)");
203                         ret = -1;
204                 }
205         }
206
207         return ret;
208 }
209
210 int read_mesg_array(int fd, struct mesg_array *ma)
211 {
212         ssize_t len;
213
214         len = (void *)&ma->array[0] - (void *)ma;
215         if (full_read(fd, ma, len)) {
216                 return -1;
217         }
218
219         len = ma->count * sizeof ma->array[0];
220         if (full_read(fd, &ma->array[0], len)) {
221                 return -1;
222         }
223
224         return 0;
225 }
226
227 int cancel_rw(struct wiimote *wiimote)
228 {
229         struct rw_mesg rw_mesg;
230
231         rw_mesg.type = RW_CANCEL;
232
233         if (write(wiimote->rw_pipe[1], &rw_mesg, sizeof rw_mesg) !=
234           sizeof rw_mesg) {
235                 cwiid_err(wiimote, "Pipe write error (rw)");
236                 return -1;
237         }
238
239         return 0;
240 }
241
242 int cancel_mesg_callback(struct wiimote *wiimote)
243 {
244         int ret = 0;
245
246         if (pthread_cancel(wiimote->mesg_callback_thread)) {
247                 cwiid_err(wiimote, "Thread cancel error (callback thread)");
248                 ret = -1;
249         }
250
251         if (pthread_detach(wiimote->mesg_callback_thread)) {
252                 cwiid_err(wiimote, "Thread detach error (callback thread)");
253                 ret = -1;
254         }
255
256         return ret;
257 }
Note: See TracBrowser for help on using the browser.