ryanbinns / ttwatch

Linux TomTom GPS Watch Utilities
MIT License
206 stars 67 forks source link

Support for Nike+ GPS Watch ? #72

Open prynhart opened 8 years ago

prynhart commented 8 years ago

Hi,

I've got a Nike+ SportWatch GPS "Powered by TomTom" (http://www.tomtom.com/lib/doc/Nike-SportWatch-QuickStartGuide-EN.pdf), and would love to be able to grab the raw GPS datafiles from it (prior to them being munged by the Nike+ Fat client and uploaded to Nike+).

I was hoping that it would really be a "TomTom" watch - but it seems that this isn't the case, as with the watch connected to a Ubuntu 10.04 LTS box, I'm getting:

# ttwatch -a Unable to open watch

Is there any chance that support could be added ? I'm hoping it's "close enough" to being a TomTom watch :-) I'm not much of a programmer, but am happy to help re USB sniffing etc.

This is how the device presents in my Mac (the output of system_profiler)

SportWatch:

  Product ID:   0x5455
  Vendor ID:    0x11ac
  Version:  2.00
  Serial Number:    105F94461E000B00
  Speed:    Up to 12 Mb/sec
  Manufacturer: Nike
  Location ID:  0xfa140000 / 8
  Current Available (mA):   500
  Current Required (mA):    500
  Capacity: 66 KB (66,048 bytes)
  Removable Media:  Yes
  Detachable Drive: Yes
  BSD Name: disk1
  Partition Map Type:   MBR (Master Boot Record)
  S.M.A.R.T. status:    Not Supported
  Volumes:
SportWatch:
  Capacity: 65 KB (65,024 bytes)
  Available:    62 KB (62,464 bytes)
  Writable: No
  File System:  MS-DOS FAT12
  BSD Name: disk1s1
  Mount Point:  /Volumes/SportWatch
  Content:  DOS_FAT_12
  Volume UUID:  F50B099E-1E3A-30BE-9AD7-474EBC44661B

Here's someones report (when they were playing around with this type of watch) for a University project: https://www.os3.nl/_media/2013-2014/courses/ccf/smartwatches-hristo-leendert.pdf

With Thanks in Advance

Patrick Rynhart

ryanbinns commented 8 years ago

Interesting. If you're feeling brave, you could edit libttwatch/libttwatch.h and change TOMTOM_VENDOR_ID and TOMTOM_MULTISPORT_PRODUCT_ID to the values of your Nike watch then recompile and try to use it. If you start with simple commands (like getting version information) then it shouldn't cause problems if it doesn't work exactly the same. From the document you linked to, it looks like it should work just fine, so you might be really lucky!

martinruenz commented 8 years ago

I tried this today and it seems not to work. I executed ./ttwatch --version, but when send_packet(watch, MSG_UNKNOWN_0D, 0, 0, 20, 0) is called from ttwatch_send_startup_message_group, then libusb_interrupt_transfer(...) returns -1 (LIBUSB_ERROR_IO). I guess this means that the device is not supported? :-/

prynhart commented 8 years ago

Yeah that's the same point that I got to also - in libttwatch.cpp, this line returns LIBUSB_ERROR_IO:

result = libusb_interrupt_transfer(watch->device, write_usb_endpoint, packet, packet_size, &count, 10000);

called for packet 09 02 00 0D (dumped using print_packet(packet, packet_size)).

My guess is that the watch is the "same", but the addresses for write and read usb_endpoint are different than the official TomTom watches. Not sure how to determine these addresses - guess you would need to USB sniff the official Nike+ fat client....

ryanbinns commented 8 years ago

USB endpoints are fairly easy to find. Run lsusb -v -d11ac and look at the output. Look for an Interface Descriptor with bInterfaceClass equal to 3 Human Interface Device. There should be two Endpoint Descriptors under that. The addresses are listed as bEndpointAddress for each one. Simply copy these values to the code. You can also check the required packet size for the OUT endpoint - the wMaxPacketSize parameter.

Or if you want to list the output of lsusb -v -d11ac I can tell you which numbers to use.

aw commented 7 years ago

@ryanbinns I've tried a few things as suggested in the comments above, but failed to get it recognized with ttwatch.

Output from lsusb:

$ lsusb -v -d 11ac:5455

