summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGentoo <installgentoo@endianness.com>2020-10-18 18:15:21 +1100
committerGentoo <installgentoo@endianness.com>2020-10-18 18:15:21 +1100
commita15647af18372d853cc316d3bc1b97c8293b7897 (patch)
treec7775cc96096586ee416946a7e6921b3cbe39a78
parent093da86246cda0aca6b395c42b5bd20633cc2190 (diff)
downloadwiimote-a15647af18372d853cc316d3bc1b97c8293b7897.tar.gz
wiimote-a15647af18372d853cc316d3bc1b97c8293b7897.tar.bz2
wiimote-a15647af18372d853cc316d3bc1b97c8293b7897.zip
improved connection code
-rw-r--r--Makefile2
-rw-r--r--main.c214
-rw-r--r--main.h42
3 files changed, 229 insertions, 29 deletions
diff --git a/Makefile b/Makefile
index 5b8f2a0..f6457e3 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ CFLAGS=-O3 -march=native -pipe
LIBS=-lbluetooth
OBJ = main.o
-HEADERS = buttons.h
+HEADERS = main.h
%.o: %.c $(DEPS) $(HEADERS)
gcc -c -o $@ $< $(CFLAGS) $(LIBS)
diff --git a/main.c b/main.c
index ee58f17..ccc885e 100644
--- a/main.c
+++ b/main.c
@@ -5,10 +5,15 @@
#include <stdbool.h>
#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
-#include "buttons.h"
+#include "main.h"
int controlSock, dataSock;
@@ -29,13 +34,94 @@ struct state
bool dpadD;
bool rumble;
+ bool continuous;
+ char mode; //data reporting mode
};
struct state newState;
+bdaddr_t findBluetooth()
+ {
+ int device_id = hci_get_route(NULL);
+ int hci_sock = hci_open_dev(device_id);
+ if (device_id < 0 || hci_sock < 0)
+ {
+ perror("opening socket");
+ exit(1);
+ }
+
+ int max_rsp = 255;
+ inquiry_info *scan_info = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
+ if (!scan_info){fprintf(stderr,"Malloc failed!\n"); exit(1);}
+
+ int timeout = 8;
+ int num_rsp = hci_inquiry(device_id, timeout, max_rsp, NULL, &scan_info, IREQ_CACHE_FLUSH);
+ if (num_rsp < 0){perror("hci_inquiry"); exit(1);}
-void connectBluetooth(char server[])
+ int i = 0;
+ for (i = 0; i < num_rsp; ++i)
+ {
+ if ((scan_info[i].dev_class[0] == 0x04) && (scan_info[i].dev_class[1] == 0x01) && (scan_info[i].dev_class[2] == 0x10))//match up with class of server...
+ {
+ printf("Found device\n");
+ //we're done
+ break;
+ }
+ else
+ {
+ printf("Non matching class: %d, %d, %d\n",scan_info[i].dev_class[0],scan_info[i].dev_class[1],scan_info[i].dev_class[2]);
+ }
+ }
+ if (i == num_rsp)
+ {
+ fprintf(stderr,"Device not found in hci search!\n");
+ exit(1);
+ }
+
+ char addr[19];
+ ba2str(&(scan_info+i)->bdaddr, addr);
+ addr[18] = '\0';
+ printf("%s\n",addr);
+
+ hci_close_dev(device_id);
+
+ return (scan_info+i)->bdaddr;
+ }
+
+
+
+
+int connectBluetooth(bdaddr_t address)
{
+ int hci_sock = hci_open_dev(hci_get_route(NULL));
+ if (hci_sock < 0){fprintf(stderr,"Could not open device!\n");}
+
+ unsigned int ptype = HCI_DM1 | HCI_DM3 | HCI_DM5 | HCI_DH1 | HCI_DH3 | HCI_DH5;
+
+ uint16_t handle;
+
+ bdaddr_t bdaddr;
+
+ if (hci_create_connection(hci_sock, &address, htobs(ptype), 0, 0, &handle, 0) < 0)
+ {
+ perror("HCI create connection failed");
+ close(hci_sock);
+ return 0;
+// exit(1);
+ }
+
+ printf("Connected!\n");
+
+ // Authenticate HCI link (without pin)
+ if (hci_authenticate_link(hci_sock, handle, 0) < 0)
+ {
+ perror("HCI authentication failed");
+// exit(1);
+ close(hci_sock);
+ return 0;
+ }
+
+
int status;
//Establishing a HID connection with the Wii Remote can be done on PSM 0x11 for the control pipe using the Bluetooth L2CAP protocol.
@@ -45,10 +131,14 @@ void connectBluetooth(char server[])
// set the connection parameters (who to connect to)
control.l2_family = AF_BLUETOOTH;
control.l2_psm = htobs(0x11);
- str2ba(server,&control.l2_bdaddr);
+ control.l2_bdaddr = address;
+ printf("First\n");
+ fflush(stdout);
status = connect(controlSock, (struct sockaddr *)&control, sizeof(control));//while the control pipe isn't used, we still gotta open it
- if(status < 0){fprintf(stderr,"Failed to connect to control pipe!: "); perror(""); exit(1);}
+ if(status < 0){fprintf(stderr,"Failed to connect to control pipe!: "); perror(""); close(hci_sock); return 0;}
+ printf("Second\n");
+ fflush(stdout);
//Establishing a HID connection with the Wii Remote can be done on PSM 0x13 for the data pipe using the Bluetooth L2CAP protocol.
struct sockaddr_l2 data = {0};
@@ -57,10 +147,20 @@ void connectBluetooth(char server[])
// set the connection parameters (who to connect to)
data.l2_family = AF_BLUETOOTH;
data.l2_psm = htobs(0x13);
- str2ba(server,&data.l2_bdaddr);
+ data.l2_bdaddr = address;
+
+ printf("Third\n");
+ fflush(stdout);
status = connect(dataSock, (struct sockaddr *)&data, sizeof(data));
- if(status < 0){fprintf(stderr,"Failed to connect to data pipe!: "); perror(""); exit(1);}
+ if(status < 0){fprintf(stderr,"Failed to connect to data pipe!: "); perror(""); close(hci_sock); return 0;}
+
+ printf("Fourth\n");
+ fflush(stdout);
+
+
+ printf("You win *claps*\n");
+ return 1;
}
void sdp()
@@ -68,42 +168,100 @@ void sdp()
//todo
}
-void initButtons(struct state *buttons)
+void initState(struct state *remoteState)
{
- buttons->a = false;
- buttons->b = false;
- buttons->plus = false;
- buttons->minus = false;
- buttons->one = false;
- buttons->two = false;
- buttons->dpadL = false;
- buttons->dpadR = false;
- buttons->dpadU = false;
- buttons->dpadD = false;
-
- buttons->rumble = false;//not a button but...
+ remoteState->a = false;
+ remoteState->b = false;
+ remoteState->plus = false;
+ remoteState->minus = false;
+ remoteState->one = false;
+ remoteState->two = false;
+ remoteState->dpadL = false;
+ remoteState->dpadR = false;
+ remoteState->dpadU = false;
+ remoteState->dpadD = false;
+
+ remoteState->rumble = false;
+ remoteState->continuous = false;
+ remoteState->mode = 0x30;//data reporting mode is 0x30 by default
}
int main(int argc, char **argv)
{
- connectBluetooth("44:23:24:65:23:52");//todo: working function, syncing and SDP
+// bdaddr_t address = findBluetooth();
+ bdaddr_t address;
+ str2ba("no",&address);
+
+ int result = 0;
+ do
+ {
+ result = connectBluetooth(address);
+ sleep(3);
+ }
+ while (!result);
+
+
+ exit(1);
//When using a Wii Remote, all input reports are prepended with 0xa1 and all output reports are prepended with 0xa2
//Output reports are sent over the data pipe, which is also used to read input reports
- //input reports are reports from the Wii remote and output reports are reports to the Wii remote
+ //input reports are reports from the Wii remote to the Wii and output reports are reports from the Wii to the Wii remote
+
+
+ struct state *remoteState;
+ remoteState = &newState;
+ initState(remoteState);
+ remoteState->a = true;//lets assume that the A button is held down
+
+
+ int size;
+ //the wiimote appears to spam a massive amount of random garbage with 0x3X reports pre "sync".
+ //I don't implement this "feature" hoping that isn't required.
- struct state *buttons;
- buttons = &newState;
- initButtons(buttons);
+ //The Wiimote conforms sync by writing: (a1) 20 BB BB LF 00 00 VV to the data pipe.
+ //Our data here is: a1 20 00 00 14 00 00 8d (LF == LED 1 enabled and speaker enabled), (VV, battery level 141)
- buttons->a = true;//lets assume that the A button is held down
+ //send the sync conformation report and repeat if al the bytes have not been written.
+ sync: size = write(dataSock,"\xa1\x20\x00\x00\x14\x00\x00\x8d",8);
+ if (size < 8){fprintf(stderr,"Writing connection confirmation failed!\n"); goto sync;}
- //first up is the assumption that the Wii sends the status reporting mode
+ //the Wii must then send output report 0x12 to change the data reporting mode, as above was sent without request
char buff[MAX+1];
- int size = read(dataSock, buff, MAX);
+ changemode: size = read(dataSock, buff, MAX);
+ if (size < 4){fprintf(stderr,"Reading data report mode failed!\n"); goto changemode;}
+/*
+The Wii Remote has a number of different data reporting modes. Each of these modes combines certain Core data features with data from external peripherals, and sends it to the host through one of the report IDs, determined by the mode. The data format from the peripherals is determined by the peripherals themselves, all the Wii Remote controller does is pull bytes from them and send them out to the host. Due to this, certain feature combinations are not available, as there are not enough bytes for them in any of the output modes.
+
+The Data Reporting Mode is set by sending a two-byte command to Report 0x12:
+
+(a2) 12 TT MM
+
+Bit 2 of TT specifies whether continuous reporting is desired. If bit 2 (0x04) is set, the Wii Remote will send reports whether there has been any change to the data or not. Otherwise, the Wii Remote will only send an output report when the data has changed.
+
+MM specifies the Reporting Mode. Each Mode is specified by the Output Report ID that the data will be sent to.
+
+Upon powerup, the Data Reporting Mode defaults to 0x30. Following a connection or disconnection event on the Extension Port, data reporting is disabled and the Data Reporting Mode must be reset before new data can arrive.
+*/
+ if (buff[0] == 0xa2 && buff[1] == 0x12)//a2 12 06 31
+ {
+ remoteState->continuous = buff[2] & 0x04;
+ remoteState->mode = buff[3];
+ }
+ else
+ {
+ fprintf(stderr,"Wii did not sent status report 0x12. %hi%hi%hi%hi was sent instead!\n",buff[0],buff[1],buff[2],buff[3]);
+ exit(1);
+ }
+
+ printf("That's about it for now\n");
+
+
+/*
+ char buff[MAX+1];
+ size = read(dataSock, buff, MAX);
switch (size)
{
@@ -139,7 +297,7 @@ int main(int argc, char **argv)
fprintf(stderr,"Unimplemented report\n");
break;
}
-
+*/
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..f597426
--- /dev/null
+++ b/main.h
@@ -0,0 +1,42 @@
+#ifndef MAIN_H
+#define MAIN_H
+
+/*
+The Wii Remote has 11 buttons that are used as regular input devices: A, B (trigger), a 4-directional D-Pad, +, -, Home, 1, and 2.
+These are reported as bits in a two-byte bitmask. These are the assignments, in big-endian order:
+
+Bit Mask First Byte Second Byte
+0 0x01 D-Pad Left Two
+1 0x02 D-Pad Right One
+2 0x04 D-Pad Down B
+3 0x08 D-Pad Up A
+4 0x10 Plus Minus
+5 0x20 Other uses Other uses
+6 0x40 Other uses Other uses
+7 0x80 Unknown Home
+*/
+
+//first byte
+#define DPAD_LEFT 0x01
+#define DPAD_RIGHT 0x02
+#define DPAD_DOWN 0x04
+#define DPAD_UP 0x08
+#define PLUS 0x10
+#define OTHER0 0x20
+#define OTHER1 0x40
+#define UNKNOWN 0x80
+
+//second byte
+#define TWO 0x01
+#define ONE 0x02
+#define B 0x04
+#define A 0x08
+#define MINUS 0x10
+#define OTHER2 0x20
+#define OTHER3 0x40
+#define HOME 0x80
+
+
+
+
+#endif