如何将 BLE FTMS 室内自行车数据拆分为两个块,以匹配每个块最多 20 字节

问题描述 投票:0回答:1

这是我为 ESP32 板编写 BLE FTMS 服务的第一个方法。老实说,我并没有真正的经验,这是我的第一个 C++ 应用程序。我成功创建了 FTMS 服务并将数据发送到培训应用程序,例如KinoMap 或类似的。我的问题是我只能发送不超过 20 字节限制的数据。

我在规范中读到,我必须将其分成 2 个块,并向第一个块添加“更多数据位”,以便能够发送超过 20 个字节,并确保客户端知道第二个数据块可用。这就是我挣扎的地方。

我可能没有足够的经验来了解问题所在,而且我对 BLE FTMS 规范了解得越多,我的困惑就越多;)我没有找到描述如何添加这个“更多数据位”以及它的外观......我尝试使用 0x01 但我不知道这是否是添加它的正确方法。

这样它就可以使用最大 20 字节:

...
byte features[] = {0x07,0x52,0x00,0x00};

void transmitFTMS(double rpm, double avgRpm, double cadence, double avgCadence, double kph, double avgKph, double power, double avgPower, 
                  double runningDistance, double runningCalories, unsigned long elapsedTime)
{
    uint16_t transmittedKph        = (uint16_t) (kph * 100);         //(0.01 resolution)
    uint16_t transmittedTime       = (uint16_t) (elapsedTime / 1000);//(1.0 resolution)
    uint16_t transmittedAvgKph     = (uint16_t) (avgKph * 100);      //(0.01 resolution)
    uint16_t transmittedRpm        = (uint16_t) (rpm * 2);           //(0.5 resolution)
    uint16_t transmittedAvgRpm     = (uint16_t) (avgRpm * 2);         //(0.1 resolution)
    uint16_t transmittedCadence    = (uint16_t) (cadence * 2);
    uint16_t transmittedAvgCadence = (uint16_t) (avgCadence * 2);
    uint16_t transmittedPower      = (uint16_t) (power * 2);      //(1.0 resolution)
    uint16_t transmittedAvgPower   = (uint16_t) (avgPower * 2);        //(1.0 resolution)
    uint32_t transmittedDistance   = (uint32_t) (runningDistance * 1000);// runningDistance in km, need m 
    uint16_t transmittedTotalCal   = (uint16_t) (runningCalories * 10);                   //(1.0 resolution)
    uint16_t transmittedCalHr      = (uint16_t) (runningCalories * 60 * 60 / elapsedTime);//(1.0 resolution) 
    uint8_t transmittedCalMin      = (uint8_t)  (runningCalories * 60 / elapsedTime);     //(1.0 resolution)
    
    bool disconnecting = !deviceConnected && oldDeviceConnected;
    bool connecting = deviceConnected && !oldDeviceConnected;
    
    byte bikeData[20]={0x56,0x09,
                    (uint8_t)transmittedKph,        (uint8_t)(transmittedKph >> 8),
                    (uint8_t)transmittedAvgKph,     (uint8_t)(transmittedAvgKph >> 8),
                    (uint8_t)transmittedCadence,    (uint8_t)(transmittedCadence >> 8),
                    (uint8_t)transmittedDistance,   (uint8_t)(transmittedDistance >> 8),
                    (uint8_t)(transmittedDistance >> 16),        
                    (uint8_t)transmittedPower,      (uint8_t)(transmittedPower >> 8),                   
                    (uint8_t)transmittedTotalCal,   (uint8_t)(transmittedTotalCal >> 8),                    
                    (uint8_t)transmittedCalHr,      (uint8_t)(transmittedCalHr >> 8),                    
                    transmittedCalMin,
                    (uint8_t)transmittedTime,      (uint8_t)(transmittedTime >> 8)
      };
    if (deviceConnected)
    {
        indoorBikeDataCharacteristic->setValue((uint8_t *)&bikeData, 20);
        indoorBikeDataCharacteristic->notify();
    }
...

我尝试按如下方式更改此设置以提交超过 20 个字节:

...
    byte bikeData1[20]={0x56,0x09,
                    (uint8_t)transmittedKph,        (uint8_t)(transmittedKph >> 8),
                    (uint8_t)transmittedAvgKph,     (uint8_t)(transmittedAvgKph >> 8),
                    (uint8_t)transmittedCadence,    (uint8_t)(transmittedCadence >> 8),
                    (uint8_t)transmittedRpm,        (uint8_t)(transmittedRpm >> 8),
                    (uint8_t)transmittedAvgRpm,     (uint8_t)(transmittedAvgRpm >> 8),
                    (uint8_t)transmittedAvgCadence, (uint8_t)(transmittedAvgCadence >> 8),
                    (uint8_t)transmittedDistance,   (uint8_t)(transmittedDistance >> 8),
                    (uint8_t)(transmittedDistance >> 16),        
                    (uint8_t)transmittedPower,      (uint8_t)(transmittedPower >> 8),
                    0x01
    };
    byte bikeData2[9]={
                    (uint8_t)transmittedAvgPower,   (uint8_t)(transmittedAvgPower >> 8),
                    (uint8_t)transmittedTotalCal,   (uint8_t)(transmittedTotalCal >> 8),                    
                    (uint8_t)transmittedCalHr,      (uint8_t)(transmittedCalHr >> 8),                    
                    transmittedCalMin,
                    (uint8_t)transmittedTime,      (uint8_t)(transmittedTime >> 8)
      };
    if (deviceConnected)
    {
        indoorBikeDataCharacteristic->setValue((uint8_t *)&bikeData1, 20);
        indoorBikeDataCharacteristic->notify();

        indoorBikeDataCharacteristic->setValue((uint8_t *)&bikeData2, 9);
        indoorBikeDataCharacteristic->notify();
    }
...

但是客户端应用程序无法处理提供的数据,我不知道失败的原因。

我希望有人能给我指出正确的方向,因为过去三周我一直在研究这个问题,但运气不佳。我还尝试更改提交数据的顺序或每个块中提交的数据,但我所做的所有尝试都无法使其按预期工作。

我不知道如何调试这个。

bluetooth-lowenergy esp32 arduino-esp32
1个回答
0
投票

遵循 FTMS 规范,室内自行车数据在 4.9 中定义。在标志字段中,您传递 0x56、0x09,其小端格式为:

100101010110

根据4.9.1.1标志字段,这表明您正在发送:

  • 平均速度
  • 瞬时节奏
  • 总距离
  • 瞬时功率
  • 能量消耗
  • 经过时间

您的代码发送:

// Instantaneous Speed (because More Data == 0)
(uint8_t)transmittedKph,        (uint8_t)(transmittedKph >> 8),

// Average Speed
(uint8_t)transmittedAvgKph,     (uint8_t)(transmittedAvgKph >> 8),

// Instantaneous Cadence
(uint8_t)transmittedCadence,    (uint8_t)(transmittedCadence >> 8),

// Total Distance
(uint8_t)transmittedDistance,   (uint8_t)(transmittedDistance >> 8), (uint8_t)(transmittedDistance >> 16),

// Instantaneous Power
(uint8_t)transmittedPower,      (uint8_t)(transmittedPower >> 8),                   

// Expended Energy (Total Energy, Energy per Hour, Energy per Minute)
(uint8_t)transmittedTotalCal,   (uint8_t)(transmittedTotalCal >> 8),                    
(uint8_t)transmittedCalHr,      (uint8_t)(transmittedCalHr >> 8),                    
transmittedCalMin,

// Elapsed Time
(uint8_t)transmittedTime,      (uint8_t)(transmittedTime >> 8)

到目前为止,一切都很好。你发送你所说的发送。

然后在你的第二批中,你似乎添加了一堆字段,但你没有更新你的标志,所以我不太确定它们的含义。特别是这些

Rpm
字段看起来就像只是节奏。所以我不确定你的意思是什么,但如果你想包括平均节奏,你需要打开它。但经过的时间不适合,所以你需要删除它。

那就是这样的。 (删除 Rpm 字段,因为我不知道它们是什么。)

// 0x150E; adds Avg Cadence, removes elapsed time
// 0001 0101 1110
byte bikeData[]={0x0E,0x15,
                (uint8_t)transmittedKph,        (uint8_t)(transmittedKph >> 8),
                (uint8_t)transmittedAvgKph,     (uint8_t)(transmittedAvgKph >> 8),
                (uint8_t)transmittedCadence,    (uint8_t)(transmittedCadence >> 8),

                // Add Average Cadence
                (uint8_t)transmittedAvgCadence, (uint8_t)(transmittedAvgCadence >> 8),

                (uint8_t)transmittedDistance,   (uint8_t)(transmittedDistance >> 8), (uint8_t)(transmittedDistance >> 16),        
                (uint8_t)transmittedPower,      (uint8_t)(transmittedPower >> 8),                   
                (uint8_t)transmittedTotalCal,   (uint8_t)(transmittedTotalCal >> 8),                    
                (uint8_t)transmittedCalHr,      (uint8_t)(transmittedCalHr >> 8),                    
                transmittedCalMin    
  };

现在您需要发送“更多数据”。这意味着在标志中设置位 0,并且发送瞬时速度。

// Flags: 0x4001, 0100 0000 0000 0001
byte bikeData2[]={0x01, 0x40
                (uint8_t)transmittedAvgPower,   (uint8_t)(transmittedAvgPower >> 8),
                (uint8_t)transmittedTime,      (uint8_t)(transmittedTime >> 8)
};

这可能很接近。关键点是您的标志必须描述数据包中的内容,数据包不能超过 20 个字节,如果您想发送不包括瞬时速度的第二个数据包,请设置位 0(“更多数据”) .

© www.soinside.com 2019 - 2024. All rights reserved.