Bus 002 Device 005: ID 11ac:5455 Nike 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x11ac Nike
  idProduct          0x5455 
  bcdDevice            2.00
  iManufacturer           1 Nike
  iProduct                2 SportWatch
  iSerial                 3 REDACTED ;)
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           64
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          4 SportWatch
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              500mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              6 SportWatch HID
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.01
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      36
          Report Descriptor: (length is 36)
            Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
                            (null)
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Global): Report ID, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x3f ] 63
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Logical Minimum, data= [ 0x01 ] 1
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x09 ] 9
            Item(Global): Report Count, data= [ 0x3f ] 63
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Logical Minimum, data= [ 0x01 ] 1
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Output, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk-Only
      iInterface              5 SportWatch Drive
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x82  EP 2 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
Device Status:     0x0000
  (Bus Powered)
ryanbinns commented 7 years ago

It looks like it uses different endpoint addresses. I'm not sure if it will work, but you could try. Try replacing lines 225-238 of libttwatch.cpp with this:

write_usb_endpoint = 0x01;
read_usb_endpoint = 0x81;

Compile and try again. Don't do anything that writes to the watch though. Use -v to read version number to start with. If that works, you can be a little more adventurous, but still be careful at first.

aw commented 7 years ago

Sadly, I tried that and it still couldn't detect it.

prynhart commented 7 years ago

Hi Ryan (cc Alex)

Sorry for not replying - I did try a few things at the time, but got stuck. If I set up SSH access to the dev box I was using with the watch plugged in, do you think you might be able to have a look ? I'm not running much at the moment :-)

Thanks,

Patrick

On 15/05/17 7:34 PM, Alex Williams wrote:

Sadly, I tried that and it still couldn't detect it.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/ryanbinns/ttwatch/issues/72#issuecomment-301398776, or mute the thread https://github.com/notifications/unsubscribe-auth/APCDi-Qztzg0Q1D9S1mA9WyM6tlBZ-s9ks5r6AAjgaJpZM4H-stG.

ryanbinns commented 7 years ago

I don't think I'd be able to do anything useful. I think to make any more progress, you'd need to capture the USB packets transmitted between the watch and the Windows software when the watch is plugged in and the software does its stuff.

prynhart commented 7 years ago

Hi Ryan,

Apologies - I've been putting this off, because it sounded too difficult (and because I didn't have a bare-metal Windows box). However, I've just had a go now, and it's much easier than I thought.

I have captured using the latest build of USBPcap (1.2.0.2) using the current version of the Nike Connect+ Software (Version 6.6.34.141).

I thought we would start with the simplest possible case:

I've done this, and the PCAP capture file is attached. I've opened it okay in Wireshark and can see communication with the device.

Very happy to upload runs etc as needed (or to switch features on and off using the Fat Client under a packet trace).

Thanks again - and apologies for not following up sooner.

Patrick NikeWatchWithoutRuns.zip

prynhart commented 7 years ago

Oops - I did not mean to close this ticket :)

cgibson33 commented 6 years ago

Hi. Nike just announced they will be retiring the only applications that pull data off their watch by April 30, so I'm guessing this thread will receive more interest.

prynhart commented 6 years ago

Yeah I know - amazing they can give less than 2 weeks notice on this - the link to the FAQ is https://en-gb-help.nike.com/app/answer/article/why-cant-i-sync/a_id/73653/country/nz

screen shot 2018-04-19 at 2 02 48 pm

cgibson33 commented 6 years ago

So, reading through the thread, it appears that you were able to capture some data, but that ryanbinns or someone else still needs some run data before being able to create a version of the software(s) that works with the Nike+ sportwatch? Correct me if I misunderstand.

prynhart commented 6 years ago

