Berg0162 / simcline

Simulation of Changing Road Inclination for Indoor Cycling
GNU General Public License v3.0
29 stars 7 forks source link

Test Zwift Hub FTMS #7

Closed Berg0162 closed 1 year ago

Berg0162 commented 1 year ago
    Hello Jorghen,

Here is the first result with FTMSClient v022

I don't know if it's good?

Next test when I receive the dongle for the Pc

Friendship, Joel

[CFG ] SoftDevice's RAM requires: 0x20002C78 FTMS and Chars 'initialized' CPS and Chars 'initialized' CSCS and Chars 'initialized' GA and Chars 'initialized' DIS and Chars 'initialized' Start Scanning for CPS, CSC and FTMS! [BLE ] BLE_GAP_EVT_ADV_REPORT : Conn Handle = 65535 [BLE ] BLE_GAP_EVT_ADV_REPORT : Conn Handle = 65535 Found advertising Peripheral with FTMS service!, see the Raw Data packet: Timestamp MAC Address Rssi Data 000000681 F8:9C:FC:53:5E:49 -60 09-02-16-18-26-18-18-18-0A-18 [BLE ] BLE_GAP_EVT_CONNECTED : Conn Handle = 0 [GAP ] MAC = F8:9C:FC:53:5E:49, Type = 1, Resolved = 0 [GAP ] Conn Interval = 20.00 ms, Latency = 0, Supervisor Timeout = 2000 ms [BLE ] BLE_GAP_EVT_DISCONNECTED : Conn Handle = 0 [GAP ] Disconnect Reason: CONN_FAILED_TO_BE_ESTABLISHED Feather nRF52 (Central) connected to Trainer (Peripheral) device: [] MAC Address: F8:9C:FC:53:5E:49 Now checking mandatory Client Services and Characteristics! Discovering Client Cycling Power (CP) Service ... [DISC ] [SVC] Handle start = 1 bool BLEDiscovery::_discoverService(uint16_t, BLEClientService&, uint16_t): 79: verify failed, error = BLE_ERROR_INVALID_CONN_HANDLE Not Found! Disconnecting since Client Cyling Power Service is mandatory! Client Disconnected, reason = 0x3E

Restart the Feather nRF52 Client for a new run! <<< Couldn't enable notify for Client CP Measurement Characteristic. Couldn't enable indicate for Client CP Control Point Characteristic. Couldn't enable notify for Client CSC Measurement Characteristic. Couldn't enable notify for Client FTM Training Status Characteristic. FTMS (trainer) is controlled by another Client (Training App)! Client (Central) is Up and Running!

BSP Library : 1.3.0 Bootloader : s140 6.1.1 Serial No : C2BA380FAD3CBBC2

--------- SoftDevice Config --------- Max UUID128 : 10 ATTR Table Size : 4096 Service Changed : 1 Central Connect Setting

--------- BLE Settings --------- Name : ItsyBitsy nRF52840 Express Max Connections : Peripheral = 0, Central = 1 Address : E2:AA:F7:E9:06:E0 (Static) TX Power : 0 dBm Conn Intervals : min = 20.00 ms, max = 30.00 ms Conn Timeout : 2000 ms Central Paired Devices:

Originally posted by @le-joebar in https://github.com/Berg0162/simcline/issues/5#issuecomment-1342980419

Berg0162 commented 1 year ago

Dear Joel, Please lets have this thread separated from Elite Direto thread!

Are you 100% sure that the Zwift Hub is not connected to another client application (i.c. Zwift)? It looks like your Zwift Hub is advertising FTMS but is NOT exposing the FTMS Service when it is connected. That means it is controlled by another Client, since you do not have (a) BLE(dongle) that must be over ANT+. Or do you have an other setup?

--> Shut down your PC, remove the ANT+ dongle and restart the PC. --> Please set the Debug level in the Arduoino IDE to RELEASE (level 0)!! Like the instructions say:

Good luck! Jörgen.

Berg0162 commented 1 year ago

Dear Joel, Please have a look at this tool for your smartphone to help you inspecting and testing BLE devices: nRF Connect by Nordic You can perfectly inspect the Zwift Hub trainer and check for the presence of BLE services like CPS, CSC, FTMS and others. You can easily connect to the trainer and test all those different Characteristics.... and their behaviour. It should be part of your toolbox I.C.E.

I have uploaded a new version for the Client (v023) that is more robust when error states occur. It will not result in an other outcome of your previous test! Regards, Jörgen.

le-joebar commented 1 year ago

Hello Jorghen,

I redid the test with Ant+ disconnected and Bluethoot gsm switched off.

Here is the result with FTMSClient v022:

Now I think it's good !

Joel

PS : I'm waiting for the dongle, maybe tomorrow

Feather nRF52 Client/Central: CPS, CSC and FTMS ----------------- Version 02.2 ------------------ Initialise the Bluefruit nRF52 module: Client (Central) [CFG ] SoftDevice's RAM requires: 0x20002C78 FTMS and Chars 'initialized' CPS and Chars 'initialized' CSCS and Chars 'initialized' GA and Chars 'initialized' DIS and Chars 'initialized' Start Scanning for CPS, CSC and FTMS! Found advertising Peripheral with FTMS service!, see the Raw Data packet: Timestamp MAC Address Rssi Data 000016641 F8:9C:FC:53:5E:49 -68 09-02-16-18-26-18-18-18-0A-18 [BLE ] BLE_GAP_EVT_CONNECTED : Conn Handle = 0 [GAP ] MAC = F8:9C:FC:53:5E:49, Type = 1, Resolved = 0 [GAP ] Conn Interval = 20.00 ms, Latency = 0, Supervisor Timeout = 2000 ms [BLE ] BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST : Conn Handle = 0 [GAP ] ATT MTU is changed to 23 [BLE ] BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST : Conn Handle = 0 [GAP ] Data Length Request is (tx, rx) octets = (251, 251), (tx, rx) time = (2120, 2120) us [BLE ] BLE_GAP_EVT_DATA_LENGTH_UPDATE : Conn Handle = 0 [GAP ] Data Length is (tx, rx) octets = (27, 27), (tx, rx) time = (1370, 1370) us [BLE ] BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP : Conn Handle = 0 Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 Now checking mandatory Client Services and Characteristics! Discovering Client Cycling Power (CP) Service ... [DISC ] [SVC] Handle start = 1 [BLE ] BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP : Conn Handle = 0 [DISC ] [SVC] Service Count: 1 [DISC ] [SVC] Found 0x1818, Handle start = 41, end = 48

Found it! CPS Max Payload: 20 Data Length: 27 Discovering Client CP Measurement characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Found 0x2A63, handle = 43

[DISC ] [DESC] Handle start = 44, end = 48 [BLE ] BLE_GATTC_EVT_DESC_DISC_RSP : Conn Handle = 0 [DISC ] [DESC] Descriptor Count: 5 [DISC ] [DESC] Descriptor 0: uuid = 0x2902, handle = 44 [DISC ] [DESC] Descriptor 1: uuid = 0x2803, handle = 45 [DISC ] [DESC] Descriptor 2: uuid = 0x2A65, handle = 46 [DISC ] [DESC] Descriptor 3: uuid = 0x2803, handle = 47 [DISC ] [DESC] Descriptor 4: uuid = 0x2A5D, handle = 48 [DISC ] Found CCCD: handle = 44 Found it! Discovering Client CP Control Point characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Handle start = 49, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 0 [DISC ] [CHR] Gatt Status = 0x0101 Not Found! NOT Mandatory! Discovering Client CP Feature characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Found 0x2A65, handle = 46

Found it! [BLE ] BLE_GATTC_EVT_READ_RSP : Conn Handle = 0 -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] Wheel revolution data supported Crank revolution data supported Discovering Client CP Sensor Location characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Found 0x2A5D, handle = 48

Found it! -> Client Reads CP Location Sensor: Loc#: 0 Other Discovering Cycling Speed and Cadence (CSC) Service ... [DISC ] [SVC] Handle start = 1 bool BLEDiscovery::_discoverService(uint16_t, BLEClientService&, uint16_t): 79: verify failed, error = NRF_ERROR_BUSY Not Found and disconnecting! CSC Service is mandatory! [BLE ] BLE_GATTC_EVT_READ_RSP : Conn Handle = 0 [BLE ] BLE_GAP_EVT_DISCONNECTED : Conn Handle = 0 [GAP ] Disconnect Reason: LOCAL_HOST_TERMINATED_CONNECTION Client Disconnected, reason = 0x16

Restart the Feather nRF52 Client for a new run! <<< Couldn't enable notify for Client CP Measurement Characteristic. Couldn't enable indicate for Client CP Control Point Characteristic. Couldn't enable notify for Client CSC Measurement Characteristic. Couldn't enable notify for Client FTM Training Status Characteristic. FTMS (trainer) is controlled by another Client (Training App)! Client (Central) is Up and Running!

BSP Library : 1.3.0 Bootloader : s140 6.1.1 Serial No : C2BA380FAD3CBBC2

--------- SoftDevice Config --------- Max UUID128 : 10 ATTR Table Size : 4096 Service Changed : 1 Central Connect Setting

--------- BLE Settings --------- Name : ItsyBitsy nRF52840 Express Max Connections : Peripheral = 0, Central = 1 Address : E2:AA:F7:E9:06:E0 (Static) TX Power : 0 dBm Conn Intervals : min = 20.00 ms, max = 30.00 ms Conn Timeout : 2000 ms Central Paired Devices:

le-joebar commented 1 year ago

Test with FTMS_Client_v023 :

Feather nRF52 Client/Central: CPS, CSC and FTMS ----------------- Version 02.3 ------------------ Initialise the Bluefruit nRF52 module: Client (Central) [CFG ] SoftDevice's RAM requires: 0x20002C78 FTMS and Chars 'initialized' CPS and Chars 'initialized' CSCS and Chars 'initialized' GA and Chars 'initialized' DIS and Chars 'initialized' Start Scanning for CPS, CSC and FTMS! [BLE ] BLE_GAP_EVT_ADV_REPORT : Conn Handle = 65535 Found advertising Peripheral with FTMS service!, see the Raw Data packet: Timestamp MAC Address Rssi Data 000013719 F8:9C:FC:53:5E:49 -66 09-02-16-18-26-18-18-18-0A-18 [BLE ] BLE_GAP_EVT_CONNECTED : Conn Handle = 0 [GAP ] MAC = F8:9C:FC:53:5E:49, Type = 1, Resolved = 0 [GAP ] Conn Interval = 20.00 ms, Latency = 0, Supervisor Timeout = 2000 ms [BLE ] BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST : Conn Handle = 0 [GAP ] ATT MTU is changed to 23 [BLE ] BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST : Conn Handle = 0 [GAP ] Data Length Request is (tx, rx) octets = (251, 251), (tx, rx) time = (2120, 2120) us [BLE ] BLE_GAP_EVT_DATA_LENGTH_UPDATE : Conn Handle = 0 [GAP ] Data Length is (tx, rx) octets = (27, 27), (tx, rx) time = (1370, 1370) us [BLE ] BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP : Conn Handle = 0 Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 Now checking mandatory Client Services and Characteristics! Discovering Client Cycling Power (CP) Service ... [DISC ] [SVC] Handle start = 1 [BLE ] BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP : Conn Handle = 0 [DISC ] [SVC] Service Count: 1 [DISC ] [SVC] Found 0x1818, Handle start = 41, end = 48

Found it! CPS Max Payload: 20 Data Length: 27 Discovering Client CP Measurement characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Found 0x2A63, handle = 43

[DISC ] [DESC] Handle start = 44, end = 48 [BLE ] BLE_GATTC_EVT_DESC_DISC_RSP : Conn Handle = 0 [DISC ] [DESC] Descriptor Count: 5 [DISC ] [DESC] Descriptor 0: uuid = 0x2902, handle = 44 [DISC ] [DESC] Descriptor 1: uuid = 0x2803, handle = 45 [DISC ] [DESC] Descriptor 2: uuid = 0x2A65, handle = 46 [DISC ] [DESC] Descriptor 3: uuid = 0x2803, handle = 47 [DISC ] [DESC] Descriptor 4: uuid = 0x2A5D, handle = 48 [DISC ] Found CCCD: handle = 44 Found it! Discovering Client CP Control Point characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Handle start = 49, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 0 [DISC ] [CHR] Gatt Status = 0x0101 Not Found! NOT Mandatory! Discovering Client CP Feature characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Found 0x2A65, handle = 46

Found it! [BLE ] BLE_GATTC_EVT_READ_RSP : Conn Handle = 0 -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] Wheel revolution data supported Crank revolution data supported Discovering Client CP Sensor Location characteristic ... [DISC ] [CHR] Handle start = 41, end = 48 [BLE ] BLE_GATTC_EVT_CHAR_DISC_RSP : Conn Handle = 0 [DISC ] [CHR] Characteristic Count: 3 [DISC ] [CHR] Found 0x2A5D, handle = 48

Found it! -> Client Reads CP Location Sensor: Loc#: 0 Other Discovering Cycling Speed and Cadence (CSC) Service ... [DISC ] [SVC] Handle start = 1 bool BLEDiscovery::_discoverService(uint16_t, BLEClientService&, uint16_t): 79: verify failed, error = NRF_ERROR_BUSY Not Found and disconnecting! CSC Service is mandatory! [BLE ] BLE_GATTC_EVT_READ_RSP : Conn Handle = 0 [BLE ] BLE_GAP_EVT_DISCONNECTED : Conn Handle = 0 [GAP ] Disconnect Reason: LOCAL_HOST_TERMINATED_CONNECTION Client Disconnected, reason = 0x16

Restart the Feather nRF52 Client for a new run! <<< Stopped! BSP Library : 1.3.0 Bootloader : s140 6.1.1 Serial No : C2BA380FAD3CBBC2

--------- SoftDevice Config --------- Max UUID128 : 10 ATTR Table Size : 4096 Service Changed : 1 Central Connect Setting

--------- BLE Settings --------- Name : ItsyBitsy nRF52840 Express Max Connections : Peripheral = 0, Central = 1 Address : E2:AA:F7:E9:06:E0 (Static) TX Power : 0 dBm Conn Intervals : min = 20.00 ms, max = 30.00 ms Conn Timeout : 2000 ms Central Paired Devices:

Berg0162 commented 1 year ago

Dear Joel, 1) I have asked you before --> Please set the Debug level in the Arduino IDE to RELEASE (level 0) !! You did NOT do this...for a particular reason? Please realize that more elaborate debug levels cost processor capacity and might lead to BLE timing errors.... See above: Discovering the CSC service an error occurs: error = NRF_ERROR_BUSY ---> Busy? Doing what? Does this error also occur when you set Release level to zero at compile time ? 2) --------- BLE Settings --------- Name : ItsyBitsy nRF52840 Express Did you have a particular reason why you bought this board and not the Feather nRF52840 Express that the Simcline projects use? I have no experience with the ItsyBitsy at all and nobody I know ever used it in this project....so I simply do not know if there are critical differences, that lead to unexpected results during operation and/or debugging in this stage or later. 3) The results are not very different from previous runs, the client detects a trainer [Zwift Hub] that advertises with CPS, CSC and FTMS... However when connected the discover actions (in the latest runs) for a mandatory service or characteristic fail at CSC. That is different from the first runs! The first runs failed when FTM was NOT detected! Does your Zwift hub not expose CSC? Is that typical for this type? Are there different types of Zwift Hubs with different specs.? 4) Please use nRF Connect to scan your Zwift hub when it is powered --> advertising -> connect -> detail the different services and characteristics that the hub is exposing... In previous issues (see Elite Direto) you can see how people made screen shots of screens of the nRF Connect tool and how instructive these images are! 5) What other devices (Treadmill(s), trainers, smartphone(s) et cetera) with BLE and/or ANT+ are present in the room that can disturb a smooth connection process. Best wishes, Jörgen.

Berg0162 commented 1 year ago

Dear Joel, After a night sleep.... I have made some changes in the Client software and uploaded version v024. 1) No longer is CSC a MANDATORY service, it is very well possible that Zwift Hub does not has it implemented... sofar we do not know! May be "nRF Connect" is giving soon better insight in what services are exposed exactly! 2) I have changed the order of the connect sequence (discover a service or characteristic). The sequence now starts with more general services that all BLE devices (must) have, only thereafter we check for FTMS... That is mandatory so if it fails -> end of exercise! If all goes well CPS (Mandatory) and CSC (Not Mandatory) are checked... I hope this will give more decisive information! Good luck, Jörgen.

le-joebar commented 1 year ago

Dear Jörghen,

I ordered today Adafruit Feather nRF52840 Express image but there are many sites out of stock! that's why I ordered the ItsyBitsy nRF52840 Express

Here is the first result with version V024. At first I turn on the trainer and watch the results. Here they are :

FTMS and Chars 'initialized' CPS and Chars 'initialized' CSCS and Chars 'initialized' GA and Chars 'initialized' DIS and Chars 'initialized' Start Scanning for CPS, CSC and FTMS! Found advertising Peripheral with FTMS service!, see the Raw Data packet: Timestamp MAC Address Rssi Data 000016166 F8:9C:FC:53:5E:49 -64 09-02-16-18-26-18-18-18-0A-18 Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 Now checking all Client Services and Characteristics! If Mandatory Services Fail --> the Client will disconnect! First checking Generic Access and Device Information Services and Characteristics! Found Client Generic Access -> Client Reads Device Name: [Zwift Hub] -> Client Reads Appearance: [0] Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! Disconnecting since Client FTM Service is mandatory! Client Disconnected, reason = 0x16

Restart the Feather nRF52 Client for a new run! <<< Stopped!

And here is the second if just after turning on I pedal to wake up the services.

This is the second result if i'm turn

Feather nRF52 Client/Central: CPS, CSC and FTMS ----------------- Version 02.4 ------------------ Initialise the Bluefruit nRF52 module: Client (Central) FTMS and Chars 'initialized' CPS and Chars 'initialized' CSCS and Chars 'initialized' GA and Chars 'initialized' DIS and Chars 'initialized' Start Scanning for CPS, CSC and FTMS! Found advertising Peripheral with FTMS service!, see the Raw Data packet: Timestamp MAC Address Rssi Data 000001764 F8:9C:FC:53:5E:49 -70 09-02-16-18-26-18-18-18-0A-18 Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 Now checking all Client Services and Characteristics! If Mandatory Services Fail --> the Client will disconnect! First checking Generic Access and Device Information Services and Characteristics! Found Client Generic Access -> Client Reads Device Name: [Zwift Hub] -> Client Reads Appearance: [1152] Found Client Device Information -> Client Reads Manufacturer: [Zwift] -> Client Reads Model Number: [06] -> Client Reads Serial Number: [06-F89CFC535E49] Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 Discovering Client FTM Feature Characteristic ... Found it! -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] Discovering Client FTM Training Status Characteristic ... Not Found! Disconnecting since Client FTM Characteristic is mandatory! Client Disconnected, reason = 0x16

Restart the Feather nRF52 Client for a new run! <<< Stopped!

Here with the V23:

Feather nRF52 Client/Central: CPS, CSC and FTMS ----------------- Version 02.3 ------------------ Initialise the Bluefruit nRF52 module: Client (Central) FTMS and Chars 'initialized' CPS and Chars 'initialized' CSCS and Chars 'initialized' GA and Chars 'initialized' DIS and Chars 'initialized' Start Scanning for CPS, CSC and FTMS! Found advertising Peripheral with FTMS service!, see the Raw Data packet: Timestamp MAC Address Rssi Data 000001160 F8:9C:FC:53:5E:49 -69 09-02-16-18-26-18-18-18-0A-18 Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 Now checking mandatory Client Services and Characteristics! Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 Discovering Client CP Measurement characteristic ... Found it! Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! Discovering Client CP Feature characteristic ... Found it! -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] Wheel revolution data supported Crank revolution data supported Discovering Client CP Sensor Location characteristic ... Found it! -> Client Reads CP Location Sensor: Loc#: 0 Other Discovering Cycling Speed and Cadence (CSC) Service ... Not Found and disconnecting! CSC Service is mandatory! Client Disconnected, reason = 0x16

Restart the Feather nRF52 Client for a new run! <<< Stopped!

Here are the screenshots with nrf connect:

Screenshot_20221210-132431_nRF Connect Screenshot_20221210-132214_nRF Connect Screenshot_20221210-132222_nRF Connect Screenshot_20221210-132412_nRF Connect

Sincerely,

Joel

le-joebar commented 1 year ago

I don't know if this can't help you? : Conect nrf debug mode log

nRF Connect, 2022-12-10 Zwift Hub (F8:9C:FC:53:5E:49) V 16:01:11.439 Connecting to F8:9C:FC:53:5E:49... D 16:01:11.439 gatt = device.connectGatt(autoConnect = false, TRANSPORT_LE, preferred PHY = LE 1M) D 16:01:11.697 [Callback] Connection state changed with status: 0 and new state: CONNECTED (2) I 16:01:11.697 Connected to F8:9C:FC:53:5E:49 V 16:01:11.702 Discovering services... D 16:01:11.702 gatt.discoverServices() D 16:01:11.728 [Broadcast] Action received: android.bluetooth.device.action.ACL_CONNECTED I 16:01:12.541 Connection parameters updated (interval: 7.5ms, latency: 0, timeout: 5000ms) D 16:01:15.576 [Callback] Services discovered with status: 0 I 16:01:15.577 Services discovered V 16:01:15.615 Generic Access (0x1800)

le-joebar commented 1 year ago

I found this program: https://github.com/arduino-libraries/ArduinoBLE/blob/master/examples/Central/PeripheralExplorer/PeripheralExplorer.ino

for ESP32 BLE of which I did the test and here is the result of the services :

ets Jun 8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0030,len:1344 load:0x40078000,len:13864 load:0x40080400,len:3608 entry 0x400805f0 Bluetooth�� Low Energy Central - Peripheral Explorer Found 64:6c:58:a5:76:71 '' fe9f Found 60:1e:b5:71:b8:93 '' fe9f Found f8:9c:fc:53:5e:49 'Zwift Hub' 1816 Connecting ... Connected Discovering attributes ... Attributes discovered

Device name: Zwift Hub Appearance: 0x0

Service 1800 Characteristic 2a00, properties 0xA, value 0x5A7769667420487562 Descriptor 2803, value 0x020500012A Descriptor 2a01, value 0x8004 Characteristic 2a01, properties 0x2, value 0x8004 Descriptor 2803, value 0x020700042A Descriptor 2a04, value 0x4800780000009001 Characteristic 2a04, properties 0x2, value 0x4800780000009001 Descriptor 2803, value 0x020900A62A Descriptor 2aa6, value 0x01 Characteristic 2aa6, properties 0x2, value 0x01 Service 1801 Characteristic 2a05, properties 0x20 Descriptor 2902, value 0x0000 Service 1826 Characteristic 2ad2, properties 0x10 Descriptor 2902, value 0x0000 Descriptor 2803, value 0x021300CC2A Descriptor 2acc, value 0x874400000CE00000 Characteristic 2acc, properties 0x2, value 0x874400000CE00000 Descriptor 2803, value 0x021500D62A Descriptor 2ad6, value 0x000064000100 Characteristic 2ad6, properties 0x2, value 0x000064000100 Descriptor 2803, value 0x021700D82A Descriptor 2ad8, value 0x0000E8030100 Characteristic 2ad8, properties 0x2, value 0x0000E8030100 Descriptor 2803, value 0x101900DA2A Descriptor 2ada, value 0x Characteristic 2ada, properties 0x10 Descriptor 2902, value 0x0000 Descriptor 2803, value 0x281C00D92A Descriptor 2ad9, value 0x Characteristic 2ad9, properties 0x28 Descriptor 2902, value 0x0000 Service 1816 Characteristic 2a5b, properties 0x10 Descriptor 2902, value 0x0000 Descriptor 2803, value 0x0223005C2A Descriptor 2a5c, value 0x0300 Characteristic 2a5c, properties 0x2, value 0x0300 Descriptor 2803, value 0x0225005D2A Descriptor 2a5d, value 0x0C Characteristic 2a5d, properties 0x2, value 0x0C Descriptor 2803, value 0x282700552A Descriptor 2a55, value 0x Characteristic 2a55, properties 0x28 Descriptor 2902, value 0x0000 Service 1818 Characteristic 2a63, properties 0x10 Descriptor 2902, value 0x0000 Descriptor 2803, value 0x022E00652A Descriptor 2a65, value 0x0C000000 Characteristic 2a65, properties 0x2, value 0x0C000000 Descriptor 2803, value 0x0230005D2A Descriptor 2a5d, value 0x0C Characteristic 2a5d, properties 0x2, value 0x0C Service fe59 Characteristic 8ec90003-f315-4f60-9fb8-838830daea50, properties 0x28 Descriptor 2902, value 0x0000 Service 180d Characteristic 2a37, properties 0x10 Descriptor 2902, value 0x0000 Descriptor 2803, value 0x023A00382A Descriptor 2a38, value 0x01 Characteristic 2a38, properties 0x2, value 0x01 Service c4630001-003f-4cec-8994-e489b04d857f Characteristic c4632b03-003f-4cec-8994-e489b04d857f, properties 0x2, value 0xFF0F0000 Descriptor 2803, value 0x123F007F854DB089E49489EC4C3F00052B63C4 Descriptor 857f, value 0x0000000000000000000000000000000000000000 Descriptor 4cec, value 0x Descriptor 470a, value 0x Characteristic c4632b05-003f-4cec-8994-e489b04d857f, properties 0x12, value 0x0000000000000000000000000000000000000000 Descriptor 2902, value 0x0000 Descriptor 2901, value 0x537461747573 Descriptor 2803, value 0x2843007F854DB089E49489EC4C3F00042B63C4 Descriptor 857f, value 0x Descriptor 4cec, value 0x Descriptor 470a, value 0x Characteristic c4632b04-003f-4cec-8994-e489b04d857f, properties 0x28 Descriptor 2902, value 0x0000 Service 180a Characteristic 2a29, properties 0x2, value 0x5A77696674 Descriptor 2803, value 0x024900242A Descriptor 2a24, value 0x3036 Characteristic 2a24, properties 0x2, value 0x3036 Descriptor 2803, value 0x024B00252A Descriptor 2a25, value 0x30362D463839434643353335453439 Characteristic 2a25, properties 0x2, value 0x30362D463839434643353335453439 Descriptor 2803, value 0x024D00272A Descriptor 2a27, value 0x31 Characteristic 2a27, properties 0x2, value 0x31 Descriptor 2803, value 0x024F00262A Descriptor 2a26, value 0x332E39 Characteristic 2a26, properties 0x2, value 0x332E39

Disconnecting ... Disconnected

Berg0162 commented 1 year ago

Dear Joel, Only this Sunday morning I had time to look into your post..... Wow! Super! That is a wealth of information! This is more than one could have asked for, what a pity we did not start this way.... I have to study it all carefully and that will take some time!

One thing is immediately striking at my first scan:

And here is the second if just after turning on I pedal to wake up the services.

I have only met trainers that are awake all the time, may be after 20 minutes go to sleep, but never within seconds/minutes... CPS (1818), CSC (1816) and FTMS (1826) are all present, NO DOUBT! I have to check if all the Chars are exposed and if there is a discrepancy in what the Client is instructed to be Mandatory and what the Zwift Hub is programmed with !!! This explains definitely the behavior in all of the runs. I will be back soon! Thanks again, this will bring the solution! Regards, Jörgen.

Berg0162 commented 1 year ago

Let's give Client_FTMS version v025 a try! I have changed several Service Characteristics to NOT Mandatory, hopefully this is now fully in accordance with the Zwift Hub settings....! (This is quite different from FTMS trainers I have met so far, but no reason for worries!) Procedure is changed: run Feather code first and then start and wake up your trainer (we know now this is critical!)

Fingers crossed!

le-joebar commented 1 year ago

Dear jörghen,

Here are the results, You should know that the first attempt was a failure. The Zwift Hub is very temperamental to wake up. On the second I had to hurry to wake him up or else I don't know what happened. But he woke up at just the right time!

Unfortunately I didn't copy everything because the serial monitor had already been closed!!!!

I'm trying to reproduce but I can't!!!

Feather nRF52 Client/Central: CPS, CSC and FTMS ----------------- Version 02.5 ------------------ Initialise the Bluefruit nRF52 module: Client (Central) FTMS and Chars 'initialized' CPS and Chars 'initialized' CSCS and Chars 'initialized' GA and Chars 'initialized' DIS and Chars 'initialized' Start Scanning for CPS, CSC and FTMS! Found advertising Peripheral with FTMS service!, see the Raw Data packet: Timestamp MAC Address Rssi Data 000021991 F8:9C:FC:53:5E:49 -69 09-02-16-18-26-18-18-18-0A-18 Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 Now checking all Client Services and Characteristics! If Mandatory Services Fail --> the Client will disconnect! First checking Generic Access and Device Information Services and Characteristics! Found Client Generic Access -> Client Reads Device Name: [Zwift Hub] -> Client Reads Appearance: [0] Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! Disconnecting since Client FTM Service is mandatory! Client Disconnected, reason = 0x16

Restart the Feather nRF52 Client for a new run! <<< Stopped!

15:54:24.551 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 15:54:26.523 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 15:54:26.643 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:26.643 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 15:54:28.645 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 15:54:28.694 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:28.694 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 15:54:30.682 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 15:54:30.915 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:30.915 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 15:54:32.764 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 15:54:32.888 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:32.888 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 15:54:34.867 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 15:54:35.131 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:35.131 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 15:54:36.980 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 15:54:37.072 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:37.072 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 15:54:39.043 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 15:54:39.168 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:39.168 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 15:54:41.168 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 15:54:41.261 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:41.261 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 15:54:43.265 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 15:54:43.310 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:43.310 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 15:54:45.302 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 15:54:45.361 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:45.382 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 15:54:47.333 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 15:54:47.519 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:47.519 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 15:54:49.443 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 15:54:49.506 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:49.552 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 15:54:51.551 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A2 00 28 33 00 ] 15:54:51.627 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:51.627 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A2 00 28 33 ] 15:54:53.625 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 01 28 33 00 ] 15:54:53.658 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:53.658 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 01 28 33 ] 15:54:55.690 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 4F 01 28 33 00 ] 15:54:55.768 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:55.768 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4F 01 28 33 ] 15:54:57.765 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 01 28 33 00 ] 15:54:58.198 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:58.198 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 01 28 33 ] 15:54:59.858 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 57 FF 28 33 00 ] 15:54:59.915 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:54:59.915 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 FF 28 33 ] 15:55:01.902 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 08 00 00 00 00 00 00 00 ] 15:55:02.041 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 08 03 ] 15:55:04.002 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 01 00 00 00 00 00 00 00 ] 15:55:04.081 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 01 01 ] 15:55:04.129 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 15:55:06.110 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 15:55:06.186 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 15:55:08.190 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 15:55:08.236 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 15:55:10.225 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 15:55:10.537 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 15:55:10.537 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 15:55:12.340 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 15:55:12.466 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 15:55:12.511 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ]

le-joebar commented 1 year ago

Now I managed to get the full serial but I don't know how I woke up the Zwift hub.

I can't reproduce every time!!!!

16:35:25.068 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:35:25.068 -> ----------------- Version 02.5 ------------------ 16:35:25.068 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:35:25.071 -> FTMS and Chars 'initialized' 16:35:25.071 -> CPS and Chars 'initialized' 16:35:25.071 -> CSCS and Chars 'initialized' 16:35:25.071 -> GA and Chars 'initialized' 16:35:25.071 -> DIS and Chars 'initialized' 16:35:25.071 -> Start Scanning for CPS, CSC and FTMS! 16:35:25.071 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:35:25.071 -> Timestamp MAC Address Rssi Data 16:35:25.071 -> 000000717 F8:9C:FC:53:5E:49 -64 09-02-16-18-26-18-18-18-0A-18 16:35:25.071 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 16:35:25.071 -> Now checking all Client Services and Characteristics! 16:35:25.071 -> If Mandatory Services Fail --> the Client will disconnect! 16:35:25.071 -> First checking Generic Access and Device Information Services and Characteristics! 16:35:25.229 -> Found Client Generic Access 16:35:25.229 -> -> Client Reads Device Name: [Zwift Hub] 16:35:25.231 -> -> Client Reads Appearance: [1152] 16:35:25.231 -> Found Client Device Information 16:35:25.242 -> -> Client Reads Manufacturer: [Zwift] 16:35:25.242 -> -> Client Reads Model Number: [06] 16:35:25.378 -> -> Client Reads Serial Number: [06-F89CFC535E49] 16:35:25.378 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 16:35:25.425 -> Discovering Client FTM Feature Characteristic ... Found it! 16:35:25.832 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 16:35:25.832 -> Discovering Client FTM Control Point Characteristic ... Found it! 16:35:26.374 -> Discovering Client FTM Status Characteristic ... Found it! 16:35:26.374 -> Discovering Client FTM Training Status Characteristic ... Ready to receive Client FTM Control Point Response Messages 16:35:26.409 -> Ready to receive Client FTM Status values 16:35:26.409 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 16:35:26.409 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 16:35:26.409 -> >>> Couldn't enable notify for Client CP Measurement Characteristic. 16:35:26.409 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 16:35:26.409 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 16:35:26.409 -> Client (Central) is Up and Running! 16:35:26.595 -> Not Found! Not Mandatory 16:35:26.595 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 16:35:26.750 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 16:35:26.750 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 16:35:27.058 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 16:35:27.058 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 16:35:27.291 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 16:35:27.383 -> Discovering Client CP Measurement characteristic ... Found it! 16:35:27.554 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 16:35:27.816 -> Discovering Client CP Feature characteristic ... Found it! 16:35:27.987 -> -> Client Reads Raw CP Feature bytes: [4] [ 00 00 00 00 ] 16:35:27.987 -> Discovering Client CP Sensor Location characteristic ... NOT Found! NOT Mandatory! 16:35:27.987 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 16:35:28.391 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 16:35:28.513 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 16:35:30.519 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 16:35:30.597 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 16:35:32.596 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 16:35:32.673 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 16:35:32.673 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 16:35:34.658 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 16:35:34.734 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:34.769 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 16:35:36.711 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 16:35:36.789 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:36.789 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 16:35:38.772 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 16:35:39.099 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:39.099 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 16:35:40.880 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 16:35:40.958 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:40.958 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 16:35:42.973 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 16:35:43.066 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:43.066 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 16:35:45.077 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 16:35:45.154 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:45.154 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 16:35:47.144 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 16:35:47.470 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:47.470 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 16:35:49.244 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 16:35:49.415 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:49.415 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 16:35:51.357 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 16:35:51.481 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:51.481 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 16:35:53.451 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 16:35:53.523 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:53.523 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 16:35:55.537 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 16:35:55.583 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:55.583 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 16:35:57.562 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 16:35:57.700 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:57.700 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 16:35:59.685 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 16:35:59.809 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:59.809 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 16:36:01.790 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 16:36:01.931 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:36:01.931 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 16:36:03.871 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 16:36:03.948 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:36:03.949 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ]

Berg0162 commented 1 year ago

Did you feel resistance change when moving the pedals?

Op zo 11 dec. 2022 16:41 schreef le-joebar @.***>:

Now is OK !

16:35:25.068 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:35:25.068 -> ----------------- Version 02.5 ------------------ 16:35:25.068 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:35:25.071 -> FTMS and Chars 'initialized' 16:35:25.071 -> CPS and Chars 'initialized' 16:35:25.071 -> CSCS and Chars 'initialized' 16:35:25.071 -> GA and Chars 'initialized' 16:35:25.071 -> DIS and Chars 'initialized' 16:35:25.071 -> Start Scanning for CPS, CSC and FTMS! 16:35:25.071 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:35:25.071 -> Timestamp MAC Address Rssi Data 16:35:25.071 -> 000000717 F8:9C:FC:53:5E:49 -64 09-02-16-18-26-18-18-18-0A-18 16:35:25.071 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 16:35:25.071 -> Now checking all Client Services and Characteristics! 16:35:25.071 -> If Mandatory Services Fail --> the Client will disconnect! 16:35:25.071 -> First checking Generic Access and Device Information Services and Characteristics! 16:35:25.229 -> Found Client Generic Access 16:35:25.229 -> -> Client Reads Device Name: [Zwift Hub] 16:35:25.231 -> -> Client Reads Appearance: [1152] 16:35:25.231 -> Found Client Device Information 16:35:25.242 -> -> Client Reads Manufacturer: [Zwift] 16:35:25.242 -> -> Client Reads Model Number: [06] 16:35:25.378 -> -> Client Reads Serial Number: [06-F89CFC535E49] 16:35:25.378 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 16:35:25.425 -> Discovering Client FTM Feature Characteristic ... Found it! 16:35:25.832 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 16:35:25.832 -> Discovering Client FTM Control Point Characteristic ... Found it! 16:35:26.374 -> Discovering Client FTM Status Characteristic ... Found it! 16:35:26.374 -> Discovering Client FTM Training Status Characteristic ... Ready to receive Client FTM Control Point Response Messages 16:35:26.409 -> Ready to receive Client FTM Status values 16:35:26.409 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 16:35:26.409 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 16:35:26.409 -> >>> Couldn't enable notify for Client CP Measurement Characteristic. 16:35:26.409 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 16:35:26.409 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 16:35:26.409 -> Client (Central) is Up and Running! 16:35:26.595 -> Not Found! Not Mandatory 16:35:26.595 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 16:35:26.750 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 16:35:26.750 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 16:35:27.058 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 16:35:27.058 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 16:35:27.291 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 16:35:27.383 -> Discovering Client CP Measurement characteristic ... Found it! 16:35:27.554 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 16:35:27.816 -> Discovering Client CP Feature characteristic ... Found it! 16:35:27.987 -> -> Client Reads Raw CP Feature bytes: [4] [ 00 00 00 00 ] 16:35:27.987 -> Discovering Client CP Sensor Location characteristic ... NOT Found! NOT Mandatory! 16:35:27.987 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 16:35:28.391 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 16:35:28.513 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 16:35:30.519 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 16:35:30.597 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 16:35:32.596 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 16:35:32.673 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 16:35:32.673 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 16:35:34.658 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 16:35:34.734 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:34.769 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 16:35:36.711 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 16:35:36.789 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:36.789 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 16:35:38.772 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 16:35:39.099 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:39.099 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 16:35:40.880 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 16:35:40.958 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:40.958 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 16:35:42.973 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 16:35:43.066 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:43.066 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 16:35:45.077 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 16:35:45.154 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:45.154 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 16:35:47.144 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 16:35:47.470 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:47.470 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 16:35:49.244 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 16:35:49.415 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:49.415 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 16:35:51.357 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 16:35:51.481 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:51.481 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 16:35:53.451 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 16:35:53.523 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:53.523 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 16:35:55.537 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 16:35:55.583 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:55.583 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 16:35:57.562 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 16:35:57.700 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:57.700 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 16:35:59.685 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 16:35:59.809 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:35:59.809 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 16:36:01.790 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 16:36:01.931 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:36:01.931 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 16:36:03.871 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 16:36:03.948 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 16:36:03.949 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ]

— Reply to this email directly, view it on GitHub https://github.com/Berg0162/simcline/issues/7#issuecomment-1345586549, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANS5LSUED4ZI4LVDL3XRNZLWMXY23ANCNFSM6AAAAAASZDERFE . You are receiving this because you authored the thread.Message ID: @.***>

le-joebar commented 1 year ago

At the first test I turned the pedals with my hand and I would say yes, I think it was decreasing! On the second test I did not pay attention!

Berg0162 commented 1 year ago

Dear Joel, It looks like a successful run now! Feather and Trainer are connected, services/characteristics were detected or not. Focus was until now on establishing the connection, but what I am still missing is the response of the trainer to the resistance simulation parameters that the client is regularly sending...and how these data are decoded by the Feather..... This is critical information!

6) Move the trainer pedals and notice/feel changes in resistance... The Client sends Resistance Parameters to the Trainer that coincide with the first 5 minutes of the Zwift Volcano Circuit! 7) Inspect the info presented by Serial Monitor.....

This is what I miss in the output: -> Client Rec'd Raw FTM Indoor Bike Data: [##] [#####################] Have a careful look at the complete debug output file that I have uploaded and notice the comment (physical experience) at the start of the tester's output file! If you want to be sure communication is working flawless you have to do the pedaling on the bike, Zwift Hub is clearly not doing it by itself! Or it is simply NOT working.... How do we know? See Output Good luck! Jörgen.

le-joebar commented 1 year ago

Hello Jorghen,

Here are the results after several connection attempts I tried several ways to connect and wake up the services.

I have never managed to do it again 2 times in a row!!!

So I don't know how to make a successful connection!!!

But we have successful results!! And I really felt the different resistances.

20:01:34.256 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 20:01:34.256 -> ----------------- Version 02.5 ------------------ 20:01:34.256 -> Initialise the Bluefruit nRF52 module: Client (Central) 20:01:34.348 -> FTMS and Chars 'initialized' 20:01:34.348 -> CPS and Chars 'initialized' 20:01:34.348 -> CSCS and Chars 'initialized' 20:01:34.348 -> GA and Chars 'initialized' 20:01:34.348 -> DIS and Chars 'initialized' 20:01:34.348 -> Start Scanning for CPS, CSC and FTMS! 20:01:35.186 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 20:01:35.186 -> Timestamp MAC Address Rssi Data 20:01:35.186 -> 000002583 F8:9C:FC:53:5E:49 -69 09-02-16-18-26-18-18-18-0A-18 20:01:35.277 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 20:01:35.277 -> Now checking all Client Services and Characteristics! 20:01:35.277 -> If Mandatory Services Fail --> the Client will disconnect! 20:01:35.277 -> First checking Generic Access and Device Information Services and Characteristics! 20:01:35.494 -> Found Client Generic Access 20:01:35.494 -> -> Client Reads Device Name: [Zwift Hub] 20:01:35.815 -> -> Client Reads Appearance: [1152] 20:01:35.815 -> Found Client Device Information 20:01:36.219 -> -> Client Reads Manufacturer: [Zwift] 20:01:36.219 -> -> Client Reads Model Number: [06] 20:01:36.389 -> -> Client Reads Serial Number: [06-F89CFC535E49] 20:01:36.389 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 20:01:36.467 -> Discovering Client FTM Feature Characteristic ... Found it! 20:01:36.653 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 20:01:36.653 -> Discovering Client FTM Control Point Characteristic ... Not Found! 20:01:36.653 -> Disconnecting since Client FTM Control Point Characteristic is mandatory! 20:01:36.699 -> Client Disconnected, reason = 0x16 20:01:36.699 -> >>> Restart the Feather nRF52 Client for a new run! <<< 20:01:37.689 -> Stopped!

20:02:38.186 -> FTMS and Chars 'initialized' 20:02:38.186 -> CPS and Chars 'initialized' 20:02:38.186 -> CSCS and Chars 'initialized' 20:02:38.186 -> GA and Chars 'initialized' 20:02:38.186 -> DIS and Chars 'initialized' 20:02:38.186 -> Start Scanning for CPS, CSC and FTMS! 20:02:38.186 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 20:02:38.186 -> Timestamp MAC Address Rssi Data 20:02:38.186 -> 000001612 F8:9C:FC:53:5E:49 -67 09-02-16-18-26-18-18-18-0A-18 20:02:38.418 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [] MAC Address: F8:9C:FC:53:5E:49 20:02:38.418 -> Now checking all Client Services and Characteristics! 20:02:38.418 -> If Mandatory Services Fail --> the Client will disconnect! 20:02:38.418 -> First checking Generic Access and Device Information Services and Characteristics! 20:02:38.418 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 20:02:38.418 -> Disconnecting since Client FTM Service is mandatory! 20:02:38.418 -> Client Disconnected, reason = 0x3E 20:02:38.418 -> >>> Restart the Feather nRF52 Client for a new run! <<< 20:02:39.988 -> Stopped!

20:03:28.928 -> FTMS and Chars 'initialized' 20:03:28.928 -> CPS and Chars 'initialized' 20:03:28.928 -> CSCS and Chars 'initialized' 20:03:28.928 -> GA and Chars 'initialized' 20:03:28.928 -> DIS and Chars 'initialized' 20:03:28.928 -> Start Scanning for CPS, CSC and FTMS! 20:03:28.928 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 20:03:28.928 -> Timestamp MAC Address Rssi Data 20:03:28.928 -> 000001315 F8:9C:FC:53:5E:49 -67 09-02-16-18-26-18-18-18-0A-18 20:03:28.943 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [] MAC Address: F8:9C:FC:53:5E:49 20:03:28.943 -> Now checking all Client Services and Characteristics! 20:03:28.943 -> If Mandatory Services Fail --> the Client will disconnect! 20:03:28.943 -> First checking Generic Access and Device Information Services and Characteristics! 20:03:28.943 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 20:03:28.943 -> Disconnecting since Client FTM Service is mandatory! 20:03:28.943 -> Client Disconnected, reason = 0x3E 20:03:28.943 -> >>> Restart the Feather nRF52 Client for a new run! <<< 20:03:30.705 -> Stopped!

20:15:52.131 -> ----------------- Version 02.5 ------------------ 20:15:52.131 -> Initialise the Bluefruit nRF52 module: Client (Central) 20:15:52.135 -> FTMS and Chars 'initialized' 20:15:52.135 -> CPS and Chars 'initialized' 20:15:52.135 -> CSCS and Chars 'initialized' 20:15:52.135 -> GA and Chars 'initialized' 20:15:52.135 -> DIS and Chars 'initialized' 20:15:52.135 -> Start Scanning for CPS, CSC and FTMS! 20:16:41.655 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 20:16:41.655 -> Timestamp MAC Address Rssi Data 20:16:41.655 -> 000052631 F8:9C:FC:53:5E:49 -63 09-02-16-18-26-18-18-18-0A-18 20:16:41.870 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 20:16:41.870 -> Now checking all Client Services and Characteristics! 20:16:41.870 -> If Mandatory Services Fail --> the Client will disconnect! 20:16:41.870 -> First checking Generic Access and Device Information Services and Characteristics! 20:16:42.087 -> Found Client Generic Access 20:16:42.087 -> -> Client Reads Device Name: [Zwift Hub] 20:16:42.351 -> -> Client Reads Appearance: [1152] 20:16:42.351 -> Found Client Device Information 20:16:42.816 -> -> Client Reads Manufacturer: [Zwift] 20:16:42.816 -> -> Client Reads Model Number: [06] 20:16:42.986 -> -> Client Reads Serial Number: [06-F89CFC535E49] 20:16:42.987 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 20:16:43.112 -> Discovering Client FTM Feature Characteristic ... Found it! 20:16:43.249 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 20:16:43.249 -> Discovering Client FTM Control Point Characteristic ... Found it! 20:16:43.974 -> Discovering Client FTM Status Characteristic ... Found it! 20:16:43.974 -> Discovering Client FTM Training Status Characteristic ... Ready to receive Client FTM Control Point Response Messages 20:16:44.310 -> Ready to receive Client FTM Status values 20:16:44.310 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 20:16:44.310 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 20:16:44.310 -> >>> Couldn't enable notify for Client CP Measurement Characteristic. 20:16:44.310 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 20:16:44.310 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 20:16:44.310 -> Client (Central) is Up and Running! 20:16:44.346 -> Not Found! Not Mandatory 20:16:44.346 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 20:16:44.516 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 20:16:44.516 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 20:16:44.870 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 20:16:44.870 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 20:16:45.056 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 20:16:45.149 -> Discovering Client CP Measurement characteristic ... Found it! 20:16:45.334 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 20:16:45.569 -> Discovering Client CP Feature characteristic ... Found it! 20:16:45.752 -> -> Client Reads Raw CP Feature bytes: [4] [ 00 00 00 00 ] 20:16:45.752 -> Discovering Client CP Sensor Location characteristic ... NOT Found! NOT Mandatory! 20:16:45.752 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 20:16:46.309 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:16:46.401 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:16:48.356 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:16:48.450 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:16:50.443 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 20:16:50.475 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 20:16:50.475 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 20:16:52.514 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 20:16:52.546 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:16:52.546 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 20:16:54.573 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 20:16:54.757 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:16:54.803 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 20:16:56.652 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:16:56.839 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:16:56.839 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:16:58.772 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 20:16:58.943 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:16:58.943 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 20:17:00.869 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 20:17:00.961 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:00.961 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 20:17:02.957 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 20:17:03.052 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:03.052 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 20:17:05.040 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 20:17:05.072 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:05.072 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 20:17:07.112 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 20:17:07.342 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:07.342 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 20:17:09.211 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 20:17:09.289 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:09.289 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 20:17:11.266 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:17:11.360 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:11.360 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:17:13.362 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 20:17:13.473 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:13.473 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 20:17:15.452 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 20:17:15.545 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:15.545 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 20:17:17.539 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 20:17:17.571 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:17.571 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 20:17:19.604 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 20:17:19.715 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:19.715 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 20:17:21.694 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 20:17:21.834 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:21.834 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 20:17:23.799 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 20:17:24.109 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:24.109 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 20:17:25.913 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 20:17:26.007 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:26.007 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 20:17:28.006 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 20:17:28.053 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:28.053 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 20:17:30.047 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 20:17:30.111 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:30.111 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 20:17:32.153 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 20:17:32.230 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:32.230 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 20:17:34.207 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 20:17:34.377 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:34.377 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 20:17:36.308 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:17:36.433 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:36.433 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:17:38.431 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A2 00 28 33 00 ] 20:17:38.510 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:38.510 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A2 00 28 33 ] 20:17:40.534 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 01 28 33 00 ] 20:17:40.643 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:40.643 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 01 28 33 ] 20:17:42.606 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 4F 01 28 33 00 ] 20:17:42.682 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:42.682 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4F 01 28 33 ] 20:17:44.682 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 01 28 33 00 ] 20:17:44.852 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:44.852 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 01 28 33 ] 20:17:46.768 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 57 FF 28 33 00 ] 20:17:46.845 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:46.845 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 FF 28 33 ] 20:17:48.847 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 08 00 00 00 00 00 00 00 ] 20:17:49.112 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 08 03 ] 20:17:50.939 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 01 00 00 00 00 00 00 00 ] 20:17:51.063 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 01 01 ] 20:17:51.063 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 20:17:53.041 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:17:53.088 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:17:55.102 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:17:55.195 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:17:57.185 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 20:17:57.510 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 20:17:57.510 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 20:17:59.284 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 20:17:59.331 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:17:59.331 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 20:18:01.351 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 20:18:01.567 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:01.567 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 20:18:03.450 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:18:03.528 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:03.528 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:18:05.512 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 20:18:05.590 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:05.590 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 20:18:07.627 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 20:18:07.673 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:07.673 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 20:18:09.683 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 20:18:09.730 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:09.730 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 20:18:11.708 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 20:18:11.802 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:11.802 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 20:18:13.746 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 20:18:14.072 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:14.072 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 20:18:15.867 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 20:18:15.945 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:15.945 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 20:18:17.918 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:18:18.089 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:18.089 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:18:20.050 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 20:18:20.096 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:20.096 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 20:18:22.115 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 20:18:22.207 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:22.207 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 20:18:24.202 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 20:18:24.249 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:24.249 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 20:18:26.259 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 20:18:26.508 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:26.508 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 20:18:28.349 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 20:18:28.551 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:28.551 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 20:18:30.463 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 20:18:30.604 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:30.604 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 20:18:32.565 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 20:18:32.643 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:32.643 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 20:18:34.646 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 20:18:34.678 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:34.678 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 20:18:36.693 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 20:18:36.769 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:36.769 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 20:18:38.750 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 20:18:39.060 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:39.060 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 20:18:40.868 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 20:18:41.054 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:41.054 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 20:18:42.968 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:18:43.187 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:43.187 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:18:45.072 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A2 00 28 33 00 ] 20:18:45.149 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:45.149 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A2 00 28 33 ] 20:18:47.124 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 01 28 33 00 ] 20:18:47.248 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:47.248 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 01 28 33 ] 20:18:49.238 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 4F 01 28 33 00 ] 20:18:49.332 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:49.332 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4F 01 28 33 ] 20:18:51.311 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 01 28 33 00 ] 20:18:51.452 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:51.452 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 01 28 33 ] 20:18:53.427 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 57 FF 28 33 00 ] 20:18:53.613 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:18:53.613 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 FF 28 33 ] 20:18:55.519 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 08 00 00 00 00 00 00 00 ] 20:18:55.550 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 08 03 ] 20:18:57.571 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 01 00 00 00 00 00 00 00 ] 20:18:57.681 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 01 01 ] 20:18:57.681 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 20:18:59.669 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:18:59.747 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:19:01.734 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:19:01.827 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:19:03.840 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 20:19:04.105 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 20:19:04.105 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 20:19:05.947 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 20:19:06.116 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:06.116 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 20:19:08.042 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 20:19:08.165 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:08.165 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 20:19:10.145 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:19:10.208 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:10.253 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:19:12.243 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 20:19:12.321 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:12.321 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 20:19:14.328 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 20:19:14.406 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:14.406 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 20:19:16.397 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 20:19:16.429 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:16.429 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 20:19:18.464 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 20:19:18.541 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:18.541 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 20:19:20.534 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 20:19:20.783 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:20.783 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 20:19:22.653 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 20:19:22.775 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:22.775 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 20:19:24.753 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:19:24.831 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:24.831 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:19:26.832 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 20:19:26.971 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:26.971 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 20:19:28.926 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 20:19:29.097 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:29.097 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 20:19:31.013 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 20:19:31.106 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:31.106 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 20:19:33.127 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 20:19:33.329 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:33.329 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 20:19:35.219 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 20:19:35.265 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:35.265 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 20:19:37.278 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 20:19:37.356 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:37.356 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 20:19:39.354 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 20:19:39.433 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:39.433 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 20:19:41.425 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 20:19:41.457 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:41.457 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 20:19:43.492 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 20:19:43.723 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:43.723 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 20:19:45.581 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 20:19:45.750 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:45.750 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 20:19:47.678 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 20:19:47.818 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:47.818 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 20:19:49.788 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:19:49.865 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:49.865 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:19:51.859 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A2 00 28 33 00 ] 20:19:51.950 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:51.950 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A2 00 28 33 ] 20:19:53.940 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 01 28 33 00 ] 20:19:54.033 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:54.033 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 01 28 33 ] 20:19:56.027 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 4F 01 28 33 00 ] 20:19:56.462 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:56.462 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4F 01 28 33 ] 20:19:58.105 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 01 28 33 00 ] 20:19:58.275 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:19:58.322 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 01 28 33 ] 20:20:00.213 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 57 FF 28 33 00 ] 20:20:00.290 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:00.337 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 FF 28 33 ] 20:20:02.267 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 08 00 00 00 00 00 00 00 ] 20:20:02.360 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 08 03 ] 20:20:04.371 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 01 00 00 00 00 00 00 00 ] 20:20:04.417 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 01 01 ] 20:20:04.417 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 20:20:06.425 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:20:06.457 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:20:08.481 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 20:20:08.527 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 20:20:10.546 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 20:20:10.624 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 20:20:10.624 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 20:20:12.620 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 20:20:12.698 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:12.698 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 20:20:14.712 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 20:20:14.806 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:14.806 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 20:20:16.785 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:20:16.862 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:16.862 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:20:18.871 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 20:20:18.980 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:18.980 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 20:20:20.978 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 20:20:21.070 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:21.070 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 20:20:23.027 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 20:20:23.396 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:23.396 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 20:20:25.145 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 20:20:25.223 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:25.223 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 20:20:27.225 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 20:20:27.365 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:27.365 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 20:20:29.329 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 20:20:29.376 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:29.376 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 20:20:31.379 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 20:20:31.469 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:31.469 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 20:20:33.446 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 20:20:33.569 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:33.569 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 20:20:35.559 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 20:20:35.591 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:35.591 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 20:20:37.619 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 20:20:37.852 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:37.852 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 20:20:39.714 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 20:20:39.977 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:39.977 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 20:20:41.827 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 20:20:41.966 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:41.966 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 20:20:43.925 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 20:20:43.973 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:43.973 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 20:20:45.950 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 20:20:46.091 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:46.091 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 20:20:48.091 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 20:20:48.138 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:48.138 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 20:20:50.141 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 20:20:50.188 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:50.188 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 20:20:52.205 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 20:20:52.513 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 20:20:52.513 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ]

Thanks,

Joel

Berg0162 commented 1 year ago

Dear Joel, This is different from how the Elite Direto is responding, but that seems not to be a problem since you experience changing resistance. I have uploaded a new version that hopefully accounts for the slightly different timing of the itsybitsy.. (???) and should avoid message cluttering during connection phase. Furthermore I have introduced a Request for Machine Control in an early stage of the connection procedure, may be this helps waking up your trainer.... Best wishes, Jörgen.

le-joebar commented 1 year ago

Hello Jorghen,

I ordered the Feather but it hasn't arrived yet.

I had also started modifying the FTMS_Client_V25 to wait for feedback from everyone's services.

So I'm going to stop and try V.26 tonight. I'll get back to you with the results.

I received the Bluethoot BLE dongle and tested the FTMS_Server_V.22. It works so my key is good for the future.

Friendship Joel,

le-joebar commented 1 year ago

I looked at your version V.26 I saw you change the time from 2.5 seconds to 5. Personally I was looking at a different solution which consisted of: Example: if ( client_FitnessMachine_Service.discover(conn_handle) ) If false to restart the complete request and this for all the services which must answer! I don't know if this is the right solution but its a lot of work. if ( client_FitnessMachine_Service.discover(conn_handle) ) If False to restart the complete request and this for all the services that must respond! I don't know if this is the right solution but its a lot of work.

le-joebar commented 1 year ago

Hello Jörghen,

Here are the results: Unfortunately V0.26 does not work better than the others. Here is the result of V0.25 modified by me.

And the code below

18:07:13.207 -> GA and Chars 'initialized' 18:07:13.207 -> DIS and Chars 'initialized' 18:07:13.207 -> Start Scanning for CPS, CSC and FTMS! 18:07:13.207 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 18:07:13.207 -> Timestamp MAC Address Rssi Data 18:07:13.207 -> 000001374 F8:9C:FC:53:5E:49 -62 09-02-16-18-26-18-18-18-0A-18 18:07:13.207 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 18:07:13.207 -> Now checking all Client Services and Characteristics! 18:07:13.207 -> If Mandatory Services Fail --> the Client will disconnect! 18:07:13.207 -> First checking Generic Access and Device Information Services and Characteristics! 18:07:13.461 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 18:07:13.461 -> Discovering Client FTM Feature Characteristic ... Discovering Client FTM Control Point Characteristic ... Found it! 18:07:14.047 -> Discovering Client FTM Status Characteristic ... Found it! 18:07:14.601 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 18:07:14.864 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 18:07:15.220 -> Ready to receive Client FTM Control Point Response Messages 18:07:15.267 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 18:07:15.267 -> Discovering Client FTM Supported Power Range Characteristic ... Ready to receive Client FTM Status values 18:07:15.267 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 18:07:15.267 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 18:07:15.267 -> >>> Couldn't enable notify for Client CP Measurement Characteristic. 18:07:15.267 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 18:07:15.267 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 18:07:15.267 -> Client (Central) is Up and Running! 18:07:15.392 -> Found it! 18:07:15.484 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 00 00 00 00 ] 18:07:15.484 -> Discovering Client FTM Indoor Bike Data Characteristic ... Not Found! Not Mandatory 18:07:15.484 -> Discovering Client Cycling Power (CP) Service ... Not Found! 18:07:15.484 -> Disconnecting since Client Cyling Power Service is mandatory! 18:07:15.531 -> Client Disconnected, reason = 0x16 18:07:15.531 -> >>> Restart the Feather nRF52 Client for a new run! <<< 18:07:26.723 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 18:07:26.723 -> ----------------- Version 02.5 ------------------ 18:07:26.723 -> Initialise the Bluefruit nRF52 module: Client (Central) 18:07:26.724 -> FTMS and Chars 'initialized' 18:07:26.724 -> CPS and Chars 'initialized' 18:07:26.724 -> CSCS and Chars 'initialized' 18:07:26.724 -> GA and Chars 'initialized' 18:07:26.724 -> DIS and Chars 'initialized' 18:07:26.724 -> Start Scanning for CPS, CSC and FTMS! 18:07:26.724 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 18:07:26.724 -> Timestamp MAC Address Rssi Data 18:07:26.724 -> 000001192 F8:9C:FC:53:5E:49 -62 09-02-16-18-26-18-18-18-0A-18 18:07:26.743 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 18:07:26.743 -> Now checking all Client Services and Characteristics! 18:07:26.743 -> If Mandatory Services Fail --> the Client will disconnect! 18:07:26.743 -> First checking Generic Access and Device Information Services and Characteristics! 18:07:26.747 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 18:07:26.747 -> Discovering Client FTM Feature Characteristic ... Discovering Client FTM Control Point Characteristic ... Found it! 18:07:27.137 -> Discovering Client FTM Status Characteristic ... Found it! 18:07:27.555 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 18:07:27.912 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 18:07:28.129 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 18:07:28.129 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 18:07:28.346 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 18:07:28.346 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 18:07:28.639 -> Discovering Client Cycling Power (CP) Service ... Ready to receive Client FTM Control Point Response Messages 18:07:28.731 -> Found it! CPS Max Payload: 20 Data Length: 27 18:07:28.731 -> Discovering Client CP Measurement characteristic ... Ready to receive Client FTM Status values 18:07:28.731 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 18:07:28.809 -> Ready to receive Client FTM Indoor Bike Data values 18:07:28.809 -> Found it! 18:07:28.809 -> Discovering Client CP Control Point characteristic ... Ready to receive Client CP Measurement values 18:07:28.809 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 18:07:28.809 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 18:07:28.809 -> Client (Central) is Up and Running! 18:07:28.932 -> Not Found! NOT Mandatory! 18:07:28.932 -> Discovering Client CP Feature characteristic ... Found it! 18:07:29.446 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 18:07:29.446 -> Wheel revolution data supported 18:07:29.446 -> Crank revolution data supported 18:07:29.446 -> Discovering Client CP Sensor Location characteristic ... Found it! 18:07:29.646 -> -> Client Reads CP Location Sensor: Loc#: 0 Other 18:07:29.646 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 18:07:29.646 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 18:07:29.646 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:07:30.031 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 18:07:30.031 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:07:30.819 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 18:07:30.864 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 18:07:31.036 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 18:07:31.036 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:07:32.006 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 18:07:32.006 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:07:32.870 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 18:07:32.916 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 18:07:33.195 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 18:07:33.195 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:07:34.074 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 18:07:34.074 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:07:34.925 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 18:07:35.266 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 18:07:35.266 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:07:35.313 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 18:07:35.313 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 18:07:36.008 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ] 18:07:36.008 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Average Cadence: 0 RPM Total Distance: 0 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:07:37.011 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ] 18:07:37.011 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Average Cadence: 0 RPM Total Distance: 0 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:07:37.011 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 18:07:37.213 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:37.213 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 18:07:37.972 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ] 18:07:38.018 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Average Cadence: 0 RPM Total Distance: 0 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:07:38.984 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ] 18:07:38.984 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Average Cadence: 0 RPM Total Distance: 0 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:07:39.110 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 18:07:39.188 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:39.188 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 18:07:39.989 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ] 18:07:39.989 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Average Cadence: 0 RPM Total Distance: 0 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:07:41.147 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ] 18:07:41.147 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Average Cadence: 0 RPM Total Distance: 0 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:07:41.193 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 18:07:41.286 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:41.286 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 18:07:41.978 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 00 00 00 00 00 00 00 00 00 14 00 00 00 00 00 00 ] 18:07:41.978 -> Speed: 0 KPH Instantaneous Cadence: 0 RPM Average Cadence: 0 RPM Total Distance: 0 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:07:43.072 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 09 05 88 00 00 00 00 00 03 00 00 14 00 78 00 0F 00 00 ] 18:07:43.072 -> Speed: 12 KPH Instantaneous Cadence: 68 RPM Average Cadence: 0 RPM Total Distance: 196608 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 120 Watt Heart Rate: 15 HBM 18:07:43.289 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 18:07:43.321 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:43.321 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 18:07:44.015 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A3 06 1A 01 00 00 00 00 07 00 00 14 00 D5 00 25 00 00 ] 18:07:44.015 -> Speed: 16 KPH Instantaneous Cadence: 141 RPM Average Cadence: 0 RPM Total Distance: 458752 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 213 Watt Heart Rate: 37 HBM 18:07:45.252 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B5 06 8F 01 00 00 00 00 0B 00 00 14 00 91 00 2F 00 00 ] 18:07:45.252 -> Speed: 17 KPH Instantaneous Cadence: 199 RPM Average Cadence: 0 RPM Total Distance: 720896 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 145 Watt Heart Rate: 47 HBM 18:07:45.344 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 18:07:45.390 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:45.390 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 18:07:46.008 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 15 07 EF 01 36 00 04 00 0F 00 00 14 00 BE 00 3C 00 00 ] 18:07:46.008 -> Speed: 18 KPH Instantaneous Cadence: 247 RPM Average Cadence: 27 RPM Total Distance: 983044 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 190 Watt Heart Rate: 60 HBM 18:07:46.999 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B4 07 5D 02 56 00 0B 00 14 00 00 14 00 C5 00 48 00 00 ] 18:07:46.999 -> Speed: 19 KPH Instantaneous Cadence: 302 RPM Average Cadence: 43 RPM Total Distance: 1310731 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 197 Watt Heart Rate: 72 HBM 18:07:47.416 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 18:07:47.667 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:47.667 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 18:07:48.011 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 15 08 BA 02 66 00 12 00 19 00 00 14 00 A4 00 4F 00 00 ] 18:07:48.011 -> Speed: 20 KPH Instantaneous Cadence: 349 RPM Average Cadence: 51 RPM Total Distance: 1638418 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 164 Watt Heart Rate: 79 HBM 18:07:49.075 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 6C 08 09 03 70 00 19 00 1E 00 00 14 00 9D 00 54 00 00 ] 18:07:49.075 -> Speed: 21 KPH Instantaneous Cadence: 388 RPM Average Cadence: 56 RPM Total Distance: 1966105 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 157 Watt Heart Rate: 84 HBM 18:07:49.490 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 18:07:49.568 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:49.568 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 18:07:50.015 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C7 08 67 03 76 00 1F 00 24 00 00 14 00 99 00 59 00 00 ] 18:07:50.015 -> Speed: 22 KPH Instantaneous Cadence: 435 RPM Average Cadence: 59 RPM Total Distance: 2359327 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 153 Watt Heart Rate: 89 HBM 18:07:51.031 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4D 09 B8 03 7A 00 25 00 2A 00 00 14 00 8E 00 5C 00 00 ] 18:07:51.031 -> Speed: 23 KPH Instantaneous Cadence: 476 RPM Average Cadence: 61 RPM Total Distance: 2752549 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 142 Watt Heart Rate: 92 HBM 18:07:51.570 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 18:07:51.849 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:51.849 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 18:07:51.973 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 70 09 00 04 80 00 2A 00 30 00 00 14 00 89 00 5F 00 00 ] 18:07:51.973 -> Speed: 24 KPH Instantaneous Cadence: 512 RPM Average Cadence: 64 RPM Total Distance: 3145770 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 137 Watt Heart Rate: 95 HBM 18:07:52.992 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5E 09 40 04 86 00 2F 00 36 00 00 14 00 85 00 61 00 00 ] 18:07:52.992 -> Speed: 23 KPH Instantaneous Cadence: 544 RPM Average Cadence: 67 RPM Total Distance: 3538991 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 133 Watt Heart Rate: 97 HBM 18:07:53.670 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 18:07:53.748 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:53.748 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 18:07:53.978 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 65 09 7A 04 88 00 34 00 3C 00 00 14 00 78 00 62 00 00 ] 18:07:53.978 -> Speed: 24 KPH Instantaneous Cadence: 573 RPM Average Cadence: 68 RPM Total Distance: 3932212 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 120 Watt Heart Rate: 98 HBM 18:07:54.980 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 87 09 AD 04 8A 00 38 00 42 00 00 14 00 70 00 63 00 00 ] 18:07:54.980 -> Speed: 24 KPH Instantaneous Cadence: 598 RPM Average Cadence: 69 RPM Total Distance: 4325432 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 112 Watt Heart Rate: 99 HBM 18:07:55.749 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 18:07:55.886 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:55.886 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 18:07:56.009 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5E 09 DC 04 8A 00 3C 00 48 00 00 14 00 5D 00 62 00 00 ] 18:07:56.009 -> Speed: 23 KPH Instantaneous Cadence: 622 RPM Average Cadence: 69 RPM Total Distance: 4718652 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 93 Watt Heart Rate: 98 HBM 18:07:57.015 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A8 09 06 05 8C 00 40 00 4E 00 00 14 00 70 00 63 00 00 ] 18:07:57.015 -> Speed: 24 KPH Instantaneous Cadence: 643 RPM Average Cadence: 70 RPM Total Distance: 5111872 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 112 Watt Heart Rate: 99 HBM 18:07:57.849 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 18:07:57.927 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:57.927 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 18:07:57.974 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 0A 3D 05 8C 00 43 00 55 00 00 14 00 74 00 64 00 00 ] 18:07:57.974 -> Speed: 25 KPH Instantaneous Cadence: 670 RPM Average Cadence: 70 RPM Total Distance: 5570627 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 116 Watt Heart Rate: 100 HBM 18:07:59.038 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D4 09 60 05 90 00 46 00 5B 00 00 14 00 7D 00 65 00 00 ] 18:07:59.038 -> Speed: 25 KPH Instantaneous Cadence: 688 RPM Average Cadence: 72 RPM Total Distance: 5963846 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 125 Watt Heart Rate: 101 HBM 18:07:59.950 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 18:07:59.997 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:07:59.997 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 18:07:59.997 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 23 0A 8E 05 92 00 49 00 62 00 00 14 00 75 00 65 00 00 ] 18:07:59.997 -> Speed: 25 KPH Instantaneous Cadence: 711 RPM Average Cadence: 73 RPM Total Distance: 6422601 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 117 Watt Heart Rate: 101 HBM 18:08:01.066 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0D 0A B9 05 92 00 4C 00 69 00 00 14 00 6B 00 66 00 00 ] 18:08:01.066 -> Speed: 25 KPH Instantaneous Cadence: 732 RPM Average Cadence: 73 RPM Total Distance: 6881356 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 107 Watt Heart Rate: 102 HBM 18:08:01.990 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4F 0A E1 05 94 00 4E 00 70 00 00 14 00 6C 00 66 00 00 ] 18:08:01.990 -> Speed: 26 KPH Instantaneous Cadence: 752 RPM Average Cadence: 74 RPM Total Distance: 7340110 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 108 Watt Heart Rate: 102 HBM 18:08:01.990 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 18:08:02.113 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:02.113 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 18:08:02.993 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 28 0A 06 06 94 00 51 00 77 00 00 14 00 63 00 66 00 00 ] 18:08:02.993 -> Speed: 26 KPH Instantaneous Cadence: 771 RPM Average Cadence: 74 RPM Total Distance: 7798865 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 99 Watt Heart Rate: 102 HBM 18:08:04.087 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 18:08:04.211 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 62 0A 28 06 98 00 53 00 7E 00 00 14 00 5A 00 65 00 00 ] 18:08:04.211 -> Speed: 26 KPH Instantaneous Cadence: 788 RPM Average Cadence: 76 RPM Total Distance: 8257619 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 90 Watt Heart Rate: 101 HBM 18:08:04.303 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:04.303 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 18:08:04.996 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 2E 0A 48 06 96 00 56 00 85 00 00 14 00 51 00 65 00 00 ] 18:08:04.996 -> Speed: 26 KPH Instantaneous Cadence: 804 RPM Average Cadence: 75 RPM Total Distance: 8716374 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 81 Watt Heart Rate: 101 HBM 18:08:06.088 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AF 0A 66 06 96 00 58 00 8C 00 00 14 00 52 00 64 00 00 ] 18:08:06.088 -> Speed: 27 KPH Instantaneous Cadence: 819 RPM Average Cadence: 75 RPM Total Distance: 9175128 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 82 Watt Heart Rate: 100 HBM 18:08:06.181 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 18:08:06.303 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:06.303 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 18:08:06.995 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9B 0A 83 06 A0 00 5A 00 93 00 00 14 00 64 00 64 00 00 ] 18:08:06.995 -> Speed: 27 KPH Instantaneous Cadence: 833 RPM Average Cadence: 80 RPM Total Distance: 9633882 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 100 Watt Heart Rate: 100 HBM 18:08:08.181 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 CA 0A 9D 06 A6 00 5C 00 9A 00 00 14 00 61 00 64 00 00 ] 18:08:08.182 -> Speed: 27 KPH Instantaneous Cadence: 846 RPM Average Cadence: 83 RPM Total Distance: 10092636 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 97 Watt Heart Rate: 100 HBM 18:08:08.274 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 18:08:08.412 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:08.412 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 18:08:08.999 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0D 0B B6 06 A6 00 5E 00 A1 00 00 14 00 5E 00 64 00 00 ] 18:08:08.999 -> Speed: 28 KPH Instantaneous Cadence: 859 RPM Average Cadence: 83 RPM Total Distance: 10551390 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 94 Watt Heart Rate: 100 HBM 18:08:10.090 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0E 0B CD 06 A2 00 60 00 A8 00 00 14 00 51 00 63 00 00 ] 18:08:10.138 -> Speed: 28 KPH Instantaneous Cadence: 870 RPM Average Cadence: 81 RPM Total Distance: 11010144 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 81 Watt Heart Rate: 99 HBM 18:08:10.373 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 18:08:10.451 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:10.451 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 18:08:11.013 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 39 0B E4 06 A6 00 62 00 AF 00 00 14 00 58 00 63 00 00 ] 18:08:11.013 -> Speed: 28 KPH Instantaneous Cadence: 882 RPM Average Cadence: 83 RPM Total Distance: 11468898 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 88 Watt Heart Rate: 99 HBM 18:08:11.978 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 6C 0B 02 07 A6 00 64 00 B7 00 00 14 00 50 00 62 00 00 ] 18:08:11.978 -> Speed: 29 KPH Instantaneous Cadence: 897 RPM Average Cadence: 83 RPM Total Distance: 11993188 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 80 Watt Heart Rate: 98 HBM 18:08:12.432 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 18:08:12.668 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:12.668 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 18:08:12.992 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 70 0B 20 07 AA 00 66 00 BF 00 00 14 00 4D 00 62 00 00 ] 18:08:12.993 -> Speed: 29 KPH Instantaneous Cadence: 912 RPM Average Cadence: 85 RPM Total Distance: 12517478 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 77 Watt Heart Rate: 98 HBM 18:08:13.995 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B7 0B 3B 07 AE 00 68 00 C7 00 00 14 00 50 00 61 00 00 ] 18:08:13.995 -> Speed: 29 KPH Instantaneous Cadence: 925 RPM Average Cadence: 87 RPM Total Distance: 13041768 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 80 Watt Heart Rate: 97 HBM 18:08:14.550 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 18:08:14.768 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:14.768 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 18:08:14.984 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A3 0B 56 07 B2 00 6A 00 CF 00 00 14 00 4C 00 61 00 00 ] 18:08:14.984 -> Speed: 29 KPH Instantaneous Cadence: 939 RPM Average Cadence: 89 RPM Total Distance: 13566058 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 76 Watt Heart Rate: 97 HBM 18:08:16.182 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 81 0B 6F 07 BA 00 6B 00 D7 00 00 14 00 39 00 60 00 00 ] 18:08:16.182 -> Speed: 29 KPH Instantaneous Cadence: 951 RPM Average Cadence: 93 RPM Total Distance: 14090347 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 57 Watt Heart Rate: 96 HBM 18:08:16.631 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 18:08:16.709 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:16.709 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 18:08:17.003 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9F 0B 86 07 BC 00 6D 00 DF 00 00 14 00 42 00 5F 00 00 ] 18:08:17.003 -> Speed: 29 KPH Instantaneous Cadence: 963 RPM Average Cadence: 94 RPM Total Distance: 14614637 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 66 Watt Heart Rate: 95 HBM 18:08:18.191 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A0 0B 9D 07 BE 00 6F 00 E7 00 00 14 00 41 00 5E 00 00 ] 18:08:18.191 -> Speed: 29 KPH Instantaneous Cadence: 974 RPM Average Cadence: 95 RPM Total Distance: 15138927 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 65 Watt Heart Rate: 94 HBM 18:08:18.671 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 18:08:18.794 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:18.794 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 18:08:18.980 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C3 0B B3 07 B6 00 71 00 EF 00 00 14 00 4E 00 5E 00 00 ] 18:08:18.980 -> Speed: 30 KPH Instantaneous Cadence: 985 RPM Average Cadence: 91 RPM Total Distance: 15663217 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 78 Watt Heart Rate: 94 HBM 18:08:20.077 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 99 0B C7 07 B2 00 72 00 F7 00 00 14 00 46 00 5D 00 00 ] 18:08:20.077 -> Speed: 29 KPH Instantaneous Cadence: 995 RPM Average Cadence: 89 RPM Total Distance: 16187506 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 70 Watt Heart Rate: 93 HBM 18:08:20.803 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 18:08:20.835 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:20.835 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 18:08:20.973 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 89 0B DB 07 B2 00 74 00 FF 00 00 14 00 47 00 5D 00 00 ] 18:08:20.973 -> Speed: 29 KPH Instantaneous Cadence: 1005 RPM Average Cadence: 89 RPM Total Distance: 16711796 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 71 Watt Heart Rate: 93 HBM 18:08:22.098 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 48 0B E6 07 AE 00 75 00 06 01 00 14 00 47 00 5C 00 00 ] 18:08:22.098 -> Speed: 28 KPH Instantaneous Cadence: 1011 RPM Average Cadence: 87 RPM Total Distance: 393333 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 71 Watt Heart Rate: 92 HBM 18:08:22.867 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A2 00 28 33 00 ] 18:08:22.913 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:22.913 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A2 00 28 33 ] 18:08:23.039 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 42 0B F1 07 B0 00 76 00 0D 01 00 14 00 59 00 5C 00 00 ] 18:08:23.039 -> Speed: 28 KPH Instantaneous Cadence: 1016 RPM Average Cadence: 88 RPM Total Distance: 852086 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 89 Watt Heart Rate: 92 HBM 18:08:24.006 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0E 0B FC 07 AA 00 77 00 14 01 00 14 00 5F 00 5C 00 00 ] 18:08:24.006 -> Speed: 28 KPH Instantaneous Cadence: 1022 RPM Average Cadence: 85 RPM Total Distance: 1310839 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 95 Watt Heart Rate: 92 HBM 18:08:24.918 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 01 28 33 00 ] 18:08:25.012 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:25.012 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 01 28 33 ] 18:08:25.012 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C9 0A 05 08 96 00 78 00 1B 01 00 14 00 70 00 5D 00 00 ] 18:08:25.012 -> Speed: 27 KPH Instantaneous Cadence: 1026 RPM Average Cadence: 75 RPM Total Distance: 1769592 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 112 Watt Heart Rate: 93 HBM 18:08:26.030 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 62 0A 0F 08 9C 00 78 00 22 01 00 14 00 95 00 5E 00 00 ] 18:08:26.030 -> Speed: 26 KPH Instantaneous Cadence: 1031 RPM Average Cadence: 78 RPM Total Distance: 2228344 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 149 Watt Heart Rate: 94 HBM 18:08:27.014 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9F 0A 18 08 A0 00 79 00 29 01 00 14 00 A9 00 5F 00 00 ] 18:08:27.014 -> Speed: 27 KPH Instantaneous Cadence: 1036 RPM Average Cadence: 80 RPM Total Distance: 2687097 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 169 Watt Heart Rate: 95 HBM 18:08:27.014 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 4F 01 28 33 00 ] 18:08:27.107 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:27.107 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4F 01 28 33 ] 18:08:27.989 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 FE 09 21 08 9C 00 7A 00 30 01 00 14 00 C0 00 61 00 00 ] 18:08:27.989 -> Speed: 25 KPH Instantaneous Cadence: 1040 RPM Average Cadence: 78 RPM Total Distance: 3145850 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 192 Watt Heart Rate: 97 HBM 18:08:28.992 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 02 0A 2A 08 98 00 7A 00 37 01 00 14 00 C9 00 63 00 00 ] 18:08:28.992 -> Speed: 25 KPH Instantaneous Cadence: 1045 RPM Average Cadence: 76 RPM Total Distance: 3604602 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 201 Watt Heart Rate: 99 HBM 18:08:29.114 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 01 28 33 00 ] 18:08:29.346 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:29.346 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 01 28 33 ] 18:08:29.995 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A3 09 2B 08 94 00 7B 00 3D 01 00 14 00 CD 00 65 00 00 ] 18:08:29.995 -> Speed: 24 KPH Instantaneous Cadence: 1045 RPM Average Cadence: 74 RPM Total Distance: 3997819 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 205 Watt Heart Rate: 101 HBM 18:08:30.983 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 6B 09 2D 08 92 00 7B 00 43 01 00 14 00 D0 00 67 00 00 ] 18:08:30.983 -> Speed: 24 KPH Instantaneous Cadence: 1046 RPM Average Cadence: 73 RPM Total Distance: 4391035 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 208 Watt Heart Rate: 103 HBM 18:08:31.216 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 57 FF 28 33 00 ] 18:08:31.309 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:31.309 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 FF 28 33 ] 18:08:32.004 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 FE 09 34 08 8E 00 7C 00 4A 01 00 14 00 C7 00 68 00 00 ] 18:08:32.004 -> Speed: 25 KPH Instantaneous Cadence: 1050 RPM Average Cadence: 71 RPM Total Distance: 4849788 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 199 Watt Heart Rate: 104 HBM 18:08:33.234 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 3C 0A 3C 08 8E 00 7C 00 51 01 00 14 00 D2 00 6A 00 00 ] 18:08:33.234 -> Speed: 26 KPH Instantaneous Cadence: 1054 RPM Average Cadence: 71 RPM Total Distance: 5308540 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 210 Watt Heart Rate: 106 HBM 18:08:33.310 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 08 00 00 00 00 00 00 00 ] 18:08:33.388 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 08 03 ] 18:08:33.974 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A0 0A 43 08 92 00 7C 00 58 01 00 14 00 B2 00 6B 00 00 ] 18:08:33.974 -> Speed: 27 KPH Instantaneous Cadence: 1057 RPM Average Cadence: 73 RPM Total Distance: 5767292 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 178 Watt Heart Rate: 107 HBM 18:08:34.984 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 EE 0A 4A 08 96 00 7D 00 5F 01 00 14 00 6F 00 6C 00 00 ] 18:08:34.984 -> Speed: 27 KPH Instantaneous Cadence: 1061 RPM Average Cadence: 75 RPM Total Distance: 6226045 m Resistance Level: 1 Instantaneous Power: 20 Watt Average Power: 111 Watt Heart Rate: 108 HBM 18:08:35.386 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 01 00 00 00 00 00 00 00 ] 18:08:35.479 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 01 01 ] 18:08:35.479 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 18:08:35.989 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 44 0A 9C 00 14 00 3A 00 00 ] 18:08:35.989 -> Speed: 26 KPH Instantaneous Cadence: 78 RPM Resistance Level: 20 Instantaneous Power: 58 Watt Heart Rate: 0 HBM 18:08:36.992 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 AC 09 00 00 14 00 00 00 00 ] 18:08:36.992 -> Speed: 24 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:08:37.486 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 18:08:37.579 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 18:08:37.997 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 18 09 00 00 14 00 00 00 00 ] 18:08:37.997 -> Speed: 23 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:08:39.290 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 8A 08 00 00 14 00 00 00 00 ] 18:08:39.290 -> Speed: 21 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:08:39.584 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 18:08:39.833 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 18:08:39.956 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 FC 07 00 00 14 00 00 00 00 ] 18:08:39.956 -> Speed: 20 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:08:40.991 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 74 07 00 00 14 00 00 00 00 ] 18:08:40.991 -> Speed: 19 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 18:08:41.684 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 18:08:41.793 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 18:08:41.793 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 18:08:42.024 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 ED 06 AC 05 00 00 00 00 04 00 00 14 00 00 00 00 00 00 ] 18:08:42.024 -> Speed: 17 KPH Instantaneous Cadence: 726 RPM Average Cadence: 0 RPM Total Distance: 262144 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:43.125 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 6A 06 AB 05 00 00 00 00 08 00 00 14 00 00 00 00 00 00 ] 18:08:43.125 -> Speed: 16 KPH Instantaneous Cadence: 725 RPM Average Cadence: 0 RPM Total Distance: 524288 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:43.770 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 18:08:43.863 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:43.863 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 18:08:43.987 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E9 05 AB 05 00 00 00 00 0C 00 00 14 00 00 00 00 00 00 ] 18:08:43.987 -> Speed: 15 KPH Instantaneous Cadence: 725 RPM Average Cadence: 0 RPM Total Distance: 786432 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:44.988 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 6C 05 51 05 00 00 00 00 0F 00 00 14 00 00 00 00 00 00 ] 18:08:44.988 -> Speed: 13 KPH Instantaneous Cadence: 680 RPM Average Cadence: 0 RPM Total Distance: 983040 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:45.858 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 18:08:45.936 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:45.936 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 18:08:45.982 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 F0 04 1A 05 00 00 00 00 12 00 00 14 00 00 00 00 00 00 ] 18:08:45.982 -> Speed: 12 KPH Instantaneous Cadence: 653 RPM Average Cadence: 0 RPM Total Distance: 1179648 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:47.261 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 7B 04 F6 04 00 00 00 00 15 00 00 14 00 00 00 00 00 00 ] 18:08:47.261 -> Speed: 11 KPH Instantaneous Cadence: 635 RPM Average Cadence: 0 RPM Total Distance: 1376256 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:47.940 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 18:08:47.972 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 07 04 A8 04 00 00 00 00 17 00 00 14 00 00 00 00 00 00 ] 18:08:47.972 -> Speed: 10 KPH Instantaneous Cadence: 596 RPM Average Cadence: 0 RPM Total Distance: 1507328 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:48.003 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:48.003 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 18:08:49.051 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 98 03 6E 04 00 00 00 00 19 00 00 14 00 00 00 00 00 00 ] 18:08:49.096 -> Speed: 9 KPH Instantaneous Cadence: 567 RPM Average Cadence: 0 RPM Total Distance: 1638400 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:50.008 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 2B 03 40 04 00 00 00 00 1B 00 00 14 00 00 00 00 00 00 ] 18:08:50.008 -> Speed: 8 KPH Instantaneous Cadence: 544 RPM Average Cadence: 0 RPM Total Distance: 1769472 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:50.008 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 18:08:50.132 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:50.132 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 18:08:51.171 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C2 02 F8 03 00 00 00 00 1C 00 00 14 00 00 00 00 00 00 ] 18:08:51.171 -> Speed: 7 KPH Instantaneous Cadence: 508 RPM Average Cadence: 0 RPM Total Distance: 1835008 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:52.014 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5C 02 BC 03 00 00 00 00 1D 00 00 14 00 00 00 00 00 00 ] 18:08:52.014 -> Speed: 6 KPH Instantaneous Cadence: 478 RPM Average Cadence: 0 RPM Total Distance: 1900544 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:52.133 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 18:08:52.169 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:52.169 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 18:08:52.969 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 FC 01 8B 03 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:52.969 -> Speed: 5 KPH Instantaneous Cadence: 453 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:54.032 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 45 03 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:54.032 -> Speed: 0 KPH Instantaneous Cadence: 418 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:54.172 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 18:08:54.375 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:54.375 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 18:08:55.011 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 09 03 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:55.056 -> Speed: 0 KPH Instantaneous Cadence: 388 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:55.994 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 D6 02 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:55.994 -> Speed: 0 KPH Instantaneous Cadence: 363 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:56.274 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 18:08:56.366 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:56.366 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 18:08:57.103 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 A8 02 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:57.103 -> Speed: 0 KPH Instantaneous Cadence: 340 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:58.006 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 80 02 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:58.006 -> Speed: 0 KPH Instantaneous Cadence: 320 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:58.393 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 18:08:58.486 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:08:58.486 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 18:08:59.043 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 5D 02 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:59.043 -> Speed: 0 KPH Instantaneous Cadence: 302 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:08:59.970 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 3D 02 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:08:59.970 -> Speed: 0 KPH Instantaneous Cadence: 286 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:00.484 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 18:09:00.562 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:00.562 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 18:09:00.982 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 20 02 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:00.982 -> Speed: 0 KPH Instantaneous Cadence: 272 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:02.154 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 06 02 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:02.154 -> Speed: 0 KPH Instantaneous Cadence: 259 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:02.545 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 18:09:02.671 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:02.671 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 18:09:03.077 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 EF 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:03.077 -> Speed: 0 KPH Instantaneous Cadence: 247 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:04.037 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 D9 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:04.037 -> Speed: 0 KPH Instantaneous Cadence: 236 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:04.670 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 18:09:04.993 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 C5 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:04.993 -> Speed: 0 KPH Instantaneous Cadence: 226 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:05.039 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:05.039 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 18:09:05.976 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 B3 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:05.976 -> Speed: 0 KPH Instantaneous Cadence: 217 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:06.769 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 18:09:06.848 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:06.848 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 18:09:06.988 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 A3 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:06.988 -> Speed: 0 KPH Instantaneous Cadence: 209 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:07.992 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 93 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:07.992 -> Speed: 0 KPH Instantaneous Cadence: 201 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:08.857 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 18:09:08.980 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 85 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:08.980 -> Speed: 0 KPH Instantaneous Cadence: 194 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:09.026 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:09.026 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 18:09:10.279 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 77 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:10.279 -> Speed: 0 KPH Instantaneous Cadence: 187 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:10.944 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 18:09:10.990 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 6B 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:10.990 -> Speed: 0 KPH Instantaneous Cadence: 181 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:11.037 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:11.037 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 18:09:12.001 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 5F 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:12.001 -> Speed: 0 KPH Instantaneous Cadence: 175 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:12.989 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 54 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:12.989 -> Speed: 0 KPH Instantaneous Cadence: 170 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:13.025 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 18:09:13.104 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:13.104 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 18:09:13.972 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 4A 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:13.972 -> Speed: 0 KPH Instantaneous Cadence: 165 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:14.978 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 40 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:14.978 -> Speed: 0 KPH Instantaneous Cadence: 160 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:15.116 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 18:09:15.194 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:15.194 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 18:09:16.125 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 37 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:16.125 -> Speed: 0 KPH Instantaneous Cadence: 155 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:17.013 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 2E 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:17.013 -> Speed: 0 KPH Instantaneous Cadence: 151 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:17.184 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 18:09:17.263 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:17.263 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 18:09:18.010 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 26 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:18.010 -> Speed: 0 KPH Instantaneous Cadence: 147 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:19.015 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 1E 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ] 18:09:19.015 -> Speed: 0 KPH Instantaneous Cadence: 143 RPM Average Cadence: 0 RPM Total Distance: 1966080 m Resistance Level: 0 Instantaneous Power: 20 Watt Average Power: 0 Watt Heart Rate: 0 HBM 18:09:19.248 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 18:09:19.372 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:09:19.372 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 18:09:20.050 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 00 00 17 01 00 00 00 00 1E 00 00 14 00 00 00 00 00 00 ]

// If FTM Feature is not found, disconnect, resume scanning, and return while (!( client_FTM_Feature_Chr.discover() )) { if ( client_FTM_Feature_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read FTM Feature Data
client_FTM_Feature_Chr.read(client_FTM_Feature_Data, 8);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Feature bytes: [8] [ ");
for (int i = 0; i < sizeof(client_FTM_Feature_Data); i++) {
    Serial.printf("%02X ", client_FTM_Feature_Data[i], HEX);
} // for
Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Disconnecting since Client FTM Feature Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
Bluefruit.Connection(conn_handle);
Serial.print("Discovering Client FTM Feature not decouvert ... ");

// return; } }

As you can see in the second test it does not find the speed and cadence values.

Probably I should put more "While".

What is weird is the value of the heart rate because the sensor is not connected (battery removed)

18:26:23.470 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 18:26:23.470 -> ----------------- Version 02.5 ------------------ 18:26:23.470 -> Initialise the Bluefruit nRF52 module: Client (Central) 18:26:23.718 -> FTMS and Chars 'initialized' 18:26:23.718 -> CPS and Chars 'initialized' 18:26:23.718 -> CSCS and Chars 'initialized' 18:26:23.718 -> GA and Chars 'initialized' 18:26:23.718 -> DIS and Chars 'initialized' 18:26:23.718 -> Start Scanning for CPS, CSC and FTMS! 18:26:23.720 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 18:26:23.720 -> Timestamp MAC Address Rssi Data 18:26:23.720 -> 000001552 F8:9C:FC:53:5E:49 -61 09-02-16-18-26-18-18-18-0A-18 18:26:23.720 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 18:26:23.720 -> Now checking all Client Services and Characteristics! 18:26:23.720 -> If Mandatory Services Fail --> the Client will disconnect! 18:26:23.720 -> First checking Generic Access and Device Information Services and Characteristics! 18:26:24.243 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 18:26:24.243 -> Discovering Client FTM Feature Characteristic ... Discovering Client FTM Control Point Characteristic ... Found it! 18:26:24.252 -> Discovering Client FTM Status Characteristic ... Found it! 18:26:24.544 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 18:26:24.823 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 18:26:25.225 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 18:26:25.225 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 18:26:25.457 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 18:26:25.457 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 18:26:25.781 -> Discovering Client Cycling Power (CP) Service ... Ready to receive Client FTM Control Point Response Messages 18:26:25.827 -> Found it! CPS Max Payload: 20 Data Length: 27 18:26:25.827 -> Discovering Client CP Measurement characteristic ... Ready to receive Client FTM Status values 18:26:25.827 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 18:26:25.906 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 18:26:25.906 -> >>> Couldn't enable notify for Client CP Measurement Characteristic. 18:26:25.906 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 18:26:25.906 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 18:26:25.906 -> Client (Central) is Up and Running! 18:26:26.045 -> Found it! 18:26:26.045 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 18:26:26.541 -> Discovering Client CP Feature characteristic ... Found it! 18:26:26.726 -> -> Client Reads Raw CP Feature bytes: [4] [ 00 00 00 00 ] 18:26:26.726 -> Discovering Client CP Sensor Location characteristic ... NOT Found! NOT Mandatory! 18:26:26.726 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 18:26:27.906 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 18:26:27.970 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 18:26:29.983 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 18:26:30.029 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 18:26:32.045 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 18:26:32.122 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 18:26:32.122 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 18:26:34.127 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 18:26:34.174 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:26:34.174 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 18:26:36.191 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 18:26:36.237 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:26:36.237 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 18:26:38.240 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 18:26:38.317 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:26:38.317 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 18:26:40.324 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 18:26:40.402 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:26:40.402 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 18:26:42.383 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 18:26:42.508 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 18:26:42.508 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 18:26:44.510 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 18:26:44.588 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ]

Berg0162 commented 1 year ago

Dear Joel, I am puzzled about how and what you have changed in the code version 025. I see a while loop that waits for ever until the FTM_Feature_Char is discovered: while (!( client_FTM_Feature_Chr.discover() )) { et cetera } FTM_Feature was never a problem....??? Did you put while loops in all discover calls...? For what purpose? Whatever you did: one of the runs now shows -> Client Rec'd Raw FTM Indoor Bike Data: et cetera That never ever happened before ...... ???? So please detail more and better what you have changed otherwise I am only guessing and that does not help progress... Greetings, Jörgen.

Berg0162 commented 1 year ago

Dear Joel, Still I would like to know more precisely what you have altered in the code of 025... that issue is still open! Your code snippet is only relevant when you think a timing problem prevents the discovery of the relevant Char's..... (?) Meanwhile I guessed that (along the same line of reasoning) enabling of the Char's with Notify or Indicate (at the Zwift Hub) might go wrong due to a timing problem...(ItsyBitsy? or Hub?). So I have inserted a timed check for notify/indicate result that gives the polling process two (2) seconds for response.... I wonder if this version 027 will bring us closer to a solution... (You still need to wake up your trainer and ride the trainer!!)

Do not take the IBD decoded data too serious, decoding the IBD data is very complicated and I would not be surprised that I understood it in a wrong way.... although it works fine with Elite Direto specifications! This is not critical for the final result, after all the MITM does not have to understand/decode everything, only what it is interested in...

By the way the FTMS_Zwift_Bridge code v023 can be tested with your setup.... (Notice that you have to pedal as well! Read the instructions)

Best wishes, Jörgen.

le-joebar commented 1 year ago

Hello Jorghen,

To answer the question should I always wake him up?

No with the modification I made I just have to turn on the trainer. No need to pedal. So the problem was not a problem of waking up but probably of receiving "char"!

Here is the V.025 that I had to modify. There are 3 "While" that I had added.

I will test your V0.27.

Sincerely, Joel

/***** This is programming code for the nRF52 based Bluefruit BLE boards

The code uses heavily the Adafruit supplied Bluefruit BLE libraries !! Adafruit invests time and resources providing open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!

MIT license, check LICENSE for more information All text must be included in any redistribution *****/

/*

// ------------------------------------------------------------------------------------------- // COMPILER DIRECTIVE to allow/suppress SERIAL.PRINT messages that help debugging... // Uncomment to activate

define DEBUG

//#define DEBUG_CP_MEASUREMENT //#define DEBUG_CSC_MEASUREMENT // --------------------------------------------------------------------------------------------

include

const uint8_t MAX_PAYLOAD = 20; // Max 20 byte data size for single packet BLE transfer uint16_t client_Connection_Handle = BLE_CONN_HANDLE_INVALID;

/* Generic Access

define UUID16_SVC_GENERIC_ACCESS 0x1800

define UUID16_CHR_DEVICE_NAME 0x2A00

define UUID16_CHR_APPEARANCE 0x2A01

define UUID16_CHR_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS 0x2A04

define UUID16_CHR_CENTRAL_ADDRESS_RESOLUTION 0x2AA6

*/ BLEClientService client_GenericAccess_Service(UUID16_SVC_GENERIC_ACCESS); BLEClientCharacteristic client_GA_Appearance_Chr(UUID16_CHR_APPEARANCE); // Read uint16_t client_GA_Appearance_Value = 0; BLEClientCharacteristic client_GA_DeviceName_Chr(UUID16_CHR_DEVICE_NAME);// Read, Write unsigned char client_GA_DeviceName_Data[MAX_PAYLOAD] = {};

/* Cycling Power Service

const char* client_CP_Feature_Str[] = { "Pedal power balance supported", "Accumulated torque supported", "Wheel revolution data supported", "Crank revolution data supported", "Extreme magnitudes supported", "Extreme angles supported", "Top/bottom dead angle supported", "Accumulated energy supported", "Offset compensation indicator supported", "Offset compensation supported", "Cycling power measurement characteristic content masking supported", "Multiple sensor locations supported", "Crank length adj. supported", "Chain length adj. supported", "Chain weight adj. supported", "Span length adj. supported", "Sensor measurement context", "Instantaineous measurement direction supported", "Factory calibrated date supported", "Enhanced offset compensation supported" };

const char* client_Sensor_Location_Str[] = { "Other", "Top of shoe", "In shoe", "Hip", "Front wheel", "Left crank", "Right crank", "Left pedal", "Right pedal", "Front hub", "Rear dropout", "Chainstay", "Rear wheel", "Rear hub", "Chest", "Spider", "Chain ring"};

/*

/CSC Measurement flags/

define CSC_MEASUREMENT_WHEEL_REV_PRESENT 0x01

define CSC_MEASUREMENT_CRANK_REV_PRESENT 0x02

/ CSC Feature flags /

define CSC_FEATURE_WHEEL_REV_DATA 0x01

define CSC_FEATURE_CRANK_REV_DATA 0x02

define CSC_FEATURE_MULTIPLE_SENSOR_LOC 0x04

const char* client_CSC_Feature_Str[] = {"Wheel rev supported", "Crank rev supported", "Multiple locations supported"};

BLEClientService client_CyclingSpeedCadence_Service(UUID16_SVC_CYCLING_SPEED_AND_CADENCE); BLEClientCharacteristic client_CSC_Measurement_Chr(UUID16_CHR_CSC_MEASUREMENT); // Notify, Read BLEClientCharacteristic client_CSC_Feature_Chr(UUID16_CHR_CSC_FEATURE); // Read const uint8_t CSC_FEATURE_FIXED_DATALEN = 2; // UINT16 uint16_t client_CSC_Feature_Flags = 0; BLEClientCharacteristic client_CSC_Location_Chr(UUID16_CHR_SENSOR_LOCATION); // Read uint8_t client_CSC_Location_Value = 0;

/* Client Service Device Information

define UUID16_SVC_DEVICE_INFORMATION 0x180A

define UUID16_CHR_MODEL_NUMBER_STRING 0x2A24

define UUID16_CHR_SERIAL_NUMBER_STRING 0x2A25

define UUID16_CHR_FIRMWARE_REVISION_STRING 0x2A26

define UUID16_CHR_HARDWARE_REVISION_STRING 0x2A27

define UUID16_CHR_SOFTWARE_REVISION_STRING 0x2A28

define UUID16_CHR_MANUFACTURER_NAME_STRING 0x2A29

*/ BLEClientService client_DIS_Service(UUID16_SVC_DEVICE_INFORMATION); BLEClientCharacteristic client_DIS_ManufacturerName_Chr(UUID16_CHR_MANUFACTURER_NAME_STRING); // Read char client_DIS_Manufacturer_Str[MAX_PAYLOAD] = {}; BLEClientCharacteristic client_DIS_ModelNumber_Chr(UUID16_CHR_MODEL_NUMBER_STRING); // Read char client_DIS_ModelNumber_Str[MAX_PAYLOAD] = {}; BLEClientCharacteristic client_DIS_SerialNumber_Chr(UUID16_CHR_SERIAL_NUMBER_STRING); // Read char client_DIS_SerialNumber_Str[MAX_PAYLOAD] = {};

/*

define TIME_SPAN 2500 // Time span (delay) in millis 1000 = 1 second

define CONTROL_POINT_TIME_SPAN 2000 // Time span for sending Control Point data

unsigned long TimeInterval = 0;

// TEST DATA set ----------------------------------------------------- // Test set (Zwift Volcano Circuit) with Control and 2D Resistance data to be sent to Control Point uint8_t ControlPointMessageCount = 0; const uint8_t ControlPointData[32][8] = { {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // Request Control {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // Request Control {0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // Start or Resume {0x11,0x00,0x00,0x22,0x01,0x28,0x33,0x00}, // Set Indoor Bike Simulation Parameters.. {0x11,0x00,0x00,0x09,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x00,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x14,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x22,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x25,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x23,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x1C,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x0F,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x00,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0xF5,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0xE4,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0xCF,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0xA8,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0x84,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0x67,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0x5D,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0x5E,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0x6F,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0x8A,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0xB8,0xFF,0x28,0x33,0x00}, {0x11,0x00,0x00,0x00,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0xA2,0x00,0x28,0x33,0x00}, {0x11,0x00,0x00,0x09,0x01,0x28,0x33,0x00}, {0x11,0x00,0x00,0x4F,0x01,0x28,0x33,0x00}, {0x11,0x00,0x00,0x67,0x01,0x28,0x33,0x00}, {0x11,0x00,0x00,0x57,0xFF,0x28,0x33,0x00}, {0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // Stop or Pause {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}};// Reset // TEST DATA set ---------------------------------------------------

void setup() {

ifdef DEBUG

Serial.begin(115200); while ( !Serial ) delay(10); // for nrf52840 with native usb

Serial.println(" Feather nRF52 Client/Central: CPS, CSC and FTMS"); Serial.println("----------------- Version 02.5 ------------------"); Serial.println("Initialise the Bluefruit nRF52 module: Client (Central)");

endif

// Initialize Bluefruit module // begin (Peripheral = 0, Central = 1) Bluefruit.begin(0, 1);

Setup_Client_FTMS(); Setup_Client_CPS(); Setup_Client_CSC(); Setup_Client_DIS(); Client_Start_Scanning();

while (Bluefruit.Scanner.isRunning()) { // do nothing else but scanning.... } TimeInterval = millis() + TIME_SPAN; // ADD just enough delay // wait enough time or go on when Client/Central is connected and all set! while( TimeInterval > millis() ) { } // Scanning is finished! Are we connected? // If NO connection is established -> Stop! if( !(Bluefruit.connected()) ) {

ifdef DEBUG

Serial.println("Stopped!");

endif

return; 

} // Try to enable Client (Trainer) CPS, CSC and FTMS data streams... Client_Enable_Notify_Indicate(); if( !(Bluefruit.connected()) ) { // Are we meanwhile disconnected?

ifdef DEBUG

Serial.println("Stopped!");

endif

return;

} // After successful enable notify/indicate of all mandatory Char's continue!

ifdef DEBUG

Serial.println("Client (Central) is Up and Running!");

endif

// Set first timing for sending first set of Control Point Data TimeInterval = millis() + CONTROL_POINT_TIME_SPAN; }

void Setup_Client_FTMS(void) {
// Initialize client FTM Service client_FitnessMachine_Service.begin(); while( !(client_FitnessMachine_Service.begin()) ) { Serial.println("Wait for FitnessMachine_Service.begin "); } // Initialize client FTM Feature characteristic client_FTM_Feature_Chr.begin();

// Initialize client FTM Training Status characteristic client_FTM_TrainingStatus_Chr.setNotifyCallback(client_FTM_TrainingStatus_Notify_callback);

client_FTM_TrainingStatus_Chr.begin();

// Initialize client FTM Supported Power Range characteristic client_FTM_SupportedPowerRange_Chr.begin();

// Initialize client FTM Supported Resistance Level Range characteristic client_FTM_SupportedResistanceLevelRange_Chr.begin();

// Initialize client FTM Indoor Bike Data characteristic client_FTM_IndoorBikeData_Chr.setNotifyCallback(client_FTM_IndoorBikeData_Notify_callback); client_FTM_IndoorBikeData_Chr.begin();

// Initialize client FTM Control Point characteristic // For receiving Control Point Responses client_FTM_ControlPoint_Chr.setIndicateCallback(client_FTM_ControlPoint_Indicate_callback); client_FTM_ControlPoint_Chr.begin();

// Initialize client FTM Status characteristic client_FTM_Status_Chr.setNotifyCallback(client_FTM_Status_Notify_callback); client_FTM_Status_Chr.begin();

ifdef DEBUG

Serial.println("FTMS and Chars 'initialized'");

endif

}

void Setup_Client_CPS(void) {
// Initialize CPS client client_CyclingPower_Service.begin();

// Initialize CP Feature characteristics of client_CyclingPower_Service. client_CP_Feature_Chr.begin();

// Initialize CP sensor location characteristics of client_CyclingPower_Service. client_CP_Location_Chr.begin();

// set up callback for receiving measurement client_CP_Measurement_Chr.setNotifyCallback(client_CP_Measurement_Chr_notify_callback); client_CP_Measurement_Chr.begin();

// Initialize Control Point and set up Indicate callback for receiving responses (indicate!) client_CP_ControlPoint_Chr.setIndicateCallback(client_CP_ControlPoint_Chr_indicate_callback); client_CP_ControlPoint_Chr.begin();

ifdef DEBUG

Serial.println("CPS and Chars 'initialized'");

endif

}

void Setup_Client_CSC(void) { // Initialize CSC client client_CyclingSpeedCadence_Service.begin();

// Initialize client characteristics of CSC. client_CSC_Location_Chr.begin();

// Initialize CSC Feature characteristics of client_CSC. client_CSC_Feature_Chr.begin();

// set up callback for receiving measurement client_CSC_Measurement_Chr.setNotifyCallback(client_CSC_Measurement_Chr_notify_callback); client_CSC_Measurement_Chr.begin();

ifdef DEBUG

Serial.println("CSCS and Chars 'initialized'");

endif

}

void Setup_Client_DIS(void) { // Initialize client Generic Access Service client_GenericAccess_Service.begin(); // Initialize some characteristics of the Generic Access Service. client_GA_DeviceName_Chr.begin(); client_GA_Appearance_Chr.begin();

ifdef DEBUG

Serial.println("GA and Chars 'initialized'");

endif

// Initialize client Device Information Service client_DIS_Service.begin(); // Initialize some characteristics of the Device Information Service. client_DIS_ManufacturerName_Chr.begin(); client_DIS_ModelNumber_Chr.begin(); client_DIS_SerialNumber_Chr.begin();

ifdef DEBUG

Serial.println("DIS and Chars 'initialized'");

endif

}

void loop() {

if ( Bluefruit.connected() ) { // If time is there, send test values of Indoor Bike Simulation Parameters to // the Trainer's FTM Control Point to drive the FTM... if(millis() > TimeInterval) { if(ControlPointMessageCount > 31) { ControlPointMessageCount = 0; } // start all over again! uint8_t CPData[8] = {};

ifdef DEBUG

Serial.print("Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ ");

endif

// Transfer multidimensional test data to CPData buffer
for (int i = 0; i < sizeof(CPData); i++) {
  CPData[i] = ControlPointData[ControlPointMessageCount][i];

ifdef DEBUG

  Serial.printf("%02X ", CPData[i], HEX);

endif

}

ifdef DEBUG

Serial.println("] ");

endif

// client_FTM_ControlPoint_Chr.write(CPData, 8); client_FTM_ControlPoint_Chr.write_resp(CPData, 8); TimeInterval = millis() + CONTROL_POINT_TIME_SPAN; ControlPointMessageCount++; } // TimeInterval } // Bluefruit connected } // end loop

void Client_Start_Scanning(void) { /* Start Central Scanning

void Client_Enable_Notify_Indicate(void) { // Reaching here means we are ready to go, let's enable Chars with Indicate/Notify // ------------------------- Enable FTMS Notify and Indicate ---------------------------------------
if ( client_FTM_ControlPoint_Chr.enableIndicate() ) { // MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Control Point Response Messages");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable indicate for Client FTM Control Point Characteristic.");
Serial.println("FTMS (trainer) is controlled by another Client (Training App)!");

endif

Bluefruit.disconnect(client_Connection_Handle);
return;

}

if ( client_FTM_Status_Chr.enableNotify() ) { // MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Status values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Status Characteristic.");
Serial.println("FTMS (trainer) is controlled by another Client (Training App)!");

endif

Bluefruit.disconnect(client_Connection_Handle);
return;

}

if ( client_FTM_TrainingStatus_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Training Status values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Training Status Characteristic.");

endif

}

if ( client_FTM_IndoorBikeData_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Indoor Bike Data values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic.");

endif

} // ------------------------- Enable FTMS Notify and Indicate ---------------------------------------
// --------------------- Enable CP and CSC Notify and Indicate ------------------------------------ if ( client_CP_Measurement_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CP Measurement values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client CP Measurement Characteristic.");

endif

}

if ( client_CP_ControlPoint_Chr.enableIndicate() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CP Control Point Responses");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable indicate for Client CP Control Point Characteristic.");

endif

}

if ( client_CSC_Measurement_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CSC Measurement values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client CSC Measurement Characteristic.");

endif

} // ------------------------- Enable CP and CSC Notify and Indicate -------------------------------- }

/**

/**

ifdef DEBUG

void ParseIndoorBikeData(uint8_t data, uint16_t len) { // ---> IBD Buffer Data Length depends on data flagged to be present !!!! uint8_t IBDDataLen = (uint8_t)len; uint8_t IBDDataBuf[IBDDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw FTM Indoor Bike Data: [%d] [ ", len); for (int i = 0; i < sizeof(IBDDataBuf); i++) { IBDDataBuf[i] = data++; Serial.printf("%02X ", IBDDataBuf[i], HEX); } Serial.println("]"); uint8_t offset = 0; uint16_t flags = 0; memcpy(&flags, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable offset += 2; // UINT16 if ((flags & 1) != 0) { // More Data Serial.print("More Data!"); } // if ((flags & 2) != 0) { // (flags & 2) --> true or false Average Speed is always(?) there (tested with Elite Direto XR) // Average Speed 0.01 uint16_t sim_Speed = 0; memcpy(&sim_Speed, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Speed: %d KPH", (sim_Speed/100)); offset += 2; // UINT16 // } if ((flags & 4) != 0) { // Instantaneous Cadence 0.5 uint16_t inst_Cadence = 0; memcpy(&inst_Cadence, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Instantaneous Cadence: %d RPM", (inst_Cadence/2)); offset += 2; // UINT16 } if ((flags & 8) != 0) { // Average Cadence 0.5 uint16_t av_Cadence = 0; memcpy(&av_Cadence, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Average Cadence: %d RPM", (av_Cadence/2)); offset += 2; // UINT16 } if ((flags & 16) != 0) { // Total Distance 1 // Little endian format, transfer 24 bit to 32 bit variable uint32_t tot_Distance = 0; memcpy(&tot_Distance, &IBDDataBuf[offset], 3); // Transfer buffer fields to variable Serial.printf(" Total Distance: %d m", tot_Distance); offset += 3; // UINT24 16 + 8 } if ((flags & 32) != 0) { // Resistance Level 1 uint16_t res_Level = 0; memcpy(&res_Level, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Resistance Level: %d ", res_Level); offset += 2; // UINT16 } if ((flags & 64) != 0) { // Instantaneous Power 1 uint16_t inst_Power = 0; memcpy(&inst_Power, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Instantaneous Power: %d Watt", inst_Power); offset += 2; // UINT16 } if ((flags & 128) != 0) { // Average Power 1 uint16_t av_Power = 0; memcpy(&av_Power, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Average Power: %d Watt", av_Power); offset += 2; // UINT16 } if ((flags & 256) != 0) { // Expended Energy -> UINT16 UINT16 UINT8 // Total Energy UINT16 1 uint16_t tot_Energy = 0; memcpy(&tot_Energy, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Tot. Energy: %d kCal", tot_Energy); offset += 2; // UINT16 // Energy per hour UINT16 1 uint16_t Energy_hr = 0; memcpy(&Energy_hr, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Energy/hr: %d kCal/hr", Energy_hr); offset += 2; // UINT16 // Energy per minute UINT8 1 uint8_t Energy_pm = 0; memcpy(&Energy_pm, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Energy/m: %d kCal/m", Energy_pm); offset += 1; // UINT8 } if ((flags & 512) != 0) { // Heart Rate 1 uint8_t Heart_Rate = 0; memcpy(&Heart_Rate, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Heart Rate: %d HBM", Heart_Rate); offset += 1; // UINT8 } if ((flags & 1024) != 0) { // Metabolic Equivalent 0.1 uint8_t Mets = 0; memcpy(&Mets, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Metabolic Equivalent: %d ", Mets/10); offset += 1; // UINT8 } if ((flags & 2048) != 0) { // Elapsed Time 1 uint16_t elap_time = 0; memcpy(&elap_time, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Elapsed time: %d s", elap_time); offset += 2; // UINT16 } if ((flags & 4096) != 0) { // Remaining Time 1 uint16_t rem_time = 0; memcpy(&rem_time, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Remaining time: %d s", rem_time); offset += 2; // UINT16 } Serial.println(); }

endif

/**

/**

/**

ifdef DEBUG

void PrintPeerAddress(uint8_t addr[6]) { for (int i = 1; i < 6; i++) { // Display byte by byte in HEX reverse: little Endian Serial.printf("%02X:",addr[(6-i)], HEX); } Serial.printf("%02X ",addr[0], HEX); }

endif

/**

while (!(client_GenericAccess_Service.discover(conn_handle))) { if ( client_GenericAccess_Service.discover(conn_handle) ) {

ifdef DEBUG

  Serial.print(F("Found Client Generic Access\n"));

endif

  if ( client_GA_DeviceName_Chr.discover() ) {
     client_GA_DeviceName_Chr.read(client_GA_DeviceName_Data, sizeof(client_GA_DeviceName_Data));

ifdef DEBUG

    Serial.printf(" -> Client Reads Device Name:   [%s]\n", client_GA_DeviceName_Data);

endif

  }     
  if ( client_GA_Appearance_Chr.discover() ) {
     client_GA_Appearance_Value = client_GA_Appearance_Chr.read16();

ifdef DEBUG

    Serial.printf(" -> Client Reads Appearance:    [%d]\n", client_GA_Appearance_Value);

endif

  }     

} // GA }
while (!( client_DIS_Service.discover(conn_handle) )){ // If DIS is not found then go on.... NOT FATAL ! if ( client_DIS_Service.discover(conn_handle) ) {

ifdef DEBUG

Serial.print(F("Found Client Device Information\n"));

endif

//  1
if ( client_DIS_ManufacturerName_Chr.discover() ) {
  // read and print out Manufacturer
    if ( client_DIS_ManufacturerName_Chr.read(client_DIS_Manufacturer_Str, sizeof(client_DIS_Manufacturer_Str)) ) {

ifdef DEBUG

    Serial.printf(" -> Client Reads Manufacturer:  [%s]\n", client_DIS_Manufacturer_Str);

endif

  }
} // 1
//  2
if ( client_DIS_ModelNumber_Chr.discover() ) {
  // read and print out Model Number
  if ( client_DIS_ModelNumber_Chr.read(client_DIS_ModelNumber_Str, sizeof(client_DIS_ModelNumber_Str)) ) { 

ifdef DEBUG

    Serial.printf(" -> Client Reads Model Number:  [%s]\n", client_DIS_ModelNumber_Str);

endif

  }
} // 2
//  3
if ( client_DIS_SerialNumber_Chr.discover() ) {
  // read and print out Serial Number
  if ( client_DIS_SerialNumber_Chr.read(client_DIS_SerialNumber_Str, sizeof(client_DIS_SerialNumber_Str)) ) {

ifdef DEBUG

    Serial.printf(" -> Client Reads Serial Number: [%s]\n", client_DIS_SerialNumber_Str);

endif

  }
} // 3

} // DIS }

// ---------------------------- END GA and DIS SERVICE ------------------------------------------------

// -----------------------------FTM SERVICE ------------------------------------------------------------

ifdef DEBUG

Serial.print("Discovering Mandatory Client Fitness Machine (FTM) Service ... ");

endif

// If FTM is not found, disconnect, resume scanning, and return if ( client_FitnessMachine_Service.discover(conn_handle) ) {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle);
uint16_t max_payload = conn->getMtu()-3;
uint16_t data_length = conn->getDataLength();
Serial.print("Found it! ");
Serial.printf("FTMS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Service is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

}

ifdef DEBUG

Serial.print("Discovering Client FTM Feature Characteristic ... ");

endif

// If FTM Feature is not found, disconnect, resume scanning, and return while (!( client_FTM_Feature_Chr.discover() )) { if ( client_FTM_Feature_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read FTM Feature Data
client_FTM_Feature_Chr.read(client_FTM_Feature_Data, 8);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Feature bytes: [8] [ ");
for (int i = 0; i < sizeof(client_FTM_Feature_Data); i++) {
    Serial.printf("%02X ", client_FTM_Feature_Data[i], HEX);
} // for
Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Disconnecting since Client FTM Feature Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
Bluefruit.Connection(conn_handle);
Serial.print("Discovering Client FTM Feature not decouvert ... ");

// return; } }

ifdef DEBUG

Serial.print("Discovering Client FTM Control Point Characteristic ... ");

endif

// If FTM Control Point is not found, disconnect, resume scanning, and return if ( client_FTM_ControlPoint_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Control Point Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

}

ifdef DEBUG

Serial.print("Discovering Client FTM Status Characteristic ... ");

endif

// If FTM Status is not found, disconnect, resume scanning, and return if ( client_FTM_Status_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Status Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

}

ifdef DEBUG

Serial.print("Discovering Client FTM Training Status Characteristic ... ");

endif

// FTM Training Status is NOT MANDATORY if ( client_FTM_TrainingStatus_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory");

endif

} /*

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

*/

ifdef DEBUG

Serial.print("Discovering Client FTM Supported Resistance Level Range Characteristic ... ");

endif

// FTM SupportedResistanceLevelRange is not mandatory! if ( client_FTM_SupportedResistanceLevelRange_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read Supported Resistance Level Range Data
client_FTM_SupportedResistanceLevelRange_Chr.read(client_FTM_SupportedResistanceLevelRange_Data, 6);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ ");
for (int i = 0; i < sizeof(client_FTM_SupportedResistanceLevelRange_Data); i++) {
    Serial.printf("%02X ", client_FTM_SupportedResistanceLevelRange_Data[i], HEX);
} // for
Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT mandatory!"); 

endif

} / Serial.println("Disconnecting since Client FTM Supported Resistance Level Range Characteristic is mandatory!"); // MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return; /

ifdef DEBUG

Serial.print("Discovering Client FTM Supported Power Range Characteristic ... ");

endif

// FTM SupportedPowerRange is not mandatory! if ( client_FTM_SupportedPowerRange_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read Supported Resistance Level Range values
client_FTM_SupportedPowerRange_Chr.read(client_FTM_SupportedPowerRange_Data, 6);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Supported Power Range bytes: [6] [ ");
for (int i = 0; i < sizeof(client_FTM_SupportedPowerRange_Data); i++) {
    Serial.printf("%02X ", client_FTM_SupportedPowerRange_Data[i], HEX);
} // for
Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT mandatory!"); 

endif

} /*

ifdef DEBUG

Serial.println("Disconnecting since Client FTM Supported Power Range Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

*/

ifdef DEBUG

Serial.print("Discovering Client FTM Indoor Bike Data Characteristic ... ");

endif

// FTM Indoor Bike Data is not mandatory if ( client_FTM_IndoorBikeData_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory"); 

endif

} /*

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Indoor Bike Data Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

*/ // ---------------------------- End FTM SERVICE --------------------------------------------- // ---------------------------- CP SERVICE --------------------------------------------------

ifdef DEBUG

Serial.print("Discovering Client Cycling Power (CP) Service ... ");

endif

// If CPS is not found, disconnect, resume scanning, and return if ( client_CyclingPower_Service.discover(conn_handle) ) {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle);
uint16_t max_payload = conn->getMtu()-3;
uint16_t data_length = conn->getDataLength();
Serial.print("Found it! ");
Serial.printf("CPS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client Cyling Power Service is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

}

ifdef DEBUG

Serial.print("Discovering Client CP Measurement characteristic ... ");

endif

if ( !client_CP_Measurement_Chr.discover() ) { // Measurement chr is mandatory, if it is not found (valid), then disconnect

ifdef DEBUG

Serial.println("Not Found!");  
Serial.println("Disconnecting since Client CP Measurement Characteristic is mandatory!");

endif

Bluefruit.disconnect(conn_handle);
return;

} else {

ifdef DEBUG

Serial.println("Found it!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Control Point characteristic ... ");

endif

if ( client_CP_ControlPoint_Chr.discover() ) { // CP Control Point chr is not mandatory

ifdef DEBUG

Serial.println("Found it!");  

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Feature characteristic ... ");

endif

if ( client_CP_Feature_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Configure the Cycle Power Feature characteristic // Properties = Read // Min Len = 1 // Max Len = 32 // B0:3 = UINT8 - Cycling Power Feature (MANDATORY) // b0 = Pedal power balance supported; 0 = false, 1 = true // b1 = Accumulated torque supported; 0 = false, 1 = true // b2 = Wheel revolution data supported; 0 = false, 1 = true // b3 = Crank revolution data supported; 0 = false, 1 = true // b4 = Extreme magnatudes supported; 0 = false, 1 = true // b5 = Extreme angles supported; 0 = false, 1 = true // b6 = Top/bottom dead angle supported; 0 = false, 1 = true // b7 = Accumulated energy supported; 0 = false, 1 = true // b8 = Offset compensation indicator supported; 0 = false, 1 = true // b9 = Offset compensation supported; 0 = false, 1 = true // b10 = Cycling power measurement characteristic content masking supported; 0 = false, 1 = true // b11 = Multiple sensor locations supported; 0 = false, 1 = true // b12 = Crank length adj. supported; 0 = false, 1 = true // b13 = Chain length adj. supported; 0 = false, 1 = true // b14 = Chain weight adj. supported; 0 = false, 1 = true // b15 = Span length adj. supported; 0 = false, 1 = true // b16 = Sensor measurement context; 0 = force, 1 = torque // b17 = Instantaineous measurement direction supported; 0 = false, 1 = true // b18 = Factory calibrated date supported; 0 = false, 1 = true // b19 = Enhanced offset compensation supported; 0 = false, 1 = true // b20:21 = Distribtue system support; 0 = legacy, 1 = not supported, 2 = supported, 3 = RFU // b22:32 = Reserved

// Read 32-bit client_CP_Feature_Chr value client_CP_Feature_Flags = client_CP_Feature_Chr.read32();

ifdef DEBUG

const uint8_t CPFC_FIXED_DATALEN = 4; uint8_t cpfcData[CPFC_FIXED_DATALEN] = {(uint8_t)(client_CP_Feature_Flags & 0xff), (uint8_t)(client_CP_Feature_Flags >> 8), (uint8_t)(client_CP_Feature_Flags >> 16), (uint8_t)(client_CP_Feature_Flags >> 24)}; Serial.print(" -> Client Reads Raw CP Feature bytes: [4] [ "); for (int i = 0; i < CPFC_FIXED_DATALEN; i++) { if ( i <= sizeof(cpfcData)) { Serial.printf("%02X ", cpfcData[i], HEX); } } Serial.println("] "); for (int i = 0; i < sizeof(client_CP_Feature_Str); i++) { if ( client_CP_Feature_Flags & (1 << i) ) { Serial.println(client_CP_Feature_Str[i]); } }

endif

} else {

ifdef DEBUG

Serial.println("NOT Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Sensor Location characteristic ... ");

endif

if ( client_CP_Location_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// The Sensor Location characteristic // Properties = Read // Min Len = 1 // Max Len = 1 // B0:1 = UINT8 - Sensor Location

// Read 8-bit client CP sensor location value
client_CP_Location_Value = client_CP_Location_Chr.read8();   

ifdef DEBUG

Serial.print(" -> Client Reads CP Location Sensor: ");
Serial.printf("Loc#: %d %s\n", client_CP_Location_Value, client_Sensor_Location_Str[client_CP_Location_Value]);

endif

} else {

ifdef DEBUG

Serial.println("NOT Found! NOT Mandatory!");

endif

} // ---------------------------- END CP SERVICE ------------------------------------------------ // ---------------------------- CSC SERVICE --------------------------------------------------

ifdef DEBUG

Serial.print("Discovering Cycling Speed and Cadence (CSC) Service ... ");

endif

if ( client_CyclingSpeedCadence_Service.discover(conn_handle) ) // UUID16_SVC_CYCLING_SPEED_AND_CADENCE {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle);
uint16_t max_payload = conn->getMtu()-3;
uint16_t data_length = conn->getDataLength();
Serial.print("Found it! ");
Serial.printf("CSCS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found! CSC Service is Not Mandatory!");

endif

return; // NO CSC -> end of client_connect_callback !!   

} /* // Is Mandatory

ifdef DEBUG

Serial.println("Not Found and disconnecting!"); 
Serial.println("CSC Service is mandatory!");

endif

Bluefruit.disconnect(conn_handle);
return;

*/

// Test for client CSC Characteristics when the client CSC Service is existing

ifdef DEBUG

Serial.print("Discovering Client CSC Measurement CHR ... ");

endif

if ( client_CSC_Measurement_Chr.discover() ) // UUID16_CHR_CSC_MEASUREMENT {

ifdef DEBUG

Serial.println("Found it! ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory!"); 

endif

} /* // Is Mandatory

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client CSC Measurement CHR is mandatory!");

endif

Bluefruit.disconnect(conn_handle);
return;

*/

ifdef DEBUG

Serial.print("Discovering Client CSC Location CHR ... ");

endif

if ( client_CSC_Location_Chr.discover() ) // UUID16_CHR_SENSOR_LOCATION {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read 16-bit client CSC sensor location value
client_CSC_Location_Value = client_CSC_Location_Chr.read8();

ifdef DEBUG

Serial.print(" -> Client Reads CSC Location Sensor: ");
Serial.printf("Loc#: %d %s\n", client_CSC_Location_Value, client_Sensor_Location_Str[client_CSC_Location_Value]);

endif

} else {

ifdef DEBUG

  Serial.println("Not Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CSC Feature CHR ... ");

endif

if ( client_CSC_Feature_Chr.discover() ) // UUID16_CHR_CSC_FEATURE {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read sensor CSC Feature value in 16 bit
client_CSC_Feature_Flags = client_CSC_Feature_Chr.read16();

ifdef DEBUG

uint8_t cscfcData[CSC_FEATURE_FIXED_DATALEN] = { (uint8_t)(client_CSC_Feature_Flags & 0xff), (uint8_t)(client_CSC_Feature_Flags >> 8) }; //  Little Endian Representation
Serial.printf(" -> Client Reads Raw CSC Feature bytes: [2] [ ");
for (int i = 0; i < sizeof(cscfcData); i++) {
  Serial.printf("%02X ", cscfcData[i], HEX);
}
Serial.println("] ");
for (int i = 0; i < sizeof(client_CSC_Feature_Str); i++) {
if ( (client_CSC_Feature_Flags & (1 << i)) != 0 )
  {
   Serial.println(client_CSC_Feature_Str[i]);
  }
}

endif

} else {

ifdef DEBUG

  Serial.println("Not Found! NOT Mandatory!");

endif

} // ---------------------------- END CSC SERVICE --------------------------------------------- } // End client_connect_callback

/**

/**

/**

// Handle the response message

ifdef DEBUG

uint8_t cpcpDataLen = (uint8_t)len; uint8_t cpcpData[cpcpDataLen]= {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw CP Control Point Data: [%d] [ ", len); for (int i = 0; i < sizeof(cpcpData); i++) { cpcpData[i] = *data++; Serial.printf("%02X ", cpcpData[i], HEX); } Serial.print("] ");

endif

}

/**

le-joebar commented 1 year ago

Dear Jörghen,

Here is the disappointing result.

The problem is still the same no feedback with V0.27

Let's not lose heart!

123456789101112131415161718192021 /***** This is programming code for the nRF52 based Bluefruit BLE boards

The code uses heavily the Adafruit supplied Bluefruit BLE libraries !! Adafruit invests time and resources providing open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!

MIT license, check LICENSE for more information All text must be included in any redistribution

Message (Enter to send message to 'Adafruit ItsyBitsy nRF52840 Express' on 'COM11') New Line 115200 baud 16:59:01.080 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:59:01.080 -> ----------------- Version 02.7 ------------------ 16:59:01.080 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:59:01.205 -> FTMS and Chars 'initialized' 16:59:01.205 -> CPS and Chars 'initialized' 16:59:01.205 -> CSCS and Chars 'initialized' 16:59:01.205 -> GA and Chars 'initialized' 16:59:01.205 -> DIS and Chars 'initialized' 16:59:01.205 -> Start Scanning for CPS, CSC and FTMS! 16:59:01.434 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:59:01.434 -> Timestamp MAC Address Rssi Data 16:59:01.434 -> 000091471 F8:9C:FC:53:5E:49 -59 09-02-16-18-26-18-18-18-0A-18 16:59:01.575 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 16:59:01.575 -> Now checking all Client Services and Characteristics! 16:59:01.575 -> If Mandatory Services Fail --> the Client will disconnect! 16:59:01.575 -> First checking Generic Access and Device Information Services and Characteristics! 16:59:01.668 -> Found Client Generic Access 16:59:01.808 -> -> Client Reads Device Name: [Zwift Hub] 16:59:02.042 -> -> Client Reads Appearance: [0] 16:59:02.042 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 16:59:02.042 -> Disconnecting since Client FTM Service is mandatory! 16:59:02.121 -> Client Disconnected, reason = 0x16 16:59:02.121 -> >>> Restart the Feather nRF52 Client for a new run! <<< 16:59:12.257 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:59:12.257 -> ----------------- Version 02.7 ------------------ 16:59:12.257 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:59:12.257 -> FTMS and Chars 'initialized' 16:59:12.257 -> CPS and Chars 'initialized' 16:59:12.257 -> CSCS and Chars 'initialized' 16:59:12.257 -> GA and Chars 'initialized' 16:59:12.257 -> DIS and Chars 'initialized' 16:59:12.257 -> Start Scanning for CPS, CSC and FTMS! 16:59:12.258 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:59:12.258 -> Timestamp MAC Address Rssi Data 16:59:12.258 -> 000001100 F8:9C:FC:53:5E:49 -55 09-02-16-18-26-18-18-18-0A-18 16:59:12.258 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 16:59:12.258 -> Now checking all Client Services and Characteristics! 16:59:12.258 -> If Mandatory Services Fail --> the Client will disconnect! 16:59:12.258 -> First checking Generic Access and Device Information Services and Characteristics! 16:59:12.266 -> Found Client Generic Access 16:59:12.266 -> -> Client Reads Device Name: [Zwift Hub] 16:59:12.266 -> -> Client Reads Appearance: [1152] 16:59:12.266 -> Found Client Device Information 16:59:12.266 -> -> Client Reads Manufacturer: [Zwift]

le-joebar commented 1 year ago

Here is the result of FTMS_Zwift_Bridge_v023:

17:15:10.800 -> Feather nRF52840 MITM supporting: CPS, CSC and FTMS 17:15:10.800 -> ------------------ Version 02.3 --------------------- 17:15:10.804 -> FTM Service and Chars are 'initialized' 17:15:10.804 -> CP Service and Chars are 'initialized' 17:15:10.804 -> CSC Service and Chars are 'initialized' 17:15:10.804 -> Generic Access Service and Chars are 'initialized' 17:15:10.804 -> Device Information Service and Chars are 'initialized' 17:15:10.804 -> Start Client-side Scanning for CPS, CSC and FTMS! 17:15:10.805 -> Found advertising Peripheral with FTMS enabled! See Raw data packet: 17:15:10.805 -> Timestamp Addr Rssi Data 17:15:10.805 -> 000001606 F8:9C:FC:53:5E:49 -55 09-02-16-18-26-18-18-18-0A-18 17:15:10.805 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:15:10.805 -> Now checking all mandatory Client Services and Characteristics! 17:15:10.805 -> If Mandatory Services Fail --> the Client will disconnect! 17:15:10.805 -> First checking Generic Access and Device Information Services and Characteristics! 17:15:10.828 -> Found Client Generic Access 17:15:10.828 -> -> Client Reads Device Name: [Zwift Hub] 17:15:10.828 -> -> Client Reads Appearance: [1152] 17:15:10.828 -> Found Client Device Information 17:15:10.828 -> -> Client Reads Manufacturer: [Zwift] 17:15:10.829 -> -> Client Reads Model Number: [06] 17:15:10.920 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:15:10.920 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:15:11.008 -> Discovering Client FTM Feature Characteristic ... Found it! 17:15:11.124 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 17:15:11.124 -> Discovering Client FTM Control Point Characteristic ... Found it! 17:15:11.703 -> Discovering Client FTM Status Characteristic ... Found it! 17:15:11.984 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 17:15:12.285 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 17:15:12.402 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 17:15:12.402 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 17:15:12.742 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 00 00 00 00 ] 17:15:12.742 -> Discovering Client FTM Indoor Bike Data Characteristic ... Not Found! Not Mandatory 17:15:12.742 -> Discovering Client Cycling Power (CP) Service ... Not Found! 17:15:12.742 -> Disconnecting since Client Cyling Power Service is mandatory! 17:15:12.834 -> Client disconnected from Peripheral Device: [Zwift Hub], reason: [16] 17:15:27.560 -> Feather nRF52840 MITM supporting: CPS, CSC and FTMS 17:15:27.560 -> ------------------ Version 02.3 --------------------- 17:15:27.822 -> FTM Service and Chars are 'initialized' 17:15:27.822 -> CP Service and Chars are 'initialized' 17:15:27.822 -> CSC Service and Chars are 'initialized' 17:15:27.822 -> Generic Access Service and Chars are 'initialized' 17:15:27.822 -> Device Information Service and Chars are 'initialized' 17:15:27.822 -> Start Client-side Scanning for CPS, CSC and FTMS! 17:15:27.836 -> Found advertising Peripheral with FTMS enabled! See Raw data packet: 17:15:27.836 -> Timestamp Addr Rssi Data 17:15:27.836 -> 000001270 F8:9C:FC:53:5E:49 -60 09-02-16-18-26-18-18-18-0A-18 17:15:27.836 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:15:27.836 -> Now checking all mandatory Client Services and Characteristics! 17:15:27.836 -> If Mandatory Services Fail --> the Client will disconnect! 17:15:27.836 -> First checking Generic Access and Device Information Services and Characteristics!

le-joebar commented 1 year ago

I'll see if with the "While" in the "Bridge V23" version if it's better

The cadence is OK but I don't have the Watts!?

20221215_181851

Here is the modified code and the results :

/***** This is programming code for the nRF52 based Bluefruit BLE boards

The code uses heavily the Adafruit supplied Bluefruit BLE libraries !! Adafruit invests time and resources providing open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!

    MIT license, check LICENSE for more information
    All text must be included in any redistribution

*****/

/* ----------------------------------------------------------------------------------------------------- This code should work with all indoor cycling trainers that fully support, Fitness Machine Service, Cycling Power Service and Cycling Speed & Cadence Service

The code links a BLE Server (a peripheral to Zwift) and a BLE Client (a central to the Trainer) with a bridge
in between, the Feather nRF52 being man-in-the-middle (MITM).
The nRF52-bridge can control, filter and alter the bi-directional interchanged data!
The client-side (central) scans and connects with the trainer relevant services: FTMS, CPS and CSC. It collects
all cyling data of the services and passes these on to the server-side....
The client-side supplies the indoor trainer with target and resistance control data.
The server-side (peripheral) advertises and enables connection with cycling apps like Zwift and collects the app's
control commands, target and resistance data. It passes these on to the client-side....
The server-side supplies the app with the generated cycling data in return.

The client plus server (MITM) are transparent to the indoor trainer as well as to the training app Zwift or alike!

Requirements: Zwift app or alike, Feather nRF52 board and a FTMS/CPS/CSC supporting indoor trainer
1) Upload and Run this code on the Feather nRF52
2) Start the Serial Monitor to catch debugging info
3) Start/Power On the indoor trainer
4) Feather nRF52 and trainer (with <name>) will pair as reported in the output
5) Start Zwift on your computer or tablet and wait....
6) Search on the Zwift pairing screens for the Feather nRF52 a.k.a. "Sim <name>"
7) Pair: Power, Cadence and Controllable one after another with "Sim <name>"
8) Optionally one can pair as well devices for heartrate and/or steering (Sterzo)
9) Start the default Zwift ride or any ride you wish

10) Make Serial Monitor output window visible on top of the Zwift window 11) Hop on the bike: do the work and feel resistance change with the road 12) Inspect the info presented by Serial Monitor.....

Your trainer's device <name> is modified by the bridge to "Sim <name>", to allow for a clear distinction
between the bridge (simulating your trainer) and your original trainer, when advertising the trainer's services!
You will notice this only when connecting to Zwift on the pairing screens! Notice: Zwift extends device names with
additional numbers for identification!

*/

// ------------------------------------------------------------------------------------------- // COMPILER DIRECTIVE to allow/suppress SERIAL.PRINT messages that help debugging... // Uncomment to activate

define DEBUG

// Restrict activating one or more of the following DEBUG directives --> process intensive // Have caused spurious side effects like a loss of quality of service handling!! //#define DEBUG_CP_MEASUREMENT //#define DEBUG_CSC_MEASUREMENT //#define DEBUG_FTM_INDOORBIKEDATA // --------------------------------------------------------------------------------------------

include

const uint8_t MAX_PAYLOAD = 20; // Max 20 byte data size for single packet BLE transfer

// Struct containing Device info to administer dis/connected devices typedef struct { uint8_t PeerAddress[6]; char PeerName[MAX_PAYLOAD]; uint16_t conn_handle; bool IsConnected; } Device_info_t; // ----------------------------------------------------------------- // Your hardware MAC/DEVICE ADDRESSES // Laptop/Desktop Device Address that runs Zwift, in printed format: [00:01:02:03:04:05] // Little Endian: in reversed order !!!!

define LAPTOPADDRESS {0x18,0x52,0x53,0x22,0x11,0x58}

// Trainer FTMS enabled Device Address, in printed format: [00:01:02:03:04:05] // Little Endian: in reversed order !!!!

define TRAINERADDRESS {0x49,0x5E,0x53,0xFC,0x9C,0xF8}

// ----------------------------------------------------------------- // Initialize connectable device registration Device_info_t Trainer = {TRAINERADDRESS, {0x00}, BLE_CONN_HANDLE_INVALID, false}; Device_info_t Laptop = { LAPTOPADDRESS, {0x00}, BLE_CONN_HANDLE_INVALID, false}; Device_info_t Smartphone = { {0x00}, {0x00}, BLE_CONN_HANDLE_INVALID, false}; // ----------------------------------------------------------------------------------

/* Generic Access

define UUID16_SVC_GENERIC_ACCESS 0x1800

define UUID16_CHR_DEVICE_NAME 0x2A00

define UUID16_CHR_APPEARANCE 0x2A01

define UUID16_CHR_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS 0x2A04 ---> not implemented

define UUID16_CHR_CENTRAL_ADDRESS_RESOLUTION 0x2AA6 ---> not implemented

*/ BLEClientService client_GenericAccess_Service(UUID16_SVC_GENERIC_ACCESS); // Optional BLEClientCharacteristic client_GA_Appearance_Chr(UUID16_CHR_APPEARANCE); // Read uint16_t client_GA_Appearance_Value = 0; BLEClientCharacteristic client_GA_DeviceName_Chr(UUID16_CHR_DEVICE_NAME); // Read, Write unsigned char client_GA_DeviceName_Data[MAX_PAYLOAD] = {};

/ Cycling Power Service CP Service: 0x1818 CP Characteristic: 0x2A63 (Measurement) CP Characteristic: 0x2A65 (Feature) CP Characteristic: 0x2A5D (Location) CP Characteristic: 0x2A66 (Control Point) / BLEClientService client_CyclingPower_Service(UUID16_SVC_CYCLING_POWER); // Mandatory BLEClientCharacteristic client_CP_Measurement_Chr(UUID16_CHR_CYCLING_POWER_MEASUREMENT); // Notify, Read, Mandatory BLEClientCharacteristic client_CP_Feature_Chr(UUID16_CHR_CYCLING_POWER_FEATURE); // Read, optional uint32_t client_CP_Feature_Flags = 0; const uint8_t CP_FEATURE_DATALEN = 4; // Set MaxLen to 4 const char client_CP_Feature_Str[] = { "Pedal power balance supported", "Accumulated torque supported", "Wheel revolution data supported", "Crank revolution data supported", \ "Extreme magnitudes supported", "Extreme angles supported", "Top/bottom dead angle supported", "Accumulated energy supported", \ "Offset compensation indicator supported", "Offset compensation supported", "Cycling power measurement characteristic content masking supported", \ "Multiple sensor locations supported", "Crank length adj. supported", "Chain length adj. supported", "Chain weight adj. supported", \ "Span length adj. supported", "Sensor measurement context", "Instantaineous measurement direction supported", "Factory calibrated date supported", \ "Enhanced offset compensation supported" }; BLEClientCharacteristic client_CP_Location_Chr(UUID16_CHR_SENSOR_LOCATION); // Read, optional uint8_t client_CP_Location_Value = 0; // UINT8 const char client_Sensor_Location_Str[] = { "Other", "Top of shoe", "In shoe", "Hip", "Front wheel", "Left crank", "Right crank", "Left pedal", \ "Right pedal", "Front hub", "Rear dropout", "Chainstay", "Rear wheel", "Rear hub", "Chest", "Spider", "Chain ring" }; BLEClientCharacteristic client_CP_ControlPoint_Chr(UUID16_CHR_CYCLING_POWER_CONTROL_POINT); // Indicate, Write, optional const uint16_t CP_CONTROL_POINT_DATALEN = 5;

/ Cycling Speed and Cadence Service CSC Service: 0x1816 CSC Measurement Characteristic: 0x2A5B CSC Feature Characteristic: 0x2A5C CSC Location Characteristic: 0x2A5D CSC Control Point Characteristic:0x2A55 ---> not implemented / BLEClientService client_CyclingSpeedCadence_Service(UUID16_SVC_CYCLING_SPEED_AND_CADENCE); // Mandatory BLEClientCharacteristic client_CSC_Measurement_Chr(UUID16_CHR_CSC_MEASUREMENT); // Notify, Read, Mandatory BLEClientCharacteristic client_CSC_Feature_Chr(UUID16_CHR_CSC_FEATURE); // Read, optional const uint8_t CSC_FEATURE_FIXED_DATALEN = 2; // UINT16 uint16_t client_CSC_Feature_Flags = 0; const char* client_CSC_Feature_Str[] = {"Wheel rev supported", "Crank rev supported", "Multiple locations supported"}; BLEClientCharacteristic client_CSC_Location_Chr(UUID16_CHR_SENSOR_LOCATION); // Read, optional uint8_t client_CSC_Location_Value = 0; // Shared with CPS --> client_Sensor_Location_Str[]

/* Service Device Information

define UUID16_SVC_DEVICE_INFORMATION 0x180A

define UUID16_CHR_MODEL_NUMBER_STRING 0x2A24

define UUID16_CHR_SERIAL_NUMBER_STRING 0x2A25

define UUID16_CHR_FIRMWARE_REVISION_STRING 0x2A26 ---> not implemented

define UUID16_CHR_HARDWARE_REVISION_STRING 0x2A27 ---> not implemented

define UUID16_CHR_SOFTWARE_REVISION_STRING 0x2A28 ---> not implemented

define UUID16_CHR_MANUFACTURER_NAME_STRING 0x2A29

*/ BLEClientService client_DIS_Service(UUID16_SVC_DEVICE_INFORMATION); // Optional BLEClientCharacteristic client_DIS_ManufacturerName_Chr(UUID16_CHR_MANUFACTURER_NAME_STRING); // Read char client_DIS_Manufacturer_Str[MAX_PAYLOAD] = {}; BLEClientCharacteristic client_DIS_ModelNumber_Chr(UUID16_CHR_MODEL_NUMBER_STRING); // Read char client_DIS_ModelNumber_Str[MAX_PAYLOAD] = {}; BLEClientCharacteristic client_DIS_SerialNumber_Chr(UUID16_CHR_SERIAL_NUMBER_STRING); // Read char client_DIS_SerialNumber_Str[MAX_PAYLOAD] = {};

/* Fitness Machine Service

define UUID16_SVC_FITNESS_MACHINE 0x1826

define UUID16_CHR_FITNESS_MACHINE_FEATURE 0x2ACC

define UUID16_CHR_INDOOR_BIKE_DATA 0x2AD2

define UUID16_CHR_TRAINING_STATUS 0x2AD3

define UUID16_CHR_SUPPORTED_SPEED_RANGE 0x2AD4 ---> not implemented

define UUID16_CHR_SUPPORTED_INCLINATION_RANGE 0x2AD5 ---> not implemented

define UUID16_CHR_SUPPORTED_RESISTANCE_LEVEL_RANGE 0x2AD6

define UUID16_CHR_SUPPORTED_HEART_RATE_RANGE 0x2AD7 ---> not implemented

define UUID16_CHR_SUPPORTED_POWER_RANGE 0x2AD8

define UUID16_CHR_FITNESS_MACHINE_CONTROL_POINT 0x2AD9

define UUID16_CHR_FITNESS_MACHINE_STATUS 0x2ADA

*/ BLEClientService client_FitnessMachine_Service(UUID16_SVC_FITNESS_MACHINE); // Mandatory // Service characteristics exposed by FTM Service BLEClientCharacteristic client_FTM_Feature_Chr(UUID16_CHR_FITNESS_MACHINE_FEATURE); // Mandatory, Read const uint8_t FTM_FEATURE_FIXED_DATALEN = 8; uint8_t client_FTM_Feature_Data[FTM_FEATURE_FIXED_DATALEN]; BLEClientCharacteristic client_FTM_IndoorBikeData_Chr(UUID16_CHR_INDOOR_BIKE_DATA); // Optional, Notify BLEClientCharacteristic client_FTM_TrainingStatus_Chr(UUID16_CHR_TRAINING_STATUS); // Optional, Read & Notify BLEClientCharacteristic client_FTM_SupportedResistanceLevelRange_Chr(UUID16_CHR_SUPPORTED_RESISTANCE_LEVEL_RANGE); // Mandatory, Read const uint8_t FTM_SRLR_FIXED_DATALEN = 6; uint8_t client_FTM_SupportedResistanceLevelRange_Data[FTM_SRLR_FIXED_DATALEN]; BLEClientCharacteristic client_FTM_SupportedPowerRange_Chr(UUID16_CHR_SUPPORTED_POWER_RANGE); // Mandatory, Read const uint8_t FTM_SPR_FIXED_DATALEN = 6; uint8_t client_FTM_SupportedPowerRange_Data[FTM_SPR_FIXED_DATALEN]; BLEClientCharacteristic client_FTM_ControlPoint_Chr(UUID16_CHR_FITNESS_MACHINE_CONTROL_POINT); // Mandatory, Write & Indicate BLEClientCharacteristic client_FTM_Status_Chr(UUID16_CHR_FITNESS_MACHINE_STATUS); // Mandatory, Notify

// ------------------------------------ START of SERVER DEFINITIONS ----------------------------------------------------- / Cycling Speed and Cadence Service / BLEService server_CyclingSpeedCadence_Service = BLEService(UUID16_SVC_CYCLING_SPEED_AND_CADENCE); BLECharacteristic server_CSC_Measurement_Chr = BLECharacteristic(UUID16_CHR_CSC_MEASUREMENT); // Notify, Read BLECharacteristic server_CSC_Feature_Chr = BLECharacteristic(UUID16_CHR_CSC_FEATURE); // Read BLECharacteristic server_CSC_Location_Chr = BLECharacteristic(UUID16_CHR_SENSOR_LOCATION); // Read

/ Cycling Power Service / BLEService server_CylingPower_Service = BLEService(UUID16_SVC_CYCLING_POWER); BLECharacteristic server_CP_Measurement_Chr = BLECharacteristic(UUID16_CHR_CYCLING_POWER_MEASUREMENT); // Notify, Read BLECharacteristic server_CP_Feature_Chr = BLECharacteristic(UUID16_CHR_CYCLING_POWER_FEATURE); // Read BLECharacteristic server_CP_Location_Chr = BLECharacteristic(UUID16_CHR_SENSOR_LOCATION); // Read BLECharacteristic server_CP_ControlPoint_Chr = BLECharacteristic(UUID16_CHR_CYCLING_POWER_CONTROL_POINT); // Indicate, Write

/ Fitness Machine Service / BLEService server_FitnessMachine_Service = BLEService(UUID16_SVC_FITNESS_MACHINE); BLECharacteristic server_FTM_Feature_Chr = BLECharacteristic(UUID16_CHR_FITNESS_MACHINE_FEATURE); // Read BLECharacteristic server_FTM_IndoorBikeData_Chr = BLECharacteristic(UUID16_CHR_INDOOR_BIKE_DATA); // Notify BLECharacteristic server_FTM_TrainingStatus_Chr = BLECharacteristic(UUID16_CHR_TRAINING_STATUS); // Notify, Read const uint8_t FTM_TRAINING_STATUS_FIXED_DATALEN = 2; // Fixed len BLECharacteristic server_FTM_SupportedResistanceLevelRange_Chr = BLECharacteristic(UUID16_CHR_SUPPORTED_RESISTANCE_LEVEL_RANGE); // Read BLECharacteristic server_FTM_SupportedPowerRange_Chr = BLECharacteristic(UUID16_CHR_SUPPORTED_POWER_RANGE); // Read BLECharacteristic server_FTM_ControlPoint_Chr = BLECharacteristic(UUID16_CHR_FITNESS_MACHINE_CONTROL_POINT); // Write & Indicate BLECharacteristic server_FTM_Status_Chr = BLECharacteristic(UUID16_CHR_FITNESS_MACHINE_STATUS); // Notify const uint8_t FTM_STATUS_DATALEN = 7; // Max Len was: [3] --> Notice that with de Elite Direto the size is: [7] !!

/ Device Information Service helper class instance / BLEDis server_bledis; // Read unsigned char FirmwareRevStr[] = "0.0.0"; unsigned char HardwareRevStr[] = "0.0.0"; unsigned char SoftwareRevStr[] = "0.0.0";

/ NORDIC UART SERVICE a.k.a. NUS NUS Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E NUS RXD : 6E400002-B5A3-F393-E0A9-E50E24DCCA9E NUS TXD : 6E400003-B5A3-F393-E0A9-E50E24DCCA9E / const uint8_t UUID_NUS_SERVICE[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E}; const uint8_t UUID_NUS_CHR_RXD[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E}; const uint8_t UUID_NUS_CHR_TXD[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E}; BLEService server_NordicUart_Service = BLEService(UUID_NUS_SERVICE); BLECharacteristic server_NUS_RXD_Chr = BLECharacteristic(UUID_NUS_CHR_RXD); // Read (Receiving Data) BLECharacteristic server_NUS_TXD_Chr = BLECharacteristic(UUID_NUS_CHR_TXD); // Notify (Sending Data)

// ----------------------------- The Fitness Machine Control Point data type structure -------------------------------- // ---------------------------- Decoding is done in: server_FTM_ControlPoint_Chr_callback ------------------------------ const uint8_t ftmcpRequestControl = 0x00; const uint8_t ftmcpReset = 0x01; const uint8_t ftmcpSetTargetSpeed = 0x02; const uint8_t ftmcpSetTargetInclination = 0x03; const uint8_t ftmcpSetTargetResistanceLevel = 0x04; const uint8_t ftmcpSetTargetPower = 0x05; const uint8_t ftmcpSetTargetHeartRate = 0x06; const uint8_t ftmcpStartOrResume = 0x07; const uint8_t ftmcpStopOrPause = 0x08; const uint8_t ftmcpSetTargetedExpendedEngery = 0x09; const uint8_t ftmcpSetTargetedNumberOfSteps = 0x0A; const uint8_t ftmcpSetTargetedNumberOfStrided = 0x0B; const uint8_t ftmcpSetTargetedDistance = 0x0C; const uint8_t ftmcpSetTargetedTrainingTime = 0x0D; const uint8_t ftmcpSetTargetedTimeInTwoHeartRateZones = 0x0E; const uint8_t ftmcpSetTargetedTimeInThreeHeartRateZones = 0x0F; const uint8_t ftmcpSetTargetedTimeInFiveHeartRateZones = 0x10; const uint8_t ftmcpSetIndoorBikeSimulationParameters = 0x11; const uint8_t ftmcpSetWheelCircumference = 0x12; const uint8_t ftmcpSetSpinDownControl = 0x13; const uint8_t ftmcpSetTargetedCadence = 0x14;

const uint8_t FTM_CONTROL_POINT_DATALEN = 19; // Control point consists of 1 opcode (byte) and maximum 18 bytes as parameters // This ftmcp_data_t structure represents the control point data. The first octet represents the opcode of the request // followed by a parameter array of maximum 18 octects typedef struct attribute( ( packed ) ) { uint8_t OPCODE; uint8_t OCTETS[(FTM_CONTROL_POINT_DATALEN - 1)]; } ftmcp_data_t; typedef union // The union type automatically maps the bytes member array to the ftmcp_data_t structure member values { ftmcp_data_t values; uint8_t bytes[FTM_CONTROL_POINT_DATALEN]; } ftmcp_data_ut; // Fitness Machine Control Point Data variable ftmcp_data_ut server_FTM_Control_Point_Data; // ----------------------- end of server_FTM_ControlPoint_Chr_callback definitions ----------------------------

// -------------------------------------- END OF SERVER DEFINITIONS -------------------------------------------

// -------------------------------------------------------------------------------- // Global Server variables for decoding of INDOOR BIKE RESISTANCE PARAMETERS // -------------------------------------------------------------------------------- float wind_speed = 0; // meters per second, resolution 0.001 float grade = 0; // percentage, resolution 0.01 float crr = 0; // Coefficient of rolling resistance, resolution 0.0001 float cw = 0; // Wind resistance Kg/m, resolution 0.01; // --------------------------------------------------------------------------------

define TIME_SPAN 5000 // Time span in millis 1000 = 1 second

unsigned long TimeInterval = 0;

void setup() {

ifdef DEBUG

Serial.begin(115200); while ( !Serial ) delay(10); // for nrf52840 with native usb Serial.println("Feather nRF52840 MITM supporting: CPS, CSC and FTMS"); Serial.println("------------------ Version 02.3 ---------------------");

endif

// Initialize Bluefruit with maximum connections as Peripheral = 1, Central = 1 Bluefruit.begin(1, 1); Setup_Client_FTMS(); Setup_Client_CPS(); Setup_Client_CSC(); Setup_Client_DIS(); Client_Start_Scanning();

while (Bluefruit.Scanner.isRunning()) { // do nothing else but scanning.... yield(); } // wait enough time or go on when Client/Central is connected and all set! TimeInterval = millis() + TIME_SPAN; // ADD just enough delay while ( (millis() < TimeInterval) || (!Trainer.IsConnected) ) { yield(); }

// Configure and Start the Device Information Service

ifdef DEBUG

Serial.println("Configuring the Server Device Information Service");

endif

server_setupDIS(); // Setup the Cycle Power Service, Speed & Cadence Service and FTMS

ifdef DEBUG

Serial.println("Configuring the Server Cycle Power Service");

endif

server_setupCPS();

ifdef DEBUG

Serial.println("Configuring the Server Cadence and Speed Service");

endif

server_setupCSC();

ifdef DEBUG

Serial.println("Configuring the Server Fitness Machine Service");

endif

server_setupFTMS();

ifdef DEBUG

Serial.println("Configuring the Server NUS Service");

endif

server_setupNUS(); // Setup and start advertising

ifdef DEBUG

Serial.println("Setting up the Server-side advertising payload(s)");

endif

server_startADV();

ifdef DEBUG

Serial.println("Server-side is CPS, CSC and FTMS advertising!");

endif

while (Bluefruit.Advertising.isRunning()) { // ONLY advertise! yield(); } TimeInterval = millis() + TIME_SPAN; // ADD just enough DELAY // wait enough time or go on when Server/Peripheral is connected and set! while ( (millis() < TimeInterval) || (!Laptop.IsConnected) ) { yield(); }

ifdef DEBUG

Serial.println("Client- and Server-side are Up and Running!");

endif

}

// ---------------------- CLIENT SIDE FUNCTIONS ------------------------- void Setup_Client_FTMS(void) { // Initialize client FTM Service client_FitnessMachine_Service.begin();

// Initialize client FTM Feature characteristic client_FTM_Feature_Chr.begin();

// Initialize client FTM Training Status characteristic client_FTM_TrainingStatus_Chr.setNotifyCallback(client_FTM_TrainingStatus_Notify_callback); client_FTM_TrainingStatus_Chr.begin();

// Initialize client FTM Supported Power Range characteristic client_FTM_SupportedPowerRange_Chr.begin();

// Initialize client FTM Supported Resistance Level Range characteristic client_FTM_SupportedResistanceLevelRange_Chr.begin();

// Initialize client FTM Indoor Bike Data characteristic client_FTM_IndoorBikeData_Chr.setNotifyCallback(client_FTM_IndoorBikeData_Notify_callback); client_FTM_IndoorBikeData_Chr.begin();

// Initialize client FTM Control Point characteristic // For receiving Control Point Responses client_FTM_ControlPoint_Chr.setIndicateCallback(client_FTM_ControlPoint_Indicate_callback); client_FTM_ControlPoint_Chr.begin();

// Initialize client FTM Status characteristic client_FTM_Status_Chr.setNotifyCallback(client_FTM_Status_Notify_callback); client_FTM_Status_Chr.begin();

ifdef DEBUG

Serial.println("FTM Service and Chars are 'initialized'");

endif

}

void Setup_Client_CPS(void) { // Initialize CPS client client_CyclingPower_Service.begin();

// Initialize CP Feature characteristics of client_CyclingPower_Service. client_CP_Feature_Chr.begin();

// Initialize CP sensor location characteristics of client_CyclingPower_Service. client_CP_Location_Chr.begin();

// set up callback for receiving measurement client_CP_Measurement_Chr.setNotifyCallback(client_CP_Measurement_Chr_notify_callback); client_CP_Measurement_Chr.begin();

// Initialize Control Point and set up Indicate callback for receiving responses (indicate!) client_CP_ControlPoint_Chr.setIndicateCallback(client_CP_ControlPoint_Chr_indicate_callback); client_CP_ControlPoint_Chr.begin();

ifdef DEBUG

Serial.println("CP Service and Chars are 'initialized'");

endif

}

void Setup_Client_CSC(void) { // Initialize CSC client client_CyclingSpeedCadence_Service.begin();

// Initialize client characteristics of CSC. client_CSC_Location_Chr.begin();

// Initialize CSC Feature characteristics of client_CSC. client_CSC_Feature_Chr.begin();

// set up callback for receiving measurement client_CSC_Measurement_Chr.setNotifyCallback(client_CSC_Measurement_Chr_notify_callback); client_CSC_Measurement_Chr.begin();

ifdef DEBUG

Serial.println("CSC Service and Chars are 'initialized'");

endif

}

void Setup_Client_DIS(void) { // Initialize client Generic Access Service client_GenericAccess_Service.begin(); // Initialize some characteristics of the Generic Access Service. client_GA_DeviceName_Chr.begin(); client_GA_Appearance_Chr.begin();

ifdef DEBUG

Serial.println("Generic Access Service and Chars are 'initialized'");

endif

// Initialize client Device Information Service client_DIS_Service.begin(); // Initialize some characteristics of the Device Information Service. client_DIS_ManufacturerName_Chr.begin(); client_DIS_ModelNumber_Chr.begin(); client_DIS_SerialNumber_Chr.begin();

ifdef DEBUG

Serial.println("Device Information Service and Chars are 'initialized'");

endif

}

void loop() { } // end loop

void Client_Start_Scanning(void) { /* Start Central Scanning

void Client_Enable_Notify_Indicate(void) { // --------------------- Enable CP and CSC Notify and Indicate ------------------------------------ // Reaching here means we are ready to go, let's enable notification on measurement chr // ------------------------- Enable FTMS Notify and Indicate ---------------------------------------
if ( client_FTM_ControlPoint_Chr.enableIndicate() ) { // MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Control Point Response Messages");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable indicate for Client FTM Control Point Characteristic.");
Serial.println("FTMS (trainer) is controlled by another Client (Training App)!");

endif

Bluefruit.disconnect(Trainer.conn_handle);
return;

}

if ( client_FTM_Status_Chr.enableNotify() ) { // MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Status values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Status Characteristic.");
Serial.println("FTMS (trainer) is controlled by another Client (Training App)!");

endif

Bluefruit.disconnect(Trainer.conn_handle);
return;

}

if ( client_FTM_TrainingStatus_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Training Status values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Training Status Characteristic.");

endif

}

if ( client_FTM_IndoorBikeData_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Indoor Bike Data values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic.");

endif

} // ------------------------- Enable FTMS Notify and Indicate ---------------------------------------
// --------------------- Enable CP and CSC Notify and Indicate ------------------------------------ if ( client_CP_Measurement_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CP Measurement values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client CP Measurement Characteristic.");

endif

}

if ( client_CP_ControlPoint_Chr.enableIndicate() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CP Control Point Responses");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable indicate for Client CP Control Point Characteristic.");

endif

}

if ( client_CSC_Measurement_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CSC Measurement values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client CSC Measurement Characteristic.");

endif

} // ------------------------- Enable CP and CSC Notify and Indicate --------------------------------

} // ------------------------- Enable FTMS Notify and Indicate ---------------------------------------

/* Hooked callback that triggered when a status value is sent @param chr Pointer client characteristic @param data Pointer to received data @param len Length of received data / void client_FTM_TrainingStatus_Notify_callback(BLEClientCharacteristic chr, uint8_t data, uint16_t len) { // Client Training Status data is tranferred to the Server // NO TREATMENT OF COMMAND !!! server_FTM_TrainingStatus_Chr.notify(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t SDataLen = (uint8_t)len; uint8_t SDataBuf[SDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw FTM Training Status Data: [%d] [ ", len); for (int i = 0; i < sizeof(SDataBuf); i++) { SDataBuf[i] = *data++; Serial.printf("%02X ", SDataBuf[i], HEX); } Serial.println("] ");

endif

}

/* Hooked callback that is triggered when an IBD value is sent @param chr Pointer client characteristic @param data Pointer to received data @param len Length of received data / void client_FTM_IndoorBikeData_Notify_callback(BLEClientCharacteristic chr, uint8_t data, uint16_t len) { // Client IBD data is tranferred to the Server // NO TREATMENT OF COMMAND !!! if (server_FTM_IndoorBikeData_Chr.notifyEnabled(Laptop.conn_handle)) { server_FTM_IndoorBikeData_Chr.notify(data, len); // Just pass on and process later! }

ifdef DEBUG_FTM_INDOORBIKEDATA

// Only when DEBUG_FTM_INDOORBIKEDATA is defined IDBData will be parsed and printed! ParseIndoorBikeData(data, len);

endif

}

ifdef DEBUG_FTM_INDOORBIKEDATA

void ParseIndoorBikeData(uint8_t data, uint16_t len) { // ---> IBD Buffer Data Length depends on data flagged to be present !!!! uint8_t IBDDataLen = (uint8_t)len; uint8_t IBDDataBuf[IBDDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw FTM IBD Data: [%d] [ ", len); for (int i = 0; i < sizeof(IBDDataBuf); i++) { IBDDataBuf[i] = data++; Serial.printf("%02X ", IBDDataBuf[i], HEX); } Serial.print("] ");

uint8_t offset = 0; uint16_t flags = 0; memcpy(&flags, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable offset += 2; // UINT16 if ((flags & 1) != 0) { // More Data Serial.print(" More Data!"); } // if ((flags & 2) != 0) { // (flags & 2) --> true or false Average Speed is always(?) there (tested with Elite Direto XR) // Average Speed 0.01 uint16_t sim_Speed = 0; memcpy(&sim_Speed, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Speed: %d KPH", (sim_Speed / 100)); offset += 2; // UINT16 // } if ((flags & 4) != 0) { // Instantaneous Cadence 0.5 uint16_t inst_Cadence = 0; memcpy(&inst_Cadence, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Instantaneous Cadence: %d RPM", (inst_Cadence / 2)); offset += 2; // UINT16 } if ((flags & 8) != 0) { // Average Cadence 0.5 uint16_t av_Cadence = 0; memcpy(&av_Cadence, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Average Cadence: %d RPM", (av_Cadence / 2)); offset += 2; // UINT16 } if ((flags & 16) != 0) { // Total Distance 1 uint32_t tot_Distance = 0; memcpy(&tot_Distance, &IBDDataBuf[offset], 3); // Transfer buffer fields to variable Serial.printf(" Total Distance: %d m", tot_Distance); offset += 3; // UINT24 } if ((flags & 32) != 0) { // Resistance Level 1 uint16_t res_Level = 0; memcpy(&res_Level, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Resistance Level: %d ", res_Level); offset += 2; // UINT16 } if ((flags & 64) != 0) { // Instantaneous Power 1 uint16_t inst_Power = 0; memcpy(&inst_Power, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Instantaneous Power: %d Watt", inst_Power); offset += 2; // UINT16 } if ((flags & 128) != 0) { // Average Power 1 uint16_t av_Power = 0; memcpy(&av_Power, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Average Power: %d Watt", av_Power); offset += 2; // UINT16 } if ((flags & 256) != 0) { // Expended Energy -> UINT16 UINT16 UINT8 // Total Energy UINT16 1 uint16_t tot_Energy = 0; memcpy(&tot_Energy, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Tot. Energy: %d kCal", tot_Energy); offset += 2; // UINT16 // Energy per hour UINT16 1 uint16_t Energy_hr = 0; memcpy(&Energy_hr, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Energy/hr: %d kCal/hr", Energy_hr); offset += 2; // UINT16 // Energy per minute UINT8 1 uint8_t Energy_pm = 0; memcpy(&Energy_pm, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Energy/m: %d kCal/m", Energy_pm); offset += 1; // UINT8 } if ((flags & 512) != 0) { // Heart Rate 1 uint8_t Heart_Rate = 0; memcpy(&Heart_Rate, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Heart Rate: %d HBM", Heart_Rate); offset += 1; // UINT8 } if ((flags & 1024) != 0) { // Metabolic Equivalent 0.1 uint8_t Mets = 0; memcpy(&Mets, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Metabolic Equivalent: %d ", Mets / 10); offset += 1; // UINT8 } if ((flags & 2048) != 0) { // Elapsed Time 1 uint16_t elap_time = 0; memcpy(&elap_time, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Elapsed time: %d s", elap_time); offset += 2; // UINT16 } if ((flags & 4096) != 0) { // Remaining Time 1 uint16_t rem_time = 0; memcpy(&rem_time, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Remaining time: %d s", rem_time); offset += 2; // UINT16 } Serial.println(); }

endif

/* Hooked callback that triggered when a value is sent @param chr Pointer client characteristic @param data Pointer to received data @param len Length of received data / void client_FTM_ControlPoint_Indicate_callback(BLEClientCharacteristic chr, uint8_t data, uint16_t len) { // The receipt of Control Point settings is acknowledged by the trainer: handle it // Send Client's Response message to the Server // NO TREATMENT OF COMMAND !!! server_FTM_ControlPoint_Chr.indicate(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t RespBufferLen = (uint8_t)len; uint8_t RespBuffer[RespBufferLen] = {}; // It is max 6 bytes long // Transfer first the contents of data to buffer (array of chars) Serial.print(" -> Client Rec'd Control Point Response: [ "); for (int i = 0; i < sizeof(RespBuffer); i++) { RespBuffer[i] = *data++; Serial.printf("%02X ", RespBuffer[i], HEX); } Serial.println("] ");

endif

}

/* Hooked callback that triggered when a value is sent @param chr Pointer client characteristic @param data Pointer to received data @param len Length of received data / void client_FTM_Status_Notify_callback(BLEClientCharacteristic chr, uint8_t data, uint16_t len) { // Client's Machine Status data is tranferred to the Server // NO TREATMENT OF COMMAND !!! server_FTM_Status_Chr.notify(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t SDataLen = (uint8_t)len; uint8_t SDataBuf[SDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw FTM Machine Status Data: [%d] [ ", len); for (int i = 0; i < sizeof(SDataBuf); i++) { SDataBuf[i] = *data++; Serial.printf("%02X ", SDataBuf[i], HEX); } Serial.println("] ");

endif

}

// Byte swap unsigned short uint16_t swap_uint16( uint16_t val ) { return (val << 8) | (val >> 8 ); }

// Find certain uuid in the data of the received advertising packet bool checkForUuidPresent(const uint16_t uuid, const uint8_t* reportData, uint8_t reportDataLen) { // Enter uuid in printed format like 0x1826 for UUID16_SVC_FITNESS_MACHINE // uuid is internally stored in Little Endian for (int i = 0; i < (reportDataLen); i++) { // step 1: never miss out a position! if ( memcmp(&uuid, (reportData + i), 2) == 0) { return true; } } return false; }

/* Callback invoked when scanner pick up an advertising data @param report Structural advertising data / void client_scan_callback(ble_gap_evt_adv_report_t* report) { // Since we configure the scanner with filterUuid(CPS, CSC, FTMS) // scan_callback is invoked for devices with usually CPS service advertised. // However, we only do business with FTMS enabled Trainer types so check // for UUID16_SVC_FITNESS_MACHINE to be present, if not --> keep scanning! uint8_t Device_Addr[6] = {0}; if (!checkForUuidPresent(UUID16_SVC_FITNESS_MACHINE, report->data.p_data, report->data.len)) { return; // Keep scanning for FTMS trainer !! } memcpy(Device_Addr, report->peer_addr.addr, 6); if ( !(memcmp(Device_Addr, Trainer.PeerAddress, 6) == 0) ) { return; // Keep scanning for the required trainer !! } // Connect to device only with required services AND device address if (Bluefruit.Scanner.isRunning()) { Bluefruit.Scanner.stop(); }

ifdef DEBUG

Serial.println("Found advertising Peripheral with FTMS enabled! See Raw data packet:"); Serial.println(F("Timestamp Addr Rssi Data")); Serial.printf("%09d ", millis()); // MAC is in little endian --> print reverse Serial.printBufferReverse(report->peer_addr.addr, 6, ':'); Serial.print(F(" ")); Serial.print(report->rssi); Serial.print(F(" ")); Serial.printBuffer(report->data.p_data, report->data.len, '-'); Serial.println();

endif

Bluefruit.Central.connect(report); }

ifdef DEBUG

void PrintPeerAddress(uint8_t addr[6]) { for (int i = 1; i < 6; i++) { // Display byte by byte in HEX reverse: little Endian Serial.printf("%02X:", addr[(6 - i)], HEX); } Serial.printf("%02X ", addr[0], HEX); }

endif

/* Callback invoked when a connection is established @param conn_handle / void client_connect_callback(uint16_t conn_handle) { Trainer.conn_handle = conn_handle; // Get the reference to current connection BLEConnection* connection = Bluefruit.Connection(conn_handle); connection->getPeerName(Trainer.PeerName, sizeof(Trainer.PeerName)); ble_gap_addr_t PeerAddr = connection->getPeerAddr(); // Fill BLE Gap struct memcpy(Trainer.PeerAddress, PeerAddr.addr, 6); // Copy Peer Address from ble_gap_addr_t struct

ifdef DEBUG

Serial.printf("Feather nRF52 (Central) connected to Trainer (Peripheral) device: [%s] MAC Address: ", Trainer.PeerName); PrintPeerAddress(Trainer.PeerAddress); Serial.println(); Serial.println("Now checking all mandatory Client Services and Characteristics!"); Serial.println("If Mandatory Services Fail --> the Client will disconnect!");

endif

// ---------------------------- GA and DIS SERVICE ------------------------------------------

ifdef DEBUG

Serial.println("First checking Generic Access and Device Information Services and Characteristics!");

endif

// If Generic Access is not found then go on.... NOT FATAL ! while (!(client_GenericAccess_Service.discover(conn_handle))) { if ( client_GenericAccess_Service.discover(conn_handle) ) {

ifdef DEBUG

  Serial.print(F("Found Client Generic Access\n"));

endif

  if ( client_GA_DeviceName_Chr.discover() ) {
     client_GA_DeviceName_Chr.read(client_GA_DeviceName_Data, sizeof(client_GA_DeviceName_Data));

ifdef DEBUG

    Serial.printf(" -> Client Reads Device Name:   [%s]\n", client_GA_DeviceName_Data);

endif

  }     
  if ( client_GA_Appearance_Chr.discover() ) {
     client_GA_Appearance_Value = client_GA_Appearance_Chr.read16();

ifdef DEBUG

    Serial.printf(" -> Client Reads Appearance:    [%d]\n", client_GA_Appearance_Value);

endif

  }     

} // GA }
// If DIS is not found then go on.... NOT FATAL !

while (!( client_DIS_Service.discover(conn_handle) )){ if ( client_DIS_Service.discover(conn_handle) ) {

ifdef DEBUG

Serial.print(F("Found Client Device Information\n"));

endif

//  1
if ( client_DIS_ManufacturerName_Chr.discover() ) {
  // read and print out Manufacturer
    if ( client_DIS_ManufacturerName_Chr.read(client_DIS_Manufacturer_Str, sizeof(client_DIS_Manufacturer_Str)) ) {

ifdef DEBUG

    Serial.printf(" -> Client Reads Manufacturer:  [%s]\n", client_DIS_Manufacturer_Str);

endif

  }
} // 1
//  2
if ( client_DIS_ModelNumber_Chr.discover() ) {
  // read and print out Model Number
  if ( client_DIS_ModelNumber_Chr.read(client_DIS_ModelNumber_Str, sizeof(client_DIS_ModelNumber_Str)) ) { 

ifdef DEBUG

    Serial.printf(" -> Client Reads Model Number:  [%s]\n", client_DIS_ModelNumber_Str);

endif

  }
} // 2
//  3
if ( client_DIS_SerialNumber_Chr.discover() ) {
  // read and print out Serial Number
  if ( client_DIS_SerialNumber_Chr.read(client_DIS_SerialNumber_Str, sizeof(client_DIS_SerialNumber_Str)) ) {

ifdef DEBUG

    Serial.printf(" -> Client Reads Serial Number: [%s]\n", client_DIS_SerialNumber_Str);

endif

  }
} // 3

} } // DIS // ---------------------------- END GA and DIS SERVICE ------------------------------------------------

// -----------------------------FTM SERVICE ------------------------------------------------------------

ifdef DEBUG

Serial.print("Discovering Mandatory Client Fitness Machine (FTM) Service ... ");

endif

// If FTM is not found, disconnect, resume scanning, and return if ( client_FitnessMachine_Service.discover(conn_handle) ) {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle);
uint16_t max_payload = conn->getMtu()-3;
uint16_t data_length = conn->getDataLength();
Serial.print("Found it! ");
Serial.printf("FTMS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Service is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

}

ifdef DEBUG

Serial.print("Discovering Client FTM Feature Characteristic ... ");

endif

// If FTM Feature is not found, disconnect, resume scanning, and return while (!( client_FTM_Feature_Chr.discover() )) { if ( client_FTM_Feature_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read FTM Feature Data
client_FTM_Feature_Chr.read(client_FTM_Feature_Data, 8);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Feature bytes: [8] [ ");
for (int i = 0; i < sizeof(client_FTM_Feature_Data); i++) {
    Serial.printf("%02X ", client_FTM_Feature_Data[i], HEX);
} // for
Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Disconnecting since Client FTM Feature Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
Bluefruit.Connection(conn_handle);
Serial.print("Discovering Client FTM Feature not decouvert ... ");

// return; } }

ifdef DEBUG

Serial.print("Discovering Client FTM Control Point Characteristic ... ");

endif

// If FTM Control Point is not found, disconnect, resume scanning, and return if ( client_FTM_ControlPoint_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Send a Request Control of Machine, OpCode == 0, no values!
const uint8_t RCM[1] = {0};
client_FTM_ControlPoint_Chr.write_resp(RCM, 1);    

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Control Point Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
Bluefruit.Connection(conn_handle);
Serial.print("Discovering Client FTM Feature not decouvert ... ");
return;

}

ifdef DEBUG

Serial.print("Discovering Client FTM Status Characteristic ... ");

endif

// If FTM Status is not found, disconnect, resume scanning, and return if ( client_FTM_Status_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Status Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

}

ifdef DEBUG

Serial.print("Discovering Client FTM Training Status Characteristic ... ");

endif

// FTM Training Status is NOT MANDATORY if ( client_FTM_TrainingStatus_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory");

endif

} /*

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

*/

ifdef DEBUG

Serial.print("Discovering Client FTM Supported Resistance Level Range Characteristic ... ");

endif

// FTM SupportedResistanceLevelRange is not mandatory! if ( client_FTM_SupportedResistanceLevelRange_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read Supported Resistance Level Range Data
client_FTM_SupportedResistanceLevelRange_Chr.read(client_FTM_SupportedResistanceLevelRange_Data, 6);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ ");
for (int i = 0; i < sizeof(client_FTM_SupportedResistanceLevelRange_Data); i++) {
    Serial.printf("%02X ", client_FTM_SupportedResistanceLevelRange_Data[i], HEX);
} // for
Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT mandatory!"); 

endif

} / Serial.println("Disconnecting since Client FTM Supported Resistance Level Range Characteristic is mandatory!"); // MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return; /

ifdef DEBUG

Serial.print("Discovering Client FTM Supported Power Range Characteristic ... ");

endif

// FTM SupportedPowerRange is not mandatory! if ( client_FTM_SupportedPowerRange_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read Supported Resistance Level Range values
client_FTM_SupportedPowerRange_Chr.read(client_FTM_SupportedPowerRange_Data, 6);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Supported Power Range bytes: [6] [ ");
for (int i = 0; i < sizeof(client_FTM_SupportedPowerRange_Data); i++) {
    Serial.printf("%02X ", client_FTM_SupportedPowerRange_Data[i], HEX);
} // for
Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT mandatory!"); 

endif

} /*

ifdef DEBUG

Serial.println("Disconnecting since Client FTM Supported Power Range Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

*/

ifdef DEBUG

Serial.print("Discovering Client FTM Indoor Bike Data Characteristic ... ");

endif

// FTM Indoor Bike Data is not mandatory if ( client_FTM_IndoorBikeData_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory"); 

endif

} /*

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client FTM Indoor Bike Data Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
return;

*/ // ---------------------------- End FTM SERVICE --------------------------------------------- // ---------------------------- CP SERVICE --------------------------------------------------

ifdef DEBUG

Serial.print("Discovering Client Cycling Power (CP) Service ... ");

endif

// If CPS is not found, disconnect, resume scanning, and return while (!( client_CyclingPower_Service.discover(conn_handle) )) {
if ( client_CyclingPower_Service.discover(conn_handle) ) {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle);
uint16_t max_payload = conn->getMtu()-3;
uint16_t data_length = conn->getDataLength();
Serial.print("Found it! ");
Serial.printf("CPS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client Cyling Power Service is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service
Bluefruit.disconnect(conn_handle);
Bluefruit.Connection(conn_handle);

Serial.print("Discovering Cycling Power (CP) Service not decouvert ... "); return; } }

ifdef DEBUG

Serial.print("Discovering Client CP Measurement characteristic ... ");

endif

if ( !client_CP_Measurement_Chr.discover() ) { // Measurement chr is mandatory, if it is not found (valid), then disconnect

ifdef DEBUG

Serial.println("Not Found!");  
Serial.println("Disconnecting since Client CP Measurement Characteristic is mandatory!");

endif

Bluefruit.disconnect(conn_handle);
return;

} else {

ifdef DEBUG

Serial.println("Found it!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Control Point characteristic ... ");

endif

if ( client_CP_ControlPoint_Chr.discover() ) { // CP Control Point chr is not mandatory

ifdef DEBUG

Serial.println("Found it!");  

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Feature characteristic ... ");

endif

if ( client_CP_Feature_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Configure the Cycle Power Feature characteristic // Properties = Read // Min Len = 1 // Max Len = 32 // B0:3 = UINT8 - Cycling Power Feature (MANDATORY) // b0 = Pedal power balance supported; 0 = false, 1 = true // b1 = Accumulated torque supported; 0 = false, 1 = true // b2 = Wheel revolution data supported; 0 = false, 1 = true // b3 = Crank revolution data supported; 0 = false, 1 = true // b4 = Extreme magnatudes supported; 0 = false, 1 = true // b5 = Extreme angles supported; 0 = false, 1 = true // b6 = Top/bottom dead angle supported; 0 = false, 1 = true // b7 = Accumulated energy supported; 0 = false, 1 = true // b8 = Offset compensation indicator supported; 0 = false, 1 = true // b9 = Offset compensation supported; 0 = false, 1 = true // b10 = Cycling power measurement characteristic content masking supported; 0 = false, 1 = true // b11 = Multiple sensor locations supported; 0 = false, 1 = true // b12 = Crank length adj. supported; 0 = false, 1 = true // b13 = Chain length adj. supported; 0 = false, 1 = true // b14 = Chain weight adj. supported; 0 = false, 1 = true // b15 = Span length adj. supported; 0 = false, 1 = true // b16 = Sensor measurement context; 0 = force, 1 = torque // b17 = Instantaineous measurement direction supported; 0 = false, 1 = true // b18 = Factory calibrated date supported; 0 = false, 1 = true // b19 = Enhanced offset compensation supported; 0 = false, 1 = true // b20:21 = Distribtue system support; 0 = legacy, 1 = not supported, 2 = supported, 3 = RFU // b22:32 = Reserved

// Read 32-bit client_CP_Feature_Chr value client_CP_Feature_Flags = client_CP_Feature_Chr.read32();

ifdef DEBUG

const uint8_t CPFC_FIXED_DATALEN = 4; uint8_t cpfcData[CPFC_FIXED_DATALEN] = {(uint8_t)(client_CP_Feature_Flags & 0xff), (uint8_t)(client_CP_Feature_Flags >> 8), (uint8_t)(client_CP_Feature_Flags >> 16), (uint8_t)(client_CP_Feature_Flags >> 24)}; Serial.print(" -> Client Reads Raw CP Feature bytes: [4] [ "); for (int i = 0; i < CPFC_FIXED_DATALEN; i++) { if ( i <= sizeof(cpfcData)) { Serial.printf("%02X ", cpfcData[i], HEX); } } Serial.println("] "); for (int i = 0; i < sizeof(client_CP_Feature_Str); i++) { if ( client_CP_Feature_Flags & (1 << i) ) { Serial.println(client_CP_Feature_Str[i]); } }

endif

} else {

ifdef DEBUG

Serial.println("NOT Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Sensor Location characteristic ... ");

endif

if ( client_CP_Location_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// The Sensor Location characteristic // Properties = Read // Min Len = 1 // Max Len = 1 // B0:1 = UINT8 - Sensor Location

// Read 8-bit client CP sensor location value
client_CP_Location_Value = client_CP_Location_Chr.read8();   

ifdef DEBUG

Serial.print(" -> Client Reads CP Location Sensor: ");
Serial.printf("Loc#: %d %s\n", client_CP_Location_Value, client_Sensor_Location_Str[client_CP_Location_Value]);

endif

} else {

ifdef DEBUG

Serial.println("NOT Found! NOT Mandatory!");

endif

} // ---------------------------- END CP SERVICE ------------------------------------------------ // ---------------------------- CSC SERVICE --------------------------------------------------

ifdef DEBUG

Serial.print("Discovering Cycling Speed and Cadence (CSC) Service ... ");

endif

if ( client_CyclingSpeedCadence_Service.discover(conn_handle) ) // UUID16_SVC_CYCLING_SPEED_AND_CADENCE {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle);
uint16_t max_payload = conn->getMtu()-3;
uint16_t data_length = conn->getDataLength();
Serial.print("Found it! ");
Serial.printf("CSCS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found! CSC Service is Not Mandatory!");

endif

return; // NO CSC -> end of client_connect_callback !!   

} /* // Is Mandatory

ifdef DEBUG

Serial.println("Not Found and disconnecting!"); 
Serial.println("CSC Service is mandatory!");

endif

Bluefruit.disconnect(conn_handle);
return;

*/

// Test for client CSC Characteristics when the client CSC Service is existing

ifdef DEBUG

Serial.print("Discovering Client CSC Measurement CHR ... ");

endif

if ( client_CSC_Measurement_Chr.discover() ) // UUID16_CHR_CSC_MEASUREMENT {

ifdef DEBUG

Serial.println("Found it! ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory!"); 

endif

} /* // Is Mandatory

ifdef DEBUG

Serial.println("Not Found!"); 
Serial.println("Disconnecting since Client CSC Measurement CHR is mandatory!");

endif

Bluefruit.disconnect(conn_handle);
return;

*/

ifdef DEBUG

Serial.print("Discovering Client CSC Location CHR ... ");

endif

if ( client_CSC_Location_Chr.discover() ) // UUID16_CHR_SENSOR_LOCATION {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read 16-bit client CSC sensor location value
client_CSC_Location_Value = client_CSC_Location_Chr.read8();

ifdef DEBUG

Serial.print(" -> Client Reads CSC Location Sensor: ");
Serial.printf("Loc#: %d %s\n", client_CSC_Location_Value, client_Sensor_Location_Str[client_CSC_Location_Value]);

endif

} else {

ifdef DEBUG

  Serial.println("Not Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CSC Feature CHR ... ");

endif

if ( client_CSC_Feature_Chr.discover() ) // UUID16_CHR_CSC_FEATURE {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read sensor CSC Feature value in 16 bit
client_CSC_Feature_Flags = client_CSC_Feature_Chr.read16();

ifdef DEBUG

uint8_t cscfcData[CSC_FEATURE_FIXED_DATALEN] = { (uint8_t)(client_CSC_Feature_Flags & 0xff), (uint8_t)(client_CSC_Feature_Flags >> 8) }; //  Little Endian Representation
Serial.printf(" -> Client Reads Raw CSC Feature bytes: [2] [ ");
for (int i = 0; i < sizeof(cscfcData); i++) {
  Serial.printf("%02X ", cscfcData[i], HEX);
}
Serial.println("] ");
for (int i = 0; i < sizeof(client_CSC_Feature_Str); i++) {
if ( (client_CSC_Feature_Flags & (1 << i)) != 0 )
  {
   Serial.println(client_CSC_Feature_Str[i]);
  }
}

endif

} else {

ifdef DEBUG

  Serial.println("Not Found! NOT Mandatory!");

endif

} // ---------------------------- END CSC SERVICE --------------------------------------------- // Only now set true after ALL Mandatory Services and Char's have been discovered !!! Trainer.IsConnected = true; } // End client_connect_callback

/* Callback invoked when a connection is dropped @param conn_handle @param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h / void client_disconnect_callback(uint16_t conn_handle, uint8_t reason) {

ifdef DEBUG

Serial.printf("Client disconnected from Peripheral Device: [%s], reason: [%02X]\n", Trainer.PeerName, reason, HEX);

endif

Trainer.conn_handle = BLE_CONN_HANDLE_INVALID; Trainer.IsConnected = false; // Force server to disconnect! if (Laptop.conn_handle != BLE_CONN_HANDLE_INVALID) { Bluefruit.disconnect(Laptop.conn_handle); } }

/* Hooked callback that triggered when a measurement value is sent from peripheral @param chr Pointer client characteristic in this example it should be cpmc @param data Pointer to received data @param len Length of received data / void client_CP_Measurement_Chr_notify_callback(BLEClientCharacteristic chr, uint8_t data, uint16_t len) { // Client CP Measurement data is tranferred to the Server (Zwift) // NO TREATMENT OF RESPONSE !!!!! if (server_CP_Measurement_Chr.notifyEnabled(Laptop.conn_handle)) { server_CP_Measurement_Chr.notify(data, len); // Just pass on and process later! }

ifdef DEBUG_CP_MEASUREMENT

uint8_t buffer[len] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw CP Data: [%d] [ ", len); for (int i = 0; i < sizeof(buffer); i++) { if ( i <= sizeof(buffer)) { buffer[i] = *data++; Serial.printf("%02X ", buffer[i], HEX); } } Serial.print("] "); uint8_t offset = 0; // Get flags field uint16_t flags = 0; memcpy(&flags, &buffer[offset], 2); // Transfer buffer fields to variable offset += 2; // UINT16 // Get Instantaneous Power values UINT16 uint16_t PowerValue = 0; memcpy(&PowerValue, &buffer[offset], 2); // Transfer buffer fields to variable offset += 2; // UINT16 Serial.printf("Instantaneous Power: %4d\n", PowerValue); // Get the other CP measurement values if ((flags & 1) != 0) { // Power Balance Present Serial.print(" --> Pedal Power Balance!"); } if ((flags & 2) != 0) { // Accumulated Torque Serial.println(" --> Accumulated Torque!"); } // etcetera...

endif

} // End cpmc_notify_callback

/* Hooked callback that triggered when a response value is sent from peripheral @param chr Pointer client characteristic @param data Pointer to received data @param len Length of received data / void client_CP_ControlPoint_Chr_indicate_callback(BLEClientCharacteristic chr, uint8_t data, uint16_t len) { // Send Client's response message to the Server (Zwift) // NO TREATMENT OF RESPONSE !!!!! server_CP_ControlPoint_Chr.indicate(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t cpcpDataLen = (uint8_t)len; uint8_t cpcpData[cpcpDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw CP Control Point Data: [%d] [ ", len); for (int i = 0; i < sizeof(cpcpData); i++) { cpcpData[i] = *data++; Serial.printf("%02X ", cpcpData[i], HEX); } Serial.print("] ");

endif

}

/* Hooked callback that triggered when a measurement value is sent from peripheral @param chr Pointer client characteristic @param data Pointer to received data @param len Length of received data / void client_CSC_Measurement_Chr_notify_callback(BLEClientCharacteristic chr, uint8_t data, uint16_t len) { // Client CSC Measurement data is transferred to the Server (Zwift) // NO TREATMENT OF RESPONSE !!!!! if (server_CSC_Measurement_Chr.notifyEnabled(Laptop.conn_handle)) { server_CSC_Measurement_Chr.notify(data, len); // Just pass on and process later! }

ifdef DEBUG_CSC_MEASUREMENT

uint8_t buffer[len] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw CSC Data: [%d] [ ", len); for (int i = 0; i < sizeof(buffer); i++) { if ( i <= sizeof(buffer)) { buffer[i] = *data++; Serial.printf("%02X ", buffer[i], HEX); } } Serial.print("] "); uint8_t offset = 0; // we define the offset that is to be used when reading the next field // Size of variables (e.g. 2 (16) or 4 bytes (32)) are constants in BluetoothGattCharacteristic // these represent the values you can find in the "Value Fields" table in the "Format" column // Read the Flags field at buffer[0] uint8_t flags = buffer[offset]; offset += 1; // UINT8 // we have to check the flags' nth bit to see if C1 field exists if ((flags & 1) != 0) { uint32_t cum_wheel_rev = 0; memcpy(&cum_wheel_rev, &buffer[offset], 4); offset += 4; // UINT32 uint16_t last_wheel_event = 0; memcpy(&last_wheel_event, &buffer[offset], 2); offset += 2; // UINT16 Serial.printf(" Cum. wheel rev.: %d Last wheel event: %d ", cum_wheel_rev, last_wheel_event); } // we have to check the flags' nth bit to see if C2 field exists if ((flags & 2) != 0) { uint16_t cum_cranks = 0; memcpy(&cum_cranks, &buffer[offset], 2); offset += 2; // UINT16 uint16_t last_crank_event = 0; memcpy(&last_crank_event, &buffer[offset], 2); offset += 2; // UINT16 Serial.printf(" Cum cranks: %d Last crank event: %d", cum_cranks, last_crank_event); } Serial.println();

endif

} // ---------------------- END of CLIENT SIDE FUNCTIONS ------------------------- // ---------------------- START of SERVER SIDE FUNCTIONS -------------------------

void server_setupNUS(void) { server_NordicUart_Service.begin(); // Add NUS TXD Characteristic server_NUS_TXD_Chr.setProperties(CHR_PROPS_NOTIFY); // Type "notify" server_NUS_TXD_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // readAccess, NO writeAccess server_NUS_TXD_Chr.setMaxLen(MAX_PAYLOAD); // To be on the safe side! server_NUS_TXD_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_NUS_TXD_Chr.begin();

// Add NUS RXD Characteristic server_NUS_RXD_Chr.setProperties(CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP); // Write with No response !! server_NUS_RXD_Chr.setPermission(SECMODE_NO_ACCESS, SECMODE_OPEN); server_NUS_RXD_Chr.setMaxLen(MAX_PAYLOAD); // Maxlen server_NUS_RXD_Chr.setWriteCallback(server_NUS_RXD_Chr_callback); server_NUS_RXD_Chr.begin(); }

void server_NUS_RXD_Chr_callback(uint16_t conn_hdl, BLECharacteristic chr, uint8_t data, uint16_t len) { // Read data received over NUS RXD from Mobile Phone

ifdef DEBUG

uint8_t NusRxdDataLen = (uint8_t)len; // Get the actual length of data bytes and type cast to (uint8_t) char NusRxdData[MAX_PAYLOAD + 1]; // Data is all ASCII ! memset(NusRxdData, 0, MAX_PAYLOAD); // set to zero if (NusRxdDataLen > MAX_PAYLOAD) { NusRxdDataLen = MAX_PAYLOAD; // Check for limit } memcpy(NusRxdData, data, NusRxdDataLen); // Transfer data to char array // Display the raw packet data in actual length Serial.printf(" -> Server NUS RXD Data [%d][%s]\n", NusRxdDataLen, NusRxdData);

endif

}

void Construct_Dev_Name(void) { const char prefix[] = {'S', 'i', 'm', ' '}; // #4 Chars size_t len = strlen((const char)client_GA_DeviceName_Data); // Len of null terminated char array int MaxLen = (MAX_PAYLOAD - sizeof(prefix) - 1); // 1 less for null terminating char if (len > MaxLen) { len = MaxLen; } int pos = MaxLen; if (len > 0) { // pfound points to the first occurence of " " (blank space char) char pfound = strstr((const char)client_GA_DeviceName_Data, " "); if (pfound != NULL) { pos = int(pfound - (char)client_GA_DeviceName_Data); // Convert to position in DevName } } if ( pos > MaxLen ) { pos = MaxLen; // Stay within char array allocated memory! } memmove(&client_GA_DeviceName_Data[sizeof(prefix)], &client_GA_DeviceName_Data, pos); // Make space: shift to the right memcpy(&client_GA_DeviceName_Data, &prefix, sizeof(prefix)); // Insert prefix at begin of DevName client_GA_DeviceName_Data[(pos + sizeof(prefix))] = 0; // Make null terminated char array at new position, skip rest! }

void server_startADV(void) { // Setup and start advertising // Supported tx_power values depending on mcu: // - nRF52832: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +3dBm and +4dBm. // - nRF52840: -40dBm, -20dBm, -16dBm, -12dBm, -8dBm, -4dBm, 0dBm, +2dBm, +3dBm, +4dBm, +5dBm, +6dBm, +7dBm and +8dBm. Bluefruit.setTxPower(4); // See above for supported values: +4dBm // Set blink rate in advertising mode Bluefruit.setConnLedInterval(250);

Construct_Dev_Name();

ifdef DEBUG

Serial.printf("Setting Server Device Name to: [%s]\n", client_GA_DeviceName_Data);

endif

Bluefruit.setName((const char*)client_GA_DeviceName_Data); if (Bluefruit.setAppearance(client_GA_Appearance_Value)) {

ifdef DEBUG

Serial.printf("Setting Server Appearance to: [%d]\n", client_GA_Appearance_Value);

endif

} // Set the connect/disconnect callback handlers Bluefruit.Periph.setConnectCallback(server_connect_callback); Bluefruit.Periph.setDisconnectCallback(server_disconnect_callback);

// Advertising packet Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); Bluefruit.Advertising.addTxPower();

// Test include only FTMS Service as defined above Bluefruit.Advertising.addService(server_CylingPower_Service); Bluefruit.Advertising.addService(server_CyclingSpeedCadence_Service); Bluefruit.Advertising.addService(server_FitnessMachine_Service); // No need to advertise NUS, Companion App detects it anyway!

// Include Bluefruit.Advertising.addName and 128-bit uuid(s) result in a packet space problem!!! // Use secondary Scan Response packet (optional) // if there is no room for 'Name' in Advertising packet Bluefruit.ScanResponse.addName();

/* Start Advertising

void server_setupDIS(void) { // Configure and Start the Device Information Service server_bledis.setManufacturer((const char)client_DIS_Manufacturer_Str); server_bledis.setModel((const char)client_DIS_ModelNumber_Str); // Notice that the Firmware Revision string is default set to // the value of the Feather-nRF52 Board being used! server_bledis.setFirmwareRev((const char)FirmwareRevStr); server_bledis.setSerialNum((const char)client_DIS_SerialNumber_Str); server_bledis.setHardwareRev((const char)HardwareRevStr); server_bledis.setSoftwareRev((const char)SoftwareRevStr); server_bledis.begin(); }

void server_setupFTMS(void) { server_FitnessMachine_Service.begin(); //

// Fitness Machine Feature, mandatory, read server_FTM_Feature_Chr.setProperties(CHR_PROPS_READ); server_FTM_Feature_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); server_FTM_Feature_Chr.setFixedLen(FTM_FEATURE_FIXED_DATALEN); server_FTM_Feature_Chr.begin(); server_FTM_Feature_Chr.write(client_FTM_Feature_Data, FTM_FEATURE_FIXED_DATALEN);

// Indoor Bike Data, optional, notify server_FTM_IndoorBikeData_Chr.setProperties(CHR_PROPS_NOTIFY); // because type "notify" server_FTM_IndoorBikeData_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // readAccess, writeAccess server_FTM_IndoorBikeData_Chr.setMaxLen(MAX_PAYLOAD); // To be on the safe side, when many features are set! server_FTM_IndoorBikeData_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_FTM_IndoorBikeData_Chr.begin();

// Training Status, optional, read & notify server_FTM_TrainingStatus_Chr.setProperties(CHR_PROPS_NOTIFY); // because type is "notify" server_FTM_TrainingStatus_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // readAccess, writeAccess server_FTM_TrainingStatus_Chr.setFixedLen(FTM_TRAINING_STATUS_FIXED_DATALEN); server_FTM_TrainingStatus_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_FTM_TrainingStatus_Chr.begin();

// Supported Resistance Level Range, read, optional server_FTM_SupportedResistanceLevelRange_Chr.setProperties(CHR_PROPS_READ); server_FTM_SupportedResistanceLevelRange_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); server_FTM_SupportedResistanceLevelRange_Chr.setFixedLen(FTM_SRLR_FIXED_DATALEN); server_FTM_SupportedResistanceLevelRange_Chr.begin(); server_FTM_SupportedResistanceLevelRange_Chr.write(client_FTM_SupportedResistanceLevelRange_Data, FTM_SRLR_FIXED_DATALEN);

// Supported Power Range, read, optional server_FTM_SupportedPowerRange_Chr.setProperties(CHR_PROPS_READ); server_FTM_SupportedPowerRange_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); server_FTM_SupportedPowerRange_Chr.setFixedLen(FTM_SPR_FIXED_DATALEN); server_FTM_SupportedPowerRange_Chr.begin(); server_FTM_SupportedPowerRange_Chr.write(client_FTM_SupportedPowerRange_Data, FTM_SPR_FIXED_DATALEN);

// Fitness Machine Control Point, optional, write server_FTM_ControlPoint_Chr.setProperties(CHR_PROPS_INDICATE | CHR_PROPS_WRITE); // CHR_PROPS_READ // | CHR_PROPS_WRITE_WO_RESP); // Write with No response !! server_FTM_ControlPoint_Chr.setPermission(SECMODE_OPEN, SECMODE_OPEN); // readAccess, writeAccess DO NOT SET: SECMODE_NO_ACCESS ! server_FTM_ControlPoint_Chr.setMaxLen(FTM_CONTROL_POINT_DATALEN); // Maxlen of Client written data: (1) OpCode and (FTM_CONTROL_POINT_DATALEN-1) OCTETS server_FTM_ControlPoint_Chr.setWriteCallback(server_FTM_ControlPoint_Chr_callback); server_FTM_ControlPoint_Chr.begin();

// Fitness Machine Status, mandatory, notify BLENotify, server_FTM_Status_Chr.setProperties(CHR_PROPS_NOTIFY); // because type is "notify" server_FTM_Status_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // readAccess, writeAccess server_FTM_Status_Chr.setMaxLen(FTM_STATUS_DATALEN); server_FTM_Status_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_FTM_Status_Chr.begin(); }

void server_FTM_ControlPoint_Chr_callback(uint16_t conn_hdl, BLECharacteristic chr, uint8_t data, uint16_t len) { // Server FTM Control Point data is tranferred to the Client // NO TREATMENT OF COMMAND !!! client_FTM_ControlPoint_Chr.write_resp(data, len); // Just pass on and process later! // Seems to cause hickups in response stream // client_FTM_ControlPoint_Chr.write(data, len); // Just pass on and process later!

uint8_t ftmcpDataLen = (uint8_t)len; memset(server_FTM_Control_Point_Data.bytes, 0, sizeof(server_FTM_Control_Point_Data.bytes)); // Transfer the contents of data to server_FTM_Control_Point_Data.bytes for (int i = 0; i < ftmcpDataLen; i++) { server_FTM_Control_Point_Data.bytes[i] = data++; } / Decodes an incoming Fitness Machine Control Point request */

ifdef DEBUG

Serial.printf(" -> Server Rec'd Raw FTM Control Point Data [len: %d] ", ftmcpDataLen); Serial.printf("[OpCode: %02X] [Values: ", server_FTM_Control_Point_Data.values.OPCODE, HEX); for (int i = 0; i < ftmcpDataLen; i++) { Serial.printf("%02X ", server_FTM_Control_Point_Data.values.OCTETS[i], HEX); } Serial.println("]");

endif

switch (server_FTM_Control_Point_Data.values.OPCODE) { case ftmcpRequestControl: {

ifdef DEBUG

    Serial.println("Request Control of Machine!");

endif

    break;
  }
case ftmcpStartOrResume: {

ifdef DEBUG

    Serial.println("Start or Resume Machine!");

endif

    break;
  }
case ftmcpStopOrPause: {

ifdef DEBUG

    Serial.println("Stop or Pause Machine, Parameter: Stop!");

endif

    break;
  }
case ftmcpSetIndoorBikeSimulationParameters: {
    // Short is 16 bit signed, so the windspeed is converted from two bytes to signed value. Highest bit is sign bit
    short ws = (server_FTM_Control_Point_Data.values.OCTETS[0] << 8) + server_FTM_Control_Point_Data.values.OCTETS[1];
    wind_speed = ws / 1000.0;
    // Short is 16 bit signed, so a negative grade is correctly converted from two bytes to signed value. Highest bit is sign bit
    short gr = (server_FTM_Control_Point_Data.values.OCTETS[3] << 8) + server_FTM_Control_Point_Data.values.OCTETS[2];
    grade = gr / 100.0;
    crr = server_FTM_Control_Point_Data.values.OCTETS[4] / 10000.0;
    cw = server_FTM_Control_Point_Data.values.OCTETS[5] / 100.0;

ifdef DEBUG // Remember, if debugging with Zwift, that these values are divided by 2 if in Zwift 50% settings!

    Serial.print("Set Indoor Bike Simulation Parameters --> ");
    Serial.print("Wind speed (1000): ");  Serial.print(wind_speed);
    Serial.print(" | Grade (100): ");     Serial.print(grade);
    Serial.print(" | Crr (10000): ");     Serial.print(crr);
    Serial.print(" | Cw (100): ");        Serial.println(cw);

endif

    break;
  }
case ftmcpReset: {

ifdef DEBUG

    Serial.println("Reset Machine!");

endif

    break;
  }
case ftmcpSetTargetResistanceLevel:
case ftmcpSetTargetSpeed:
case ftmcpSetTargetInclination:
case ftmcpSetTargetPower:
case ftmcpSetTargetHeartRate:
case ftmcpSetTargetedExpendedEngery:
case ftmcpSetTargetedNumberOfSteps:
case ftmcpSetTargetedNumberOfStrided:
case ftmcpSetTargetedDistance:
case ftmcpSetTargetedTrainingTime:
case ftmcpSetTargetedTimeInTwoHeartRateZones:
case ftmcpSetTargetedTimeInThreeHeartRateZones:
case ftmcpSetTargetedTimeInFiveHeartRateZones:
case ftmcpSetWheelCircumference:
case ftmcpSetSpinDownControl:
case ftmcpSetTargetedCadence:
  {

ifdef DEBUG

    Serial.println("Unresolved OpCode!");

endif

    break;
  }

} // switch }

void server_setupCPS(void) { // Configure the Cycling Power service server_CylingPower_Service.begin();

server_CP_Measurement_Chr.setProperties(CHR_PROPS_NOTIFY); // type is "notify" server_CP_Measurement_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // readAccess, writeAccess server_CP_Measurement_Chr.setMaxLen(MAX_PAYLOAD); // Will work in most cases! server_CP_Measurement_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_CP_Measurement_Chr.begin();

server_CP_ControlPoint_Chr.setProperties(CHR_PROPS_INDICATE | CHR_PROPS_WRITE); // Indicate and Write !! server_CP_ControlPoint_Chr.setPermission(SECMODE_OPEN, SECMODE_OPEN); // readAccess, writeAccess DO NOT SET: SECMODE_NO_ACCESS ! server_CP_ControlPoint_Chr.setMaxLen(CP_CONTROL_POINT_DATALEN); // The charactersitic's data set varies in length server_CP_ControlPoint_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_CP_ControlPoint_Chr.begin(); server_CP_ControlPoint_Chr.setWriteCallback(server_CP_ControlPoint_Chr_callback); // Respond to events with "Write with Response" !!

server_CP_Feature_Chr.setProperties(CHR_PROPS_READ); server_CP_Feature_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); server_CP_Feature_Chr.setMaxLen(CP_FEATURE_DATALEN); server_CP_Feature_Chr.begin(); server_CP_Feature_Chr.write32(client_CP_Feature_Flags);

server_CP_Location_Chr.setProperties(CHR_PROPS_READ); server_CP_Location_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); server_CP_Location_Chr.setFixedLen(1); // UINT8 server_CP_Location_Chr.begin(); server_CP_Location_Chr.write8(client_CP_Location_Value); // Set the characteristic }

void server_setupCSC() { // Configure the Cadence and Speed service server_CyclingSpeedCadence_Service.begin();

server_CSC_Measurement_Chr.setProperties(CHR_PROPS_NOTIFY); // because type "notify" server_CSC_Measurement_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // readAccess, writeAccess server_CSC_Measurement_Chr.setMaxLen(MAX_PAYLOAD); server_CSC_Measurement_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_CSC_Measurement_Chr.begin();

// Set the CSC Feature characteristic server_CSC_Feature_Chr.setProperties(CHR_PROPS_READ); server_CSC_Feature_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); server_CSC_Feature_Chr.setFixedLen(CSC_FEATURE_FIXED_DATALEN); server_CSC_Feature_Chr.begin(); server_CSC_Feature_Chr.write16(client_CSC_Feature_Flags);

// Configure the Sensor Location characteristic server_CSC_Location_Chr.setProperties(CHR_PROPS_READ); server_CSC_Location_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); server_CSC_Location_Chr.setFixedLen(1); server_CSC_Location_Chr.begin(); server_CSC_Location_Chr.write8(client_CSC_Location_Value); // Set the characteristic }

void server_CP_ControlPoint_Chr_callback(uint16_t conn_hdl, BLECharacteristic chr, uint8_t data, uint16_t len) { // Server CP Control Point data from Zwift is transferred to the Trainer // NO TREATMENT OF COMMAND !!! client_CP_ControlPoint_Chr.write_resp(data, len); // Just pass on and process later! // Not sure this is the right choice! // client_CP_ControlPoint_Chr.write(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t cpcpDataLen = (uint8_t)len; // Get the actual length of data bytes and type cast to (uint8_t) uint8_t cpcpData[cpcpDataLen]; memset(cpcpData, 0, cpcpDataLen); // set to zero // Display the raw request packet actual length Serial.printf(" -> Server CP Control Point Data [%d] [ ", cpcpDataLen); // Transfer the contents of data to cpcpData for (int i = 0; i < cpcpDataLen; i++) { if ( i <= sizeof(cpcpData)) { cpcpData[i] = *data++; // Display the raw request packet byte by byte in HEX Serial.printf("%02X ", cpcpData[i], HEX); } } Serial.println(" ] ");

endif

}

void server_connect_callback(uint16_t conn_handle) { char Peer_Name[MAX_PAYLOAD] = {0}; uint8_t Peer_Addr[6] = {0}; // Get the reference to current connection BLEConnection* connection = Bluefruit.Connection(conn_handle); connection->getPeerName(Peer_Name, sizeof(Peer_Name)); ble_gap_addr_t peer_address = connection->getPeerAddr(); memcpy(Peer_Addr, peer_address.addr, 6);

ifdef DEBUG

Serial.printf("Feather nRF52 (Peripheral) connected to Central device: [%s] MAC Address: ", Peer_Name); PrintPeerAddress(Peer_Addr); Serial.println();

endif

// Who has been exactly connected? // [1] Laptop is connecting if (memcmp(Peer_Addr, Laptop.PeerAddress, 6) == 0 ) { // Check Laptop MAC address // Laptop/PC is connecting ! memcpy(Laptop.PeerName, Peer_Name, sizeof(Peer_Name)); Laptop.conn_handle = conn_handle; Laptop.IsConnected = true; // MITM Server is connected with Central (Laptop/Smartphone) and ONLY // now enable the peripheral (trainer) to stream CPS, CSC and FTMS data... if(Trainer.IsConnected) { Client_Enable_Notify_Indicate(); }

ifdef DEBUG

Serial.println("Waiting for Central (Zwift) to set CCCD Notify/Indicate (enable) and start....");

endif

return; // We are done here!

} // [2] Smartphone is connecting memcpy(Smartphone.PeerName, Peer_Name, sizeof(Peer_Name)); Smartphone.conn_handle = conn_handle; Smartphone.IsConnected = true; memcpy(Smartphone.PeerAddress, Peer_Addr, 6);

ifdef DEBUG

Serial.println("Waiting for Central (Phone) to set NUS Txd 'Notify' and start....");

endif

}

/ Callback invoked when a connection is dropped @param conn_handle connection where this event happens @param reason is a BLE_HCI_STATUS_CODE / void server_disconnect_callback(uint16_t conn_handle, uint8_t reason) { if (Laptop.conn_handle == conn_handle ) { // Laptop/Desktop is disconnected Laptop.conn_handle = BLE_CONN_HANDLE_INVALID; Laptop.IsConnected = false;

ifdef DEBUG

Serial.printf("Server disconnected from Central (Laptop): [%s], reason: [%02X]\n", Laptop.PeerName, reason, HEX);

endif

} if (Smartphone.conn_handle == conn_handle ) { // Smartphone is disconnected Smartphone.conn_handle = BLE_CONN_HANDLE_INVALID; Smartphone.IsConnected = false;

ifdef DEBUG

Serial.printf("Server disconnected from Central (Phone): [%s], reason: [%02X]\n", Smartphone.PeerName, reason, HEX);

endif

} Bluefruit.Advertising.start(0); }

void server_cccd_callback(uint16_t conn_handle, BLECharacteristic* chr, uint16_t cccd_value) { // When changed, display the Notify/Indicate Status for all characteristics

ifdef DEBUG

Serial.printf("Central Device Updated CCCD to: [%d] --> ", cccd_value);

endif

// Check the characteristic UUID this CCCD callback is associated with, // in case this handler is used for multiple CCCD records. if (chr->uuid == server_CP_Measurement_Chr.uuid) { if (chr->notifyEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server CP: Measurement 'Notify' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server CP: Measurement 'Notify' disabled");

endif

}

}

if (chr->uuid == server_CP_ControlPoint_Chr.uuid) { if (chr->indicateEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server CP: ControlPoint 'Indicate' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server CP: ControlPoint 'Indicate' disabled");

endif

}

}

if (chr->uuid == server_CSC_Measurement_Chr.uuid) { if (chr->notifyEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server CSC: Measurement 'Notify' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server CSC: Measurement 'Notify' disabled");

endif

}

}

if (chr->uuid == server_FTM_IndoorBikeData_Chr.uuid) { if (chr->notifyEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server FTM: IndoorBikeData 'Notify' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server FTM: IndoorBikeData 'Notify' disabled");

endif

}

}

if (chr->uuid == server_FTM_TrainingStatus_Chr.uuid) { // Zwift is NOT interested at all !!! if (chr->notifyEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server FTM: TrainingStatus 'Notify' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server FTM: TrainingStatus 'Notify' disabled");

endif

}

}

if (chr->uuid == server_FTM_Status_Chr.uuid) { if (chr->notifyEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server FTM: Status 'Notify' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server FTM: Status 'Notify' disabled");

endif

}

}

if (chr->uuid == server_FTM_ControlPoint_Chr.uuid) { if (chr->indicateEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server FTM: ControlPoint 'Indicate' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server FTM: ControlPoint 'Indicate' disabled");

endif

}

}

if (chr->uuid == server_NUS_TXD_Chr.uuid) { if (chr->notifyEnabled(conn_handle)) {

ifdef DEBUG

  Serial.print("Server NUS: TXD 'Notify' enabled");

endif

} else {

ifdef DEBUG

  Serial.print("Server NUS: TXD 'Notify' disabled");

endif

}

}

ifdef DEBUG

Serial.println();

endif

} // end Server CCCD callback // ---------------------- END of SERVER SIDE FUNCTIONS -------------------------

Result :

18:15:39.969 -> Feather nRF52840 MITM supporting: CPS, CSC and FTMS 18:15:39.969 -> ------------------ Version 02.3 --------------------- 18:15:39.969 -> FTM Service and Chars are 'initialized' 18:15:39.969 -> CP Service and Chars are 'initialized' 18:15:39.969 -> CSC Service and Chars are 'initialized' 18:15:39.969 -> Generic Access Service and Chars are 'initialized' 18:15:39.969 -> Device Information Service and Chars are 'initialized' 18:15:39.969 -> Start Client-side Scanning for CPS, CSC and FTMS! 18:15:39.969 -> Found advertising Peripheral with FTMS enabled! See Raw data packet: 18:15:39.969 -> Timestamp Addr Rssi Data 18:15:39.969 -> 000001090 F8:9C:FC:53:5E:49 -60 09-02-16-18-26-18-18-18-0A-18 18:15:39.969 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 18:15:39.969 -> Now checking all mandatory Client Services and Characteristics! 18:15:39.969 -> If Mandatory Services Fail --> the Client will disconnect! 18:15:39.969 -> First checking Generic Access and Device Information Services and Characteristics! 18:15:39.969 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 18:15:39.969 -> Discovering Client FTM Feature Characteristic ... Discovering Client FTM Control Point Characteristic ... Found it! 18:15:40.064 -> Discovering Client FTM Status Characteristic ... Found it! 18:15:40.391 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 18:15:40.672 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 18:15:40.827 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 18:15:40.827 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 18:15:41.088 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 18:15:41.088 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 18:15:41.368 -> Discovering Client Cycling Power (CP) Service ... Discovering Client CP Measurement characteristic ... Found it! 18:15:41.724 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 18:15:42.005 -> Discovering Client CP Feature characteristic ... Found it! 18:15:42.175 -> -> Client Reads Raw CP Feature bytes: [4] [ 00 00 00 00 ] 18:15:42.175 -> Discovering Client CP Sensor Location characteristic ... NOT Found! NOT Mandatory! 18:15:42.175 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 18:15:42.346 -> Discovering Client CSC Measurement CHR ... Found it! 18:15:42.532 -> Discovering Client CSC Location CHR ... Found it! 18:15:42.718 -> -> Client Reads CSC Location Sensor: Loc#: 0 Other 18:15:42.718 -> Discovering Client CSC Feature CHR ... Not Found! NOT Mandatory! 18:15:44.315 -> Configuring the Server Device Information Service 18:15:44.315 -> Configuring the Server Cycle Power Service 18:15:44.315 -> Configuring the Server Cadence and Speed Service 18:15:44.315 -> Configuring the Server Fitness Machine Service 18:15:44.315 -> Configuring the Server NUS Service 18:15:44.315 -> Setting up the Server-side advertising payload(s) 18:15:44.315 -> Setting Server Device Name to: [Sim ] 18:15:44.315 -> Setting Server Appearance to: [0] 18:15:44.315 -> Server-side is CPS, CSC and FTMS advertising! 18:17:45.853 -> Feather nRF52 (Peripheral) connected to Central device: [DESKTOP-1CC9OQN] MAC Address: 58:11:22:53:52:18 18:17:45.853 -> Ready to receive Client FTM Control Point Response Messages 18:17:45.900 -> Ready to receive Client FTM Status values 18:17:45.900 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 18:17:46.024 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 18:17:46.024 -> Ready to receive Client CP Measurement values 18:17:46.024 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 18:17:46.057 -> Ready to receive Client CSC Measurement values 18:17:46.057 -> Waiting for Central (Zwift) to set CCCD Notify/Indicate (enable) and start.... 18:17:50.388 -> Client- and Server-side are Up and Running! 18:17:51.217 -> Central Device Updated CCCD to: [1] --> Server CP: Measurement 'Notify' enabled 18:17:51.639 -> Central Device Updated CCCD to: [1] --> Server CSC: Measurement 'Notify' enabled 18:17:52.343 -> Central Device Updated CCCD to: [1] --> Server FTM: IndoorBikeData 'Notify' enabled 18:17:53.126 -> Central Device Updated CCCD to: [1] --> Server FTM: Status 'Notify' enabled 18:19:20.062 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 00] [Values: 00 ] 18:19:20.062 -> Request Control of Machine! 18:19:20.235 -> -> Client Rec'd Control Point Response: [ 80 00 01 ] 18:19:20.360 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 01] [Values: 00 ] 18:19:20.360 -> Reset Machine! 18:19:20.360 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 00] [Values: 00 ] 18:19:20.360 -> Request Control of Machine! 18:19:20.626 -> -> Client Rec'd Control Point Response: [ 80 01 01 ] 18:19:20.626 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 18:19:25.543 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 00] [Values: 00 ] 18:19:25.543 -> Request Control of Machine! 18:19:25.589 -> -> Client Rec'd Control Point Response: [ 80 00 01 ] 18:19:25.730 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 07] [Values: 00 ] 18:19:25.730 -> Start or Resume Machine! 18:19:25.869 -> -> Client Rec'd Control Point Response: [ 80 07 01 ] 18:19:25.869 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 18:19:26.804 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 CC 00 28 33 00 ] 18:19:26.804 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.04 | Crr (10000): 0.00 | Cw (100): 0.51 18:19:26.945 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:19:26.945 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CC 00 28 33 ] 18:19:55.908 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 84 00 28 33 00 ] 18:19:55.908 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.32 | Crr (10000): 0.00 | Cw (100): 0.51 18:19:56.293 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:19:56.293 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 00 28 33 ] 18:19:57.253 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 04 00 28 33 00 ] 18:19:57.253 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.04 | Crr (10000): 0.00 | Cw (100): 0.51 18:19:57.458 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:19:57.458 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 04 00 28 33 ] 18:19:58.366 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 2D 01 28 33 00 ] 18:19:58.366 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 3.01 | Crr (10000): 0.00 | Cw (100): 0.51 18:19:58.538 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:19:58.538 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 2D 01 28 33 ] 18:19:59.475 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 2C 01 28 33 00 ] 18:19:59.475 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 3.00 | Crr (10000): 0.00 | Cw (100): 0.51 18:19:59.616 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:19:59.616 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 2C 01 28 33 ] 18:20:01.176 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 2B 01 28 33 00 ] 18:20:01.176 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.99 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:01.362 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:01.362 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 2B 01 28 33 ] 18:20:04.460 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 2A 01 28 33 00 ] 18:20:04.460 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.98 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:04.664 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:04.664 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 2A 01 28 33 ] 18:20:06.262 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 29 01 28 33 00 ] 18:20:06.262 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.97 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:06.434 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:06.434 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 29 01 28 33 ] 18:20:08.944 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 28 01 28 33 00 ] 18:20:08.944 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.96 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:09.069 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:09.069 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 28 01 28 33 ] 18:20:11.448 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 27 01 28 33 00 ] 18:20:11.448 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.95 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:11.494 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:11.494 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 27 01 28 33 ] 18:20:13.321 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 26 01 28 33 00 ] 18:20:13.321 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.94 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:13.477 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:13.477 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 26 01 28 33 ] 18:20:15.857 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 25 01 28 33 00 ] 18:20:15.857 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.93 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:16.183 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:16.183 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 01 28 33 ] 18:20:17.808 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 24 01 28 33 00 ] 18:20:17.808 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.92 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:18.059 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:18.059 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 24 01 28 33 ] 18:20:18.953 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 23 01 28 33 00 ] 18:20:18.953 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.91 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:19.139 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:19.139 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 01 28 33 ] 18:20:21.451 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 22 01 28 33 00 ] 18:20:21.451 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.90 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:21.670 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:21.670 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 18:20:22.628 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 21 01 28 33 00 ] 18:20:22.628 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.89 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:22.722 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:22.722 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 21 01 28 33 ] 18:20:24.290 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 20 01 28 33 00 ] 18:20:24.290 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.88 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:24.370 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:24.370 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 20 01 28 33 ] 18:20:25.946 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1F 01 28 33 00 ] 18:20:25.946 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.87 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:26.165 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:26.165 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1F 01 28 33 ] 18:20:26.994 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1E 01 28 33 00 ] 18:20:26.994 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.86 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:27.150 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:27.150 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1E 01 28 33 ] 18:20:28.998 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1D 01 28 33 00 ] 18:20:28.998 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.85 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:29.170 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:29.170 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1D 01 28 33 ] 18:20:29.985 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1C 01 28 33 00 ] 18:20:29.985 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.84 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:30.311 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:30.311 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 01 28 33 ] 18:20:31.250 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1B 01 28 33 00 ] 18:20:31.250 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.83 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:31.328 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 8:20:31.328 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1B 01 28 33 ] 18:20:32.141 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1A 01 28 33 00 ] 18:20:32.141 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.82 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:32.234 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:32.234 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1A 01 28 33 ] 18:20:33.843 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 19 01 28 33 00 ] 18:20:33.843 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.81 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:33.984 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:33.984 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 19 01 28 33 ] 18:20:34.948 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 18 01 28 33 00 ] 18:20:34.948 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.80 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:35.200 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:35.200 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 18 01 28 33 ] 18:20:36.098 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 17 01 28 33 00 ] 18:20:36.098 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.79 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:36.331 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:36.331 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 17 01 28 33 ] 18:20:37.287 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 16 01 28 33 00 ] 18:20:37.287 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.78 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:37.507 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:37.507 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 16 01 28 33 ] 18:20:38.335 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 14 01 28 33 00 ] 18:20:38.335 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.76 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:38.569 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 18:20:38.569 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 01 28 33 ] 18:20:39.430 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 13 01 28 33 00 ] 18:20:39.430 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.75 | Crr (10000): 0.00 | Cw (100): 0.51 18:20:39.525 -> -> Client Rec'd Control Point Response: [ 80 11 01 ]

Berg0162 commented 1 year ago

I have to look info this... How was your experience on the bike? Did you feel the resistance, grade is about 3%... ?

Op do 15 dec. 2022 19:09 schreef le-joebar @.***>:

I'll see if with the "While" in the "Bridge V23" version if it's better

The cadence is OK but I don't have the Watts!?

[image: 20221215_181851] https://user-images.githubusercontent.com/61932881/207935585-0f4be135-2c92-4284-819a-80c9edc65b79.jpg

Here is the modified code and the results :

/***** This is programming code for the nRF52 based Bluefruit BLE boards

The code uses heavily the Adafruit supplied Bluefruit BLE libraries !! Adafruit invests time and resources providing open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!

MIT license, check LICENSE for more information
All text must be included in any redistribution

*****/ /*

This code should work with all indoor cycling trainers that fully support, Fitness Machine Service, Cycling Power Service and Cycling Speed & Cadence Service

The code links a BLE Server (a peripheral to Zwift) and a BLE Client (a central to the Trainer) with a bridge in between, the Feather nRF52 being man-in-the-middle (MITM). The nRF52-bridge can control, filter and alter the bi-directional interchanged data! The client-side (central) scans and connects with the trainer relevant services: FTMS, CPS and CSC. It collects all cyling data of the services and passes these on to the server-side.... The client-side supplies the indoor trainer with target and resistance control data. The server-side (peripheral) advertises and enables connection with cycling apps like Zwift and collects the app's control commands, target and resistance data. It passes these on to the client-side.... The server-side supplies the app with the generated cycling data in return.

The client plus server (MITM) are transparent to the indoor trainer as well as to the training app Zwift or alike!

Requirements: Zwift app or alike, Feather nRF52 board and a FTMS/CPS/CSC supporting indoor trainer 1) Upload and Run this code on the Feather nRF52 2) Start the Serial Monitor to catch debugging info 3) Start/Power On the indoor trainer 4) Feather nRF52 and trainer (with ) will pair as reported in the output 5) Start Zwift on your computer or tablet and wait.... 6) Search on the Zwift pairing screens for the Feather nRF52 a.k.a. "Sim " 7) Pair: Power, Cadence and Controllable one after another with "Sim " 8) Optionally one can pair as well devices for heartrate and/or steering (Sterzo) 9) Start the default Zwift ride or any ride you wish

  1. Make Serial Monitor output window visible on top of the Zwift window
  2. Hop on the bike: do the work and feel resistance change with the road
  3. Inspect the info presented by Serial Monitor.....

Your trainer's device is modified by the bridge to "Sim ", to allow for a clear distinction between the bridge (simulating your trainer) and your original trainer, when advertising the trainer's services! You will notice this only when connecting to Zwift on the pairing screens! Notice: Zwift extends device names with additional numbers for identification!

*/

//

// COMPILER DIRECTIVE to allow/suppress SERIAL.PRINT messages that help debugging... // Uncomment to activate

define DEBUG

// Restrict activating one or more of the following DEBUG directives --> process intensive // Have caused spurious side effects like a loss of quality of service handling!! //#define DEBUG_CP_MEASUREMENT //#define DEBUG_CSC_MEASUREMENT //#define DEBUG_FTM_INDOORBIKEDATA //

include

const uint8_t MAX_PAYLOAD = 20; // Max 20 byte data size for single packet BLE transfer

// Struct containing Device info to administer dis/connected devices typedef struct { uint8_t PeerAddress[6]; char PeerName[MAX_PAYLOAD]; uint16_t conn_handle; bool IsConnected; } Device_info_t; // ----------------------------------------------------------------- // Your hardware MAC/DEVICE ADDRESSES // Laptop/Desktop Device Address that runs Zwift, in printed format: [00:01:02:03:04:05] // Little Endian: in reversed order !!!!

define LAPTOPADDRESS {0x18,0x52,0x53,0x22,0x11,0x58}

// Trainer FTMS enabled Device Address, in printed format: [00:01:02:03:04:05] // Little Endian: in reversed order !!!!

define TRAINERADDRESS {0x49,0x5E,0x53,0xFC,0x9C,0xF8}

// ----------------------------------------------------------------- // Initialize connectable device registration Device_info_t Trainer = {TRAINERADDRESS, {0x00}, BLE_CONN_HANDLE_INVALID, false}; Device_info_t Laptop = { LAPTOPADDRESS, {0x00}, BLE_CONN_HANDLE_INVALID, false}; Device_info_t Smartphone = { {0x00}, {0x00}, BLE_CONN_HANDLE_INVALID, false}; //

/* Generic Access

define UUID16_SVC_GENERIC_ACCESS 0x1800

define UUID16_CHR_DEVICE_NAME 0x2A00

define UUID16_CHR_APPEARANCE 0x2A01

define UUID16_CHR_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS 0x2A04 --->

not implemented

define UUID16_CHR_CENTRAL_ADDRESS_RESOLUTION 0x2AA6 ---> not implemented

*/ BLEClientService client_GenericAccess_Service(UUID16_SVC_GENERIC_ACCESS); // Optional BLEClientCharacteristic client_GA_Appearance_Chr(UUID16_CHR_APPEARANCE); // Read uint16_t client_GA_Appearance_Value = 0; BLEClientCharacteristic client_GA_DeviceName_Chr(UUID16_CHR_DEVICE_NAME); // Read, Write unsigned char client_GA_DeviceName_Data[MAX_PAYLOAD] = {};

/* Cycling Power Service CP Service: 0x1818 CP Characteristic: 0x2A63 (Measurement) CP Characteristic: 0x2A65 (Feature) CP Characteristic: 0x2A5D (Location) CP Characteristic: 0x2A66 (Control Point)

/ BLEClientService client_CyclingPower_Service(UUID16_SVC_CYCLING_POWER); // Mandatory BLEClientCharacteristic client_CP_Measurement_Chr(UUID16_CHR_CYCLING_POWER_MEASUREMENT); // Notify, Read, Mandatory BLEClientCharacteristic client_CP_Feature_Chr(UUID16_CHR_CYCLING_POWER_FEATURE); // Read, optional uint32_t client_CP_Feature_Flags = 0; const uint8_t CP_FEATURE_DATALEN = 4; // Set MaxLen to 4 const char client_CP_Feature_Str[] = { "Pedal power balance supported", "Accumulated torque supported", "Wheel revolution data supported", "Crank revolution data supported", "Extreme magnitudes supported", "Extreme angles supported", "Top/bottom dead angle supported", "Accumulated energy supported", "Offset compensation indicator supported", "Offset compensation supported", "Cycling power measurement characteristic content masking supported", "Multiple sensor locations supported", "Crank length adj. supported", "Chain length adj. supported", "Chain weight adj. supported", "Span length adj. supported", "Sensor measurement context", "Instantaineous measurement direction supported", "Factory calibrated date supported", "Enhanced offset compensation supported" }; BLEClientCharacteristic client_CP_Location_Chr(UUID16_CHR_SENSOR_LOCATION); // Read, optional uint8_t client_CP_Location_Value = 0; // UINT8 const char* client_Sensor_Location_Str[] = { "Other", "Top of shoe", "In shoe", "Hip", "Front wheel", "Left crank", "Right crank", "Left pedal", "Right pedal", "Front hub", "Rear dropout", "Chainstay", "Rear wheel", "Rear hub", "Chest", "Spider", "Chain ring" }; BLEClientCharacteristic client_CP_ControlPoint_Chr(UUID16_CHR_CYCLING_POWER_CONTROL_POINT); // Indicate, Write, optional const uint16_t CP_CONTROL_POINT_DATALEN = 5;

/* Cycling Speed and Cadence Service CSC Service: 0x1816 CSC Measurement Characteristic: 0x2A5B CSC Feature Characteristic: 0x2A5C CSC Location Characteristic: 0x2A5D CSC Control Point Characteristic:0x2A55 ---> not implemented

/ BLEClientService client_CyclingSpeedCadence_Service(UUID16_SVC_CYCLING_SPEED_AND_CADENCE); // Mandatory BLEClientCharacteristic client_CSC_Measurement_Chr(UUID16_CHR_CSC_MEASUREMENT); // Notify, Read, Mandatory BLEClientCharacteristic client_CSC_Feature_Chr(UUID16_CHR_CSC_FEATURE); // Read, optional const uint8_t CSC_FEATURE_FIXED_DATALEN = 2; // UINT16 uint16_t client_CSC_Feature_Flags = 0; const char client_CSC_Feature_Str[] = {"Wheel rev supported", "Crank rev supported", "Multiple locations supported"}; BLEClientCharacteristic client_CSC_Location_Chr(UUID16_CHR_SENSOR_LOCATION); // Read, optional uint8_t client_CSC_Location_Value = 0; // Shared with CPS --> client_Sensor_Location_Str[]

/* Service Device Information

define UUID16_SVC_DEVICE_INFORMATION 0x180A

define UUID16_CHR_MODEL_NUMBER_STRING 0x2A24

define UUID16_CHR_SERIAL_NUMBER_STRING 0x2A25

define UUID16_CHR_FIRMWARE_REVISION_STRING 0x2A26 ---> not implemented

define UUID16_CHR_HARDWARE_REVISION_STRING 0x2A27 ---> not implemented

define UUID16_CHR_SOFTWARE_REVISION_STRING 0x2A28 ---> not implemented

define UUID16_CHR_MANUFACTURER_NAME_STRING 0x2A29

*/ BLEClientService client_DIS_Service(UUID16_SVC_DEVICE_INFORMATION); // Optional BLEClientCharacteristic client_DIS_ManufacturerName_Chr(UUID16_CHR_MANUFACTURER_NAME_STRING); // Read char client_DIS_Manufacturer_Str[MAX_PAYLOAD] = {}; BLEClientCharacteristic client_DIS_ModelNumber_Chr(UUID16_CHR_MODEL_NUMBER_STRING); // Read char client_DIS_ModelNumber_Str[MAX_PAYLOAD] = {}; BLEClientCharacteristic client_DIS_SerialNumber_Chr(UUID16_CHR_SERIAL_NUMBER_STRING); // Read char client_DIS_SerialNumber_Str[MAX_PAYLOAD] = {};

/* Fitness Machine Service

define UUID16_SVC_FITNESS_MACHINE 0x1826

define UUID16_CHR_FITNESS_MACHINE_FEATURE 0x2ACC

define UUID16_CHR_INDOOR_BIKE_DATA 0x2AD2

define UUID16_CHR_TRAINING_STATUS 0x2AD3

define UUID16_CHR_SUPPORTED_SPEED_RANGE 0x2AD4 ---> not implemented

define UUID16_CHR_SUPPORTED_INCLINATION_RANGE 0x2AD5 ---> not implemented

define UUID16_CHR_SUPPORTED_RESISTANCE_LEVEL_RANGE 0x2AD6

define UUID16_CHR_SUPPORTED_HEART_RATE_RANGE 0x2AD7 ---> not implemented

define UUID16_CHR_SUPPORTED_POWER_RANGE 0x2AD8

define UUID16_CHR_FITNESS_MACHINE_CONTROL_POINT 0x2AD9

define UUID16_CHR_FITNESS_MACHINE_STATUS 0x2ADA

*/ BLEClientService client_FitnessMachine_Service(UUID16_SVC_FITNESS_MACHINE); // Mandatory // Service characteristics exposed by FTM Service BLEClientCharacteristic client_FTM_Feature_Chr(UUID16_CHR_FITNESS_MACHINE_FEATURE); // Mandatory, Read const uint8_t FTM_FEATURE_FIXED_DATALEN = 8; uint8_t client_FTM_Feature_Data[FTM_FEATURE_FIXED_DATALEN]; BLEClientCharacteristic client_FTM_IndoorBikeData_Chr(UUID16_CHR_INDOOR_BIKE_DATA); // Optional, Notify BLEClientCharacteristic client_FTM_TrainingStatus_Chr(UUID16_CHR_TRAINING_STATUS); // Optional, Read & Notify BLEClientCharacteristic client_FTM_SupportedResistanceLevelRange_Chr(UUID16_CHR_SUPPORTED_RESISTANCE_LEVEL_RANGE); // Mandatory, Read const uint8_t FTM_SRLR_FIXED_DATALEN = 6; uint8_t client_FTM_SupportedResistanceLevelRange_Data[FTM_SRLR_FIXED_DATALEN]; BLEClientCharacteristic client_FTM_SupportedPowerRange_Chr(UUID16_CHR_SUPPORTED_POWER_RANGE); // Mandatory, Read const uint8_t FTM_SPR_FIXED_DATALEN = 6; uint8_t client_FTM_SupportedPowerRange_Data[FTM_SPR_FIXED_DATALEN]; BLEClientCharacteristic client_FTM_ControlPoint_Chr(UUID16_CHR_FITNESS_MACHINE_CONTROL_POINT); // Mandatory, Write & Indicate BLEClientCharacteristic client_FTM_Status_Chr(UUID16_CHR_FITNESS_MACHINE_STATUS); // Mandatory, Notify

// ------------------------------------ START of SERVER DEFINITIONS

/ Cycling Speed and Cadence Service / BLEService server_CyclingSpeedCadence_Service = BLEService(UUID16_SVC_CYCLING_SPEED_AND_CADENCE); BLECharacteristic server_CSC_Measurement_Chr = BLECharacteristic(UUID16_CHR_CSC_MEASUREMENT); // Notify, Read BLECharacteristic server_CSC_Feature_Chr = BLECharacteristic(UUID16_CHR_CSC_FEATURE); // Read BLECharacteristic server_CSC_Location_Chr = BLECharacteristic(UUID16_CHR_SENSOR_LOCATION); // Read

/ Cycling Power Service / BLEService server_CylingPower_Service = BLEService(UUID16_SVC_CYCLING_POWER); BLECharacteristic server_CP_Measurement_Chr = BLECharacteristic(UUID16_CHR_CYCLING_POWER_MEASUREMENT); // Notify, Read BLECharacteristic server_CP_Feature_Chr = BLECharacteristic(UUID16_CHR_CYCLING_POWER_FEATURE); // Read BLECharacteristic server_CP_Location_Chr = BLECharacteristic(UUID16_CHR_SENSOR_LOCATION); // Read BLECharacteristic server_CP_ControlPoint_Chr = BLECharacteristic(UUID16_CHR_CYCLING_POWER_CONTROL_POINT); // Indicate, Write

/ Fitness Machine Service / BLEService server_FitnessMachine_Service = BLEService(UUID16_SVC_FITNESS_MACHINE); BLECharacteristic server_FTM_Feature_Chr = BLECharacteristic(UUID16_CHR_FITNESS_MACHINE_FEATURE); // Read BLECharacteristic server_FTM_IndoorBikeData_Chr = BLECharacteristic(UUID16_CHR_INDOOR_BIKE_DATA); // Notify BLECharacteristic server_FTM_TrainingStatus_Chr = BLECharacteristic(UUID16_CHR_TRAINING_STATUS); // Notify, Read const uint8_t FTM_TRAINING_STATUS_FIXED_DATALEN = 2; // Fixed len BLECharacteristic server_FTM_SupportedResistanceLevelRange_Chr = BLECharacteristic(UUID16_CHR_SUPPORTED_RESISTANCE_LEVEL_RANGE); // Read BLECharacteristic server_FTM_SupportedPowerRange_Chr = BLECharacteristic(UUID16_CHR_SUPPORTED_POWER_RANGE); // Read BLECharacteristic server_FTM_ControlPoint_Chr = BLECharacteristic(UUID16_CHR_FITNESS_MACHINE_CONTROL_POINT); // Write & Indicate BLECharacteristic server_FTM_Status_Chr = BLECharacteristic(UUID16_CHR_FITNESS_MACHINE_STATUS); // Notify const uint8_t FTM_STATUS_DATALEN = 7; // Max Len was: [3] --> Notice that with de Elite Direto the size is: [7] !!

/ Device Information Service helper class instance / BLEDis server_bledis; // Read unsigned char FirmwareRevStr[] = "0.0.0"; unsigned char HardwareRevStr[] = "0.0.0"; unsigned char SoftwareRevStr[] = "0.0.0";

/ NORDIC UART SERVICE a.k.a. NUS NUS Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E NUS RXD : 6E400002-B5A3-F393-E0A9-E50E24DCCA9E NUS TXD : 6E400003-B5A3-F393-E0A9-E50E24DCCA9E / const uint8_t UUID_NUS_SERVICE[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E}; const uint8_t UUID_NUS_CHR_RXD[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E}; const uint8_t UUID_NUS_CHR_TXD[] = {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E}; BLEService server_NordicUart_Service = BLEService(UUID_NUS_SERVICE); BLECharacteristic server_NUS_RXD_Chr = BLECharacteristic(UUID_NUS_CHR_RXD); // Read (Receiving Data) BLECharacteristic server_NUS_TXD_Chr = BLECharacteristic(UUID_NUS_CHR_TXD); // Notify (Sending Data)

// ----------------------------- The Fitness Machine Control Point data type structure -------------------------------- // ---------------------------- Decoding is done in: server_FTM_ControlPoint_Chr_callback ------------------------------ const uint8_t ftmcpRequestControl = 0x00; const uint8_t ftmcpReset = 0x01; const uint8_t ftmcpSetTargetSpeed = 0x02; const uint8_t ftmcpSetTargetInclination = 0x03; const uint8_t ftmcpSetTargetResistanceLevel = 0x04; const uint8_t ftmcpSetTargetPower = 0x05; const uint8_t ftmcpSetTargetHeartRate = 0x06; const uint8_t ftmcpStartOrResume = 0x07; const uint8_t ftmcpStopOrPause = 0x08; const uint8_t ftmcpSetTargetedExpendedEngery = 0x09; const uint8_t ftmcpSetTargetedNumberOfSteps = 0x0A; const uint8_t ftmcpSetTargetedNumberOfStrided = 0x0B; const uint8_t ftmcpSetTargetedDistance = 0x0C; const uint8_t ftmcpSetTargetedTrainingTime = 0x0D; const uint8_t ftmcpSetTargetedTimeInTwoHeartRateZones = 0x0E; const uint8_t ftmcpSetTargetedTimeInThreeHeartRateZones = 0x0F; const uint8_t ftmcpSetTargetedTimeInFiveHeartRateZones = 0x10; const uint8_t ftmcpSetIndoorBikeSimulationParameters = 0x11; const uint8_t ftmcpSetWheelCircumference = 0x12; const uint8_t ftmcpSetSpinDownControl = 0x13; const uint8_t ftmcpSetTargetedCadence = 0x14;

const uint8_t FTM_CONTROL_POINT_DATALEN = 19; // Control point consists of 1 opcode (byte) and maximum 18 bytes as parameters // This ftmcp_data_t structure represents the control point data. The first octet represents the opcode of the request // followed by a parameter array of maximum 18 octects typedef struct attribute( ( packed ) ) { uint8_t OPCODE; uint8_t OCTETS[(FTM_CONTROL_POINT_DATALEN - 1)]; } ftmcp_data_t; typedef union // The union type automatically maps the bytes member array to the ftmcp_data_t structure member values { ftmcp_data_t values; uint8_t bytes[FTM_CONTROL_POINT_DATALEN]; } ftmcp_data_ut; // Fitness Machine Control Point Data variable ftmcp_data_ut server_FTM_Control_Point_Data; // ----------------------- end of server_FTM_ControlPoint_Chr_callback definitions ----------------------------

// -------------------------------------- END OF SERVER DEFINITIONS

//

// Global Server variables for decoding of INDOOR BIKE RESISTANCE PARAMETERS //

float wind_speed = 0; // meters per second, resolution 0.001 float grade = 0; // percentage, resolution 0.01 float crr = 0; // Coefficient of rolling resistance, resolution 0.0001 float cw = 0; // Wind resistance Kg/m, resolution 0.01; //

define TIME_SPAN 5000 // Time span in millis 1000 = 1 second

unsigned long TimeInterval = 0;

void setup() {

ifdef DEBUG

Serial.begin(115200); while ( !Serial ) delay(10); // for nrf52840 with native usb Serial.println("Feather nRF52840 MITM supporting: CPS, CSC and FTMS"); Serial.println("------------------ Version 02.3 ---------------------");

endif

// Initialize Bluefruit with maximum connections as Peripheral = 1, Central = 1 Bluefruit.begin(1, 1); Setup_Client_FTMS(); Setup_Client_CPS(); Setup_Client_CSC(); Setup_Client_DIS(); Client_Start_Scanning();

while (Bluefruit.Scanner.isRunning()) { // do nothing else but scanning.... yield(); } // wait enough time or go on when Client/Central is connected and all set! TimeInterval = millis() + TIME_SPAN; // ADD just enough delay while ( (millis() < TimeInterval) || (!Trainer.IsConnected) ) { yield(); }

// Configure and Start the Device Information Service

ifdef DEBUG

Serial.println("Configuring the Server Device Information Service");

endif

server_setupDIS(); // Setup the Cycle Power Service, Speed & Cadence Service and FTMS

ifdef DEBUG

Serial.println("Configuring the Server Cycle Power Service");

endif

server_setupCPS();

ifdef DEBUG

Serial.println("Configuring the Server Cadence and Speed Service");

endif

server_setupCSC();

ifdef DEBUG

Serial.println("Configuring the Server Fitness Machine Service");

endif

server_setupFTMS();

ifdef DEBUG

Serial.println("Configuring the Server NUS Service");

endif

server_setupNUS(); // Setup and start advertising

ifdef DEBUG

Serial.println("Setting up the Server-side advertising payload(s)");

endif

server_startADV();

ifdef DEBUG

Serial.println("Server-side is CPS, CSC and FTMS advertising!");

endif

while (Bluefruit.Advertising.isRunning()) { // ONLY advertise! yield(); } TimeInterval = millis() + TIME_SPAN; // ADD just enough DELAY // wait enough time or go on when Server/Peripheral is connected and set! while ( (millis() < TimeInterval) || (!Laptop.IsConnected) ) { yield(); }

ifdef DEBUG

Serial.println("Client- and Server-side are Up and Running!");

endif

}

// ---------------------- CLIENT SIDE FUNCTIONS ------------------------- void Setup_Client_FTMS(void) { // Initialize client FTM Service client_FitnessMachine_Service.begin();

// Initialize client FTM Feature characteristic client_FTM_Feature_Chr.begin();

// Initialize client FTM Training Status characteristic

client_FTM_TrainingStatus_Chr.setNotifyCallback(client_FTM_TrainingStatus_Notify_callback); client_FTM_TrainingStatus_Chr.begin();

// Initialize client FTM Supported Power Range characteristic client_FTM_SupportedPowerRange_Chr.begin();

// Initialize client FTM Supported Resistance Level Range characteristic client_FTM_SupportedResistanceLevelRange_Chr.begin();

// Initialize client FTM Indoor Bike Data characteristic

client_FTM_IndoorBikeData_Chr.setNotifyCallback(client_FTM_IndoorBikeData_Notify_callback); client_FTM_IndoorBikeData_Chr.begin();

// Initialize client FTM Control Point characteristic // For receiving Control Point Responses

client_FTM_ControlPoint_Chr.setIndicateCallback(client_FTM_ControlPoint_Indicate_callback); client_FTM_ControlPoint_Chr.begin();

// Initialize client FTM Status characteristic client_FTM_Status_Chr.setNotifyCallback(client_FTM_Status_Notify_callback); client_FTM_Status_Chr.begin();

ifdef DEBUG

Serial.println("FTM Service and Chars are 'initialized'");

endif

}

void Setup_Client_CPS(void) { // Initialize CPS client client_CyclingPower_Service.begin();

// Initialize CP Feature characteristics of client_CyclingPower_Service. client_CP_Feature_Chr.begin();

// Initialize CP sensor location characteristics of client_CyclingPower_Service. client_CP_Location_Chr.begin();

// set up callback for receiving measurement

client_CP_Measurement_Chr.setNotifyCallback(client_CP_Measurement_Chr_notify_callback); client_CP_Measurement_Chr.begin();

// Initialize Control Point and set up Indicate callback for receiving responses (indicate!)

client_CP_ControlPoint_Chr.setIndicateCallback(client_CP_ControlPoint_Chr_indicate_callback); client_CP_ControlPoint_Chr.begin();

ifdef DEBUG

Serial.println("CP Service and Chars are 'initialized'");

endif

}

void Setup_Client_CSC(void) { // Initialize CSC client client_CyclingSpeedCadence_Service.begin();

// Initialize client characteristics of CSC. client_CSC_Location_Chr.begin();

// Initialize CSC Feature characteristics of client_CSC. client_CSC_Feature_Chr.begin();

// set up callback for receiving measurement

client_CSC_Measurement_Chr.setNotifyCallback(client_CSC_Measurement_Chr_notify_callback); client_CSC_Measurement_Chr.begin();

ifdef DEBUG

Serial.println("CSC Service and Chars are 'initialized'");

endif

}

void Setup_Client_DIS(void) { // Initialize client Generic Access Service client_GenericAccess_Service.begin(); // Initialize some characteristics of the Generic Access Service. client_GA_DeviceName_Chr.begin(); client_GA_Appearance_Chr.begin();

ifdef DEBUG

Serial.println("Generic Access Service and Chars are 'initialized'");

endif

// Initialize client Device Information Service client_DIS_Service.begin(); // Initialize some characteristics of the Device Information Service. client_DIS_ManufacturerName_Chr.begin(); client_DIS_ModelNumber_Chr.begin(); client_DIS_SerialNumber_Chr.begin();

ifdef DEBUG

Serial.println("Device Information Service and Chars are 'initialized'");

endif

}

void loop() { } // end loop

void Client_Start_Scanning(void) { /* Start Central Scanning

  • Enable auto scan if disconnected
  • Interval = 100 ms, window = 80 ms
  • Don't use active scan
  • Filter only accept CP service
  • Start(timeout) with timeout = 0 will scan forever (until connected) */ // Client/Central Callbacks defined Bluefruit.Central.setDisconnectCallback(client_disconnect_callback); Bluefruit.Central.setConnectCallback(client_connect_callback); Bluefruit.Scanner.setRxCallback(client_scan_callback); Bluefruit.Scanner.restartOnDisconnect(false); // default is true !!! this stage we do not want to RESTART Bluefruit.Scanner.filterRssi(-70); // original value of -80 , we want to scan only nearby peripherals, so get close to your device !! Bluefruit.Scanner.setInterval(160, 80); // in unit of 0.625 ms // Invoke callback if CPS or CSC or FTMS is advertised Bluefruit.Scanner.filterUuid(UUID16_SVC_CYCLING_POWER, UUID16_SVC_CYCLING_SPEED_AND_CADENCE, UUID16_SVC_FITNESS_MACHINE); Bluefruit.Scanner.useActiveScan(true); Bluefruit.Scanner.start(0); // 500 // 0 = Don't stop scanning or n = after n/100 seconds

    ifdef DEBUG

    Serial.println("Start Client-side Scanning for CPS, CSC and FTMS!"); delay(100); // To show print message !

    endif

    }

void Client_Enable_Notify_Indicate(void) { // --------------------- Enable CP and CSC Notify and Indicate

// Reaching here means we are ready to go, let's enable notification on measurement chr // ------------------------- Enable FTMS Notify and Indicate

if ( client_FTM_ControlPoint_Chr.enableIndicate() ) { // MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Control Point Response Messages");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable indicate for Client FTM Control Point Characteristic."); Serial.println("FTMS (trainer) is controlled by another Client (Training App)!");

endif

Bluefruit.disconnect(Trainer.conn_handle); return; }

if ( client_FTM_Status_Chr.enableNotify() ) { // MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Status values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Status Characteristic."); Serial.println("FTMS (trainer) is controlled by another Client (Training App)!");

endif

Bluefruit.disconnect(Trainer.conn_handle); return; }

if ( client_FTM_TrainingStatus_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Training Status values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Training Status Characteristic.");

endif

}

if ( client_FTM_IndoorBikeData_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client FTM Indoor Bike Data values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic.");

endif

} // ------------------------- Enable FTMS Notify and Indicate

// --------------------- Enable CP and CSC Notify and Indicate

if ( client_CP_Measurement_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CP Measurement values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client CP Measurement Characteristic.");

endif

}

if ( client_CP_ControlPoint_Chr.enableIndicate() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CP Control Point Responses");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable indicate for Client CP Control Point Characteristic.");

endif

}

if ( client_CSC_Measurement_Chr.enableNotify() ) { // NOT MANDATORY

ifdef DEBUG

Serial.println("Ready to receive Client CSC Measurement values");

endif

} else {

ifdef DEBUG

Serial.println(">>> Couldn't enable notify for Client CSC Measurement Characteristic.");

endif

} // ------------------------- Enable CP and CSC Notify and Indicate

} // ------------------------- Enable FTMS Notify and Indicate

/** Hooked callback that triggered when a status value is sent @param https://github.com/param chr Pointer client characteristic @param https://github.com/param data Pointer to received data @param https://github.com/param len Length of received data

/ void client_FTM_TrainingStatus_Notify_callback(BLEClientCharacteristic chr, uint8_t* data, uint16_t len) { // Client Training Status data is tranferred to the Server // NO TREATMENT OF COMMAND !!! server_FTM_TrainingStatus_Chr.notify(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t SDataLen = (uint8_t)len; uint8_t SDataBuf[SDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw FTM Training Status Data: [%d] [ ", len); for (int i = 0; i < sizeof(SDataBuf); i++) { SDataBuf[i] = *data++; Serial.printf("%02X ", SDataBuf[i], HEX); } Serial.println("] ");

endif

}

/** Hooked callback that is triggered when an IBD value is sent @param https://github.com/param chr Pointer client characteristic @param https://github.com/param data Pointer to received data @param https://github.com/param len Length of received data

/ void client_FTM_IndoorBikeData_Notify_callback(BLEClientCharacteristic chr, uint8_t* data, uint16_t len) { // Client IBD data is tranferred to the Server // NO TREATMENT OF COMMAND !!! if (server_FTM_IndoorBikeData_Chr.notifyEnabled(Laptop.conn_handle)) { server_FTM_IndoorBikeData_Chr.notify(data, len); // Just pass on and process later! }

ifdef DEBUG_FTM_INDOORBIKEDATA

// Only when DEBUG_FTM_INDOORBIKEDATA is defined IDBData will be parsed and printed! ParseIndoorBikeData(data, len);

endif

}

ifdef DEBUG_FTM_INDOORBIKEDATA

void ParseIndoorBikeData(uint8_t data, uint16_t len) { // ---> IBD Buffer Data Length depends on data flagged to be present !!!! uint8_t IBDDataLen = (uint8_t)len; uint8_t IBDDataBuf[IBDDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw FTM IBD Data: [%d] [ ", len); for (int i = 0; i < sizeof(IBDDataBuf); i++) { IBDDataBuf[i] = data++; Serial.printf("%02X ", IBDDataBuf[i], HEX); } Serial.print("] ");

uint8_t offset = 0; uint16_t flags = 0; memcpy(&flags, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable offset += 2; // UINT16 if ((flags & 1) != 0) { // More Data Serial.print(" More Data!"); } // if ((flags & 2) != 0) { // (flags & 2) --> true or false Average Speed is always(?) there (tested with Elite Direto XR) // Average Speed 0.01 uint16_t sim_Speed = 0; memcpy(&sim_Speed, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Speed: %d KPH", (sim_Speed / 100)); offset += 2; // UINT16 // } if ((flags & 4) != 0) { // Instantaneous Cadence 0.5 uint16_t inst_Cadence = 0; memcpy(&inst_Cadence, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Instantaneous Cadence: %d RPM", (inst_Cadence / 2)); offset += 2; // UINT16 } if ((flags & 8) != 0) { // Average Cadence 0.5 uint16_t av_Cadence = 0; memcpy(&av_Cadence, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Average Cadence: %d RPM", (av_Cadence / 2)); offset += 2; // UINT16 } if ((flags & 16) != 0) { // Total Distance 1 uint32_t tot_Distance = 0; memcpy(&tot_Distance, &IBDDataBuf[offset], 3); // Transfer buffer fields to variable Serial.printf(" Total Distance: %d m", tot_Distance); offset += 3; // UINT24 } if ((flags & 32) != 0) { // Resistance Level 1 uint16_t res_Level = 0; memcpy(&res_Level, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Resistance Level: %d ", res_Level); offset += 2; // UINT16 } if ((flags & 64) != 0) { // Instantaneous Power 1 uint16_t inst_Power = 0; memcpy(&inst_Power, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Instantaneous Power: %d Watt", inst_Power); offset += 2; // UINT16 } if ((flags & 128) != 0) { // Average Power 1 uint16_t av_Power = 0; memcpy(&av_Power, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Average Power: %d Watt", av_Power); offset += 2; // UINT16 } if ((flags & 256) != 0) { // Expended Energy -> UINT16 UINT16 UINT8 // Total Energy UINT16 1 uint16_t tot_Energy = 0; memcpy(&tot_Energy, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Tot. Energy: %d kCal", tot_Energy); offset += 2; // UINT16 // Energy per hour UINT16 1 uint16_t Energy_hr = 0; memcpy(&Energy_hr, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Energy/hr: %d kCal/hr", Energy_hr); offset += 2; // UINT16 // Energy per minute UINT8 1 uint8_t Energy_pm = 0; memcpy(&Energy_pm, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Energy/m: %d kCal/m", Energy_pm); offset += 1; // UINT8 } if ((flags & 512) != 0) { // Heart Rate 1 uint8_t Heart_Rate = 0; memcpy(&Heart_Rate, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Heart Rate: %d HBM", Heart_Rate); offset += 1; // UINT8 } if ((flags & 1024) != 0) { // Metabolic Equivalent 0.1 uint8_t Mets = 0; memcpy(&Mets, &IBDDataBuf[offset], 1); // Transfer buffer fields to variable Serial.printf(" Metabolic Equivalent: %d ", Mets / 10); offset += 1; // UINT8 } if ((flags & 2048) != 0) { // Elapsed Time 1 uint16_t elap_time = 0; memcpy(&elap_time, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Elapsed time: %d s", elap_time); offset += 2; // UINT16 } if ((flags & 4096) != 0) { // Remaining Time 1 uint16_t rem_time = 0; memcpy(&rem_time, &IBDDataBuf[offset], 2); // Transfer buffer fields to variable Serial.printf(" Remaining time: %d s", rem_time); offset += 2; // UINT16 } Serial.println(); }

endif

/** Hooked callback that triggered when a value is sent @param https://github.com/param chr Pointer client characteristic @param https://github.com/param data Pointer to received data @param https://github.com/param len Length of received data

/ void client_FTM_ControlPoint_Indicate_callback(BLEClientCharacteristic chr, uint8_t* data, uint16_t len) { // The receipt of Control Point settings is acknowledged by the trainer: handle it // Send Client's Response message to the Server // NO TREATMENT OF COMMAND !!! server_FTM_ControlPoint_Chr.indicate(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t RespBufferLen = (uint8_t)len; uint8_t RespBuffer[RespBufferLen] = {}; // It is max 6 bytes long // Transfer first the contents of data to buffer (array of chars) Serial.print(" -> Client Rec'd Control Point Response: [ "); for (int i = 0; i < sizeof(RespBuffer); i++) { RespBuffer[i] = *data++; Serial.printf("%02X ", RespBuffer[i], HEX); } Serial.println("] ");

endif

}

/** Hooked callback that triggered when a value is sent @param https://github.com/param chr Pointer client characteristic @param https://github.com/param data Pointer to received data @param https://github.com/param len Length of received data

/ void client_FTM_Status_Notify_callback(BLEClientCharacteristic chr, uint8_t* data, uint16_t len) { // Client's Machine Status data is tranferred to the Server // NO TREATMENT OF COMMAND !!! server_FTM_Status_Chr.notify(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t SDataLen = (uint8_t)len; uint8_t SDataBuf[SDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw FTM Machine Status Data: [%d] [ ", len); for (int i = 0; i < sizeof(SDataBuf); i++) { SDataBuf[i] = *data++; Serial.printf("%02X ", SDataBuf[i], HEX); } Serial.println("] ");

endif

}

// Byte swap unsigned short uint16_t swap_uint16( uint16_t val ) { return (val << 8) | (val >> 8 ); }

// Find certain uuid in the data of the received advertising packet bool checkForUuidPresent(const uint16_t uuid, const uint8_t* reportData, uint8_t reportDataLen) { // Enter uuid in printed format like 0x1826 for UUID16_SVC_FITNESS_MACHINE // uuid is internally stored in Little Endian for (int i = 0; i < (reportDataLen); i++) { // step 1: never miss out a position! if ( memcmp(&uuid, (reportData + i), 2) == 0) { return true; } } return false; }

/** Callback invoked when scanner pick up an advertising data @param https://github.com/param report Structural advertising data

/ void client_scan_callback(ble_gap_evt_adv_report_t report) { // Since we configure the scanner with filterUuid(CPS, CSC, FTMS) // scan_callback is invoked for devices with usually CPS service advertised. // However, we only do business with FTMS enabled Trainer types so check // for UUID16_SVC_FITNESS_MACHINE to be present, if not --> keep scanning! uint8_t Device_Addr[6] = {0}; if (!checkForUuidPresent(UUID16_SVC_FITNESS_MACHINE, report->data.p_data, report->data.len)) { return; // Keep scanning for FTMS trainer !! } memcpy(Device_Addr, report->peer_addr.addr, 6); if ( !(memcmp(Device_Addr, Trainer.PeerAddress, 6) == 0) ) { return; // Keep scanning for the required trainer !! } // Connect to device only with required services AND device address if (Bluefruit.Scanner.isRunning()) { Bluefruit.Scanner.stop(); }

ifdef DEBUG

Serial.println("Found advertising Peripheral with FTMS enabled! See Raw data packet:"); Serial.println(F("Timestamp Addr Rssi Data")); Serial.printf("%09d ", millis()); // MAC is in little endian --> print reverse Serial.printBufferReverse(report->peer_addr.addr, 6, ':'); Serial.print(F(" ")); Serial.print(report->rssi); Serial.print(F(" ")); Serial.printBuffer(report->data.p_data, report->data.len, '-'); Serial.println();

endif

Bluefruit.Central.connect(report); }

ifdef DEBUG

void PrintPeerAddress(uint8_t addr[6]) { for (int i = 1; i < 6; i++) { // Display byte by byte in HEX reverse: little Endian Serial.printf("%02X:", addr[(6 - i)], HEX); } Serial.printf("%02X ", addr[0], HEX); }

endif

/** Callback invoked when a connection is established @param https://github.com/param conn_handle

/ void client_connect_callback(uint16_t conn_handle) { Trainer.conn_handle = conn_handle; // Get the reference to current connection BLEConnection connection = Bluefruit.Connection(conn_handle); connection->getPeerName(Trainer.PeerName, sizeof(Trainer.PeerName)); ble_gap_addr_t PeerAddr = connection->getPeerAddr(); // Fill BLE Gap struct memcpy(Trainer.PeerAddress, PeerAddr.addr, 6); // Copy Peer Address from ble_gap_addr_t struct

ifdef DEBUG

Serial.printf("Feather nRF52 (Central) connected to Trainer (Peripheral) device: [%s] MAC Address: ", Trainer.PeerName); PrintPeerAddress(Trainer.PeerAddress); Serial.println(); Serial.println("Now checking all mandatory Client Services and Characteristics!"); Serial.println("If Mandatory Services Fail --> the Client will disconnect!");

endif

// ---------------------------- GA and DIS SERVICE

ifdef DEBUG

Serial.println("First checking Generic Access and Device Information Services and Characteristics!");

endif

// If Generic Access is not found then go on.... NOT FATAL ! while (!(client_GenericAccess_Service.discover(conn_handle))) { if ( client_GenericAccess_Service.discover(conn_handle) ) {

ifdef DEBUG

Serial.print(F("Found Client Generic Access\n"));

endif

if ( client_GA_DeviceName_Chr.discover() ) { client_GA_DeviceName_Chr.read(client_GA_DeviceName_Data, sizeof(client_GA_DeviceName_Data));

ifdef DEBUG

Serial.printf(" -> Client Reads Device Name: [%s]\n", client_GA_DeviceName_Data);

endif

} if ( client_GA_Appearance_Chr.discover() ) { client_GA_Appearance_Value = client_GA_Appearance_Chr.read16();

ifdef DEBUG

Serial.printf(" -> Client Reads Appearance: [%d]\n", client_GA_Appearance_Value);

endif

} } // GA } // If DIS is not found then go on.... NOT FATAL !

while (!( client_DIS_Service.discover(conn_handle) )){ if ( client_DIS_Service.discover(conn_handle) ) {

ifdef DEBUG

Serial.print(F("Found Client Device Information\n"));

endif

// 1 if ( client_DIS_ManufacturerName_Chr.discover() ) { // read and print out Manufacturer if ( client_DIS_ManufacturerName_Chr.read(client_DIS_Manufacturer_Str, sizeof(client_DIS_Manufacturer_Str)) ) {

ifdef DEBUG

Serial.printf(" -> Client Reads Manufacturer: [%s]\n", client_DIS_Manufacturer_Str);

endif

} } // 1 // 2 if ( client_DIS_ModelNumber_Chr.discover() ) { // read and print out Model Number if ( client_DIS_ModelNumber_Chr.read(client_DIS_ModelNumber_Str, sizeof(client_DIS_ModelNumber_Str)) ) {

ifdef DEBUG

Serial.printf(" -> Client Reads Model Number: [%s]\n", client_DIS_ModelNumber_Str);

endif

} } // 2 // 3 if ( client_DIS_SerialNumber_Chr.discover() ) { // read and print out Serial Number if ( client_DIS_SerialNumber_Chr.read(client_DIS_SerialNumber_Str, sizeof(client_DIS_SerialNumber_Str)) ) {

ifdef DEBUG

Serial.printf(" -> Client Reads Serial Number: [%s]\n", client_DIS_SerialNumber_Str);

endif

} } // 3 } } // DIS // ---------------------------- END GA and DIS SERVICE

// -----------------------------FTM SERVICE

ifdef DEBUG

Serial.print("Discovering Mandatory Client Fitness Machine (FTM) Service ... ");

endif

// If FTM is not found, disconnect, resume scanning, and return if ( client_FitnessMachine_Service.discover(conn_handle) ) {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle); uint16_t max_payload = conn->getMtu()-3; uint16_t data_length = conn->getDataLength(); Serial.print("Found it! "); Serial.printf("FTMS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client FTM Service is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return; }

ifdef DEBUG

Serial.print("Discovering Client FTM Feature Characteristic ... ");

endif

// If FTM Feature is not found, disconnect, resume scanning, and return while (!( client_FTM_Feature_Chr.discover() )) { if ( client_FTM_Feature_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read FTM Feature Data client_FTM_Feature_Chr.read(client_FTM_Feature_Data, 8);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Feature bytes: [8] [ "); for (int i = 0; i < sizeof(client_FTM_Feature_Data); i++) { Serial.printf("%02X ", client_FTM_Feature_Data[i], HEX); } // for Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Disconnecting since Client FTM Feature Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); Bluefruit.Connection(conn_handle); Serial.print("Discovering Client FTM Feature not decouvert ... "); // return; } }

ifdef DEBUG

Serial.print("Discovering Client FTM Control Point Characteristic ... ");

endif

// If FTM Control Point is not found, disconnect, resume scanning, and return if ( client_FTM_ControlPoint_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Send a Request Control of Machine, OpCode == 0, no values! const uint8_t RCM[1] = {0}; client_FTM_ControlPoint_Chr.write_resp(RCM, 1); } else {

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client FTM Control Point Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); Bluefruit.Connection(conn_handle); Serial.print("Discovering Client FTM Feature not decouvert ... "); return; }

ifdef DEBUG

Serial.print("Discovering Client FTM Status Characteristic ... ");

endif

// If FTM Status is not found, disconnect, resume scanning, and return if ( client_FTM_Status_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client FTM Status Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return; }

ifdef DEBUG

Serial.print("Discovering Client FTM Training Status Characteristic ... ");

endif

// FTM Training Status is NOT MANDATORY if ( client_FTM_TrainingStatus_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory");

endif

} /*

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client FTM Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return; */

ifdef DEBUG

Serial.print("Discovering Client FTM Supported Resistance Level Range Characteristic ... ");

endif

// FTM SupportedResistanceLevelRange is not mandatory! if ( client_FTM_SupportedResistanceLevelRange_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read Supported Resistance Level Range Data client_FTM_SupportedResistanceLevelRange_Chr.read(client_FTM_SupportedResistanceLevelRange_Data, 6);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ "); for (int i = 0; i < sizeof(client_FTM_SupportedResistanceLevelRange_Data); i++) { Serial.printf("%02X ", client_FTM_SupportedResistanceLevelRange_Data[i], HEX); } // for Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT mandatory!");

endif

} / Serial.println("Disconnecting since Client FTM Supported Resistance Level Range Characteristic is mandatory!"); // MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return; /

ifdef DEBUG

Serial.print("Discovering Client FTM Supported Power Range Characteristic ... ");

endif

// FTM SupportedPowerRange is not mandatory! if ( client_FTM_SupportedPowerRange_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read Supported Resistance Level Range values client_FTM_SupportedPowerRange_Chr.read(client_FTM_SupportedPowerRange_Data, 6);

ifdef DEBUG

Serial.print(" -> Client Reads Raw FTM Supported Power Range bytes: [6] [ "); for (int i = 0; i < sizeof(client_FTM_SupportedPowerRange_Data); i++) { Serial.printf("%02X ", client_FTM_SupportedPowerRange_Data[i], HEX); } // for Serial.println("] ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT mandatory!");

endif

} /*

ifdef DEBUG

Serial.println("Disconnecting since Client FTM Supported Power Range Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return; */

ifdef DEBUG

Serial.print("Discovering Client FTM Indoor Bike Data Characteristic ... ");

endif

// FTM Indoor Bike Data is not mandatory if ( client_FTM_IndoorBikeData_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory");

endif

} /*

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client FTM Indoor Bike Data Characteristic is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); return;

/ // ---------------------------- End FTM SERVICE --------------------------------------------- // ---------------------------- CP SERVICE -------------------------------------------------- #ifdef DEBUG Serial.print("Discovering Client Cycling Power (CP) Service ... "); #endif // If CPS is not found, disconnect, resume scanning, and return while (!( client_CyclingPower_Service.discover(conn_handle) )) { if ( client_CyclingPower_Service.discover(conn_handle) ) { #ifdef DEBUG BLEConnection conn = Bluefruit.Connection(conn_handle); uint16_t max_payload = conn->getMtu()-3; uint16_t data_length = conn->getDataLength(); Serial.print("Found it! "); Serial.printf("CPS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client Cyling Power Service is mandatory!");

endif

// MANDATORY so disconnect since we couldn't find the service Bluefruit.disconnect(conn_handle); Bluefruit.Connection(conn_handle); Serial.print("Discovering Cycling Power (CP) Service not decouvert ... "); return; } }

ifdef DEBUG

Serial.print("Discovering Client CP Measurement characteristic ... ");

endif

if ( !client_CP_Measurement_Chr.discover() ) { // Measurement chr is mandatory, if it is not found (valid), then disconnect

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client CP Measurement Characteristic is mandatory!");

endif

Bluefruit.disconnect(conn_handle); return; } else {

ifdef DEBUG

Serial.println("Found it!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Control Point characteristic ... ");

endif

if ( client_CP_ControlPoint_Chr.discover() ) { // CP Control Point chr is not mandatory

ifdef DEBUG

Serial.println("Found it!");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Feature characteristic ... ");

endif

if ( client_CP_Feature_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// Configure the Cycle Power Feature characteristic // Properties = Read // Min Len = 1 // Max Len = 32 // B0:3 = UINT8 - Cycling Power Feature (MANDATORY) // b0 = Pedal power balance supported; 0 = false, 1 = true // b1 = Accumulated torque supported; 0 = false, 1 = true // b2 = Wheel revolution data supported; 0 = false, 1 = true // b3 = Crank revolution data supported; 0 = false, 1 = true // b4 = Extreme magnatudes supported; 0 = false, 1 = true // b5 = Extreme angles supported; 0 = false, 1 = true // b6 = Top/bottom dead angle supported; 0 = false, 1 = true // b7 = Accumulated energy supported; 0 = false, 1 = true // b8 = Offset compensation indicator supported; 0 = false, 1 = true // b9 = Offset compensation supported; 0 = false, 1 = true // b10 = Cycling power measurement characteristic content masking supported; 0 = false, 1 = true // b11 = Multiple sensor locations supported; 0 = false, 1 = true // b12 = Crank length adj. supported; 0 = false, 1 = true // b13 = Chain length adj. supported; 0 = false, 1 = true // b14 = Chain weight adj. supported; 0 = false, 1 = true // b15 = Span length adj. supported; 0 = false, 1 = true // b16 = Sensor measurement context; 0 = force, 1 = torque // b17 = Instantaineous measurement direction supported; 0 = false, 1 = true // b18 = Factory calibrated date supported; 0 = false, 1 = true // b19 = Enhanced offset compensation supported; 0 = false, 1 = true // b20:21 = Distribtue system support; 0 = legacy, 1 = not supported, 2 = supported, 3 = RFU // b22:32 = Reserved

// Read 32-bit client_CP_Feature_Chr value client_CP_Feature_Flags = client_CP_Feature_Chr.read32();

ifdef DEBUG

const uint8_t CPFC_FIXED_DATALEN = 4; uint8_t cpfcData[CPFC_FIXED_DATALEN] = {(uint8_t)(client_CP_Feature_Flags & 0xff), (uint8_t)(client_CP_Feature_Flags >> 8), (uint8_t)(client_CP_Feature_Flags >> 16), (uint8_t)(client_CP_Feature_Flags >> 24)}; Serial.print(" -> Client Reads Raw CP Feature bytes: [4] [ "); for (int i = 0; i < CPFC_FIXED_DATALEN; i++) { if ( i <= sizeof(cpfcData)) { Serial.printf("%02X ", cpfcData[i], HEX); } } Serial.println("] "); for (int i = 0; i < sizeof(client_CP_Feature_Str); i++) { if ( client_CP_Feature_Flags & (1 << i) ) { Serial.println(client_CP_Feature_Str[i]); } }

endif

} else {

ifdef DEBUG

Serial.println("NOT Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CP Sensor Location characteristic ... ");

endif

if ( client_CP_Location_Chr.discover() ) {

ifdef DEBUG

Serial.println("Found it!");

endif

// The Sensor Location characteristic // Properties = Read // Min Len = 1 // Max Len = 1 // B0:1 = UINT8 - Sensor Location

// Read 8-bit client CP sensor location value client_CP_Location_Value = client_CP_Location_Chr.read8();

ifdef DEBUG

Serial.print(" -> Client Reads CP Location Sensor: "); Serial.printf("Loc#: %d %s\n", client_CP_Location_Value, client_Sensor_Location_Str[client_CP_Location_Value]);

endif

} else {

ifdef DEBUG

Serial.println("NOT Found! NOT Mandatory!");

endif

} // ---------------------------- END CP SERVICE

// ---------------------------- CSC SERVICE

ifdef DEBUG

Serial.print("Discovering Cycling Speed and Cadence (CSC) Service ... ");

endif

if ( client_CyclingSpeedCadence_Service.discover(conn_handle) ) // UUID16_SVC_CYCLING_SPEED_AND_CADENCE {

ifdef DEBUG

BLEConnection* conn = Bluefruit.Connection(conn_handle); uint16_t max_payload = conn->getMtu()-3; uint16_t data_length = conn->getDataLength(); Serial.print("Found it! "); Serial.printf("CSCS Max Payload: %d Data Length: %d\n", max_payload, data_length);

endif

} else {

ifdef DEBUG

Serial.println("Not Found! CSC Service is Not Mandatory!");

endif

return; // NO CSC -> end of client_connect_callback !! } /* // Is Mandatory

ifdef DEBUG

Serial.println("Not Found and disconnecting!"); Serial.println("CSC Service is mandatory!");

endif

Bluefruit.disconnect(conn_handle); return; */

// Test for client CSC Characteristics when the client CSC Service is existing

ifdef DEBUG

Serial.print("Discovering Client CSC Measurement CHR ... ");

endif

if ( client_CSC_Measurement_Chr.discover() ) // UUID16_CHR_CSC_MEASUREMENT {

ifdef DEBUG

Serial.println("Found it! ");

endif

} else {

ifdef DEBUG

Serial.println("Not Found! Not Mandatory!");

endif

} /* // Is Mandatory

ifdef DEBUG

Serial.println("Not Found!"); Serial.println("Disconnecting since Client CSC Measurement CHR is mandatory!");

endif

Bluefruit.disconnect(conn_handle); return; */

ifdef DEBUG

Serial.print("Discovering Client CSC Location CHR ... ");

endif

if ( client_CSC_Location_Chr.discover() ) // UUID16_CHR_SENSOR_LOCATION {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read 16-bit client CSC sensor location value client_CSC_Location_Value = client_CSC_Location_Chr.read8();

ifdef DEBUG

Serial.print(" -> Client Reads CSC Location Sensor: "); Serial.printf("Loc#: %d %s\n", client_CSC_Location_Value, client_Sensor_Location_Str[client_CSC_Location_Value]);

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT Mandatory!");

endif

}

ifdef DEBUG

Serial.print("Discovering Client CSC Feature CHR ... ");

endif

if ( client_CSC_Feature_Chr.discover() ) // UUID16_CHR_CSC_FEATURE {

ifdef DEBUG

Serial.println("Found it!");

endif

// Read sensor CSC Feature value in 16 bit client_CSC_Feature_Flags = client_CSC_Feature_Chr.read16();

ifdef DEBUG

uint8_t cscfcData[CSC_FEATURE_FIXED_DATALEN] = { (uint8_t)(client_CSC_Feature_Flags & 0xff), (uint8_t)(client_CSC_Feature_Flags >> 8) }; // Little Endian Representation Serial.printf(" -> Client Reads Raw CSC Feature bytes: [2] [ "); for (int i = 0; i < sizeof(cscfcData); i++) { Serial.printf("%02X ", cscfcData[i], HEX); } Serial.println("] "); for (int i = 0; i < sizeof(client_CSC_Feature_Str); i++) { if ( (client_CSC_Feature_Flags & (1 << i)) != 0 ) { Serial.println(client_CSC_Feature_Str[i]); } }

endif

} else {

ifdef DEBUG

Serial.println("Not Found! NOT Mandatory!");

endif

} // ---------------------------- END CSC SERVICE

// Only now set true after ALL Mandatory Services and Char's have been discovered !!! Trainer.IsConnected = true; } // End client_connect_callback

/* Callback invoked when a connection is dropped @param https://github.com/param conn_handle @param https://github.com/param reason is a BLE_HCI_STATUS_CODE which can be found in ble_hci.h / void client_disconnect_callback(uint16_t conn_handle, uint8_t reason) {

ifdef DEBUG

Serial.printf("Client disconnected from Peripheral Device: [%s], reason: [%02X]\n", Trainer.PeerName, reason, HEX);

endif

Trainer.conn_handle = BLE_CONN_HANDLE_INVALID; Trainer.IsConnected = false; // Force server to disconnect! if (Laptop.conn_handle != BLE_CONN_HANDLE_INVALID) { Bluefruit.disconnect(Laptop.conn_handle); } }

/** Hooked callback that triggered when a measurement value is sent from peripheral @param https://github.com/param chr Pointer client characteristic in this example it should be cpmc @param https://github.com/param data Pointer to received data @param https://github.com/param len Length of received data

/ void client_CP_Measurement_Chr_notify_callback(BLEClientCharacteristic chr, uint8_t* data, uint16_t len) { // Client CP Measurement data is tranferred to the Server (Zwift) // NO TREATMENT OF RESPONSE !!!!! if (server_CP_Measurement_Chr.notifyEnabled(Laptop.conn_handle)) { server_CP_Measurement_Chr.notify(data, len); // Just pass on and process later! }

ifdef DEBUG_CP_MEASUREMENT

uint8_t buffer[len] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw CP Data: [%d] [ ", len); for (int i = 0; i < sizeof(buffer); i++) { if ( i <= sizeof(buffer)) { buffer[i] = *data++; Serial.printf("%02X ", buffer[i], HEX); } } Serial.print("] "); uint8_t offset = 0; // Get flags field uint16_t flags = 0; memcpy(&flags, &buffer[offset], 2); // Transfer buffer fields to variable offset += 2; // UINT16 // Get Instantaneous Power values UINT16 uint16_t PowerValue = 0; memcpy(&PowerValue, &buffer[offset], 2); // Transfer buffer fields to variable offset += 2; // UINT16 Serial.printf("Instantaneous Power: %4d\n", PowerValue); // Get the other CP measurement values if ((flags & 1) != 0) { // Power Balance Present Serial.print(" --> Pedal Power Balance!"); } if ((flags & 2) != 0) { // Accumulated Torque Serial.println(" --> Accumulated Torque!"); } // etcetera...

endif

} // End cpmc_notify_callback

/** Hooked callback that triggered when a response value is sent from peripheral @param https://github.com/param chr Pointer client characteristic @param https://github.com/param data Pointer to received data @param https://github.com/param len Length of received data

/ void client_CP_ControlPoint_Chr_indicate_callback(BLEClientCharacteristic chr, uint8_t* data, uint16_t len) { // Send Client's response message to the Server (Zwift) // NO TREATMENT OF RESPONSE !!!!! server_CP_ControlPoint_Chr.indicate(data, len); // Just pass on and process later!

ifdef DEBUG

uint8_t cpcpDataLen = (uint8_t)len; uint8_t cpcpData[cpcpDataLen] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw CP Control Point Data: [%d] [ ", len); for (int i = 0; i < sizeof(cpcpData); i++) { cpcpData[i] = *data++; Serial.printf("%02X ", cpcpData[i], HEX); } Serial.print("] ");

endif

}

/** Hooked callback that triggered when a measurement value is sent from peripheral @param https://github.com/param chr Pointer client characteristic @param https://github.com/param data Pointer to received data @param https://github.com/param len Length of received data

/ void client_CSC_Measurement_Chr_notify_callback(BLEClientCharacteristic chr, uint8_t* data, uint16_t len) { // Client CSC Measurement data is transferred to the Server (Zwift) // NO TREATMENT OF RESPONSE !!!!! if (server_CSC_Measurement_Chr.notifyEnabled(Laptop.conn_handle)) { server_CSC_Measurement_Chr.notify(data, len); // Just pass on and process later! }

ifdef DEBUG_CSC_MEASUREMENT

uint8_t buffer[len] = {}; // Transfer first the contents of data to buffer (array of chars) Serial.printf(" -> Client Rec'd Raw CSC Data: [%d] [ ", len); for (int i = 0; i < sizeof(buffer); i++) { if ( i <= sizeof(buffer)) { buffer[i] = *data++; Serial.printf("%02X ", buffer[i], HEX); } } Serial.print("] "); uint8_t offset = 0; // we define the offset that is to be used when reading the next field // Size of variables (e.g. 2 (16) or 4 bytes (32)) are constants in BluetoothGattCharacteristic // these represent the values you can find in the "Value Fields" table in the "Format" column // Read the Flags field at buffer[0] uint8_t flags = buffer[offset]; offset += 1; // UINT8 // we have to check the flags' nth bit to see if C1 field exists if ((flags & 1) != 0) { uint32_t cum_wheel_rev = 0; memcpy(&cum_wheel_rev, &buffer[offset], 4); offset += 4; // UINT32 uint16_t last_wheel_event = 0; memcpy(&last_wheel_event, &buffer[offset], 2); offset += 2; // UINT16 Serial.printf(" Cum. wheel rev.: %d Last wheel event: %d ", cum_wheel_rev, last_wheel_event); } // we have to check the flags' nth bit to see if C2 field exists if ((flags & 2) != 0) { uint16_t cum_cranks = 0; memcpy(&cum_cranks, &buffer[offset], 2); offset += 2; // UINT16 uint16_t last_crank_event = 0; memcpy(&last_crank_event, &buffer[offset], 2); offset += 2; // UINT16 Serial.printf(" Cum cranks: %d Last crank event: %d", cum_cranks, last_crank_event); } Serial.println();

endif

} // ---------------------- END of CLIENT SIDE FUNCTIONS

// ---------------------- START of SERVER SIDE FUNCTIONS

void server_setupNUS(void) { server_NordicUart_Service.begin(); // Add NUS TXD Characteristic server_NUS_TXD_Chr.setProperties(CHR_PROPS_NOTIFY); // Type "notify" server_NUS_TXD_Chr.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); // readAccess, NO writeAccess server_NUS_TXD_Chr.setMaxLen(MAX_PAYLOAD); // To be on the safe side! server_NUS_TXD_Chr.setCccdWriteCallback(server_cccd_callback); // Optionally capture CCCD updates server_NUS_TXD_Chr.begin();

// Add NUS RXD Characteristic server_NUS_RXD_Chr.setProperties(CHR_PROPS_WRITE | CHR_PROPS_WRITE_WO_RESP); // Write with No response !! server_NUS_RXD_Chr.setPermission(SECMODE_NO_ACCESS, SECMODE_OPEN); server_NUS_RXD_Chr.setMaxLen(MAX_PAYLOAD); // Maxlen server_NUS_RXD_Chr.setWriteCallback(server_NUS_RXD_Chr_callback); server_NUS_RXD_Chr.begin(); }

void server_NUS_RXD_Chr_callback(uint16_t conn_hdl, BLECharacteristic chr, uint8_t data, uint16_t len) { // Read data received over NUS RXD from Mobile Phone

ifdef DEBUG

uint8_t NusRxdDataLen = (uint8_t)len; // Get the actual length of data bytes and type cast to (uint8_t) char NusRxdData[MAX_PAYLOAD + 1]; // Data is all ASCII ! memset(NusRxdData, 0, MAX_PAYLOAD); // set to zero if (NusRxdDataLen > MAX_PAYLOAD) { NusRxdDataLen = MAX_PAYLOAD; // Check for limit } memcpy(NusRxdData, data, NusRxdDataLen); // Transfer data to char array // Display the raw packet data in actual length Serial.printf(" -> Server NUS RXD Data [%d][%s]\n", NusRxdDataLen, NusRxdData);

endif

}

void Construct_Dev_Name(void) { const char prefix[] = {'S', 'i'

Berg0162 commented 1 year ago

Dear Joel, With respect to FTMS_Zwift_Bridge: You inserted several While loops (in client_connect_callback): No doubt that you also have seen that these have negative (side-)effects, GA- and DIS readings are missed -> No manufacturer name, model number, et cetera. --> consequence later: empty variables:

18:15:44.315 -> Setting Server Device Name to: [Sim ] 18:15:44.315 -> Setting Server Appearance to: [0]

I do not see for example the trainer send IndoorBikeData to Zwift as a response to the resistance parameter settings..... nor a different output as we have seen before... My conclusion is: I am sorry but I do not see any improvement in the output/behavior, with some While loops, on the contrary. Next time just run the original uploaded FTMS Zwift Bridge version 023.

I am still missing the test of the latest uploaded FTMS_Client v027 (please without you inserting extra while loops).

Keep faith, somehow we will tackle the Hub connection problem! Beste wishes, Jörgen.

le-joebar commented 1 year ago

Dear Jörghen,

Here is the disappointing result.

The problem is still the same no feedback with V0.27

Let's not lose heart!

123456789101112131415161718192021 /***** This is programming code for the nRF52 based Bluefruit BLE boards

The code uses heavily the Adafruit supplied Bluefruit BLE libraries !! Adafruit invests time and resources providing open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit!

MIT license, check LICENSE for more information All text must be included in any redistribution

Message (Enter to send message to 'Adafruit ItsyBitsy nRF52840 Express' on 'COM11') New Line 115200 baud 16:59:01.080 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:59:01.080 -> ----------------- Version 02.7 ------------------ 16:59:01.080 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:59:01.205 -> FTMS and Chars 'initialized' 16:59:01.205 -> CPS and Chars 'initialized' 16:59:01.205 -> CSCS and Chars 'initialized' 16:59:01.205 -> GA and Chars 'initialized' 16:59:01.205 -> DIS and Chars 'initialized' 16:59:01.205 -> Start Scanning for CPS, CSC and FTMS! 16:59:01.434 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:59:01.434 -> Timestamp MAC Address Rssi Data 16:59:01.434 -> 000091471 F8:9C:FC:53:5E:49 -59 09-02-16-18-26-18-18-18-0A-18 16:59:01.575 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 16:59:01.575 -> Now checking all Client Services and Characteristics! 16:59:01.575 -> If Mandatory Services Fail --> the Client will disconnect! 16:59:01.575 -> First checking Generic Access and Device Information Services and Characteristics! 16:59:01.668 -> Found Client Generic Access 16:59:01.808 -> -> Client Reads Device Name: [Zwift Hub] 16:59:02.042 -> -> Client Reads Appearance: [0] 16:59:02.042 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 16:59:02.042 -> Disconnecting since Client FTM Service is mandatory! 16:59:02.121 -> Client Disconnected, reason = 0x16 16:59:02.121 -> >>> Restart the Feather nRF52 Client for a new run! <<< 16:59:12.257 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:59:12.257 -> ----------------- Version 02.7 ------------------ 16:59:12.257 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:59:12.257 -> FTMS and Chars 'initialized' 16:59:12.257 -> CPS and Chars 'initialized' 16:59:12.257 -> CSCS and Chars 'initialized' 16:59:12.257 -> GA and Chars 'initialized' 16:59:12.257 -> DIS and Chars 'initialized' 16:59:12.257 -> Start Scanning for CPS, CSC and FTMS! 16:59:12.258 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:59:12.258 -> Timestamp MAC Address Rssi Data 16:59:12.258 -> 000001100 F8:9C:FC:53:5E:49 -55 09-02-16-18-26-18-18-18-0A-18 16:59:12.258 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 16:59:12.258 -> Now checking all Client Services and Characteristics! 16:59:12.258 -> If Mandatory Services Fail --> the Client will disconnect! 16:59:12.258 -> First checking Generic Access and Device Information Services and Characteristics! 16:59:12.266 -> Found Client Generic Access 16:59:12.266 -> -> Client Reads Device Name: [Zwift Hub] 16:59:12.266 -> -> Client Reads Appearance: [1152] 16:59:12.266 -> Found Client Device Information 16:59:12.266 -> -> Client Reads Manufacturer: [Zwift]

le-joebar commented 1 year ago

Here is the result of FTMS_Zwift_Bridge_v023:

17:15:10.800 -> Feather nRF52840 MITM supporting: CPS, CSC and FTMS 17:15:10.800 -> ------------------ Version 02.3 --------------------- 17:15:10.804 -> FTM Service and Chars are 'initialized' 17:15:10.804 -> CP Service and Chars are 'initialized' 17:15:10.804 -> CSC Service and Chars are 'initialized' 17:15:10.804 -> Generic Access Service and Chars are 'initialized' 17:15:10.804 -> Device Information Service and Chars are 'initialized' 17:15:10.804 -> Start Client-side Scanning for CPS, CSC and FTMS! 17:15:10.805 -> Found advertising Peripheral with FTMS enabled! See Raw data packet: 17:15:10.805 -> Timestamp Addr Rssi Data 17:15:10.805 -> 000001606 F8:9C:FC:53:5E:49 -55 09-02-16-18-26-18-18-18-0A-18 17:15:10.805 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:15:10.805 -> Now checking all mandatory Client Services and Characteristics! 17:15:10.805 -> If Mandatory Services Fail --> the Client will disconnect! 17:15:10.805 -> First checking Generic Access and Device Information Services and Characteristics! 17:15:10.828 -> Found Client Generic Access 17:15:10.828 -> -> Client Reads Device Name: [Zwift Hub] 17:15:10.828 -> -> Client Reads Appearance: [1152] 17:15:10.828 -> Found Client Device Information 17:15:10.828 -> -> Client Reads Manufacturer: [Zwift] 17:15:10.829 -> -> Client Reads Model Number: [06] 17:15:10.920 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:15:10.920 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:15:11.008 -> Discovering Client FTM Feature Characteristic ... Found it! 17:15:11.124 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 17:15:11.124 -> Discovering Client FTM Control Point Characteristic ... Found it! 17:15:11.703 -> Discovering Client FTM Status Characteristic ... Found it! 17:15:11.984 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 17:15:12.285 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 17:15:12.402 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 17:15:12.402 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 17:15:12.742 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 00 00 00 00 ] 17:15:12.742 -> Discovering Client FTM Indoor Bike Data Characteristic ... Not Found! Not Mandatory 17:15:12.742 -> Discovering Client Cycling Power (CP) Service ... Not Found! 17:15:12.742 -> Disconnecting since Client Cyling Power Service is mandatory! 17:15:12.834 -> Client disconnected from Peripheral Device: [Zwift Hub], reason: [16] 17:15:27.560 -> Feather nRF52840 MITM supporting: CPS, CSC and FTMS 17:15:27.560 -> ------------------ Version 02.3 --------------------- 17:15:27.822 -> FTM Service and Chars are 'initialized' 17:15:27.822 -> CP Service and Chars are 'initialized' 17:15:27.822 -> CSC Service and Chars are 'initialized' 17:15:27.822 -> Generic Access Service and Chars are 'initialized' 17:15:27.822 -> Device Information Service and Chars are 'initialized' 17:15:27.822 -> Start Client-side Scanning for CPS, CSC and FTMS! 17:15:27.836 -> Found advertising Peripheral with FTMS enabled! See Raw data packet: 17:15:27.836 -> Timestamp Addr Rssi Data 17:15:27.836 -> 000001270 F8:9C:FC:53:5E:49 -60 09-02-16-18-26-18-18-18-0A-18 17:15:27.836 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:15:27.836 -> Now checking all mandatory Client Services and Characteristics! 17:15:27.836 -> If Mandatory Services Fail --> the Client will disconnect! 17:15:27.836 -> First checking Generic Access and Device Information Services and Characteristics!

Berg0162 commented 1 year ago

Dear Joel, I think we should first exclude an unexpected behavior/contribution/interference of ItsyBitsy before we undertake new test actions. A failing ItsyBitsy would be the simple explanation but I do not expect it to be that easy!

I find the results very unpredictable and that bothers me most! So I have to ask the question: are the circumstances/procedures every test exactly the same? Could you give me a complete summary of what your procedure is step by step? Please also include when devices are switched on and or reset and what apps are active (like nRF Connect, Zwift, Rouvy, ESP32 boards...) that have access to BLE and might (in theory) connect over BLE..., when in time do you wake up the trainer and when are you moving the pedals on the trainer... The last run shows FTMS to be discovered and Cycling Power of the same device is not..? Can there be a device (smartphone) that auto connects to CP in the meantime, it is very unlikely that only FTMS is exposed and CP NOT? Unless the connection process is completely disturbed by an (un)known agent or CP is simply occupied by another device I find the results unimaginably. I have made so many BLE applications (with so many different devices) and I never came across such erratic behavior. Never a Char-discovery ever failed unless it was simply NOT implemented on the other side (device)...? No way that one had to pull it in a While loop... call it and you get the answer: yes the Char/SVC is there or not!

By the way what is this:

Message (Enter to send message to 'Adafruit ItsyBitsy nRF52840 Express' on 'COM11')

Where does it come from? Do you use some special application on the PC other than Arduino IDE and the regular Serial Monitor on com# to fill the screen? Regards, Jörgen.

le-joebar commented 1 year ago

Hello Jorghen,

This comes from the Arduino IDE 2.0, no doubt that I copied it with the rest before pasting it.

I received the Feather just now I resume all the tests with and more detail !!

Berg0162 commented 1 year ago

Daar Joël, Fingers crossed.... I have found my decoding misunderstanding in the IBData... so when we will be able to convince Zwift Hub to send those data, at least it is decoded correctly and your HBM will be zero!😉 Good luck! Jörgen

Op vr 16 dec. 2022 16:06 schreef le-joebar @.***>:

Hello Jorghen,

This comes from the Arduino IDE 2.0, no doubt that I copied it with the rest before pasting it.

I received the Feather just now I resume all the tests with and more detail !!

— Reply to this email directly, view it on GitHub https://github.com/Berg0162/simcline/issues/7#issuecomment-1355027051, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANS5LSVSCA5ZCIPA53RQJHDWNSAQVANCNFSM6AAAAAASZDERFE . You are receiving this because you authored the thread.Message ID: @.***>

le-joebar commented 1 year ago

Dear Jörgen,

I redid all the tests with the feather nRF52840. from V22 to 27.

There is no Bluetooth (Watch, Gsm, Google nest) active nearby. The only thing I hadn't thought of before was my desktop's USB dongle for my mouse. So I removed it and started all over again without it!

I did a Scan with nRFConnect There is no device found, no server and then I turned off my mobile

All tests were done twice with the same version.

-1 turn on the trainer and then turn on the FTMS. -2 Switch on the FTMS and then train it.

I do not pedal to wake up because on Zwift with the Bluethoot USB dongle it is not necessary for him to discover the services. Likewise on an ESP program that I showed you; the services are present just when the trainer is switched on.

17:13:06.265 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:13:06.265 -> ----------------- Version 02.2 ------------------ 17:13:06.265 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:13:06.265 -> FTMS and Chars 'initialized' 17:13:06.265 -> CPS and Chars 'initialized' 17:13:06.265 -> CSCS and Chars 'initialized' 17:13:06.265 -> GA and Chars 'initialized' 17:13:06.265 -> DIS and Chars 'initialized' 17:13:06.265 -> Start Scanning for CPS, CSC and FTMS! 17:13:06.266 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:13:06.266 -> Timestamp MAC Address Rssi Data 17:13:06.266 -> 000001249 F8:9C:FC:53:5E:49 -54 09-02-16-18-26-18-18-18-0A-18 17:13:07.123 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:13:07.123 -> Now checking mandatory Client Services and Characteristics! 17:13:07.123 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 17:13:07.124 -> Discovering Client CP Measurement characteristic ... Found it! 17:13:07.124 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 17:13:07.133 -> Discovering Client CP Feature characteristic ... Found it! 17:13:07.285 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 17:13:07.285 -> Wheel revolution data supported 17:13:07.285 -> Crank revolution data supported 17:13:07.285 -> Discovering Client CP Sensor Location characteristic ... Found it! 17:13:07.469 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 17:13:07.469 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 17:13:07.533 -> Discovering Client CSC Measurement CHR ... Found it! 17:13:07.905 -> Discovering Client CSC Location CHR ... Found it! 17:13:07.905 -> -> Client Reads CSC Location Sensor: Loc#: 0 Other 17:13:07.905 -> Discovering Client CSC Feature CHR ... Not Found! NOT Mandatory! 17:13:07.905 -> Discovering Client Fitness Machine (FTM) Service ... Not Found! 17:13:07.905 -> Disconnecting since Client FTM Service is mandatory! 17:13:08.074 -> Client Disconnected, reason = 0x16 17:13:08.074 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:13:08.818 -> >>> Couldn't enable notify for Client CP Measurement Characteristic. 17:13:08.818 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 17:13:08.818 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 17:13:08.818 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 17:13:08.818 -> FTMS (trainer) is controlled by another Client (Training App)! 17:13:08.818 -> Client (Central) is Up and Running!

17:13:52.954 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:13:52.954 -> ----------------- Version 02.2 ------------------ 17:13:52.954 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:13:52.954 -> FTMS and Chars 'initialized' 17:13:52.954 -> CPS and Chars 'initialized' 17:13:52.954 -> CSCS and Chars 'initialized' 17:13:52.954 -> GA and Chars 'initialized' 17:13:52.954 -> DIS and Chars 'initialized' 17:13:52.954 -> Start Scanning for CPS, CSC and FTMS! 17:14:04.080 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:14:04.080 -> Timestamp MAC Address Rssi Data 17:14:04.080 -> 000012677 F8:9C:FC:53:5E:49 -51 09-02-16-18-26-18-18-18-0A-18 17:14:04.205 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:14:04.205 -> Now checking mandatory Client Services and Characteristics! 17:14:04.205 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 17:14:04.330 -> Discovering Client CP Measurement characteristic ... Found it! 17:14:04.794 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 17:14:04.963 -> Discovering Client CP Feature characteristic ... Found it! 17:14:05.147 -> -> Client Reads Raw CP Feature bytes: [4] [ 00 00 00 00 ] 17:14:05.147 -> Discovering Client CP Sensor Location characteristic ... NOT Found! NOT Mandatory! 17:14:05.147 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found and disconnecting! 17:14:05.147 -> CSC Service is mandatory! 17:14:05.239 -> Client Disconnected, reason = 0x16 17:14:05.239 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:14:06.639 -> >>> Couldn't enable notify for Client CP Measurement Characteristic. 17:14:06.639 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 17:14:06.639 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 17:14:06.639 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 17:14:06.639 -> FTMS (trainer) is controlled by another Client (Training App)! 17:14:06.639 -> Client (Central) is Up and Running!

17:18:37.912 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:18:37.912 -> ----------------- Version 02.3 ------------------ 17:18:37.912 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:18:37.913 -> FTMS and Chars 'initialized' 17:18:37.913 -> CPS and Chars 'initialized' 17:18:37.913 -> CSCS and Chars 'initialized' 17:18:37.913 -> GA and Chars 'initialized' 17:18:37.913 -> DIS and Chars 'initialized' 17:18:37.913 -> Start Scanning for CPS, CSC and FTMS! 17:18:37.937 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:18:37.937 -> Timestamp MAC Address Rssi Data 17:18:37.937 -> 000001832 F8:9C:FC:53:5E:49 -51 09-02-16-18-26-18-18-18-0A-18 17:18:37.939 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:18:37.939 -> Now checking mandatory Client Services and Characteristics! 17:18:37.939 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 17:18:38.075 -> Discovering Client CP Measurement characteristic ... Found it! 17:18:38.376 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 17:18:38.547 -> Discovering Client CP Feature characteristic ... Found it! 17:18:38.702 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 17:18:38.702 -> Wheel revolution data supported 17:18:38.702 -> Crank revolution data supported 17:18:38.702 -> Discovering Client CP Sensor Location characteristic ... Found it! 17:18:38.872 -> -> Client Reads CP Location Sensor: Loc#: 0 Other 17:18:38.872 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found and disconnecting! 17:18:38.872 -> CSC Service is mandatory! 17:18:39.057 -> Client Disconnected, reason = 0x16 17:18:39.057 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:18:40.313 -> Stopped!

17:20:02.831 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:20:02.831 -> ----------------- Version 02.3 ------------------ 17:20:02.831 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:20:02.831 -> FTMS and Chars 'initialized' 17:20:02.831 -> CPS and Chars 'initialized' 17:20:02.831 -> CSCS and Chars 'initialized' 17:20:02.831 -> GA and Chars 'initialized' 17:20:02.831 -> DIS and Chars 'initialized' 17:20:02.831 -> Start Scanning for CPS, CSC and FTMS! 17:20:09.489 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:20:09.489 -> Timestamp MAC Address Rssi Data 17:20:09.489 -> 000008794 F8:9C:FC:53:5E:49 -60 09-02-16-18-26-18-18-18-0A-18 17:20:09.722 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:20:09.722 -> Now checking mandatory Client Services and Characteristics! 17:20:09.722 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 17:20:09.956 -> Discovering Client CP Measurement characteristic ... Found it! 17:20:10.142 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 17:20:10.331 -> Discovering Client CP Feature characteristic ... Found it! 17:20:10.502 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 17:20:10.502 -> Wheel revolution data supported 17:20:10.502 -> Crank revolution data supported 17:20:10.502 -> Discovering Client CP Sensor Location characteristic ... Found it! 17:20:10.721 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 17:20:10.721 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 17:20:10.935 -> Discovering Client CSC Measurement CHR ... Found it! 17:20:11.265 -> Discovering Client CSC Location CHR ... Found it! 17:20:11.265 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 17:20:11.265 -> Discovering Client CSC Feature CHR ... Found it! 17:20:11.452 -> -> Client Reads Raw CSC Feature bytes: [2] [ 00 00 ] 17:20:11.452 -> Discovering Client Fitness Machine (FTM) Service ... Not Found! 17:20:11.452 -> Disconnecting since Client FTM Service is mandatory! 17:20:11.547 -> Client Disconnected, reason = 0x16 17:20:11.547 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:20:12.140 -> Stopped!

17:21:55.142 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:21:55.142 -> ----------------- Version 02.4 ------------------ 17:21:55.142 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:21:55.142 -> FTMS and Chars 'initialized' 17:21:55.142 -> CPS and Chars 'initialized' 17:21:55.142 -> CSCS and Chars 'initialized' 17:21:55.142 -> GA and Chars 'initialized' 17:21:55.142 -> DIS and Chars 'initialized' 17:21:55.142 -> Start Scanning for CPS, CSC and FTMS! 17:21:55.142 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:21:55.142 -> Timestamp MAC Address Rssi Data 17:21:55.142 -> 000001279 F8:9C:FC:53:5E:49 -54 09-02-16-18-26-18-18-18-0A-18 17:21:55.142 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:21:55.142 -> Now checking all Client Services and Characteristics! 17:21:55.142 -> If Mandatory Services Fail --> the Client will disconnect! 17:21:55.142 -> First checking Generic Access and Device Information Services and Characteristics! 17:21:55.143 -> Found Client Generic Access 17:21:55.143 -> -> Client Reads Device Name: [Zwift Hub] 17:21:55.174 -> -> Client Reads Appearance: [1152] 17:21:55.174 -> Found Client Device Information 17:21:55.753 -> -> Client Reads Manufacturer: [Zwift] 17:21:55.753 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 17:21:55.753 -> Disconnecting since Client FTM Service is mandatory! 17:21:55.800 -> Client Disconnected, reason = 0x16 17:21:55.801 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:21:56.993 -> Stopped!

17:22:57.468 -> ----------------- Version 02.4 ------------------ 17:22:57.468 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:22:58.154 -> FTMS and Chars 'initialized' 17:22:58.154 -> CPS and Chars 'initialized' 17:22:58.154 -> CSCS and Chars 'initialized' 17:22:58.154 -> GA and Chars 'initialized' 17:22:58.154 -> DIS and Chars 'initialized' 17:22:58.154 -> Start Scanning for CPS, CSC and FTMS! 17:23:04.954 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:23:04.954 -> Timestamp MAC Address Rssi Data 17:23:04.954 -> 000008494 F8:9C:FC:53:5E:49 -52 09-02-16-18-26-18-18-18-0A-18 17:23:05.310 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:23:05.310 -> Now checking all Client Services and Characteristics! 17:23:05.310 -> If Mandatory Services Fail --> the Client will disconnect! 17:23:05.310 -> First checking Generic Access and Device Information Services and Characteristics! 17:23:05.495 -> Found Client Generic Access 17:23:05.495 -> -> Client Reads Device Name: [Zwift Hub] 17:23:05.713 -> -> Client Reads Appearance: [1152] 17:23:05.713 -> Found Client Device Information 17:23:06.067 -> -> Client Reads Manufacturer: [Zwift] 17:23:06.067 -> -> Client Reads Model Number: [06] 17:23:06.207 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:23:06.207 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:23:06.468 -> Discovering Client FTM Feature Characteristic ... Found it! 17:23:06.653 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 17:23:06.653 -> Discovering Client FTM Training Status Characteristic ... Not Found! 17:23:07.030 -> Disconnecting since Client FTM Characteristic is mandatory! 17:23:07.062 -> Client Disconnected, reason = 0x16 17:23:07.062 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:23:07.695 -> Stopped!

17:25:53.099 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:25:53.099 -> ----------------- Version 02.5 ------------------ 17:25:53.099 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:25:53.099 -> FTMS and Chars 'initialized' 17:25:53.099 -> CPS and Chars 'initialized' 17:25:53.099 -> CSCS and Chars 'initialized' 17:25:53.099 -> GA and Chars 'initialized' 17:25:53.099 -> DIS and Chars 'initialized' 17:25:53.099 -> Start Scanning for CPS, CSC and FTMS! 17:25:53.099 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:25:53.099 -> Timestamp MAC Address Rssi Data 17:25:53.099 -> 000001091 F8:9C:FC:53:5E:49 -56 09-02-16-18-26-18-18-18-0A-18 17:25:53.099 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:25:53.099 -> Now checking all Client Services and Characteristics! 17:25:53.099 -> If Mandatory Services Fail --> the Client will disconnect! 17:25:53.099 -> First checking Generic Access and Device Information Services and Characteristics! 17:25:53.325 -> Found Client Generic Access 17:25:53.325 -> -> Client Reads Device Name: [Zwift Hub] 17:25:53.666 -> -> Client Reads Appearance: [1152] 17:25:53.666 -> Found Client Device Information 17:25:54.036 -> -> Client Reads Manufacturer: [Zwift] 17:25:54.036 -> -> Client Reads Model Number: [06] 17:25:54.345 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:25:54.345 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:25:54.484 -> Discovering Client FTM Feature Characteristic ... Found it! 17:25:54.623 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 17:25:54.623 -> Discovering Client FTM Control Point Characteristic ... Found it! 17:25:54.982 -> Discovering Client FTM Status Characteristic ... Ready to receive Client FTM Control Point Response Messages 17:25:54.982 -> >>> Couldn't enable notify for Client FTM Status Characteristic. 17:25:54.982 -> FTMS (trainer) is controlled by another Client (Training App)! 17:25:54.982 -> Client (Central) is Up and Running! 17:25:55.058 -> Found it! 17:25:55.058 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 17:25:55.058 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Not Found! NOT mandatory! 17:25:55.058 -> Discovering Client FTM Supported Power Range Characteristic ... Not Found! NOT mandatory! 17:25:55.058 -> Discovering Client FTM Indoor Bike Data Characteristic ... Not Found! Not Mandatory 17:25:55.058 -> Discovering Client Cycling Power (CP) Service ... Not Found! 17:25:55.058 -> Disconnecting since Client Cyling Power Service is mandatory! 17:25:55.058 -> Client Disconnected, reason = 0x16 17:25:55.058 -> >>> Restart the Feather nRF52 Client for a new run! <<<

17:26:41.726 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:26:41.726 -> ----------------- Version 02.5 ------------------ 17:26:41.726 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:26:41.726 -> FTMS and Chars 'initialized' 17:26:41.726 -> CPS and Chars 'initialized' 17:26:41.726 -> CSCS and Chars 'initialized' 17:26:41.726 -> GA and Chars 'initialized' 17:26:41.726 -> DIS and Chars 'initialized' 17:26:41.726 -> Start Scanning for CPS, CSC and FTMS! 17:26:48.666 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:26:48.666 -> Timestamp MAC Address Rssi Data 17:26:48.666 -> 000008960 F8:9C:FC:53:5E:49 -57 09-02-16-18-26-18-18-18-0A-18 17:26:49.019 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:26:49.019 -> Now checking all Client Services and Characteristics! 17:26:49.019 -> If Mandatory Services Fail --> the Client will disconnect! 17:26:49.019 -> First checking Generic Access and Device Information Services and Characteristics! 17:26:49.376 -> Found Client Generic Access 17:26:49.376 -> -> Client Reads Device Name: [Zwift Hub] 17:26:49.732 -> -> Client Reads Appearance: [1152] 17:26:49.732 -> Found Client Device Information 17:26:50.007 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 17:26:50.007 -> Disconnecting since Client FTM Service is mandatory! 17:26:50.101 -> Client Disconnected, reason = 0x16 17:26:50.101 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:26:51.400 -> Stopped!

17:29:23.561 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:29:23.561 -> ----------------- Version 02.6 ------------------ 17:29:23.561 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:29:24.053 -> FTMS and Chars 'initialized' 17:29:24.053 -> CPS and Chars 'initialized' 17:29:24.053 -> CSCS and Chars 'initialized' 17:29:24.053 -> GA and Chars 'initialized' 17:29:24.053 -> DIS and Chars 'initialized' 17:29:24.053 -> Start Scanning for CPS, CSC and FTMS! 17:29:24.053 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:29:24.053 -> Timestamp MAC Address Rssi Data 17:29:24.053 -> 000000990 F8:9C:FC:53:5E:49 -58 09-02-16-18-26-18-18-18-0A-18 17:29:24.058 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:29:24.058 -> Now checking all Client Services and Characteristics! 17:29:24.058 -> If Mandatory Services Fail --> the Client will disconnect! 17:29:24.058 -> First checking Generic Access and Device Information Services and Characteristics! 17:29:24.058 -> Found Client Generic Access 17:29:24.284 -> -> Client Reads Device Name: [Zwift Hub] 17:29:24.469 -> -> Client Reads Appearance: [1152] 17:29:24.516 -> Found Client Device Information 17:29:24.736 -> -> Client Reads Manufacturer: [Zwift] 17:29:24.968 -> -> Client Reads Model Number: [06] 17:29:25.139 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:29:25.139 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:29:25.264 -> Discovering Client FTM Feature Characteristic ... Found it! 17:29:25.576 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 17:29:25.576 -> Discovering Client FTM Control Point Characteristic ... Not Found! 17:29:25.576 -> Disconnecting since Client FTM Control Point Characteristic is mandatory! 17:29:25.623 -> Client Disconnected, reason = 0x16 17:29:25.623 -> >>> Restart the Feather nRF52 Client for a new run! <<<

17:30:45.419 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:30:45.419 -> ----------------- Version 02.6 ------------------ 17:30:45.419 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:30:45.420 -> FTMS and Chars 'initialized' 17:30:45.420 -> CPS and Chars 'initialized' 17:30:45.420 -> CSCS and Chars 'initialized' 17:30:45.420 -> GA and Chars 'initialized' 17:30:45.420 -> DIS and Chars 'initialized' 17:30:45.420 -> Start Scanning for CPS, CSC and FTMS! 17:31:20.566 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:31:20.566 -> Timestamp MAC Address Rssi Data 17:31:20.566 -> 000037231 F8:9C:FC:53:5E:49 -58 09-02-16-18-26-18-18-18-0A-18 17:31:20.876 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:31:20.876 -> Now checking all Client Services and Characteristics! 17:31:20.876 -> If Mandatory Services Fail --> the Client will disconnect! 17:31:20.876 -> First checking Generic Access and Device Information Services and Characteristics! 17:31:21.015 -> Found Client Generic Access 17:31:21.384 -> -> Client Reads Device Name: [] 17:31:21.384 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 17:31:21.384 -> Disconnecting since Client FTM Service is mandatory! 17:31:21.476 -> Client Disconnected, reason = 0x16 17:31:21.476 -> >>> Restart the Feather nRF52 Client for a new run! <<<

17:35:49.982 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:35:49.982 -> ----------------- Version 02.7 ------------------ 17:35:49.982 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:35:50.410 -> FTMS and Chars 'initialized' 17:35:50.410 -> CPS and Chars 'initialized' 17:35:50.410 -> CSCS and Chars 'initialized' 17:35:50.410 -> GA and Chars 'initialized' 17:35:50.410 -> DIS and Chars 'initialized' 17:35:50.410 -> Start Scanning for CPS, CSC and FTMS! 17:36:08.272 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:36:08.272 -> Timestamp MAC Address Rssi Data 17:36:08.272 -> 000019071 F8:9C:FC:53:5E:49 -54 09-02-16-18-26-18-18-18-0A-18 17:36:08.460 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:36:08.460 -> Now checking all Client Services and Characteristics! 17:36:08.460 -> If Mandatory Services Fail --> the Client will disconnect! 17:36:08.460 -> First checking Generic Access and Device Information Services and Characteristics! 17:36:08.585 -> Found Client Generic Access 17:36:08.864 -> -> Client Reads Device Name: [] 17:36:08.864 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Not Found! 17:36:08.864 -> Disconnecting since Client FTM Service is mandatory! 17:36:08.864 -> Client Disconnected, reason = 0x16 17:36:08.864 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:36:13.400 -> Stopped!

17:36:53.019 -> FTMS and Chars 'initialized' 17:36:53.019 -> CPS and Chars 'initialized' 17:36:53.019 -> CSCS and Chars 'initialized' 17:36:53.019 -> GA and Chars 'initialized' 17:36:53.019 -> DIS and Chars 'initialized' 17:36:53.019 -> Start Scanning for CPS, CSC and FTMS! 17:36:53.020 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:36:53.020 -> Timestamp MAC Address Rssi Data 17:36:53.020 -> 000001308 F8:9C:FC:53:5E:49 -60 09-02-16-18-26-18-18-18-0A-18 17:36:53.020 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:36:53.020 -> Now checking all Client Services and Characteristics! 17:36:53.020 -> If Mandatory Services Fail --> the Client will disconnect! 17:36:53.020 -> First checking Generic Access and Device Information Services and Characteristics! 17:36:53.021 -> Found Client Generic Access 17:36:53.021 -> -> Client Reads Device Name: [Zwift Hub] 17:36:53.152 -> -> Client Reads Appearance: [1152] 17:36:53.154 -> Found Client Device Information 17:36:53.309 -> -> Client Reads Manufacturer: [Zwift] 17:36:53.712 -> -> Client Reads Model Number: [06] 17:36:53.881 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:36:53.881 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:36:53.928 -> Discovering Client FTM Feature Characteristic ... Found it! 17:36:54.098 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 17:36:54.098 -> Discovering Client FTM Control Point Characteristic ... Found it! 17:36:54.653 -> Discovering Client FTM Status Characteristic ... Not Found! 17:36:54.653 -> Disconnecting since Client FTM Status Characteristic is mandatory! 17:36:54.888 -> Client Disconnected, reason = 0x16 17:36:54.888 -> >>> Restart the Feather nRF52 Client for a new run! <<< 17:36:57.446 -> Stopped!

Berg0162 commented 1 year ago

Dear Joel, I have uploaded a new FTMS_Client version 028!

1) Upload and Run this code on the Feather-nRF52 2) Start the Serial Monitor to catch verbose debugging and data info 3) Power ON/Wake UP trainer -> do NOT connect with other devices

I think we have stumbled on a timing problem, now and then a run is more or less succesfull, never it stops at exactly the same point! Only once sofar the code execution really reached the end...... So it is possible!

I have inserted calls to delay(SOME_TIME) in the Client_Connect_Callback function to handle possible time-outs that may occur during discover SVC or Char's... The delay time is now set to 100 ms! Just a guess! Depending on what the result is, you can increase or decrease the value and see how the result is influenced positively or negatively.... Give it a try and fingers crossed, Jörgen

le-joebar commented 1 year ago

Dear Jörghen,

I had to increase the delay to 200 The system starts in any direction 9/10 times

I have given you several examples of start-ups because I believe that certain services are there at certain start-ups and not at others!

The resistance is well felt during the test :)

JACKPOT !!!!!!! Congratulation !!! 👍

11:40:31.097 -> -> Client Reads Appearance: [1152] 11:40:31.210 -> Found Client Device Information 11:40:31.489 -> -> Client Reads Manufacturer: [Zwift] 11:40:31.944 -> -> Client Reads Model Number: [06] 11:40:32.161 -> -> Client Reads Serial Number: [06-F89CFC535E49] 11:40:32.302 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 11:40:32.537 -> Discovering Client FTM Feature Characteristic ... Found it! 11:40:32.742 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 11:40:32.835 -> Discovering Client FTM Control Point Characteristic ... Found it! 11:40:33.212 -> Discovering Client FTM Status Characteristic ... Found it! 11:40:33.620 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 11:40:34.229 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 11:40:34.403 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 11:40:34.497 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 11:40:34.747 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 00 00 00 00 ] 11:40:34.839 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 11:40:35.057 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 11:40:35.134 -> Discovering Client Cycling Power (CP) Service ... Ready to receive Client FTM Control Point Response Messages 11:40:35.181 -> Found it! CPS Max Payload: 20 Data Length: 27 11:40:35.273 -> Ready to receive Client FTM Status values 11:40:35.273 -> Discovering Client CP Measurement characteristic ... Found it! 11:40:35.756 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 11:40:36.023 -> Discovering Client CP Feature characteristic ... Found it! 11:40:36.023 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 11:40:36.023 -> Wheel revolution data supported 11:40:36.023 -> Crank revolution data supported 11:40:36.162 -> Discovering Client CP Sensor Location characteristic ... Found it! 11:40:36.255 -> -> Client Reads CP Location Sensor: Loc#: 0 Other 11:40:36.379 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 11:40:37.221 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 11:40:37.300 -> Ready to receive Client FTM Indoor Bike Data values 11:40:37.300 -> Ready to receive Client CP Measurement values 11:40:38.365 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:40:38.365 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:40:39.220 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 0B 02 00 00 14 00 00 00 00 ] 11:40:39.220 -> Instant. Speed: 5 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:40:39.314 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 11:40:40.385 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 07 03 00 00 14 00 11 00 00 ] 11:40:40.385 -> Instant. Speed: 7 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 17 Watt Heart Rate: 0 HBM 11:40:41.272 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 58 04 00 00 14 00 40 00 00 ] 11:40:41.272 -> Instant. Speed: 11 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 64 Watt Heart Rate: 0 HBM 11:40:41.320 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 11:40:41.320 -> Client (Central) is Up and Running! 11:40:42.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 78 05 00 00 14 00 90 00 00 ] 11:40:42.206 -> Instant. Speed: 14 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 144 Watt Heart Rate: 0 HBM 11:40:43.237 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 CF 05 20 00 14 00 71 00 00 ] 11:40:43.237 -> Instant. Speed: 14 KPH Instantaneous Cadence: 16 RPM Resistance Level: 20 Instantaneous Power: 113 Watt Heart Rate: 0 HBM 11:40:43.315 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:40:43.581 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:40:44.313 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 25 06 46 00 14 00 71 00 00 ] 11:40:44.313 -> Instant. Speed: 15 KPH Instantaneous Cadence: 35 RPM Resistance Level: 20 Instantaneous Power: 113 Watt Heart Rate: 0 HBM 11:40:45.311 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 96 06 5A 00 14 00 94 00 00 ] 11:40:45.311 -> Instant. Speed: 16 KPH Instantaneous Cadence: 45 RPM Resistance Level: 20 Instantaneous Power: 148 Watt Heart Rate: 0 HBM 11:40:45.405 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:40:45.763 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:40:46.212 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 D5 06 68 00 14 00 7E 00 00 ] 11:40:46.212 -> Instant. Speed: 17 KPH Instantaneous Cadence: 52 RPM Resistance Level: 20 Instantaneous Power: 126 Watt Heart Rate: 0 HBM 11:40:47.194 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 16 07 72 00 14 00 6D 00 00 ] 11:40:47.194 -> Instant. Speed: 18 KPH Instantaneous Cadence: 57 RPM Resistance Level: 20 Instantaneous Power: 109 Watt Heart Rate: 0 HBM 11:40:47.506 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 11:40:47.646 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 11:40:47.646 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 11:40:48.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 71 07 17 07 7A 00 7A 00 05 00 00 14 00 61 00 61 00 00 ] 11:40:48.206 -> Instant. Speed: 19 KPH Average Speed: 18 KPH Instantaneous Cadence: 61 RPM Average Cadence: 61 RPM Total Distance: 5 m Resistance Level: 20 Instantaneous Power: 97 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:40:49.611 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 11:40:49.690 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 EC 07 17 07 80 00 7D 00 0A 00 00 14 00 62 00 61 00 00 ] 11:40:49.737 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 64 RPM Average Cadence: 62 RPM Total Distance: 10 m Resistance Level: 20 Instantaneous Power: 98 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:40:49.814 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:49.814 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 11:40:50.545 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1E 08 17 07 82 00 7E 00 0F 00 00 14 00 63 00 62 00 00 ] 11:40:50.545 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 65 RPM Average Cadence: 63 RPM Total Distance: 15 m Resistance Level: 20 Instantaneous Power: 99 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:40:51.247 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D3 07 17 07 86 00 80 00 14 00 00 14 00 5F 00 61 00 00 ] 11:40:51.247 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 67 RPM Average Cadence: 64 RPM Total Distance: 20 m Resistance Level: 20 Instantaneous Power: 95 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:40:51.715 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 11:40:51.887 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:51.887 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 11:40:52.338 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A2 07 17 07 88 00 82 00 19 00 00 14 00 6A 00 63 00 00 ] 11:40:52.338 -> Instant. Speed: 19 KPH Average Speed: 18 KPH Instantaneous Cadence: 68 RPM Average Cadence: 65 RPM Total Distance: 25 m Resistance Level: 20 Instantaneous Power: 106 Watt Average Power: 99 Watt Heart Rate: 0 HBM 11:40:53.228 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 19 08 17 07 88 00 83 00 1E 00 00 14 00 85 00 68 00 00 ] 11:40:53.228 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 68 RPM Average Cadence: 65 RPM Total Distance: 30 m Resistance Level: 20 Instantaneous Power: 133 Watt Average Power: 104 Watt Heart Rate: 0 HBM 11:40:53.821 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:40:54.224 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:54.224 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:40:54.224 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 38 08 17 07 88 00 83 00 23 00 00 14 00 74 00 6A 00 00 ] 11:40:54.224 -> Instant. Speed: 21 KPH Average Speed: 18 KPH Instantaneous Cadence: 68 RPM Average Cadence: 65 RPM Total Distance: 35 m Resistance Level: 20 Instantaneous Power: 116 Watt Average Power: 106 Watt Heart Rate: 0 HBM 11:40:55.302 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4E 08 17 07 8A 00 84 00 28 00 00 14 00 67 00 69 00 00 ] 11:40:55.302 -> Instant. Speed: 21 KPH Average Speed: 18 KPH Instantaneous Cadence: 69 RPM Average Cadence: 66 RPM Total Distance: 40 m Resistance Level: 20 Instantaneous Power: 103 Watt Average Power: 105 Watt Heart Rate: 0 HBM 11:40:55.908 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 11:40:56.034 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:56.034 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 11:40:56.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D1 08 3F 07 8C 00 85 00 2E 00 00 14 00 57 00 67 00 00 ] 11:40:56.206 -> Instant. Speed: 22 KPH Average Speed: 18 KPH Instantaneous Cadence: 70 RPM Average Cadence: 66 RPM Total Distance: 46 m Resistance Level: 20 Instantaneous Power: 87 Watt Average Power: 103 Watt Heart Rate: 0 HBM 11:40:57.159 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 7F 08 3B 07 94 00 86 00 33 00 00 14 00 5A 00 66 00 00 ] 11:40:57.205 -> Instant. Speed: 21 KPH Average Speed: 18 KPH Instantaneous Cadence: 74 RPM Average Cadence: 67 RPM Total Distance: 51 m Resistance Level: 20 Instantaneous Power: 90 Watt Average Power: 102 Watt Heart Rate: 0 HBM 11:40:57.986 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 11:40:58.159 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:58.159 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 11:40:58.284 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AC 08 58 07 96 00 88 00 39 00 00 14 00 47 00 63 00 00 ] 11:40:58.284 -> Instant. Speed: 22 KPH Average Speed: 18 KPH Instantaneous Cadence: 75 RPM Average Cadence: 68 RPM Total Distance: 57 m Resistance Level: 20 Instantaneous Power: 71 Watt Average Power: 99 Watt Heart Rate: 0 HBM 11:40:59.254 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 84 08 71 07 96 00 89 00 3F 00 00 14 00 58 00 62 00 00 ] 11:40:59.254 -> Instant. Speed: 21 KPH Average Speed: 19 KPH Instantaneous Cadence: 75 RPM Average Cadence: 68 RPM Total Distance: 63 m Resistance Level: 20 Instantaneous Power: 88 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:41:00.125 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 11:41:00.344 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E7 08 86 07 20 00 81 00 45 00 00 14 00 5F 00 62 00 00 ] 11:41:00.344 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 16 RPM Average Cadence: 64 RPM Total Distance: 69 m Resistance Level: 20 Instantaneous Power: 95 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:41:00.344 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:00.344 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 11:41:01.324 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C5 08 98 07 6E 00 7F 00 4B 00 00 14 00 57 00 61 00 00 ] 11:41:01.324 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 55 RPM Average Cadence: 63 RPM Total Distance: 75 m Resistance Level: 20 Instantaneous Power: 87 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:41:02.199 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 11:41:02.245 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B2 08 A8 07 8C 00 80 00 51 00 00 14 00 5C 00 61 00 00 ] 11:41:02.245 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 70 RPM Average Cadence: 64 RPM Total Distance: 81 m Resistance Level: 20 Instantaneous Power: 92 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:41:02.245 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:02.245 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 11:41:03.228 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 BB 08 B5 07 94 00 81 00 57 00 00 14 00 5D 00 60 00 00 ] 11:41:03.228 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 74 RPM Average Cadence: 64 RPM Total Distance: 87 m Resistance Level: 20 Instantaneous Power: 93 Watt Average Power: 96 Watt Heart Rate: 0 HBM 11:41:04.228 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 11:41:04.306 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 07 09 C1 07 94 00 82 00 5D 00 00 14 00 55 00 60 00 00 ] 11:41:04.306 -> Instant. Speed: 23 KPH Average Speed: 19 KPH Instantaneous Cadence: 74 RPM Average Cadence: 65 RPM Total Distance: 93 m Resistance Level: 20 Instantaneous Power: 85 Watt Average Power: 96 Watt Heart Rate: 0 HBM 11:41:04.400 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:04.400 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 11:41:05.210 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D4 08 CC 07 98 00 84 00 63 00 00 14 00 5B 00 5F 00 00 ] 11:41:05.210 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 76 RPM Average Cadence: 66 RPM Total Distance: 99 m Resistance Level: 20 Instantaneous Power: 91 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:06.189 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E1 08 D5 07 9C 00 85 00 69 00 00 14 00 5E 00 5F 00 00 ] 11:41:06.190 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 66 RPM Total Distance: 105 m Resistance Level: 20 Instantaneous Power: 94 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:06.329 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 11:41:06.829 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:06.829 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 11:41:07.264 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 BD 08 DE 07 9C 00 86 00 6F 00 00 14 00 61 00 5F 00 00 ] 11:41:07.264 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 67 RPM Total Distance: 111 m Resistance Level: 20 Instantaneous Power: 97 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:08.339 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1F 09 E6 07 98 00 87 00 75 00 00 14 00 58 00 5F 00 00 ] 11:41:08.339 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 76 RPM Average Cadence: 67 RPM Total Distance: 117 m Resistance Level: 20 Instantaneous Power: 88 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:08.431 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:41:08.618 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:08.618 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:41:09.414 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D6 08 ED 07 9E 00 88 00 7B 00 00 14 00 54 00 5E 00 00 ] 11:41:09.414 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 68 RPM Total Distance: 123 m Resistance Level: 20 Instantaneous Power: 84 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:41:10.240 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E6 08 F3 07 A2 00 89 00 81 00 00 14 00 53 00 5E 00 00 ] 11:41:10.240 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 81 RPM Average Cadence: 68 RPM Total Distance: 129 m Resistance Level: 20 Instantaneous Power: 83 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:41:10.550 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 11:41:10.691 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:10.691 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 11:41:11.235 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C4 08 F9 07 9C 00 8A 00 87 00 00 14 00 44 00 5D 00 00 ] 11:41:11.235 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 69 RPM Total Distance: 135 m Resistance Level: 20 Instantaneous Power: 68 Watt Average Power: 93 Watt Heart Rate: 0 HBM 11:41:12.235 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 04 09 FF 07 9C 00 8A 00 8D 00 00 14 00 43 00 5C 00 00 ] 11:41:12.235 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 69 RPM Total Distance: 141 m Resistance Level: 20 Instantaneous Power: 67 Watt Average Power: 92 Watt Heart Rate: 0 HBM 11:41:12.639 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 11:41:12.857 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:12.857 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 11:41:13.217 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 09 09 04 08 A0 00 8B 00 93 00 00 14 00 4C 00 5B 00 00 ] 11:41:13.217 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 80 RPM Average Cadence: 69 RPM Total Distance: 147 m Resistance Level: 20 Instantaneous Power: 76 Watt Average Power: 91 Watt Heart Rate: 0 HBM 11:41:14.169 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E7 08 08 08 9E 00 8C 00 99 00 00 14 00 4A 00 5B 00 00 ] 11:41:14.216 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 70 RPM Total Distance: 153 m Resistance Level: 20 Instantaneous Power: 74 Watt Average Power: 91 Watt Heart Rate: 0 HBM 11:41:14.745 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 11:41:14.902 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:14.902 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 11:41:15.183 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1D 09 0D 08 9E 00 8D 00 9F 00 00 14 00 48 00 5A 00 00 ] 11:41:15.183 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 70 RPM Total Distance: 159 m Resistance Level: 20 Instantaneous Power: 72 Watt Average Power: 90 Watt Heart Rate: 0 HBM 11:41:16.368 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1E 09 11 08 A0 00 8D 00 A5 00 00 14 00 49 00 59 00 00 ] 11:41:16.368 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 80 RPM Average Cadence: 70 RPM Total Distance: 165 m Resistance Level: 20 Instantaneous Power: 73 Watt Average Power: 89 Watt Heart Rate: 0 HBM 11:41:16.853 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 11:41:16.992 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:16.992 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 11:41:17.366 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 17 09 14 08 9E 00 8E 00 AB 00 00 14 00 3F 00 58 00 00 ] 11:41:17.366 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 71 RPM Total Distance: 171 m Resistance Level: 20 Instantaneous Power: 63 Watt Average Power: 88 Watt Heart Rate: 0 HBM 11:41:18.255 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 6F 09 18 08 A2 00 8E 00 B1 00 00 14 00 44 00 58 00 00 ] 11:41:18.255 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 81 RPM Average Cadence: 71 RPM Total Distance: 177 m Resistance Level: 20 Instantaneous Power: 68 Watt Average Power: 88 Watt Heart Rate: 0 HBM 11:41:18.941 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 11:41:19.158 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:19.158 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 11:41:19.252 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 65 09 1B 08 9E 00 8F 00 B7 00 00 14 00 4E 00 57 00 00 ] 11:41:19.252 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 71 RPM Total Distance: 183 m Resistance Level: 20 Instantaneous Power: 78 Watt Average Power: 87 Watt Heart Rate: 0 HBM 11:41:20.216 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5B 09 1E 08 A6 00 90 00 BD 00 00 14 00 39 00 56 00 00 ] 11:41:20.216 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 83 RPM Average Cadence: 72 RPM Total Distance: 189 m Resistance Level: 20 Instantaneous Power: 57 Watt Average Power: 86 Watt Heart Rate: 0 HBM 11:41:21.042 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 11:41:21.215 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9C 09 21 08 B0 00 91 00 C3 00 00 14 00 32 00 55 00 00 ] 11:41:21.215 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 88 RPM Average Cadence: 72 RPM Total Distance: 195 m Resistance Level: 20 Instantaneous Power: 50 Watt Average Power: 85 Watt Heart Rate: 0 HBM 11:41:21.215 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:21.215 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 11:41:22.182 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A5 09 24 08 B0 00 91 00 C9 00 00 14 00 3A 00 55 00 00 ] 11:41:22.182 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 88 RPM Average Cadence: 72 RPM Total Distance: 201 m Resistance Level: 20 Instantaneous Power: 58 Watt Average Power: 85 Watt Heart Rate: 0 HBM 11:41:23.149 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 11:41:23.196 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8D 09 27 08 A2 00 92 00 CF 00 00 14 00 26 00 53 00 00 ] 11:41:23.196 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 81 RPM Average Cadence: 73 RPM Total Distance: 207 m Resistance Level: 20 Instantaneous Power: 38 Watt Average Power: 83 Watt Heart Rate: 0 HBM 11:41:23.196 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:23.196 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 11:41:24.179 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AC 09 29 08 8A 00 92 00 D5 00 00 14 00 26 00 52 00 00 ] 11:41:24.179 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 69 RPM Average Cadence: 73 RPM Total Distance: 213 m Resistance Level: 20 Instantaneous Power: 38 Watt Average Power: 82 Watt Heart Rate: 0 HBM 11:41:25.221 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 11:41:25.441 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 7D 09 2B 08 66 00 90 00 DB 00 00 14 00 29 00 51 00 00 ] 11:41:25.441 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 51 RPM Average Cadence: 72 RPM Total Distance: 219 m Resistance Level: 20 Instantaneous Power: 41 Watt Average Power: 81 Watt Heart Rate: 0 HBM 11:41:25.549 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:25.549 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 11:41:26.249 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8C 09 2E 08 5A 00 8F 00 E1 00 00 14 00 29 00 50 00 00 ] 11:41:26.249 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 45 RPM Average Cadence: 71 RPM Total Distance: 225 m Resistance Level: 20 Instantaneous Power: 41 Watt Average Power: 80 Watt Heart Rate: 0 HBM 11:41:27.260 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9A 09 30 08 5E 00 8E 00 E7 00 00 14 00 26 00 4F 00 00 ] 11:41:27.260 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 47 RPM Average Cadence: 71 RPM Total Distance: 231 m Resistance Level: 20 Instantaneous Power: 38 Watt Average Power: 79 Watt Heart Rate: 0 HBM 11:41:27.307 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 11:41:27.447 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:27.447 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 11:41:28.242 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 87 09 32 08 66 00 8D 00 ED 00 00 14 00 22 00 4E 00 00 ] 11:41:28.242 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 51 RPM Average Cadence: 70 RPM Total Distance: 237 m Resistance Level: 20 Instantaneous Power: 34 Watt Average Power: 78 Watt Heart Rate: 0 HBM 11:41:29.224 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5C 09 34 08 66 00 8C 00 F3 00 00 14 00 2E 00 4D 00 00 ] 11:41:29.224 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 51 RPM Average Cadence: 70 RPM Total Distance: 243 m Resistance Level: 20 Instantaneous Power: 46 Watt Average Power: 77 Watt Heart Rate: 0 HBM 11:41:29.410 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 11:41:29.782 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:29.782 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 11:41:30.296 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 EB 08 35 08 00 00 89 00 F9 00 00 14 00 00 00 4B 00 00 ] 11:41:30.296 -> Instant. Speed: 22 KPH Average Speed: 21 KPH Instantaneous Cadence: 0 RPM Average Cadence: 68 RPM Total Distance: 249 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 75 Watt Heart Rate: 0 HBM 11:41:31.196 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AA 09 37 08 00 00 86 00 FF 00 00 14 00 00 00 49 00 00 ] 11:41:31.196 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 0 RPM Average Cadence: 67 RPM Total Distance: 255 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 73 Watt Heart Rate: 0 HBM 11:41:31.523 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 11:41:31.757 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:31.757 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 11:41:32.458 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 CB 09 39 08 50 00 84 00 05 01 00 14 00 35 00 49 00 00 ] 11:41:32.458 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 40 RPM Average Cadence: 66 RPM Total Distance: 261 m Resistance Level: 20 Instantaneous Power: 53 Watt Average Power: 73 Watt Heart Rate: 0 HBM 11:41:33.472 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E4 09 3A 08 56 00 83 00 0B 01 00 14 00 33 00 48 00 00 ] 11:41:33.472 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 43 RPM Average Cadence: 65 RPM Total Distance: 267 m Resistance Level: 20 Instantaneous Power: 51 Watt Average Power: 72 Watt Heart Rate: 0 HBM 11:41:33.612 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:41:33.830 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:33.830 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:41:34.376 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 25 0A 44 08 56 00 82 00 12 01 00 14 00 33 00 48 00 00 ] 11:41:34.376 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 43 RPM Average Cadence: 65 RPM Total Distance: 274 m Resistance Level: 20 Instantaneous Power: 51 Watt Average Power: 72 Watt Heart Rate: 0 HBM 11:41:35.450 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1B 0A 4C 08 54 00 81 00 19 01 00 14 00 2E 00 47 00 00 ] 11:41:35.450 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 42 RPM Average Cadence: 64 RPM Total Distance: 281 m Resistance Level: 20 Instantaneous Power: 46 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:35.712 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A2 00 28 33 00 ] 11:41:35.993 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:35.993 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A2 00 28 33 ] 11:41:36.259 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1F 0A 55 08 5E 00 81 00 20 01 00 14 00 27 00 47 00 00 ] 11:41:36.259 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 47 RPM Average Cadence: 64 RPM Total Distance: 288 m Resistance Level: 20 Instantaneous Power: 39 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:37.320 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AE 09 56 08 64 00 80 00 26 01 00 14 00 27 00 46 00 00 ] 11:41:37.320 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 50 RPM Average Cadence: 64 RPM Total Distance: 294 m Resistance Level: 20 Instantaneous Power: 39 Watt Average Power: 70 Watt Heart Rate: 0 HBM 11:41:37.818 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 01 28 33 00 ] 11:41:38.148 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:38.148 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 01 28 33 ] 11:41:38.241 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 65 09 57 08 5C 00 7F 00 2C 01 00 14 00 1F 00 45 00 00 ] 11:41:38.241 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 46 RPM Average Cadence: 63 RPM Total Distance: 300 m Resistance Level: 20 Instantaneous Power: 31 Watt Average Power: 69 Watt Heart Rate: 0 HBM 11:41:39.209 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0B 09 57 08 54 00 7E 00 32 01 00 14 00 1F 00 45 00 00 ] 11:41:39.209 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 42 RPM Average Cadence: 63 RPM Total Distance: 306 m Resistance Level: 20 Instantaneous Power: 31 Watt Average Power: 69 Watt Heart Rate: 0 HBM 11:41:39.909 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 4F 01 28 33 00 ] 11:41:40.021 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:40.021 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4F 01 28 33 ] 11:41:40.301 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 19 09 58 08 50 00 7E 00 38 01 00 14 00 4C 00 45 00 00 ] 11:41:40.301 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 40 RPM Average Cadence: 63 RPM Total Distance: 312 m Resistance Level: 20 Instantaneous Power: 76 Watt Average Power: 69 Watt Heart Rate: 0 HBM 11:41:41.281 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8B 08 59 08 50 00 7D 00 3E 01 00 14 00 7A 00 46 00 00 ] 11:41:41.281 -> Instant. Speed: 21 KPH Average Speed: 21 KPH Instantaneous Cadence: 40 RPM Average Cadence: 62 RPM Total Distance: 318 m Resistance Level: 20 Instantaneous Power: 122 Watt Average Power: 70 Watt Heart Rate: 0 HBM 11:41:41.999 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 01 28 33 00 ] 11:41:42.203 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:42.203 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 01 28 33 ] 11:41:42.203 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E7 08 5A 08 30 00 7B 00 44 01 00 14 00 7A 00 47 00 00 ] 11:41:42.203 -> Instant. Speed: 22 KPH Average Speed: 21 KPH Instantaneous Cadence: 24 RPM Average Cadence: 61 RPM Total Distance: 324 m Resistance Level: 20 Instantaneous Power: 122 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:43.463 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 27 08 54 08 70 00 7B 00 49 01 00 14 00 62 00 47 00 00 ] 11:41:43.463 -> Instant. Speed: 20 KPH Average Speed: 21 KPH Instantaneous Cadence: 56 RPM Average Cadence: 61 RPM Total Distance: 329 m Resistance Level: 20 Instantaneous Power: 98 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:44.118 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 57 FF 28 33 00 ] 11:41:44.258 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 85 08 55 08 86 00 7B 00 4F 01 00 14 00 C1 00 49 00 00 ] 11:41:44.258 -> Instant. Speed: 21 KPH Average Speed: 21 KPH Instantaneous Cadence: 67 RPM Average Cadence: 61 RPM Total Distance: 335 m Resistance Level: 20 Instantaneous Power: 193 Watt Average Power: 73 Watt Heart Rate: 0 HBM 11:41:44.337 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:44.337 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 FF 28 33 ] 11:41:45.414 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E0 08 55 08 8C 00 7C 00 55 01 00 14 00 B9 00 4B 00 00 ] 11:41:45.414 -> Instant. Speed: 22 KPH Average Speed: 21 KPH Instantaneous Cadence: 70 RPM Average Cadence: 62 RPM Total Distance: 341 m Resistance Level: 20 Instantaneous Power: 185 Watt Average Power: 75 Watt Heart Rate: 0 HBM 11:41:46.191 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 08 00 00 00 00 00 00 00 ] 11:41:46.238 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 28 09 56 08 8E 00 7C 00 5B 01 00 14 00 C6 00 4D 00 00 ] 11:41:46.238 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 71 RPM Average Cadence: 62 RPM Total Distance: 347 m Resistance Level: 20 Instantaneous Power: 198 Watt Average Power: 77 Watt Heart Rate: 0 HBM 11:41:46.238 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 08 03 ] 11:41:47.396 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 38 09 57 08 98 00 7C 00 61 01 00 14 00 71 00 4E 00 00 ] 11:41:47.396 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 76 RPM Average Cadence: 62 RPM Total Distance: 353 m Resistance Level: 20 Instantaneous Power: 113 Watt Average Power: 78 Watt Heart Rate: 0 HBM 11:41:48.212 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 81 09 58 08 9E 00 7D 00 67 01 00 14 00 3F 00 4E 00 00 ] 11:41:48.212 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 79 RPM Average Cadence: 62 RPM Total Distance: 359 m Resistance Level: 20 Instantaneous Power: 63 Watt Average Power: 78 Watt Heart Rate: 0 HBM 11:41:48.253 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 01 00 00 00 00 00 00 00 ] 11:41:48.394 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 01 01 ] 11:41:48.394 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 11:41:49.269 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 C7 09 A6 00 14 00 31 00 00 ] 11:41:49.315 -> Instant. Speed: 25 KPH Instantaneous Cadence: 83 RPM Resistance Level: 20 Instantaneous Power: 49 Watt Heart Rate: 0 HBM 11:41:50.351 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:41:50.477 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 AB 09 AC 00 14 00 38 00 00 ] 11:41:50.477 -> Instant. Speed: 24 KPH Instantaneous Cadence: 86 RPM Resistance Level: 20 Instantaneous Power: 56 Watt Heart Rate: 0 HBM 11:41:50.570 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:41:51.365 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 B0 09 9E 00 14 00 3C 00 00 ] 11:41:51.365 -> Instant. Speed: 24 KPH Instantaneous Cadence: 79 RPM Resistance Level: 20 Instantaneous Power: 60 Watt Heart Rate: 0 HBM 11:41:52.239 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 E7 09 84 00 14 00 4C 00 00 ] 11:41:52.285 -> Instant. Speed: 25 KPH Instantaneous Cadence: 66 RPM Resistance Level: 20 Instantaneous Power: 76 Watt Heart Rate: 0 HBM 11:41:52.457 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:41:52.535 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:41:53.362 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 F0 09 7A 00 14 00 4C 00 00 ] 11:41:53.362 -> Instant. Speed: 25 KPH Instantaneous Cadence: 61 RPM Resistance Level: 20 Instantaneous Power: 76 Watt Heart Rate: 0 HBM 11:41:54.534 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 11:41:54.613 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 0A 90 00 14 00 58 00 00 ] 11:41:54.613 -> Instant. Speed: 25 KPH Instantaneous Cadence: 72 RPM Resistance Level: 20 Instantaneous Power: 88 Watt Heart Rate: 0 HBM 11:41:54.798 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 11:41:54.798 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 11:41:55.252 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A4 09 81 08 A2 00 A2 00 06 00 00 14 00 59 00 59 00 00 ] 11:41:55.252 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 81 RPM Total Distance: 6 m Resistance Level: 20 Instantaneous Power: 89 Watt Average Power: 89 Watt Heart Rate: 0 HBM 11:41:56.231 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A7 09 81 08 AA 00 A6 00 0C 00 00 14 00 5A 00 59 00 00 ] 11:41:56.231 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 85 RPM Average Cadence: 83 RPM Total Distance: 12 m Resistance Level: 20 Instantaneous Power: 90 Watt Average Power: 89 Watt Heart Rate: 0 HBM 11:41:56.655 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 11:41:56.874 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:56.874 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 11:41:57.190 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9E 09 81 08 A8 00 A6 00 12 00 00 14 00 53 00 57 00 00 ] 11:41:57.190 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 84 RPM Average Cadence: 83 RPM Total Distance: 18 m Resistance Level: 20 Instantaneous Power: 83 Watt Average Power: 87 Watt Heart Rate: 0 HBM 11:41:58.221 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 45 09 81 08 A8 00 A7 00 18 00 00 14 00 50 00 55 00 00 ] 11:41:58.221 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 84 RPM Average Cadence: 83 RPM Total Distance: 24 m Resistance Level: 20 Instantaneous Power: 80 Watt Average Power: 85 Watt Heart Rate: 0 HBM 11:41:58.736 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 11:41:59.018 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:59.018 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 11:41:59.203 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 35 09 81 08 A6 00 A6 00 1E 00 00 14 00 73 00 5B 00 00 ] 11:41:59.203 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 83 RPM Average Cadence: 83 RPM Total Distance: 30 m Resistance Level: 20 Instantaneous Power: 115 Watt Average Power: 91 Watt Heart Rate: 0 HBM 11:42:00.276 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 60 09 81 08 A2 00 A6 00 24 00 00 14 00 B0 00 69 00 00 ] 11:42:00.276 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 83 RPM Total Distance: 36 m Resistance Level: 20 Instantaneous Power: 176 Watt Average Power: 105 Watt Heart Rate: 0 HBM 11:42:00.833 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:42:01.239 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:01.285 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:42:01.285 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8D 09 81 08 A4 00 A5 00 2A 00 00 14 00 9C 00 70 00 00 ] 11:42:01.285 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 82 RPM Average Cadence: 82 RPM Total Distance: 42 m Resistance Level: 20 Instantaneous Power: 156 Watt Average Power: 112 Watt Heart Rate: 0 HBM 11:42:02.267 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 71 09 81 08 A0 00 A5 00 30 00 00 14 00 61 00 6E 00 00 ] 11:42:02.267 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 82 RPM Total Distance: 48 m Resistance Level: 20 Instantaneous Power: 97 Watt Average Power: 110 Watt Heart Rate: 0 HBM 11:42:02.952 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 11:42:03.169 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:03.169 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 11:42:03.264 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5C 09 81 08 A2 00 A4 00 36 00 00 14 00 59 00 6C 00 00 ] 11:42:03.264 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 82 RPM Total Distance: 54 m Resistance Level: 20 Instantaneous Power: 89 Watt Average Power: 108 Watt Heart Rate: 0 HBM 11:42:04.248 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 26 09 81 08 A6 00 A4 00 3C 00 00 14 00 52 00 69 00 00 ] 11:42:04.248 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 83 RPM Average Cadence: 82 RPM Total Distance: 60 m Resistance Level: 20 Instantaneous Power: 82 Watt Average Power: 105 Watt Heart Rate: 0 HBM 11:42:05.043 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 11:42:05.137 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:05.137 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 11:42:05.231 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 56 09 81 08 A8 00 A5 00 42 00 00 14 00 43 00 66 00 00 ] 11:42:05.231 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 84 RPM Average Cadence: 82 RPM Total Distance: 66 m Resistance Level: 20 Instantaneous Power: 67 Watt Average Power: 102 Watt Heart Rate: 0 HBM 11:42:06.225 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 3E 09 81 08 A2 00 A4 00 48 00 00 14 00 55 00 64 00 00 ] 11:42:06.225 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 82 RPM Total Distance: 72 m Resistance Level: 20 Instantaneous Power: 85 Watt Average Power: 100 Watt Heart Rate: 0 HBM 11:42:07.145 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 11:42:07.223 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5B 09 81 08 A0 00 A4 00 4E 00 00 14 00 4A 00 62 00 00 ] 11:42:07.223 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 82 RPM Total Distance: 78 m Resistance Level: 20 Instantaneous Power: 74 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:42:07.223 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:07.223 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 11:42:08.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4C 09 81 08 A0 00 A4 00 54 00 00 14 00 5D 00 62 00 00 ] 11:42:08.206 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 82 RPM Total Distance: 84 m Resistance Level: 20 Instantaneous Power: 93 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:42:09.183 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 42 09 81 08 A0 00 A3 00 5A 00 00 14 00 55 00 61 00 00 ] 11:42:09.183 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 81 RPM Total Distance: 90 m Resistance Level: 20 Instantaneous Power: 85 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:42:09.217 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 11:42:09.375 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:09.375 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 11:42:10.247 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 32 09 81 08 A2 00 A3 00 60 00 00 14 00 5F 00 61 00 00 ] 11:42:10.247 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 81 RPM Total Distance: 96 m Resistance Level: 20 Instantaneous Power: 95 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:42:11.318 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 11:42:11.539 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 17 09 81 08 A0 00 A3 00 66 00 00 14 00 4E 00 60 00 00 ] 11:42:11.539 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 81 RPM Total Distance: 102 m Resistance Level: 20 Instantaneous Power: 78 Watt Average Power: 96 Watt Heart Rate: 0 HBM 11:42:11.632 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:11.632 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 11:42:12.349 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4C 09 81 08 9E 00 A3 00 6C 00 00 14 00 53 00 5F 00 00 ] 11:42:12.349 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 79 RPM Average Cadence: 81 RPM Total Distance: 108 m Resistance Level: 20 Instantaneous Power: 83 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:42:13.427 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 11:42:13.490 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 46 09 81 08 9E 00 A2 00 72 00 00 14 00 56 00 5E 00 00 ] 11:42:13.490 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 79 RPM Average Cadence: 81 RPM Total Distance: 114 m Resistance Level: 20 Instantaneous Power: 86 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:42:13.569 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:13.614 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 11:42:14.223 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0B 09 81 08 A2 00 A2 00 78 00 00 14 00 58 00 5E 00 00 ] 11:42:14.223 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 81 RPM Total Distance: 120 m Resistance Level: 20 Instantaneous Power: 88 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:42:15.205 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 43 09 81 08 A0 00 A2 00 7E 00 00 14 00 5A 00 5E 00 00 ] 11:42:15.205 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 81 RPM Total Distance: 126 m Resistance Level: 20 Instantaneous Power: 90 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:42:15.518 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ]

11:55:16.952 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 11:55:16.952 -> ----------------- Version 02.8 ------------------ 11:55:16.952 -> Initialise the Bluefruit nRF52 module: Client (Central) 11:55:16.952 -> FTMS and Chars 'initialized' 11:55:16.952 -> CPS and Chars 'initialized' 11:55:16.952 -> CSCS and Chars 'initialized' 11:55:16.952 -> GA and Chars 'initialized' 11:55:16.952 -> DIS and Chars 'initialized' 11:55:16.952 -> Start Scanning for CPS, CSC and FTMS! 11:55:16.952 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 11:55:16.952 -> Timestamp MAC Address Rssi Data 11:55:16.952 -> 000001201 F8:9C:FC:53:5E:49 -57 09-02-16-18-26-18-18-18-0A-18 11:55:16.952 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 11:55:16.952 -> Now checking all Client Services and Characteristics! 11:55:16.952 -> If Mandatory Services Fail --> the Client will disconnect! 11:55:16.960 -> First checking Generic Access and Device Information Services and Characteristics! 11:55:16.960 -> Found Client Generic Access 11:55:17.141 -> -> Client Reads Device Name: [Zwift Hub] 11:55:17.563 -> -> Client Reads Appearance: [0] 11:55:17.842 -> Found Client Device Information 11:55:18.310 -> -> Client Reads Manufacturer: [Zwift] 11:55:18.622 -> -> Client Reads Model Number: [06] 11:55:19.060 -> -> Client Reads Serial Number: [06-F89CFC535E49] 11:55:19.246 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 11:55:19.744 -> Discovering Client FTM Feature Characteristic ... Found it! 11:55:19.929 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 11:55:20.116 -> Discovering Client FTM Control Point Characteristic ... Found it! 11:55:20.660 -> Discovering Client FTM Status Characteristic ... Found it! 11:55:21.423 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 11:55:21.470 -> Discovering Client FTM Training Status Characteristic ... Ready to receive Client FTM Control Point Response Messages 11:55:21.747 -> Ready to receive Client FTM Status values 11:55:21.747 -> Not Found! Not Mandatory 11:55:21.964 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 11:55:22.147 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 00 00 00 00 ] 11:55:22.335 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 11:55:22.615 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 00 00 00 00 ] 11:55:22.802 -> Discovering Client FTM Indoor Bike Data Characteristic ... Not Found! Not Mandatory 11:55:23.068 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 11:55:23.502 -> Discovering Client CP Measurement characteristic ... Found it! 11:55:23.719 -> Discovering Client CP Control Point characteristic ... >>> Couldn't enable notify for Client FTM Training Status Characteristic. 11:55:23.856 -> Not Found! NOT Mandatory! 11:55:24.307 -> Discovering Client CP Feature characteristic ... Found it! 11:55:24.307 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 11:55:24.307 -> Wheel revolution data supported 11:55:24.307 -> Crank revolution data supported 11:55:24.572 -> Discovering Client CP Sensor Location characteristic ... Found it! 11:55:24.665 -> -> Client Reads CP Location Sensor: Loc#: 0 Other 11:55:24.930 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 11:55:25.565 -> Discovering Client CSC Measurement CHR ... Found it! 11:55:25.689 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 11:55:25.768 -> Discovering Client CSC Location CHR ... Ready to receive Client CP Measurement values 11:55:25.893 -> Found it! 11:55:25.893 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 11:55:26.207 -> Discovering Client CSC Feature CHR ... Found it! 11:55:26.207 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 11:55:26.207 -> Wheel rev supported 11:55:26.207 -> Crank rev supported 11:55:27.766 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 11:55:27.806 -> Ready to receive Client CSC Measurement values 11:55:27.806 -> Client (Central) is Up and Running! 11:55:29.812 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:55:29.889 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:55:31.910 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ]

11:58:33.742 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 11:58:34.020 -> Discovering Client FTM Feature Characteristic ... Found it! 11:58:34.283 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 11:58:34.487 -> Discovering Client FTM Control Point Characteristic ... Found it! 11:58:35.014 -> Discovering Client FTM Status Characteristic ... Found it! 11:58:35.685 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 11:58:35.762 -> Ready to receive Client FTM Control Point Response Messages 11:58:35.762 -> Discovering Client FTM Training Status Characteristic ... Ready to receive Client FTM Status values 11:58:35.966 -> Not Found! Not Mandatory 11:58:36.151 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 11:58:36.323 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 00 00 00 00 ] 11:58:36.539 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 11:58:36.817 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 11:58:37.314 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 11:58:37.608 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 11:58:37.827 -> Discovering Client CP Measurement characteristic ... >>> Couldn't enable notify for Client FTM Training Status Characteristic. 11:58:37.905 -> Ready to receive Client FTM Indoor Bike Data values 11:58:37.905 -> Found it! 11:58:38.121 -> Ready to receive Client CP Measurement values 11:58:38.121 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 11:58:38.710 -> Discovering Client CP Feature characteristic ... Found it! 11:58:38.710 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 11:58:38.710 -> Wheel revolution data supported 11:58:38.710 -> Crank revolution data supported 11:58:39.161 -> Discovering Client CP Sensor Location characteristic ... Found it! 11:58:39.208 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 11:58:39.548 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 11:58:39.907 -> Discovering Client CSC Measurement CHR ... Found it! 11:58:39.985 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 11:58:40.016 -> Ready to receive Client CSC Measurement values 11:58:40.016 -> Client (Central) is Up and Running! 11:58:40.110 -> Discovering Client CSC Location CHR ... Found it! 11:58:40.559 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 11:58:40.762 -> Discovering Client CSC Feature CHR ... Found it! 11:58:40.932 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 11:58:40.932 -> Wheel rev supported 11:58:40.932 -> Crank rev supported 11:58:41.119 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.119 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:58:41.119 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.119 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:58:41.119 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.119 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:58:41.164 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.164 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance

:02:21.226 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 12:02:21.226 -> ----------------- Version 02.8 ------------------ 12:02:21.226 -> Initialise the Bluefruit nRF52 module: Client (Central) 12:02:21.435 -> FTMS and Chars 'initialized' 12:02:21.435 -> CPS and Chars 'initialized' 12:02:21.435 -> CSCS and Chars 'initialized' 12:02:21.435 -> GA and Chars 'initialized' 12:02:21.435 -> DIS and Chars 'initialized' 12:02:21.435 -> Start Scanning for CPS, CSC and FTMS! 12:02:21.435 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 12:02:21.435 -> Timestamp MAC Address Rssi Data 12:02:21.435 -> 000001359 F8:9C:FC:53:5E:49 -54 09-02-16-18-26-18-18-18-0A-18 12:02:21.440 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 12:02:21.440 -> Now checking all Client Services and Characteristics! 12:02:21.440 -> If Mandatory Services Fail --> the Client will disconnect! 12:02:21.468 -> First checking Generic Access and Device Information Services and Characteristics! 12:02:21.604 -> Found Client Generic Access 12:02:21.959 -> -> Client Reads Device Name: [Zwift Hub] 12:02:22.503 -> -> Client Reads Appearance: [1152] 12:02:22.831 -> Found Client Device Information 12:02:23.268 -> -> Client Reads Manufacturer: [Zwift] 12:02:24.091 -> -> Client Reads Serial Number: [06-F89CFC535E49] 12:02:24.296 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 12:02:24.574 -> Discovering Client FTM Feature Characteristic ... Found it! 12:02:24.716 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 12:02:24.946 -> Discovering Client FTM Control Point Characteristic ... Not Found! 12:02:24.946 -> Disconnecting since Client FTM Control Point Characteristic is mandatory! 12:02:24.993 -> Client Disconnected, reason = 0x16 12:02:24.993 -> >>> Restart the Feather nRF52 Client for a new run! <<< 12:02:26.206 -> Stopped! 12:02:46.062 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 12:02:46.062 -> ----------------- Version 02.8 ------------------ 12:02:46.062 -> Initialise the Bluefruit nRF52 module: Client (Central) 12:02:46.062 -> FTMS and Chars 'initialized' 12:02:46.062 -> CPS and Chars 'initialized' 12:02:46.062 -> CSCS and Chars 'initialized' 12:02:46.062 -> GA and Chars 'initialized' 12:02:46.062 -> DIS and Chars 'initialized' 12:02:46.062 -> Start Scanning for CPS, CSC and FTMS! 12:02:46.478 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 12:02:46.478 -> Timestamp MAC Address Rssi Data 12:02:46.478 -> 000001488 F8:9C:FC:53:5E:49 -52 09-02-16-18-26-18-18-18-0A-18 12:02:46.500 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 12:02:46.500 -> Now checking all Client Services and Characteristics! 12:02:46.500 -> If Mandatory Services Fail --> the Client will disconnect! 12:02:46.500 -> First checking Generic Access and Device Information Services and Characteristics! 12:02:46.592 -> Found Client Generic Access 12:02:46.964 -> -> Client Reads Device Name: [Zwift Hub] 12:02:47.320 -> -> Client Reads Appearance: [1152] 12:02:47.583 -> Found Client Device Information 12:02:47.880 -> -> Client Reads Manufacturer: [Zwift] 12:02:48.252 -> -> Client Reads Model Number: [06] 12:02:48.655 -> -> Client Reads Serial Number: [06-F89CFC535E49] 12:02:48.842 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 12:02:49.124 -> Discovering Client FTM Feature Characteristic ... Found it! 12:02:49.340 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 12:02:49.560 -> Discovering Client FTM Control Point Characteristic ... Found it! 12:02:50.137 -> Discovering Client FTM Status Characteristic ... Found it! 12:02:50.586 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 12:02:50.977 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 12:02:51.020 -> Found it! 12:02:51.020 -> Ready to receive Client FTM Control Point Response Messages 12:02:51.066 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 12:02:51.252 -> Ready to receive Client FTM Status values 12:02:51.252 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 12:02:51.518 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 12:02:51.920 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 12:02:52.156 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 12:02:52.620 -> Discovering Client CP Measurement characteristic ... Found it! 12:02:52.979 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 12:02:53.119 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 12:02:53.165 -> Discovering Client CP Feature characteristic ... Ready to receive Client FTM Indoor Bike Data values 12:02:53.229 -> Found it! 12:02:53.229 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 12:02:53.229 -> Wheel revolution data supported 12:02:53.229 -> Crank revolution data supported 12:02:53.229 -> Ready to receive Client CP Measurement values 12:02:53.514 -> Discovering Client CP Sensor Location characteristic ... Found it! 12:02:53.607 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 12:02:53.918 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 12:02:54.540 -> Discovering Client CSC Measurement CHR ... Found it! 12:02:54.898 -> Discovering Client CSC Location CHR ... Found it! 12:02:54.898 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 12:02:55.256 -> Discovering Client CSC Feature CHR ... Found it! 12:02:55.256 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 12:02:55.302 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 12:02:55.302 -> Wheel rev supported 12:02:55.302 -> Crank rev supported 12:02:55.302 -> Ready to receive Client CSC Measurement values 12:02:55.302 -> Client (Central) is Up and Running! 12:02:55.489 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 12:02:55.489 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 12:02:55.489 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 12:02:55.489 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 12:02:56.207 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 12:02:56.207 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 12:02:57.216 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 12:02:57.216 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 12:02:57.293 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 12:02:57.371 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ]

Berg0162 commented 1 year ago

Pfff, I cannot deny that I feel relieved! How come I did not propose this solution earlier? So stupid! It popped up only yesterday evening after I had studied and compared all your recent test results...

Even your HBM is zero now! Never thought you would be happy with such a result! 😉

If you want to, you can finetune the delay(SOME_TIME); and reach 10 out of 10 !!!

Have a nice weekend!

Op za 17 dec. 2022 12:18 schreef le-joebar @.***>:

Dear Jörghen,

I had to increase the delay to 200 The system starts in any direction 9/10 times

I have given you several examples of start-ups because I believe that certain services are there at certain start-ups and not at others!

The resistance is well felt during the test :)

JACKPOT !!!!!!! Congratulation !!! 👍

11:40:31.097 -> -> Client Reads Appearance: [1152] 11:40:31.210 -> Found Client Device Information 11:40:31.489 -> -> Client Reads Manufacturer: [Zwift] 11:40:31.944 -> -> Client Reads Model Number: [06] 11:40:32.161 -> -> Client Reads Serial Number: [06-F89CFC535E49] 11:40:32.302 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 11:40:32.537 -> Discovering Client FTM Feature Characteristic ... Found it! 11:40:32.742 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 11:40:32.835 -> Discovering Client FTM Control Point Characteristic ... Found it! 11:40:33.212 -> Discovering Client FTM Status Characteristic ... Found it! 11:40:33.620 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 11:40:34.229 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 11:40:34.403 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 11:40:34.497 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 11:40:34.747 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 00 00 00 00 ] 11:40:34.839 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 11:40:35.057 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 11:40:35.134 -> Discovering Client Cycling Power (CP) Service ... Ready to receive Client FTM Control Point Response Messages 11:40:35.181 -> Found it! CPS Max Payload: 20 Data Length: 27 11:40:35.273 -> Ready to receive Client FTM Status values 11:40:35.273 -> Discovering Client CP Measurement characteristic ... Found it! 11:40:35.756 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 11:40:36.023 -> Discovering Client CP Feature characteristic ... Found it! 11:40:36.023 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 11:40:36.023 -> Wheel revolution data supported 11:40:36.023 -> Crank revolution data supported 11:40:36.162 -> Discovering Client CP Sensor Location characteristic ... Found it! 11:40:36.255 -> -> Client Reads CP Location Sensor: Loc#: 0 Other 11:40:36.379 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 11:40:37.221 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 11:40:37.300 -> Ready to receive Client FTM Indoor Bike Data values 11:40:37.300 -> Ready to receive Client CP Measurement values 11:40:38.365 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:40:38.365 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:40:39.220 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 0B 02 00 00 14 00 00 00 00 ] 11:40:39.220 -> Instant. Speed: 5 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:40:39.314 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 11:40:40.385 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 07 03 00 00 14 00 11 00 00 ] 11:40:40.385 -> Instant. Speed: 7 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 17 Watt Heart Rate: 0 HBM 11:40:41.272 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 58 04 00 00 14 00 40 00 00 ] 11:40:41.272 -> Instant. Speed: 11 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 64 Watt Heart Rate: 0 HBM 11:40:41.320 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 11:40:41.320 -> Client (Central) is Up and Running! 11:40:42.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 78 05 00 00 14 00 90 00 00 ] 11:40:42.206 -> Instant. Speed: 14 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 144 Watt Heart Rate: 0 HBM 11:40:43.237 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 CF 05 20 00 14 00 71 00 00 ] 11:40:43.237 -> Instant. Speed: 14 KPH Instantaneous Cadence: 16 RPM Resistance Level: 20 Instantaneous Power: 113 Watt Heart Rate: 0 HBM 11:40:43.315 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:40:43.581 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:40:44.313 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 25 06 46 00 14 00 71 00 00 ] 11:40:44.313 -> Instant. Speed: 15 KPH Instantaneous Cadence: 35 RPM Resistance Level: 20 Instantaneous Power: 113 Watt Heart Rate: 0 HBM 11:40:45.311 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 96 06 5A 00 14 00 94 00 00 ] 11:40:45.311 -> Instant. Speed: 16 KPH Instantaneous Cadence: 45 RPM Resistance Level: 20 Instantaneous Power: 148 Watt Heart Rate: 0 HBM 11:40:45.405 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:40:45.763 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:40:46.212 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 D5 06 68 00 14 00 7E 00 00 ] 11:40:46.212 -> Instant. Speed: 17 KPH Instantaneous Cadence: 52 RPM Resistance Level: 20 Instantaneous Power: 126 Watt Heart Rate: 0 HBM 11:40:47.194 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 16 07 72 00 14 00 6D 00 00 ] 11:40:47.194 -> Instant. Speed: 18 KPH Instantaneous Cadence: 57 RPM Resistance Level: 20 Instantaneous Power: 109 Watt Heart Rate: 0 HBM 11:40:47.506 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 11:40:47.646 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 11:40:47.646 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 11:40:48.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 71 07 17 07 7A 00 7A 00 05 00 00 14 00 61 00 61 00 00 ] 11:40:48.206 -> Instant. Speed: 19 KPH Average Speed: 18 KPH Instantaneous Cadence: 61 RPM Average Cadence: 61 RPM Total Distance: 5 m Resistance Level: 20 Instantaneous Power: 97 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:40:49.611 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 11:40:49.690 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 EC 07 17 07 80 00 7D 00 0A 00 00 14 00 62 00 61 00 00 ] 11:40:49.737 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 64 RPM Average Cadence: 62 RPM Total Distance: 10 m Resistance Level: 20 Instantaneous Power: 98 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:40:49.814 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:49.814 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 11:40:50.545 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1E 08 17 07 82 00 7E 00 0F 00 00 14 00 63 00 62 00 00 ] 11:40:50.545 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 65 RPM Average Cadence: 63 RPM Total Distance: 15 m Resistance Level: 20 Instantaneous Power: 99 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:40:51.247 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D3 07 17 07 86 00 80 00 14 00 00 14 00 5F 00 61 00 00 ] 11:40:51.247 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 67 RPM Average Cadence: 64 RPM Total Distance: 20 m Resistance Level: 20 Instantaneous Power: 95 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:40:51.715 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 11:40:51.887 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:51.887 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 11:40:52.338 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A2 07 17 07 88 00 82 00 19 00 00 14 00 6A 00 63 00 00 ] 11:40:52.338 -> Instant. Speed: 19 KPH Average Speed: 18 KPH Instantaneous Cadence: 68 RPM Average Cadence: 65 RPM Total Distance: 25 m Resistance Level: 20 Instantaneous Power: 106 Watt Average Power: 99 Watt Heart Rate: 0 HBM 11:40:53.228 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 19 08 17 07 88 00 83 00 1E 00 00 14 00 85 00 68 00 00 ] 11:40:53.228 -> Instant. Speed: 20 KPH Average Speed: 18 KPH Instantaneous Cadence: 68 RPM Average Cadence: 65 RPM Total Distance: 30 m Resistance Level: 20 Instantaneous Power: 133 Watt Average Power: 104 Watt Heart Rate: 0 HBM 11:40:53.821 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:40:54.224 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:54.224 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:40:54.224 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 38 08 17 07 88 00 83 00 23 00 00 14 00 74 00 6A 00 00 ] 11:40:54.224 -> Instant. Speed: 21 KPH Average Speed: 18 KPH Instantaneous Cadence: 68 RPM Average Cadence: 65 RPM Total Distance: 35 m Resistance Level: 20 Instantaneous Power: 116 Watt Average Power: 106 Watt Heart Rate: 0 HBM 11:40:55.302 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4E 08 17 07 8A 00 84 00 28 00 00 14 00 67 00 69 00 00 ] 11:40:55.302 -> Instant. Speed: 21 KPH Average Speed: 18 KPH Instantaneous Cadence: 69 RPM Average Cadence: 66 RPM Total Distance: 40 m Resistance Level: 20 Instantaneous Power: 103 Watt Average Power: 105 Watt Heart Rate: 0 HBM 11:40:55.908 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 11:40:56.034 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:56.034 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 11:40:56.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D1 08 3F 07 8C 00 85 00 2E 00 00 14 00 57 00 67 00 00 ] 11:40:56.206 -> Instant. Speed: 22 KPH Average Speed: 18 KPH Instantaneous Cadence: 70 RPM Average Cadence: 66 RPM Total Distance: 46 m Resistance Level: 20 Instantaneous Power: 87 Watt Average Power: 103 Watt Heart Rate: 0 HBM 11:40:57.159 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 7F 08 3B 07 94 00 86 00 33 00 00 14 00 5A 00 66 00 00 ] 11:40:57.205 -> Instant. Speed: 21 KPH Average Speed: 18 KPH Instantaneous Cadence: 74 RPM Average Cadence: 67 RPM Total Distance: 51 m Resistance Level: 20 Instantaneous Power: 90 Watt Average Power: 102 Watt Heart Rate: 0 HBM 11:40:57.986 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 11:40:58.159 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:40:58.159 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 11:40:58.284 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AC 08 58 07 96 00 88 00 39 00 00 14 00 47 00 63 00 00 ] 11:40:58.284 -> Instant. Speed: 22 KPH Average Speed: 18 KPH Instantaneous Cadence: 75 RPM Average Cadence: 68 RPM Total Distance: 57 m Resistance Level: 20 Instantaneous Power: 71 Watt Average Power: 99 Watt Heart Rate: 0 HBM 11:40:59.254 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 84 08 71 07 96 00 89 00 3F 00 00 14 00 58 00 62 00 00 ] 11:40:59.254 -> Instant. Speed: 21 KPH Average Speed: 19 KPH Instantaneous Cadence: 75 RPM Average Cadence: 68 RPM Total Distance: 63 m Resistance Level: 20 Instantaneous Power: 88 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:41:00.125 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 11:41:00.344 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E7 08 86 07 20 00 81 00 45 00 00 14 00 5F 00 62 00 00 ] 11:41:00.344 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 16 RPM Average Cadence: 64 RPM Total Distance: 69 m Resistance Level: 20 Instantaneous Power: 95 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:41:00.344 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:00.344 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 11:41:01.324 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C5 08 98 07 6E 00 7F 00 4B 00 00 14 00 57 00 61 00 00 ] 11:41:01.324 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 55 RPM Average Cadence: 63 RPM Total Distance: 75 m Resistance Level: 20 Instantaneous Power: 87 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:41:02.199 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 11:41:02.245 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B2 08 A8 07 8C 00 80 00 51 00 00 14 00 5C 00 61 00 00 ] 11:41:02.245 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 70 RPM Average Cadence: 64 RPM Total Distance: 81 m Resistance Level: 20 Instantaneous Power: 92 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:41:02.245 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:02.245 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 11:41:03.228 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 BB 08 B5 07 94 00 81 00 57 00 00 14 00 5D 00 60 00 00 ] 11:41:03.228 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 74 RPM Average Cadence: 64 RPM Total Distance: 87 m Resistance Level: 20 Instantaneous Power: 93 Watt Average Power: 96 Watt Heart Rate: 0 HBM 11:41:04.228 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 11:41:04.306 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 07 09 C1 07 94 00 82 00 5D 00 00 14 00 55 00 60 00 00 ] 11:41:04.306 -> Instant. Speed: 23 KPH Average Speed: 19 KPH Instantaneous Cadence: 74 RPM Average Cadence: 65 RPM Total Distance: 93 m Resistance Level: 20 Instantaneous Power: 85 Watt Average Power: 96 Watt Heart Rate: 0 HBM 11:41:04.400 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:04.400 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 11:41:05.210 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D4 08 CC 07 98 00 84 00 63 00 00 14 00 5B 00 5F 00 00 ] 11:41:05.210 -> Instant. Speed: 22 KPH Average Speed: 19 KPH Instantaneous Cadence: 76 RPM Average Cadence: 66 RPM Total Distance: 99 m Resistance Level: 20 Instantaneous Power: 91 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:06.189 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E1 08 D5 07 9C 00 85 00 69 00 00 14 00 5E 00 5F 00 00 ] 11:41:06.190 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 66 RPM Total Distance: 105 m Resistance Level: 20 Instantaneous Power: 94 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:06.329 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 11:41:06.829 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:06.829 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 11:41:07.264 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 BD 08 DE 07 9C 00 86 00 6F 00 00 14 00 61 00 5F 00 00 ] 11:41:07.264 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 67 RPM Total Distance: 111 m Resistance Level: 20 Instantaneous Power: 97 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:08.339 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1F 09 E6 07 98 00 87 00 75 00 00 14 00 58 00 5F 00 00 ] 11:41:08.339 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 76 RPM Average Cadence: 67 RPM Total Distance: 117 m Resistance Level: 20 Instantaneous Power: 88 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:41:08.431 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:41:08.618 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:08.618 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:41:09.414 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 D6 08 ED 07 9E 00 88 00 7B 00 00 14 00 54 00 5E 00 00 ] 11:41:09.414 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 68 RPM Total Distance: 123 m Resistance Level: 20 Instantaneous Power: 84 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:41:10.240 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E6 08 F3 07 A2 00 89 00 81 00 00 14 00 53 00 5E 00 00 ] 11:41:10.240 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 81 RPM Average Cadence: 68 RPM Total Distance: 129 m Resistance Level: 20 Instantaneous Power: 83 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:41:10.550 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 11:41:10.691 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:10.691 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 11:41:11.235 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C4 08 F9 07 9C 00 8A 00 87 00 00 14 00 44 00 5D 00 00 ] 11:41:11.235 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 69 RPM Total Distance: 135 m Resistance Level: 20 Instantaneous Power: 68 Watt Average Power: 93 Watt Heart Rate: 0 HBM 11:41:12.235 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 04 09 FF 07 9C 00 8A 00 8D 00 00 14 00 43 00 5C 00 00 ] 11:41:12.235 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 78 RPM Average Cadence: 69 RPM Total Distance: 141 m Resistance Level: 20 Instantaneous Power: 67 Watt Average Power: 92 Watt Heart Rate: 0 HBM 11:41:12.639 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 11:41:12.857 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:12.857 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 11:41:13.217 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 09 09 04 08 A0 00 8B 00 93 00 00 14 00 4C 00 5B 00 00 ] 11:41:13.217 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 80 RPM Average Cadence: 69 RPM Total Distance: 147 m Resistance Level: 20 Instantaneous Power: 76 Watt Average Power: 91 Watt Heart Rate: 0 HBM 11:41:14.169 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E7 08 08 08 9E 00 8C 00 99 00 00 14 00 4A 00 5B 00 00 ] 11:41:14.216 -> Instant. Speed: 22 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 70 RPM Total Distance: 153 m Resistance Level: 20 Instantaneous Power: 74 Watt Average Power: 91 Watt Heart Rate: 0 HBM 11:41:14.745 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 11:41:14.902 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:14.902 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 11:41:15.183 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1D 09 0D 08 9E 00 8D 00 9F 00 00 14 00 48 00 5A 00 00 ] 11:41:15.183 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 70 RPM Total Distance: 159 m Resistance Level: 20 Instantaneous Power: 72 Watt Average Power: 90 Watt Heart Rate: 0 HBM 11:41:16.368 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1E 09 11 08 A0 00 8D 00 A5 00 00 14 00 49 00 59 00 00 ] 11:41:16.368 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 80 RPM Average Cadence: 70 RPM Total Distance: 165 m Resistance Level: 20 Instantaneous Power: 73 Watt Average Power: 89 Watt Heart Rate: 0 HBM 11:41:16.853 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 11:41:16.992 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:16.992 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 11:41:17.366 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 17 09 14 08 9E 00 8E 00 AB 00 00 14 00 3F 00 58 00 00 ] 11:41:17.366 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 71 RPM Total Distance: 171 m Resistance Level: 20 Instantaneous Power: 63 Watt Average Power: 88 Watt Heart Rate: 0 HBM 11:41:18.255 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 6F 09 18 08 A2 00 8E 00 B1 00 00 14 00 44 00 58 00 00 ] 11:41:18.255 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 81 RPM Average Cadence: 71 RPM Total Distance: 177 m Resistance Level: 20 Instantaneous Power: 68 Watt Average Power: 88 Watt Heart Rate: 0 HBM 11:41:18.941 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 11:41:19.158 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:19.158 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 11:41:19.252 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 65 09 1B 08 9E 00 8F 00 B7 00 00 14 00 4E 00 57 00 00 ] 11:41:19.252 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 79 RPM Average Cadence: 71 RPM Total Distance: 183 m Resistance Level: 20 Instantaneous Power: 78 Watt Average Power: 87 Watt Heart Rate: 0 HBM 11:41:20.216 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5B 09 1E 08 A6 00 90 00 BD 00 00 14 00 39 00 56 00 00 ] 11:41:20.216 -> Instant. Speed: 23 KPH Average Speed: 20 KPH Instantaneous Cadence: 83 RPM Average Cadence: 72 RPM Total Distance: 189 m Resistance Level: 20 Instantaneous Power: 57 Watt Average Power: 86 Watt Heart Rate: 0 HBM 11:41:21.042 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 11:41:21.215 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9C 09 21 08 B0 00 91 00 C3 00 00 14 00 32 00 55 00 00 ] 11:41:21.215 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 88 RPM Average Cadence: 72 RPM Total Distance: 195 m Resistance Level: 20 Instantaneous Power: 50 Watt Average Power: 85 Watt Heart Rate: 0 HBM 11:41:21.215 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:21.215 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 11:41:22.182 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A5 09 24 08 B0 00 91 00 C9 00 00 14 00 3A 00 55 00 00 ] 11:41:22.182 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 88 RPM Average Cadence: 72 RPM Total Distance: 201 m Resistance Level: 20 Instantaneous Power: 58 Watt Average Power: 85 Watt Heart Rate: 0 HBM 11:41:23.149 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 11:41:23.196 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8D 09 27 08 A2 00 92 00 CF 00 00 14 00 26 00 53 00 00 ] 11:41:23.196 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 81 RPM Average Cadence: 73 RPM Total Distance: 207 m Resistance Level: 20 Instantaneous Power: 38 Watt Average Power: 83 Watt Heart Rate: 0 HBM 11:41:23.196 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:23.196 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 11:41:24.179 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AC 09 29 08 8A 00 92 00 D5 00 00 14 00 26 00 52 00 00 ] 11:41:24.179 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 69 RPM Average Cadence: 73 RPM Total Distance: 213 m Resistance Level: 20 Instantaneous Power: 38 Watt Average Power: 82 Watt Heart Rate: 0 HBM 11:41:25.221 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 11:41:25.441 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 7D 09 2B 08 66 00 90 00 DB 00 00 14 00 29 00 51 00 00 ] 11:41:25.441 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 51 RPM Average Cadence: 72 RPM Total Distance: 219 m Resistance Level: 20 Instantaneous Power: 41 Watt Average Power: 81 Watt Heart Rate: 0 HBM 11:41:25.549 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:25.549 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 11:41:26.249 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8C 09 2E 08 5A 00 8F 00 E1 00 00 14 00 29 00 50 00 00 ] 11:41:26.249 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 45 RPM Average Cadence: 71 RPM Total Distance: 225 m Resistance Level: 20 Instantaneous Power: 41 Watt Average Power: 80 Watt Heart Rate: 0 HBM 11:41:27.260 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9A 09 30 08 5E 00 8E 00 E7 00 00 14 00 26 00 4F 00 00 ] 11:41:27.260 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 47 RPM Average Cadence: 71 RPM Total Distance: 231 m Resistance Level: 20 Instantaneous Power: 38 Watt Average Power: 79 Watt Heart Rate: 0 HBM 11:41:27.307 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 11:41:27.447 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:27.447 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 11:41:28.242 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 87 09 32 08 66 00 8D 00 ED 00 00 14 00 22 00 4E 00 00 ] 11:41:28.242 -> Instant. Speed: 24 KPH Average Speed: 20 KPH Instantaneous Cadence: 51 RPM Average Cadence: 70 RPM Total Distance: 237 m Resistance Level: 20 Instantaneous Power: 34 Watt Average Power: 78 Watt Heart Rate: 0 HBM 11:41:29.224 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5C 09 34 08 66 00 8C 00 F3 00 00 14 00 2E 00 4D 00 00 ] 11:41:29.224 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 51 RPM Average Cadence: 70 RPM Total Distance: 243 m Resistance Level: 20 Instantaneous Power: 46 Watt Average Power: 77 Watt Heart Rate: 0 HBM 11:41:29.410 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 11:41:29.782 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:29.782 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 11:41:30.296 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 EB 08 35 08 00 00 89 00 F9 00 00 14 00 00 00 4B 00 00 ] 11:41:30.296 -> Instant. Speed: 22 KPH Average Speed: 21 KPH Instantaneous Cadence: 0 RPM Average Cadence: 68 RPM Total Distance: 249 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 75 Watt Heart Rate: 0 HBM 11:41:31.196 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AA 09 37 08 00 00 86 00 FF 00 00 14 00 00 00 49 00 00 ] 11:41:31.196 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 0 RPM Average Cadence: 67 RPM Total Distance: 255 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 73 Watt Heart Rate: 0 HBM 11:41:31.523 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 11:41:31.757 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:31.757 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 11:41:32.458 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 CB 09 39 08 50 00 84 00 05 01 00 14 00 35 00 49 00 00 ] 11:41:32.458 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 40 RPM Average Cadence: 66 RPM Total Distance: 261 m Resistance Level: 20 Instantaneous Power: 53 Watt Average Power: 73 Watt Heart Rate: 0 HBM 11:41:33.472 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E4 09 3A 08 56 00 83 00 0B 01 00 14 00 33 00 48 00 00 ] 11:41:33.472 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 43 RPM Average Cadence: 65 RPM Total Distance: 267 m Resistance Level: 20 Instantaneous Power: 51 Watt Average Power: 72 Watt Heart Rate: 0 HBM 11:41:33.612 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:41:33.830 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:33.830 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:41:34.376 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 25 0A 44 08 56 00 82 00 12 01 00 14 00 33 00 48 00 00 ] 11:41:34.376 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 43 RPM Average Cadence: 65 RPM Total Distance: 274 m Resistance Level: 20 Instantaneous Power: 51 Watt Average Power: 72 Watt Heart Rate: 0 HBM 11:41:35.450 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1B 0A 4C 08 54 00 81 00 19 01 00 14 00 2E 00 47 00 00 ] 11:41:35.450 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 42 RPM Average Cadence: 64 RPM Total Distance: 281 m Resistance Level: 20 Instantaneous Power: 46 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:35.712 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A2 00 28 33 00 ] 11:41:35.993 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:35.993 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A2 00 28 33 ] 11:41:36.259 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 1F 0A 55 08 5E 00 81 00 20 01 00 14 00 27 00 47 00 00 ] 11:41:36.259 -> Instant. Speed: 25 KPH Average Speed: 21 KPH Instantaneous Cadence: 47 RPM Average Cadence: 64 RPM Total Distance: 288 m Resistance Level: 20 Instantaneous Power: 39 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:37.320 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AE 09 56 08 64 00 80 00 26 01 00 14 00 27 00 46 00 00 ] 11:41:37.320 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 50 RPM Average Cadence: 64 RPM Total Distance: 294 m Resistance Level: 20 Instantaneous Power: 39 Watt Average Power: 70 Watt Heart Rate: 0 HBM 11:41:37.818 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 01 28 33 00 ] 11:41:38.148 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:38.148 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 01 28 33 ] 11:41:38.241 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 65 09 57 08 5C 00 7F 00 2C 01 00 14 00 1F 00 45 00 00 ] 11:41:38.241 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 46 RPM Average Cadence: 63 RPM Total Distance: 300 m Resistance Level: 20 Instantaneous Power: 31 Watt Average Power: 69 Watt Heart Rate: 0 HBM 11:41:39.209 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0B 09 57 08 54 00 7E 00 32 01 00 14 00 1F 00 45 00 00 ] 11:41:39.209 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 42 RPM Average Cadence: 63 RPM Total Distance: 306 m Resistance Level: 20 Instantaneous Power: 31 Watt Average Power: 69 Watt Heart Rate: 0 HBM 11:41:39.909 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 4F 01 28 33 00 ] 11:41:40.021 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:40.021 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4F 01 28 33 ] 11:41:40.301 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 19 09 58 08 50 00 7E 00 38 01 00 14 00 4C 00 45 00 00 ] 11:41:40.301 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 40 RPM Average Cadence: 63 RPM Total Distance: 312 m Resistance Level: 20 Instantaneous Power: 76 Watt Average Power: 69 Watt Heart Rate: 0 HBM 11:41:41.281 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8B 08 59 08 50 00 7D 00 3E 01 00 14 00 7A 00 46 00 00 ] 11:41:41.281 -> Instant. Speed: 21 KPH Average Speed: 21 KPH Instantaneous Cadence: 40 RPM Average Cadence: 62 RPM Total Distance: 318 m Resistance Level: 20 Instantaneous Power: 122 Watt Average Power: 70 Watt Heart Rate: 0 HBM 11:41:41.999 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 01 28 33 00 ] 11:41:42.203 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:42.203 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 01 28 33 ] 11:41:42.203 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E7 08 5A 08 30 00 7B 00 44 01 00 14 00 7A 00 47 00 00 ] 11:41:42.203 -> Instant. Speed: 22 KPH Average Speed: 21 KPH Instantaneous Cadence: 24 RPM Average Cadence: 61 RPM Total Distance: 324 m Resistance Level: 20 Instantaneous Power: 122 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:43.463 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 27 08 54 08 70 00 7B 00 49 01 00 14 00 62 00 47 00 00 ] 11:41:43.463 -> Instant. Speed: 20 KPH Average Speed: 21 KPH Instantaneous Cadence: 56 RPM Average Cadence: 61 RPM Total Distance: 329 m Resistance Level: 20 Instantaneous Power: 98 Watt Average Power: 71 Watt Heart Rate: 0 HBM 11:41:44.118 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 57 FF 28 33 00 ] 11:41:44.258 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 85 08 55 08 86 00 7B 00 4F 01 00 14 00 C1 00 49 00 00 ] 11:41:44.258 -> Instant. Speed: 21 KPH Average Speed: 21 KPH Instantaneous Cadence: 67 RPM Average Cadence: 61 RPM Total Distance: 335 m Resistance Level: 20 Instantaneous Power: 193 Watt Average Power: 73 Watt Heart Rate: 0 HBM 11:41:44.337 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:44.337 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 FF 28 33 ] 11:41:45.414 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E0 08 55 08 8C 00 7C 00 55 01 00 14 00 B9 00 4B 00 00 ] 11:41:45.414 -> Instant. Speed: 22 KPH Average Speed: 21 KPH Instantaneous Cadence: 70 RPM Average Cadence: 62 RPM Total Distance: 341 m Resistance Level: 20 Instantaneous Power: 185 Watt Average Power: 75 Watt Heart Rate: 0 HBM 11:41:46.191 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 08 00 00 00 00 00 00 00 ] 11:41:46.238 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 28 09 56 08 8E 00 7C 00 5B 01 00 14 00 C6 00 4D 00 00 ] 11:41:46.238 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 71 RPM Average Cadence: 62 RPM Total Distance: 347 m Resistance Level: 20 Instantaneous Power: 198 Watt Average Power: 77 Watt Heart Rate: 0 HBM 11:41:46.238 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 08 03 ] 11:41:47.396 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 38 09 57 08 98 00 7C 00 61 01 00 14 00 71 00 4E 00 00 ] 11:41:47.396 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 76 RPM Average Cadence: 62 RPM Total Distance: 353 m Resistance Level: 20 Instantaneous Power: 113 Watt Average Power: 78 Watt Heart Rate: 0 HBM 11:41:48.212 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 81 09 58 08 9E 00 7D 00 67 01 00 14 00 3F 00 4E 00 00 ] 11:41:48.212 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 79 RPM Average Cadence: 62 RPM Total Distance: 359 m Resistance Level: 20 Instantaneous Power: 63 Watt Average Power: 78 Watt Heart Rate: 0 HBM 11:41:48.253 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 01 00 00 00 00 00 00 00 ] 11:41:48.394 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 01 01 ] 11:41:48.394 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 11:41:49.269 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 C7 09 A6 00 14 00 31 00 00 ] 11:41:49.315 -> Instant. Speed: 25 KPH Instantaneous Cadence: 83 RPM Resistance Level: 20 Instantaneous Power: 49 Watt Heart Rate: 0 HBM 11:41:50.351 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:41:50.477 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 AB 09 AC 00 14 00 38 00 00 ] 11:41:50.477 -> Instant. Speed: 24 KPH Instantaneous Cadence: 86 RPM Resistance Level: 20 Instantaneous Power: 56 Watt Heart Rate: 0 HBM 11:41:50.570 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:41:51.365 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 B0 09 9E 00 14 00 3C 00 00 ] 11:41:51.365 -> Instant. Speed: 24 KPH Instantaneous Cadence: 79 RPM Resistance Level: 20 Instantaneous Power: 60 Watt Heart Rate: 0 HBM 11:41:52.239 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 E7 09 84 00 14 00 4C 00 00 ] 11:41:52.285 -> Instant. Speed: 25 KPH Instantaneous Cadence: 66 RPM Resistance Level: 20 Instantaneous Power: 76 Watt Heart Rate: 0 HBM 11:41:52.457 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:41:52.535 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:41:53.362 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 F0 09 7A 00 14 00 4C 00 00 ] 11:41:53.362 -> Instant. Speed: 25 KPH Instantaneous Cadence: 61 RPM Resistance Level: 20 Instantaneous Power: 76 Watt Heart Rate: 0 HBM 11:41:54.534 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 11:41:54.613 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 0A 90 00 14 00 58 00 00 ] 11:41:54.613 -> Instant. Speed: 25 KPH Instantaneous Cadence: 72 RPM Resistance Level: 20 Instantaneous Power: 88 Watt Heart Rate: 0 HBM 11:41:54.798 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 11:41:54.798 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 11:41:55.252 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A4 09 81 08 A2 00 A2 00 06 00 00 14 00 59 00 59 00 00 ] 11:41:55.252 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 81 RPM Total Distance: 6 m Resistance Level: 20 Instantaneous Power: 89 Watt Average Power: 89 Watt Heart Rate: 0 HBM 11:41:56.231 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A7 09 81 08 AA 00 A6 00 0C 00 00 14 00 5A 00 59 00 00 ] 11:41:56.231 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 85 RPM Average Cadence: 83 RPM Total Distance: 12 m Resistance Level: 20 Instantaneous Power: 90 Watt Average Power: 89 Watt Heart Rate: 0 HBM 11:41:56.655 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 11:41:56.874 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:56.874 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 11:41:57.190 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 9E 09 81 08 A8 00 A6 00 12 00 00 14 00 53 00 57 00 00 ] 11:41:57.190 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 84 RPM Average Cadence: 83 RPM Total Distance: 18 m Resistance Level: 20 Instantaneous Power: 83 Watt Average Power: 87 Watt Heart Rate: 0 HBM 11:41:58.221 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 45 09 81 08 A8 00 A7 00 18 00 00 14 00 50 00 55 00 00 ] 11:41:58.221 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 84 RPM Average Cadence: 83 RPM Total Distance: 24 m Resistance Level: 20 Instantaneous Power: 80 Watt Average Power: 85 Watt Heart Rate: 0 HBM 11:41:58.736 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 11:41:59.018 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:41:59.018 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 11:41:59.203 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 35 09 81 08 A6 00 A6 00 1E 00 00 14 00 73 00 5B 00 00 ] 11:41:59.203 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 83 RPM Average Cadence: 83 RPM Total Distance: 30 m Resistance Level: 20 Instantaneous Power: 115 Watt Average Power: 91 Watt Heart Rate: 0 HBM 11:42:00.276 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 60 09 81 08 A2 00 A6 00 24 00 00 14 00 B0 00 69 00 00 ] 11:42:00.276 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 83 RPM Total Distance: 36 m Resistance Level: 20 Instantaneous Power: 176 Watt Average Power: 105 Watt Heart Rate: 0 HBM 11:42:00.833 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 11:42:01.239 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:01.285 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 11:42:01.285 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 8D 09 81 08 A4 00 A5 00 2A 00 00 14 00 9C 00 70 00 00 ] 11:42:01.285 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 82 RPM Average Cadence: 82 RPM Total Distance: 42 m Resistance Level: 20 Instantaneous Power: 156 Watt Average Power: 112 Watt Heart Rate: 0 HBM 11:42:02.267 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 71 09 81 08 A0 00 A5 00 30 00 00 14 00 61 00 6E 00 00 ] 11:42:02.267 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 82 RPM Total Distance: 48 m Resistance Level: 20 Instantaneous Power: 97 Watt Average Power: 110 Watt Heart Rate: 0 HBM 11:42:02.952 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 11:42:03.169 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:03.169 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 11:42:03.264 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5C 09 81 08 A2 00 A4 00 36 00 00 14 00 59 00 6C 00 00 ] 11:42:03.264 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 82 RPM Total Distance: 54 m Resistance Level: 20 Instantaneous Power: 89 Watt Average Power: 108 Watt Heart Rate: 0 HBM 11:42:04.248 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 26 09 81 08 A6 00 A4 00 3C 00 00 14 00 52 00 69 00 00 ] 11:42:04.248 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 83 RPM Average Cadence: 82 RPM Total Distance: 60 m Resistance Level: 20 Instantaneous Power: 82 Watt Average Power: 105 Watt Heart Rate: 0 HBM 11:42:05.043 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 11:42:05.137 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:05.137 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 11:42:05.231 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 56 09 81 08 A8 00 A5 00 42 00 00 14 00 43 00 66 00 00 ] 11:42:05.231 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 84 RPM Average Cadence: 82 RPM Total Distance: 66 m Resistance Level: 20 Instantaneous Power: 67 Watt Average Power: 102 Watt Heart Rate: 0 HBM 11:42:06.225 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 3E 09 81 08 A2 00 A4 00 48 00 00 14 00 55 00 64 00 00 ] 11:42:06.225 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 82 RPM Total Distance: 72 m Resistance Level: 20 Instantaneous Power: 85 Watt Average Power: 100 Watt Heart Rate: 0 HBM 11:42:07.145 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 11:42:07.223 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5B 09 81 08 A0 00 A4 00 4E 00 00 14 00 4A 00 62 00 00 ] 11:42:07.223 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 82 RPM Total Distance: 78 m Resistance Level: 20 Instantaneous Power: 74 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:42:07.223 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:07.223 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 11:42:08.206 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4C 09 81 08 A0 00 A4 00 54 00 00 14 00 5D 00 62 00 00 ] 11:42:08.206 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 82 RPM Total Distance: 84 m Resistance Level: 20 Instantaneous Power: 93 Watt Average Power: 98 Watt Heart Rate: 0 HBM 11:42:09.183 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 42 09 81 08 A0 00 A3 00 5A 00 00 14 00 55 00 61 00 00 ] 11:42:09.183 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 81 RPM Total Distance: 90 m Resistance Level: 20 Instantaneous Power: 85 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:42:09.217 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 11:42:09.375 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:09.375 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 11:42:10.247 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 32 09 81 08 A2 00 A3 00 60 00 00 14 00 5F 00 61 00 00 ] 11:42:10.247 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 81 RPM Total Distance: 96 m Resistance Level: 20 Instantaneous Power: 95 Watt Average Power: 97 Watt Heart Rate: 0 HBM 11:42:11.318 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 11:42:11.539 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 17 09 81 08 A0 00 A3 00 66 00 00 14 00 4E 00 60 00 00 ] 11:42:11.539 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 81 RPM Total Distance: 102 m Resistance Level: 20 Instantaneous Power: 78 Watt Average Power: 96 Watt Heart Rate: 0 HBM 11:42:11.632 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:11.632 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 11:42:12.349 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4C 09 81 08 9E 00 A3 00 6C 00 00 14 00 53 00 5F 00 00 ] 11:42:12.349 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 79 RPM Average Cadence: 81 RPM Total Distance: 108 m Resistance Level: 20 Instantaneous Power: 83 Watt Average Power: 95 Watt Heart Rate: 0 HBM 11:42:13.427 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 11:42:13.490 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 46 09 81 08 9E 00 A2 00 72 00 00 14 00 56 00 5E 00 00 ] 11:42:13.490 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 79 RPM Average Cadence: 81 RPM Total Distance: 114 m Resistance Level: 20 Instantaneous Power: 86 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:42:13.569 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 11:42:13.614 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 11:42:14.223 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0B 09 81 08 A2 00 A2 00 78 00 00 14 00 58 00 5E 00 00 ] 11:42:14.223 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 81 RPM Average Cadence: 81 RPM Total Distance: 120 m Resistance Level: 20 Instantaneous Power: 88 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:42:15.205 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 43 09 81 08 A0 00 A2 00 7E 00 00 14 00 5A 00 5E 00 00 ] 11:42:15.205 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 80 RPM Average Cadence: 81 RPM Total Distance: 126 m Resistance Level: 20 Instantaneous Power: 90 Watt Average Power: 94 Watt Heart Rate: 0 HBM 11:42:15.518 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ]

11:55:16.952 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 11:55:16.952 -> ----------------- Version 02.8 ------------------ 11:55:16.952 -> Initialise the Bluefruit nRF52 module: Client (Central) 11:55:16.952 -> FTMS and Chars 'initialized' 11:55:16.952 -> CPS and Chars 'initialized' 11:55:16.952 -> CSCS and Chars 'initialized' 11:55:16.952 -> GA and Chars 'initialized' 11:55:16.952 -> DIS and Chars 'initialized' 11:55:16.952 -> Start Scanning for CPS, CSC and FTMS! 11:55:16.952 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 11:55:16.952 -> Timestamp MAC Address Rssi Data 11:55:16.952 -> 000001201 F8:9C:FC:53:5E:49 -57 09-02-16-18-26-18-18-18-0A-18 11:55:16.952 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 11:55:16.952 -> Now checking all Client Services and Characteristics! 11:55:16.952 -> If Mandatory Services Fail --> the Client will disconnect! 11:55:16.960 -> First checking Generic Access and Device Information Services and Characteristics! 11:55:16.960 -> Found Client Generic Access 11:55:17.141 -> -> Client Reads Device Name: [Zwift Hub] 11:55:17.563 -> -> Client Reads Appearance: [0] 11:55:17.842 -> Found Client Device Information 11:55:18.310 -> -> Client Reads Manufacturer: [Zwift] 11:55:18.622 -> -> Client Reads Model Number: [06] 11:55:19.060 -> -> Client Reads Serial Number: [06-F89CFC535E49] 11:55:19.246 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 11:55:19.744 -> Discovering Client FTM Feature Characteristic ... Found it! 11:55:19.929 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 11:55:20.116 -> Discovering Client FTM Control Point Characteristic ... Found it! 11:55:20.660 -> Discovering Client FTM Status Characteristic ... Found it! 11:55:21.423 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 11:55:21.470 -> Discovering Client FTM Training Status Characteristic ... Ready to receive Client FTM Control Point Response Messages 11:55:21.747 -> Ready to receive Client FTM Status values 11:55:21.747 -> Not Found! Not Mandatory 11:55:21.964 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 11:55:22.147 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 00 00 00 00 ] 11:55:22.335 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 11:55:22.615 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 00 00 00 00 ] 11:55:22.802 -> Discovering Client FTM Indoor Bike Data Characteristic ... Not Found! Not Mandatory 11:55:23.068 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 11:55:23.502 -> Discovering Client CP Measurement characteristic ... Found it! 11:55:23.719 -> Discovering Client CP Control Point characteristic ... >>> Couldn't enable notify for Client FTM Training Status Characteristic. 11:55:23.856 -> Not Found! NOT Mandatory! 11:55:24.307 -> Discovering Client CP Feature characteristic ... Found it! 11:55:24.307 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 11:55:24.307 -> Wheel revolution data supported 11:55:24.307 -> Crank revolution data supported 11:55:24.572 -> Discovering Client CP Sensor Location characteristic ... Found it! 11:55:24.665 -> -> Client Reads CP Location Sensor: Loc#: 0 Other 11:55:24.930 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 11:55:25.565 -> Discovering Client CSC Measurement CHR ... Found it! 11:55:25.689 -> >>> Couldn't enable notify for Client FTM Indoor Bike Data Characteristic. 11:55:25.768 -> Discovering Client CSC Location CHR ... Ready to receive Client CP Measurement values 11:55:25.893 -> Found it! 11:55:25.893 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 11:55:26.207 -> Discovering Client CSC Feature CHR ... Found it! 11:55:26.207 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 11:55:26.207 -> Wheel rev supported 11:55:26.207 -> Crank rev supported 11:55:27.766 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 11:55:27.806 -> Ready to receive Client CSC Measurement values 11:55:27.806 -> Client (Central) is Up and Running! 11:55:29.812 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 11:55:29.889 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 11:55:31.910 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ]

11:58:33.742 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 11:58:34.020 -> Discovering Client FTM Feature Characteristic ... Found it! 11:58:34.283 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 11:58:34.487 -> Discovering Client FTM Control Point Characteristic ... Found it! 11:58:35.014 -> Discovering Client FTM Status Characteristic ... Found it! 11:58:35.685 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 11:58:35.762 -> Ready to receive Client FTM Control Point Response Messages 11:58:35.762 -> Discovering Client FTM Training Status Characteristic ... Ready to receive Client FTM Status values 11:58:35.966 -> Not Found! Not Mandatory 11:58:36.151 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 11:58:36.323 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 00 00 00 00 ] 11:58:36.539 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 11:58:36.817 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 11:58:37.314 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 11:58:37.608 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 11:58:37.827 -> Discovering Client CP Measurement characteristic ... >>> Couldn't enable notify for Client FTM Training Status Characteristic. 11:58:37.905 -> Ready to receive Client FTM Indoor Bike Data values 11:58:37.905 -> Found it! 11:58:38.121 -> Ready to receive Client CP Measurement values 11:58:38.121 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 11:58:38.710 -> Discovering Client CP Feature characteristic ... Found it! 11:58:38.710 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 11:58:38.710 -> Wheel revolution data supported 11:58:38.710 -> Crank revolution data supported 11:58:39.161 -> Discovering Client CP Sensor Location characteristic ... Found it! 11:58:39.208 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 11:58:39.548 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 11:58:39.907 -> Discovering Client CSC Measurement CHR ... Found it! 11:58:39.985 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 11:58:40.016 -> Ready to receive Client CSC Measurement values 11:58:40.016 -> Client (Central) is Up and Running! 11:58:40.110 -> Discovering Client CSC Location CHR ... Found it! 11:58:40.559 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 11:58:40.762 -> Discovering Client CSC Feature CHR ... Found it! 11:58:40.932 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 11:58:40.932 -> Wheel rev supported 11:58:40.932 -> Crank rev supported 11:58:41.119 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.119 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:58:41.119 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.119 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:58:41.119 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.119 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 11:58:41.164 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 11:58:41.164 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance

:02:21.226 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 12:02:21.226 -> ----------------- Version 02.8 ------------------ 12:02:21.226 -> Initialise the Bluefruit nRF52 module: Client (Central) 12:02:21.435 -> FTMS and Chars 'initialized' 12:02:21.435 -> CPS and Chars 'initialized' 12:02:21.435 -> CSCS and Chars 'initialized' 12:02:21.435 -> GA and Chars 'initialized' 12:02:21.435 -> DIS and Chars 'initialized' 12:02:21.435 -> Start Scanning for CPS, CSC and FTMS! 12:02:21.435 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 12:02:21.435 -> Timestamp MAC Address Rssi Data 12:02:21.435 -> 000001359 F8:9C:FC:53:5E:49 -54 09-02-16-18-26-18-18-18-0A-18 12:02:21.440 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 12:02:21.440 -> Now checking all Client Services and Characteristics! 12:02:21.440 -> If Mandatory Services Fail --> the Client will disconnect! 12:02:21.468 -> First checking Generic Access and Device Information Services and Characteristics! 12:02:21.604 -> Found Client Generic Access 12:02:21.959 -> -> Client Reads Device Name: [Zwift Hub] 12:02:22.503 -> -> Client Reads Appearance: [1152] 12:02:22.831 -> Found Client Device Information 12:02:23.268 -> -> Client Reads Manufacturer: [Zwift] 12:02:24.091 -> -> Client Reads Serial Number: [06-F89CFC535E49] 12:02:24.296 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 12:02:24.574 -> Discovering Client FTM Feature Characteristic ... Found it! 12:02:24.716 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 12:02:24.946 -> Discovering Client FTM Control Point Characteristic ... Not Found! 12:02:24.946 -> Disconnecting since Client FTM Control Point Characteristic is mandatory! 12:02:24.993 -> Client Disconnected, reason = 0x16 12:02:24.993 -> >>> Restart the Feather nRF52 Client for a new run! <<< 12:02:26.206 -> Stopped! 12:02:46.062 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 12:02:46.062 -> ----------------- Version 02.8 ------------------ 12:02:46.062 -> Initialise the Bluefruit nRF52 module: Client (Central) 12:02:46.062 -> FTMS and Chars 'initialized' 12:02:46.062 -> CPS and Chars 'initialized' 12:02:46.062 -> CSCS and Chars 'initialized' 12:02:46.062 -> GA and Chars 'initialized' 12:02:46.062 -> DIS and Chars 'initialized' 12:02:46.062 -> Start Scanning for CPS, CSC and FTMS! 12:02:46.478 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 12:02:46.478 -> Timestamp MAC Address Rssi Data 12:02:46.478 -> 000001488 F8:9C:FC:53:5E:49 -52 09-02-16-18-26-18-18-18-0A-18 12:02:46.500 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 12:02:46.500 -> Now checking all Client Services and Characteristics! 12:02:46.500 -> If Mandatory Services Fail --> the Client will disconnect! 12:02:46.500 -> First checking Generic Access and Device Information Services and Characteristics! 12:02:46.592 -> Found Client Generic Access 12:02:46.964 -> -> Client Reads Device Name: [Zwift Hub] 12:02:47.320 -> -> Client Reads Appearance: [1152] 12:02:47.583 -> Found Client Device Information 12:02:47.880 -> -> Client Reads Manufacturer: [Zwift] 12:02:48.252 -> -> Client Reads Model Number: [06] 12:02:48.655 -> -> Client Reads Serial Number: [06-F89CFC535E49] 12:02:48.842 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 12:02:49.124 -> Discovering Client FTM Feature Characteristic ... Found it! 12:02:49.340 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 12:02:49.560 -> Discovering Client FTM Control Point Characteristic ... Found it! 12:02:50.137 -> Discovering Client FTM Status Characteristic ... Found it! 12:02:50.586 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 12:02:50.977 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 12:02:51.020 -> Found it! 12:02:51.020 -> Ready to receive Client FTM Control Point Response Messages 12:02:51.066 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 12:02:51.252 -> Ready to receive Client FTM Status values 12:02:51.252 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 12:02:51.518 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 12:02:51.920 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 12:02:52.156 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 12:02:52.620 -> Discovering Client CP Measurement characteristic ... Found it! 12:02:52.979 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 12:02:53.119 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 12:02:53.165 -> Discovering Client CP Feature characteristic ... Ready to receive Client FTM Indoor Bike Data values 12:02:53.229 -> Found it! 12:02:53.229 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 12:02:53.229 -> Wheel revolution data supported 12:02:53.229 -> Crank revolution data supported 12:02:53.229 -> Ready to receive Client CP Measurement values 12:02:53.514 -> Discovering Client CP Sensor Location characteristic ... Found it! 12:02:53.607 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 12:02:53.918 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 12:02:54.540 -> Discovering Client CSC Measurement CHR ... Found it! 12:02:54.898 -> Discover

le-joebar commented 1 year ago

Jörghen,

I took the FTMS_BRIDGE_V023 and added the delay as in the FTMS Client.

Here is the result :

The Cyclist moves correctly and power and cadence are correct.

I can't turn on the cardio frequency meter otherwise everything crashes!! 20221217_151846

20221217_152053

5:18:07.676 -> First checking Generic Access and Device Information Services and Characteristics! 15:18:07.676 -> Found Client Generic Access 15:18:07.697 -> -> Client Reads Device Name: [Zwift Hub] 15:18:07.860 -> -> Client Reads Appearance: [1152] 15:18:08.067 -> Found Client Device Information 15:18:08.697 -> -> Client Reads Manufacturer: [Zwift] 15:18:09.116 -> -> Client Reads Model Number: [06] 15:18:09.474 -> -> Client Reads Serial Number: [06-F89CFC535E49] 15:18:09.657 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 15:18:09.967 -> Discovering Client FTM Feature Characteristic ... Found it! 15:18:10.154 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 15:18:10.340 -> Discovering Client FTM Control Point Characteristic ... Found it! 15:18:10.947 -> Discovering Client FTM Status Characteristic ... Found it! 15:18:11.442 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 15:18:12.155 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 15:18:12.247 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 15:18:12.463 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 15:18:12.727 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 15:18:12.942 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 15:18:13.516 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 15:18:13.780 -> Discovering Client CP Measurement characteristic ... Found it! 15:18:14.197 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 15:18:14.570 -> Discovering Client CP Feature characteristic ... Found it! 15:18:14.723 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 15:18:14.723 -> Wheel revolution data supported 15:18:14.723 -> Crank revolution data supported 15:18:14.908 -> Discovering Client CP Sensor Location characteristic ... Found it! 15:18:15.186 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 15:18:15.372 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 15:18:15.635 -> Discovering Client CSC Measurement CHR ... Found it! 15:18:15.977 -> Discovering Client CSC Location CHR ... Found it! 15:18:16.133 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 15:18:16.335 -> Discovering Client CSC Feature CHR ... Found it! 15:18:16.519 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 15:18:16.519 -> Wheel rev supported 15:18:16.519 -> Crank rev supported 15:18:16.705 -> Configuring the Server Device Information Service 15:18:16.705 -> Configuring the Server Cycle Power Service 15:18:16.705 -> Configuring the Server Cadence and Speed Service 15:18:16.705 -> Configuring the Server Fitness Machine Service 15:18:16.705 -> Configuring the Server NUS Service 15:18:16.705 -> Setting up the Server-side advertising payload(s) 15:18:16.705 -> Setting Server Device Name to: [Sim Zwift] 15:18:16.705 -> Setting Server Appearance to: [1152] 15:18:16.705 -> Server-side is CPS, CSC and FTMS advertising! 15:18:17.278 -> Feather nRF52 (Peripheral) connected to Central device: [DESKTOP-1CC9OQN] MAC Address: 58:11:22:53:52:18 15:18:17.278 -> Ready to receive Client FTM Control Point Response Messages 15:18:17.278 -> Ready to receive Client FTM Status values 15:18:17.278 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 15:18:17.401 -> Ready to receive Client FTM Indoor Bike Data values 15:18:17.434 -> Ready to receive Client CP Measurement values 15:18:17.434 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 15:18:17.527 -> >>> Couldn't enable notify for Client CSC Measurement Characteristic. 15:18:17.527 -> Waiting for Central (Zwift) to set CCCD Notify/Indicate (enable) and start.... 15:18:22.114 -> Client- and Server-side are Up and Running! 15:18:22.469 -> Central Device Updated CCCD to: [1] --> Server CP: Measurement 'Notify' enabled 15:18:22.940 -> Central Device Updated CCCD to: [1] --> Server CSC: Measurement 'Notify' enabled 15:18:23.568 -> Central Device Updated CCCD to: [1] --> Server FTM: IndoorBikeData 'Notify' enabled 15:18:24.361 -> Central Device Updated CCCD to: [1] --> Server FTM: Status 'Notify' enabled 15:19:30.101 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 B2 FF 28 33 00 ] 15:19:30.101 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.78 | Crr (10000): 0.00 | Cw (100): 0.51 15:19:30.271 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 15:19:30.271 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B2 FF 28 33 ] 15:19:39.262 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 00 00 28 33 00 ] 15:19:39.262 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.00 | Crr (10000): 0.00 | Cw (100): 0.51 15:19:39.354 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 15:19:39.354 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ]

Berg0162 commented 1 year ago

Dear Joel,

I took the FTMS_BRIDGE_V023 and added the delay as in the FTMS Client.

Well done! And....very good result.....

I can't turn on the cardio frequency meter otherwise everything crashes!!

That sounds dramatic.... However, I was just a little bit googling and ended up with a popular friend DCRainmaker:

->Protocol Compatibility: ANT+ FE-C, ANT+ Power, Bluetooth Smart Trainer Control, Bluetooth Smart Power (everything you need) –>Unique Party Trick: Can rebroadcast your heart rate sensor within a single channel, ideal for Apple TV Zwift users (who are Bluetooth channel limited)

Additionally, it’s here you can do heart rate bridging/pairing. This allows you to pair your chest strap with the Zwift Hub, and then get pass-through heart rate, so that the trainer handles the HR connection to the app on behalf of your strap. The main/singular reason you’d want to do this is for Apple TV usage of Zwift or other apps. That’s because Apple TV has a two concurrent connection limit (plus the remote). So if you wanted to do steering in Zwift, then this wouldn’t be possible since you’d have one connection for the trainer, and then one for your heart rate sensor (leaving none for steering).

But with HR bridging, the heart rate sensor data gets funneled in the same ‘channel’ as the trainer data, so it only counts as one channel – not two. You can simply search for your HR strap in this menu and then pair to it.

The question is: What is your setup? What settings do you use in the Zwift Hub Companion App with respect to HBM?

Now, before we start riding, we should double-check the Zwift app for any firmware updates. This is done via the Zwift Companion App (which is the smartphone one). You’ll see a new option for Zwift hardware, and you can check/update it there..

The bottom line is: Should the Simcline FTMS code in the end allocate Apple TV users that buy a Zwift Hub and expect HBM to be rebroadcasted? Notice that this feature is NOT FTMS standard but an extra goodie of the Zwift company!

Berg0162 commented 1 year ago

Dear Joel, Did you spent any time on fine tuning the SOME_TIME in the FTMS_Client latest version? Before we are spending time on other parts we have to get this delay function to be optimized (for Zwift Hub specifically) and that is something I can't do, not having a Zwift Hub at hand... so I am relying on you. Regards, Jörgen.

le-joebar commented 1 year ago

Hello Jorghen,

Yes I tested several different delays from 200 to 300 ms I put the different ones for you results but for me 250 ms is the best at 200 I don't always have the same results at 250 it's perfect!

The cardio frequency meter problem is solved, I had disconnected it from the trainer with Zwift Compagion.

I put it back and now it's ok

20221219_162330

300 ms

16:55:20.353 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:55:20.353 -> ----------------- Version 02.8 ------------------ 16:55:20.353 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:55:20.353 -> FTMS and Chars 'initialized' 16:55:20.353 -> CPS and Chars 'initialized' 16:55:20.353 -> CSCS and Chars 'initialized' 16:55:20.353 -> GA and Chars 'initialized' 16:55:20.353 -> DIS and Chars 'initialized' 16:55:20.353 -> Start Scanning for CPS, CSC and FTMS! 16:55:20.354 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:55:20.354 -> Timestamp MAC Address Rssi Data 16:55:20.354 -> 000001217 F8:9C:FC:53:5E:49 -57 09-02-16-18-26-18-18-18-0A-18 16:55:20.354 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address:F8:9C:FC:53:5E:49 16:55:20.354 -> Now checking all Client Services and Characteristics! 16:55:20.354 -> If Mandatory Services Fail --> the Client will disconnect! 16:55:20.380 -> First checking Generic Access and Device Information Services and Characteristics! 16:55:20.380 -> Found Client Generic Access 16:55:20.381 -> -> Client Reads Device Name: [Zwift Hub] 16:55:20.720 -> -> Client Reads Appearance: [1152] 16:55:21.076 -> Found Client Device Information 16:55:21.463 -> -> Client Reads Manufacturer: [Zwift] 16:55:21.818 -> -> Client Reads Model Number: [06] 16:55:22.220 -> -> Client Reads Serial Number: [06-F89CFC535E49] 16:55:22.527 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 16:55:22.881 -> Discovering Client FTM Feature Characteristic ... Found it! 16:55:22.958 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 16:55:23.264 -> Discovering Client FTM Control Point Characteristic ... Found it! 16:55:23.709 -> Discovering Client FTM Status Characteristic ... Found it! 16:55:24.109 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 16:55:24.519 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 16:55:24.558 -> Found it! 16:55:24.558 -> Ready to receive Client FTM Control Point Response Messages 16:55:24.604 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 16:55:24.880 -> Ready to receive Client FTM Status values 16:55:24.880 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 16:55:25.050 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 16:55:25.448 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 16:55:25.773 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 16:55:26.177 -> Discovering Client CP Measurement characteristic ... Found it! 16:55:26.640 -> Discovering Client CP Control Point characteristic ... >>> Couldn't enable notify for Client FTM Training Status Characteristic. 16:55:26.686 -> Not Found! NOT Mandatory! 16:55:26.765 -> Ready to receive Client FTM Indoor Bike Data values 16:55:26.765 -> Ready to receive Client CP Measurement values 16:55:27.089 -> Discovering Client CP Feature characteristic ... Found it! 16:55:27.089 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 16:55:27.089 -> Wheel revolution data supported 16:55:27.089 -> Crank revolution data supported 16:55:27.433 -> Discovering Client CP Sensor Location characteristic ... Found it! 16:55:27.479 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 16:55:27.820 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 16:55:28.277 -> Discovering Client CSC Measurement CHR ... Found it! 16:55:28.629 -> Discovering Client CSC Location CHR ... Found it! 16:55:28.629 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 16:55:28.769 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 16:55:28.769 -> Ready to receive Client CSC Measurement values 16:55:28.769 -> Client (Central) is Up and Running! 16:55:28.940 -> Discovering Client CSC Feature CHR ... Found it! 16:55:29.034 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 16:55:29.034 -> Wheel rev supported 16:55:29.034 -> Crank rev supported 16:55:29.342 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 16:55:29.342 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM

250 ms

16:51:06.619 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 16:51:06.619 -> ----------------- Version 02.8 ------------------ 16:51:06.619 -> Initialise the Bluefruit nRF52 module: Client (Central) 16:51:06.619 -> FTMS and Chars 'initialized' 16:51:06.619 -> CPS and Chars 'initialized' 16:51:06.619 -> CSCS and Chars 'initialized' 16:51:06.619 -> GA and Chars 'initialized' 16:51:06.619 -> DIS and Chars 'initialized' 16:51:06.619 -> Start Scanning for CPS, CSC and FTMS! 16:51:06.619 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 16:51:06.619 -> Timestamp MAC Address Rssi Data 16:51:06.619 -> 000001406 F8:9C:FC:53:5E:49 -56 09-02-16-18-26-18-18-18-0A-18 16:51:06.619 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 16:51:06.619 -> Now checking all Client Services and Characteristics! 16:51:06.619 -> If Mandatory Services Fail --> the Client will disconnect! 16:51:06.619 -> First checking Generic Access and Device Information Services and Characteristics! 16:51:06.620 -> Found Client Generic Access 16:51:06.629 -> -> Client Reads Device Name: [Zwift Hub] 16:51:06.891 -> -> Client Reads Appearance: [1152] 16:51:07.186 -> Found Client Device Information 16:51:07.498 -> -> Client Reads Manufacturer: [Zwift] 16:51:07.855 -> -> Client Reads Model Number: [06] 16:51:08.176 -> -> Client Reads Serial Number: [06-F89CFC535E49] 16:51:08.407 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 16:51:08.702 -> Discovering Client FTM Feature Characteristic ... Found it! 16:51:08.791 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 16:51:09.053 -> Discovering Client FTM Control Point Characteristic ... Found it! 16:51:09.395 -> Discovering Client FTM Status Characteristic ... Found it! 16:51:09.802 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 16:51:10.176 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 16:51:10.254 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 16:51:10.475 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 16:51:10.630 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 16:51:10.897 -> Discovering Client FTM Indoor Bike Data Characteristic ... Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 16:51:10.897 -> Ready to receive Client FTM Control Point Response Messages 16:51:10.897 -> Found it! 16:51:11.177 -> Ready to receive Client FTM Status values 16:51:11.177 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 16:51:11.537 -> Discovering Client CP Measurement characteristic ... Found it! 16:51:11.896 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 16:51:12.256 -> Discovering Client CP Feature characteristic ... Found it! 16:51:12.256 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 16:51:12.256 -> Wheel revolution data supported 16:51:12.256 -> Crank revolution data supported 16:51:12.565 -> Discovering Client CP Sensor Location characteristic ... Found it! 16:51:12.581 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 16:51:12.903 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 16:51:12.937 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 16:51:13.108 -> Ready to receive Client FTM Indoor Bike Data values 16:51:13.108 -> Ready to receive Client CP Measurement values 16:51:13.294 -> Discovering Client CSC Measurement CHR ... Found it! 16:51:13.635 -> Discovering Client CSC Location CHR ... Found it! 16:51:13.635 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 16:51:13.959 -> Discovering Client CSC Feature CHR ... Found it! 16:51:13.959 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 16:51:13.959 -> Wheel rev supported 16:51:13.959 -> Crank rev supported 16:51:14.192 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 16:51:14.192 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM 16:51:14.192 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ]

200 ms

17:14:15.007 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:14:15.007 -> ----------------- Version 02.8 ------------------ 17:14:15.007 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:14:15.422 -> FTMS and Chars 'initialized' 17:14:15.422 -> CPS and Chars 'initialized' 17:14:15.422 -> CSCS and Chars 'initialized' 17:14:15.422 -> GA and Chars 'initialized' 17:14:15.422 -> DIS and Chars 'initialized' 17:14:15.422 -> Start Scanning for CPS, CSC and FTMS! 17:14:15.422 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:14:15.422 -> Timestamp MAC Address Rssi Data 17:14:15.422 -> 000000633 F8:9C:FC:53:5E:49 -55 09-02-16-18-26-18-18-18-0A-18 17:14:15.422 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:14:15.422 -> Now checking all Client Services and Characteristics! 17:14:15.422 -> If Mandatory Services Fail --> the Client will disconnect! 17:14:15.422 -> First checking Generic Access and Device Information Services and Characteristics! 17:14:15.432 -> Found Client Generic Access 17:14:16.068 -> -> Client Reads Device Name: [Zwift Hub] 17:14:16.074 -> -> Client Reads Appearance: [0] 17:14:16.137 -> Found Client Device Information 17:14:16.494 -> -> Client Reads Manufacturer: [Zwift] 17:14:16.833 -> -> Client Reads Model Number: [06] 17:14:17.190 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:14:17.378 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:14:17.675 -> Discovering Client FTM Feature Characteristic ... Found it! 17:14:17.892 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 17:14:18.064 -> Discovering Client FTM Control Point Characteristic ... Found it! 17:14:18.467 -> Discovering Client FTM Status Characteristic ... Found it! 17:14:18.928 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 17:14:19.473 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 17:14:19.566 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 17:14:19.721 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 17:14:19.767 -> Ready to receive Client FTM Control Point Response Messages 17:14:19.767 -> Discovering Client FTM Supported Power Range Characteristic ... >>> Couldn't enable notify for Client FTM Status Characteristic. 17:14:19.845 -> FTMS (trainer) is controlled by another Client (Training App)! 17:14:19.845 -> Client (Central) is Up and Running! 17:14:19.969 -> Not Found! NOT mandatory! 17:14:20.173 -> Discovering Client FTM Indoor Bike Data Characteristic ... Not Found! Not Mandatory 17:14:20.344 -> Discovering Client Cycling Power (CP) Service ... Not Found! 17:14:20.344 -> Disconnecting since Client Cyling Power Service is mandatory! 17:14:20.344 -> Client Disconnected, reason = 0x16 17:14:20.344 -> >>> Restart the Feather nRF52 Client for a new run! <<<

200 ms

17:15:00.572 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 17:15:00.572 -> ----------------- Version 02.8 ------------------ 17:15:00.572 -> Initialise the Bluefruit nRF52 module: Client (Central) 17:15:00.572 -> FTMS and Chars 'initialized' 17:15:00.572 -> CPS and Chars 'initialized' 17:15:00.572 -> CSCS and Chars 'initialized' 17:15:00.572 -> GA and Chars 'initialized' 17:15:00.572 -> DIS and Chars 'initialized' 17:15:00.572 -> Start Scanning for CPS, CSC and FTMS! 17:15:00.572 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 17:15:00.572 -> Timestamp MAC Address Rssi Data 17:15:00.572 -> 000001199 F8:9C:FC:53:5E:49 -55 09-02-16-18-26-18-18-18-0A-18 17:15:00.595 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:15:00.595 -> Now checking all Client Services and Characteristics! 17:15:00.595 -> If Mandatory Services Fail --> the Client will disconnect! 17:15:00.595 -> First checking Generic Access and Device Information Services and Characteristics! 17:15:00.595 -> Found Client Generic Access 17:15:00.690 -> -> Client Reads Device Name: [Zwift Hub] 17:15:01.141 -> -> Client Reads Appearance: [1152] 17:15:01.422 -> Found Client Device Information 17:15:01.890 -> -> Client Reads Manufacturer: [Zwift] 17:15:02.356 -> -> Client Reads Model Number: [06] 17:15:02.682 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:15:02.899 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:15:03.349 -> Discovering Client FTM Feature Characteristic ... Found it! 17:15:03.489 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 17:15:03.690 -> Discovering Client FTM Control Point Characteristic ... Found it! 17:15:04.158 -> Discovering Client FTM Status Characteristic ... Found it! 17:15:04.763 -> Discovering Client FTM Training Status Characteristic ... Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 17:15:05.073 -> Not Found! Not Mandatory 17:15:05.198 -> Ready to receive Client FTM Control Point Response Messages 17:15:05.198 -> Ready to receive Client FTM Status values 17:15:05.276 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 17:15:05.461 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 17:15:05.677 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 17:15:05.971 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 17:15:06.519 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 17:15:06.862 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 17:15:07.173 -> Discovering Client CP Measurement characteristic ... >>> Couldn't enable notify for Client FTM Training Status Characteristic. 17:15:07.220 -> Found it! 17:15:07.312 -> Ready to receive Client FTM Indoor Bike Data values 17:15:07.312 -> Ready to receive Client CP Measurement values 17:15:07.544 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 17:15:07.918 -> Discovering Client CP Feature characteristic ... Found it! 17:15:07.918 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 17:15:07.918 -> Wheel revolution data supported 17:15:07.918 -> Crank revolution data supported 17:15:08.199 -> Discovering Client CP Sensor Location characteristic ... Found it! 17:15:08.324 -> -> Client Reads CP Location Sensor: Loc#: 0 Other 17:15:08.513 -> Discovering Cycling Speed and Cadence (CSC) Service ... Not Found! CSC Service is Not Mandatory! 17:15:08.513 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 00 00 00 00 14 00 00 00 00 ] 17:15:08.513 -> Instant. Speed: 0 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 0 Watt Heart Rate: 0 HBM

Berg0162 commented 1 year ago

Dear Joel, It looks like the Zwift Hub needs a 250 ms delay, indeed! This is surprisingly long, I know trainers that need a delay of 0.0 seconds to work perfectly....time after time! I have done some additional testing and changed the code in such a way that: 1) I have slightly changed the pattern of the delay calls in client connect, now there are 24 calls: delaying about 6 seconds.... 2) I have included the forced delay time elsewhere --> cluttering of the output is now minimized (I hope) 3) I have included code for decoding the FTM Feature Version 029 has been uploaded and you are invited to give it a try again with the Zwift Hub trainer! Best wishes, Jörgen

le-joebar commented 1 year ago

Hello Jorghen,

The HRM is connected but the value is not transmitted with each request! I don't know if it's serious?

Here are the results of FTMS_0.29 :

14:46:22.160 -> Feather nRF52 Client/Central: CPS, CSC and FTMS 14:46:22.160 -> ----------------- Version 02.9 ------------------ 14:46:22.160 -> Processor: Feather nRF52840 14:46:22.160 -> Initialise the Bluefruit nRF52 module: Client (Central) 14:46:22.161 -> FTMS and Chars 'initialized' 14:46:22.161 -> CPS and Chars 'initialized' 14:46:22.161 -> CSCS and Chars 'initialized' 14:46:22.161 -> GA and Chars 'initialized' 14:46:22.161 -> DIS and Chars 'initialized' 14:46:22.161 -> Start Scanning for CPS, CSC and FTMS! 14:46:22.161 -> Found advertising Peripheral with FTMS service!, see the Raw Data packet: 14:46:22.161 -> Timestamp MAC Address Rssi Data 14:46:22.161 -> 000001328 F8:9C:FC:53:5E:49 -59 09-02-16-18-26-18-18-18-0A-18 14:46:22.161 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 14:46:22.161 -> Now checking all Client Services and Characteristics! 14:46:22.161 -> If Mandatory Services Fail --> the Client will disconnect! 14:46:22.161 -> First checking Generic Access and Device Information Services and Characteristics! 14:46:22.183 -> Found Client Generic Access 14:46:22.183 -> -> Client Reads Device Name: [Zwift Hub] 14:46:22.524 -> -> Client Reads Appearance: [1152] 14:46:22.533 -> Found Client Device Information 14:46:22.832 -> -> Client Reads Manufacturer: [Zwift] 14:46:23.252 -> -> Client Reads Model Number: [06] 14:46:23.575 -> -> Client Reads Serial Number: [06-F89CFC535E49] 14:46:23.808 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 14:46:24.105 -> Discovering Client FTM Feature Characteristic ... Found it! 14:46:24.182 -> -> Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 14:46:24.182 -> - Fitness Machine Features: 14:46:24.182 -> Average Speed Supported 14:46:24.182 -> Cadence Supported 14:46:24.182 -> Total Distance Supported 14:46:24.182 -> Resistance Level Supported 14:46:24.182 -> Heart Rate Measurement Supported 14:46:24.182 -> Power Measurement Supported 14:46:24.182 -> - Target Setting Features: 14:46:24.182 -> Resistance Target Setting Supported 14:46:24.182 -> Power Target Setting Supported 14:46:24.182 -> Indoor Bike Simulation Parameters Supported 14:46:24.182 -> Wheel Circumference Configuration Supported 14:46:24.182 -> Spin Down Control Supported 14:46:24.431 -> Discovering Client FTM Control Point Characteristic ... Found it! 14:46:24.788 -> Discovering Client FTM Status Characteristic ... Found it! 14:46:25.162 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 14:46:25.566 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 14:46:25.660 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 14:46:25.926 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 14:46:26.051 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 14:46:26.302 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 14:46:26.616 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 14:46:26.895 -> Discovering Client CP Measurement characteristic ... Found it! 14:46:27.206 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 14:46:27.560 -> Discovering Client CP Feature characteristic ... Found it! 14:46:27.636 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 14:46:27.636 -> Wheel revolution data supported 14:46:27.636 -> Crank revolution data supported 14:46:27.868 -> Discovering Client CP Sensor Location characteristic ... Found it! 14:46:27.959 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 14:46:28.204 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 14:46:28.530 -> Discovering Client CSC Measurement CHR ... Found it! 14:46:28.853 -> Discovering Client CSC Location CHR ... Found it! 14:46:28.885 -> -> Client Reads CSC Location Sensor: Loc#: 12 Rear wheel 14:46:29.158 -> Discovering Client CSC Feature CHR ... Found it! 14:46:29.272 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 14:46:29.272 -> Wheel rev supported 14:46:29.272 -> Crank rev supported 14:46:29.781 -> Enable Notify/Indicate of relevant Peripheral (Trainer) Characteristics 14:46:29.859 -> Ready to receive Client FTM Control Point Response Messages 14:46:29.859 -> Ready to receive Client FTM Status values 14:46:31.836 -> >>> Couldn't enable notify for Client FTM Training Status Characteristic. 14:46:31.975 -> Ready to receive Client FTM Indoor Bike Data values 14:46:31.975 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 E5 08 00 00 14 00 7D 00 00 ] 14:46:31.975 -> Instant. Speed: 22 KPH Instantaneous Cadence: 0 RPM Resistance Level: 20 Instantaneous Power: 125 Watt Heart Rate: 0 HBM 14:46:32.976 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 38 09 4C 00 14 00 78 00 00 ] 14:46:32.976 -> Instant. Speed: 23 KPH Instantaneous Cadence: 38 RPM Resistance Level: 20 Instantaneous Power: 120 Watt Heart Rate: 0 HBM 14:46:33.839 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 14:46:33.932 -> Ready to receive Client CP Measurement values 14:46:33.932 -> Ready to receive Client CSC Measurement values 14:46:33.978 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 67 09 70 00 14 00 79 00 00 ] 14:46:33.978 -> Instant. Speed: 24 KPH Instantaneous Cadence: 56 RPM Resistance Level: 20 Instantaneous Power: 121 Watt Heart Rate: 0 HBM 14:46:34.983 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 A7 09 7E 00 14 00 97 00 00 ] 14:46:34.983 -> Instant. Speed: 24 KPH Instantaneous Cadence: 63 RPM Resistance Level: 20 Instantaneous Power: 151 Watt Heart Rate: 0 HBM 14:46:35.938 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 14:46:35.970 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 CD 09 86 00 14 00 83 00 00 ] 14:46:35.970 -> Instant. Speed: 25 KPH Instantaneous Cadence: 67 RPM Resistance Level: 20 Instantaneous Power: 131 Watt Heart Rate: 0 HBM 14:46:35.970 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 14:46:36.973 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 A9 09 8A 00 14 00 84 00 00 ] 14:46:36.973 -> Instant. Speed: 24 KPH Instantaneous Cadence: 69 RPM Resistance Level: 20 Instantaneous Power: 132 Watt Heart Rate: 0 HBM 14:46:37.978 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 B9 09 8E 00 14 00 84 00 00 ] 14:46:37.978 -> Instant. Speed: 24 KPH Instantaneous Cadence: 71 RPM Resistance Level: 20 Instantaneous Power: 132 Watt Heart Rate: 0 HBM 14:46:37.978 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 00 00 00 00 00 00 00 00 ] 14:46:38.009 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 00 01 ] 14:46:38.965 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 CB 09 8E 00 14 00 75 00 4F ] 14:46:38.965 -> Instant. Speed: 25 KPH Instantaneous Cadence: 71 RPM Resistance Level: 20 Instantaneous Power: 117 Watt Heart Rate: 79 HBM 14:46:39.978 -> -> Client Rec'd Raw FTM Indoor Bike Data: [11] [ 64 02 71 09 8E 00 14 00 77 00 00 ] 14:46:39.978 -> Instant. Speed: 24 KPH Instantaneous Cadence: 71 RPM Resistance Level: 20 Instantaneous Power: 119 Watt Heart Rate: 0 HBM 14:46:40.017 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 07 00 00 00 00 00 00 00 ] 14:46:40.141 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 07 01 ] 14:46:40.141 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 14:46:40.975 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5F 09 81 08 8C 00 8C 00 06 00 00 14 00 76 00 76 00 00 ] 14:46:40.975 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 70 RPM Average Cadence: 70 RPM Total Distance: 6 m Resistance Level: 20 Instantaneous Power: 118 Watt Average Power: 118 Watt Heart Rate: 0 HBM 14:46:42.040 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 74 09 81 08 8E 00 8D 00 0C 00 00 14 00 74 00 75 00 00 ] 14:46:42.040 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 71 RPM Average Cadence: 70 RPM Total Distance: 12 m Resistance Level: 20 Instantaneous Power: 116 Watt Average Power: 117 Watt Heart Rate: 0 HBM 14:46:42.118 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 01 28 33 00 ] 14:46:42.395 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:42.395 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 01 28 33 ] 14:46:43.042 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 49 09 81 08 8A 00 8C 00 12 00 00 14 00 73 00 74 00 00 ] 14:46:43.042 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 69 RPM Average Cadence: 70 RPM Total Distance: 18 m Resistance Level: 20 Instantaneous Power: 115 Watt Average Power: 116 Watt Heart Rate: 0 HBM 14:46:44.030 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 03 09 81 08 8A 00 8B 00 18 00 00 14 00 7F 00 77 00 00 ] 14:46:44.030 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 69 RPM Average Cadence: 69 RPM Total Distance: 24 m Resistance Level: 20 Instantaneous Power: 127 Watt Average Power: 119 Watt Heart Rate: 0 HBM 14:46:44.217 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 09 00 28 33 00 ] 14:46:44.387 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:44.387 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 14:46:45.022 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 5E 09 81 08 88 00 8A 00 1E 00 00 14 00 87 00 7A 00 00 ] 14:46:45.023 -> Instant. Speed: 23 KPH Average Speed: 21 KPH Instantaneous Cadence: 68 RPM Average Cadence: 69 RPM Total Distance: 30 m Resistance Level: 20 Instantaneous Power: 135 Watt Average Power: 122 Watt Heart Rate: 0 HBM 14:46:45.997 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B7 09 81 08 88 00 8A 00 24 00 00 14 00 9F 00 80 00 56 ] 14:46:45.997 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 68 RPM Average Cadence: 69 RPM Total Distance: 36 m Resistance Level: 20 Instantaneous Power: 159 Watt Average Power: 128 Watt Heart Rate: 86 HBM 14:46:46.308 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 14:46:46.448 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:46.448 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 14:46:47.003 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 79 09 81 08 88 00 8A 00 2A 00 00 14 00 8B 00 81 00 00 ] 14:46:47.003 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 68 RPM Average Cadence: 69 RPM Total Distance: 42 m Resistance Level: 20 Instantaneous Power: 139 Watt Average Power: 129 Watt Heart Rate: 0 HBM 14:46:47.991 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A7 09 81 08 8A 00 8A 00 30 00 00 14 00 73 00 80 00 00 ] 14:46:47.991 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 69 RPM Average Cadence: 69 RPM Total Distance: 48 m Resistance Level: 20 Instantaneous Power: 115 Watt Average Power: 128 Watt Heart Rate: 0 HBM 14:46:48.411 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 14 00 28 33 00 ] 14:46:48.503 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:48.503 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 14 00 28 33 ] 14:46:48.983 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B1 09 81 08 8C 00 8A 00 36 00 00 14 00 64 00 7C 00 00 ] 14:46:48.983 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 70 RPM Average Cadence: 69 RPM Total Distance: 54 m Resistance Level: 20 Instantaneous Power: 100 Watt Average Power: 124 Watt Heart Rate: 0 HBM 14:46:49.953 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 91 09 81 08 8C 00 8A 00 3C 00 00 14 00 66 00 7A 00 00 ] 14:46:49.953 -> Instant. Speed: 24 KPH Average Speed: 21 KPH Instantaneous Cadence: 70 RPM Average Cadence: 69 RPM Total Distance: 60 m Resistance Level: 20 Instantaneous Power: 102 Watt Average Power: 122 Watt Heart Rate: 0 HBM 14:46:50.511 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 22 00 28 33 00 ] 14:46:50.867 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:50.867 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 22 00 28 33 ] 14:46:51.131 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 FA 09 A2 08 8E 00 8A 00 43 00 00 14 00 5C 00 77 00 00 ] 14:46:51.131 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 71 RPM Average Cadence: 69 RPM Total Distance: 67 m Resistance Level: 20 Instantaneous Power: 92 Watt Average Power: 119 Watt Heart Rate: 0 HBM 14:46:52.042 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 C9 09 9F 08 90 00 8B 00 49 00 00 14 00 63 00 76 00 00 ] 14:46:52.042 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 72 RPM Average Cadence: 69 RPM Total Distance: 73 m Resistance Level: 20 Instantaneous Power: 99 Watt Average Power: 118 Watt Heart Rate: 0 HBM 14:46:52.597 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 25 00 28 33 00 ] 14:46:52.751 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:52.751 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 25 00 28 33 ] 14:46:53.028 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B3 09 9D 08 90 00 8B 00 4F 00 00 14 00 5D 00 74 00 00 ] 14:46:53.028 -> Instant. Speed: 24 KPH Average Speed: 22 KPH Instantaneous Cadence: 72 RPM Average Cadence: 69 RPM Total Distance: 79 m Resistance Level: 20 Instantaneous Power: 93 Watt Average Power: 116 Watt Heart Rate: 0 HBM 14:46:54.015 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B9 09 9B 08 92 00 8C 00 55 00 00 14 00 55 00 71 00 00 ] 14:46:54.015 -> Instant. Speed: 24 KPH Average Speed: 22 KPH Instantaneous Cadence: 73 RPM Average Cadence: 70 RPM Total Distance: 85 m Resistance Level: 20 Instantaneous Power: 85 Watt Average Power: 113 Watt Heart Rate: 0 HBM 14:46:54.709 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 23 00 28 33 00 ] 14:46:54.833 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:54.833 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 14:46:55.003 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 AF 09 99 08 94 00 8C 00 5B 00 00 14 00 8F 00 73 00 00 ] 14:46:55.003 -> Instant. Speed: 24 KPH Average Speed: 22 KPH Instantaneous Cadence: 74 RPM Average Cadence: 70 RPM Total Distance: 91 m Resistance Level: 20 Instantaneous Power: 143 Watt Average Power: 115 Watt Heart Rate: 0 HBM 14:46:56.070 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 2B 0A AF 08 92 00 8C 00 62 00 00 14 00 50 00 71 00 00 ] 14:46:56.070 -> Instant. Speed: 26 KPH Average Speed: 22 KPH Instantaneous Cadence: 73 RPM Average Cadence: 70 RPM Total Distance: 98 m Resistance Level: 20 Instantaneous Power: 80 Watt Average Power: 113 Watt Heart Rate: 0 HBM 14:46:56.812 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 1C 00 28 33 00 ] 14:46:56.969 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:56.969 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 14:46:56.969 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 F0 09 C1 08 94 00 8D 00 69 00 00 14 00 83 00 72 00 00 ] 14:46:56.969 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 74 RPM Average Cadence: 70 RPM Total Distance: 105 m Resistance Level: 20 Instantaneous Power: 131 Watt Average Power: 114 Watt Heart Rate: 0 HBM 14:46:57.983 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 B5 09 BE 08 94 00 8D 00 6F 00 00 14 00 74 00 72 00 00 ] 14:46:57.983 -> Instant. Speed: 24 KPH Average Speed: 22 KPH Instantaneous Cadence: 74 RPM Average Cadence: 70 RPM Total Distance: 111 m Resistance Level: 20 Instantaneous Power: 116 Watt Average Power: 114 Watt Heart Rate: 0 HBM 14:46:58.909 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 0F 00 28 33 00 ] 14:46:59.063 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A3 09 BA 08 90 00 8D 00 75 00 00 14 00 4E 00 70 00 00 ] 14:46:59.064 -> Instant. Speed: 24 KPH Average Speed: 22 KPH Instantaneous Cadence: 72 RPM Average Cadence: 70 RPM Total Distance: 117 m Resistance Level: 20 Instantaneous Power: 78 Watt Average Power: 112 Watt Heart Rate: 0 HBM 14:46:59.064 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:46:59.064 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 0F 00 28 33 ] 14:47:00.039 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A9 09 B8 08 90 00 8D 00 7B 00 00 14 00 63 00 70 00 00 ] 14:47:00.039 -> Instant. Speed: 24 KPH Average Speed: 22 KPH Instantaneous Cadence: 72 RPM Average Cadence: 70 RPM Total Distance: 123 m Resistance Level: 20 Instantaneous Power: 99 Watt Average Power: 112 Watt Heart Rate: 0 HBM 14:47:01.027 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 00 00 28 33 00 ] 14:47:01.027 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 09 0A C6 08 8E 00 8D 00 82 00 00 14 00 66 00 6F 00 00 ] 14:47:01.027 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 71 RPM Average Cadence: 70 RPM Total Distance: 130 m Resistance Level: 20 Instantaneous Power: 102 Watt Average Power: 111 Watt Heart Rate: 0 HBM 14:47:01.120 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:01.120 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 14:47:02.030 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 DC 09 C3 08 90 00 8E 00 88 00 00 14 00 6B 00 6F 00 00 ] 14:47:02.030 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 72 RPM Average Cadence: 71 RPM Total Distance: 136 m Resistance Level: 20 Instantaneous Power: 107 Watt Average Power: 111 Watt Heart Rate: 0 HBM 14:47:03.021 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E3 09 C0 08 90 00 8E 00 8E 00 00 14 00 63 00 6E 00 00 ] 14:47:03.021 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 72 RPM Average Cadence: 71 RPM Total Distance: 142 m Resistance Level: 20 Instantaneous Power: 99 Watt Average Power: 110 Watt Heart Rate: 0 HBM 14:47:03.085 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 F5 FF 28 33 00 ] 14:47:03.284 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:03.284 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F5 FF 28 33 ] 14:47:04.006 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 09 0A CD 08 92 00 8E 00 95 00 00 14 00 6A 00 6E 00 00 ] 14:47:04.006 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 73 RPM Average Cadence: 71 RPM Total Distance: 149 m Resistance Level: 20 Instantaneous Power: 106 Watt Average Power: 110 Watt Heart Rate: 0 HBM 14:47:04.996 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 FF 09 D8 08 92 00 8E 00 9C 00 00 14 00 67 00 6E 00 00 ] 14:47:04.996 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 73 RPM Average Cadence: 71 RPM Total Distance: 156 m Resistance Level: 20 Instantaneous Power: 103 Watt Average Power: 110 Watt Heart Rate: 0 HBM 14:47:05.214 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 E4 FF 28 33 00 ] 14:47:05.353 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:05.353 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E4 FF 28 33 ] 14:47:05.985 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 2F 0A E3 08 94 00 8E 00 A3 00 00 14 00 62 00 6D 00 61 ] 14:47:05.985 -> Instant. Speed: 26 KPH Average Speed: 22 KPH Instantaneous Cadence: 74 RPM Average Cadence: 71 RPM Total Distance: 163 m Resistance Level: 20 Instantaneous Power: 98 Watt Average Power: 109 Watt Heart Rate: 97 HBM 14:47:06.972 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 EA 09 DF 08 94 00 8E 00 A9 00 00 14 00 68 00 6D 00 61 ] 14:47:06.972 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 74 RPM Average Cadence: 71 RPM Total Distance: 169 m Resistance Level: 20 Instantaneous Power: 104 Watt Average Power: 109 Watt Heart Rate: 97 HBM 14:47:07.312 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 CF FF 28 33 00 ] 14:47:07.512 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:07.512 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 CF FF 28 33 ] 14:47:07.973 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 0A 0A E9 08 92 00 8E 00 B0 00 00 14 00 50 00 6C 00 00 ] 14:47:07.973 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 73 RPM Average Cadence: 71 RPM Total Distance: 176 m Resistance Level: 20 Instantaneous Power: 80 Watt Average Power: 108 Watt Heart Rate: 0 HBM 14:47:09.038 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 F0 09 F2 08 92 00 8F 00 B7 00 00 14 00 47 00 6B 00 00 ] 14:47:09.038 -> Instant. Speed: 25 KPH Average Speed: 22 KPH Instantaneous Cadence: 73 RPM Average Cadence: 71 RPM Total Distance: 183 m Resistance Level: 20 Instantaneous Power: 71 Watt Average Power: 107 Watt Heart Rate: 0 HBM 14:47:09.424 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 A8 FF 28 33 00 ] 14:47:09.549 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:09.594 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 A8 FF 28 33 ] 14:47:10.017 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 76 0A FA 08 94 00 8F 00 BE 00 00 14 00 5B 00 6A 00 00 ] 14:47:10.017 -> Instant. Speed: 26 KPH Average Speed: 22 KPH Instantaneous Cadence: 74 RPM Average Cadence: 71 RPM Total Distance: 190 m Resistance Level: 20 Instantaneous Power: 91 Watt Average Power: 106 Watt Heart Rate: 0 HBM 14:47:11.028 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 3A 0A 02 09 94 00 8F 00 C5 00 00 14 00 58 00 6A 00 00 ] 14:47:11.028 -> Instant. Speed: 26 KPH Average Speed: 23 KPH Instantaneous Cadence: 74 RPM Average Cadence: 71 RPM Total Distance: 197 m Resistance Level: 20 Instantaneous Power: 88 Watt Average Power: 106 Watt Heart Rate: 0 HBM 14:47:11.499 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 84 FF 28 33 00 ] 14:47:11.618 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:11.655 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 FF 28 33 ] 14:47:12.108 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 59 0A 09 09 96 00 8F 00 CC 00 00 14 00 4E 00 69 00 00 ] 14:47:12.108 -> Instant. Speed: 26 KPH Average Speed: 23 KPH Instantaneous Cadence: 75 RPM Average Cadence: 71 RPM Total Distance: 204 m Resistance Level: 20 Instantaneous Power: 78 Watt Average Power: 105 Watt Heart Rate: 0 HBM 14:47:12.996 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 CC 09 05 09 98 00 8F 00 D2 00 00 14 00 1F 00 67 00 00 ] 14:47:12.996 -> Instant. Speed: 25 KPH Average Speed: 23 KPH Instantaneous Cadence: 76 RPM Average Cadence: 71 RPM Total Distance: 210 m Resistance Level: 20 Instantaneous Power: 31 Watt Average Power: 103 Watt Heart Rate: 0 HBM 14:47:13.627 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 67 FF 28 33 00 ] 14:47:13.998 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:13.998 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 FF 28 33 ] 14:47:13.998 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 25 09 01 09 00 00 8B 00 D8 00 00 14 00 00 00 64 00 64 ] 14:47:13.998 -> Instant. Speed: 23 KPH Average Speed: 23 KPH Instantaneous Cadence: 0 RPM Average Cadence: 69 RPM Total Distance: 216 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 100 Watt Heart Rate: 100 HBM 14:47:14.971 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 82 08 FE 08 00 00 87 00 DE 00 00 14 00 00 00 61 00 00 ] 14:47:14.971 -> Instant. Speed: 21 KPH Average Speed: 23 KPH Instantaneous Cadence: 0 RPM Average Cadence: 67 RPM Total Distance: 222 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 97 Watt Heart Rate: 0 HBM 14:47:15.724 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5D FF 28 33 00 ] 14:47:15.972 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:15.972 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5D FF 28 33 ] 14:47:15.972 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 E7 07 F0 08 00 00 83 00 E3 00 00 14 00 00 00 5E 00 00 ] 14:47:15.972 -> Instant. Speed: 20 KPH Average Speed: 22 KPH Instantaneous Cadence: 0 RPM Average Cadence: 65 RPM Total Distance: 227 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 94 Watt Heart Rate: 0 HBM 14:47:16.973 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 4E 07 E3 08 00 00 80 00 E8 00 00 14 00 00 00 5B 00 00 ] 14:47:16.973 -> Instant. Speed: 18 KPH Average Speed: 22 KPH Instantaneous Cadence: 0 RPM Average Cadence: 64 RPM Total Distance: 232 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 91 Watt Heart Rate: 0 HBM 14:47:17.825 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 5E FF 28 33 00 ] 14:47:17.935 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:17.935 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E FF 28 33 ] 14:47:18.014 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 BC 06 CE 08 00 00 7C 00 EC 00 00 14 00 00 00 59 00 00 ] 14:47:18.014 -> Instant. Speed: 17 KPH Average Speed: 22 KPH Instantaneous Cadence: 0 RPM Average Cadence: 62 RPM Total Distance: 236 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 89 Watt Heart Rate: 0 HBM 14:47:19.033 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 2A 06 B9 08 00 00 79 00 F0 00 00 14 00 00 00 57 00 00 ] 14:47:19.033 -> Instant. Speed: 15 KPH Average Speed: 22 KPH Instantaneous Cadence: 0 RPM Average Cadence: 60 RPM Total Distance: 240 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 87 Watt Heart Rate: 0 HBM 14:47:19.920 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 6F FF 28 33 00 ] 14:47:20.012 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:20.012 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F FF 28 33 ] 14:47:20.012 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 A0 05 9D 08 00 00 76 00 F3 00 00 14 00 00 00 55 00 00 ] 14:47:20.012 -> Instant. Speed: 14 KPH Average Speed: 22 KPH Instantaneous Cadence: 0 RPM Average Cadence: 59 RPM Total Distance: 243 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 85 Watt Heart Rate: 0 HBM 14:47:21.023 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 17 05 81 08 00 00 73 00 F6 00 00 14 00 00 00 52 00 00 ] 14:47:21.023 -> Instant. Speed: 13 KPH Average Speed: 21 KPH Instantaneous Cadence: 0 RPM Average Cadence: 57 RPM Total Distance: 246 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 82 Watt Heart Rate: 0 HBM 14:47:21.987 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 94 04 67 08 00 00 71 00 F9 00 00 14 00 00 00 50 00 00 ] 14:47:21.987 -> Instant. Speed: 11 KPH Average Speed: 21 KPH Instantaneous Cadence: 0 RPM Average Cadence: 56 RPM Total Distance: 249 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 80 Watt Heart Rate: 0 HBM 14:47:22.029 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 8A FF 28 33 00 ] 14:47:22.167 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:22.167 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A FF 28 33 ] 14:47:22.985 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 15 04 46 08 00 00 6E 00 FB 00 00 14 00 00 00 4F 00 00 ] 14:47:22.985 -> Instant. Speed: 10 KPH Average Speed: 21 KPH Instantaneous Cadence: 0 RPM Average Cadence: 55 RPM Total Distance: 251 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 79 Watt Heart Rate: 0 HBM 14:47:23.993 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 99 03 27 08 00 00 6B 00 FD 00 00 14 00 00 00 4D 00 00 ] 14:47:23.993 -> Instant. Speed: 9 KPH Average Speed: 20 KPH Instantaneous Cadence: 0 RPM Average Cadence: 53 RPM Total Distance: 253 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 77 Watt Heart Rate: 0 HBM 14:47:24.132 -> Client sends Indoor Bike Simulation Parameters to Trainer's FTM Control Point: [ 11 00 00 B8 FF 28 33 00 ] 14:47:24.258 -> -> Client Rec'd Raw FTM Control Point Response Data: [ 80 11 01 ] 14:47:24.258 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B8 FF 28 33 ] 14:47:24.939 -> -> Client Rec'd Raw FTM Indoor Bike Data: [20] [ FE 02 25 03 08 08 00 00 69 00 FF 00 00 14 00 00 00 4B 00 00 ] 14:47:24.939 -> Instant. Speed: 8 KPH Average Speed: 20 KPH Instantaneous Cadence: 0 RPM Average Cadence: 52 RPM Total Distance: 255 m Resistance Level: 20 Instantaneous Power: 0 Watt Average Power: 75 Watt Heart Rate: 0 HBM

Berg0162 commented 1 year ago

Dear Joel, That looks perfect! The whole connect procedure took more than 7 seconds. No cluttering of print output anymore, no failing discover- or read actions! At the very moment the IBD Char is enabled the trainer starts to send IBD data. Perfect! The trainer is being ready!

IBD data will always contain an empty HBM value. No problem! This code does NOT support Zwift's special party trick for Apple TV users!

If you connect your heart rate strap: DO NOT connect it with the Zwift Hub trainer (switch OFF that feature in the Zwift Companion app) but connect it with Zwift (or Rouvy or any controlling app) directly using its specific name like 'Garmin HRM strap' or whatever name yours has! If you see on the Zwift pairing screen a Heart Rate connection with the name: 'Sim nRF52', you know that things are wrongly connected! That configuration is NOT supported!

Thanks for your testing effort! I will prepare now accordingly the FTMS_Zwift_Bridge code! Have a nice day! Jörgen.

le-joebar commented 1 year ago

Jörghen,

Concern the HRM and test bridge, it is by connecting it to the Zwift hub that the system works if I do not do so then the system breaks down !?

Berg0162 commented 1 year ago

Sorry Joël, Please be more specific, this is far too cryptic for me!

Op di 20 dec. 2022 16:31 schreef le-joebar @.***>:

Jörghen,

Concern the HRM and test bridge, it is by connecting it to the Zwift hub that the system works if I do not do so then the system breaks down !?

— Reply to this email directly, view it on GitHub https://github.com/Berg0162/simcline/issues/7#issuecomment-1359568811, or unsubscribe https://github.com/notifications/unsubscribe-auth/ANS5LST5NPEPEAACMVYEVRLWOHGMHANCNFSM6AAAAAASZDERFE . You are receiving this because you authored the thread.Message ID: @.***>

Berg0162 commented 1 year ago

Dear Joel, Uploaded as promised an up-to-date version for FTMS_Zwift_Bridge_v024

I wondered, does the highlighted FTM Feature mean: trainer is NOW set for HRM rebroadcasting? If you switch it to OFF (with the Companion App) is this FTM Feature then missing (OFF state) ???

Client Reads Raw FTM Feature bytes: [8] [ 87 44 00 00 0C E0 00 00 ] 14:46:24.182 -> - Fitness Machine Features: 14:46:24.182 -> Average Speed Supported 14:46:24.182 -> Cadence Supported 14:46:24.182 -> Total Distance Supported 14:46:24.182 -> Resistance Level Supported 14:46:24.182 -> Heart Rate Measurement Supported 14:46:24.182 -> Power Measurement Supported 14:46:24.182 -> - Target Setting Features: 14:46:24.182 -> Resistance Target Setting Supported 14:46:24.182 -> Power Target Setting Supported 14:46:24.182 -> Indoor Bike Simulation Parameters Supported 14:46:24.182 -> Wheel Circumference Configuration Supported 14:46:24.182 -> Spin Down Control Supported

--> Not to difficult to test with Client_FTMS_v029.... NO Heart Rate band needed! Make the change and just check the decoded FTM Feature output...for a change! Reverse the process and see if the feature comes back again! Enjoy your day! Jörgen.

le-joebar commented 1 year ago

Hello Jorghen,

I tested the FTMS_BRIDGE V24 version

No problem encountered

Here are the results.

We find the "grade" value to evolve by half the value on Zwift, it's normal since I set the difficulty value of the trainer to 50%.

image

I checked the result with HRM connected via Companion or not. There is no change in the presentation of the service it remains present.

I don't think you need to look for an answer of why it works?

image

Just a question. What is the value: Wind speed (1000): 0.00 | Rank (100): 0.51 | Crr(10000): 0.00 | Cw(100): 0.51

17:31:54.953 -> Feather nRF52840 MITM supporting: CPS, CSC and FTMS 17:31:54.953 -> ------------------ Version 02.4 --------------------- 17:31:55.408 -> FTM Service and Chars are 'initialized' 17:31:55.408 -> CP Service and Chars are 'initialized' 17:31:55.408 -> CSC Service and Chars are 'initialized' 17:31:55.408 -> Generic Access Service and Chars are 'initialized' 17:31:55.408 -> Device Information Service and Chars are 'initialized' 17:31:55.408 -> Start Client-side Scanning for CPS, CSC and FTMS! 17:32:08.832 -> Found advertising Peripheral with FTMS enabled! See Raw data packet: 17:32:08.832 -> Timestamp Addr Rssi Data 17:32:08.832 -> 000015263 F8:9C:FC:53:5E:49 -58 09-02-16-18-26-18-18-18-0A-18 17:32:09.045 -> Feather nRF52 (Central) connected to Trainer (Peripheral) device: [Zwift Hub] MAC Address: F8:9C:FC:53:5E:49 17:32:09.045 -> Now checking all mandatory Client Services and Characteristics! 17:32:09.045 -> If Mandatory Services Fail --> the Client will disconnect! 17:32:09.294 -> First checking Generic Access and Device Information Services and Characteristics! 17:32:09.373 -> Found Client Generic Access 17:32:09.793 -> -> Client Reads Device Name: [Zwift Hub] 17:32:10.326 -> -> Client Reads Appearance: [0] 17:32:10.731 -> Found Client Device Information 17:32:11.087 -> -> Client Reads Manufacturer: [Zwift] 17:32:11.651 -> -> Client Reads Model Number: [06] 17:32:12.091 -> -> Client Reads Serial Number: [06-F89CFC535E49] 17:32:12.324 -> Discovering Mandatory Client Fitness Machine (FTM) Service ... Found it! FTMS Max Payload: 20 Data Length: 27 17:32:12.651 -> Discovering Client FTM Feature Characteristic ... Found it! 17:32:12.882 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ] 17:32:12.882 -> - Fitness Machine Features: 17:32:12.882 -> - Target Setting Features: 17:32:13.158 -> Discovering Client FTM Control Point Characteristic ... Found it! 17:32:13.702 -> Discovering Client FTM Status Characteristic ... Found it! 17:32:14.192 -> Discovering Client FTM Training Status Characteristic ... Not Found! Not Mandatory 17:32:14.566 -> Discovering Client FTM Supported Resistance Level Range Characteristic ... Found it! 17:32:14.656 -> -> Client Reads Raw FTM Supported Resistance Level Range bytes: [6] [ 00 00 64 00 01 00 ] 17:32:14.920 -> Discovering Client FTM Supported Power Range Characteristic ... Found it! 17:32:15.044 -> -> Client Reads Raw FTM Supported Power Range bytes: [6] [ 00 00 E8 03 01 00 ] 17:32:15.310 -> Discovering Client FTM Indoor Bike Data Characteristic ... Found it! 17:32:15.661 -> Discovering Client Cycling Power (CP) Service ... Found it! CPS Max Payload: 20 Data Length: 27 17:32:15.913 -> Discovering Client CP Measurement characteristic ... Found it! 17:32:16.268 -> Discovering Client CP Control Point characteristic ... Not Found! NOT Mandatory! 17:32:16.576 -> Discovering Client CP Feature characteristic ... Found it! 17:32:16.685 -> -> Client Reads Raw CP Feature bytes: [4] [ 0C 00 00 00 ] 17:32:16.685 -> Wheel revolution data supported 17:32:16.685 -> Crank revolution data supported 17:32:16.916 -> Discovering Client CP Sensor Location characteristic ... Found it! 17:32:17.009 -> -> Client Reads CP Location Sensor: Loc#: 12 Rear wheel 17:32:17.271 -> Discovering Cycling Speed and Cadence (CSC) Service ... Found it! CSCS Max Payload: 20 Data Length: 27 17:32:17.349 -> Configuring the Server Device Information Service 17:32:17.349 -> Configuring the Server Cycle Power Service 17:32:17.349 -> Configuring the Server Cadence and Speed Service 17:32:17.349 -> Configuring the Server Fitness Machine Service 17:32:17.349 -> Configuring the Server NUS Service 17:32:17.349 -> Setting up the Server-side advertising payload(s) 17:32:17.349 -> Setting Server Device Name to: [Sim Zwift] 17:32:17.349 -> Setting Server Appearance to: [0] 17:32:17.349 -> Server-side is CPS, CSC and FTMS advertising! 17:32:17.533 -> Discovering Client CSC Measurement CHR ... Found it! 17:32:17.919 -> Discovering Client CSC Location CHR ... Found it! 17:32:18.044 -> -> Client Reads CSC Location Sensor: Loc#: 0 Other 17:32:18.275 -> Discovering Client CSC Feature CHR ... Found it! 17:32:18.399 -> -> Client Reads Raw CSC Feature bytes: [2] [ 03 00 ] 17:32:18.399 -> Wheel rev supported 17:32:18.399 -> Crank rev supported 17:34:12.339 -> Client- and Server-side are Up and Running! 17:34:14.345 -> Ready to receive Client FTM Indoor Bike Data values 17:34:14.345 -> >>> Couldn't enable indicate for Client CP Control Point Characteristic. 17:34:14.383 -> Ready to receive Client CP Measurement values 17:34:14.430 -> Ready to receive Client CSC Measurement values 17:34:14.430 -> Waiting for Central (Zwift) to set CCCD Notify/Indicate (enable) and start.... 17:34:16.038 -> Central Device Updated CCCD to: [1] --> Server CP: Measurement 'Notify' enabled 17:34:16.586 -> Central Device Updated CCCD to: [1] --> Server CSC: Measurement 'Notify' enabled 17:34:17.291 -> Central Device Updated CCCD to: [1] --> Server FTM: IndoorBikeData 'Notify' enabled 17:34:18.057 -> Central Device Updated CCCD to: [1] --> Server FTM: Status 'Notify' enabled 17:34:42.216 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 00] [Values: 00 ] 17:34:42.216 -> Request Control of Machine! 17:34:42.311 -> -> Client Rec'd Control Point Response: [ 80 00 01 ] 17:34:42.451 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 01] [Values: 00 ] 17:34:42.451 -> Reset Machine! 17:34:42.451 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 00] [Values: 00 ] 17:34:42.451 -> Request Control of Machine! 17:34:42.593 -> -> Client Rec'd Control Point Response: [ 80 01 01 ] 17:34:42.593 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 01 ] 17:34:47.592 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 00] [Values: 00 ] 17:34:47.592 -> Request Control of Machine! 17:34:47.639 -> -> Client Rec'd Control Point Response: [ 80 00 01 ] 17:34:47.716 -> -> Server Rec'd Raw FTM Control Point Data [len: 1] [OpCode: 07] [Values: 00 ] 17:34:47.716 -> Start or Resume Machine! 17:34:47.811 -> -> Client Rec'd Control Point Response: [ 80 07 01 ] 17:34:47.811 -> -> Client Rec'd Raw FTM Machine Status Data: [1] [ 04 ] 17:34:48.743 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 FD 00 28 33 00 ] 17:34:48.743 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 2.53 | Crr (10000): 0.00 | Cw (100): 0.51 17:34:48.882 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:34:48.882 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 FD 00 28 33 ] 17:36:06.275 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 B1 00 28 33 00 ] 17:36:06.318 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.77 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:06.401 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:06.401 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 B1 00 28 33 ] 17:36:07.326 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 33 00 28 33 00 ] 17:36:07.326 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.51 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:07.372 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:07.372 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 33 00 28 33 ] 17:36:32.918 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 32 00 28 33 00 ] 17:36:32.918 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.50 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:33.010 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:33.010 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 32 00 28 33 ] 17:36:36.157 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 33 00 28 33 00 ] 17:36:36.157 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.51 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:36.267 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:36.267 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 33 00 28 33 ] 17:36:37.107 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 35 00 28 33 00 ] 17:36:37.107 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.53 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:37.154 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:37.199 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 35 00 28 33 ] 17:36:38.079 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 39 00 28 33 00 ] 17:36:38.079 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.57 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:38.156 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:38.156 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 39 00 28 33 ] 17:36:39.030 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 40 00 28 33 00 ] 17:36:39.030 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.64 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:39.155 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:39.155 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 40 00 28 33 ] 17:36:40.061 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 4E 00 28 33 00 ] 17:36:40.061 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.78 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:40.141 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:40.141 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4E 00 28 33 ] 17:36:41.046 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 61 00 28 33 00 ] 17:36:41.046 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.97 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:41.311 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:41.311 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 61 00 28 33 ] 17:36:42.122 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 71 00 28 33 00 ] 17:36:42.122 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.13 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:42.387 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:42.387 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 71 00 28 33 ] 17:36:43.231 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 75 00 28 33 00 ] 17:36:43.231 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.17 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:43.278 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:43.278 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 75 00 28 33 ] 17:36:44.194 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 68 00 28 33 00 ] 17:36:44.194 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.04 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:44.273 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:44.273 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 68 00 28 33 ] 17:36:45.161 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 4E 00 28 33 00 ] 17:36:45.161 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.78 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:45.300 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:45.300 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 4E 00 28 33 ] 17:36:46.203 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 2A 00 28 33 00 ] 17:36:46.203 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.42 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:46.250 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:46.250 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 2A 00 28 33 ] 17:36:47.123 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1C 00 28 33 00 ] 17:36:47.123 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.28 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:47.247 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:47.247 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1C 00 28 33 ] 17:36:48.139 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 21 00 28 33 00 ] 17:36:48.139 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.33 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:48.328 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:48.328 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 21 00 28 33 ] 17:36:49.215 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1F 00 28 33 00 ] 17:36:49.215 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.31 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:49.324 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:49.324 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1F 00 28 33 ] 17:36:50.197 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 1A 00 28 33 00 ] 17:36:50.197 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.26 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:50.290 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:50.290 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 1A 00 28 33 ] 17:36:51.183 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 13 00 28 33 00 ] 17:36:51.183 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.19 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:51.276 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:51.276 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 13 00 28 33 ] 17:36:52.208 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 09 00 28 33 00 ] 17:36:52.208 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.09 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:52.286 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:52.286 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 09 00 28 33 ] 17:36:53.143 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 00 00 28 33 00 ] 17:36:53.143 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.00 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:53.221 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:53.221 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 00 00 28 33 ] 17:36:54.051 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 F9 FF 28 33 00 ] 17:36:54.051 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.07 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:54.271 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:54.271 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 F9 FF 28 33 ] 17:36:55.143 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 EF FF 28 33 00 ] 17:36:55.143 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.17 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:55.235 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:55.235 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 EF FF 28 33 ] 17:36:56.109 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 E3 FF 28 33 00 ] 17:36:56.109 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.29 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:56.141 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:56.141 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E3 FF 28 33 ] 17:36:56.998 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 D4 FF 28 33 00 ] 17:36:56.998 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.44 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:57.044 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:57.044 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 D4 FF 28 33 ] 17:36:57.934 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 BE FF 28 33 00 ] 17:36:57.934 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.66 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:58.044 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:58.044 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 BE FF 28 33 ] 17:36:58.901 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 9F FF 28 33 00 ] 17:36:58.901 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.97 | Crr (10000): 0.00 | Cw (100): 0.51 17:36:59.072 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:36:59.072 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 9F FF 28 33 ] 17:36:59.932 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 86 FF 28 33 00 ] 17:36:59.932 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -1.22 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:00.119 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:00.119 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 86 FF 28 33 ] 17:37:00.979 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 74 FF 28 33 00 ] 17:37:00.979 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -1.40 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:01.105 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:01.105 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 74 FF 28 33 ] 17:37:01.980 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 6D FF 28 33 00 ] 17:37:01.980 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -1.47 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:02.104 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:02.104 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6D FF 28 33 ] 17:37:02.964 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 72 FF 28 33 00 ] 17:37:02.964 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -1.42 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:03.183 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:03.183 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 72 FF 28 33 ] 17:37:04.026 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 88 FF 28 33 00 ] 17:37:04.026 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -1.20 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:04.072 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:04.072 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 88 FF 28 33 ] 17:37:04.994 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 AD FF 28 33 00 ] 17:37:04.994 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.83 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:05.180 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:05.180 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 AD FF 28 33 ] 17:37:05.974 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 E6 FF 28 33 00 ] 17:37:05.974 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): -0.26 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:06.053 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:06.053 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 E6 FF 28 33 ] 17:37:06.926 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 23 00 28 33 00 ] 17:37:06.926 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.35 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:07.037 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:07.037 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 23 00 28 33 ] 17:37:07.913 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 67 00 28 33 00 ] 17:37:07.913 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.03 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:08.039 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:08.039 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 00 28 33 ] 17:37:08.930 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8B 00 28 33 00 ] 17:37:08.930 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.39 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:09.009 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:09.009 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8B 00 28 33 ] 17:37:09.993 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 96 00 28 33 00 ] 17:37:09.993 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.50 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:10.134 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:10.134 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 96 00 28 33 ] 17:37:11.022 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 93 00 28 33 00 ] 17:37:11.022 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.47 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:11.101 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:11.101 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 93 00 28 33 ] 17:37:11.973 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8B 00 28 33 00 ] 17:37:11.973 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.39 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:12.160 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:12.160 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8B 00 28 33 ] 17:37:13.062 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 7F 00 28 33 00 ] 17:37:13.062 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.27 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:13.156 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:13.156 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 7F 00 28 33 ] 17:37:14.073 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 76 00 28 33 00 ] 17:37:14.073 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.18 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:14.340 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:14.340 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 76 00 28 33 ] 17:37:15.183 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 71 00 28 33 00 ] 17:37:15.183 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.13 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:15.322 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:15.322 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 71 00 28 33 ] 17:37:16.215 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 70 00 28 33 00 ] 17:37:16.215 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.12 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:16.305 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:16.305 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 70 00 28 33 ] 17:37:17.211 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 6D 00 28 33 00 ] 17:37:17.211 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.09 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:17.477 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:17.477 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6D 00 28 33 ] 17:37:37.763 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 6B 00 28 33 00 ] 17:37:37.763 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.07 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:37.950 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:37.950 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6B 00 28 33 ] 17:37:38.760 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 65 00 28 33 00 ] 17:37:38.760 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.01 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:38.808 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:38.808 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 65 00 28 33 ] 17:37:39.744 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 61 00 28 33 00 ] 17:37:39.744 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.97 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:39.916 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:39.916 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 61 00 28 33 ] 17:37:40.808 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 5B 00 28 33 00 ] 17:37:40.808 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.91 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:41.027 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:41.027 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5B 00 28 33 ] 17:37:41.945 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 56 00 28 33 00 ] 17:37:41.945 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.86 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:42.039 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:42.039 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 56 00 28 33 ] 17:37:42.909 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 57 00 28 33 00 ] 17:37:42.909 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.87 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:43.081 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:43.081 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 57 00 28 33 ] 17:37:43.954 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 5E 00 28 33 00 ] 17:37:43.954 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 0.94 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:44.032 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:44.032 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 5E 00 28 33 ] 17:37:44.982 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 67 00 28 33 00 ] 17:37:44.982 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.03 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:45.121 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:45.121 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 67 00 28 33 ] 17:37:45.979 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 6F 00 28 33 00 ] 17:37:45.979 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.11 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:46.103 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:46.103 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6F 00 28 33 ] 17:37:46.957 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 75 00 28 33 00 ] 17:37:46.957 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.17 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:47.127 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:47.127 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 75 00 28 33 ] 17:37:48.183 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 7A 00 28 33 00 ] 17:37:48.183 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.22 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:48.277 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:48.277 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 7A 00 28 33 ] 17:37:49.026 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 7E 00 28 33 00 ] 17:37:49.026 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.26 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:49.165 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:49.165 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 7E 00 28 33 ] 17:37:49.989 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 80 00 28 33 00 ] 17:37:49.989 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.28 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:50.067 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:50.067 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 80 00 28 33 ] 17:37:50.941 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 83 00 28 33 00 ] 17:37:50.941 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.31 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:51.066 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:51.066 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 83 00 28 33 ] 17:37:51.796 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 84 00 28 33 00 ] 17:37:51.796 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.32 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:51.984 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:51.984 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 84 00 28 33 ] 17:37:52.936 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 86 00 28 33 00 ] 17:37:52.936 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.34 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:53.030 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:53.030 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 86 00 28 33 ] 17:37:53.949 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 88 00 28 33 00 ] 17:37:53.949 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.36 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:54.027 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:54.027 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 88 00 28 33 ] 17:37:54.792 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8A 00 28 33 00 ] 17:37:54.792 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.38 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:54.961 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:54.961 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8A 00 28 33 ] 17:37:55.786 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8B 00 28 33 00 ] 17:37:55.786 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.39 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:55.910 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:55.910 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8B 00 28 33 ] 17:37:56.766 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8C 00 28 33 00 ] 17:37:56.766 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.40 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:56.797 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:56.797 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8C 00 28 33 ] 17:37:57.734 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8D 00 28 33 00 ] 17:37:57.734 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.41 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:57.954 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:57.954 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8D 00 28 33 ] 17:37:59.588 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8E 00 28 33 00 ] 17:37:59.588 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.42 | Crr (10000): 0.00 | Cw (100): 0.51 17:37:59.681 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:37:59.681 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8E 00 28 33 ] 17:38:02.050 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8F 00 28 33 00 ] 17:38:02.050 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.43 | Crr (10000): 0.00 | Cw (100): 0.51 17:38:02.129 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:38:02.129 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8F 00 28 33 ] 17:38:05.208 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 90 00 28 33 00 ] 17:38:05.208 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.44 | Crr (10000): 0.00 | Cw (100): 0.51 17:38:05.366 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:38:05.366 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 90 00 28 33 ] 17:38:15.990 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8F 00 28 33 00 ] 17:38:15.990 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.43 | Crr (10000): 0.00 | Cw (100): 0.51 17:38:16.069 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:38:16.069 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8F 00 28 33 ] 17:38:21.556 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8E 00 28 33 00 ] 17:38:21.557 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.42 | Crr (10000): 0.00 | Cw (100): 0.51 17:38:21.648 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:38:21.648 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8E 00 28 33 ] 17:38:23.971 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8D 00 28 33 00 ] 17:38:23.971 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.41 | Crr (10000): 0.00 | Cw (100): 0.51 17:38:24.158 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:38:24.158 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8D 00 28 33 ] 17:38:25.746 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8C 00 28 33 00 ] 17:38:25.746 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.40 | Crr (10000): 0.00 | Cw (100): 0.51 17:38:25.918 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:38:25.918 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8C 00 28 33 ] 17:38:28.284 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 8B 00 28 33 00 ] 17:38:28.284 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.39 | Crr (10000): 0.00 | Cw (100): 0.51 17:38:28.409 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:38:28.409 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 8B 00 28 33 ] 17:39:28.747 -> -> Server Rec'd Raw FTM Control Point Data [len: 7] [OpCode: 11] [Values: 00 00 6D 00 28 33 00 ] 17:39:28.747 -> Set Indoor Bike Simulation Parameters --> Wind speed (1000): 0.00 | Grade (100): 1.09 | Crr (10000): 0.00 | Cw (100): 0.51 17:39:28.856 -> -> Client Rec'd Control Point Response: [ 80 11 01 ] 17:39:28.856 -> -> Client Rec'd Raw FTM Machine Status Data: [7] [ 12 00 00 6D 00 28 33 ] 17:40:21.715 -> Server disconnected from Central (Laptop): [], reason: [13]

Berg0162 commented 1 year ago

Dear Joel, Thanks for your effort and well done! Not a bad result, however a few readings are missed in the beginning, that needs my(!) attention:

17:32:10.326 -> -> Client Reads Appearance: [0] 17:32:12.882 -> -> Client Reads Raw FTM Feature bytes: [8] [ 00 00 00 00 00 00 00 00 ]

You have to help me to clarify the HRM (Heart Rate Measurement) connection context, I need to precisely understand how critical devices are connected......that helps making the code more robust for different situations and "une déformation professionnelle" ! In the recent run, I see HRM is paired (on the screen shots you included) and showing real BPM (like 70 Beats Per Minute)
--> do you use a Heart Rate Strap, or an other device? Can you give me the type and brand name? --> is the Zwift Game App (on the PC) connected directly with your Heart Rate Strap? OR --> is the Zwift HUB Trainer connected with your Heart Rate Strap and then the trainer is connected with the Zwift Game App (on the PC)?

I am pleasantly surprised about the following Client_FTMS test result:

I checked the result with HRM connected via Companion or not. There is no change in the presentation of the service it remains present.

--> I assume that in both (above) cases the real time BPM data are shown, is that correct? Apparently the Zwift Game app (on the PC) is using the Indoor Bike Data for extracting the BPM when it is not connected directly with your heart rate strap. You have seen in previous FTMS_Client runs that a BPM field is present in IBData! I have to think about possible consequences but again this is a clever feature!

Now remains the following issue:

I can't turn on the cardio frequency meter otherwise everything crashes!!

What is the present status? Can you crash the code in certain situations?

I hope you will take some time to answer the questions and again thank you for doing the testing so quickly! Regards, Jörgen.