Skip to content

Add wireless controller syncing functionality to WPAD/LWBT #197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions gc/bte/bd_addr.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@
extern "C" {
#endif /* __cplusplus */

#define BD_ADDR_LEN 6

struct bd_addr {
u8 addr[6];
u8 addr[BD_ADDR_LEN];
};

#define BD_ADDR_LEN 6

#define BD_ADDR_ANY (&(struct bd_addr){{0,0,0,0,0,0}})
#define BD_ADDR_LOCAL (&(struct bd_addr){{0,0,0,0xff,0xff,0xff}})

Expand All @@ -55,6 +55,23 @@ struct bd_addr {
(bdaddr)->addr[3] = d; \
(bdaddr)->addr[4] = e; \
(bdaddr)->addr[5] = f; }while(0)

#define BD_ADDR_FROM_BYTES(bdaddr, bytes) do{ \
(bdaddr)->addr[0] = bytes[5]; \
(bdaddr)->addr[1] = bytes[4]; \
(bdaddr)->addr[2] = bytes[3]; \
(bdaddr)->addr[3] = bytes[2]; \
(bdaddr)->addr[4] = bytes[1]; \
(bdaddr)->addr[5] = bytes[0]; }while(0)

#define BYTES_FROM_BD_ADDR(bytes, bdaddr) do{ \
bytes[0] = (bdaddr)->addr[5]; \
bytes[1] = (bdaddr)->addr[4]; \
bytes[2] = (bdaddr)->addr[3]; \
bytes[3] = (bdaddr)->addr[2]; \
bytes[4] = (bdaddr)->addr[1]; \
bytes[5] = (bdaddr)->addr[0]; }while(0)

//TODO: USE memcmp????
#define bd_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
((addr1)->addr[1] == (addr2)->addr[1]) && \
Expand Down
69 changes: 52 additions & 17 deletions gc/bte/bte.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,27 @@
#define HIDP_CTRL_VC_UNPLUG 0x05

/* HIDP data transaction headers */
#define HIDP_DATA_RTYPE_MASK 0x03
#define HIDP_DATA_RSRVD_MASK 0x0c
#define HIDP_DATA_RTYPE_OTHER 0x00
#define HIDP_DATA_RTYPE_INPUT 0x01
#define HIDP_DATA_RTYPE_OUPUT 0x02
#define HIDP_DATA_RTYPE_FEATURE 0x03
#define HIDP_DATA_RTYPE_MASK 0x03
#define HIDP_DATA_RSRVD_MASK 0x0c
#define HIDP_DATA_RTYPE_OTHER 0x00
#define HIDP_DATA_RTYPE_INPUT 0x01
#define HIDP_DATA_RTYPE_OUPUT 0x02
#define HIDP_DATA_RTYPE_FEATURE 0x03

#define HIDP_PROTO_BOOT 0x00
#define HIDP_PROTO_REPORT 0x01

#define BD_LINK_KEY_LEN 16
#define BD_NAME_LEN 248
#define BD_MAX_INQUIRY_DEVS 255

enum pair_mode {
PAIR_MODE_NORMAL,
PAIR_MODE_TEMPORARY
};

#ifdef __cplusplus
extern "C" {
extern "C" {
#endif /* __cplusplus */

struct l2cap_pcb;
Expand All @@ -88,10 +97,22 @@ struct inquiry_info_ex
u16 co;
};

struct inquiry_res
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest prefixing structures with bte_, in order to avoid potential conflicts with the application's code (I see that the existing code is not that careful, but I suggest trying to follow this pattern from now on).

Copy link

@Aeplet Aeplet Jun 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest prefixing structures with bte_, in order to avoid potential conflicts with the application's code (I see that the existing code is not that careful, but I suggest trying to follow this pattern from now on).

I assume like bte_inquiry_res?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep.

{
u8 count;
struct inquiry_info_ex *info;
};

struct linkkey_info
{
struct bd_addr bdaddr;
u8 key[16];
u8 key[BD_LINK_KEY_LEN];
};

struct pad_name_info
{
struct bd_addr bdaddr;
u8 name[BD_NAME_LEN];
};

struct bte_pcb
Expand All @@ -112,6 +133,7 @@ struct bte_pcb


s32 (*recv)(void *arg,void *buffer,u16 len);
s32 (*conn_req)(void *arg,struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 *cod,u8 link_type,u8 err);
s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err);
s32 (*disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err);
};
Expand All @@ -120,34 +142,47 @@ typedef s32 (*btecallback)(s32 result,void *userdata);