Unfortunately the strap on my Nike+ GPS Sportwatch broke very recently and it won't connect up to any of my computers (a common fault with these watches). However, what you're saying above is correct - i.e. a patch needs to be created for the Nike version of this TomTom watch. Capturing the USB packets was straight forward on Windows (I followed the instructions at https://wiki.wireshark.org/CaptureSetup/USB) - so in theory anyone with a Windows box, the watch, and the Nike+ Connect Software (while it is still running) should be able to capture the protocol exchange between the client and the watch.

cgibson33 commented 6 years ago

Ok. I guess I better get on that then. I assume I need to run a variety of use cases. First I will try to capture watch connection with 1 run to transfer/upload.

cgibson33 commented 6 years ago

I managed to capture a single run transfer. I have never used wireshark before, so I suspect that the file may also contain traffic from other USB ports. Any directions on how to remove information from the other ports?

cgibson33 commented 6 years ago

The capture used the 64 bit version of wireshark with USBPcap included with the wireshark installation. Easy enough to use once I got it installed correctly. I suppose I should read the wireshark wiki on how to analyse the resultant file.

cgibson33 commented 6 years ago

one run filtered for bus1 and device ID6.zip

Ok - I think I did that correctly - I did the capture and then created a new file filtered only for bus1 and device ID that correlated to the watch. I noticed that the address seemed to change from 1.6.0 to 1.6.1 but that appears to be the correct data/traffic.

prynhart commented 6 years ago

Nice work. Not sure what the next step would be though - need someone who can look at the comms in the packet capture and compare this with what’s happening in the source. Would be good to get something underway before the shutdown, but at least these captures are around while the Nike client is still working.

Other things that could be captured while the client still works (probably with the runs empty) would be the settings - e.g. comms when the colours are inverted, weight of runner, enable/disable beep. I.e. All the control / admin features if the watch. Maybe do a trace for one at a time (so as little is changing as possible).

Get Outlook for iOShttps://aka.ms/o0ukef


From: cgibson33 notifications@github.com Sent: Saturday, April 21, 2018 12:56:40 PM To: ryanbinns/ttwatch Cc: Rynhart, Patrick; State change Subject: Re: [ryanbinns/ttwatch] Support for Nike+ GPS Watch ? (#72)

one run filtered for bus1 and device ID6.ziphttps://github.com/ryanbinns/ttwatch/files/1934020/one.run.filtered.for.bus1.and.device.ID6.zip

Ok - I think I did that correctly - I did the capture and then created a new file filtered only for bus1 and device ID that correlated to the watch. I noticed that the address seemed to change from 1.6.0 to 1.6.1 but that appears to be the correct data/traffic.

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHubhttps://github.com/ryanbinns/ttwatch/issues/72#issuecomment-383255579, or mute the threadhttps://github.com/notifications/unsubscribe-auth/APCDi_94PH8f6qzWL5uO2FMprVvryecBks5tqoPIgaJpZM4H-stG.

cgibson33 commented 6 years ago

Will do. Do you think it would be ok if I left the watch plugged in the whole time, but just recorded each action separately using different file names? Also, I think there is a watch reset function that I should record because that might be the only way to clear the watch memory when it is getting full.

internecivusraptus commented 6 years ago

I think I should share my research notes. All the relevant information can be filtered by entering usb.capdata into wireshark's display filter — it's a leftover capture data that we're interested in. This leftover data is 64 bytes long. First byte is a direction (09 into watch, 01 from watch), second byte is a packet size, third one is just a counter. For the query that goes into watch, fourth byte is a command, next bytes are arguments. For the respond that we receive from watch fourth byte and next bytes are the reply data, last byte is some sort of check byte, it has to be the same as a counter byte.

The system nike client uses to download tracks is pretty dumb — it sends the '09 05 xx 10 00 00 00 ..' packet, the watch responds with a complete eeprom dump and the client is analyzing it afterwards. Typical response is '01 3d xx 01 xx xx xx (significant_data_bytes) xx' when we still have data to receive and '01 (size_of_packet) xx 00 xx xx xx (significant_data_bytes) 00 .. 00 xx' when it is the last packet.

It seems that I have a corrupted watch, so I couldn't analyze what I am getting from the watch.

P.S. I was still able to change some settings like sounds, weight, metric or imperial units, etc.

prynhart commented 6 years ago

Hi Ryan,

Recording the reset function sounds like an excellent idea :-) With regard to recording each action, not sure.  I guess it depends whether the Connect client sends / updates the watch immediately when a change is made.  (It probably does.). If you can see traffic (in wireshark afterwards) when you change/adjust a feature then this would be a good indicator as to whether you've got the exchange recorded.

The surefire / OCD way to do it would be to disconnect the watch each time, and record each transaction individually.  (i.e. Record, Connect Watch, Start client, Change one feature, Exit client, disconnect watch.). This would obviously be more noisy though.

In short - not sure which is the best approach :-)

Thanks,

Patrick

On 22/04/18 3:04 AM, cgibson33 wrote:

Will do. Do you think it would be ok if I left the watch plugged in the whole time, but just recorded each action separately using different file names? Also, I think there is a watch reset function that I should record because that might be the only way to clear the watch memory when it is getting full.

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/ryanbinns/ttwatch/issues/72#issuecomment-383303636, or mute the thread https://github.com/notifications/unsubscribe-auth/APCDi6NYpuupqCos4DSoUyr-IAx60NxXks5tq0qYgaJpZM4H-stG.

