Skip to content
totalreverse edited this page Dec 8, 2018 · 17 revisions

Table of Contents

Hardware Overview

This is a collection of information from the internet, together with own investigations. Not every information is confirmed.

*** WORK IN PROGRESS ***

There are two major kind of brakes: magnetic (eddy current) brakes and motorbrakes.

To control magnetic brakes, there are two ways: manually with a bowden control cable or electrically. The motorbrakes are always controlled electrically.

A (manual) magnetic brake is controlled by a bowden cable, which changes the distance of magnets to a rotating plate.

For electrical brakes, some kind of device controls the motor force or an (electrical) magnetic field.

The unit can be a stand-alone unit or a (host) computer controlled unit. Sometimes the controller is inside the brake and sometimes the controller is an external head unit connected to the brake by wire or wireless. The cable is always a full connected 6P6C RJ12 (RJ-25) cable. The wireless technology of the TACX brakes are always ANT+. There are two different ANT+ protocols. Older brakes talk a proprietary protocol. The newer brakes talk a portable ANT+ FE-C protocol (fitness equipment control).

"Wheel On" magnetic brakes are

  • Basic, Excel and Grand Excel (sometimes called Cycleforce ...)
  • i-Magic
  • Flow
  • Vortex
  • Satori (non electrical, but with wireless feedback)

"Wheel On" Motorbrakes are

  • Fortius
  • Cosmos
  • Bushido
  • Genius

"Direct Drive" magnetic (electrical) brakes are

  • Flux (S), Flux 2

"Direct Drive" motorbrakes are

  • Neo, Neo 2

Tacx calls some of their trainers "smart". Smart means, that these trainers support the newer (standardized) ANT+ FE-C protocol together with Bluetooth 4.0.

Other name additions are VR, Multiplayer (typically bundled with TTS software, a steering device and a multiplayer license).

Note: There is a so called "PC Smart Upgrade (T2990)". This is a bundle with TTS4 (advanced), a wireless "control device" (T2022, with a built-in receiver for legacy heart belts) and an USB ANT+ antenna (T2028). The "control device" talks the old proprietary ANT+ protocol.

Tacx products

WIP

Abbreviation Description
MB motor brake
EC eddy current (magnetic)
50 50 Hz / 230 V (Europe)
60 60 Hz / 110 V (US)
HU head unit
RJ12 RJ12 cable
ANT legacy ANT+
ANTFEC ANT FE-C controlled
Acc Accessory

First some notes about 32 and 64 bit compatibility of some of the PC products: The (non wireless) PC head units are plain vanilla USB (1.1) and they work with 32 bit and 64 bit. The problem with the older head units is, that TACX do not support a firmware loader for the older firmware and the newer TTS software does not support the older communication protocol of the T1902 firmware.

Tacx
Cat Type Year Description Additional Information
T1601 Brake EC, 50 199x Cycleforce Excel/Basic brake similar, but not identical to Flow brake i.e. New T1904 and T1932 can not drive the old T1601
T1620 Bundle EC, 50 1995 ? Cycleforce Excel : Bundle with T1601 brake and T1642 head unit
T1640 Bundle EC, 50 1995 ? Cycleforce Grand Excel: Bundle with T1601 brake and T1642 head unit also contains a so called 'grand excel USB interface' ?
T1642 Unit HU, EC, 50 1995 ? Cycleforce Excel stand-alone head unit (has parallel port to connect PC or Printer)
T1652 Unit HU, EC, 50 1995 ? Cycleforce Basic stand-alone head unit
T1670 Bundle EC, 50 1995 ? Cycleforce Basic with T1601 brake and T1652 stand-alone head unit
T1680 Bundle EC, 50 Flow with magnetic T1901 brake, T1682 head unit and T1690 skyliner
T1682 Unit HU, EC, 50/60 orange Flow stand-alone head unit
T1684 Bundle EC, 60 Flow T1911 brake (US) with T1682 head unit and T1690 skyliner
T1690 Acc front wheel skyliner

