Changeset 101

Show
Ignore:
Timestamp:
04/24/07 19:41:13 (2 years ago)
Author:
dsmith
Message:

merge api_overhaul into head (#22, #24, #29)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/ChangeLog

    r91 r101  
     12007-04-24 L. Donnie Smith <cwiid@abstrakraft.org> 
     2        libcwiid 
     3        * rewrite (API overhaul) 
     4 
     5        wmdemo 
     6        * updated for API overhaul 
     7 
     8        wmgui 
     9        * updated for API overhaul 
     10 
     11        wminput 
     12        * updated for API overhaul 
     13 
    1142007-04-15 <work.eric@gmail.com> 
    215        wminput 
  • trunk/NEWS

    r37 r101  
     10.5.03 
     2        - Bugfixes, lswm utility, disconnect messages, wminput infinite wait 
     3 
    140.5.02 
    25        - Bugfixes, configure --disable-ldconfig 
  • trunk/libcwiid/Makefile.in

    r83 r101  
    66MAJOR_VER = 0 
    77MINOR_VER = 1 
    8 SOURCES = connect.c command.c event.c rw.c bluetooth.c util.c queue.c 
     8SOURCES = bluetooth.c command.c connect.c interface.c process.c state.c \ 
     9          thread.c util.c 
    910LDLIBS += -lbluetooth -lpthread -lrt 
    1011LIB_INST_DIR = @libdir@ 
  • trunk/libcwiid/bluetooth.c

    r88 r101  
    1616 * 
    1717 *  ChangeLog: 
     18 *  2007-04-24 L. Donnie Smith (cwiid@abstrakraft.org> 
     19 *  * revised error messages 
     20 * 
    1821 *  2007-04-12 L. Donnie Smith <cwiid@abstrakraft.org> 
    1922 *  * streamlined wiimote filter 
     
    8184        if ((dev_count = hci_inquiry(dev_id, timeout, max_inquiry, NULL, 
    8285                                     &dev_list, IREQ_CACHE_FLUSH)) == -1) { 
    83                 cwiid_err(NULL, "Error on bluetooth device inquiry"); 
     86                cwiid_err(NULL, "Bluetooth device inquiry error"); 
    8487                err = 1; 
    8588                goto CODA; 
     
    9396        /* Open connection to Bluetooth Interface */ 
    9497        if ((sock = hci_open_dev(dev_id)) == -1) { 
    95                 cwiid_err(NULL, "Error opening Bluetooth interface"); 
     98                cwiid_err(NULL, "Bluetooth interface open error"); 
    9699                err = 1; 
    97100                goto CODA; 
     
    103106        } 
    104107        if ((*bdinfo = malloc(max_bdinfo * sizeof **bdinfo)) == NULL) { 
    105                 cwiid_err(NULL, "Error mallocing bdinfo array"); 
     108                cwiid_err(NULL, "Memory allocation error (bdinfo array)"); 
    106109                err = 1; 
    107110                goto CODA; 
     
    122125                if (hci_remote_name(sock, &dev_list[i].bdaddr, BT_NAME_LEN, 
    123126                                    (*bdinfo)[bdinfo_count].name, 10000)) { 
    124                         cwiid_err(NULL, "Error reading Bluetooth device name"); 
     127                        cwiid_err(NULL, "Bluetooth name read error"); 
    125128                        err = 1; 
    126129                        goto CODA; 
     
    148151                if ((*bdinfo = realloc(*bdinfo, bdinfo_count * sizeof **bdinfo)) 
    149152                  == NULL) { 
    150                         cwiid_err(NULL, "Error reallocing bdinfo array"); 
     153                        cwiid_err(NULL, "Memory reallocation error (bdinfo array)"); 
    151154                        err = 1; 
    152155                        goto CODA; 
  • trunk/libcwiid/command.c

    r83 r101  
    1616 * 
    1717 *  ChangeLog: 
     18 *  2007-04-24 L. Donnie Smith <cwiid@abstrakraft.org> 
     19 *  * rewrite for API overhaul 
     20 *  * added rw and beep functions from rw.c 
     21 * 
    1822 *  2007-04-09 L. Donnie Smith <cwiid@abstrakraft.org> 
    1923 *  * renamed wiimote to libcwiid, renamed structures accordingly 
     24 * 
     25 *  2007-04-04 L. Donnie Smith <cwiid@abstrakraft.org> 
     26 *  * updated cwiid_read and cwiid_write to trigger and detect rw_error 
    2027 * 
    2128 *  2007-03-14 L. Donnie Smith <cwiid@abstrakraft.org> 
    2229 *  * audited error checking (coda and error handler sections) 
    2330 *  * updated comments 
     31 *  * cwiid_read - changed to obey decode flag only for register read 
    2432 * 
    2533 *  2007-03-06 L. Donnie Smith <cwiid@abstrakraft.org> 
     
    3240 
    3341#include <stdint.h> 
     42#include <time.h> 
     43#include <pthread.h> 
    3444#include <unistd.h> 
    3545#include "cwiid_internal.h" 
    3646 
    37 /* IR Sensitivity Block */ 
    38 unsigned char ir_block1[] = CLIFF_IR_BLOCK_1; 
    39 unsigned char ir_block2[] = CLIFF_IR_BLOCK_2; 
    40  
    41 struct write_seq ir_enable10_seq[] = { 
    42         {WRITE_SEQ_RPT, RPT_IR_ENABLE1, (const void *)"\x04", 1, 0}, 
    43         {WRITE_SEQ_RPT, RPT_IR_ENABLE2, (const void *)"\x04", 1, 0}, 
    44         {WRITE_SEQ_MEM, 0xB00030, (const void *)"\x08", 1,     CWIID_RW_REG}, 
    45         {WRITE_SEQ_MEM, 0xB00000, ir_block1, sizeof(ir_block1)-1, CWIID_RW_REG}, 
    46         {WRITE_SEQ_MEM, 0xB0001A, ir_block2, sizeof(ir_block2)-1, CWIID_RW_REG}, 
    47         {WRITE_SEQ_MEM, 0xB00033, (const void *)"\x01", 1,     CWIID_RW_REG} 
    48 }; 
    49  
    50 struct write_seq ir_enable12_seq[] = { 
    51         {WRITE_SEQ_RPT, RPT_IR_ENABLE1, (const void *)"\x04", 1, 0}, 
    52         {WRITE_SEQ_RPT, RPT_IR_ENABLE2, (const void *)"\x04", 1, 0}, 
    53         {WRITE_SEQ_MEM, 0xB00030, (const void *)"\x08", 1,     CWIID_RW_REG}, 
    54         {WRITE_SEQ_MEM, 0xB00000, ir_block1, sizeof(ir_block1)-1, CWIID_RW_REG}, 
    55         {WRITE_SEQ_MEM, 0xB0001A, ir_block2, sizeof(ir_block2)-1, CWIID_RW_REG}, 
    56         {WRITE_SEQ_MEM, 0xB00033, (const void *)"\x03", 1,     CWIID_RW_REG} 
    57 }; 
    58  
    59 struct write_seq ir_disable_seq[] = { 
    60         {WRITE_SEQ_RPT, RPT_IR_ENABLE1, (const void *)"\x00", 1, 0}, 
    61         {WRITE_SEQ_RPT, RPT_IR_ENABLE2, (const void *)"\x00", 1, 0} 
    62 }; 
    63  
    6447#define CMD_BUF_LEN     21 
    6548int cwiid_command(struct wiimote *wiimote, enum cwiid_command command, 
    66                   uint8_t flags) { 
     49                  int flags) { 
    6750        int ret = 0; 
    6851        unsigned char buf[CMD_BUF_LEN]; 
    6952 
     53        /* TODO: assumption: char assignments are atomic, no mutex lock needed */ 
    7054        switch (command) { 
    7155        case CWIID_CMD_STATUS: 
    7256                buf[0] = 0; 
    7357                if (send_report(wiimote, 0, RPT_STATUS_REQ, 1, buf)) { 
    74                         cwiid_err(wiimote, "Error requesting status"); 
     58                        cwiid_err(wiimote, "Status request error"); 
    7559                        ret = -1; 
    7660                } 
    7761                break; 
    7862        case CWIID_CMD_LED: 
    79                 wiimote->led_rumble_state = ((flags & 0x0F)<<4) | 
    80                                             (wiimote->led_rumble_state & 0x01); 
    81                 buf[0]=wiimote->led_rumble_state; 
     63                wiimote->state.led = flags & 0x0F; 
     64                buf[0] = wiimote->state.led<<4 | wiimote->state.rumble; 
    8265                if (send_report(wiimote, SEND_RPT_NO_RUMBLE, RPT_LED_RUMBLE, 1, buf)) { 
    83                         cwiid_err(wiimote, "Error setting LEDs"); 
     66                        cwiid_err(wiimote, "Report send error (led)"); 
    8467                        ret = -1; 
    8568                } 
    8669                break; 
    8770        case CWIID_CMD_RUMBLE: 
    88                 wiimote->led_rumble_state = (wiimote->led_rumble_state & 0xFE) | 
    89                                             (flags ? 1 : 0); 
    90                 buf[0]=wiimote->led_rumble_state; 
     71                wiimote->state.rumble = flags ? 1 : 0; 
     72                buf[0] = wiimote->state.led<<4 | wiimote->state.rumble; 
    9173                if (send_report(wiimote, SEND_RPT_NO_RUMBLE, RPT_LED_RUMBLE, 1, buf)) { 
    92                         cwiid_err(wiimote, "Error setting rumble"); 
     74                        cwiid_err(wiimote, "Report send error (rumble)"); 
    9375                        ret = -1; 
    9476                } 
     
    9880                break; 
    9981        default: 
    100                 cwiid_err(wiimote, "Unknown command"); 
    10182                ret = -1; 
    10283                break; 
     
    10687} 
    10788 
    108 #define RPT_MODE_BUF_LEN 2 
    109 int update_rpt_mode(struct wiimote *wiimote, int8_t flags) 
     89#define RPT_READ_REQ_LEN 6 
     90int cwiid_read(struct wiimote *wiimote, uint8_t flags, uint32_t offset, 
     91               uint16_t len, void *data) 
    11092{ 
    111         unsigned char buf[RPT_MODE_BUF_LEN]; 
    112         uint8_t rpt_mode; 
    113         struct write_seq *ir_enable_seq; 
    114         int seq_len; 
     93        unsigned char buf[RPT_READ_REQ_LEN]; 
     94        struct rw_mesg mesg; 
     95        unsigned char *cursor; 
    11596        int ret = 0; 
    116  
    117         /* Lock wiimote access */ 
    118         if (pthread_mutex_lock(&wiimote->wiimote_mutex)) { 
    119                 cwiid_err(wiimote, "Error locking wiimote_mutex"); 
     97        int i; 
     98 
     99        /* Compose read request packet */ 
     100        buf[0]=flags & (CWIID_RW_EEPROM | CWIID_RW_REG); 
     101        buf[1]=(unsigned char)((offset>>16) & 0xFF); 
     102        buf[2]=(unsigned char)((offset>>8) & 0xFF); 
     103        buf[3]=(unsigned char)(offset & 0xFF); 
     104        buf[4]=(unsigned char)((len>>8) & 0xFF); 
     105        buf[5]=(unsigned char)(len & 0xFF); 
     106 
     107        /* Lock wiimote rw access */ 
     108        if (pthread_mutex_lock(&wiimote->rw_mutex)) { 
     109                cwiid_err(wiimote, "Mutex lock error (rw_mutex)"); 
     110                return -1; 
     111        } 
     112 
     113        /* Setup read info */ 
     114        wiimote->rw_status = RW_READ; 
     115 
     116        /* TODO: Document: user is responsible for ensuring that read/write 
     117         * operations are not in flight while disconnecting.  Nothing serious, 
     118         * just accesses to freed memory */ 
     119        /* Send read request packet */ 
     120        if (send_report(wiimote, 0, RPT_READ_REQ, RPT_READ_REQ_LEN, buf)) { 
     121                cwiid_err(wiimote, "Report send error (read)"); 
    120122                ret = -1; 
    121123                goto CODA; 
    122124        } 
    123125 
    124         /* Use -1 to update the reporting mode without changing flags */ 
    125         if (flags == -1) { 
    126                 flags = wiimote->rpt_mode_flags; 
    127         } 
    128  
    129         /* Pick a report mode based on report flags */ 
    130         if ((flags & CWIID_RPT_EXT) && 
    131           ((wiimote->extension == CWIID_EXT_NUNCHUK) || 
    132            (wiimote->extension == CWIID_EXT_CLASSIC))) { 
    133                 if ((flags & CWIID_RPT_IR) && 
    134                   (flags & CWIID_RPT_ACC)) { 
    135                         rpt_mode = RPT_BTN_ACC_IR10_EXT6; 
    136                         ir_enable_seq = ir_enable10_seq; 
    137                         seq_len = SEQ_LEN(ir_enable10_seq); 
    138                 } 
    139                 else if (flags & CWIID_RPT_IR) { 
    140                         rpt_mode = RPT_BTN_IR10_EXT9; 
    141                         ir_enable_seq = ir_enable10_seq; 
    142                         seq_len = SEQ_LEN(ir_enable10_seq); 
    143                 } 
    144                 else if (flags & CWIID_RPT_ACC) { 
    145                         rpt_mode = RPT_BTN_ACC_EXT16; 
    146                 } 
    147                 else if (flags & CWIID_RPT_BTN) { 
    148                         rpt_mode = RPT_BTN_EXT8; 
    149                 } 
    150                 else { 
    151                         rpt_mode = RPT_EXT21; 
    152                 }        
    153         } 
    154         else { 
    155                 if (flags & CWIID_RPT_IR) { 
    156                         rpt_mode = RPT_BTN_ACC_IR12; 
    157                         ir_enable_seq = ir_enable12_seq; 
    158                         seq_len = SEQ_LEN(ir_enable12_seq); 
    159                 } 
    160                 else if (flags & CWIID_RPT_ACC) { 
    161                         rpt_mode = RPT_BTN_ACC; 
    162                 } 
    163                 else { 
    164                         rpt_mode = RPT_BTN; 
    165                 } 
    166         } 
    167  
    168         /* Enable IR */ 
    169         /* TODO: only do this when necessary (record old IR mode) */ 
    170         if ((flags & CWIID_RPT_IR)) { 
    171                 if (exec_write_seq(wiimote, seq_len, ir_enable_seq)) { 
    172                         cwiid_err(wiimote, "Error on IR enable"); 
    173                         ret = -1; 
    174                         goto CODA; 
    175                 } 
    176         } 
    177         /* Disable IR */ 
    178         else if ((wiimote->rpt_mode_flags & CWIID_RPT_IR) & 
    179                  !(flags & CWIID_RPT_IR)) { 
    180                 if (exec_write_seq(wiimote, SEQ_LEN(ir_disable_seq), 
    181                                    ir_disable_seq)) { 
    182                         cwiid_err(wiimote, "Error on IR enable"); 
    183                         ret = -1; 
    184                         goto CODA; 
    185                 } 
    186         } 
    187  
    188         /* Send SET_REPORT */ 
    189         buf[0]=0; 
    190         buf[1]=rpt_mode; 
    191         if (send_report(wiimote, 0, RPT_RPT_MODE, RPT_MODE_BUF_LEN, buf)) { 
    192                 cwiid_err(wiimote, "Error setting report state"); 
    193                 ret = -1; 
    194                 goto CODA; 
    195         } 
    196  
    197         wiimote->rpt_mode_flags = flags; 
     126        /* TODO:Better sanity checks (offset) */ 
     127        /* Read packets */ 
     128        for (cursor = data; cursor - (unsigned char *)data < len; 
     129             cursor += mesg.len) { 
     130                if (full_read(wiimote->rw_pipe[0], &mesg, sizeof mesg)) { 
     131                        cwiid_err(wiimote, "Pipe read error (rw pipe)"); 
     132                        ret = -1; 
     133                        goto CODA; 
     134                } 
     135 
     136                if (mesg.type == RW_CANCEL) { 
     137                        ret = -1; 
     138                        goto CODA; 
     139                } 
     140                else if (mesg.type != RW_READ) { 
     141                        cwiid_err(wiimote, "Unexpected write message"); 
     142                        ret = -1; 
     143                        goto CODA; 
     144                } 
     145 
     146                if (mesg.error) { 
     147                        cwiid_err(wiimote, "Wiimote read error"); 
     148                        ret = -1; 
     149                        goto CODA; 
     150                } 
     151 
     152                memcpy(cursor, &mesg.data, mesg.len); 
     153        } 
    198154 
    199155CODA: 
    200         /* Unlock cwiid_mutex */ 
    201         if (pthread_mutex_unlock(&wiimote->wiimote_mutex)) { 
    202                 cwiid_err(wiimote, "Error unlocking wiimote_mutex: deadlock warning"); 
     156        /* Clear rw_status */ 
     157        wiimote->rw_status = RW_IDLE; 
     158 
     159        /* Unlock rw_mutex */ 
     160        if (pthread_mutex_unlock(&wiimote->rw_mutex)) { 
     161                cwiid_err(wiimote, "Mutex unlock error (rw_mutex) - deadlock warning"); 
     162        } 
     163 
     164        /* Decode (only for register reads) */ 
     165        if ((ret == 0) && (flags & CWIID_RW_DECODE) && (flags & CWIID_RW_REG)) { 
     166                for (i=0; i < len; i++) { 
     167                        ((unsigned char *)data)[i] = DECODE(((unsigned char *)data)[i]); 
     168                } 
    203169        } 
    204170 
     
    206172} 
    207173 
     174#define RPT_WRITE_LEN 21 
     175int cwiid_write(struct wiimote *wiimote, uint8_t flags, uint32_t offset, 
     176                  uint16_t len, const void *data) 
     177{ 
     178        unsigned char buf[RPT_WRITE_LEN]; 
     179        uint16_t sent=0; 
     180        struct rw_mesg mesg; 
     181        int ret = 0; 
     182 
     183        /* Compose write packet header */ 
     184        buf[0]=flags; 
     185 
     186        /* Lock wiimote rw access */ 
     187        if (pthread_mutex_lock(&wiimote->rw_mutex)) { 
     188                cwiid_err(wiimote, "Mutex lock error (rw mutex)"); 
     189                return -1; 
     190        } 
     191 
     192        /* Send packets */ 
     193        wiimote->rw_status = RW_WRITE; 
     194        while (sent<len) { 
     195                /* Compose write packet */ 
     196                buf[1]=(unsigned char)(((offset+sent)>>16) & 0xFF); 
     197                buf[2]=(unsigned char)(((offset+sent)>>8) & 0xFF); 
     198                buf[3]=(unsigned char)((offset+sent) & 0xFF); 
     199                if (len-sent >= 0x10) { 
     200                        buf[4]=(unsigned char)0x10; 
     201                } 
     202                else { 
     203                        buf[4]=(unsigned char)(len-sent); 
     204                } 
     205                memcpy(buf+5, data+sent, buf[4]); 
     206 
     207                if (send_report(wiimote, 0, RPT_WRITE, RPT_WRITE_LEN, buf)) { 
     208                        cwiid_err(wiimote, "Report send error (write)"); 
     209                        ret = -1; 
     210                        goto CODA; 
     211                } 
     212 
     213                /* Read packets from pipe */ 
     214                if (read(wiimote->rw_pipe[0], &mesg, sizeof mesg) != sizeof mesg) { 
     215                        cwiid_err(wiimote, "Pipe read error (rw pipe)"); 
     216                        ret = -1; 
     217                        goto CODA; 
     218                } 
     219 
     220                if (mesg.type == RW_CANCEL) { 
     221                        ret = -1; 
     222                        goto CODA; 
     223                } 
     224                else if (mesg.type != RW_WRITE) { 
     225                        cwiid_err(wiimote, "Unexpected read message"); 
     226                        ret = -1; 
     227                        goto CODA; 
     228                } 
     229 
     230                if (mesg.error) { 
     231                        cwiid_err(wiimote, "Wiimote write error"); 
     232                        ret = -1; 
     233                        goto CODA; 
     234                }; 
     235 
     236                sent+=buf[4]; 
     237        } 
     238 
     239CODA: 
     240        /* Clear rw_status */ 
     241        wiimote->rw_status = RW_IDLE; 
     242 
     243        /* Unlock rw_mutex */ 
     244        if (pthread_mutex_unlock(&wiimote->rw_mutex)) { 
     245                cwiid_err(wiimote, "Mutex unlock error (rw_mutex) - deadlock warning"); 
     246        } 
     247 
     248        return ret; 
     249} 
     250 
     251 
     252struct write_seq speaker_enable_seq[] = { 
     253        {WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x04", 1, 0}, 
     254        {WRITE_SEQ_RPT,   RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0}, 
     255        {WRITE_SEQ_MEM, 0xA20009, (const void *)"\x01", 1, CWIID_RW_REG}, 
     256        {WRITE_SEQ_MEM, 0xA20001, (const void *)"\x08", 1, CWIID_RW_REG}, 
     257        {WRITE_SEQ_MEM, 0xA20001, (const void *)"\x00\x00\x00\x0C\x40\x00\x00", 
     258                                  7, CWIID_RW_REG}, 
     259        {WRITE_SEQ_MEM, 0xA20008, (const void *)"\x01", 1, CWIID_RW_REG}, 
     260        {WRITE_SEQ_RPT,   RPT_SPEAKER_MUTE, (const void *)"\x00", 1, 0} 
     261}; 
     262 
     263struct write_seq speaker_disable_seq[] = { 
     264        {WRITE_SEQ_RPT,   RPT_SPEAKER_MUTE, (const void *)"\x04", 1, 0}, 
     265        {WRITE_SEQ_RPT, RPT_SPEAKER_ENABLE, (const void *)"\x00", 1, 0} 
     266}; 
     267 
     268#define SOUND_BUF_LEN   21 
     269int cwiid_beep(cwiid_wiimote_t *wiimote) 
     270{ 
     271        /* unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xCC, 0x33, 0xCC, 0x33, 
     272            0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 0xCC, 0x33, 
     273            0xCC, 0x33, 0xCC, 0x33}; */ 
     274        unsigned char buf[SOUND_BUF_LEN] = { 0xA0, 0xC3, 0xC3, 0xC3, 0xC3, 
     275            0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 
     276            0xC3, 0xC3, 0xC3, 0xC3}; 
     277        int i; 
     278        int ret = 0; 
     279        pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER; 
     280        pthread_cond_t timer_cond = PTHREAD_COND_INITIALIZER; 
     281        struct timespec t; 
     282 
     283        if (exec_write_seq(wiimote, SEQ_LEN(speaker_enable_seq), 
     284                           speaker_enable_seq)) { 
     285                cwiid_err(wiimote, "Speaker enable error"); 
     286                ret = -1; 
     287        } 
     288 
     289        pthread_mutex_lock(&timer_mutex); 
     290 
     291        for (i=0; i<100; i++) { 
     292                clock_gettime(CLOCK_REALTIME, &t); 
     293                t.tv_nsec += 10204081; 
     294                /* t.tv_nsec += 7000000; */ 
     295                if (send_report(wiimote, 0, RPT_SPEAKER_DATA, SOUND_BUF_LEN, buf)) { 
     296                        printf("%d\n", i); 
     297                        cwiid_err(wiimote, "Report send error (speaker data)"); 
     298                        ret = -1; 
     299                        break; 
     300                } 
     301                /* TODO: I should be shot for this, but hey, it works. 
     302                 * longterm - find a better wait */ 
     303                pthread_cond_timedwait(&timer_cond, &timer_mutex, &t); 
     304        } 
     305 
     306        pthread_mutex_unlock(&timer_mutex); 
     307 
     308        if (exec_write_seq(wiimote, SEQ_LEN(speaker_disable_seq), 
     309                           speaker_disable_seq)) { 
     310                cwiid_err(wiimote, "Speaker disable error"); 
     311                ret = -1; 
     312        } 
     313 
     314        return ret; 
     315} 
  • trunk/libcwiid/connect.c

    r83 r101  
    1616 * 
    1717 *  ChangeLog: 
     18 *  2007-04-24 L. Donnie Smith <cwiid@abstrakraft.org> 
     19 *  * rewrite for API overhaul 
     20 * 
    1821 *  2007-04-09 L. Donnie Smith <cwiid@abstrakraft.org> 
    1922 *  * renamed wiimote to libcwiid, renamed structures accordingly 
     
    3841 */ 
    3942 
    40 #include <pthread.h> 
    4143#include <stdlib.h> 
    4244#include <string.h> 
     45#include <fcntl.h> 
     46#include <pthread.h> 
    4347#include <sys/types.h> 
    4448#include <sys/socket.h> 
     
    4751#include <bluetooth/l2cap.h> 
    4852#include "cwiid_internal.h" 
    49 #include "queue.h" 
    5053 
    5154pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER; 
    5255static int wiimote_id = 0; 
    5356 
    54 cwiid_wiimote_t *cwiid_connect(bdaddr_t *bdaddr, 
    55                                cwiid_mesg_callback_t *mesg_callback, int *id) 
     57cwiid_wiimote_t *cwiid_connect(bdaddr_t *bdaddr, int flags) 
    5658{ 
    5759        struct wiimote *wiimote = NULL; 
    58         struct sockaddr_l2 ctl_remote_addr, int_remote_addr; 
     60        struct sockaddr_l2 remote_addr; 
     61        char mesg_pipe_init = 0, status_pipe_init = 0, error_pipe_init = 0, 
     62             rw_pipe_init = 0, state_mutex_init = 0, rw_mutex_init = 0, 
     63             rpt_mutex_init = 0, router_thread_init = 0, status_thread_init = 0; 
     64        void *pthread_ret; 
    5965 
    6066        /* Allocate wiimote */ 
    6167        if ((wiimote = malloc(sizeof *wiimote)) == NULL) { 
    62                 cwiid_err(NULL, "Error allocating cwiid_wiimote"); 
    63                 goto ERR_HND; 
    64         } 
    65  
    66         /* Set wiimote members for proper error detection */ 
    67         wiimote->ctl_socket = -1; 
    68         wiimote->int_socket = -1; 
    69         wiimote->dispatch_queue = NULL; 
     68                cwiid_err(NULL, "Memory allocation error (cwiid_wiimote_t)"); 
     69                goto ERR_HND; 
     70        } 
     71 
     72        /* set flags */ 
     73        wiimote->flags = flags; 
     74 
     75        /* For error detection */ 
     76        wiimote->ctl_socket = wiimote->int_socket = -1; 
    7077 
    7178        /* Global Lock, Store and Increment wiimote_id */ 
    7279        if (pthread_mutex_lock(&global_mutex)) { 
    73                 cwiid_err(NULL, "Error locking global lock"); 
     80                cwiid_err(NULL, "Mutex lock error (global mutex)"); 
    7481                goto ERR_HND; 
    7582        } 
    7683        wiimote->id = wiimote_id++; 
    7784        if (pthread_mutex_unlock(&global_mutex)) { 
    78                 cwiid_err(wiimote, "Error unlocking global lock"); 
    79                 goto ERR_HND; 
    80         } 
    81         /* Return the id in a pointer, if desired */ 
    82         if (id) { 
    83                 *id = wiimote->id; 
    84         } 
    85  
    86         /* Store mesg callback */ 
    87         wiimote->mesg_callback = mesg_callback; 
     85                cwiid_err(wiimote, "Mutex unlock error (global mutex) - " 
     86                                   "deadlock warning"); 
     87                goto ERR_HND; 
     88        } 
    8889 
    8990        /* If BDADDR_ANY is given, find available wiimote */ 
     
    9495        } 
    9596 
    96         /* Clear address structs, fill address family, address, and ports */ 
    97         memset(&ctl_remote_addr, 0, sizeof(ctl_remote_addr)); 
    98         ctl_remote_addr.l2_family = AF_BLUETOOTH; 
    99         ctl_remote_addr.l2_bdaddr = *bdaddr; 
    100         ctl_remote_addr.l2_psm = htobs(CTL_PSM); 
    101  
    102         memset(&int_remote_addr, 0, sizeof(int_remote_addr)); 
    103         int_remote_addr.l2_family = AF_BLUETOOTH; 
    104         int_remote_addr.l2_bdaddr = *bdaddr; 
    105         int_remote_addr.l2_psm = htobs(INT_PSM); 
    106  
    107         /* Get Bluetooth Sockets */ 
     97        /* Connect to Wiimote */ 
     98        /* Control Channel */ 
     99        memset(&remote_addr, 0, sizeof remote_addr); 
     100        remote_addr.l2_family = AF_BLUETOOTH; 
     101        remote_addr.l2_bdaddr = *bdaddr; 
     102        remote_addr.l2_psm = htobs(CTL_PSM); 
    108103        if ((wiimote->ctl_socket = 
    109104          socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) { 
    110                 cwiid_err(wiimote, "Error opening control socket"); 
    111                 goto ERR_HND; 
    112         } 
     105                cwiid_err(wiimote, "Socket creation error (control socket)"); 
     106                goto ERR_HND; 
     107        } 
     108        if (connect(wiimote->ctl_socket, (struct sockaddr *)&remote_addr, 
     109                        sizeof remote_addr)) { 
     110                cwiid_err(wiimote, "Socket connect error (control channel)"); 
     111                goto ERR_HND; 
     112        } 
     113 
     114        /* Interrupt Channel */ 
     115        remote_addr.l2_psm = htobs(INT_PSM); 
    113116        if ((wiimote->int_socket = 
    114117          socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1) { 
    115                 cwiid_err(wiimote, "Error opening interrupt socket"); 
    116                 goto ERR_HND; 
    117         } 
    118  
    119         /* Connect to Wiimote */ 
    120         if (connect(wiimote->ctl_socket, (struct sockaddr *)&ctl_remote_addr, 
    121                         sizeof(ctl_remote_addr))) { 
    122                 cwiid_err(wiimote, "Error opening control channel"); 
    123                 goto ERR_HND; 
    124         } 
    125         if (connect(wiimote->int_socket, (struct sockaddr *)&int_remote_addr, 
    126                         sizeof(int_remote_addr))) { 
    127                 cwiid_err(wiimote, "Error opening interrupt channel"); 
    128                 goto ERR_HND; 
    129         } 
    130  
    131         /* Create Dispatch Queue */ 
    132         if ((wiimote->dispatch_queue = queue_new()) == NULL) { 
    133                 cwiid_err(wiimote, "Error creating dispatch queue"); 
    134                 goto ERR_HND; 
    135         } 
    136  
    137         /* TODO: backout logic (pthread_*_destroy) */ 
    138         /* Mutex and cond init */ 
    139         if (pthread_mutex_init(&wiimote->wiimote_mutex, NULL) || 
    140           pthread_mutex_init(&wiimote->rw_mutex, NULL) || 
    141           pthread_cond_init(&wiimote->rw_cond, NULL) || 
    142           pthread_mutex_init(&wiimote->rw_cond_mutex, NULL)) { 
    143                 cwiid_err(wiimote, "Error initializing synchronization variables"); 
    144                 goto ERR_HND; 
    145         } 
    146  
    147         /* Set rw_status before interrupt thread */ 
    148         wiimote->rw_status = RW_NONE; 
    149         wiimote->rw_error = 0; 
     118                cwiid_err(wiimote, "Socket creation error (interrupt socket)"); 
     119                goto ERR_HND; 
     120        } 
     121        if (connect(wiimote->int_socket, (struct sockaddr *)&remote_addr, 
     122                        sizeof remote_addr)) { 
     123                cwiid_err(wiimote, "Socket connect error (interrupt channel)"); 
     124                goto ERR_HND; 
     125        } 
     126 
     127        /* Create pipes */ 
     128        if (pipe(wiimote->mesg_pipe)) { 
     129                cwiid_err(wiimote, "Pipe creation error (mesg pipe)"); 
     130                goto ERR_HND; 
     131        } 
     132        mesg_pipe_init = 1; 
     133        if (pipe(wiimote->status_pipe)) { 
     134                cwiid_err(wiimote, "Pipe creation error (status pipe)"); 
     135                goto ERR_HND; 
     136        } 
     137        status_pipe_init = 1; 
     138        if (pipe(wiimote->error_pipe)) { 
     139                cwiid_err(wiimote, "Pipe creation error (error pipe)"); 
     140                goto ERR_HND; 
     141        } 
     142        error_pipe_init = 1; 
     143        if (pipe(wiimote->rw_pipe)) { 
     144                cwiid_err(wiimote, "Pipe creation error (rw pipe)"); 
     145                goto ERR_HND; 
     146        } 
     147        rw_pipe_init = 1; 
     148 
     149        /* Setup blocking */ 
     150        if (fcntl(wiimote->mesg_pipe[1], F_SETFL, O_NONBLOCK)) { 
     151                cwiid_err(wiimote, "File control error (mesg write pipe)"); 
     152                goto ERR_HND; 
     153        } 
     154        if (wiimote->flags & CWIID_FLAG_NONBLOCK) { 
     155                if (fcntl(wiimote->mesg_pipe[0], F_SETFL, O_NONBLOCK)) { 
     156                        cwiid_err(wiimote, "File control error (mesg read pipe)"); 
     157                        goto ERR_HND; 
     158                } 
     159        } 
     160 
     161        /* Init mutexes */ 
     162        if (pthread_mutex_init(&wiimote->state_mutex, NULL)) { 
     163                cwiid_err(wiimote, "Mutex initialization error (state mutex)"); 
     164                goto ERR_HND; 
     165        } 
     166        state_mutex_init = 1; 
     167        if (pthread_mutex_init(&wiimote->rw_mutex, NULL)) { 
     168                cwiid_err(wiimote, "Mutex initialization error (rw mutex)"); 
     169                goto ERR_HND; 
     170        } 
     171        rw_mutex_init = 1; 
     172        if (pthread_mutex_init(&wiimote->rpt_mutex, NULL)) { 
     173                cwiid_err(wiimote, "Mutex initialization error (rpt mutex)"); 
     174                goto ERR_HND; 
     175        } 
     176        rpt_mutex_init = 1; 
     177 
     178        /* Set rw_status before starting router thread */ 
     179        wiimote->rw_status = RW_IDLE; 
    150180 
    151181        /* Launch interrupt channel listener and dispatch threads */ 
    152         if (pthread_create(&wiimote->int_listen_thread, NULL, 
    153                            (void *(*)(void *))&int_listen, wiimote)) { 
    154                 cwiid_err(wiimote, "Error creating interrupt channel listener thread"); 
    155                 goto ERR_HND; 
    156         } 
    157         if (pthread_create(&wiimote->dispatch_thread, NULL, 
    158                            (void *(*)(void *))&dispatch, wiimote)) { 
    159                pthread_cancel(wiimote->int_listen_thread); 
    160                 pthread_join(wiimote->int_listen_thread, NULL); 
    161                 cwiid_err(wiimote, "Error creating dispatch thread")
    162                goto ERR_HND; 
    163         } 
     182        if (pthread_create(&wiimote->router_thread, NULL, 
     183                           (void *(*)(void *))&router_thread, wiimote)) { 
     184                cwiid_err(wiimote, "Thread creation error (router thread)"); 
     185                goto ERR_HND; 
     186        } 
     187        router_thread_init = 1; 
     188        if (pthread_create(&wiimote->status_thread, NULL, 
     189                           (void *(*)(void *))&status_thread, wiimote)) { 
     190                cwiid_err(wiimote, "Thread creation error (status thread)"); 
     191                goto ERR_HND
     192        } 
     193        status_thread_init = 1; 
    164194 
    165195        /* Success!  Update state */ 
    166         wiimote->buttons = 0; 
    167         wiimote->rpt_mode_flags = 0; 
    168         wiimote->extension = CWIID_EXT_NONE; 
    169         wiimote->led_rumble_state = 0; 
     196        memset(&wiimote->state, 0, sizeof wiimote->state); 
     197        wiimote->mesg_callback = NULL; 
    170198        cwiid_command(wiimote, CWIID_CMD_LED, 0); 
    171199        cwiid_command(wiimote, CWIID_CMD_STATUS, 0); 
     
    175203ERR_HND: 
    176204        if (wiimote) { 
    177                 if (wiimote->dispatch_queue) { 
    178                         queue_free(wiimote->dispatch_queue, 
    179                                    (free_func_t *)free_mesg_array); 
    180                 } 
     205                /* Close threads */ 
     206                if (router_thread_init) { 
     207                        pthread_cancel(wiimote->router_thread); 
     208                        if (pthread_join(wiimote->router_thread, &pthread_ret)) { 
     209                                cwiid_err(wiimote, "Thread join error (router thread)"); 
     210                        } 
     211                        else if (!((pthread_ret == PTHREAD_CANCELED) && 
     212                                 (pthread_ret == NULL))) { 
     213                                cwiid_err(wiimote, "Bad return value from router thread"); 
     214                        } 
     215                } 
     216 
     217                if (status_thread_init) { 
     218                        pthread_cancel(wiimote->status_thread); 
     219                        if (pthread_join(wiimote->status_thread, &pthread_ret)) { 
     220                                cwiid_err(wiimote, "Thread join error (status thread)"); 
     221                        } 
     222                        else if (!((pthread_ret == PTHREAD_CANCELED) && (pthread_ret == NULL))) { 
     223                                cwiid_err(wiimote, "Bad return value from status thread"); 
     224                        } 
     225                } 
     226 
     227                /* Close Sockets */ 
    181228                if (wiimote->int_socket != -1) { 
    182229                        if (close(wiimote->int_socket)) { 
    183                                 cwiid_err(wiimote, "Error closing interrupt channel"); 
     230                                cwiid_err(wiimote, "Socket close error (interrupt channel)"); 
    184231                        } 
    185232                } 
    186233                if (wiimote->ctl_socket != -1) { 
    187234                        if (close(wiimote->ctl_socket)) { 
    188                                 cwiid_err(wiimote, "Error closing control channel"); 
     235                                cwiid_err(wiimote, "Socket close error (control channel)"); 
     236                        } 
     237                } 
     238                /* Close Pipes */ 
     239                if (mesg_pipe_init) { 
     240                        if (close(wiimote->mesg_pipe[0]) || close(wiimote->mesg_pipe[1])) { 
     241                                cwiid_err(wiimote, "Pipe close error (mesg pipe)"); 
     242                        } 
     243                } 
     244                if (status_pipe_init) { 
     245                        if (close(wiimote->status_pipe[0]) || 
     246                          close(wiimote->status_pipe[1])) { 
     247                                cwiid_err(wiimote, "Pipe close error (status pipe)"); 
     248                        } 
     249                } 
     250                if (error_pipe_init) { 
     251                        if (close(wiimote->error_pipe[0]) || 
     252                          close(wiimote->error_pipe[1])) { 
     253                                cwiid_err(wiimote, "Pipe close error (error pipe)"); 
     254                        } 
     255                } 
     256                if (rw_pipe_init) { 
     257                        if (close(wiimote->rw_pipe[0]) || close(wiimote->rw_pipe[1])) { 
     258                                cwiid_err(wiimote, "Pipe close error (rw pipe)"); 
     259                        } 
     260                } 
     261                /* Destroy Mutexes */ 
     262                if (state_mutex_init) { 
     263                        if (pthread_mutex_destroy(&wiimote->state_mutex)) { 
     264                                cwiid_err(wiimote, "Mutex destroy error (state mutex)"); 
     265                        } 
     266                } 
     267                if (rw_mutex_init) { 
     268                        if (pthread_mutex_destroy(&wiimote->rw_mutex)) { 
     269                                cwiid_err(wiimote, "Mutex destroy error (rw mutex)"); 
     270                        } 
     271                } 
     272                if (rpt_mutex_init) { 
     273                        if (pthread_mutex_destroy(&wiimote->rpt_mutex)) { 
     274                                cwiid_err(wiimote, "Mutex destroy error (rpt mutex)"); 
    189275                        } 
    190276                } 
     
    198284        void *pthread_ret; 
    199285 
    200         /* Cancel and join int_thread */ 
    201         if (pthread_cancel(wiimote->int_listen_thread)) { 
    202                 /* int could exit on it's own, so we don't care */ 
    203                 /* cwiid_err(wiimote, "Error canceling int_listen_thread"); */ 
    204         } 
    205         else { 
    206                 if (pthread_join(wiimote->int_listen_thread, &pthread_ret)) { 
    207                         cwiid_err(wiimote, "Error joining int_listen_thread"); 
    208                 } 
    209                 else if (pthread_ret != PTHREAD_CANCELED) { 
    210   &