Skip to content
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

Support for Bluetooth #8

Open
nephitejnf opened this issue Oct 24, 2019 · 13 comments
Open

Support for Bluetooth #8

nephitejnf opened this issue Oct 24, 2019 · 13 comments

Comments

@nephitejnf
Copy link

Not sure if there are plans for this already, but support for bluetooth would be awesome to see, especially for other with the switch lite. I know there is support for the BLE mode on the sc-controller project, that was rolled out after Valve rolled out the BLE mode.

@greggersaurus
Copy link
Owner

I have considered what it will require. I'll list my thoughts below for now:

  • Currently no work has been done to interface with the nRF51822 Bluetooth chip.
  • Interfacing with the nRF51822 seems to be done with the UART on the LPC11U37F
  • We should be able to leverage DFU to reprogram the nRF51822. However, this presents a risk of bricking the nRF51822 (meaning the controller will only work in wired mode). So we need to proceed cautiously when looking into this.

@david-sawatzke
Copy link

No idea if this is accurate, but when switching to the BLE firmware, steam outputs this, after updating the nxp firmware before that:

Starting SWD flash work itemFWU: Starting SWD radio update
Fetching Config Sets 1
CClientJobFetchPersonalizationFileID
FWU: Sending start command
FWU: Erasing by pages
FWU: start addr erased 0, end addr erased 126996

They seem to be using the nxp chip as an swd programmer, which seems pretty brick resistant.
This is also supported by the connections reverse engineering, which states that the swdio/swclk pins of the nrf are connected to the lpc11u37f.
For dev purposes, simply flashing a cmsis-dap firmware onto the lpc11u37 should probably work well enough, and there seem to already exist ports, for example http://wiki.tinker-pot.com/doku.php?id=en:cmsis-dap_adapter

@greggersaurus
Copy link
Owner

Awesome. Thanks for that additional info @david-sawatzke. The CMSIS-DAP firmware seems really promising!

Also, I'm aware I'm being a bit paranoid about bricking the nRF51822. Part of it is the "better safe than sorry" approach. Especially when it could ruin someone's hardware, which is no longer being produced :(. Also, I was fortunate enough to be on a podcast to talk about this project and got to talk to Jeff Keyzer (one of the designers for the SC) and he mentioned bricking the radio chip at least once (https://embedded.fm/episodes/304). So that adds a little to the concern ¯_(ツ)_/¯

@LemmaEOF
Copy link

LemmaEOF commented Jan 6, 2020

I’m pretty sure you can reflash the nRF51822 over wired connection, since that’s what you do to enable BLE mode.

@greggersaurus
Copy link
Owner

@Boundarybreaker if you have any details on how the wired connection is reflashing the nRF51822 via Steam and how that might be leveraged or reproduced please let me know. Otherwise thanks for the tip regarding another path to dig into!

@LemmaEOF
Copy link

I don't have any details, sadly. I just know that I didn't have the bluetooth dongle for one of my steam controllers, but was able to update it to BLE over wired connection.

@2bndy5
Copy link

2bndy5 commented Jan 20, 2020

I've been reading through the nRF5 SDK docs; I found this little section on the nRF51's debugging interface in the nRF51 reference manual. It's not everything we need to know, but its a start. Also the same document has details on the nRF51822 UART, but that is pretty straight forward. We just need to upload a program that dumps outgoing data (from UART RX/ LPC11's TX) into either the nRF51's TX FIFO (RF comms) or BLE advertise() call, and also handle pairing/bonding operations (RF & BLE).

Valve is probably using a generic SoftDevice + customized GATT profile for utilizing the nRF51 as a BLE co-processor (many DIY-ers use the UART service in a GATT profile -- not whatever Valve did). I have a hunch that Valve might be using the EasyDMA mode to utilize the nRF51 as an RF co-processor. Although that's assuming the included wireless dongle is also using an nRF51xxx or nRF52xxx, which is probably not the case. An older nRF24 could send/receive RF signals to/from the nRF51 using the nordic proprietary Enhanced ShockBurst protocol (Logitech is using an nRF24 for their unifying receiver dongle -- with added encryption & their own HID++ protocol). The nRF5 SDK also boasts Zigabee/ANT/Thread/Mesh support, but that's for later down the road.

It should be said that Bluetooth is different from BLE, and the nRF51822 doesn't support full-fledged Bluetooth. So maybe adjust the title of this issue...

EDIT: I can confirm that the dongle is using an nRF24LU1P

@roblabla
Copy link

roblabla commented Mar 12, 2020