prynhart commented 6 years ago

Very interesting.  I wonder if this 'offline' processing is being done because the watch itself doesn't support an API that can pull individual events off it ?  If so, the watch would be very different to the 'other' TomTom watches that this Github project supports.

On 22/04/18 9:57 PM, Igor Gritsenko wrote:

I think I should share my research notes. All the relevant information can be filtered by entering |usb.capdata| into wireshark's display filter — it's a leftover capture data that we're interested in. This leftover data is 64 bytes long. First byte is a direction (09 into watch, 01 from watch), second byte is a packet size, third one is just a counter. For the query that goes into watch, fourth byte is a command, next bytes are arguments. For the respond that we receive from watch fourth byte and next bytes are the reply data, last byte is some sort of check byte, it has to be the same as a counter byte.

The system nike client uses to download tracks is pretty dumb — it sends the '09 05 xx 10 00 00 00 ..' packet, the watch responds with a complete eeprom dump and the client is analyzing it afterwards. Typical response is '01 3d xx 01 xx xx xx (significant_data_bytes) xx' when we still have data to receive and '01 (size_of_packet) xx 00 xx xx xx (significant_data_bytes) 00 .. 00 xx' when it is the last packet.

It seems that I have a corrupted watch, so I couldn't analyze what I am getting from the watch.

— You are receiving this because you modified the open/close state. Reply to this email directly, view it on GitHub https://github.com/ryanbinns/ttwatch/issues/72#issuecomment-383369183, or mute the thread https://github.com/notifications/unsubscribe-auth/APCDi2WSNdb5cNx5VRDsXUqp1QVhPGWeks5trFP0gaJpZM4H-stG.

cgibson33 commented 6 years ago

Ok - last minute I recorded a bunch of settings interactions including a factory reset Documents.zip

cgibson33 commented 6 years ago

When I did the settings changes, you could see packages transferring as soon as I typed any number or changed any setting on the fly, so I didn't bother removing the watch at any point

cgibson33 commented 6 years ago

And Nike has checked out of the building - I assume that will get people's attention. capture

cgibson33 commented 6 years ago

Ok - so now what? Do I need to do some further analysis on the captures? Is this watch too different than the other watches serviced by this code?

iglezouton commented 6 years ago

Hi guys, other solution would be to run a local proxy interpecting calls to Nike+ from the local app running and then store the data locally. But this is in case this project can't support the watch because as @prynhart suggested would be very different to the 'other' TomTom watches

prynhart commented 6 years ago

Hi guys - unfortunately nothing to add, I don't know how different this watch is. Hopefully someone else watching this thread can advise. Thanks, Patrick

tomasdev commented 6 years ago

@iglezouton your suggested proxy solution doesn't work, because there are pre-flight validations on services that don't work anymore, even before the upload service is called.

tomasdev commented 6 years ago

@cgibson33 could you post your guide to watch the packets? I've tried USB Probe (mac only) and Wireshark with no luck.

cgibson33 commented 6 years ago

The main problems I had with wireshark were just getting installed with USBPCap included - that can be accomplished just by selecting that option during install - assuming you have the version of wirecap with USBPCap and WinPCAP (gui) included. Once installed, its easy: Just start capturing and then add display filters at the top using the expression button or autocomplete - at a minimum you will have to filter for Bus and device ID (use AND expression). The PC seems to randomly assign ID numbers but I usually found the watch traffic on Bus 1 and ID 6, 7, or 8. Wireshark will still be recording ALL USB traffic. Once done, stop recording and save the file - you can re-filter it later at any time and then just save the filtered packets if you want. tempsnip

cgibson33 commented 6 years ago

Note that it is now impossible to record any actual communications for GPS updates or Run uploads since Nike has shut down the server - the only thing you can record is settings changes.

slavutichd commented 6 years ago

С мая 2018 года компания Nike прекратила поддержку Nike sportwatch gps описанный в вашей статье. Не удалось ли создать install программу ... с конвертацией в gpx?

MauroMarini commented 6 years ago

Hi everybody, is it possible, after uninstalling the Nike app, to use an "USB tool" to try to engage the watch and let it transfer the data? What tool should be used to try?

ViktorNest commented 6 years ago

Maybe someone can figure it out?

https://www.os3.nl/_media/2013-2014/courses/ccf/smartwatches-hristo-leendert.pdf

rvernica commented 4 years ago

The code posted here seems to be able to download binary data from the watch and parse it into XML.

There is also this project, but I'm not sure what are its capabilities.