未验证 提交 b8ea455f 编写于 作者: T Tomáš Pilný 提交者: GitHub

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 1f3a9414ee13341f80bd6d51cdbd57254aadfe97.

* 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: NRodrigo Garcia <rodrigo.garcia@espressif.com>
上级 23f653ad
...@@ -14,8 +14,6 @@ ...@@ -14,8 +14,6 @@
#include <BLEEddystoneTLM.h> #include <BLEEddystoneTLM.h>
#include <BLEBeacon.h> #include <BLEBeacon.h>
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
int scanTime = 5; //In seconds int scanTime = 5; //In seconds
BLEScan *pBLEScan; BLEScan *pBLEScan;
...@@ -37,8 +35,7 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks ...@@ -37,8 +35,7 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
Serial.println(devUUID.toString().c_str()); Serial.println(devUUID.toString().c_str());
Serial.println(""); Serial.println("");
} }
else
{
if (advertisedDevice.haveManufacturerData() == true) if (advertisedDevice.haveManufacturerData() == true)
{ {
std::string strManufacturerData = advertisedDevice.getManufacturerData(); std::string strManufacturerData = advertisedDevice.getManufacturerData();
...@@ -65,30 +62,39 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks ...@@ -65,30 +62,39 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
Serial.printf("\n"); Serial.printf("\n");
} }
} }
return;
}
uint8_t *payLoad = advertisedDevice.getPayload(); 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 (payLoad < payLoadEnd) // Eddystone Service Data and respective BLE UUID were found
if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
{ {
if (payLoad[11] == 0x10) if (*payLoad == 0x10)
{ {
Serial.println("Found an EddystoneURL beacon!"); Serial.println("Found an EddystoneURL beacon!");
BLEEddystoneURL foundEddyURL = BLEEddystoneURL(); BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct! uint8_t URLLen = *(payLoad - 4) - 3; // Get Field Length less 3 bytes (type and UUID)
foundEddyURL.setData(std::string((char*)payLoad, URLLen));
foundEddyURL.setData(eddyContent);
std::string bareURL = foundEddyURL.getURL(); std::string bareURL = foundEddyURL.getURL();
if (bareURL[0] == 0x00) if (bareURL[0] == 0x00)
{ {
size_t payLoadLen = advertisedDevice.getPayloadLength(); // dumps all bytes in advertising payload
Serial.println("DATA-->"); Serial.println("DATA-->");
uint8_t *payLoad = advertisedDevice.getPayload();
for (int idx = 0; idx < payLoadLen; idx++) for (int idx = 0; idx < payLoadLen; idx++)
{ {
Serial.printf("0x%08X ", payLoad[idx]); Serial.printf("0x%02X ", payLoad[idx]);
} }
Serial.println("\nInvalid Data"); Serial.println("\nInvalid Data");
return; return;
...@@ -99,29 +105,18 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks ...@@ -99,29 +105,18 @@ class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
Serial.printf("TX power %d\n", foundEddyURL.getPower()); Serial.printf("TX power %d\n", foundEddyURL.getPower());
Serial.println("\n"); Serial.println("\n");
} }
else if (payLoad[11] == 0x20) else if (*payLoad == 0x20)
{ {
Serial.println("Found an EddystoneTLM beacon!"); Serial.println("Found an EddystoneTLM beacon!");
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
eddyContent = "01234567890123";
for (int idx = 0; idx < 14; idx++)
{
eddyContent[idx] = payLoad[idx + 11];
}
foundEddyURL.setData(eddyContent); BLEEddystoneTLM eddystoneTLM;
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt()); eddystoneTLM.setData(std::string((char*)payLoad, 14));
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp()); Serial.printf("Reported battery voltage: %dmV\n", eddystoneTLM.getVolt());
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8); Serial.printf("Reported temperature: %.2f°C (raw data=0x%04X)\n", eddystoneTLM.getTemp(), eddystoneTLM.getRawTemp());
float calcTemp = temp / 256.0f; Serial.printf("Reported advertise count: %d\n", eddystoneTLM.getCount());
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp); Serial.printf("Reported time since last reboot: %ds\n", eddystoneTLM.getTime());
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
Serial.printf("Reported time since last reboot: %ds\n", foundEddyURL.getTime());
Serial.println("\n"); Serial.println("\n");
Serial.print(foundEddyURL.toString().c_str()); Serial.print(eddystoneTLM.toString().c_str());
Serial.println("\n"); Serial.println("\n");
} }
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
5. Stop advertising. 5. Stop advertising.
6. deep sleep 6. deep sleep
To read data advertised by this beacon use second ESP with example sketch BLE_Beacon_Scanner
*/ */
#include "sys/time.h" #include "sys/time.h"
...@@ -22,7 +23,7 @@ ...@@ -22,7 +23,7 @@
#include "BLEUtils.h" #include "BLEUtils.h"
#include "BLEBeacon.h" #include "BLEBeacon.h"
#include "BLEAdvertising.h" #include "BLEAdvertising.h"
#include "BLEEddystoneURL.h" #include "BLEEddystoneTLM.h"
#include "esp_sleep.h" #include "esp_sleep.h"
...@@ -48,10 +49,10 @@ void setBeacon() ...@@ -48,10 +49,10 @@ void setBeacon()
char beacon_data[25]; char beacon_data[25];
uint16_t beconUUID = 0xFEAA; uint16_t beconUUID = 0xFEAA;
uint16_t volt = random(2800, 3700); // 3300mV = 3.3V uint16_t volt = random(2800, 3700); // 3300mV = 3.3V
float tempFloat = random(2000, 3100) / 100.0f; float tempFloat = random(-3000, 3000) / 100.0f;
Serial.printf("Random temperature is %.2fC\n", tempFloat); Serial.printf("Random temperature is %.2f°C\n", tempFloat);
int temp = (int)(tempFloat * 256); //(uint16_t)((float)23.00); int temp = (int)(tempFloat * 256);
Serial.printf("Converted to 8.8 format %0X%0X\n", (temp >> 8), (temp & 0xFF)); Serial.printf("Converted to 8.8 format %0X%0X\n", (temp >> 8) & 0xFF, (temp & 0xFF));
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
...@@ -82,13 +83,11 @@ void setBeacon() ...@@ -82,13 +83,11 @@ void setBeacon()
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(115200);
gettimeofday(&nowTimeStruct, NULL); gettimeofday(&nowTimeStruct, NULL);
Serial.printf("start ESP32 %d\n", bootcount++); 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);
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", nowTimeStruct.tv_sec, nowTimeStruct.tv_sec - last);
last = nowTimeStruct.tv_sec; last = nowTimeStruct.tv_sec;
lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter
...@@ -103,12 +102,11 @@ void setup() ...@@ -103,12 +102,11 @@ void setup()
setBeacon(); setBeacon();
// Start advertising // Start advertising
pAdvertising->start(); pAdvertising->start();
Serial.println("Advertizing started for 10s ..."); Serial.println("Advertising started for 10s ...");
delay(10000); delay(10000);
pAdvertising->stop(); 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); esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
Serial.printf("in deep sleep\n");
} }
void loop() void loop()
......
...@@ -40,7 +40,7 @@ uint16_t BLEBeacon::getMinor() { ...@@ -40,7 +40,7 @@ uint16_t BLEBeacon::getMinor() {
} }
BLEUUID BLEBeacon::getProximityUUID() { BLEUUID BLEBeacon::getProximityUUID() {
return BLEUUID(m_beaconData.proximityUUID, 16, false); return BLEUUID(m_beaconData.proximityUUID, 16, true);
} }
int8_t BLEBeacon::getSignalPower() { int8_t BLEBeacon::getSignalPower() {
......
...@@ -17,8 +17,6 @@ ...@@ -17,8 +17,6 @@
#include "BLEEddystoneTLM.h" #include "BLEEddystoneTLM.h"
static const char LOG_TAG[] = "BLEEddystoneTLM"; 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() { BLEEddystoneTLM::BLEEddystoneTLM() {
beaconUUID = 0xFEAA; beaconUUID = 0xFEAA;
...@@ -47,9 +45,13 @@ uint16_t BLEEddystoneTLM::getVolt() { ...@@ -47,9 +45,13 @@ uint16_t BLEEddystoneTLM::getVolt() {
} // getVolt } // getVolt
float BLEEddystoneTLM::getTemp() { float BLEEddystoneTLM::getTemp() {
return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f; return EDDYSTONE_TEMP_U16_TO_FLOAT(m_eddystoneData.temp);
} // getTemp } // getTemp
uint16_t BLEEddystoneTLM::getRawTemp() {
return ENDIAN_CHANGE_U16(m_eddystoneData.temp);
} // getRawTemp
uint32_t BLEEddystoneTLM::getCount() { uint32_t BLEEddystoneTLM::getCount() {
return ENDIAN_CHANGE_U32(m_eddystoneData.advCount); return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
} // getCount } // getCount
...@@ -73,7 +75,7 @@ std::string BLEEddystoneTLM::toString() { ...@@ -73,7 +75,7 @@ std::string BLEEddystoneTLM::toString() {
out += " mV\n"; out += " mV\n";
out += "Temperature "; 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 += val;
out += " C\n"; out += " C\n";
...@@ -110,6 +112,21 @@ std::string BLEEddystoneTLM::toString() { ...@@ -110,6 +112,21 @@ std::string BLEEddystoneTLM::toString() {
/** /**
* Set the raw data for the beacon record. * 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) { void BLEEddystoneTLM::setData(std::string data) {
if (data.length() != sizeof(m_eddystoneData)) { if (data.length() != sizeof(m_eddystoneData)) {
...@@ -132,7 +149,7 @@ void BLEEddystoneTLM::setVolt(uint16_t volt) { ...@@ -132,7 +149,7 @@ void BLEEddystoneTLM::setVolt(uint16_t volt) {
} // setVolt } // setVolt
void BLEEddystoneTLM::setTemp(float temp) { void BLEEddystoneTLM::setTemp(float temp) {
m_eddystoneData.temp = (uint16_t)temp; m_eddystoneData.temp = EDDYSTONE_TEMP_FLOAT_TO_U16(temp);
} // setTemp } // setTemp
void BLEEddystoneTLM::setCount(uint32_t advCount) { void BLEEddystoneTLM::setCount(uint32_t advCount) {
......
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#include "BLEUUID.h" #include "BLEUUID.h"
#define EDDYSTONE_TLM_FRAME_TYPE 0x20 #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. * @brief Representation of a beacon.
...@@ -24,6 +28,7 @@ public: ...@@ -24,6 +28,7 @@ public:
uint8_t getVersion(); uint8_t getVersion();
uint16_t getVolt(); uint16_t getVolt();
float getTemp(); float getTemp();
uint16_t getRawTemp();
uint32_t getCount(); uint32_t getCount();
uint32_t getTime(); uint32_t getTime();
std::string toString(); std::string toString();
......
...@@ -35,7 +35,7 @@ private: ...@@ -35,7 +35,7 @@ private:
struct { struct {
uint8_t frameType; uint8_t frameType;
int8_t advertisedTxPower; 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; } __attribute__((packed)) m_eddystoneData;
}; // BLEEddystoneURL }; // BLEEddystoneURL
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册