Skip to content

Commit b8ea455

Browse files
PilnyTomasSuGlider
andauthored
Fix for negative temp in Eddystone TLM; solving #7618 (#7791)
* Changed data type of temperature * Changed data type in EddystoneTLM class and example * Revert "Changed data type in EddystoneTLM class and example" This reverts commit 1f3a941. * Draft of Eddystone TLM example * Adds MACROs to convert beacon temperature 2 Macros EDDYSTONE_TEMP_U16_TO_FLOAT(tempU16) - takes the TLM BigEndian 8.8 fixed point representation and returns its float value EDDYSTONE_TEMP_FLOAT_TO_U16(tempFloat) - takes a float (temperature) and returns its BigEndian 8.8 fixed point representation * Fixed temp * Changed to conform with PR comments * Fixed comment on closing bracket * Prints negative TEMP big endian as just 2 bytes * Extacts correct Eddyston Service Data * Fixes BLEEddystoneTLM::toString() negative temp * Fixes URL field length * Fixes Eddystone URL decoding * Fixes MSB for iBeacon UUID iBeacons use big endian BLE fields. * Fix to detect iBeacon that also has Service UUID This fix makes the BLE_iBeacon.ino to work correctly with the BLE_Beacon_Scanner.ino example --------- Co-authored-by: Rodrigo Garcia <rodrigo.garcia@espressif.com>
1 parent 23f653a commit b8ea455

File tree

6 files changed

+114
-99
lines changed

6 files changed

+114
-99
lines changed

libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino

+50-55
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
#include <BLEEddystoneTLM.h>
1515
#include <BLEBeacon.h>
1616

17-
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
18-
1917
int scanTime = 5; //In seconds
2018
BLEScan *pBLEScan;
2119

@@ -37,58 +35,66 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
3735
Serial.println(devUUID.toString().c_str());
3836
Serial.println("");
3937
}
40-
else
38+
39+
if (advertisedDevice.haveManufacturerData() == true)
4140
{
42-
if (advertisedDevice.haveManufacturerData() == true)
43-
{
44-
std::string strManufacturerData = advertisedDevice.getManufacturerData();
41+
std::string strManufacturerData = advertisedDevice.getManufacturerData();
4542

46-
uint8_t cManufacturerData[100];
47-
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
43+
uint8_t cManufacturerData[100];
44+
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
4845

49-
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
50-
{
51-
Serial.println("Found an iBeacon!");
52-
BLEBeacon oBeacon = BLEBeacon();
53-
oBeacon.setData(strManufacturerData);
54-
Serial.printf("iBeacon Frame\n");
55-
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());
56-
}
57-
else
46+
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
47+
{
48+
Serial.println("Found an iBeacon!");
49+
BLEBeacon oBeacon = BLEBeacon();
50+
oBeacon.setData(strManufacturerData);
51+
Serial.printf("iBeacon Frame\n");
52+
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());
53+
}
54+
else
55+
{
56+
Serial.println("Found another manufacturers beacon!");
57+
Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
58+
for (int i = 0; i < strManufacturerData.length(); i++)
5859
{
59-
Serial.println("Found another manufacturers beacon!");
60-
Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
61-
for (int i = 0; i < strManufacturerData.length(); i++)
62-
{
63-
Serial.printf("[%X]", cManufacturerData[i]);
64-
}
65-
Serial.printf("\n");
60+
Serial.printf("[%X]", cManufacturerData[i]);
6661
}
62+
Serial.printf("\n");
6763
}
68-
return;
6964
}
7065

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

