Reputation: 11
I am looking at the FTMS (Bluetooth) spec and can't figure out how to get the range of supported values in the Set Indoor Bike Simulation Parameters Procedure (section 4.16.2.18).
Basic use case would be displaying the message: 'Your Trainer supports simulation of grades up to 20%.'
A Smart Bike Trainer would support the setting of Power Target, Resistance Level and Indoor Bike Simulation Parameters, under 0x2AD9 Fitness Machine Control Point. The first 2 have dedicated charactersitics under 0x1826 Fitness Machine Service:
from which you can read the minimum, maximum value, and increment unit supported by the particular hardware device.
Bike Trainers also support different levels of grade simulation, which is also a big marketing differentiator. It can be up to 5%, 10%, 20%, and more or anything in between.
EDIT: For this case specifically Ifor 's comment has been most helpful. Indeed those values are speed dependent.
When I am setting this value with the Set Indoor Bike Simulation Parameters which is defined in section 4.16.2.18., I would like know what is the maximum value supported by the Bike Trainer. Is there a standard way to figure that out as there is for Power Target and Resistance Level setting? And while we are on it what about the other 3 params: wind speed, rolling resistance and wind resistance coefficient?
I am asking about this part of the FTMS spec document: FTMS section 4.16.2.18
EDIT: My main worry is how the trainer reacts when you write a value above the maximum. For Resistance Target it overflows and goes into very undesirable behavior. For Power Target it just ignores the value and stays at the maximum. I want to be sure that the trainer won't suddenly set the grade, or other simulation params to 0 when I write a value too high as it does with Resistance Target.
Also do you write negative values for trainers like the Tacx Neo that claim to support Descent simulation?
Here is nRF Connect Log from a session with a typical Smart Bike Trainer:
nRF Connect, 2020-12-01
Tacx Flux 46731 (FA:03:E3:1B:FE:4C)
I 19:11:25.482 [Server] Server started
V 19:11:25.507 Device Information (0x180A)
- Firmware Revision String [R] (0x2A26)
- Manufacturer Name String [R] (0x2A29)
- Model Number String [R] (0x2A24)
Unknown Service (669aa605-0c08-969e-e211-86ad5062675f)
- Unknown Characteristic [W] (669aab01-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
- Unknown Characteristic [N] (669aab02-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
Client Characteristic Configuration (0x2902)
- Unknown Characteristic [W WNR] (669aab21-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
- Unknown Characteristic [N] (669aab22-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
Client Characteristic Configuration (0x2902)
Unknown Service (669aa501-0c08-969e-e211-86ad5062675f)
- Unknown Characteristic [R W] (669aac01-0c08-969e-e211-86ad5062675f)
Characteristic Presentation Format (0x2904)
Cycling Power (0x1818)
- Cycling Power Measurement [N] (0x2A63)
Client Characteristic Configuration (0x2902)
- Cycling Power Feature [R] (0x2A65)
- Sensor Location [R] (0x2A5D)
- Cycling Power Control Point [I W] (0x2A66)
Client Characteristic Configuration (0x2902)
Fitness Machine (0x1826)
- Indoor Bike Data [N] (0x2AD2)
Client Characteristic Configuration (0x2902)
- Fitness Machine Feature [R] (0x2ACC)
- Supported Resistance Level Range [R] (0x2AD6)
- Supported Power Range [R] (0x2AD8)
- Fitness Machine Status [N] (0x2ADA)
Client Characteristic Configuration (0x2902)
- Fitness Machine Control Point [I W] (0x2AD9)
Client Characteristic Configuration (0x2902)
Unknown Service (6e40fec1-b5a3-f393-e0a9-e50e24dcca9e)
- Unknown Characteristic [N] (6e40fec2-b5a3-f393-e0a9-e50e24dcca9e)
Client Characteristic Configuration (0x2902)
- Unknown Characteristic [W WNR] (6e40fec3-b5a3-f393-e0a9-e50e24dcca9e)
V 19:11:25.818 Connecting to FA:03:E3:1B:FE:4C...
D 19:11:25.818 gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M)
D 19:11:26.494 [Server callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I 19:11:26.494 [Server] Device with address FA:03:E3:1B:FE:4C connected
D 19:11:26.547 [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED
D 19:11:26.586 [Callback] Connection state changed with status: 0 and new state: CONNECTED (2)
I 19:11:26.586 Connected to FA:03:E3:1B:FE:4C
V 19:11:26.663 Discovering services...
D 19:11:26.664 gatt.discoverServices()
I 19:11:26.732 Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms)
D 19:11:27.617 [Callback] Services discovered with status: 0
I 19:11:27.617 Services discovered
V 19:11:27.671 Generic Access (0x1800)
- Device Name [R] (0x2A00)
- Appearance [R] (0x2A01)
- Peripheral Preferred Connection Parameters [R] (0x2A04)
Generic Attribute (0x1801)
- Service Changed [I] (0x2A05)
Client Characteristic Configuration (0x2902)
Device Information (0x180A)
- Firmware Revision String [R] (0x2A26)
- Manufacturer Name String [R] (0x2A29)
- Model Number String [R] (0x2A24)
Unknown Service (669aa605-0c08-969e-e211-86ad5062675f)
- Unknown Characteristic [W] (669aab01-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
- Unknown Characteristic [N] (669aab02-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
Client Characteristic Configuration (0x2902)
- Unknown Characteristic [W WNR] (669aab21-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
- Unknown Characteristic [N] (669aab22-0c08-969e-e211-86ad5062675f)
Characteristic User Description (0x2901)
Client Characteristic Configuration (0x2902)
Unknown Service (669aa501-0c08-969e-e211-86ad5062675f)
- Unknown Characteristic [R W] (669aac01-0c08-969e-e211-86ad5062675f)
Characteristic Presentation Format (0x2904)
Cycling Power (0x1818)
- Cycling Power Measurement [N] (0x2A63)
Client Characteristic Configuration (0x2902)
- Cycling Power Feature [R] (0x2A65)
- Sensor Location [R] (0x2A5D)
- Cycling Power Control Point [I W] (0x2A66)
Client Characteristic Configuration (0x2902)
Fitness Machine (0x1826)
- Indoor Bike Data [N] (0x2AD2)
Client Characteristic Configuration (0x2902)
- Fitness Machine Feature [R] (0x2ACC)
- Supported Resistance Level Range [R] (0x2AD6)
- Supported Power Range [R] (0x2AD8)
- Fitness Machine Status [N] (0x2ADA)
Client Characteristic Configuration (0x2902)
- Fitness Machine Control Point [I W] (0x2AD9)
Client Characteristic Configuration (0x2902)
Unknown Service (6e40fec1-b5a3-f393-e0a9-e50e24dcca9e)
- Unknown Characteristic [N] (6e40fec2-b5a3-f393-e0a9-e50e24dcca9e)
Client Characteristic Configuration (0x2902)
- Unknown Characteristic [W WNR] (6e40fec3-b5a3-f393-e0a9-e50e24dcca9e)
D 19:11:27.671 gatt.setCharacteristicNotification(00002a05-0000-1000-8000-00805f9b34fb, true)
D 19:11:27.673 gatt.setCharacteristicNotification(669aab02-0c08-969e-e211-86ad5062675f, true)
D 19:11:27.675 gatt.setCharacteristicNotification(669aab22-0c08-969e-e211-86ad5062675f, true)
D 19:11:27.676 gatt.setCharacteristicNotification(00002a63-0000-1000-8000-00805f9b34fb, true)
D 19:11:27.677 gatt.setCharacteristicNotification(00002a66-0000-1000-8000-00805f9b34fb, true)
D 19:11:27.679 gatt.setCharacteristicNotification(00002ad2-0000-1000-8000-00805f9b34fb, true)
D 19:11:27.679 gatt.setCharacteristicNotification(00002ada-0000-1000-8000-00805f9b34fb, true)
D 19:11:27.680 gatt.setCharacteristicNotification(00002ad9-0000-1000-8000-00805f9b34fb, true)
D 19:11:27.681 gatt.setCharacteristicNotification(6e40fec2-b5a3-f393-e0a9-e50e24dcca9e, true)
I 19:11:27.756 Connection parameters updated (interval: 140.0ms, latency: 0, timeout: 4000ms)
V 19:11:43.635 Reading characteristic 00002acc-0000-1000-8000-00805f9b34fb
D 19:11:43.635 gatt.readCharacteristic(00002acc-0000-1000-8000-00805f9b34fb)
I 19:11:43.860 Read Response received from 00002acc-0000-1000-8000-00805f9b34fb, value: (0x) 82-40-00-00-0C-A0-00-00
A 19:11:43.860 "Fitness Machine Features:
Cadence Supported
Resistance Level Supported
Power Measurement Supported
Target Setting Features:
Resistance Target Setting Supported
Power Target Setting Supported
Indoor Bike Simulation Parameters Supported
Spin Down Control Supported" received
V 19:11:47.599 Reading characteristic 00002ad6-0000-1000-8000-00805f9b34fb
D 19:11:47.599 gatt.readCharacteristic(00002ad6-0000-1000-8000-00805f9b34fb)
I 19:11:47.777 Read Response received from 00002ad6-0000-1000-8000-00805f9b34fb, value: (0x) 00-00-E8-03-01-00
A 19:11:47.777 "Minimum Resistance Level: 0.0
Maximum Resistance Level: 100.0
Minimum Increment: 0.1" received
V 19:11:49.567 Reading characteristic 00002ad8-0000-1000-8000-00805f9b34fb
D 19:11:49.567 gatt.readCharacteristic(00002ad8-0000-1000-8000-00805f9b34fb)
I 19:11:49.735 Read Response received from 00002ad8-0000-1000-8000-00805f9b34fb, value: (0x) 00-00-20-03-01-00
A 19:11:49.735 "Minimum Power: 0 W
Maximum Power: 800 W
Minimum Increment: 1 W" received
V 19:11:53.235 Reading descriptor 00002902-0000-1000-8000-00805f9b34fb
D 19:11:53.235 gatt.readDescriptor(00002902-0000-1000-8000-00805f9b34fb)
I 19:11:53.517 Read Response received from descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 00-00
A 19:11:53.517 "Notifications and indications disabled" received
V 19:11:56.203 Enabling notifications for 00002ada-0000-1000-8000-00805f9b34fb
D 19:11:56.203 gatt.setCharacteristicNotification(00002ada-0000-1000-8000-00805f9b34fb, true)
D 19:11:56.204 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I 19:11:56.457 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A 19:11:56.457 "Notifications enabled" sent
V 19:11:56.466 Notifications enabled for 00002ada-0000-1000-8000-00805f9b34fb
V 19:12:21.266 Reading characteristic 00002a65-0000-1000-8000-00805f9b34fb
D 19:12:21.266 gatt.readCharacteristic(00002a65-0000-1000-8000-00805f9b34fb)
I 19:12:21.516 Read Response received from 00002a65-0000-1000-8000-00805f9b34fb, value: (0x) 0C-00-00-00
A 19:12:21.516 "(0x) 0C-00-00-00" received
V 19:12:24.300 Reading characteristic 00002a5d-0000-1000-8000-00805f9b34fb
D 19:12:24.300 gatt.readCharacteristic(00002a5d-0000-1000-8000-00805f9b34fb)
I 19:12:24.455 Read Response received from 00002a5d-0000-1000-8000-00805f9b34fb, value: (0x) 0C
A 19:12:24.455 "Rear Wheel" received
V 19:12:29.553 Reading descriptor 00002902-0000-1000-8000-00805f9b34fb
D 19:12:29.553 gatt.readDescriptor(00002902-0000-1000-8000-00805f9b34fb)
I 19:12:29.775 Read Response received from descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 00-00
A 19:12:29.775 "Notifications and indications disabled" received
V 19:12:32.623 Enabling indications for 00002a66-0000-1000-8000-00805f9b34fb
D 19:12:32.623 gatt.setCharacteristicNotification(00002a66-0000-1000-8000-00805f9b34fb, true)
D 19:12:32.624 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0200)
I 19:12:32.856 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 02-00
A 19:12:32.856 "Indications enabled" sent
V 19:12:32.866 Indications enabled for 00002a66-0000-1000-8000-00805f9b34fb
V 19:12:40.710 Reading descriptor 00002902-0000-1000-8000-00805f9b34fb
D 19:12:40.710 gatt.readDescriptor(00002902-0000-1000-8000-00805f9b34fb)
I 19:12:40.976 Read Response received from descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 00-00
A 19:12:40.976 "Notifications and indications disabled" received
V 19:12:42.341 Enabling notifications for 00002a63-0000-1000-8000-00805f9b34fb
D 19:12:42.341 gatt.setCharacteristicNotification(00002a63-0000-1000-8000-00805f9b34fb, true)
D 19:12:42.342 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0100)
I 19:12:42.515 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 01-00
A 19:12:42.515 "Notifications enabled" sent
V 19:12:42.520 Notifications enabled for 00002a63-0000-1000-8000-00805f9b34fb
I 19:12:43.079 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-60
A 19:12:43.079 "(0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-60" received
I 19:12:44.059 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-64
A 19:12:44.059 "(0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-64" received
I 19:12:45.038 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-68
A 19:12:45.038 "(0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-68" received
I 19:12:46.019 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-6C
A 19:12:46.019 "(0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-6C" received
I 19:12:47.139 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-70
A 19:12:47.139 "(0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-70" received
I 19:12:48.118 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-74
A 19:12:48.118 "(0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-74" received
I 19:12:49.099 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-0A-00-00-00-00-00-00-00-00-00-00-78
A 19:12:49.099 "(0x) 30-00-0A-00-00-00-00-00-00-00-00-00-00-78" received
I 19:12:50.079 Notification received from 00002a63-0000-1000-8000-00805f9b34fb, value: (0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-7C
A 19:12:50.079 "(0x) 30-00-00-00-00-00-00-00-00-00-00-00-00-7C" received
V 19:12:50.310 Disabling notifications for 00002a63-0000-1000-8000-00805f9b34fb
D 19:12:50.310 gatt.setCharacteristicNotification(00002a63-0000-1000-8000-00805f9b34fb, false)
D 19:12:50.311 gatt.writeDescriptor(00002902-0000-1000-8000-00805f9b34fb, value=0x0000)
I 19:12:50.495 Data written to descr. 00002902-0000-1000-8000-00805f9b34fb, value: (0x) 00-00
A 19:12:50.495 "Notifications and indications disabled" sent
V 19:12:50.497 Notifications and indications disabled for 00002a63-0000-1000-8000-00805f9b34fb
Upvotes: 0
Views: 2271
Reputation: 11
I did an implementation of FTMS for the nRF52382 to interface Zwift. Zwift currently only uses two commands that need to be handled: SET_TARGET_POWER (in ERG mode) and SET_SIMULATION_PARAMETERS. The others I have never seen (SET_INCLINE, SET_RESISTANCE) I presume they are not actually used but only their FE-C counterparts. Also SET_SIMULATION_PARAMETERS only has changing values for grade, windspeed, cww and cr are always fixed (for me). I presume the FE-C emulations get different values. You will need to implement the FE-C formulas described in the ANT+ spec, i.e. calculate rolling resistance, wind resistance and gravitational resistance to derive the "imposed resistance" by the game into your FTMS server. (Read the spec precisely: the encodings are different between FTMS and FE-C!)
Once you have this you can then calculate which setting on your smart trainer best corresponds to the required resistance and set that. I've been working on that for the past two months and it works great so far. Zwift is remote controlling my dumb trainer through the nRF52832 that I interfaced to my hometrainer's PCB
Upvotes: 1