void BTE_Init(void);
void BTE_Shutdown(void);
void BTE_Close(void);
s32 BTE_InitCore(btecallback cb);
s32 BTE_ApplyPatch(btecallback cb);
s32 BTE_InitSub(btecallback cb);
s32 BTE_ReadStoredLinkKey(struct linkkey_info *keys,u8 max_cnt,btecallback cb);
s32 BTE_ReadBdAddr(struct bd_addr *bdaddr, btecallback cb);
s32 BTE_SetEvtFilter(u8 filter_type,u8 filter_cond_type,u8 *cond, btecallback cb);
s32 BTE_ReadRemoteName(struct pad_name_info *padinfo, btecallback cb);
s32 BTE_Inquiry(u8 max_cnt,u8 flush, btecallback cb);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not use the existing btecallback, because that forces us to pass the result in the userdata parameter, therefore making it impossible for the client to receive its own "userdata" pointer. I suggest using this callback type:

typedef s32 (*bte_inquiry_callback)(s32 result, bte_inquiry_res *res, void *userdata);

or, actually better, move the s32 result inside bte_inquiry_res (or we can change count to be s32, and a negative value means error) and have

typedef s32 (*bte_inquiry_callback)(bte_inquiry_res *res, void *userdata);

I haven't check the rest of the new functions, but please consider allowing the client to receive its own userdata.

s32 BTE_PeriodicInquiry(u8 max_cnt,u8 flush,btecallback cb);
s32 BTE_ExitPeriodicInquiry(void);
s32 BTE_LinkKeyRequestReply(struct bd_addr *bdaddr,u8 *key);
s32 BTE_LinkKeyRequestNegativeReply(struct bd_addr *bdaddr);
void (*BTE_SetDisconnectCallback(void (*callback)(struct bd_addr *bdaddr,u8 reason)))(struct bd_addr *bdaddr,u8 reason);
void BTE_SetHostSyncButtonCallback(void (*callback)(u32 held));
void BTE_SetConnectionRequestCallback(s8 (*callback)(void *arg,struct bd_addr *bdaddr,u8 *cod,u8 link_type));
void BTE_SetLinkKeyRequestCallback(s8 (*callback)(void *arg,struct bd_addr *bdaddr));
void BTE_SetLinkKeyNotificationCallback(s8 (*callback)(void *arg,struct bd_addr *bdaddr,u8 *key));
u8 BTE_GetPairMode(void);
s32 BTE_WriteStoredLinkKey(struct bd_addr *bdaddr,u8 *key);
s32 BTE_ClearStoredLinkKeys(void);
s32 BTE_DeleteStoredLinkKey(struct bd_addr *bdaddr);

struct bte_pcb* bte_new(void);
void bte_free(struct bte_pcb *pcb);
void bte_arg(struct bte_pcb *pcb,void *arg);
void bte_received(struct bte_pcb *pcb, s32 (*recv)(void *arg,void *buffer,u16 len));
void bte_disconnected(struct bte_pcb *pcb,s32 (disconn_cfm)(void *arg,struct bte_pcb *pcb,u8 err));

s32 bte_registerdeviceasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err));

s32 bte_disconnect(struct bte_pcb *pcb);

//s32 bte_listen(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm);
//s32 bte_accept(struct bte_pcb *pcb,s32 (*recv)(void *arg,void *buffer,u16 len));
s32 bte_inquiry(struct inquiry_info *info,u8 max_cnt,u8 flush);
s32 bte_inquiry_ex(struct inquiry_info_ex *info,u8 max_cnt,u8 flush);
//s32 bte_connect(struct bte_pcb *pcb,struct bd_addr *bdaddr,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len));
//s32 bte_connect_ex(struct bte_pcb *pcb,struct inquiry_info_ex *info,u8 psm,s32 (*recv)(void *arg,void *buffer,u16 len));
s32 bte_listenasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err));
s32 bte_listenasync_step2(struct bte_pcb *pcb,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err));
s32 bte_connectasync(struct bte_pcb *pcb,struct bd_addr *bdaddr,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err));
s32 bte_connectasync_step2(struct bte_pcb *pcb,s32 (*conn_cfm)(void *arg,struct bte_pcb *pcb,u8 err));
s32 bte_senddata(struct bte_pcb *pcb,void *message,u16 len);
s32 bte_sendmessage(struct bte_pcb *pcb,void *message,u16 len);
s32 bte_sendmessageasync(struct bte_pcb *pcb,void *message,u16 len,s32 (*sent)(void *arg,struct bte_pcb *pcb,u8 err));

