diff --git a/xbox/.gitignore b/xbox/.gitignore deleted file mode 100644 index bd6bac6..0000000 --- a/xbox/.gitignore +++ /dev/null @@ -1 +0,0 @@ -xbox diff --git a/xbox/XBOXONE b/xbox/XBOXONE deleted file mode 100644 index 485dbbb..0000000 --- a/xbox/XBOXONE +++ /dev/null @@ -1,155 +0,0 @@ -2013/11/21 - Got my xbox one controller. Woo! Hack hack hack. - -Here's what we have so far: - -When the xbox one controller turns on, it gives you something like: -02 20 11 1c 7e ed 8a 56 0f 45 00 00 5e 04 d1 02 01 00 01 00 17 01 02 00 01 00 01 00 01 00 01 00 - ^ - '-- This byte seems to count upward every time the read returns, roughly twice a second - -Should you try to write -04 20 -The behavior will change (this is what put us onto this line of investigation). - -If you subsequently write any of these: -04 20 ?? 1c 7e ed 8a 56 0f 45 00 00 5e 04 d1 02 01 00 01 00 17 01 02 00 01 00 01 00 01 00 01 00 -04 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -04 20 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF - -The light will turn on (YAY!) and then you can start reading again. - -You will read something like the following a few times: -04 f0 01 3a ba 01 10 00 01 00 00 00 00 00 00 00 00 00 00 00 ba 00 7b 00 16 00 1f 00 20 00 27 00 2d 00 4a 00 00 00 00 00 00 00 00 00 02 01 00 00 00 01 00 01 00 00 06 01 02 03 04 06 07 05 01 05 -04 f0 02 3a ba 01 10 00 01 00 00 00 00 00 00 00 00 00 00 00 ba 00 7b 00 16 00 1f 00 20 00 27 00 2d 00 4a 00 00 00 00 00 00 00 00 00 02 01 00 00 00 01 00 01 00 00 06 01 02 03 04 06 07 05 01 04 - -Whenever you hit the xbox button, you will read these: -07 20 01 02 01 5b -07 20 02 02 00 5b - -(Note that at various points, the counter byte (the third byte) seems to go back to 1) - -1..16 + 0x20 -2013/11/21 23:20:05 read 32 bytes: 02 20 09 1c 7e ed 8a 56 0f 45 00 00 5e 04 d1 02 01 00 01 00 17 01 02 00 01 00 01 00 01 00 01 00 [err: ] -2013/11/21 23:20:05 read 8 bytes: 03 20 01 04 80 00 00 00 [err: ] -2013/11/21 23:20:05 read 18 bytes: 20 00 01 0e 00 00 00 00 00 00 97 0a 6f 01 b6 06 37 f8 [err: ] - -Actually, the magic number appears to be [05 20]. -It seems like [04 20] asks for some calibration data. - -Here is an edited session log of me hitting buttons: - -2013/11/21 23:33:53 Found Microsoft Xbox One controller -2013/11/21 23:33:53 sent 2 bytes: 05 20 [err: ] -2013/11/21 23:33:53 read 8 bytes: 03 20 01 04 80 00 00 00 [err: ] - -a -2013/11/21 23:34:03 read 18 bytes: 20 00 06 0e 10 00 00 00 00 00 73 0b 0f 01 b0 05 7c f8 [err: ] -2013/11/21 23:34:03 read 18 bytes: 20 00 07 0e 00 00 00 00 00 00 73 0b 0f 01 b0 05 7c f8 [err: ] - -b -2013/11/21 23:35:23 read 18 bytes: 20 00 22 0e 40 00 00 00 00 00 73 0b 0f 01 b0 05 02 fc [err: ] -2013/11/21 23:35:24 read 18 bytes: 20 00 23 0e 00 00 00 00 00 00 73 0b 0f 01 b0 05 02 fc [err: ] - -y -2013/11/21 23:35:27 read 18 bytes: 20 00 27 0e 00 00 00 00 00 00 73 0b 0f 01 b0 05 02 fc [err: ] -2013/11/21 23:35:27 read 18 bytes: 20 00 28 0e 80 00 00 00 00 00 73 0b 0f 01 b0 05 02 fc [err: ] - -down -2013/11/21 23:35:35 read 18 bytes: 20 00 44 0e 00 02 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:35:35 read 18 bytes: 20 00 45 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -up -2013/11/21 23:35:40 read 18 bytes: 20 00 46 0e 00 01 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:35:40 read 18 bytes: 20 00 47 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -left -2013/11/21 23:35:45 read 18 bytes: 20 00 48 0e 00 04 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:35:45 read 18 bytes: 20 00 49 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -right -2013/11/21 23:35:50 read 18 bytes: 20 00 4a 0e 00 08 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:35:50 read 18 bytes: 20 00 4b 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -2013/11/21 23:35:53 read 8 bytes: 03 20 07 04 80 01 00 00 [err: ] - -share -2013/11/21 23:36:01 read 18 bytes: 20 00 50 0e 08 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:01 read 18 bytes: 20 00 51 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -menu -2013/11/21 23:36:08 read 18 bytes: 20 00 56 0e 04 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:08 read 18 bytes: 20 00 57 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -sync -2013/11/22 00:02:00 read 18 bytes: 20 00 0a 0e 01 00 00 00 00 00 50 0e cf fc 4e 05 37 f8 [err: ] -2013/11/22 00:02:00 read 18 bytes: 20 00 0b 0e 00 00 00 00 00 00 50 0e cf fc 4e 05 37 f8 [err: ] - -lb -2013/11/21 23:36:14 read 18 bytes: 20 00 5a 0e 00 10 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:14 read 18 bytes: 20 00 5b 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -rb -2013/11/21 23:36:17 read 18 bytes: 20 00 5e 0e 00 20 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:17 read 18 bytes: 20 00 5f 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -lt -2013/11/21 23:36:25 read 18 bytes: 20 00 64 0e 00 00 a4 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 65 0e 00 00 06 02 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 66 0e 00 00 f4 03 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 67 0e 00 00 ff 03 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 68 0e 00 00 1a 02 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 69 0e 00 00 22 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 6a 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 6b 0e 00 00 b7 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 6c 0e 00 00 9a 02 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 6d 0e 00 00 ff 03 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 6e 0e 00 00 59 03 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:25 read 18 bytes: 20 00 6f 0e 00 00 22 01 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -rt -2013/11/21 23:36:28 read 18 bytes: 20 00 72 0e 00 00 00 00 12 01 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 73 0e 00 00 00 00 88 02 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 74 0e 00 00 00 00 ff 03 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 75 0e 00 00 00 00 30 03 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 76 0e 00 00 00 00 90 01 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 77 0e 00 00 00 00 40 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 78 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 79 0e 00 00 00 00 22 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 7a 0e 00 00 00 00 d5 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 7b 0e 00 00 00 00 f6 01 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 7c 0e 00 00 00 00 a5 03 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:28 read 18 bytes: 20 00 7d 0e 00 00 00 00 ff 03 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:29 read 18 bytes: 20 00 7e 0e 00 00 00 00 47 03 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:29 read 18 bytes: 20 00 7f 0e 00 00 00 00 c8 01 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:29 read 18 bytes: 20 00 80 0e 00 00 00 00 94 00 73 0b 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:29 read 18 bytes: 20 00 81 0e 00 00 00 00 00 00 73 0b 0f 01 85 05 41 f7 [err: ] - -2013/11/21 23:36:33 read 8 bytes: 03 20 09 04 80 01 00 00 [err: ] - -left stick -2013/11/21 23:36:34 read 18 bytes: 20 00 83 0e 00 00 00 00 00 00 69 0a 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 84 0e 00 00 00 00 00 00 c9 09 0f 01 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 85 0e 00 00 00 00 00 00 3b 09 0f 01 85 05 41 f7 [err: ] -... -2013/11/21 23:36:34 read 18 bytes: 20 00 9c 0e 00 00 00 00 00 00 ff 7f f1 b1 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 9d 0e 00 00 00 00 00 00 ff 7f b5 d1 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 9e 0e 00 00 00 00 00 00 ff 7f 60 d6 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 9f 0e 00 00 00 00 00 00 ff 7f 6e 07 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 a0 0e 00 00 00 00 00 00 ff 7f 3f 0c 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 a1 0e 00 00 00 00 00 00 ff 7f 88 38 85 05 41 f7 [err: ] -2013/11/21 23:36:34 read 18 bytes: 20 00 a2 0e 00 00 00 00 00 00 ff 7f cd 3b 85 05 41 f7 [err: ] - -right stick -2013/11/21 23:36:38 read 18 bytes: 20 00 e3 0e 00 00 00 00 00 00 69 0a c3 fe 3e 05 46 ef [err: ] -2013/11/21 23:36:38 read 18 bytes: 20 00 e4 0e 00 00 00 00 00 00 69 0a c3 fe 3e 05 24 ec [err: ] -2013/11/21 23:36:38 read 18 bytes: 20 00 e5 0e 00 00 00 00 00 00 69 0a c3 fe 3e 05 f6 e7 [err: ] -2013/11/21 23:36:38 read 18 bytes: 20 00 e6 0e 00 00 00 00 00 00 69 0a c3 fe 21 08 d6 e3 [err: ] -... -2013/11/21 23:36:38 read 18 bytes: 20 00 ee 0e 00 00 00 00 00 00 69 0a c3 fe ff 7f 24 e2 [err: ] -2013/11/21 23:36:38 read 18 bytes: 20 00 ef 0e 00 00 00 00 00 00 69 0a c3 fe ff 7f 3b e6 [err: ] -2013/11/21 23:36:38 read 18 bytes: 20 00 f0 0e 00 00 00 00 00 00 69 0a c3 fe ff 7f 3a 0d [err: ] -2013/11/21 23:36:38 read 18 bytes: 20 00 f1 0e 00 00 00 00 00 00 69 0a c3 fe ff 7f 04 12 [err: ] -2013/11/21 23:36:38 read 18 bytes: 20 00 f2 0e 00 00 00 00 00 00 69 0a c3 fe ff 7f 3e 3b [err: ] - -Open questions: -Are battery levels included in one of the status lines? diff --git a/xbox/xbox.go b/xbox/xbox.go deleted file mode 100644 index 53a6719..0000000 --- a/xbox/xbox.go +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright 2013 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "encoding/binary" - "flag" - "fmt" - "log" - "math" - "time" - - "github.com/kylelemons/gousb/usb" -) - -var ( - readonly = flag.Bool("readonly", false, "Only read from the controller") - debug = flag.Int("debug", 0, "USB debugging control") -) - -type modelInfo struct { - config, iface, setup, endIn, endOut uint8 - kind string -} - -func main() { - flag.Parse() - - ctx := usb.NewContext() - defer ctx.Close() - - if *debug != 0 { - ctx.Debug(*debug) - } - - var model modelInfo - - devs, err := ctx.ListDevices(func(desc *usb.Descriptor) bool { - switch { - case desc.Vendor == 0x045e && desc.Product == 0x028e: - log.Printf("Found standard Microsoft controller") - /* - 250.006 045e:028e Xbox360 Controller (Microsoft Corp.) - Protocol: Vendor Specific Class (Vendor Specific Subclass) Vendor Specific Protocol - Config 01: - -------------- - Interface 00 Setup 00 - Vendor Specific Class - Endpoint 1 IN interrupt - unsynchronized data [32 0] - Endpoint 1 OUT interrupt - unsynchronized data [32 0] - -------------- - Interface 01 Setup 00 - Vendor Specific Class - Endpoint 2 IN interrupt - unsynchronized data [32 0] - Endpoint 2 OUT interrupt - unsynchronized data [32 0] - Endpoint 3 IN interrupt - unsynchronized data [32 0] - Endpoint 3 OUT interrupt - unsynchronized data [32 0] - -------------- - Interface 02 Setup 00 - Vendor Specific Class - Endpoint 0 IN interrupt - unsynchronized data [32 0] - -------------- - Interface 03 Setup 00 - Vendor Specific Class - -------------- - */ - model = modelInfo{1, 0, 0, 1, 1, "360"} - - case desc.Vendor == 0x045e && desc.Product == 0x02d1: - log.Printf("Found Microsoft Xbox One controller") - /* - 250.006 045e:02d1 Unknown (Microsoft Corp.) - Protocol: Vendor Specific Class - Config 01: - -------------- - Interface 00 Setup 00 - Vendor Specific Class - Endpoint 1 OUT interrupt - unsynchronized data [64 0] - Endpoint 1 IN interrupt - unsynchronized data [64 0] - -------------- - Interface 01 Setup 00 - Vendor Specific Class - Interface 01 Setup 01 - Vendor Specific Class - Endpoint 2 OUT isochronous - unsynchronized data [228 0] - Endpoint 2 IN isochronous - unsynchronized data [228 0] - -------------- - Interface 02 Setup 00 - Vendor Specific Class - Interface 02 Setup 01 - Vendor Specific Class - Endpoint 3 OUT bulk - unsynchronized data [64 0] - Endpoint 3 IN bulk - unsynchronized data [64 0] - -------------- - */ - model = modelInfo{1, 0, 0, 1, 1, "one"} - - case desc.Vendor == 0x1689 && desc.Product == 0xfd00: - log.Printf("Found Razer Onza Tournament controller") - /* - 250.006 1689:fd00 Unknown 1689:fd00 - Protocol: Vendor Specific Class (Vendor Specific Subclass) Vendor Specific Protocol - Config 01: - -------------- - Interface 00 Setup 00 - Vendor Specific Class - Endpoint 1 IN interrupt - unsynchronized data [32 0] - Endpoint 2 OUT interrupt - unsynchronized data [32 0] - -------------- - Interface 01 Setup 00 - Vendor Specific Class - Endpoint 3 IN interrupt - unsynchronized data [32 0] - Endpoint 0 OUT interrupt - unsynchronized data [32 0] - Endpoint 1 IN interrupt - unsynchronized data [32 0] - Endpoint 1 OUT interrupt - unsynchronized data [32 0] - -------------- - Interface 02 Setup 00 - Vendor Specific Class - Endpoint 2 IN interrupt - unsynchronized data [32 0] - -------------- - Interface 03 Setup 00 - Vendor Specific Class - -------------- - */ - model = modelInfo{1, 0, 0, 1, 2, "360"} - default: - return false - } - return true - }) - if err != nil { - log.Fatalf("listdevices: %s", err) - } - defer func() { - for _, d := range devs { - d.Close() - } - }() - if len(devs) != 1 { - log.Fatalf("found %d devices, want 1", len(devs)) - } - controller := devs[0] - - if err := controller.Reset(); err != nil { - log.Fatalf("reset: %s", err) - } - - in, err := controller.OpenEndpoint( - model.config, - model.iface, - model.setup, - model.endIn|uint8(usb.ENDPOINT_DIR_IN)) - if err != nil { - log.Fatalf("in: openendpoint: %s", err) - } - - out, err := controller.OpenEndpoint( - model.config, - model.iface, - model.setup, - model.endOut|uint8(usb.ENDPOINT_DIR_OUT)) - if err != nil { - log.Fatalf("out: openendpoint: %s", err) - } - - switch { - case *readonly: - var b [512]byte - for { - n, err := in.Read(b[:]) - log.Printf("read %d bytes: % x [err: %v]", n, b[:n], err) - if err != nil { - break - } - } - case model.kind == "360": - XBox360(controller, in, out) - case model.kind == "one": - XBoxOne(controller, in, out) - } -} - -func XBox360(controller *usb.Device, in, out usb.Endpoint) { - // https://github.com/Grumbel/xboxdrv/blob/master/PROTOCOL - - const ( - Empty byte = iota // 00000000 ( 0) no LEDs - WarnAll // 00000001 ( 1) flash all briefly - NewPlayer1 // 00000010 ( 2) p1 flash then solid - NewPlayer2 // 00000011 - NewPlayer3 // 00000100 - NewPlayer4 // 00000101 - Player1 // 00000110 ( 6) p1 solid - Player2 // 00000111 - Player3 // 00001000 - Player4 // 00001001 - Waiting // 00001010 (10) empty w/ loops - WarnPlayer // 00001011 (11) flash active - _ // 00001100 (12) empty - Battery // 00001101 (13) squiggle - Searching // 00001110 (14) slow flash - Booting // 00001111 (15) solid then flash - ) - - led := func(b byte) { - out.Write([]byte{0x01, 0x03, b}) - } - - setPlayer := func(player byte) { - spin := []byte{ - Player1, Player2, Player4, Player3, - } - spinIdx := 0 - spinDelay := 100 * time.Millisecond - - led(Booting) - time.Sleep(100 * time.Millisecond) - for spinDelay > 20*time.Millisecond { - led(spin[spinIdx]) - time.Sleep(spinDelay) - spinIdx = (spinIdx + 1) % len(spin) - spinDelay -= 5 * time.Millisecond - } - for i := 0; i < 40; i++ { // just for safety - cur := spin[spinIdx] - led(cur) - time.Sleep(spinDelay) - spinIdx = (spinIdx + 1) % len(spin) - if cur == player { - break - } - } - } - - led(Empty) - time.Sleep(1 * time.Second) - setPlayer(Player1) - - var b [512]byte - for { - n, err := in.Read(b[:]) - log.Printf("read %d bytes: % x [err: %v]", n, b[:n], err) - if err != nil { - break - } - } - - /* - time.Sleep(1 * time.Second) - setPlayer(Player2) - time.Sleep(1 * time.Second) - setPlayer(Player3) - time.Sleep(1 * time.Second) - setPlayer(Player4) - time.Sleep(5 * time.Second) - led(Waiting) - */ - - var last, cur [512]byte - decode := func() { - n, err := in.Read(cur[:]) - if err != nil || n != 20 { - log.Printf("ignoring read: %d bytes, err = %v", n, err) - return - } - - // 1-bit values - for _, v := range []struct { - idx int - bit uint - name string - }{ - {2, 0, "DPAD U"}, - {2, 1, "DPAD D"}, - {2, 2, "DPAD L"}, - {2, 3, "DPAD R"}, - {2, 4, "START"}, - {2, 5, "BACK"}, - {2, 6, "THUMB L"}, - {2, 7, "THUMB R"}, - {3, 0, "LB"}, - {3, 1, "RB"}, - {3, 2, "GUIDE"}, - {3, 4, "A"}, - {3, 5, "B"}, - {3, 6, "X"}, - {3, 7, "Y"}, - } { - c := cur[v.idx] & (1 << v.bit) - l := last[v.idx] & (1 << v.bit) - if c == l { - continue - } - switch { - case c != 0: - log.Printf("Button %q pressed", v.name) - case l != 0: - log.Printf("Button %q released", v.name) - } - } - - // 8-bit values - for _, v := range []struct { - idx int - name string - }{ - {4, "LT"}, - {5, "RT"}, - } { - c := cur[v.idx] - l := last[v.idx] - if c == l { - continue - } - log.Printf("Trigger %q = %v", v.name, c) - } - - dword := func(hi, lo byte) int16 { - return int16(hi)<<8 | int16(lo) - } - - // +y - // N - // -x W-|-E +x - // S - // -y - dirs := [...]string{ - "W", "SW", "S", "SE", "E", "NE", "N", "NW", "W", - } - dir := func(x, y int16) (string, int32) { - // Direction - rad := math.Atan2(float64(y), float64(x)) - dir := 4 * rad / math.Pi - card := int(dir + math.Copysign(0.5, dir)) - - // Magnitude - mag := math.Sqrt(float64(x)*float64(x) + float64(y)*float64(y)) - return dirs[card+4], int32(mag) - } - - // 16-bit values - for _, v := range []struct { - hiX, loX int - hiY, loY int - name string - }{ - {7, 6, 9, 8, "LS"}, - {11, 10, 13, 12, "RS"}, - } { - c, cmag := dir( - dword(cur[v.hiX], cur[v.loX]), - dword(cur[v.hiY], cur[v.loY]), - ) - l, lmag := dir( - dword(last[v.hiX], last[v.loX]), - dword(last[v.hiY], last[v.loY]), - ) - ccenter := cmag < 10240 - lcenter := lmag < 10240 - if ccenter && lcenter { - continue - } - if c == l && cmag == lmag { - continue - } - if cmag > 10240 { - log.Printf("Stick %q = %v x %v", v.name, c, cmag) - } else { - log.Printf("Stick %q centered", v.name) - } - } - - last, cur = cur, last - } - - controller.ReadTimeout = 60 * time.Second - for { - decode() - } -} - -func XBoxOne(controller *usb.Device, in, out usb.Endpoint) { - read := func() (tag, code byte, data []byte, err error) { - var b [64]byte - - n, err := in.Read(b[:]) - log.Printf("read %d bytes: % x [err: %v]", n, b[:n], err) - - if err != nil { - return 0, 0, nil, err - } - if n < 2 { - return 0, 0, nil, fmt.Errorf("only read %d bytes", n) - } - - return b[0], b[1], b[2:], nil - } - - write := func(data ...byte) error { - n, err := out.Write(data) - log.Printf("sent %d bytes: % x [err: %v]", n, data, err) - if n < len(data) { - return fmt.Errorf("only sent %d of %d bytes", n, len(data)) - } - return err - } - - dieIf := func(err error, format string, args ...interface{}) { - if err == nil { - return - } - msg := fmt.Sprintf(format, args...) - log.Fatalf("%s: %s", msg, err) - } - - var err error - - // Initializ - err = write(0x05, 0x20) - dieIf(err, "initialization") - - decode := func(data []byte) { - if len(data) != 16 { - log.Printf("Only got %d bytes (want 16)", len(data)) - } - var ( - _ = data[0] // sequence number - _ = data[1] // unknown - btn1 = data[2] // ybxaSM?N S=share, M=Menu, N=Sync - btn2 = data[3] // ?lr?RLDU r=R-Thumb, l=L-Thumb, R=D-Right, L=D-Left, D=D-Down, U=D-Up - - lt = binary.LittleEndian.Uint16(data[4:6]) // left trigger, 0..1024 - rt = binary.LittleEndian.Uint16(data[6:8]) // right trigger, 0..1024 - - lx = int16(binary.LittleEndian.Uint16(data[8:10])) // right stick X - ly = int16(binary.LittleEndian.Uint16(data[10:12])) // right stick X - rx = int16(binary.LittleEndian.Uint16(data[12:14])) // right stick X - ry = int16(binary.LittleEndian.Uint16(data[14:16])) // right stick X - ) - - // btn1, least to most significant - for i, btn := range []string{ - "SYNC", "BTN1|0x02", "MENU", "SHARE", - "A", "X", "B", "Y", - } { - if btn1&(1<