Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/wiimote/src/external/wiicpp/wiic/wiic.c @ 9780

Last change on this file since 9780 was 9780, checked in by georgr, 10 years ago

WiiCpp library successfully (?) added - won't work without libbluetooth-dev

  • Property svn:executable set to *
File size: 17.0 KB
Line 
1/*
2 *    wiic.c
3 *
4 *        This file is part of WiiC, written by:
5 *              Gabriele Randelli
6 *              Email: randelli@dis.uniroma1.it
7 *
8 *    Copyright 2010
9 *             
10 *        This file is based on Wiiuse, written By:
11 *              Michael Laforest        < para >
12 *              Email: < thepara (--AT--) g m a i l [--DOT--] com >
13 *
14 *        Copyright 2006-2007
15 *
16 *    This program is free software; you can redistribute it and/or modify
17 *    it under the terms of the GNU General Public License as published by
18 *    the Free Software Foundation; either version 3 of the License, or
19 *    (at your option) any later version.
20 *
21 *    This program is distributed in the hope that it will be useful,
22 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
23 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 *    GNU General Public License for more details.
25 *
26 *    You should have received a copy of the GNU General Public License
27 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
28 *
29 *        $Header$
30 */
31
32/**
33 *      @file
34 *      @brief General wiimote operations.
35 *
36 *      The file includes functions that handle general
37 *      tasks.  Most of these are functions that are part
38 *      of the API.
39 */
40
41#include <stdio.h>
42#include <stdlib.h>
43#include <unistd.h>
44#include <sys/time.h>
45
46#include "definitions.h"
47#include "wiic_internal.h"
48#include "events.h"
49#include "io.h"
50
51static int g_banner = 0;
52
53/**
54 *      @breif Returns the version of the library.
55 */
56const char* wiic_version() {
57        return WIIC_VERSION;
58}
59
60
61/**
62 *      @brief Clean up wiimote_t array created by wiic_init()
63 */
64void wiic_cleanup(struct wiimote_t** wm, int wiimotes) {
65        int i = 0;
66
67        if (!wm)
68                return;
69
70        WIIC_DEBUG("wiiC clean up...");
71
72        for (; i < wiimotes; ++i) {
73                wiic_disconnect(wm[i]);
74                free(wm[i]);
75        }
76
77        free(wm);
78
79        return;
80}
81
82
83/**
84 *      @brief Initialize an array of wiimote structures.
85 *
86 *      @param wiimotes         Number of wiimote_t structures to create.
87 *
88 *      @return An array of initialized wiimote_t structures.
89 *
90 *      @see wiic_connect()
91 *
92 *      The array returned by this function can be passed to various
93 *      functions, including wiic_connect().
94 */
95struct wiimote_t** wiic_init(int wiimotes) {
96        int i = 0;
97        struct wiimote_t** wm = NULL;
98
99        /*
100         *      Please do not remove this banner.
101         *      GPL asks that you please leave output credits intact.
102         *      Thank you.
103         *
104         *      This banner is only displayed once so that if you need
105         *      to call this function again it won't be intrusive.
106         */
107        if (!g_banner) {
108                WIIC_DEBUG(     "WiiC v" WIIC_VERSION " loaded.\n"
109                                "By: Gabriele Randelli <randelli[at]dis{dot}uniroma1{dot}it>\n"
110                                "http://www.dis.uniroma1.it/~randelli\n\n");
111                g_banner = 1;
112        }
113
114        if (!wiimotes)
115                return NULL;
116
117        wm = malloc(sizeof(struct wiimote_t*) * wiimotes);
118
119        for (i = 0; i < wiimotes; ++i) {
120                wm[i] = malloc(sizeof(struct wiimote_t));
121                memset(wm[i], 0, sizeof(struct wiimote_t));
122
123                wm[i]->unid = i+1;
124
125                #ifdef __APPLE__
126                        wm[i]->device = 0;
127                        wm[i]->address = 0;
128                        wm[i]->inputCh = 0;
129                        wm[i]->outputCh = 0;
130                        wm[i]->disconnectionRef = 0;
131                        wm[i]->connectionHandler = 0;
132                #elif LINUX
133                        wm[i]->bdaddr = *BDADDR_ANY;
134                        wm[i]->out_sock = -1;
135                        wm[i]->in_sock = -1;   
136                #endif
137
138                wm[i]->state = WIIMOTE_INIT_STATES;
139                wm[i]->flags = WIIC_INIT_FLAGS;
140                wm[i]->autoreconnect = 0;
141                wm[i]->event = WIIC_NONE;
142
143                wm[i]->exp.type = EXP_NONE;
144
145                wiic_set_aspect_ratio(wm[i], WIIC_ASPECT_4_3);
146                wiic_set_ir_position(wm[i], WIIC_IR_ABOVE);
147
148                wm[i]->orient_threshold = 0.5f;
149                wm[i]->accel_threshold = 5;
150
151                wm[i]->accel_calib.st_alpha = WIIC_DEFAULT_SMOOTH_ALPHA;
152               
153                gettimeofday(&(wm[i]->timestamp),0);
154        }
155
156        return wm;
157}
158
159
160/**
161 *      @brief  The wiimote disconnected.
162 *
163 *      @param wm       Pointer to a wiimote_t structure.
164 */
165void wiic_disconnected(struct wiimote_t* wm) {
166        if (!wm)        return;
167       
168        // Auto-reconnect?
169        if(wm->autoreconnect && wiic_connect_single(wm,NULL,1))
170                return;
171               
172        WIIC_INFO("Wiimote disconnected [id %i].", wm->unid);
173
174        /* disable the connected flag */
175        WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_CONNECTED);
176
177        /* reset a bunch of stuff */
178        #if __APPLE__ // MacOSX
179                if(wm->inputCh) {
180                        IOBluetoothObjectRelease(wm->inputCh);
181                        wm->inputCh = 0;
182                }
183                if(wm->outputCh) {
184                        IOBluetoothObjectRelease(wm->outputCh);                 
185                        wm->outputCh = 0;                       
186                }
187        #else // Linux
188                wm->out_sock = -1;
189                wm->in_sock = -1;
190        #endif
191
192        wm->leds = 0;
193        wm->state = WIIMOTE_INIT_STATES;
194        wm->read_req = NULL;
195        wm->handshake_state = 0;
196        wm->btns = 0;
197        wm->btns_held = 0;
198        wm->btns_released = 0;
199        memset(wm->event_buf, 0, sizeof(wm->event_buf));
200        wm->event = WIIC_DISCONNECT;
201}
202
203
204/**
205 *      @brief  Enable or disable the rumble.
206 *
207 *      @param wm               Pointer to a wiimote_t structure.
208 *      @param status   1 to enable, 0 to disable.
209 */
210void wiic_rumble(struct wiimote_t* wm, int status) {
211        byte buf;
212
213        if (!wm || !WIIMOTE_IS_CONNECTED(wm))
214                return;
215
216        /* make sure to keep the current lit leds */
217        buf = wm->leds;
218
219        if (status) {
220                WIIC_DEBUG("Starting rumble...");
221                WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
222        } else {
223                WIIC_DEBUG("Stopping rumble...");
224                WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_RUMBLE);
225        }
226
227        /* preserve IR state */
228        if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR))
229                buf |= 0x04;
230
231        wiic_send(wm, WM_CMD_RUMBLE, &buf, 1);
232}
233
234
235/**
236 *      @brief  Toggle the state of the rumble.
237 *
238 *      @param wm               Pointer to a wiimote_t structure.
239 */
240void wiic_toggle_rumble(struct wiimote_t* wm) {
241        if (!wm)        return;
242
243        wiic_rumble(wm, !WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE));
244}
245
246
247/**
248 *      @brief  Set the enabled LEDs.
249 *
250 *      @param wm               Pointer to a wiimote_t structure.
251 *      @param leds             What LEDs to enable.
252 *
253 *      \a leds is a bitwise or of WIIMOTE_LED_1, WIIMOTE_LED_2, WIIMOTE_LED_3, or WIIMOTE_LED_4.
254 */
255void wiic_set_leds(struct wiimote_t* wm, int leds) {
256        byte buf;
257
258        if (!wm || !WIIMOTE_IS_CONNECTED(wm)) 
259                return;
260
261        /* remove the lower 4 bits because they control rumble */
262        wm->leds = (leds & 0xF0);
263        buf = wm->leds;
264
265        wiic_send(wm, WM_CMD_LED, &buf, 1);
266}
267
268
269/**
270 *      @brief  Set if the wiimote should report motion sensing.
271 *
272 *      @param wm               Pointer to a wiimote_t structure.
273 *      @param status   1 to enable, 0 to disable.
274 *
275 *      Since reporting motion sensing sends a lot of data,
276 *      the wiimote saves power by not transmitting it
277 *      by default.
278 */
279void wiic_motion_sensing(struct wiimote_t* wm, int status) {
280        if (status)
281                WIIMOTE_ENABLE_STATE(wm, WIIMOTE_STATE_ACC);
282        else
283                WIIMOTE_DISABLE_STATE(wm, WIIMOTE_STATE_ACC);
284
285        wiic_set_report_type(wm);
286}
287
288
289/**
290 *      @brief  Set the report type based on the current wiimote state.
291 *
292 *      @param wm               Pointer to a wiimote_t structure.
293 *
294 *      @return The report type sent.
295 *
296 *      The wiimote reports formatted packets depending on the
297 *      report type that was last requested.  This function will
298 *      update the type of report that should be sent based on
299 *      the current state of the device.
300 */
301int wiic_set_report_type(struct wiimote_t* wm) {
302        byte buf[2];
303        int motion, exp, ir;
304
305        if (!wm || !WIIMOTE_IS_CONNECTED(wm))
306                return 0;
307
308        buf[0] = (WIIMOTE_IS_FLAG_SET(wm, WIIC_CONTINUOUS) ? 0x04 : 0x00);      /* set to 0x04 for continuous reporting */
309        buf[1] = 0x00;
310
311        motion = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_ACC);
312        exp = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_EXP);
313        ir = WIIMOTE_IS_SET(wm, WIIMOTE_STATE_IR);
314
315        if (motion && ir && exp)        buf[1] = WM_RPT_BTN_ACC_IR_EXP;
316        else if (motion && exp)         buf[1] = WM_RPT_BTN_ACC_EXP;
317        else if (motion && ir)          buf[1] = WM_RPT_BTN_ACC_IR;
318        else if (ir && exp)                     buf[1] = WM_RPT_BTN_IR_EXP;
319        else if (ir)                            buf[1] = WM_RPT_BTN_ACC_IR;
320        else if (exp)                           buf[1] = WM_RPT_BTN_EXP; 
321        else if (motion)                        buf[1] = WM_RPT_BTN_ACC;
322        else                                            buf[1] = WM_RPT_BTN;
323
324        WIIC_DEBUG("Setting report type: 0x%x", buf[1]);
325
326        exp = wiic_send(wm, WM_CMD_REPORT_TYPE, buf, 2);
327        if (exp <= 0)
328                return exp;
329
330        return buf[1];
331}
332
333
334/**
335 *      @brief  Read data from the wiimote (callback version).
336 *
337 *      @param wm               Pointer to a wiimote_t structure.
338 *      @param read_cb  Function pointer to call when the data arrives from the wiimote.
339 *      @param buffer   An allocated buffer to store the data as it arrives from the wiimote.
340 *                                      Must be persistent in memory and large enough to hold the data.
341 *      @param addr             The address of wiimote memory to read from.
342 *      @param len              The length of the block to be read.
343 *
344 *      The library can only handle one data read request at a time
345 *      because it must keep track of the buffer and other
346 *      events that are specific to that request.  So if a request
347 *      has already been made, subsequent requests will be added
348 *      to a pending list and be sent out when the previous
349 *      finishes.
350 */
351int wiic_read_data_cb(struct wiimote_t* wm, wiic_read_cb read_cb, byte* buffer, unsigned int addr, unsigned short len) {
352        struct read_req_t* req;
353
354        if (!wm || !WIIMOTE_IS_CONNECTED(wm))
355                return 0;
356        if (!buffer || !len || !read_cb)
357                return 0;
358
359        /* make this request structure */
360        req = (struct read_req_t*)malloc(sizeof(struct read_req_t));
361        req->cb = read_cb;
362        req->buf = buffer;
363        req->addr = addr;
364        req->size = len;
365        req->wait = len;
366        req->dirty = 0;
367        req->next = NULL;
368
369        /* add this to the request list */
370        if (!wm->read_req) {
371                /* root node */
372                wm->read_req = req;
373
374                WIIC_DEBUG("Data read request can be sent out immediately.");
375
376                /* send the request out immediately */
377                wiic_send_next_pending_read_request(wm);
378        } else {
379                struct read_req_t* nptr = wm->read_req;
380                for (; nptr->next; nptr = nptr->next);
381                nptr->next = req;
382
383                WIIC_DEBUG("Added pending data read request.");
384        }
385
386        return 1;
387}
388
389
390/**
391 *      @brief  Read data from the wiimote (event version).
392 *
393 *      @param wm               Pointer to a wiimote_t structure.
394 *      @param buffer   An allocated buffer to store the data as it arrives from the wiimote.
395 *                                      Must be persistent in memory and large enough to hold the data.
396 *      @param addr             The address of wiimote memory to read from.
397 *      @param len              The length of the block to be read.
398 *
399 *      The library can only handle one data read request at a time
400 *      because it must keep track of the buffer and other
401 *      events that are specific to that request.  So if a request
402 *      has already been made, subsequent requests will be added
403 *      to a pending list and be sent out when the previous
404 *      finishes.
405 */
406int wiic_read_data(struct wiimote_t* wm, byte* buffer, unsigned int addr, unsigned short len) {
407        struct read_req_t* req;
408
409        if (!wm || !WIIMOTE_IS_CONNECTED(wm))
410                return 0;
411        if (!buffer || !len)
412                return 0;
413
414        /* make this request structure */
415        req = (struct read_req_t*)malloc(sizeof(struct read_req_t));
416        req->cb = NULL;
417        req->buf = buffer;
418        req->addr = addr;
419        req->size = len;
420        req->wait = len;
421        req->dirty = 0;
422        req->next = NULL;
423
424        /* add this to the request list */
425        if (!wm->read_req) {
426                /* root node */
427                wm->read_req = req;
428
429                WIIC_DEBUG("Data read request can be sent out immediately.");
430
431                /* send the request out immediately */
432                wiic_send_next_pending_read_request(wm);
433        } else {
434                struct read_req_t* nptr = wm->read_req;
435                for (; nptr->next; nptr = nptr->next);
436                nptr->next = req;
437
438                WIIC_DEBUG("Added pending data read request.");
439        }
440
441        return 1;
442}
443
444
445/**
446 *      @brief Send the next pending data read request to the wiimote.
447 *
448 *      @param wm               Pointer to a wiimote_t structure.
449 *
450 *      @see wiic_read_data()
451 *
452 *      This function is not part of the wiic API.
453 */
454void wiic_send_next_pending_read_request(struct wiimote_t* wm) {
455        byte buf[6];
456        struct read_req_t* req;
457
458        if (!wm || !WIIMOTE_IS_CONNECTED(wm))
459                return;
460        if (!wm->read_req)      return;
461
462        /* skip over dirty ones since they have already been read */
463        req = wm->read_req;
464        while (req && req->dirty)
465                req = req->next;
466        if (!req)
467                return;
468               
469        /* the offset is in big endian */
470        *(unsigned int*)(buf) = BIG_ENDIAN_LONG(req->addr);
471        /* the length is in big endian */
472        *(unsigned short*)(buf + 4) = BIG_ENDIAN_SHORT(req->size);
473
474        WIIC_DEBUG("Request read at address: 0x%x  length: %i", req->addr, req->size);
475        wiic_send(wm, WM_CMD_READ_DATA, buf, 6);
476}
477
478
479/**
480 *      @brief Request the wiimote controller status.
481 *
482 *      @param wm               Pointer to a wiimote_t structure.
483 *
484 *      Controller status includes: battery level, LED status, expansions
485 */
486void wiic_status(struct wiimote_t* wm) {
487        byte buf = 0;
488
489        if (!wm || !WIIMOTE_IS_CONNECTED(wm))
490                return;
491
492        WIIC_DEBUG("Requested wiimote status.");
493
494        wiic_send(wm, WM_CMD_CTRL_STATUS, &buf, 1);
495}
496
497
498/**
499 *      @brief Find a wiimote_t structure by its unique identifier.
500 *
501 *      @param wm               Pointer to a wiimote_t structure.
502 *      @param wiimotes The number of wiimote_t structures in \a wm.
503 *      @param unid             The unique identifier to search for.
504 *
505 *      @return Pointer to a wiimote_t structure, or NULL if not found.
506 */
507struct wiimote_t* wiic_get_by_id(struct wiimote_t** wm, int wiimotes, int unid) {
508        int i = 0;
509
510        for (; i < wiimotes; ++i) {
511                if (wm[i]->unid == unid)
512                        return wm[i];
513        }
514
515        return NULL;
516}
517
518
519/**
520 *      @brief  Write data to the wiimote.
521 *
522 *      @param wm                       Pointer to a wiimote_t structure.
523 *      @param addr                     The address to write to.
524 *      @param data                     The data to be written to the memory location.
525 *      @param len                      The length of the block to be written.
526 */
527int wiic_write_data(struct wiimote_t* wm, unsigned int addr, byte* data, byte len) {
528        byte buf[21] = {0};             /* the payload is always 23 */
529
530        if (!wm || !WIIMOTE_IS_CONNECTED(wm))
531                return 0;
532        if (!data || !len)
533                return 0;
534
535        WIIC_DEBUG("Writing %i bytes to memory location 0x%x...", len, addr);
536
537        #ifdef WITH_WIIC_DEBUG
538        {
539                int i = 0;
540                printf("Write data is: ");
541                for (; i < len; ++i)
542                        printf("%x ", data[i]);
543                printf("\n");
544        }
545        #endif
546
547        /* the offset is in big endian */
548        *(int*)(buf) = BIG_ENDIAN_LONG(addr);
549
550        /* length */
551        *(byte*)(buf + 4) = len;
552
553        /* data */
554        memcpy(buf + 5, data, len);
555
556        wiic_send(wm, WM_CMD_WRITE_DATA, buf, 21);
557        return 1;
558}
559
560
561/**
562 *      @brief  Send a packet to the wiimote.
563 *
564 *      @param wm                       Pointer to a wiimote_t structure.
565 *      @param report_type      The report type to send (WIIMOTE_CMD_LED, WIIMOTE_CMD_RUMBLE, etc). Found in wiic.h
566 *      @param msg                      The payload.
567 *      @param len                      Length of the payload in bytes.
568 *
569 *      This function should replace any write()s directly to the wiimote device.
570 */
571int wiic_send(struct wiimote_t* wm, byte report_type, byte* msg, int len) {
572        byte buf[32];           /* no payload is better than this */
573        int rumble = 0;
574
575        buf[0] = WM_SET_REPORT | WM_BT_OUTPUT;
576        buf[1] = report_type;
577
578        switch (report_type) {
579                case WM_CMD_LED:
580                case WM_CMD_RUMBLE:
581                case WM_CMD_CTRL_STATUS:
582                case WM_CMD_REPORT_TYPE:
583                {
584                        /* Rumble flag for: 0x11, 0x13, 0x14, 0x15, 0x19 or 0x1a */
585                        if (WIIMOTE_IS_SET(wm, WIIMOTE_STATE_RUMBLE))
586                                rumble = 1;
587                        break;
588                }
589                default:
590                        break;
591        }
592
593        memcpy(buf+2, msg, len);
594        if (rumble) 
595                buf[2] |= 0x01;
596        else 
597                buf[2] &= 0xFE; // Fix for Wiiuse bug
598
599        #ifdef WITH_WIIC_DEBUG
600        {
601                int x = 2;
602                printf("[DEBUG] (id %i) SEND: (%x) %.2x ", wm->unid, buf[0], buf[1]);
603                for (; x < len+2; ++x)
604                        printf("%.2x ", buf[x]);
605                printf("\n");
606        }
607        #endif
608
609        return wiic_io_write(wm, buf, len+2);
610}
611
612
613/**
614 *      @brief Set flags for the specified wiimote.
615 *
616 *      @param wm                       Pointer to a wiimote_t structure.
617 *      @param enable           Flags to enable.
618 *      @param disable          Flags to disable.
619 *
620 *      @return The flags set after 'enable' and 'disable' have been applied.
621 *
622 *      The values 'enable' and 'disable' may be any flags OR'ed together.
623 *      Flags are defined in wiic.h.
624 */
625int wiic_set_flags(struct wiimote_t* wm, int enable, int disable) {
626        if (!wm)        return 0;
627
628        /* remove mutually exclusive flags */
629        enable &= ~disable;
630        disable &= ~enable;
631
632        wm->flags |= enable;
633        wm->flags &= ~disable;
634
635        return wm->flags;
636}
637
638
639/**
640 *      @brief Set the wiimote smoothing alpha value.
641 *
642 *      @param wm                       Pointer to a wiimote_t structure.
643 *      @param alpha            The alpha value to set. Between 0 and 1.
644 *
645 *      @return Returns the old alpha value.
646 *
647 *      The alpha value is between 0 and 1 and is used in an exponential
648 *      smoothing algorithm.
649 *
650 *      Smoothing is only performed if the WIIC_SMOOTHING is set.
651 */
652float wiic_set_smooth_alpha(struct wiimote_t* wm, float alpha) {
653        float old;
654
655        if (!wm)        return 0.0f;
656
657        old = wm->accel_calib.st_alpha;
658
659        wm->accel_calib.st_alpha = alpha;
660
661        /* if there is a nunchuk set that too */
662        if (wm->exp.type == EXP_NUNCHUK)
663                wm->exp.nunchuk.accel_calib.st_alpha = alpha;
664
665        return old;
666}
667
668
669/**
670 *      @brief  Set the orientation event threshold.
671 *
672 *      @param wm                       Pointer to a wiimote_t structure.
673 *      @param threshold        The decimal place that should be considered a significant change.
674 *
675 *      If threshold is 0.01, and any angle changes by 0.01 then a significant change
676 *      has occured and the event callback will be invoked.  If threshold is 1 then
677 *      the angle has to change by a full degree to generate an event.
678 */
679void wiic_set_orient_threshold(struct wiimote_t* wm, float threshold) {
680        if (!wm)        return;
681
682        wm->orient_threshold = threshold;
683}
684
685
686/**
687 *      @brief  Set the accelerometer event threshold.
688 *
689 *      @param wm                       Pointer to a wiimote_t structure.
690 *      @param threshold        The decimal place that should be considered a significant change.
691 */
692void wiic_set_accel_threshold(struct wiimote_t* wm, int threshold) {
693        if (!wm)        return;
694
695        wm->accel_threshold = threshold;
696}
697
698
699/**
700 *      @brief Try to resync with the wiimote by starting a new handshake.
701 *
702 *      @param wm                       Pointer to a wiimote_t structure.
703 */
704void wiic_resync(struct wiimote_t* wm) {
705        if (!wm)        return;
706
707        wm->handshake_state = 0;
708        wiic_handshake(wm, NULL, 0);
709}
710
711/**
712 *      @brief Update the relative timestamp of a wiimote device
713 *
714 *      @param wm                       Pointer to a wiimote_t structure.
715 */
716void wiic_update_timestamp(struct wiimote_t* wm)
717{
718        // We retrieve the overall gesture timestamp
719        gettimeofday(&(wm->timestamp),0);
720}
Note: See TracBrowser for help on using the repository browser.