BLE CSCS - works in nrfconnect and nothing else

Exhausted everything. 

Here's the guts of the code. A task is called at 2Hz to push the value, which at 1024/s makes an event time of +512. I set the cumulative RPM to +1 for testing. Both values appear correctly in the nrfConnect App. Only RPM is supported.

However, osmand shows a much higher RPM, Wahoo app shows zero. Garmin won't connect/bond. Tried a few more and nothing is working. 

static uint8_t encoded_csc_meas[] = {1,0,0,0,0,0,0};



void BLUETOOTH_EventCscsMotionAssess(void) {

  #ifdef BLE_CSCS_DISABLE
    return;
  #endif

  ret_code_t           err_code;

  lastWheelEventTime += 512; // 1/1024s units
  cumulativeRPM ++;
 
  uint32_encode(cumulativeRPM, &encoded_csc_meas[1]);
  uint16_encode(lastWheelEventTime, &encoded_csc_meas[5]);

  ble_gatts_hvx_params_t hvx_params;
  memset(&hvx_params, 0, sizeof(hvx_params));
  hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
  hvx_params.offset = 0;
  hvx_params.p_len  = &len;
  hvx_params.p_data = encoded_csc_meas;
  hvx_params.handle = m_cscs.meas_handles.value_handle;

  for(uint8_t i = 0; i < NRF_SDH_BLE_PERIPHERAL_LINK_COUNT; i++) {
    if (connections.handles[i] != BLE_CONN_HANDLE_INVALID) {
      len = sizeof(encoded_csc_meas);
      err_code = sd_ble_gatts_hvx(connections.handles[i], &hvx_params);
      if (err_code < 0x3000) {
        APP_ERROR_CHECK(err_code);
      }
    }
  }
}





  • Hi Andrew,

    *Please note that from the reference documents, the CSCS measurement is expected to be sent via ble_cscs_measurement_send() using a ble_cscs_meas_t structure, not by manually creating the notification payload. Please follow exact same structure as in documents: nRF5 SDK v17.1.0: ble_cscs_meas_s Struct Reference

    *The service module encodes this struct into the characteristic according to the Bluetooth CSCS spec when you call "ble_cscs_measurement_send"

    *The first byte in the characteristic is a flags field, whose bits indicate whether wheel and/or crank data are present. Nordic struct is_wheel_rev_data_present and is_crank_rev_data_present control those bits.

    *In your code you are bypassing ble_cscs_measurement_send() and encoding manually. Also you say “Only RPM is supported”, but your buffer first byte is 1. In the Bluetooth CSCS spec, bit 0 is “Wheel Revolution Data Present” and bit 1 is “Crank Revolution Data Present”. The Nordic struct has separate Booleans for wheel and crank data.
    If you intend to expose crank‑only (RPM), the flags should indicate crank data present and wheel data not present, and the payload layout must match that case.
    Your buffer layout (flags + 4 bytes + 2 bytes) matches the wheel‑only case (cumulative wheel revs + last wheel event time), not crank‑only. So apps that interpret it as wheel data will compute speed, not cadence, apps that expect crank data may see nonsense or zero.


    *The Nordic struct names are explicit: cumulative_wheel_revs, last_wheel_event_time, cumulative_crank_revs, last_crank_event_time.
    You’re putting “cumulativeRPM” into the 32‑bit field and “lastWheelEventTime” into the 16‑bit field, but third‑party apps will interpret those as cumulative wheel revolutions and last wheel event time (or crank equivalents), not RPM. nRF Connect is just showing raw values, so it looks “correct” there, but other apps are doing real CSCS math.

    Please try to use the recommended usage sequence based on the reference documents:


    *Fill a ble_cscs_meas_t with the correct semantics (stop manually building encoded_csc_meas and calling sd_ble_gatts_hvx() directly for CSCS).
    *Set is_wheel_rev_data_present / is_crank_rev_data_present according to what you actually provide.
    *Call ble_cscs_measurement_send(&m_cscs, &meas) and let the library encode and send the notification.

  • So let's break this down as I'm not agreeing. I'm only sending RPM so looking at the encoded payload is the following

    static uint8_t encoded_csc_meas[] = {1,0,0,0,0,0,0};


    The first byte is the flags field. www.bluetooth.com/.../index-en.html

    Which according to this specification the first bit indicates wheel revolutions is supported, that's what 1 is. The next 32 and 16 bit spaces are for cumulative and last event which in my case is fixed. If crank bit is not set then the additional bytes are not set or sent.

    The sdk code is doing the same thing

        // Cumulative Wheel Revolutions and Last Wheel Event Time Fields
        if (p_cscs->feature & BLE_CSCS_FEATURE_WHEEL_REV_BIT)
        {
            if (p_csc_measurement->is_wheel_rev_data_present)
            {
                flags |= CSC_MEAS_FLAG_MASK_WHEEL_REV_DATA_PRESENT;
                len += uint32_encode(p_csc_measurement->cumulative_wheel_revs, &p_encoded_buffer[len]);
                len += uint16_encode(p_csc_measurement->last_wheel_event_time, &p_encoded_buffer[len]);
            }
        }
    









  • I have it

      if (rpm) {
        lastWheelEventTime += (1024*60)/rpm;
        cumulativeRPM++;
      }





Related