Skip to content

Fix for negative temp in Eddystone TLM; solving #7618 #7791

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Feb 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 50 additions & 55 deletions libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
#include <BLEEddystoneTLM.h>
#include <BLEBeacon.h>

#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))

int scanTime = 5; //In seconds
BLEScan *pBLEScan;

Expand All @@ -37,58 +35,66 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
Serial.println(devUUID.toString().c_str());
Serial.println("");
}
else

if (advertisedDevice.haveManufacturerData() == true)
{
if (advertisedDevice.haveManufacturerData() == true)
{
std::string strManufacturerData = advertisedDevice.getManufacturerData();
std::string strManufacturerData = advertisedDevice.getManufacturerData();

uint8_t cManufacturerData[100];
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
uint8_t cManufacturerData[100];
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);

if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
{
Serial.println("Found an iBeacon!");
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setData(strManufacturerData);
Serial.printf("iBeacon Frame\n");
Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d\n", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower());
}
else
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
{
Serial.println("Found an iBeacon!");
BLEBeacon oBeacon = BLEBeacon();
oBeacon.setData(strManufacturerData);
Serial.printf("iBeacon Frame\n");
Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d\n", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower());
}
else
{
Serial.println("Found another manufacturers beacon!");
Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
for (int i = 0; i < strManufacturerData.length(); i++)
{
Serial.println("Found another manufacturers beacon!");
Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
for (int i = 0; i < strManufacturerData.length(); i++)
{
Serial.printf("[%X]", cManufacturerData[i]);
}
Serial.printf("\n");
Serial.printf("[%X]", cManufacturerData[i]);
}
Serial.printf("\n");
}
return;
}

uint8_t *payLoad = advertisedDevice.getPayload();
// search for Eddystone Service Data in the advertising payload
// *payload shall point to eddystone data or to its end when not found
const uint8_t serviceDataEddystone[3] = {0x16, 0xAA, 0xFE}; // it has Eddystone BLE UUID
const size_t payLoadLen = advertisedDevice.getPayloadLength();
uint8_t *payLoadEnd = payLoad + payLoadLen - 1; // address of the end of payLoad space
while (payLoad < payLoadEnd) {
if (payLoad[1] == serviceDataEddystone[0] && payLoad[2] == serviceDataEddystone[1] && payLoad[3] == serviceDataEddystone[2]) {
// found!
payLoad += 4;
break;
}
payLoad += *payLoad + 1; // payLoad[0] has the field Length
}

BLEUUID checkUrlUUID = (uint16_t)0xfeaa;