#ifdef __cplusplus
}
}
#endif /* __cplusplus */

#endif
Expand Down
22 changes: 22 additions & 0 deletions gc/ogc/conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ enum {

#define CONF_PAD_MAX_REGISTERED 10
#define CONF_PAD_MAX_ACTIVE 4
#define CONF_PAD_ACTIVE_AND_OTHER (CONF_PAD_MAX_ACTIVE + 2)
#define CONF_PAD_TOTAL (CONF_PAD_MAX_REGISTERED + CONF_PAD_ACTIVE_AND_OTHER)

typedef struct _conf_pad_device conf_pad_device;

Expand All @@ -146,7 +148,24 @@ struct _conf_pads {
conf_pad_device unknown;
} ATTRIBUTE_PACKED;

typedef struct _conf_pad_guest_device conf_pad_guest_device;

struct _conf_pad_guest_device {
u8 bdaddr[6];
char name[0x40];
u8 link_key[16];
} ATTRIBUTE_PACKED;

typedef struct _conf_pad_guests conf_pad_guests;

struct _conf_pad_guests {
u8 num_guests;
conf_pad_guest_device guests[CONF_PAD_MAX_ACTIVE];
conf_pad_guest_device unknown[2]; // Balance Board can't be set as guest...
} ATTRIBUTE_PACKED;

s32 CONF_Init(void);
s32 CONF_SaveChanges(void);
s32 CONF_GetLength(const char *name);
s32 CONF_GetType(const char *name);
s32 CONF_Get(const char *name, void *buffer, u32 length);
Expand All @@ -164,6 +183,9 @@ s32 CONF_GetCounterBias(u32 *bias);
s32 CONF_GetScreenSaverMode(void);
s32 CONF_GetDisplayOffsetH(s8 *offset);
s32 CONF_GetPadDevices(conf_pads *pads);
s32 CONF_SetPadDevices(const conf_pads *pads);
s32 CONF_GetPadGuestDevices(conf_pad_guests *pads);
s32 CONF_SetPadGuestDevices(const conf_pad_guests *pads);
s32 CONF_GetNickName(u8 *nickname);
s32 CONF_GetAspectRatio(void);
s32 CONF_GetEULA(void);
Expand Down
10 changes: 6 additions & 4 deletions gc/wiiuse/wiiuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ typedef enum cmd_blk_s
{
CMD_READY = 0,
CMD_SENT,
CMD_DONE
CMD_DONE,
CMD_FAILED
} cmd_blk_s;

struct cmd_blk_t
Expand Down Expand Up @@ -660,9 +661,10 @@ typedef struct wiimote_t {
* @brief Wiimote listen structure.
*/
typedef struct wiimote_listen_t {
WCONST u8 name[0x40];
WCONST struct bd_addr bdaddr;
WCONST struct bte_pcb *sock;
WCONST struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr);
WCONST struct wiimote_t *(*assign_cb)(struct wiimote_listen_t *wml, u8 err);
WCONST struct wiimote_t *wm;
} wiimote_listen;
#endif
Expand Down Expand Up @@ -697,7 +699,8 @@ WIIUSE_EXPORT extern const char* wiiuse_version();
#ifndef GEKKO
WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes);
#else
WIIUSE_EXPORT extern int wiiuse_register(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, struct wiimote_t *(*assign_cb)(struct bd_addr *bdaddr));
WIIUSE_EXPORT extern int wiiuse_accept(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, u8 *name, struct wiimote_t *(*assign_cb)(wiimote_listen *wml, u8 err));
WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_listen_t *wml, struct bd_addr *bdaddr, u8 *name, struct wiimote_t *(*assign_cb)(wiimote_listen *wml, u8 err));
WIIUSE_EXPORT extern struct wiimote_t** wiiuse_init(int wiimotes, wii_event_cb event_cb);
WIIUSE_EXPORT extern void wiiuse_sensorbar_enable(int enable);
#endif
Expand All @@ -721,7 +724,6 @@ WIIUSE_EXPORT extern int wiiuse_write_streamdata(struct wiimote_t *wm,ubyte *dat

/* connect.c */
WIIUSE_EXPORT extern int wiiuse_find(struct wiimote_t** wm, int max_wiimotes, int timeout);
WIIUSE_EXPORT extern int wiiuse_connect(struct wiimote_t** wm, int wiimotes);
WIIUSE_EXPORT extern void wiiuse_disconnect(struct wiimote_t* wm);

/* events.c */
Expand Down
28 changes: 26 additions & 2 deletions gc/wiiuse/wpad.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ enum {
WPAD_CHAN_2,
WPAD_CHAN_3,
WPAD_BALANCE_BOARD,
WPAD_MAX_WIIMOTES,
WPAD_CHAN_UNKNOWN,
WPAD_MAX_DEVICES,
};

// Compatibility with old apps
#define WPAD_MAX_WIIMOTES WPAD_MAX_DEVICES

#define WPAD_BUTTON_2 0x0001
#define WPAD_BUTTON_1 0x0002
Expand Down Expand Up @@ -136,6 +140,14 @@ enum {
#define WPAD_THRESH_DEFAULT_BALANCEBOARD 60
#define WPAD_THRESH_DEFAULT_MOTION_PLUS 100

#define WPAD_DISCON_AUTH_FAILURE 0x05 /* HCI_AUTHENTICATION_FAILURE */
#define WPAD_DISCON_TIMEOUT 0x08 /* HCI_CONN_TIMEOUT */
#define WPAD_DISCON_SYNC_PRESSED 0x13 /* HCI_OTHER_END_TERMINATED_CONN_USER_ENDED */
#define WPAD_DISCON_BATTERY_DIED 0x14 /* HCI_OTHER_END_TERMINATED_CONN_LOW_RESOURCES */
#define WPAD_DISCON_POWER_OFF 0x15 /* HCI_OTHER_END_TERMINATED_CONN_ABOUT_TO_POWER_OFF */
#define WPAD_DISCON_IDLE_TIMEOUT 0x16 /* HCI_CONN_TERMINATED_BY_LOCAL_HOST */
#define WPAD_DISCON_REPEATED_ATTEMPTS 0x17 /* HCI_REPEATED_ATTEMPTS */

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
Expand Down Expand Up @@ -166,6 +178,9 @@ typedef struct _wpad_encstatus

typedef void (*WPADDataCallback)(s32 chan, const WPADData *data);
typedef void (*WPADShutdownCallback)(s32 chan);
typedef void (*WPADDisconnectCallback)(s32 chan, u8 reason);
typedef void (*WPADStatusCallback)(s32 chan);
typedef void (*WPADHostSyncBtnCallback)(u32 held);

s32 WPAD_Init(void);
s32 WPAD_ControlSpeaker(s32 chan,s32 enable);
Expand All @@ -182,10 +197,17 @@ s32 WPAD_SetEventBufs(s32 chan, WPADData *bufs, u32 cnt);
s32 WPAD_Disconnect(s32 chan);
s32 WPAD_IsSpeakerEnabled(s32 chan);
s32 WPAD_SendStreamData(s32 chan,void *buf,u32 len);
void WPAD_Shutdown(void);
s32 WPAD_Search(void);
s32 WPAD_StopSearch(void);
s32 WPAD_StartPairing(void);
s32 WPAD_WipeSavedControllers(void);
s32 WPAD_Shutdown(void);
void WPAD_SetIdleTimeout(u32 seconds);
void WPAD_SetPowerButtonCallback(WPADShutdownCallback cb);
void WPAD_SetBatteryDeadCallback(WPADShutdownCallback cb);
void WPAD_SetDisconnectCallback(WPADDisconnectCallback cb);
void WPAD_SetHostSyncButtonCallback(WPADHostSyncBtnCallback cb);
void WPAD_SetStatusCallback(WPADStatusCallback cb);
s32 WPAD_ScanPads(void);
s32 WPAD_Rumble(s32 chan, int status);
s32 WPAD_SetIdleThresholds(s32 chan, s32 btns, s32 ir, s32 accel, s32 js, s32 wb, s32 mp);
Expand All @@ -200,6 +222,8 @@ void WPAD_Orientation(int chan, struct orient_t *orient);
void WPAD_GForce(int chan, struct gforce_t *gforce);
void WPAD_Accel(int chan, struct vec3w_t *accel);
void WPAD_Expansion(int chan, struct expansion_t *exp);
void WPAD_PadStatus(int chan);
bool WPAD_IsBatteryCritical(int chan);

#ifdef __cplusplus
}
Expand Down
Loading