Older Tacx wireless trainers are not ANT+ FE-C compatible and use a proprietary ANT-based protocol instead.
This summary is based on work done by @totalreverse, @fluxoid-org, @mikeymclellan, @m472 and @rjohn65 (see sources) along with own research.
This document is a work in progress and represents a best guess. Some of the information has not been verified with actual hardware.
All messages are sent as broadcast data (unless otherwise noted). All integer values are big-endian (MSB first).
The following pages are supported by all Tacx legacy ANT devices (unless otherwise noted).
Page 0xac - Request information
Bytes | Value | Interpretation |
---|---|---|
0 | 0xac | Page |
1 | 0x01 | Request serial |
0x02 | Request version | |
0x04 | Request battery status | |
0x11 | Request brake version (Bushido and Vortex head units only) | |
0x12 | Request brake serial (Bushido and Vortex head units only) | |
2-7 | 0x00 | Padding |
Page 0xad (0x01) Serial number
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x01 | Sub page |
2 | 0x00 | Reserved |
3 | UInt8 | Production year |
4-7 | Int32 | Device number |
The serial number is of the form XX-YY-ZZZZZ where
XX = 20 (Blacktrack)
XX = 21 (Genius)
XX = 22 (Genius head unit)
YY = Production year
ZZZZZ = Device number
Page 0xad (0x02) Version
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x02 | Sub page |
2 | UInt8 | Major version |
3 | UInt8 | Minor version |
4-5 | UInt16 | Build number |
6-7 | ? | ? |
Page 0xad (0x04) Battery status
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x02 | Sub page |
2 | UInt8 | Battery status |
0 | Reserved | |
1 | New | |
2 | Good | |
3 | Ok | |
4 | Low | |
5 | Critical | |
6 | Reserved | |
>=7 | Invalid | |
3-7 | ? | ? |
Battery status definition is the same as ANT+ common page 82 (D00001198_-_ANT+_Common_Data_Pages_Rev_3.1.pdf, 6.11.2).
The Bushido and Vortex protocols are very similar to the Genius protocol (with some subtle differences) when pairing with the head unit. The protocol used between the head unit and the brake itself is also ANT-based but is quite different.
ANT channel configuration (PC)
Parameter | Value |
---|---|
Channel type | Slave (0x00) |
Network key | Public network |
RF frequency | channel 60 (2460 MHz) (Genius/Bushido head unit) |
channel 78 (2478 MHz) (Vortex head unit) | |
Transmission type | 0 (for pairing) |
Device type | 83 (0x53) (Genius) |
82 (0x52) (Bushido head unit) | |
62 (0x3e) (Vortex head unit) | |
Device number | 0 (for pairing) |
Channel period | 4096 (8 Hz) (Genius/Bushido head unit) |
3840 (~8.5 Hz) (Vortex head unit) |
The brake continuously sends sub pages 0x01, 0x02 and 0x03 during training.
Page 0xdd (0x01) - Speed/Power/Cadence
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdd | Page |
1 | 0x01 | Sub page |
2-3 | UInt16 | Wheel speed (0.1 km/h) |
4-5 | UInt16 | Power (W) |
6 | UInt8 | Cadence (rpm) |
7 | UInt8 | L/R Balance (%) |
Page 0xdd (0x02) - Distance/HR
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdd | Page |
1 | 0x02 | Sub page |
2-5 | UInt32 | Distance (m) |
6 | UInt8 | Heart rate (bpm) |
7 | 0x00 | Padding |
Page 0xdd (0x03) - Alarm/Temperature
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdd | Page |
1 | 0x03 | Sub page |
2-3 | UInt16 | Alarm status (bitmask) |
4 | UInt8 | Brake temperature (°C?) |
5-6 | UInt16 | Power generated ("Powerback") (W) |
(Genius only) | ||
7 | 0x00 | Padding |
Alarm status (Genius)
Bitmask | Interpretation | Severity | Message |
---|---|---|---|
0x0001 | Overtemperature | Warning | Temperature too Hot! Slow Down! |
0x0004 | Overvoltage | Error | Overvoltage! Stop! |
0x0008 | Generic error | ||
0x0020 | Overcurrent | Warning | Overcurrent! Brake Limited! |
0x0080 | Speed too high | Warning | Speed is too high. |
0x0100 | Undervoltage | Warning | Undervoltage! Speed Up! |
0x0200 | Virtual power | ||
0x4000 | Downhill speed limited | ||
0x8000 | Communication error | Error | No communication with the brake |
Alarm status (Bushido)
Bitmask | Interpretation | Severity | Message |
---|---|---|---|
0x0001 | Temperature level 1 | ||
0x0002 | Temperature level 2 | ||
0x0003 | Temperature level 3 | Warning | Temperature too Hot! Slow Down! |
0x0004 | Temperature level 4 | Warning | Temperature too Hot! Brake Limited! |
0x0005 | Temperature level 5 | Error | Temperature too Hot! Stop! |
0x0008 | Overvoltage | Error | Overvoltage! Stop! |
0x0010 | Overcurrent level 1 | Warning | Overcurrent! Brake Limited! |
0x0020 | Overcurrent level 2 | Error | Overcurrent! Stop! |
0x0080 | Speed too high | Warning | Speed is too high. |
0x0100 | Undervoltage | Warning | Undervoltage! Speed Up! |
0x2000 | Virtual power | ||
0x4000 | Virtual speed | ||
0x8000 | Communication error | Error | No communication with the brake |
Alarm status (Vortex)
Bitmask | Interpretation | Severity | Message |
---|---|---|---|
0x0001 | Wrong mains voltage | Error | Problems with mains voltage Brake Limited! |
0x0002 | Temperature high | Warning | Temperature too Hot! Slow Down! |
0x0004 | No brake coils | Error | Brake coils not connected with electric circuits. Stop! |
0x1000 | Virtual power | ||
0x2000 | Virtual speed | ||
0x4000 | Brake not paired | Error | Vortex connected to a brake but they are not paired. It's not possible to alter the brake power. Stop! |
0x8000 | Communication error | Error | No communication with the brake |
Page 0xdd (0x04) - Calibration status (Genius)
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdd | Page |
1 | 0x04 | Sub page |
2 | UInt8 | Calibration state |
0x00 | Stopped | |
0x01 | Started | |
0x02 | Running | |
0x03 | Calibrated | |
0x04 | Uncalibrated | |
0x81 | Value error | |
0x82 | Cadence error | |
0x83 | Speed error | |
0x84 | Timeout | |
0x85 | Torque error | |
3-4 | UInt16 | Calibration value |
5-7 | ? | ? |
Calibration value is informational only. It is applied automatically on successful calibration. Power-cycling the brake resets status to uncalibrated, but calibration value is persisted. The recommended range for the is calibration value is 60-90 ("green" range in TTS).
Page 0xdd (0x10) - Buttons (Bushido/Vortex) This page is sent as acknowledged, not broadcast data.
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdd | Page |
1 | 0x10 | Sub page |
2 | 0xXY | X: Key flag |
Y: Key code | ||
3-6 | 0x00 | Padding |
7 | UInt8 | Button event count |
(Vortex only) |
Key flag
Byte | Interpretation |
---|---|
0x0 | Normal press |
0x8 | Long press (>0.5s) |
0xc | Very long press (>2.5s) |
Key code
Byte | Interpretation |
---|---|
0x0 | None |
0x1 | Left |
0x2 | Up |
0x3 | OK |
0x4 | Down |
0x5 | Right |
The PC regularly sends 0x01 and 0x02, alternating between the two.
Page 0xdc (0x01) - Target
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdc | Page |
1 | 0x01 | Sub page |
2 | 0x00 | Slope mode |
0x01 | Power mode | |
0x02 | Heart rate mode (?) | |
3-4 | Int16 | Target slope (0.1%)/power (W)/heart rate (bpm) |
5 | UInt8 | Rider + bike weight (kg) |
6 | 0x00 | |
0xee | Reset distance (Genius and Bushido only) | |
7 | 0x00 | Padding |
The rider/bike weight is used for both gravity simulation (in slope mode) and to adjust the inertia of the virtual flywheel. The virtual flywheel is active even in power mode. Power mode is very slow to adjust to changes in cadence/power target unless the rider/bike weight is lowered (e.g. ~10kg).
Page 0xdc (0x02) - Wind/Track resistance
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdc | Page |
1 | 0x02 | Sub page |
2-3 | Int16 | 0.5 * wind resistance coefficient (0.001 kg/m) |
4-5 | Int16 | Genius: Wind speed (0.004 m/s, tail wind +/head wind -) |
Bushido: Wind speed (1 m/s, tail wind -/head wind +) (?) | ||
UInt16 | Vortex: Wind speed (1 m/s, head wind only) (?) | |
6-7 | UInt16 | Rolling resistance (0.01 N) (Vortex only) |
TTS4 apparently assumes units of 0.01 m/s for the Genius, but seems to be closer to 0.004 m/s in reality.
wind resistance coefficient = air density * surface area * drag coefficient
TTS4 default values
air density = 1.226 kg/m^3
surface area = 0.5m^2
drag coefficient = 0.5
0.5 * wind resistance coefficient = 0.15325 kg/m (0x0099)
rolling resistance = (user weight + bike weight) * 9.81 m/s^2 * rolling resistance coefficient
There is no setting for rolling resistance on the Genius and Bushido. Presumably a default rolling resistance coefficient of 0.004 is used (smooth asphalt).
Page 0xdc (0x04) - Calibration (Genius)
Bytes | Value | Interpretation |
---|---|---|
0 | 0xdc | Page |
1 | 0x04 | Sub page |
2 | UInt8 | Calibration action |
0x00 | Stop | |
0x01 | Start | |
0x02 | Request calibration info | |
0xff | Trigger production calibration | |
3-7 | 0x00 | Padding |
Check that speed is 0, then send Start (0x01) to start calibration, request calibration information (0x04) to monitor for errors/completion at ~1s intervals. Send Stop (0x00) on user request only to interrupt calibration.
Page 0x00 - Keep-alive (Bushido/Vortex)
Regularly send to keep the head unit from turning off (every ~10s).
Bytes | Value | Interpretation |
---|---|---|
0 | 0x00 | Keep-alive |
1-7 | 0x00 | Padding |
Broadcast data may be lost, so the following commands should be re-sent until a response (0xad) is received.
Page 0xac (0x03) - Set mode (Bushido/Vortex)
Bytes | Value | Interpretation |
---|---|---|
0 | 0xac | Page |
1 | 0x03 | Set mode command |
2 | UInt8 | Mode |
0x00 | Stand-alone | |
0x01 | Reset distance | |
0x02 | Training | |
0x03 | Paused ("Start cycling") | |
0x04 | PC control | |
3-7 | 0x00 | Padding |
Keep requesting the new mode until confirmation is received with page 0xad (0x01). Need to switch to mode 0x04 when connecting, optionally clear the distance counter with 0x01, then switch to 0x03 (can maybe be omitted?), then start with 0x02. During training, if state 0x03 is received, request 0x02 to continue.
Page 0xad (0x01) Serial number/mode (Bushido)
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x01 | Sub page |
2 | UInt8 | Mode |
0x00 | Stand-alone | |
0x01 | Reset distance | |
0x02 | Training | |
0x03 | Paused ("Start cycling") | |
0x04 | PC control | |
3 | UInt8 | Production year |
4-7 | Int32 | Device number |
The serial number is of the form XX-YY-ZZZZZ where
XX = Device type (Bushido head unit: 82)
YY = Production year
ZZZZZ = Device number
Page 0xad (0x01) Serial number (Vortex)
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x01 | Sub page |
2 | UInt8 | Mode |
0x00 | Stand-alone | |
0x01 | Reset distance | |
0x02 | Training | |
0x03 | Paused ("Start cycling") | |
0x04 | PC control | |
3 | UInt8 | Production year |
4 | UInt8 | Device type |
5-7 | UInt32 | Device number |
(MSB=0x00) |
XX = Device type
YY = Production year
ZZZZZ = Device number
Page 0xad (0x11) Brake serial number (Bushido)
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x11 | Sub page |
2 | ? | ? |
3 | UInt8 | Production year |
4-7 | Int32 | Device number |
The serial number is of the form XX-YY-ZZZZZ where
XX = Device type (Bushido brake: 81)
YY = Production year
ZZZZZ = Device number
Page 0xad (0x11) Brake serial number (Vortex)
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x11 | Sub page |
2 | ? | ? |
3 | UInt8 | Production year |
4 | UInt8 | Device type (?) |
5-7 | UInt32 | Device number |
(MSB=0x00) |
The serial number is of the form XX-YY-ZZZZZ where
XX = Device type
YY = Production year
ZZZZZ = Device number
Page 0xad (0x12) Brake version (Bushido/Vortex)
Bytes | Values | Interpretation |
---|---|---|
0 | 0xad | Page |
1 | 0x12 | Sub page |
2 | UInt8 | Major version |
3 | UInt8 | Minor version |
4-5 | UInt16 | Build number |
6-7 | ? | ? |
ANT channel configuration (PC)
Parameter | Value |
---|---|
Channel type | Slave (0x00) |
Network key | Public network |
RF frequency | channel 60 (2460 MHz) |
Transmission type | 0 (for pairing) |
Device type | 81 (0x51) |
Device number | 0 (for pairing) |
Channel period | 4096 (8 Hz) |
Page 0x01 - Force/Power
Bytes | Value | Interpretation |
---|---|---|
0 | 0x01 | Page |
1-2 | ? | ? |
3-4 | UInt16 | Power (W) |
5-6 | ? | ? |
7 | 0x00 | Padding |
Page 0x02 - Speed/Cadence/Balance
Bytes | Value | Interpretation |
---|---|---|
0 | 0x02 | Page |
1-2 | UInt16 | Wheel speed (0.1 km/h) |
3 | UInt8 | Cadence (rpm) |
4 | UInt8 | L/R Balance (%) |
5-7 | 0x00 | Padding |
Page 0x04 - Motor Voltage/Current
Bytes | Value | Interpretation |
---|---|---|
0 | 0x04 | Page |
1-7 | ? | ? |
Page 0x08 - Distance
Bytes | Value | Interpretation |
---|---|---|
0 | 0x08 | Page |
1-4 | UInt32 | Distance (m) |
3-7 | 0x00 | Padding |
Page 0x10 - Alarm
Bytes | Value | Interpretation |
---|---|---|
0 | 0x10 | Page |
1-2 | UInt16 | Alarm status (bit mask) |
3 | UInt8 | Brake temperture (?) |
4-7 | 0x00 | Padding |
Alarm status
Bitmask | Interpretation | Severity | Message |
---|---|---|---|
0x0001 | Temperature level 1 | ||
0x0002 | Temperature level 2 | ||
0x0003 | Temperature level 3 | Warning | Temperature too Hot! Slow Down! |
0x0004 | Temperature level 4 | Warning | Temperature too Hot! Brake Limited! |
0x0005 | Temperature level 5 | Error | Temperature too Hot! Stop! |
0x0008 | Overvoltage | Error | Overvoltage! Stop! |
0x0010 | Overcurrent level 1 | Warning | Overcurrent! Brake Limited! |
0x0020 | Overcurrent level 2 | Error | Overcurrent! Stop! |
0x0080 | Speed too high | Warning | Speed is too high. |
0x0100 | Undervoltage | Warning | Undervoltage! Speed Up! |
Page 0x22 - Calibration data
Bytes | Value | Interpretation |
---|---|---|
0 | 0x22 | Page |
1-2 | ? | ? |
3 | UInt8 | Calibration status |
0x00 | Off | |
0x01 | Start Cycling | |
0x02 | Speed up (to 40 km/h) | |
0x03 | Stop Cycling | |
0x04 | Wait for spin down | |
0x05 | Spin down | |
0x06 | Processing | |
0x0a | Show data | |
0x0b | End calibration | |
0x0c | Finished | |
0x0d | Error | |
0x42 | Calibration successful | |
0x4d | Request calibration value | |
4-5 | UInt16 | Rolling resistance (0.1N?) |
(HU value × 10) | ||
(for status 0x42 only) | ||
0x0000 | (otherwise) | |
6-7 | 0x00 | Padding |
"green" range: 130-190 |
Page 0x01 - Target force
Bytes | Value | Interpretation |
---|---|---|
0 | 0x01 | Page |
1-2 | UInt16 | Force (0.1N) |
3-7 | 0x00 | Padding |
Page 0x23 - Calibration mode
Bytes | Value | Interpretation |
---|---|---|
0 | 0x23 | Page |
1 | UInt8 | Command |
0x4d | Start calibration | |
0x58 | Request calibration result | |
0x63 | Request rolling resistance | |
2-7 | 0x00 | Padding |
ANT channel configuration (PC)
Parameter | Value |
---|---|
Channel type | Slave (0x00) |
Network key | Public network |
RF frequency | channel 66 (2466 MHz) |
Transmission type | 0 (for pairing) |
Device type | 61 (0x3d) |
Device number | 0 (for pairing) |
Channel period | 8192 (4 Hz) |
Page 0x00 - Power/Speed/Cadence
Bytes | Value | Interpretation |
---|---|---|
0 | 0x00 | Page |
1 (bit 7) | bool | Virtual speed |
1 (bit 5-6) | UInt8 | Calibration status |
1 (bits 0:2)-2 | UInt16 | Power (W) |
3 (bits 1:2)-4 | UInt16 | Speed (0.1 km/h) |
5-6 | ? | ? |
7 | UInt8 | Cadence |
Calibration status
Value | Interpretation |
---|---|
0x0 | None |
0x1 | Running |
0x2 | New |
0x3 | Failed |
Page 0x01 - Serial number/Alarm
Bytes | Value | Interpretation |
---|---|---|
0 | 0x01 | Page |
1 | UInt8 | Device type |
2 | UInt8 | Production year |
3-5 | UInt32 | Device number (MSB=0) |
6-7 | UInt16 | Alarm status (bit mask) |
The serial number is of the form XX-YY-ZZZZZ where
XX = Device type
YY = Production year
ZZZZZ = Device number
Alarm status
Bitmask | Interpretation | Severity | Message |
---|---|---|---|
0x0001 | Wrong mains voltage | Error | Problems with mains voltage Brake Limited! |
0x0002 | Temperature high | Warning | Temperature too Hot! Slow Down! |
0x0004 | No brake coils | Error | Brake coils not connected with electric circuits. Stop! |
Page 0x02 - Version
Bytes | Value | Interpretation |
---|---|---|
0 | 0x02 | Page |
1-2 | UInt16 | Total distance (0.1 km) |
4 | UInt8 | Major version |
5 | UInt8 | Minor version |
6-7 | UInt16 | Build number |
Page 0x03 - Calibration
Bytes | Value | Interpretation |
---|---|---|
0 | 0x03 | Page |
1-4 | 0xffffffff | Reserved |
5 | Int8 | Calibration value |
(HU value × 10) | ||
6-7 | UInt16 | device number of paired HU |
Page 0x10/0x55 - Coupling
Bytes | Value | Interpretation |
---|---|---|
0 | 0x10 | Page |
1-2 | UInt16 | HU device number |
3 | 0x55 | Command |
4 | 0x7F | ? |
5-7 | 0x00 | Padding |
Page 0x10/0xaa - Target power/calibration
Bytes | Value | Interpretation |
---|---|---|
0 | 0x10 | Page |
1-2 | UInt16 | device number of paired HU |
3 | 0xaa | Command |
4 | UInt8 | Calibration request |
5 | Int8 | Calibration value |
6-7 | UInt16 | Target power (W) |
The Genius head unit is an optional handlebar controller with five buttons and analog heart rate receiver (non-coded 5.3kHz).
ANT channel configuration (PC)
Parameter | Value |
---|---|
Channel type | Slave (0x00) |
Network key | Public network |
RF frequency | channel 60 (2460 MHz) |
Transmission type | 0 (for pairing) |
Device type | 85 (0x55) |
Device number | 0 (for pairing) |
Channel period | 4096 (8 Hz) |
Page 0x00 - Button/HR data (head unit -> PC)
Bytes | Value | Interpretation |
---|---|---|
0 | 0x00 | Page |
1-2 | UInt16 | Key code (bitmask) |
3 | UInt8 | Heart rate (bpm) |
4-7 | 0x00 | Padding |
Key codes
Bitmask | Interpretation |
---|---|
0x0000 | None |
0x0001 | Left |
0x0002 | Up |
0x0004 | Right |
0x0008 | Down |
0x0010 | OK |
Page 0x01 - Keep alive (PC -> head unit)
Regularly send to keep the head unit from turning off (every ~10s).
Bytes | Value | Interpretation |
---|---|---|
0 | 0x01 | Page |
1-7 | 0x00 | Padding |
Page 0x02 - Request data (?) (PC -> head unit)
Sent continuously by TTS, but doesn't seem necessary normally. Maybe only if heart rate is used. Changes the blinking pattern of the LEDs.
Bytes | Value | Interpretation |
---|---|---|
0 | 0x02 | Page |
1-7 | 0x00 | Padding |
ANT channel configuration (PC)
Parameter | Value |
---|---|
Channel type | Slave (0x00) |
Network key | Public network |
RF frequency | channel 60 (2460 MHz) |
Transmission type | 0 (for pairing) |
Device type | 84 (0x54) |
Device number | 0 (for pairing) |
Channel period | 2048 (16 Hz) |
The Blacktrack continuously sends page 0x00 with the current steering angle.
Page 0x00 - Steering data (Blacktrack -> PC)
Bytes | Value | Interpretation |
---|---|---|
0 | 0x00 | Page |
1-2 | Int16 | Steering angle |
3 | 0xff | ? |
4-7 | 0x00 | Padding |
Three point calibration (full left, full right and center) of the steering angle is required.
Page 0x01 - Keep alive (PC -> Blacktrack)
Regularly send to keep the steering unit from turning off (every ~10s).
Bytes | Value | Interpretation |
---|---|---|
0 | 0x01 | Page |
1-7 | 0x00 | Padding |
This work is licensed under a Creative Commons Attribution 4.0 International License.
- https://github.com/totalreverse/ttyT1941/wiki#Protocol-of-older-wireless-ant-tacx-trainers
- https://github.com/fluxoid-org/CyclismoProject/wiki/Tacx-Bushido-Headunit-protocol
- WouterJD/FortiusANT#101
- https://github.com/rjon65/FortiusANT/blob/bushido/pythoncode/BushidoBridge.py
- https://gist.github.com/m472/172bcc563bd822fc85526de25371097c
- https://fccid.io/2AAAZ021/
Hi, just wondering if you have any more detail on the request pages - I can’t seem to get a battery status page out of the Bushido head unit - have you been able to do this?