73-
BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
74-
75-
if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
81+
if (payLoad < payLoadEnd) // Eddystone Service Data and respective BLE UUID were found
7682
{
77-
if (payLoad[11] == 0x10)
83+
if (*payLoad == 0x10)
7884
{
7985
Serial.println("Found an EddystoneURL beacon!");
8086
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
81-
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
82-
83-
foundEddyURL.setData(eddyContent);
87+
uint8_t URLLen = *(payLoad - 4) - 3; // Get Field Length less 3 bytes (type and UUID)
88+
foundEddyURL.setData(std::string((char*)payLoad, URLLen));
8489
std::string bareURL = foundEddyURL.getURL();
8590
if (bareURL[0] == 0x00)
8691
{
87-
size_t payLoadLen = advertisedDevice.getPayloadLength();
92+
// dumps all bytes in advertising payload
8893
Serial.println("DATA-->");
94+
uint8_t *payLoad = advertisedDevice.getPayload();
8995
for (int idx = 0; idx < payLoadLen; idx++)
9096
{
91-
Serial.printf("0x%08X ", payLoad[idx]);
97+
Serial.printf("0x%02X ", payLoad[idx]);
9298
}
9399
Serial.println("\nInvalid Data");
94100
return;
@@ -98,30 +104,19 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
98104
Serial.printf("Decoded URL: %s\n", foundEddyURL.getDecodedURL().c_str());
99105
Serial.printf("TX power %d\n", foundEddyURL.getPower());
100106
Serial.println("\n");
101-
}
102-
else if (payLoad[11] == 0x20)
107+
}
108+
else if (*payLoad == 0x20)
103109
{
104110
Serial.println("Found an EddystoneTLM beacon!");
105-
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
106-
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
107-
108-
eddyContent = "01234567890123";
109-
110-
for (int idx = 0; idx < 14; idx++)
111-
{
112-
eddyContent[idx] = payLoad[idx + 11];
113-
}
114-
115-
foundEddyURL.setData(eddyContent);
116-
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
117-
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
118-
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
119-
float calcTemp = temp / 256.0f;
120-
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
121-
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
122-
Serial.printf("Reported time since last reboot: %ds\n", foundEddyURL.getTime());
111+
112+
BLEEddystoneTLM eddystoneTLM;
113+
eddystoneTLM.setData(std::string((char*)payLoad, 14));
114+
Serial.printf("Reported battery voltage: %dmV\n", eddystoneTLM.getVolt());
115+
Serial.printf("Reported temperature: %.2f°C (raw data=0x%04X)\n", eddystoneTLM.getTemp(), eddystoneTLM.getRawTemp());
116+
Serial.printf("Reported advertise count: %d\n", eddystoneTLM.getCount());
117+
Serial.printf("Reported time since last reboot: %ds\n", eddystoneTLM.getTime());
123118
Serial.println("\n");
124-
Serial.print(foundEddyURL.toString().c_str());
119+
Serial.print(eddystoneTLM.toString().c_str());
125120
Serial.println("\n");
126121
}
127122
}

libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino

+10-12
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
5. Stop advertising.
1414
6. deep sleep
1515
16+
To read data advertised by this beacon use second ESP with example sketch BLE_Beacon_Scanner
1617
*/
1718
#include "sys/time.h"
1819

@@ -22,7 +23,7 @@
2223
#include "BLEUtils.h"
2324
#include "BLEBeacon.h"
2425
#include "BLEAdvertising.h"
25-
#include "BLEEddystoneURL.h"
26+
#include "BLEEddystoneTLM.h"
2627

2728
#include "esp_sleep.h"
2829

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

5657
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
5758
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
@@ -82,13 +83,11 @@ void setBeacon()
8283

8384
void setup()
8485
{
85-
8686
Serial.begin(115200);
8787
gettimeofday(&nowTimeStruct, NULL);
8888

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

9392
last = nowTimeStruct.tv_sec;
9493
lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter
@@ -103,12 +102,11 @@ void setup()
103102
setBeacon();
104103
// Start advertising
105104
pAdvertising->start();
106-
Serial.println("Advertizing started for 10s ...");
105+
Serial.println("Advertising started for 10s ...");
107106
delay(10000);
108107
pAdvertising->stop();
109-
Serial.printf("enter deep sleep for 10s\n");
108+
Serial.printf("Enter deep sleep for 10s\n");
110109
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
111-
Serial.printf("in deep sleep\n");
112110
}
113111

114112
void loop()

libraries/BLE/src/BLEBeacon.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ uint16_t BLEBeacon::getMinor() {
4040
}
4141

4242
BLEUUID BLEBeacon::getProximityUUID() {
43-
return BLEUUID(m_beaconData.proximityUUID, 16, false);
43+
return BLEUUID(m_beaconData.proximityUUID, 16, true);
4444
}
4545