Tacx
Cat Type Year Description Additional Information
T1900 Bundle EC, 50 i-Magic bundle T1901 brake, head unit, TTS3 software PDF
T1901 Brake EC, 50 Flow, i-Magic brake
T1902 Unit EC/(MB), 50/60 ? solid green head unit Needs firmware after every power up. Compatible to brakes T1601, T1901, T1911 (and even to T1941, T1946 motor brake with special firmware)
T1904 Unit EC/MB, 50/60 ? green ring head unit. built-in firmware. Can drive brakes T1901, T1911, T1941, T1946. NOT compatible with T1601
T1905 Acc steering frame for T1901, T1904, T1935, T1942 head units
T1911 Brake EC, 60 Flow, i-Magic brake (US version)
T1912 Bundle EC, 60 i-Magic bundle 60Hz T1911 brake, T1902 head unit, TTS3 software (US)
T1915 Upgrade Kit EC/(MB), 50/60 i-Magic upgrade Kit T1902 head unit and software
T1925 Upgrade Kit EC/(MB), 50/60 Fortius upgrade kit T1932 Blue Ring head unit with software (TTS4 Basic?)
T1930 Bundle Fortius Multiplayer T1941 (220V/50Hz),T1905 Steering Frame, Software, T1932 PDF
T1932 Unit EC/(MB), 50/60 blue ring head unit
T1935 Bundle Fortius Multiplayer T1946 (110V/60Hz), T1932 head unit, T1905 steering, Software,
T1940 Bundle Fortius Bundle 220V/50Hz T1941, T1932 (NO steering frame, and NO one year multiplayer license)
T1941 Brake Fortius Motorbrake 220V/50Hz
T1949.50 Acc Fortius power unit 220V/50Hz
T1942 Unit Fortius solid blue head unit
T1945 Bundle Fortius Bundle 110V/60Hz T1946, T1932 (NO steering frame, and NO one year multiplayer license)
T1946 Brake Fortius Motorbrake 110V/60Hz
T1949.50 Acc Fortius power unit 110V/60Hz

Tacx
Cat Type Year Description Additional Information
T1960 Bundle EC, 50 2008 Vortex bundle T1961 brake and (legacy) ANT+ Head Unit Tacx PDF
T1961 Brake EC, 50 Vortex brake 230V 50/(60) Hz Magnetic Brake (NO 110V but 230/60 Hz)
T1970 Bundle MB, 50 ? Cosmos T1941 Motorbrake, T1972 stand alone head unit
T1975 Bundle MB, 60 Cosmos T1946 Motorbrake, T1972 stand alone head unit (US)
T1972 Unit Cosmos computer Cosmos stand alone head unit
T1980 Bundle MB 2008 Bushido Brake with stand alone head unit
No power required, ANT+
PDF 1, PDF 2
T1981 Brake Bushido
T1982 Unit Bushido computer Dark Grey stand alone head unit, ANT+ wireless

Vortex max power 950W (60 kph)


Tacx
Cat Type Year Description Additional Information
T2000 Bundle MB 2012 i-Genius Multiplayer brake with T2022, T2028, TTS4 software, T2420 steering (blacktrack) and multiplayer license
T2010 Bundle MB i-Genius Multiplayer smart probably later rebranded to Genius Smart (T2080),
T2020 Bundle MB i-Genius brake with T2022, T2028, TTS4 software
T2022 Acc MB ANT+ Controller Bushido, Genius/Ironman interface 'blue ufo' handle bar controller talking legacy ANT+ protocol
T2028 Acc MB ANT+ Antenna USB ANT+ receiver with antenna and a long USB cable
T2050 Bundle MB Ironman Rebranded T2020 i-Genius ?
T2060 Bundle MB Ironman smart Rebranded T2080FC plus World Championship Kona DVD
T2080 Bundle MB 2015 Genius Smart ANT+ FE-C and Bluetooth, controlled via App
T2080FC Bundle MB Genius Smart Full Connect ANT+ FE-C and Bluetooth plus T2022, T2028, TTS4 software

Power and incline Limits for Genius trainers are 2000W and 20%


Tacx
Cat Type Year Description Additional Information
T2162 (green) i-vortex head unit? green sides, ANT+ wireless
T2170 i-Vortex
T2171 i-Vortex resistance unit 110/230 Volt
T2172 i-Vortex head unit white/gray with blue sides, ANT+ wireless
T2179 Skyliner, vortex, i-vortex, Flow ...
T2180 Vortex Smart
T2181 Vortex Smart resistance unit
T2180FC Vortex Smart Full connect

Tacx
Cat Type Year Description Additional Information
T2200 EC, 50Hz 2011 Flow
T2210 EC, 60Hz Flow (60 Hz US)
T2220 EC, 50Hz 2011 Flow Multiplayer
T2230 EC, 60Hz 2011 Flow Multiplayer (60 Hz US)
T2240 EC 2015 Flow Smart ANT+ FE-C and Bluetooth, controlled via App
T2240FC EC 2017 Flow Smart Full connect ANT+ FE-C and Bluetooth plus T2022, T2028, TTS4 software
T2250 EC, 50Hz 2012 i-Flow
T2250 EC, 60Hz 2012 i-Flow (60 Hz US)

Power and incline Limits for Flow trainers are 800W (60 kph) and 6%

A closer look at the T1902 and T1942 head units

The CPU in the "solid" head units are a ezusb an2131s from Cypress that is fairly flexible (see AN2131).

Firmware loading

The head units do not have a non volatile memory except the eeprom, which contains the initial USB descriptor and the individual device ID. So, the firmware has to be loaded after every power up (under linux i.e. with the fxload tool).