if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
if (payLoad < payLoadEnd) // Eddystone Service Data and respective BLE UUID were found
{
if (payLoad[11] == 0x10)
if (*payLoad == 0x10)
{
Serial.println("Found an EddystoneURL beacon!");
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!

foundEddyURL.setData(eddyContent);
uint8_t URLLen = *(payLoad - 4) - 3; // Get Field Length less 3 bytes (type and UUID)
foundEddyURL.setData(std::string((char*)payLoad, URLLen));
std::string bareURL = foundEddyURL.getURL();
if (bareURL[0] == 0x00)
{
size_t payLoadLen = advertisedDevice.getPayloadLength();
// dumps all bytes in advertising payload
Serial.println("DATA-->");
uint8_t *payLoad = advertisedDevice.getPayload();
for (int idx = 0; idx < payLoadLen; idx++)
{
Serial.printf("0x%08X ", payLoad[idx]);
Serial.printf("0x%02X ", payLoad[idx]);
}
Serial.println("\nInvalid Data");
return;
Expand All @@ -98,30 +104,19 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
Serial.printf("Decoded URL: %s\n", foundEddyURL.getDecodedURL().c_str());
Serial.printf("TX power %d\n", foundEddyURL.getPower());
Serial.println("\n");
}
else if (payLoad[11] == 0x20)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just changed Line 102 to:
else if (payLoad[22] == 0x20)

in order to make it work.

}
else if (*payLoad == 0x20)
{
Copy link
Collaborator

@SuGlider SuGlider Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that this is right? [11] --> [22]? All fine.

Copy link
Collaborator

@SuGlider SuGlider Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I checked it with nRF APP and it is correct. The position is 22.

Serial.println("Found an EddystoneTLM beacon!");
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
Copy link
Collaborator

@SuGlider SuGlider Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just changed Line 106 to:
std::string eddyContent((char *)&payLoad[22]); // incomplete EddystoneURL struct!


eddyContent = "01234567890123";

for (int idx = 0; idx < 14; idx++)
{
eddyContent[idx] = payLoad[idx + 11];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just changed Line 112 to:
eddyContent[idx] = payLoad[idx + 22];

}

foundEddyURL.setData(eddyContent);
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just changed Line 118 to:
int16_t temp = payLoad[22+5] + (payLoad[22+4] << 8);

float calcTemp = temp / 256.0f;
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
Serial.printf("Reported time since last reboot: %ds\n", foundEddyURL.getTime());

BLEEddystoneTLM eddystoneTLM;
eddystoneTLM.setData(std::string((char*)payLoad, 14));
Serial.printf("Reported battery voltage: %dmV\n", eddystoneTLM.getVolt());
Serial.printf("Reported temperature: %.2f°C (raw data=0x%04X)\n", eddystoneTLM.getTemp(), eddystoneTLM.getRawTemp());
Serial.printf("Reported advertise count: %d\n", eddystoneTLM.getCount());
Serial.printf("Reported time since last reboot: %ds\n", eddystoneTLM.getTime());
Serial.println("\n");
Serial.print(foundEddyURL.toString().c_str());
Serial.print(eddystoneTLM.toString().c_str());
Serial.println("\n");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason for removing Lines 123 to 125?

}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
5. Stop advertising.
6. deep sleep

To read data advertised by this beacon use second ESP with example sketch BLE_Beacon_Scanner
*/
#include "sys/time.h"

Expand All @@ -22,7 +23,7 @@
#include "BLEUtils.h"
#include "BLEBeacon.h"
#include "BLEAdvertising.h"
#include "BLEEddystoneURL.h"
#include "BLEEddystoneTLM.h"

#include "esp_sleep.h"

Expand All @@ -48,10 +49,10 @@ void setBeacon()
char beacon_data[25];
uint16_t beconUUID = 0xFEAA;
uint16_t volt = random(2800, 3700); // 3300mV = 3.3V
float tempFloat = random(2000, 3100) / 100.0f;
Serial.printf("Random temperature is %.2fC\n", tempFloat);
int temp = (int)(tempFloat * 256); //(uint16_t)((float)23.00);
Serial.printf("Converted to 8.8 format %0X%0X\n", (temp >> 8), (temp & 0xFF));
float tempFloat = random(-3000, 3000) / 100.0f;
Serial.printf("Random temperature is %.2f°C\n", tempFloat);
int temp = (int)(tempFloat * 256);
Serial.printf("Converted to 8.8 format %0X%0X\n", (temp >> 8) & 0xFF, (temp & 0xFF));

BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
Expand Down Expand Up @@ -82,13 +83,11 @@ void setBeacon()

void setup()
{

Serial.begin(115200);
gettimeofday(&nowTimeStruct, NULL);

Serial.printf("start ESP32 %d\n", bootcount++);

Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", nowTimeStruct.tv_sec, nowTimeStruct.tv_sec - last);
Serial.printf("Starting ESP32. Bootcount = %d\n", bootcount++);
Serial.printf("Deep sleep (%lds since last reset, %lds since last boot)\n", nowTimeStruct.tv_sec, nowTimeStruct.tv_sec - last);

last = nowTimeStruct.tv_sec;
lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter
Expand All @@ -103,12 +102,11 @@ void setup()
setBeacon();
// Start advertising
pAdvertising->start();
Serial.println("Advertizing started for 10s ...");
Serial.println("Advertising started for 10s ...");
delay(10000);
pAdvertising->stop();
Serial.printf("enter deep sleep for 10s\n");
Serial.printf("Enter deep sleep for 10s\n");
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
Serial.printf("in deep sleep\n");
}

void loop()
Expand Down
2 changes: 1 addition & 1 deletion libraries/BLE/src/BLEBeacon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ uint16_t BLEBeacon::getMinor() {
}

BLEUUID BLEBeacon::getProximityUUID() {
return BLEUUID(m_beaconData.proximityUUID, 16, false);
return BLEUUID(m_beaconData.proximityUUID, 16, true);
}

int8_t BLEBeacon::getSignalPower() {
Expand Down
27 changes: 22 additions & 5 deletions libraries/BLE/src/BLEEddystoneTLM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
#include "BLEEddystoneTLM.h"

static const char LOG_TAG[] = "BLEEddystoneTLM";
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
#define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24))

BLEEddystoneTLM::BLEEddystoneTLM() {
beaconUUID = 0xFEAA;
Expand Down Expand Up @@ -47,9 +45,13 @@ uint16_t BLEEddystoneTLM::getVolt() {
} // getVolt

float BLEEddystoneTLM::getTemp() {
return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f;
return EDDYSTONE_TEMP_U16_TO_FLOAT(m_eddystoneData.temp);
} // getTemp
Copy link
Collaborator

@SuGlider SuGlider Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said, this is a breaking change. I think it should stay the same:
float BLEEddystoneTLM::getTemp()

It should just use the new MACRO to convert u16 to float, considering the signal.
EDDYSTONE_TEMP_U16_TO_FLOAT(tempU16)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion is to eliminate uint16_t BLEEddystoneTLM::getTemp() and just keep original float BLEEddystoneTLM::getTemp() that converts U16 BigEndian to Float (return value) using the MACRO.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be the final code:

float BLEEddystoneTLM::getTemp() {
	return EDDYSTONE_TEMP_U16_TO_FLOAT(m_eddystoneData.temp);
} // getTemp


uint16_t BLEEddystoneTLM::getRawTemp() {
return ENDIAN_CHANGE_U16(m_eddystoneData.temp);
} // getRawTemp

Copy link
Collaborator

@SuGlider SuGlider Feb 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As said, this is a breaking change. I think it should stay the same:
float BLEEddystoneTLM::getTemp()

It should just use the new MACRO to convert u16 to float, considering the signal.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_eddystoneData.temp is in Bigendian 8.8 fixed point (16 bits) and EDDYSTONE_TEMP_U16_TO_FLOAT() already does all the job.

No need to use ENDIAN_CHANGE_U16() here.

Please eliminate this method because it causes a breaking change to the API.

uint32_t BLEEddystoneTLM::getCount() {
return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
} // getCount
Expand All @@ -73,7 +75,7 @@ std::string BLEEddystoneTLM::toString() {
out += " mV\n";

out += "Temperature ";
snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
snprintf(val, sizeof(val), "%.2f", ((int16_t)ENDIAN_CHANGE_U16(m_eddystoneData.temp)) / 256.0f);
out += val;
out += " C\n";

Expand Down Expand Up @@ -110,6 +112,21 @@ std::string BLEEddystoneTLM::toString() {

/**
* Set the raw data for the beacon record.
* Example:
* uint8_t *payLoad = advertisedDevice.getPayload();
* eddystoneTLM.setData(std::string((char*)payLoad+22, advertisedDevice.getPayloadLength() - 22));
* Note: the offset 22 works for current implementation of example BLE_EddystoneTLM Beacon.ino, however it is not static and will be reimplemented
* Data frame:
* | Field || Len | Type | UUID | EddyStone TLM |
* | Offset || 0 | 1 | 2 | 4 |
* | Len || 1 B | 1 B | 2 B | 14 B |
* | Data || ?? | ?? | 0xAA | 0xFE | ??? |
*
* EddyStone TLM frame:
* | Field || Type | Version | Batt mV | Beacon temp | Cnt since boot | Time since boot |
* | Offset || 0 | 1 | 2 | 4 | 6 | 10 |
* | Len || 1 B | 1 B | 2 B | 2 B | 4 B | 4 B |
* | Data || 0x20 | ?? | ?? | ?? | ?? | ?? | | | | | | | | |
*/
void BLEEddystoneTLM::setData(std::string data) {
if (data.length() != sizeof(m_eddystoneData)) {
Expand All @@ -132,7 +149,7 @@ void BLEEddystoneTLM::setVolt(uint16_t volt) {
} // setVolt

void BLEEddystoneTLM::setTemp(float temp) {
m_eddystoneData.temp = (uint16_t)temp;
m_eddystoneData.temp = EDDYSTONE_TEMP_FLOAT_TO_U16(temp);
} // setTemp

void BLEEddystoneTLM::setCount(uint32_t advCount) {
Expand Down
55 changes: 30 additions & 25 deletions libraries/BLE/src/BLEEddystoneTLM.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
#include "BLEUUID.h"

#define EDDYSTONE_TLM_FRAME_TYPE 0x20
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00)>>8) + (((x)&0xFF)<<8))
#define ENDIAN_CHANGE_U32(x) ((((x)&0xFF000000)>>24) + (((x)&0x00FF0000)>>8)) + ((((x)&0xFF00)<<8) + (((x)&0xFF)<<24))
#define EDDYSTONE_TEMP_U16_TO_FLOAT(tempU16) (((int16_t)ENDIAN_CHANGE_U16(tempU16)) / 256.0f)
#define EDDYSTONE_TEMP_FLOAT_TO_U16(tempFloat) (ENDIAN_CHANGE_U16(((int)((tempFloat) * 256))))

/**
* @brief Representation of a beacon.
Expand All @@ -18,33 +22,34 @@
*/
class BLEEddystoneTLM {
public:
BLEEddystoneTLM();
std::string getData();
BLEUUID getUUID();
uint8_t getVersion();
uint16_t getVolt();
float getTemp();
uint32_t getCount();
uint32_t getTime();
std::string toString();
void setData(std::string data);
void setUUID(BLEUUID l_uuid);
void setVersion(uint8_t version);
void setVolt(uint16_t volt);
void setTemp(float temp);
void setCount(uint32_t advCount);
void setTime(uint32_t tmil);
BLEEddystoneTLM();
std::string getData();
BLEUUID getUUID();
uint8_t getVersion();
uint16_t getVolt();
float getTemp();
uint16_t getRawTemp();
uint32_t getCount();
uint32_t getTime();
std::string toString();
void setData(std::string data);
void setUUID(BLEUUID l_uuid);
void setVersion(uint8_t version);
void setVolt(uint16_t volt);
void setTemp(float temp);
void setCount(uint32_t advCount);
void setTime(uint32_t tmil);

private:
uint16_t beaconUUID;
struct {
uint8_t frameType;
uint8_t version;
uint16_t volt;
uint16_t temp;
uint32_t advCount;
uint32_t tmil;
} __attribute__((packed)) m_eddystoneData;
uint16_t beaconUUID;
struct {
uint8_t frameType;
uint8_t version;
uint16_t volt;
uint16_t temp;
uint32_t advCount;
uint32_t tmil;
} __attribute__((packed)) m_eddystoneData;

}; // BLEEddystoneTLM

Expand Down
2 changes: 1 addition & 1 deletion libraries/BLE/src/BLEEddystoneURL.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class BLEEddystoneURL {
struct {
uint8_t frameType;
int8_t advertisedTxPower;
uint8_t url[16];
uint8_t url[18]; // 18 bytes: 1 byte for URL scheme + up to 17 bytes of URL
} __attribute__((packed)) m_eddystoneData;

}; // BLEEddystoneURL
Expand Down