4646
int8_t BLEBeacon::getSignalPower() {

libraries/BLE/src/BLEEddystoneTLM.cpp

+22-5
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@
1717
#include "BLEEddystoneTLM.h"
1818

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

2321
BLEEddystoneTLM::BLEEddystoneTLM() {
2422
beaconUUID = 0xFEAA;
@@ -47,9 +45,13 @@ uint16_t BLEEddystoneTLM::getVolt() {
4745
} // getVolt
4846

4947
float BLEEddystoneTLM::getTemp() {
50-
return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f;
48+
return EDDYSTONE_TEMP_U16_TO_FLOAT(m_eddystoneData.temp);
5149
} // getTemp
5250

51+
uint16_t BLEEddystoneTLM::getRawTemp() {
52+
return ENDIAN_CHANGE_U16(m_eddystoneData.temp);
53+
} // getRawTemp
54+
5355
uint32_t BLEEddystoneTLM::getCount() {
5456
return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
5557
} // getCount
@@ -73,7 +75,7 @@ std::string BLEEddystoneTLM::toString() {
7375
out += " mV\n";
7476

7577
out += "Temperature ";
76-
snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
78+
snprintf(val, sizeof(val), "%.2f", ((int16_t)ENDIAN_CHANGE_U16(m_eddystoneData.temp)) / 256.0f);
7779
out += val;
7880
out += " C\n";
7981

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

111113
/**
112114
* Set the raw data for the beacon record.
115+
* Example:
116+
* uint8_t *payLoad = advertisedDevice.getPayload();
117+
* eddystoneTLM.setData(std::string((char*)payLoad+22, advertisedDevice.getPayloadLength() - 22));
118+
* Note: the offset 22 works for current implementation of example BLE_EddystoneTLM Beacon.ino, however it is not static and will be reimplemented
119+
* Data frame:
120+
* | Field || Len | Type | UUID | EddyStone TLM |
121+
* | Offset || 0 | 1 | 2 | 4 |
122+
* | Len || 1 B | 1 B | 2 B | 14 B |
123+
* | Data || ?? | ?? | 0xAA | 0xFE | ??? |
124+
*
125+
* EddyStone TLM frame:
126+
* | Field || Type | Version | Batt mV | Beacon temp | Cnt since boot | Time since boot |
127+
* | Offset || 0 | 1 | 2 | 4 | 6 | 10 |
128+
* | Len || 1 B | 1 B | 2 B | 2 B | 4 B | 4 B |
129+
* | Data || 0x20 | ?? | ?? | ?? | ?? | ?? | | | | | | | | |
113130
*/
114131
void BLEEddystoneTLM::setData(std::string data) {
115132
if (data.length() != sizeof(m_eddystoneData)) {
@@ -132,7 +149,7 @@ void BLEEddystoneTLM::setVolt(uint16_t volt) {
132149
} // setVolt
133150

134151
void BLEEddystoneTLM::setTemp(float temp) {
135-
m_eddystoneData.temp = (uint16_t)temp;
152+
m_eddystoneData.temp = EDDYSTONE_TEMP_FLOAT_TO_U16(temp);
136153
} // setTemp
137154

138155
void BLEEddystoneTLM::setCount(uint32_t advCount) {

libraries/BLE/src/BLEEddystoneTLM.h

+30-25
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include "BLEUUID.h"
1111

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

1418
/**
1519
* @brief Representation of a beacon.
@@ -18,33 +22,34 @@
1822
*/
1923
class BLEEddystoneTLM {
2024
public:
21-
BLEEddystoneTLM();
22-
std::string getData();
23-
BLEUUID getUUID();
24-
uint8_t getVersion();
25-
uint16_t getVolt();
26-
float getTemp();
27-
uint32_t getCount();
28-
uint32_t getTime();
29-
std::string toString();
30-
void setData(std::string data);
31-
void setUUID(BLEUUID l_uuid);
32-
void setVersion(uint8_t version);
33-
void setVolt(uint16_t volt);
34-
void setTemp(float temp);
35-
void setCount(uint32_t advCount);
36-
void setTime(uint32_t tmil);
25+
BLEEddystoneTLM();
26+
std::string getData();
27+
BLEUUID getUUID();
28+
uint8_t getVersion();
29+
uint16_t getVolt();
30+
float getTemp();
31+
uint16_t getRawTemp();
32+
uint32_t getCount();
33+
uint32_t getTime();
34+
std::string toString();
35+
void setData(std::string data);
36+
void setUUID(BLEUUID l_uuid);
37+
void setVersion(uint8_t version);
38+
void setVolt(uint16_t volt);
39+
void setTemp(float temp);
40+
void setCount(uint32_t advCount);
41+
void setTime(uint32_t tmil);
3742

3843
private:
39-
uint16_t beaconUUID;
40-
struct {
41-
uint8_t frameType;
42-
uint8_t version;
43-
uint16_t volt;
44-
uint16_t temp;
45-
uint32_t advCount;
46-
uint32_t tmil;
47-
} __attribute__((packed)) m_eddystoneData;
44+
uint16_t beaconUUID;
45+
struct {
46+
uint8_t frameType;
47+
uint8_t version;
48+
uint16_t volt;
49+
uint16_t temp;
50+
uint32_t advCount;
51+
uint32_t tmil;
52+
} __attribute__((packed)) m_eddystoneData;
4853

4954
}; // BLEEddystoneTLM
5055

libraries/BLE/src/BLEEddystoneURL.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class BLEEddystoneURL {
3535
struct {
3636
uint8_t frameType;
3737
int8_t advertisedTxPower;
38-
uint8_t url[16];
38+
uint8_t url[18]; // 18 bytes: 1 byte for URL scheme + up to 17 bytes of URL
3939
} __attribute__((packed)) m_eddystoneData;
4040

4141
}; // BLEEddystoneURL

0 commit comments

Comments
 (0)