So I started reverse engineering the protocol a bit, the findings presented below are based on my reverse engineering efforts on version 57bf5c10 (which doesn't have bluetooth support).

The USART protocol has a first "framing" layer where a packet starts with byte \0x02 and ends with byte \0x03. Byte \0x1f is used as an escaping character, such that within the packet, every time a 2, 3 or 1f is encountered, it is prefixed by a 1f and xor'd with 0x20.

Code for doing the escaping (sorry, it's Rust, but I hope the idea is conveyed):

fn usart_send_escaped_str(mut data: &[u8]) {
    while let Some(pos) = data.iter().position(|&v| v == 0x02 || v == 0x03 || v == 0x1f) {
        if pos != 0 {
            usart_send_raw_str(&data[..pos]);
        }
        usart_send_raw_str(&[0x1f, data[pos] ^ 0x20]);
        data = &data[pos + 1..];
    }

    if !data.is_empty() {
        usart_send_raw_str(data);
    }
}

Once the framing layer is removed, we get a datagram-oriented protocol. The first byte of the datagram is usually a packet ID. This table is what I more-or-less understood happening. Note that this is all just an informed guess based on my RE efforts, and 1000% untested :D. I'll keep it updated when I find new stuff.

Here are the packet IDs nRF->LPC:

Hex Packet ID Char Packet ID Packet Name Description
0x50 'P' ControllerHIDTransaction Initiated by the nRF side: calls the Controller SetReport handler, and then sends the resulting "answer" report back (see packet 0x50 LPC->nRF side)
0x52 'R'
0x53 'S' IsReady? No data. Seems to signal when the nRF chip is started and ready to go?
0x57 'W'
0x58 'X' NrfVersion Has 4 bytes arguments corresponding to the nRF version.
0x59 'Y' FirmwareUploadResult 1 byte argument, some kind of success code?
0x5a 'Z'
0x5b '['
0x66 'f'
0x69 'i'
0x6a 'j'

Packet IDs LPC->nRF:

Hex Packet ID Char Packet ID Packet Name Description
0x51 'Q' Sends lots of data, including the Keyboard Report and Mouse Report.
0x53 'S'
0x54 'T' Always followed by one byte.
0x56 'V' Sends 0x19 additional bytes. Always followed by a 'Q' packet.
0x58 'X' QueryNrfVersion Asks the NRF chip to send its version.
0x59 'Y' StartFirmwareUpload No args, signals the start of a firmware upload. If it works like the LPC bootloader, it will erase the flash.
0x5a 'Z' FirmwareUpload Sends at most 0x40 bytes of firmware data to flash on the nRF. The nRF will start flashing from 0x10_000.
0x5b '[' EndFirmwareUpload Sends a 0x10 byte checksum to verify the uploaded firmware.
0x5c '\' RESET Always accompanied by "RESET". Resets the nRF chip.
0x5d ']' Sent when receiving a HID Controller SetReport packet 0x9a. Data from that packet is forwarded.
0x63 'c' GetDeviceID Sends a DeviceID request.
0x64 'd' doze ALways followed by "doze".
0x69 'i' Has 0x20 bytes of arguments. Sent when receiving a HID Controller SetReport packet 0xbb.
0x6a 'j' Has 2 bytes.

@roblabla
Copy link

Here's some new info. It turns out there is an nRF firmware hidden within the vcf_wired_controller_d0g_57bf5c10.bin file. When the Steam Controller firmware runs, it pings the nRF firmware for its version, and if it's different from what it expects, it will upload a default firmware that's stored at offset 0x1C010 and of size 0x3CFC.

That's a relatively small firmware, all things considered. Small enough that it seems doable to pick it apart relatively quickly to find its workings. I already identified the function that parses the protocol (and found some new LPC->nRF packets in the process) just by going through every function looking for a big if/else forest 😆. So I'll be focusing my effort on this cute little firmware, see what's to be found in there.

@2bndy5
Copy link

2bndy5 commented Mar 13, 2020

@roblabla I must say I'm impressed with your progress!

I recently ran across a multiple protocol support in the nRF5 SDK that theoretically allows both BLE and ESB protocols concurrently using Nordic's Timeslots API. Although this API isn't fully utilized in any existing opensource firmware that I"m aware of (looking into the Arduino support for the nRF52840 and CircuitPython firmware for various nRF chips) outside of scheduling events for BLE protocol usage via the Nordic softdevice (s130 seems to be the preferred softdevice version in the aforementioned firmwares).

As far as reverse engineering purposes, the Timeslots API may not need special implementation as the Steam controller uses either ESB or BLE, but not at the same time.

@Argon2000
Copy link

Any progress/update on this feature? I just tested my SC with my Switch using cable, and it works great!
The not so great thing though is that the cable is like 1.5m long 😆. This would be awesome if you got working.
Thanks for the great work so far guys!

@JerionZer0
Copy link

JerionZer0 commented Nov 17, 2020

Hi, any progress on this? It’s a wonderful enhancement idea that I’d love to see working.

@X007AceX
Copy link

Fantastic work! I have a SC that has been collecting dust until I stumbled on this project. Looking forward to bluetooth support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants