WouterJD / FortiusANT

FortiusANT enables a pre-smart Tacx trainer (usb- or ANT-connected) to communicate with TrainerRoad, Rouvy or Zwift through ANT or Bluetooth LE.
GNU General Public License v3.0
153 stars 78 forks source link

Support for Vortex T1961 brake and T2172 head unit (~101, 117) #46

Open WouterJD opened 4 years ago

WouterJD commented 4 years ago

hi, I own a Tacx i-vortex (the non-smart one). Would this work with it? I might give it a try :)

Originally posted by @iepuzaur in https://github.com/WouterJD/FortiusANT/issues/14#issuecomment-612229158

WouterJD commented 4 years ago

Hi @iepuzaur

I have created this separate issue for you.

Some questions:

  1. Could you ever use Tacx tts-4 software with your i-vortex?
  2. Is it connected to a PC with a USB-cable?
  3. Does the i-vortex have a headunit on the steering rod of your bicicle with number like 1902, 1904, 1932 or 1934?

If yes, there is a fair chance that FortiusANT may work and I will assist. Just let me know!

By the way, where are you from? I like to know who I talk with :-)

WouterJD commented 4 years ago

https://tacx.com/product/i-vortex/

Is this the machine?

iepuzaur commented 4 years ago

Hi, Thanks for creating the topic, indeed the i-vortex is the one from the link you sent, except i have it on light green color. Now with spending time at home a lot, I wanted to use it again and discovered Tacx sold to Garmin, support is inexistent and if you lost your previous installation of TTS4, than it's rather useless. It is the version before Vortex Smart and has only Ant+, without fe-c. the trainer works fine with TTS 4, connection is not made by usb cable, but through an Ant+ usb dongle. I'll have a look at the repo and see if I manage anything, would be glad to test this. Greets from Bucharest, Romania

iepuzaur commented 4 years ago

Head unit is 1962 though.

WouterJD commented 4 years ago

So your i-Vortex is from the time that Tacx wanted to keep software and hardware bundled and proprietary. What would be needed is to (1) understand how the i-Vortex communicates through ANT and (2) convert that tp "ANT+ FE-C". (1) is the challenge.

As said above: please try ExplorANT.py and check what it finds; that's the first step. To do this you need a computer (windos, linux, mac) and (for a starter) with one USB ANT-dongle? If you want to start Zwift... from the same computer a second dongle is required.

I have been searching for an "i-Vortex ANT definition" and found the folllowing article: https://www.dcrainmaker.com/2015/06/trainer-profile-zwifttrainerroadkinomap.html (June 2015)

So how do you upgrade your trainer? Via a simple app. Tacx today released a new utility app called ‘Tacx Utility’, this app connects to your Smart series trainer and updates the trainer’s firmware. Once upgraded, then 3rd party apps that support the ANT+ Trainer Profile can control it as they see fit.

Zwift: ... As long as you upgrade your trainers firmware first, you can then scan for the trainer using the usual Zwift option, which will in turn find the trainer and allow you to control it. Super simple.

It's interesting to give it a try.

totalreverse commented 4 years ago

It looks like Goldencheetah has support for the proprietary i-Vortex ANT protocol. Check the src/ANT/ANTMessage.cpp file.

WouterJD commented 4 years ago

Thanks, man, you're a great help. Will check

totalreverse commented 4 years ago

ANT parameters are (unconfirmed)

ANT Device-Type = 0x3d Channel 66 = 0x42 Period = 0x2000 No network key (= the default key after resetting the ANT dongle)

You're doing a great job, btw.

WouterJD commented 4 years ago

Just being lazy and asking; does this mean if I would simply bridge the i-vortex as a FE-C it would be enough?

I guessed that would be the easy way to make a proprietary trainer

totalreverse commented 4 years ago

Just being lazy and asking; does this mean if I would simply bridge the i-vortex as a FE-C it would be enough?

Answer: Unfortunately No

GoldenCheetah ANTMessage.cpp Line ~ 660 ++

        case ANTChannel::CHANNEL_TYPE_TACX_VORTEX:
        {
            const uint8_t* const payload = message + 4;
            vortexPage = payload[0];

            switch (vortexPage)
            {
            case TACX_VORTEX_DATA_SPEED:
                vortexUsingVirtualSpeed = (payload[1] >> 7) == 1;
                vortexPower = payload[2] | ((payload[1] & 7) << 8); // watts
                vortexSpeed = payload[4] | ((payload[3] & 3) << 8); // cm/s
                // 0, 1, 2, 3 = none, running, new, failed
                vortexCalibrationState = (payload[1] >> 5) & 3;
                // unclear if this is set to anything
                vortexCadence = payload[7];
                break;

            case TACX_VORTEX_DATA_SERIAL:
                // unk0 .. unk2 make up the serial number of the trainer
                //uint8_t unk0 = payload[1];
                //uint8_t unk1 = payload[2];
                //uint32_t unk2 = payload[3] << 16 | payload[4] << 8 || payload[5];
                // various flags, only known one is for virtual speed used
                //uint8_t alarmStatus = payload[6] << 8 | payload[7];
                break;

            case TACX_VORTEX_DATA_VERSION:
            {
                //uint8_t major = payload[4];
                //uint8_t minor = payload[5];
                //uint8_t build = payload[6] << 8 | payload[7];
                break;
            }

            case TACX_VORTEX_DATA_CALIBRATION:
                // one byte for calibration, tacx treats this as signed
                vortexCalibration = payload[5];
                // duplicate of ANT deviceId, I think, necessary for issuing commands
                vortexId = payload[6] << 8 | payload[7];
                break;
            }

            break;
        }

ANTMessage.cpp Line about 955 ++


ANTMessage ANTMessage::tacxVortexSetFCSerial(const uint8_t channel, const uint16_t setVortexId)
{
    return ANTMessage(9, ANT_BROADCAST_DATA, channel, 0x10, setVortexId >> 8, setVortexId & 0xFF,
                      0x55, // coupling request
                      0x7F, 0, 0, 0);
}

ANTMessage ANTMessage::tacxVortexStartCalibration(const uint8_t channel, const uint16_t vortexId)
{
    return ANTMessage(9, ANT_BROADCAST_DATA, channel, 0x10, vortexId >> 8, vortexId & 0xFF,
                      0, 0xFF /* signals calibration start */, 0, 0, 0);
}

ANTMessage ANTMessage::tacxVortexStopCalibration(const uint8_t channel, const uint16_t vortexId)
{
    return ANTMessage(9, ANT_BROADCAST_DATA, channel, 0x10, vortexId >> 8, vortexId & 0xFF,
                      0, 0x7F /* signals calibration stop */, 0, 0, 0);
}

ANTMessage ANTMessage::tacxVortexSetCalibrationValue(const uint8_t channel, const uint16_t vortexId, const uint8_t calibrationValue)
{
    return ANTMessage(9, ANT_BROADCAST_DATA, channel, 0x10, vortexId >> 8, vortexId & 0xFF,
                      0, 0x7F, calibrationValue, 0, 0);
}

ANTMessage ANTMessage::tacxVortexSetPower(const uint8_t channel, const uint16_t vortexId, const uint16_t power)
{
    return ANTMessage(9, ANT_BROADCAST_DATA, channel, 0x10, vortexId >> 8, vortexId & 0xFF,
                      0xAA, // power request
                      0, 0, // no calibration related data
                      power >> 8, power & 0xFF);
}
WouterJD commented 4 years ago

Thanks again; let's seet what @iepuzaur will provide. New challenge to port the software at distance, not having the device at hand.

plundberg75 commented 4 years ago

Hi WouterJD I have the same trainer Tacx Vortex with the T1962 head unit, Happy to help if you just let me know what you need!

WouterJD commented 4 years ago

Great guys; it will not be an easy job - but worth while trying. It will take some testing....

Currently busy to get the software running on MacOS: #45 :-)

As probably stated above, the first step is to install the software - and you do not need to a python expert, check the wiki - and run ExplorANT, a small tool that shows what's going on on the ANT+ network.

Command: ExplorANT -d127 which will create a logfile, please post.

In the meantime, say hallo on Strava: https://www.strava.com/athletes/2885978

iepuzaur commented 4 years ago

I am on windows 10 as well.

În mie., 15 apr. 2020 la 17:43, WouterJD notifications@github.com a scris:

By the way:

  • What systems do you use? I work with windows
  • Please download the newest software which has been improved the last days to debug the MacOS environment

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/WouterJD/FortiusANT/issues/46#issuecomment-614081599, or unsubscribe https://github.com/notifications/unsubscribe-auth/APEJOVRATFKEMRK5YKPHMODRMXBXLANCNFSM4MGACCGA .

plundberg75 commented 4 years ago

Windows 10 for me as well

darkpotpot commented 4 years ago

Hi,

I also have an i-vortex. I'll probably be able to do the test at the end of the day (in 8 hours) if nobody had the time to do it before.

For this first test, do I need to reinstall the trainer as a libusb-win32 device or it doesn't matter for now ?

Anyway, thanks for the time spent on this.

WouterJD commented 4 years ago

Welcome! Yes it's a libusb device; please check https://github.com/WouterJD/FortiusANT/wiki#windows

iepuzaur commented 4 years ago

Yes, sorry about that. the log attached. ExplorANT.2020-04-16 09-12-38.log

WouterJD commented 4 years ago

It seems that ExplorANT is running and does not "see" any ANT+ devices. The idea is that you start Tacx iVortex and then start ExplorANT.

Can that be the case? I hope that the iVortex acts like a master ANT+ device and should be visible...

To avoid misunderstanding:

Thanks

darkpotpot commented 4 years ago

In case of any help, I did the manip. Started i-vortex trainer and head unit. Started TTS4, both units are seen. Started ExplorANT.

As a side note, at the very beginning of the trainer, tacx tts4 needed to have head unit started in order to control the trainer. Then, at some point they did an update and it was not needed anymore. Tacx TTS4 was able to control the trainer without the head unit

ExplorANT.2020-04-16 16-02-43.log

iepuzaur commented 4 years ago

so I have checked as per your indications, then I get this:

16:05:15,811: ExplorANT started 16:05:15,812: -d 127 (0b1111111) 16:05:15,813: -D -1 (-0x1) 16:05:15,816: -H -1 (-0x1) 16:05:15,816: -F -1 (-0x1) 16:05:15,817: -------------------- 16:05:15,817: Dongles in the system: 16:05:15,859: manufacturer=Dynastream Innovations, product= ANT USBStick2, vendor= 0xfcf, product=0x1008(4104) 16:05:15,860: -------------------- 16:05:15,861: GetDongle - Check for dongle 4100 Older 16:05:15,871: GetDongle - Check for dongle 4104 Suunto 16:05:15,889: GetDongle - Try dongle: manufacturer=Dynastream Innovations, product= ANT USBStick2, vendor= 0xfcf, product=0x1008(4104) DEVICE ID 0fcf:1008 on Bus 000 Address 001 ================= bLength : 0x12 (18 bytes) bDescriptorType : 0x1 Device bcdUSB : 0x200 USB 2.0 bDeviceClass : 0x0 Specified at interface bDeviceSubClass : 0x0 bDeviceProtocol : 0x0 bMaxPacketSize0 : 0x20 (32 bytes) idVendor : 0x0fcf idProduct : 0x1008 bcdDevice : 0x100 Device 1.0 iManufacturer : 0x1 Dynastream Innovations iProduct : 0x2 ANT USBStick2 iSerialNumber : 0x3 123  ¡¢£¤ ÀÁÂà DSI
bNumConfigurations : 0x1 CONFIGURATION 1: 100 mA ================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x2 Configuration wTotalLength : 0x20 (32 bytes) bNumInterfaces : 0x1 bConfigurationValue : 0x1 iConfiguration : 0x2 ANT USBStick2 bmAttributes : 0x80 Bus Powered bMaxPower : 0x32 (100 mA) INTERFACE 0: Vendor Specific =========================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x0 bAlternateSetting : 0x0 bNumEndpoints : 0x2 bInterfaceClass : 0xff Vendor Specific bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x2 ANT USBStick2 ENDPOINT 0x81: Bulk IN =============================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x81 IN bmAttributes : 0x2 Bulk wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x1 ENDPOINT 0x1: Bulk OUT =============================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x1 OUT bmAttributes : 0x2 Bulk wMaxPacketSize : 0x40 (64 bytes) bInterval : 0x1 16:05:15,914: GetDongle - Set configuration 16:05:15,914: GetDongle - Send reset string to dongle 16:05:15,915: GetDongle - Exception: [Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, win error: The requested resource is in use.\r\n' 16:05:15,918: GetDongle - Check for dongle 4105 Garmin 16:05:15,927: GetDongle() returns: No (free) ANT-dongle found 16:05:15,928: No (free) ANT-dongle found 16:05:15,928: We're done

Of course this is because the other app is using the Ant+ usb device. But what I have sent earlier is for sure with the units (brake and headunit connected to the ant+ usb stick).

PS. If worth knowing, my Ant+ USB device is T2018 of Tacx.

WouterJD commented 4 years ago

stop tts4 before starting explorANT and redo test

WouterJD commented 4 years ago

In case of any help, I did the manip. Started i-vortex trainer and head unit. Started TTS4, both units are seen. Started ExplorANT.

ExplorANT.2020-04-16 16-02-43.log

Good next step. I have modified ExplorANT to separate the logging from the console + some minor improvements. Important change -done for MacOS support- is that dongle error handling is improved, messages MAY got lost, hence a rerun is useful. Thanks.

Please download software, rerun and let me see output.

darkpotpot commented 4 years ago

Hi, here is the log with the latest version ExplorANT.2020-04-17 07-00-01.log

WouterJD commented 4 years ago

This logfile looks as if there is no device "in the air". I have reviewed the device pairing-process and learned from it and updated the software.

Please download antDongle and ExplorANT and retry.

I assume that you have the iVortex "ready to use" when running ExplorANT, true?

darkpotpot commented 4 years ago

Yes, everything is "ready to use". If I launch Tacx TTS4, it discovers immediately both devices (head unit and trainer). Of course when I do your test, Tacx TTS4 is not launched. New log is attached ExplorANT.2020-04-17 11-37-13.log

WouterJD commented 4 years ago

So, the "normal" open pairing mechanism does not work. It will require an extended version of ExplorANT to support more pairing options. I will come back on it

WouterJD commented 4 years ago

ANT Device-Type = 0x3d Channel 66 = 0x42 Period = 0x2000

I have extended the device pairing for the Tacx i-Vortex for pairing with masters with the pairing-bit set; which does not make a lot of difference it seems.

Also, I always open a channel for VTX (i-Vortex) and listen to messages.

So ready for next test.

darkpotpot commented 4 years ago

Test done ExplorANT.2020-04-18 06-41-34.log

WouterJD commented 4 years ago

One device is recognized

06:41:42,638: ExplorANT:   ? discovered on channel=0, number= 5866 typeID=122 TrType=122
06:41:42,638: ExplorANT: added to list

Will continue later-on, other things to be done now!

PS. 122?? DeviceTypeID_bike_cadence =122 do you have an active bike-cadence sensor on your bike?

Q: while doing the test, did you cycle on the bike & trainer?

darkpotpot commented 4 years ago

Well yesterday I did the test in a room with no bike. Today I did it where I store usually the trainer and the bike. So indeed there might have been other ant devices like speed sensor, cadence sensor and power sensor. I removed everything from the room and did the test again. Sorry about that.

And no, I did not cycle. This time I did.

ExplorANT.2020-04-18 09-12-00.log

WouterJD commented 4 years ago

No worries. Well. I think I listen on channel 7 to the Tacx i-Vortex but do not receive any messages. The setup is now OK; I will have to study the material as provided above by @totalreverse to check what I should do, using the investigations Golden Cheetah evidently have done.

iepuzaur commented 4 years ago

Not sure if it helps, but if you need a team viewer access to test directly next time when you have time to look on this matter, I could grant it to my laptop which runs the trainer.

Thanks a lot for the effort!

În sâm., 18 apr. 2020 la 13:01 WouterJD notifications@github.com a scris:

No worries. Well. I think I listen on channel 7 to the Tacx i-Vortex but do not receive an messages. The setup is now OK; I will have to study the material as provided above by @totalreverse https://github.com/totalreverse to check what I should do, using the investigations Golden Cheetah evidently have done.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/WouterJD/FortiusANT/issues/46#issuecomment-615835131, or unsubscribe https://github.com/notifications/unsubscribe-auth/APEJOVUH5TKRGU3QKYREQADRNF253ANCNFSM4MGACCGA .

WouterJD commented 4 years ago

sure @iepuzaur please do the test as above and communicate logfile. ci!

iepuzaur commented 4 years ago

Here attached my log. ExplorANT.2020-04-18 12-08-25.log

WouterJD commented 4 years ago

same result. I will study GoldenCheetah code where the solution should be and come back on it.

WouterJD commented 4 years ago

Great to have two testers!

WouterJD commented 4 years ago

BTW @iepuzaur and @darkpotpot do you have Strava accounts? We could meet there to exchange our Tacx results in near future👍

iepuzaur commented 4 years ago

Honestly I haven't use it and nevertheless I am just a humble amateur :)) so I will definitely be the last :-)) but I will see if I can (re)connect it to Tacx (my Tacx was dusty for some years and only this terrible situation put it back on track, also noticing that much changed in the field since I have lost interest in it i.e. smart trainers). Again, your help is very appreciated!

mattipee commented 4 years ago

Quick scan over GoldenCheetah source, and recording here what is where.

WouterJD commented 4 years ago

I'll do what I can

darkpotpot commented 4 years ago

BTW @iepuzaur and @darkpotpot do you have Strava accounts? We could meet there to exchange our Tacx results in near future👍

Yes I have one. If a French Guy is asking to follow you, then it's me ;) Thank you for your work on this.

totalreverse commented 4 years ago

@WouterJD it looks to me, that you set the right devicetype and the right period but not the right channel (0x39 instead of 0x42 for vortex) and you're using a network with the ANT+ key. The vortex use the default key. After resetting the dongle just omit the key-setting or if you set a key on network #0 you can use i.e. network #1 (without a key).

WouterJD commented 4 years ago

Thanks for thinking with us!

PS. I do not understand the channel 0x39/0x42 paragraph; 0x42 is the msgID_AssignChannel or do I misunderstand?

Summarized, two changes:

Action for next test, action @iepuzaur, @darkpotpot, @plundberg75:

totalreverse commented 4 years ago

Ah yes - using the word "Channel" for the Frequency is not a good idea. Frequency = 66 is what I wanted to say. Are you sure you checked in the right antDongle.py file? The current file looks like an old version.

WouterJD commented 4 years ago

@totalreverse & @mattipee thanks for references to code samples!

GoldenCheetah ANTMessage.cpp Line ~ 660 ++ case ANTChannel::CHANNEL_TYPE_TACX_VORTEX: { const uint8_t* const payload = message + 4; vortexPage = payload[0];

        switch (vortexPage)
        {
        case TACX_VORTEX_DATA_SPEED:
            vortexUsingVirtualSpeed = (payload[1] >> 7) == 1;
            vortexPower = payload[2] | ((payload[1] & 7) << 8); // watts
            vortexSpeed = payload[4] | ((payload[3] & 3) << 8); // cm/s
            // 0, 1, 2, 3 = none, running, new, failed
            vortexCalibrationState = (payload[1] >> 5) & 3;
            // unclear if this is set to anything
            vortexCadence = payload[7];

Sorry for asking, but I'm a little bit stuck here how to read this I expect the payload to be 7 bytes (it's always seven) where pageNr is the first.

            0=Datapage number
            1=Power1
            2=Power2
            3=Speed1
            4=Speed2
            5=not used
            6=not used
            7=Cadence, but this would be the eighth byte...

The first bit of Power1 is vortexUsingVirtualSpeed; I'm fine with that The second and third bit of Power1 are vortexCalibrationState but also calculated in Power1; isn't that strange? Power is calculated as Power1 << 8 | Power2 but I would expect Power2 << 8 | Power1 (little endian) And if the payload would be seven bytes; payload[7] would be out of range?

I do not have a logfile of received packages (yet) so cannot check...

Got some hints?

WouterJD commented 4 years ago

Ah yes - using the word "Channel" for the Frequency is not a good idea. Frequency = 66 is what I wanted to say. Are you sure you checked in the right antDongle.py file? The current file looks like an old version.

Sorry... now it's the good one.

totalreverse commented 4 years ago

"vortex power" is an 11 bit value with the lower 8 bits from payload[2] and bit 0,1,2 from payload[1] as bit 8,9,10 in the power value (when I say bit 0 I mean "bit 0" = 2^0=1 and bit 7 is 2^7=128). So bit 7 of payload[1] is "vortexUsingVirtualSpeed" and bit 5,6 is vortexCalibrationState. Bit 3,4 of payload[1] is not decoded.

And yes: looks like the vortex trainer talks a big endian protocol.

Btw: The ANT+ payload is also 8 bytes long and the page number is the first byte (byte 0)

WouterJD commented 4 years ago

OK, Big endian and 8 bytes (Tacx indeed tried to make things difficult). The waiting is for a logfile.

But if Power uses payload[1] & 7 and vortexCalibrationState = (payload[1] >> 5) & 3; then the CalibrationState bits are calculated into Power, or am I getting tired?

totalreverse commented 4 years ago
bit #   7 6 5 4 3 2 1 0
values: a b c d e f g h 
payload[1] & 7        results in "0 0 0 0 0 f g h" and
(payload[1] >> 5) & 3 results in "0 0 0 0 0 0 b c"