Tacx always says, that the solid-green will work only on 32bit systems. To clarify this:

It is NOT(!) a problem with 32bit or 64bit systems.

You can easily load the firmware with the "fxload" tools under every operating system. There is a little python script, that can do the thing without any native binaries.

You can find the original firmwares on most of the Tacx DVD inside the driver directory. The T1942 firmware file is named FortiusSWPID1942Renum.hex. The original T1902 firmware is part of a the I-magic.sys file. You can cut it out of the File with a little helper tool (LINK).

Steering unit

Steering: The game-port protocol. See wikipedia THere is a NE585 (4x NE555) timer inside.

Controlling the resistance

The eddy-current (magnetic) brakes have 6 permanent magnets (newer brakes have 8 magnets) and the same numer of (head unit controlled) electro-magnets. With the electro-magnets switched off, the only magnetic force comes from the permanent magnets.

What happens if the electro magnets are switched on, depends on the timing of the switching. The source of the magnetic field is your powerline sinus voltage. On one half of the sinus period, the electro magnetic field reduces (compensates) the field of the permanent magnets and in the other half of the period the electro magnetic field increases the permanent magnetic field.

The head unit switchs the electro magnets on and off, synchronized to the powerline phase to increase or decrease the permant magnetic field. The length of the pulse depends on the selected resistance.

It's is a little like a RPC (reverse phase control) device synced with your powerline frequency. NOTE: Literature recommends "phase angle control" for inductive loads, but as far as I understood the brake control, TACX uses RPC. TODO: Have to verify this!

Inside the T1902 and T1942

