├── lib └── libwupc.a ├── source ├── wupc_structs.h └── wupc.c ├── README ├── include └── wupc │ └── wupc.h └── Makefile /lib/libwupc.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FIX94/libwupc/HEAD/lib/libwupc.a -------------------------------------------------------------------------------- /source/wupc_structs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _WUPC_STRUCTS_H_ 3 | #define _WUPC_STRUCTS_H_ 4 | 5 | struct WUPCStat { 6 | u32 connected; 7 | u32 transferstate; 8 | u32 channel; 9 | u32 rumble; 10 | s16 xAxisLmid; 11 | s16 xAxisRmid; 12 | s16 yAxisLmid; 13 | s16 yAxisRmid; 14 | struct bte_pcb *sock; 15 | struct bd_addr bdaddr; 16 | }; 17 | 18 | struct WUPCButtons { 19 | u32 up; 20 | u32 down; 21 | u32 state; 22 | }; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | libwupc - A WiiU Pro Controller Library for Wii Homebrew Applications by FIX94 2 | WiiU Pro Controller Documentation from TeHaxor69 3 | 4 | 1. Copy the "lib" and "include" folder into your "portlibs" folder 5 | 6 | 2. Make these modifications to your Makefile: 7 | -add "-lwupc" right behind "-lwiiuse" to your LIBS 8 | -add ",-wrap,wiiuse_register" to your LDFLAGS 9 | 10 | 3. Modify your code like this: 11 | -make sure to include in all files you use WUPC calls 12 | -call "WUPC_Init" before "WPAD_Init" 13 | -call "WUPC_Shutdown" before "WPAD_Shutdown" 14 | -either use the separate calls or use WUPC_Data at the same place you would normally use the WPAD calls for your data handling 15 | -if you use ButtonsUp, ButtonsUp and/or ButtonsHeld, make sure to call "WUPC_UpdateButtonStats" before "WPAD_ScanPads", 16 | if you dont use any of these you can ignore "WUPC_UpdateButtonStats" 17 | 18 | Notes: 19 | -The X and Y-Axis are going from about -1024 to +1024, make sure you adjust your calculations to that 20 | -The Buttons are using the same layout as the classic controller buttons, use the "WPAD_CLASSIC_BUTTON_" definitions in 21 | -The Battery Status goes from 0 (critical) to 4 (full) 22 | 23 | Have Fun! -------------------------------------------------------------------------------- /include/wupc/wupc.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2014 FIX94 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | ****************************************************************************/ 17 | #ifndef _WUPC_H_ 18 | #define _WUPC_H_ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | struct WUPCData { 25 | s16 xAxisL; 26 | s16 xAxisR; 27 | s16 yAxisL; 28 | s16 yAxisR; 29 | u32 button; 30 | u8 battery; 31 | u8 extra; 32 | }; 33 | 34 | #define WUPC_EXTRA_BUTTON_RSTICK 0x01 35 | #define WUPC_EXTRA_BUTTON_LSTICK 0x02 36 | 37 | #define WUPC_EXTRA_CHARGING 0x04 38 | #define WUPC_EXTRA_USBCONNECTED 0x08 39 | 40 | void WUPC_Init(); 41 | void WUPC_Disconnect(u8 chan); 42 | void WUPC_Shutdown(); 43 | struct WUPCData *WUPC_Data(u8 chan); 44 | void WUPC_Rumble(u8 chan, bool rumble); 45 | u32 WUPC_UpdateButtonStats(); 46 | u32 WUPC_ButtonsUp(u8 chan); 47 | u32 WUPC_ButtonsDown(u8 chan); 48 | u32 WUPC_ButtonsHeld(u8 chan); 49 | s16 WUPC_lStickX(u8 chan); 50 | s16 WUPC_lStickY(u8 chan); 51 | s16 WUPC_rStickX(u8 chan); 52 | s16 WUPC_rStickY(u8 chan); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | # Clear the implicit built in rules 3 | #--------------------------------------------------------------------------------- 4 | .SUFFIXES: 5 | #--------------------------------------------------------------------------------- 6 | ifeq ($(strip $(DEVKITPPC)),) 7 | $(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") 8 | endif 9 | 10 | include $(DEVKITPPC)/wii_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # INCLUDES is a list of directories containing extra header files 17 | #--------------------------------------------------------------------------------- 18 | TARGET := libwupc 19 | BUILD := build 20 | SOURCES := source 21 | DATA := data 22 | INCLUDES := include 23 | 24 | #--------------------------------------------------------------------------------- 25 | # options for code generation 26 | #--------------------------------------------------------------------------------- 27 | CFLAGS = -g -O2 -Wall -Wextra $(MACHDEP) $(INCLUDE) 28 | 29 | #--------------------------------------------------------------------------------- 30 | # no real need to edit anything past this point unless you need to add additional 31 | # rules for different file extensions 32 | #--------------------------------------------------------------------------------- 33 | ifneq ($(BUILD),$(notdir $(CURDIR))) 34 | #--------------------------------------------------------------------------------- 35 | export OUTPUT := $(CURDIR)/lib/$(TARGET) 36 | 37 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 38 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 39 | 40 | export DEPSDIR := $(CURDIR)/$(BUILD) 41 | 42 | #--------------------------------------------------------------------------------- 43 | # automatically build a list of object files for our project 44 | #--------------------------------------------------------------------------------- 45 | export CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 46 | #--------------------------------------------------------------------------------- 47 | export OFILES := $(CFILES:.c=.o) 48 | export LD := $(CC) 49 | 50 | #--------------------------------------------------------------------------------- 51 | # build a list of include paths 52 | #--------------------------------------------------------------------------------- 53 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 54 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 55 | -I$(LIBOGC_INC) 56 | 57 | #--------------------------------------------------------------------------------- 58 | # build a list of library paths 59 | #--------------------------------------------------------------------------------- 60 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ 61 | -L$(LIBOGC_LIB) 62 | 63 | .PHONY: $(BUILD) clean 64 | 65 | #--------------------------------------------------------------------------------- 66 | $(BUILD): 67 | @[ -d $@ ] || mkdir -p $@ 68 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 69 | 70 | #--------------------------------------------------------------------------------- 71 | clean: 72 | @echo clean ... 73 | @rm -fr $(BUILD) $(OUTPUT).a 74 | 75 | 76 | #--------------------------------------------------------------------------------- 77 | else 78 | 79 | DEPENDS := $(OFILES:.o=.d) 80 | 81 | #--------------------------------------------------------------------------------- 82 | # main targets 83 | #--------------------------------------------------------------------------------- 84 | $(OUTPUT).a: $(OFILES) 85 | 86 | -include $(DEPENDS) 87 | 88 | #--------------------------------------------------------------------------------- 89 | endif 90 | #--------------------------------------------------------------------------------- 91 | -------------------------------------------------------------------------------- /source/wupc.c: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | * Copyright (C) 2014 FIX94 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | ****************************************************************************/ 17 | 18 | /* WiiU Pro Controller Documentation from TeHaxor69 */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "wupc_structs.h" 26 | #include "wupc/wupc.h" 27 | 28 | extern __typeof(wiiuse_register) __real_wiiuse_register; 29 | 30 | static vu32 __WUPC_ChannelsUsed = 0; 31 | 32 | static conf_pads __WUPC_Devices; 33 | static struct WUPCStat *__WUPC_Connected[4]; 34 | static struct WUPCStat __WUPC_Status[CONF_PAD_MAX_REGISTERED]; 35 | static struct WUPCData __WUPC_PadData[4]; 36 | static struct WUPCButtons __WUPC_PadButtons[4]; 37 | 38 | static u32 __WUPC_Inited = 0; 39 | 40 | static const u8 __WUPC_LEDState[] = { 0x10, 0x20, 0x40, 0x80 }; 41 | 42 | #define CHAN_MAX 4 43 | 44 | #define TRANSFER_CALIBRATE 0 45 | #define TRANSFER_DONE 1 46 | 47 | static void __WUPC_SetLED(struct bte_pcb *sock, u32 state) 48 | { 49 | u8 buf[2]; 50 | buf[0] = 0x11; 51 | buf[1] = __WUPC_LEDState[state]; 52 | bte_senddata(sock,buf,2); 53 | } 54 | static s32 __WUPC_HandleData(void *arg,void *buffer,u16 len) 55 | { 56 | struct WUPCStat *stat = (struct WUPCStat*)arg; 57 | u32 chan = stat->channel; 58 | 59 | if(*(u8*)buffer == 0x3D && len == 22) 60 | { 61 | if(stat->transferstate == TRANSFER_CALIBRATE) 62 | { 63 | stat->xAxisLmid = bswap16(*(u16*)(((u8*)buffer)+1)); 64 | stat->xAxisRmid = bswap16(*(u16*)(((u8*)buffer)+3)); 65 | stat->yAxisLmid = bswap16(*(u16*)(((u8*)buffer)+5)); 66 | stat->yAxisRmid = bswap16(*(u16*)(((u8*)buffer)+7)); 67 | stat->transferstate = TRANSFER_DONE; 68 | } 69 | __WUPC_PadData[chan].xAxisL = bswap16(*(u16*)(((u8*)buffer)+1)) - stat->xAxisLmid; 70 | __WUPC_PadData[chan].xAxisR = bswap16(*(u16*)(((u8*)buffer)+3)) - stat->xAxisRmid; 71 | __WUPC_PadData[chan].yAxisL = bswap16(*(u16*)(((u8*)buffer)+5)) - stat->yAxisLmid; 72 | __WUPC_PadData[chan].yAxisR = bswap16(*(u16*)(((u8*)buffer)+7)) - stat->yAxisRmid; 73 | __WUPC_PadData[chan].button = ~(*(u16*)(((u8*)buffer)+9)) << 16; 74 | u8 extradata = ~(*(((u8*)buffer)+11)); 75 | __WUPC_PadData[chan].battery = (extradata >> 4) & 0x7; 76 | __WUPC_PadData[chan].extra = extradata & 0xF; 77 | } 78 | return ERR_OK; 79 | } 80 | 81 | static s32 __WUPC_HandleConnect(void *arg,struct bte_pcb *pcb,u8 err) 82 | { 83 | struct WUPCStat *stat = (struct WUPCStat*)arg; 84 | 85 | if(__WUPC_ChannelsUsed >= CHAN_MAX) 86 | { 87 | bte_disconnect(pcb); 88 | return err; 89 | } 90 | 91 | stat->channel = __WUPC_ChannelsUsed; 92 | stat->rumble = 0; 93 | 94 | __WUPC_SetLED(pcb, __WUPC_ChannelsUsed); 95 | 96 | u8 buf[3]; 97 | buf[0] = 0x12; 98 | buf[1] = 0x00; 99 | buf[2] = 0x3D; 100 | bte_senddata(pcb,buf,3); 101 | stat->transferstate = TRANSFER_CALIBRATE; 102 | 103 | __WUPC_Connected[__WUPC_ChannelsUsed] = stat; 104 | __WUPC_ChannelsUsed++; 105 | return err; 106 | } 107 | 108 | static s32 __WUPC_HandleDisconnect(void *arg,struct bte_pcb *pcb __attribute__((unused)),u8 err) 109 | { 110 | struct WUPCStat *stat = (struct WUPCStat*)arg; 111 | if(__WUPC_ChannelsUsed) __WUPC_ChannelsUsed--; 112 | 113 | u32 i; 114 | for(i = stat->channel; i < 3; ++i) 115 | __WUPC_Connected[i] = __WUPC_Connected[i+1]; 116 | __WUPC_Connected[3] = NULL; 117 | 118 | for(i = 0; i < CONF_PAD_MAX_REGISTERED; ++i) 119 | { 120 | if(__WUPC_Status[i].channel > stat->channel && __WUPC_Status[i].channel != CHAN_MAX) 121 | { 122 | __WUPC_Status[i].channel--; 123 | __WUPC_SetLED(__WUPC_Status[i].sock, __WUPC_Status[i].channel); 124 | } 125 | } 126 | stat->channel = CHAN_MAX; 127 | return err; 128 | } 129 | 130 | int __WUPC_RegisterPad(struct WUPCStat *stat, struct bd_addr *_bdaddr) 131 | { 132 | stat->channel = CHAN_MAX; 133 | stat->bdaddr = *_bdaddr; 134 | 135 | if(stat->sock == NULL) 136 | { 137 | stat->sock = bte_new(); 138 | if(stat->sock == NULL) 139 | return ERR_OK; 140 | } 141 | 142 | bte_arg(stat->sock, stat); 143 | bte_received(stat->sock, __WUPC_HandleData); 144 | bte_disconnected(stat->sock, __WUPC_HandleDisconnect); 145 | 146 | bte_registerdeviceasync(stat->sock, _bdaddr, __WUPC_HandleConnect); 147 | 148 | return ERR_OK; 149 | } 150 | 151 | int __wrap_wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr)) 152 | { 153 | if(__WUPC_Inited) 154 | { 155 | u8 got_addr[] = { bdaddr->addr[5], bdaddr->addr[4], bdaddr->addr[3], bdaddr->addr[2], bdaddr->addr[1], bdaddr->addr[0] }; 156 | u32 i; 157 | for(i = 0; i < __WUPC_Devices.num_registered; ++i) 158 | { 159 | if(strstr(__WUPC_Devices.registered[i].name, "-UC") != NULL) 160 | { 161 | u8 *cur_bdaddr = __WUPC_Devices.registered[i].bdaddr; 162 | if(memcmp(cur_bdaddr, got_addr, 6) == 0) 163 | return __WUPC_RegisterPad(&__WUPC_Status[i], bdaddr); 164 | } 165 | } 166 | } 167 | return __real_wiiuse_register(wml,bdaddr,assign_cb); 168 | } 169 | 170 | void WUPC_Init() 171 | { 172 | if(__WUPC_Inited == 1) 173 | return; 174 | if(CONF_GetPadDevices(&__WUPC_Devices) < 0) 175 | return; 176 | 177 | u32 i; 178 | for(i = 0; i < CHAN_MAX; ++i) 179 | __WUPC_Connected[i] = NULL; 180 | 181 | for(i = 0; i < CONF_PAD_MAX_REGISTERED; ++i) 182 | __WUPC_Status[i].channel = CHAN_MAX; 183 | 184 | __WUPC_ChannelsUsed = 0; 185 | __WUPC_Inited = 1; 186 | } 187 | 188 | void WUPC_Disconnect(u8 chan) 189 | { 190 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return; 191 | bte_disconnect(__WUPC_Connected[chan]->sock); 192 | } 193 | 194 | void WUPC_Shutdown() 195 | { 196 | if(__WUPC_Inited == 0) 197 | return; 198 | 199 | __WUPC_Inited = 0; 200 | 201 | u32 i; 202 | for(i = 0; i < CONF_PAD_MAX_REGISTERED; ++i) 203 | { 204 | if(__WUPC_Status[i].channel != CHAN_MAX) 205 | bte_disconnect(__WUPC_Status[i].sock); 206 | } 207 | } 208 | 209 | struct WUPCData *WUPC_Data(u8 chan) 210 | { 211 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return NULL; 212 | return &__WUPC_PadData[chan]; 213 | } 214 | 215 | void WUPC_Rumble(u8 chan, bool rumble) 216 | { 217 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return; 218 | 219 | u8 buf[2]; 220 | buf[0] = 0x11; 221 | buf[1] = __WUPC_LEDState[chan] | rumble; 222 | bte_senddata(__WUPC_Connected[chan]->sock,buf,2); 223 | } 224 | 225 | u32 WUPC_UpdateButtonStats() 226 | { 227 | u32 newstate, oldstate; 228 | u32 i, ret = 0; 229 | for(i = 0; i < CHAN_MAX; ++i) 230 | { 231 | if(__WUPC_Connected[i] == NULL) 232 | return ret; 233 | newstate = __WUPC_PadData[i].button; 234 | oldstate = __WUPC_PadButtons[i].state; 235 | __WUPC_PadButtons[i].state = newstate; 236 | __WUPC_PadButtons[i].up = oldstate & ~newstate; 237 | __WUPC_PadButtons[i].down = newstate & (newstate ^ oldstate); 238 | ret |= (1<= CHAN_MAX || __WUPC_Connected[chan] == NULL) return 0; 246 | return __WUPC_PadButtons[chan].up; 247 | } 248 | u32 WUPC_ButtonsDown(u8 chan) 249 | { 250 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return 0; 251 | return __WUPC_PadButtons[chan].down; 252 | } 253 | u32 WUPC_ButtonsHeld(u8 chan) 254 | { 255 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return 0; 256 | return __WUPC_PadButtons[chan].state; 257 | } 258 | s16 WUPC_lStickX(u8 chan) 259 | { 260 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return 0; 261 | return __WUPC_PadData[chan].xAxisL; 262 | } 263 | s16 WUPC_lStickY(u8 chan) 264 | { 265 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return 0; 266 | return __WUPC_PadData[chan].yAxisL; 267 | } 268 | s16 WUPC_rStickX(u8 chan) 269 | { 270 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return 0; 271 | return __WUPC_PadData[chan].xAxisR; 272 | } 273 | s16 WUPC_rStickY(u8 chan) 274 | { 275 | if(chan >= CHAN_MAX || __WUPC_Connected[chan] == NULL) return 0; 276 | return __WUPC_PadData[chan].yAxisR; 277 | } 278 | --------------------------------------------------------------------------------