root/branches/dev/libcwiid/util.c

Revision 112, 6.2 kB (checked in by dsmith, 2 years ago)

added timestamp to message interfaces

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