; T1902 (solid green)
; T1942 (solid blue)
;
; EZ-USB port:
;
; ===========================================================================
; PORT A (same for Imagic & Fortius)
; ===========================================================================
;
; OUTA PINA.4 0x10 LED Red
; OUTA PINA.5 0x20 LED Green
;
; ===========================================================================
; PORT B (same for Imagic & Fortius)
; ===========================================================================
;
; similar to imagic: BIT 4-7 Buttons (IN), BIT 0-3 "Gameport"  OUT/IN
; PINB/OUTB 0x0f : 555/585 Timer for Gameport/Steering (steering is Bit #2 = mask 0x04)
; PINB 0xf0 : Buttons (enter: 0x10, down: 0x20, up: 0x40, cancel: 0x80)
;
; ===========================================================================
; PORT C
; ===========================================================================
;
; PINSC.7 magnetic field switch (or :Tx) (only "solid green" T1902) - 1:on 0:off
; PINSC.6 not connected / unknown
; PINSC.5 Heartbeat                 (alt function: connected to 'T0')
; PINSC.4 Cadence (on T1901)        (alt function: connected to 'T1')
; PINSC.3 Powerline "zero crossing" (alt function: connected to INT1)
; PINSC.2 Wheel (or: Rx)            (alt function: connected to INT0) (see note 1)
; PINSC.1 connected to Tx0 (only on "solid blue" T1942)
; PINSC.0 connected to Rx0 (only on "solid blue" T1942) (see note 1)
;
; Note 1: on the "solid blue" head unit the "blue" wire is connected to the PINSC.2 and PINSC.0!
;
Pin C# dir Dev function
PINC.0 IN Serial0 B Rx Alt-Function (OUT) - for T1941 motorbrake communication
PINC.1 OUT Serial0 B Tx Alt-Function - for T1941 motorbrake communication
Can be "missused" as magnetic field PAC/PWM/RPC when used with T1601/T1901 eddy current brake
PINC.2 IN INT0 B/G Wheel-Sensor (only when powered) for T1901-EddyCurrent-Brake (T1902: Rx)
PINC.3 IN INT1 B/G Power-Line-Frequency zero crossing (only when T1601/T1901 is powered)
PINC.4 IN T0 B/G CAD on T1901 brake, works also with unpowered T1601/T1901 (detected by sampling)
PINC.5 IN T1 B/G HR - works without brake connected (detected by sampling)
PINC.6 (IN) unused?
PINC.7 OUT G "PAC/PWM/RPC-controls" magnetic field of T1601/T1901 eddy current brake.
Can be "missused" as TX when used with T1941 motorbrake

( "B" is "blue" device, "G" is "green" device )

; head unit backside socket
;
;      __|^^^|__
;    _|         |_
;    |           |  cable  |  connect to PINC# (H/L: signal default when port is 'IN')
;    |           |  wire   |       solid-blue         solid-green
;    |6 5 4 3 2 1|  ------------------------------------------------
;     | | | | | |__ white  |          4  (H)            4  (H)  (3.3V TTL)
;     | | | | |____ black  |         --- (L)           --- (L)  (mass?)
;     | | | |______ red    |          1  (L)            7  (L)
;     | | |________ green  |          3  (L)            3  (L)  (sinus (AC) ~15V internally converted to 0V/~5V)
;     | |__________ yellow |             --- V_Brake ---   (Voltage/Power from brake 15-18V (T1901) or 5.8V (T1942))
;     |____________ blue   |     0 and 2 (H)            2  (H)  (3.3v TTL?)
;
;  'noisy' => there is a minor noise-feedback from the other signals
;
; One can see, that on both devices the important wires are connected to a pin
; at the CPU. Unfortunately the serial communication function of the motorbrake
; is not connected to the serial0-Tx/Rx pins in the 'solid-green' head unit
; The only way to control the motorbrake with the solid-green is to emulate
; a serial signal with "bitbanging" on PINC.2 (INT0) for Rx and PINC.7 for Tx,
; which is time critical and more expensive but possible.
;

Serial Communication between head unit and Fortius brakes

The communication between the head unit and the Fortius motorbrake is a serial 3.3V 'TTL' signal (not RS232) with 19200 baud and 8N1 coding.

Note: the used timer on the EZ-USB can only generate a 18750 baud signal.

Data frame

; The commands and answers all look like "4-bytes-cmd-header" | Msg-Data | "2-bytes-checksum"
; the length of the msg is coded in the second byte of the header (header[1])
; initial Motorbrake command:
; 02 00 00 00
;    => short answer from T1941 brake (and what T1904 says instead)
;     T1941[24+16+2]: 03 0c 00 00 65 09 00 00 ba c4 77 18 08 0c 00 00 [c4 70]
;     T1904[24+40]:   03 0c 00 00 02 19 00 00 00 00 00 00 00 00 00 00 35 69 00 00 00 00 02 55 64 [00...]
;
; Note: If you send 0x02,0x00,0x00,0x00 commands to early (while switching on the brake), the brake 
; initialization is uncomplete and the brake sends the following answer:
; 1-2 times:
;  01 46 46 30 32 30 30 30 30 43 44 46 46 39 44 38 31 17
;     => ff 02 00 00 cd ff
; and then:
;  01 30 33 30 43 30 30 30 30 36 35 30 39 30 30 30 30 42 41
;  43 34 37 37 31 38 30 38 30 43 00 00 00 00 44 46 36 42 17
;                                ^^^^^^^^^^^
; Instead of converted zeros "30 30 30 30" the brake sends real zeros "00 00 00 00"
; A (valid) checksum is calculated based on "00 00 00 00"
;
; standard Motorbrake command:
;
; |    Header   |  Message ....
; |  0  1  2  3 |     4        5     |        6         |  7 |   8  |    9   |      10            11
; | 01 08 01 00 |  LOAD_LSB LOAD_MSB | PEDALSENSOR_ECHO | 00 | MODE | WEIGHT | CALIBRATE_LSB CALIBRATE_MSB
;
; LOAD depends on the operating mode
;   0. Off-Mode:       set to zero
;   1. Ergo-Mode:      load = f_power(power)      with f ~= targetpower(Watt) * 13      with power = [0..1000]
;   2. Slope-Mode:     load = f_resistance(slope) with f ~= (slope(%) + Ds) * (10*5*13) with slope = [-5..20] and Ds = -0.4
;   3. Calibrate-Mode: load = f_speed(speed)      with f ~= speed(kph) * 290            with speed = [0..20++] (be careful)
;
; CALIBRATE adds/reduce the resistance to compensate the friction of the system in Ergo/Slope Mode
;     Ergo & Slope Mode & Off-Mode:
;       calibrate = f_calibrate( factor ):  f_calibrate = (factor + 8) * 130              with factor = [-8..8]
;                      default is factor=0   ===>>   default CALIBRATE = 0x0410
;          in "Off-Mode" the value probably does not matter
;     Calibrate-Mode:
;          set to zero (but probably value does not matter?)
;
; ================================================================
;
; Default calibration is 0x0410 = 1040 = 80*13 (or 8*130)
;
; The Tacx TTS4 software does the calibration at 20 kph (selectedLoad = 0x16a3).
; If the 'gauge' is perfect in the "green" middle of the calibration bar, then TTS4 sets the
; calibration value to 0x0492 (90*13)
;
; The calibration value is exactly the negated value you can read as "currentLoad", when 
; running the calibration at 20 kph.
; You start the calibration with 20 kph and the avg. load is for example about 0xfb70 
; => 0x10000-0xFB70 = 0x490 
; => rounded to multiples of 13 this is 0x492
;
; ================================================================
;
;    PEDALSENSOR_ECHO:
;        necessary? -> set Bit 0 (=0x1) to echo the pedal-sensor event from bit 0 of byte 42 of brake answer frame
;
;    WEIGHT:
;        Off-Mode:       set to default 0x52 (probably value does not matter)
;        Ergo-Mode:      set weight to 0x0a to enable ergo mode
;        Slope-Mode:     set total weight of rider+bike to control simulated resistance
;        Calibrate-Mode: set to default 0x52 (probably value does not matter)
;
;    MODE:
;        Off-Mode:           set to "0"
;        Ergo- & Slope-Mode: set to "2" (to distinguish between ergo & slope: set the weight: see above)
;        Calibrate-Mode:     set to "3"
;
;    => long answer from brake (and what T1904 says instead)
;     T1941[24+23+1]: 03 13 02 00 00 00 00 00 00 00 f0 61 00 00 00 00 80 06 00 00 00 00 02 [e5] // one byte checksum fragment
;     T1904[24+40]:   03 13 02 00 00 00 00 00 00 00 00 00 0f 04 0f 04 43 a8 00 00 00 00 02 55 64 [00...]
;     T1932[24+40]:   TODO
;
; illegal message (a possible testmessage to detect motorbrake):
; 01
;    => the middle part and the checksum can vary
;     T1941[24+6+2] : ff 02 14 00 ce ff [48 4d]    -> little endian is 02FF, 0014, FFCE [cksm]
;     T1904[24+49]  : normal answer
;     T1932[24+40]:   TODO
;

Marshalling and Checksum

Before transfering the data to the Fortius brake, the head unit marshalls the data frame and adds a checksum.

Every frame starts with 0x01 and ends with 0x17.

Every byte is recoded into a Hexcode before going on the wire. So every byte needs two bytes on the serial. Every byte is splitted into 4 bit nibbles and converted to ASCII (chracters '0'-'9' and 'A'-'F'). The only exception is the start and end byte (0x01,0x17). They are sent raw.

Python code is:

def bin2hex(b):
    if b >= 0 and b < 10:
        return b + 0x30      # '0'
    elif b >= 10 and b < 16:
        return b - 10 + 0x41 # 'A'
    else:
        raise NameError("only 4bit nibbles allowed")

There is a 16 bit checksum at the end. (hexcoded the checksum nees 4 bytes on the wire). The checksum includes the 0x01 start frame byte, but not the end frame byte.

Python code is:

def parity16(b):
    b ^= b >> 8
    b ^= b >> 4
    b &= 0xf
    return (0x6996 >> b) & 1

def checksum(buffer):
    shiftreg = 0x0000;
    poly = 0xc001;
    for a in buffer:
        tmp = a ^ (shiftreg & 0xff);
        shiftreg >>= 8;

        if parity16(tmp):
            shiftreg ^= poly;

        shiftreg ^= tmp << 6;
        shiftreg ^= tmp << 7;
    return shiftreg

Communication Protocolls of cable based trainers

The TACX USB vendor ID is 0x3561.

The blue-ring head unit has ID "3561:1932" and the green-ring has "3561:1904". I own a blue-ring and green-ring head unit and a both are all-in-one units, that can handle both brakes (the eddy-current-brake T1902 and the motorbrake T1940) Note: the newer 'blue ring' and 'green ring' head units can not driver the old T1601 eddy current brake sold with the Basic, Excel and Grand Excel.

Device USB Id Notes
T1902 3561:1902 Old "solid green" IMagic head unit (with or without loaded firmware)
T1904 3561:1904 New "white green" IMagic head unit (white body with green or (sometimes) white ring - firmware inside)
T1932 3561:1932 New "white blue" VR head unit (white body with blue ring - firmware inside
T1942 V1 3561:e6be Old "solid blue" Fortius head unit (without firmware loaded)
T1942 V2 3561:1942 Old "solid blue" Fortius head unit (with firmware loaded)

You can load the firmware of the "solid blue" device (FortiusSWPID1942Renum.hex) also to the solid green/yellow/white. The solid green head unit 'magically' converts to a 'solid blue' one. This works at least on the devices I own.

BUT: You have to control the brake different, because the PCB layout between the CPU (PortC) and the serial cable is a little different. The green unit uses PINC.7 to controll the magnetic field, whereas the blue unit uses the serial interface on PINC.0 / PINC.1.

ATTENTION: maybe the powerline signal from the magnetic brake has 16v voltage level (no 3.3TTL). Mabye the blue head unit cannot handle this (but mine is still alive). I have not checked the wireing on the PCB.

On linux:

  fxload -I FortiusSWPID1942Renum.hex -d /dev/bus/usb/xyz/abc

where "xyz" is the bus number and "abc" is the device number

For example try the following:

$> lsusb -d 3561:
Bus 002 Device 011: ID 3561:1902
$> fxload -I FortiusSWPID1942Renum.hex -d /dev/bus/usb/002/011
$> lsusb -d 3561:
Bus 002 Device 012: ID 3561:1942

In this example, the device now has a new ID 012 on bus 002 and a new unit ID "3561:1942" That's the ID of the "solid blue". 3561 is the ID of "Tacx bv".

Funny - isn't it.

T1902 USB 'legacy' protocol: 6 Bytes OUT, 21 Bytes IN

Outbound:

The device can send up to 6 bytes. Less bytes are allowed.

Byte
Description Notes
0 desired 'force' value. Range is 0x00...0xFF
0x80 is 'neutral' (electrical magnetic field switched off).
Values less than 0x80 reduce brake force (electrical magnetic field reduces the static magnetic fields) and values greater than 0x80 increase the brake force (electrical magnetic field increase the static magnetic fields).
1 start/stop control Only Bits 0-2 are used:

* 0x01 PAUSE/START manual control of stop watch
* 0x02 AUTOPAUSE - if wheel is less than '20'
* 0x04 AUTOSTART if wheel is greater or equal 20

To force a start without wheeling you need to start the stopwatch (Bit0=1) and disable auto-stopping (Bit1=0). Bit2 does not matter.

Auto-Start/Stop is achieved with 0x06
2 Set stop watch high byte optional
3 Set stop watch mid byte optional
4 Set stop watch low byte optional
5 Set stop watch hundreds optional, different for older firmwares

Inbound

Byte
Description Notes
0 Status and Cursors Bit0: 0x01=HeartBeat
Bit1: 0x02=Power-Detect
Bit2+3: Powerline frequency
* 0x0C: 50Hz
* 0x08: 60Hz
* 0x04: unused
* 0x00: <50Hz
Bit4: 0x10=Enter Button
Bit5: 0x20=Down Button
Bit6: 0x40=Cancel Button
Bit7: 0x80=Up Button
1 WheelSpeed High turns of the wheel in the last second?
2 WheelSpeed Low
3 Cadence RPM (revelation per minute)
4 Heartrate BPM (beats per minute)
5 Stopwatch Seconds High
6 Stopwatch Seconds Mid
7 Stopwatch Seconds Low
8 Stopwatch Hundreds
9 Resistence value of brake
10 PedalSensor Bit 5: 0x00 or 0x10
11 Axis 1 floating between 0xBf-0xC3
12 Axis 2 0x00-0xff Steering if plugged
https://en.wikipedia.org/wiki/Game_port
13 Axis 3 Unused? always 0x00
14 Axis 4 Unused? always 0x00
15 Counter running 0-255 every 70-80 ms, (old firmware fa, 1a)
16 Wheel Count Number of Counts of (metal) wheel since last call (~70-80ms)?
17 Year YY: individual Year of production of YOUR unit (20YY)
18 Serial High YOUR individual Device-ID (high)
19 Serial Low YOUR individual Device-ID (low)
20 Firmware-Version 0x1c new, 0x1a old

Bytes 17-19: matchs YOUR sticker on head unit backside

Newer USB 12/48 Bytes protocol

All outbound messages are motorbrake command messages, that are just handled as described above. After adding a checksum, marshalling and framing, they are directly sent to the serial.

For inbound messages, the first 24 bytes are from the head unit. The second 24 bytes are unmarshalled answers from the motorbrake. Note: Normal answers have 23 bytes plus 2 bytes checksum. So the last byte is the first byte of the checksum. The second checksum byte is discarded inside the head unit.

The CAD-information is copied from the motorbrake data block to the head unit data block

Outbound Version Message

Bytes № Description Notes
  02 00 00 00

Inbound Version Message

struct frameHeadUnit {
    uint16_t    deviceSerial;       //  0...1   hex-serial of YOUR head-unit (see sticker on backside)
    uint16_t    fixed1;             //  2...3   0x0000 (T1904 has 0x0005)
    uint16_t    fixed2;             //  4...5   0x0108 (little endian) - other firmwares sometimes 0x0104, (T1904: 0x0001)
    uint16_t    fixed3;             //  6...7   0x0000
    uint8_t     year_production;    //  8       production year of YOUR head unit  (see sticker on backside: first value - maybe after product#)
    uint8_t     unused1;            //  9       random artefact from uncleared IN2BUF?
    uint8_t     unused2;            // 10       random artefact from uncleared IN2BUF?
    uint16_t    heartRate;          // 11..12   in BPM - T1942: MSB always zero
    uint8_t     buttons;            // 13
    //uint8_t     rxErrorCode;      // 14       0xfb= RX-Checksum Error, 0xfe=RX-bufferoverrun [in Frame from Motorbrake]
    uint8_t     unused3:1;          // 14.0     zero
    uint8_t     heartDetect:1;      // 14.1     bit is 'in sync' with RED LED
    uint8_t     unused4:6;          // 14.2..14.6 zero
    uint8_t     rxErrorCount;       // 15       counts motorbrake serial-communication receive-errors
    uint16_t    axis0;              // 16..17   typcially 'floating' - we set it to 0x07d0
    uint16_t    axis1;              // 18..19   steering (uncalibrated) ... typically between 0x0300 and 0x0580 (T1904), 0x0220-0x0540 (T1942)
    uint16_t    axis2;              // 20..21   unused: often 0x07d0 (timeout of gameport 'A/D-conversion')
    uint16_t    axis3;              // 22..23   unused: often 0x07d0 (timeout of gameport 'A/D-conversion')
};
Bytes № Description Notes
TODO

Outbound Control Message

Bytes № Description Notes
  01 08 01 00  ................

struct frameCommandFortius {
    struct frameHeader header;

    uint16_t force;      // 0..1 : load,force,resistance, slope -- 50-1000w on a Fortius
    uint8_t  pedalecho;  // 2
    uint8_t  zero0;      // 3
    uint8_t  mode;       // 4 IDLE/NONE=0, ERGO/SLOPE=2, CALIBRATE/SPEED=3
    uint8_t  weight;     // 5 for ERGO: weight=0x0a; for SLOPE: weight=rider+bike weight in kg, IDLE/NONE: set weight=0x52
    uint16_t calibrate;  // 6..7 (in mode "0" and "2" it is: val = (calibrate + 8) * 130 with calibrate [-8..8] - set to "0" while calibrating (mode 3)
};

Inbound Control Message

Bytes № Description Notes
struct frameHeader {
    uint8_t command;
    uint8_t size;       // main message size ...
    uint8_t datapage;   // ?
    uint8_t zero;       // never seen anything else than 0x00 - maybe high byte of little endian 16 bit?
};

struct frameBrakeLong {
    struct frameHeader header;      // 24..27
    uint32_t    distance;           // 28..31  total distance
    uint16_t    speed;              // 32..33  wheel speed in kmh ~= speed / 290
    uint16_t    unknown34_35;       // 34..35  increases if you accelerate, bit 0..2 always zero
    uint16_t    unknown36_37;       // 36..37  Changes similar to 38..39 on T1904 - probably avg. power

    // ERGO:  LOAD = 128 * Watts / 10         => Watts  = 10 * LOAD / 128
    // SLOPE: LOAD = 128 * 10 * slope% + 512  => Slope% = (LOAD - 512) / 128 / 10
    uint16_t    currentLoad;        // 38..39
    uint16_t    targetLoad;         // 40..41
    uint8_t     events;             // 42  - 0x01 pedal-sensor event, 0x04 brake-stops event
    uint8_t     unknown43;          // 43
    uint8_t     cadence;            // 44 in RPM
    uint8_t     unknown45;          // 45 (value > 0x00 when accelerating )
    uint8_t     modeEcho;           // 46 motor brake bounces/echos the mode-byte from command-frame
    uint8_t     checksumLSB;        // 47 fragemented checksum
    // Standard 48 byte frame ends here - we added checksumMSB
    uint8_t     checksumMSB;        // 48 fragemented checksum
    // padding to 64 byte frame
    uint8_t     pad[15];
};

struct frameBrakeShort {
    struct frameHeader header;
    uint32_t    firmwareVersion;     // 0.x.y.c
    uint32_t    serialNumber;        // tt-YY-#####  (tt=41 (T1941), YY=year, ##### brake individual serial)
    uint16_t    version2;            // Date of firmware DD.MM or MM.DD?? (together with YY in the serial?)
    uint16_t    unused;              // ??
    uint8_t     checksumLSB;
    uint8_t     checksumMSB;
};

struct frameBrakeError {
    struct frameHeader header;
    uint16_t    errorcode;  // always 0xffce ?
    uint8_t     checksumLSB;
    uint8_t     checksumMSB;
};


struct frame {
    struct frameHeadUnit   unit;   // size 24 (bytes 0..23)
    union {
        uint8_t buf[25+15];        // bytes 24..48 + padding is 49..63
        struct frameBrakeLong  l;  // size 25
        struct frameBrakeShort s;
        struct frameBrakeError e;
    } brake;
};




// Legacy:
struct frameCommandImagic {
    // brake load/resistance
    uint8_t  load;

    //  Stopwatch Control (0x01/0x04/0x05 pause, 0x00/other values: start)
    //    3 bits (0-2) are relevant
    //           0x01 STOP/START  'isRunning'
    //           0x02 AUTOSTOP  if 'Wheel' < 20
    //           0x04 AUTOSTART if 'Wheel' >= 20
    //  To force a start without wheeling you need to a) start the Stopwatch (Bit0=1) and
    //  and b) disable autostopping (Bit1=0). Bit2 does not matter in this case
    //
    //  Auto-Start/Stop is achieved with 0x06
    //  0x01/0x04/0x05 pause, 0x00/other values: start/continue
    uint8_t  autostartstop;

    // optional: stopwatch (re)set values (different on older firmwares?)
    uint8_t  stopwatchSecHigh;
    uint8_t  stopwatchSecMid;
    uint8_t  stopwatchSecLow;
    uint8_t  stopwatchHundreds;
};

// internal EZ USB eeprom
struct eeprom {
    uint8_t  loadType;   // 0xB0 -> reduced USB descriptor, 0xB2 => load firmware from eeprom
    uint16_t vendorID;
    uint16_t productID;
    uint16_t deviceID;
    uint8_t  unused[6];
    uint8_t  year_production;
    uint16_t deviceSerial;
};

Newer USB 12/64 Bytes protocol

The T1904 and T1935 can handle both brake types: magnetic brakes and the motor brakes (but for some reason not the old T1601 magentic brake). Because there is no serial communication between the head unit and the magnetic brakes, the head unit emulates the (serial) data frames when it is connected to a magnetic brake.

The checksum in byte 47 is always a static value and bytes 48 to 63 are padded with zeros.

When connected to magentic brakes every received frame is 64 bytes long. There are no 24 byte answers.

If there is no steering connected the head units sends a little higher default value.


Protocoll of older wireless ANT+ Tacx trainers

All devices are using the default ANT+ network key. The default key is set after a reset of the ANT dongle. Please send a ANT reset command to the usb dongle to (re)set all you networks to the default network key.

Device parameters

Tacx brakes and the other Tacx devices are using several different ANT channels, periods and device types.

Tacx Device Name ANT Device-Type (*1) Channel frequency Channel period =Hz Notes
(i)Vortex Brake 0x3d 66 = 0x42 0x2000 = 8192 4 Hz GoldenCheetah has demystified the protocol. Check i.e. ANT.h and ANTMessage.cpp
Vortex Display 0x3e 78 = 0x4e 0x0f00 = 3840 ~8.53 Hz T2172 light-blue, T2162 yellow-green
Bushido Brake 0x51 60 = 0x3c 0x1000 = 4096 8 Hz pyBushido and Cyclismo both have demystified the protocol
Bushido Display 0x52 60 = 0x3c 0x1000 = 4096 8 Hz hosts sends 4E #ch# AC commands
Genius Brake 0x53 60 = 0x3c 0x1000 = 4096 8 Hz
Blacktrack Steering 0x54 60 = 0x3c 0x0800 = 2048 16 Hz Steering T2420. Probably also NEO track T2430. Slave => Master: Keep alive ? [01 00 00 00 00 00 00 00] ? steering
Cursor Control 0x55 60 = 0x3c 0x1000 = 4096 8 Hz The small blue round (Bushido head unit) controller
Flux Brake 0x56 66 = 0x42 0x2000 = 8192 4 Hz TTS4 knows this device, but maybe it was never released (with legacy ANT protocol) Keepalive / Control messages from host to brake: host sends: 4E #ch# 10 00 00 aa 7e 00 00 00
Flow Brake 0x5f 66 = 0x42 0x2000 = 8192 4 Hz Same as Flux Brake: see above

Note *1: With ANT+ Pairing Bit add 0x80 to the ANT Device-Type

Commands and Answers

All older Tacx ANT+ devices handle at least the 3 commands. A command always starts with "AC" followed by the command number. All answers start with "AD" followed by the command number, followed by the payload.

Host Cmd Nr type Data from Host Answer (example) note
01 Get Device Serial ac 01 00 00 00 00 00 00 ad 01 01 0c 00 00 25 78 Big endian: "01"=20 ("00"=19??), "0c"=12 year of production, "00 00 25 78" is MY serial => 20-12-09592
02 Get SW Version ac 02 00 00 00 00 00 00 ad 02 01 01 01 e9 00 00 Big endian: here 01.01.01e9 = 1.1.489
04 Battery Status ac 04 00 00 00 00 00 00 ad 04 03 xx xx xx xx xx Here 03 = OK, xx xx xx xx xx contains data from the last command

ANT+ Battery Status Values

Status Value Notes
New 1
Good 2
OK 3
Low 4
Critical 5
Charging 6 Not used?
unknown 7

Regualar Pages from the device

Every devices send regualar data pages.

Cursor Control Page

Byte 0 1 2 3 4 5 6 7
Value 00 00 0x FF 00 00 00 00

Byte 2 contains a 4 bit (OR-ed) value with

Bit Nr. value meainng
0 x = 1 Up
1 x = 2 Right
2 x = 4 Down
3 x = 8 Left

Protocoll of Smart Tacx trainers with wireless ANT FE-C

Not much to describe here. The brake talks standard ANT FE-C

Clone this wiki locally