Library issue with BleCharacteristic.setValue()

I'm trying to set a 6 byte value onto a BleCharacteristic, but when I do, I only get 4 bytes on the central side. So I've tried to call the method like this:

uint8_t buf[6];
buf[0] = 0x01;
uint32_t value = ieee11073_from_float(71.2); // hard-coded for this example
memcpy(&buf[1], &value, 4);
buf[5] = 0x1;
myCharacteristic.setValue(&buf, sizeof(buf));

but I get an error that there's no matching function.

Specifically, the error I get is:

error: no matching function for call to 'particle::BleCharacteristic::setValue(uint8_t (*)[6], unsigned int)'

It doesn't like the len parameter. Without the len parameter, I get some weird 4 byte array that doesn't represent the 6 bytes I set.

This almost exactly from the temperaturethemometer.ino example from the Particle library BLE documentation. Additionally, when I look at spark_wiring_ble.h there is a matching overloaded method:

ssize_t setValue(const uint8_t* buf, size_t len, BleTxRxType type = BleTxRxType::AUTO);

The weird thing is if I load the temperaturethermometer.ino example, it works! What's going on?

This is on an Argon with deviceOS@6.2.1.

That looks like it should work. What is the definition for myCharacteristic and what is its scope (global, local, etc.)?

It's defined globally as a part of an environmental sensing service, I have characteristics (temperature and humidity). I have a method that I pass a value and characteristic into when the values update.

BleUuid environmentService(BLE_SIG_UUID_ENVIRONMENT_SENSING_SVC);
BleCharacteristic temperatureCharacteristic("temp", BleCharacteristicProperty::NOTIFY, BleUuid(0x2A6E), environmentService);
BleCharacteristic humidityMeasurementCharacteristic("humidity", BleCharacteristicProperty::NOTIFY, BleUuid(0x2A6F), environmentService);

Then in the loop, I take a reading from my temperature & humidity sensor and call publishCharacteristic.

void loop() {
takeReading(true); // reads from DHT and updates global values temp, humidity
...
publishCharacteristic(temp, tempMeasurementCharacteristic);
publishCharacteristic(humidity, humidityMeasurementCharacteristic);
....
}
void publishCharacteristic(float value, BleCharacteristic myCharacteristic) {
uint8_t buf[6];
uint32_t lValue = ieee11073_from_float(value);
memcpy(&buf[1], &lValue, 4);
buf[0] = 0x1;
buf[5] = 0x1;
myCharacteristic.setValue(&buf);
}

uint32_t ieee11073_from_float(float value) {
uint8_t exponent = 0xFE;
uint32_t mantissa = (uint32_t)(value * 100);
return (((uint32_t)exponent) << 24) | mantissa;
}

It also includes the DHT.h library, which includes Adafruit_Sensor.h. Could that be interfering with the version of spark_wiring_ble.h?

I believe the problem is that this is making a copy of the characteristic on the stack when calling publishCharacteristic. It may work if you declare it as:

void publishCharacteristic(float value, BleCharacteristic &myCharacteristic)

My C is a little rusty, but shouldn't the & be on the calling side and then dereferenced with an * on the function declaration? Like this:

void loop() {
takeReading(true);
publishCharacteristic(temp, &tempMeasurementCharacteristic);
publishCharacteristic(humidity, &humidityMeasurementCharacteristic);
...
}

void publishCharacteristic(float value, BleCharacteristic *myCharacteristic) {
uint8_t buf[6];
uint32_t lValue = ieee11073_from_float(value);
memcpy(&buf[1], &lValue, 4);
buf[0] = 0x1;
buf[5] = 0x1;
(*myCharacteristic).setValue(&buf);
}

Even so, this still gives me the compile error for no matching function for call if I try to add the sizeof(buf) parameter to setValue.

OK, now I see what's wrong. It's matching against the template, not the regular setValue. This compiles and should work:

void publishCharacteristic(float value, BleCharacteristic &myCharacteristic)
{
    uint8_t buf[6];
    uint32_t lValue = ieee11073_from_float(value);
    memcpy(&buf[1], &lValue, 4);
    buf[0] = 0x1;
    buf[5] = 0x1;
    myCharacteristic.setValue((const uint8_t *)&buf, sizeof(buf));
}

While you can change all of the characteristics from by value to by pointer like you did, the other alternative is to change it to pass by reference as I did here.

2 Likes

OK, that did compile! Thanks!

Update: Not only does it compile, but it works! I'm getting the correct 6 bytes back on the central side now. Thanks again!

1 Like