From 04004927e2ac2b0328adef0c34c30231a7d06f93 Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Fri, 20 Mar 2020 14:35:07 +0800
Subject: [PATCH 1/2] Fix issue #3833, data parsing of Eddystone TLM data frame
 Add Beacon scanner example to show usage of BLEEddystoneTLM class and 
 BLEEddystoneURL class Add EddystoneTLM beacon example Add EddystoneURL beacon
 example

---
 .../BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino | 153 ++++++++++++++
 .../BLE_Beacon_Scanner/BLE_Beacon_Scanner.md  |   9 +
 .../BLE_EddystoneTLM_Beacon.ino               | 116 +++++++++++
 .../BLE_EddystoneTLM_Beacon.md                |  14 ++
 .../BLE_EddystoneURL_Beacon.ino               | 192 ++++++++++++++++++
 .../BLE_EddystoneURL_Beacon.md                |  14 ++
 libraries/BLE/src/BLEEddystoneTLM.cpp         |  32 ++-
 7 files changed, 521 insertions(+), 9 deletions(-)
 create mode 100644 libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
 create mode 100644 libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.md
 create mode 100644 libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino
 create mode 100644 libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.md
 create mode 100644 libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.ino
 create mode 100644 libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.md

diff --git a/libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino b/libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
new file mode 100644
index 00000000000..b46baa7c84e
--- /dev/null
+++ b/libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
@@ -0,0 +1,153 @@
+/*
+   Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
+   Ported to Arduino ESP32 by Evandro Copercini
+   Changed to a beacon scanner to report iBeacon, EddystoneURL and EddystoneTLM beacons by beegee-tokyo
+*/
+
+#include <Arduino.h>
+
+#include <BLEDevice.h>
+#include <BLEUtils.h>
+#include <BLEScan.h>
+#include <BLEAdvertisedDevice.h>
+#include <BLEEddystoneURL.h>
+#include <BLEEddystoneTLM.h>
+#include <BLEBeacon.h>
+
+#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
+
+int scanTime = 5; //In seconds
+BLEScan *pBLEScan;
+
+class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
+{
+    void onResult(BLEAdvertisedDevice advertisedDevice)
+    {
+      if (advertisedDevice.haveName())
+      {
+        Serial.print("Device name: ");
+        Serial.println(advertisedDevice.getName().c_str());
+        Serial.println("");
+      }
+
+      if (advertisedDevice.haveServiceUUID())
+      {
+        BLEUUID devUUID = advertisedDevice.getServiceUUID();
+        Serial.print("Found ServiceUUID: ");
+        Serial.println(devUUID.toString().c_str());
+        Serial.println("");
+      }
+      else
+      {
+        if (advertisedDevice.haveManufacturerData() == true)
+        {
+          std::string strManufacturerData = advertisedDevice.getManufacturerData();
+
+          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
+          {
+            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");
+          }
+        }
+        return;
+      }
+
+      uint8_t *payLoad = advertisedDevice.getPayload();
+
+      BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
+
+      if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
+      {
+        if (payLoad[11] == 0x10)
+        {
+          Serial.println("Found an EddystoneURL beacon!");
+          BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
+          std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
+
+          foundEddyURL.setData(eddyContent);
+          std::string bareURL = foundEddyURL.getURL();
+          if (bareURL[0] == 0x00)
+          {
+            size_t payLoadLen = advertisedDevice.getPayloadLength();
+            Serial.println("DATA-->");
+            for (int idx = 0; idx < payLoadLen; idx++)
+            {
+              Serial.printf("0x%08X ", payLoad[idx]);
+            }
+            Serial.println("\nInvalid Data");
+            return;
+          }
+
+          Serial.printf("Found URL: %s\n", foundEddyURL.getURL().c_str());
+          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)
+        {
+          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);
+          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);
+          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());
+          Serial.println("\n");
+          Serial.print(foundEddyURL.toString().c_str());
+          Serial.println("\n");
+        }
+      }
+    }
+};
+
+void setup()
+{
+  Serial.begin(115200);
+  Serial.println("Scanning...");
+
+  BLEDevice::init("");
+  pBLEScan = BLEDevice::getScan(); //create new scan
+  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
+  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
+  pBLEScan->setInterval(100);
+  pBLEScan->setWindow(99); // less or equal setInterval value
+}
+
+void loop()
+{
+  // put your main code here, to run repeatedly:
+  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
+  Serial.print("Devices found: ");
+  Serial.println(foundDevices.getCount());
+  Serial.println("Scan done!");
+  pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
+  delay(2000);
+}
diff --git a/libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.md b/libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.md
new file mode 100644
index 00000000000..558c3e7aec0
--- /dev/null
+++ b/libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.md
@@ -0,0 +1,9 @@
+## BLE Beacon Scanner
+
+Initiates a BLE device scan.
+Checks if the discovered devices are 
+- an iBeacon
+- an Eddystone TLM beacon
+- an Eddystone URL beacon
+
+and sends the decoded beacon information over Serial log
\ No newline at end of file
diff --git a/libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino b/libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino
new file mode 100644
index 00000000000..96be28cd588
--- /dev/null
+++ b/libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.ino
@@ -0,0 +1,116 @@
+/*
+   EddystoneTLM beacon by BeeGee based on https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino
+   EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
+*/
+
+/*
+   Create a BLE server that will send periodic Eddystone URL frames.
+   The design of creating the BLE server is:
+   1. Create a BLE Server
+   2. Create advertising data
+   3. Start advertising.
+   4. wait
+   5. Stop advertising.
+   6. deep sleep
+   
+*/
+#include "sys/time.h"
+
+#include <Arduino.h>
+
+#include "BLEDevice.h"
+#include "BLEUtils.h"
+#include "BLEBeacon.h"
+#include "BLEAdvertising.h"
+#include "BLEEddystoneURL.h"
+
+#include "esp_sleep.h"
+
+#define GPIO_DEEP_SLEEP_DURATION 10     // sleep x seconds and then wake up
+RTC_DATA_ATTR static time_t last;    // remember last boot in RTC Memory
+RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
+
+// See the following for generating UUIDs:
+// https://www.uuidgenerator.net/
+BLEAdvertising *pAdvertising;
+struct timeval nowTimeStruct;
+
+time_t lastTenth;
+
+#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
+
+// Check
+// https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
+// and http://www.hugi.scene.org/online/coding/hugi%2015%20-%20cmtadfix.htm
+// for the temperature value. It is a 8.8 fixed-point notation
+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));
+
+  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
+  BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
+
+  oScanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
+  oScanResponseData.setCompleteServices(BLEUUID(beconUUID));
+
+  beacon_data[0] = 0x20;                // Eddystone Frame Type (Unencrypted Eddystone-TLM)
+  beacon_data[1] = 0x00;                // TLM version
+  beacon_data[2] = (volt >> 8);           // Battery voltage, 1 mV/bit i.e. 0xCE4 = 3300mV = 3.3V
+  beacon_data[3] = (volt & 0xFF);           //
+  beacon_data[4] = (temp >> 8);           // Beacon temperature
+  beacon_data[5] = (temp & 0xFF);           //
+  beacon_data[6] = ((bootcount & 0xFF000000) >> 24);  // Advertising PDU count
+  beacon_data[7] = ((bootcount & 0xFF0000) >> 16);  //
+  beacon_data[8] = ((bootcount & 0xFF00) >> 8);   //
+  beacon_data[9] = (bootcount & 0xFF);        //
+  beacon_data[10] = ((lastTenth & 0xFF000000) >> 24); // Time since power-on or reboot as 0.1 second resolution counter
+  beacon_data[11] = ((lastTenth & 0xFF0000) >> 16);   //
+  beacon_data[12] = ((lastTenth & 0xFF00) >> 8);    //
+  beacon_data[13] = (lastTenth & 0xFF);       //
+
+  oScanResponseData.setServiceData(BLEUUID(beconUUID), std::string(beacon_data, 14));
+  oAdvertisementData.setName("TLMBeacon");
+  pAdvertising->setAdvertisementData(oAdvertisementData);
+  pAdvertising->setScanResponseData(oScanResponseData);
+}
+
+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);
+
+  last = nowTimeStruct.tv_sec;
+  lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter
+
+  // Create the BLE Device
+  BLEDevice::init("TLMBeacon");
+
+  BLEDevice::setPower(ESP_PWR_LVL_N12);
+
+  pAdvertising = BLEDevice::getAdvertising();
+
+  setBeacon();
+  // Start advertising
+  pAdvertising->start();
+  Serial.println("Advertizing started for 10s ...");
+  delay(10000);
+  pAdvertising->stop();
+  Serial.printf("enter deep sleep for 10s\n");
+  esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
+  Serial.printf("in deep sleep\n");
+}
+
+void loop()
+{
+}
diff --git a/libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.md b/libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.md
new file mode 100644
index 00000000000..2e34029d197
--- /dev/null
+++ b/libraries/BLE/examples/BLE_EddystoneTLM_Beacon/BLE_EddystoneTLM_Beacon.md
@@ -0,0 +1,14 @@
+## Eddystone TLM beacon
+EddystoneTLM beacon by BeeGee based on
+[pcbreflux ESP32 Eddystone TLM deepsleep](https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino)
+
+[EddystoneTLM frame specification](https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md)
+
+   Create a BLE server that will send periodic Eddystone TLM frames.
+   The design of creating the BLE server is:
+   1. Create a BLE Server
+   2. Create advertising data
+   3. Start advertising.
+   4. wait
+   5. Stop advertising.
+   6. deep sleep
diff --git a/libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.ino b/libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.ino
new file mode 100644
index 00000000000..335ea1ffbe6
--- /dev/null
+++ b/libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.ino
@@ -0,0 +1,192 @@
+/*
+   EddystoneURL beacon by BeeGee
+   EddystoneURL frame specification https://github.com/google/eddystone/blob/master/eddystone-url/README.md
+
+*/
+
+/*
+   Create a BLE server that will send periodic Eddystone URL frames.
+   The design of creating the BLE server is:
+   1. Create a BLE Server
+   2. Create advertising data
+   3. Start advertising.
+   4. wait
+   5. Stop advertising.
+   6. deep sleep
+
+*/
+#include "sys/time.h"
+
+#include <Arduino.h>
+
+#include "BLEDevice.h"
+#include "BLEUtils.h"
+#include "BLEBeacon.h"
+#include "BLEAdvertising.h"
+#include "BLEEddystoneURL.h"
+
+#include "esp_sleep.h"
+
+#define GPIO_DEEP_SLEEP_DURATION 10     // sleep x seconds and then wake up
+RTC_DATA_ATTR static time_t last;    // remember last boot in RTC Memory
+RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
+
+// See the following for generating UUIDs:
+// https://www.uuidgenerator.net/
+BLEAdvertising *pAdvertising;
+struct timeval now;
+
+#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
+
+static const char *eddystone_url_prefix_subs[] = {
+  "http://www.",
+  "https://www.",
+  "http://",
+  "https://",
+  "urn:uuid:",
+  NULL
+};
+
+static const char *eddystone_url_suffix_subs[] = {
+  ".com/",
+  ".org/",
+  ".edu/",
+  ".net/",
+  ".info/",
+  ".biz/",
+  ".gov/",
+  ".com",
+  ".org",
+  ".edu",
+  ".net",
+  ".info",
+  ".biz",
+  ".gov",
+  NULL
+};
+
+static int string_begin_with(const char *str, const char *prefix)
+{
+  int prefix_len = strlen(prefix);
+  if (strncmp(prefix, str, prefix_len) == 0)
+  {
+    return prefix_len;
+  }
+  return 0;
+}
+
+void setBeacon()
+{
+  BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
+  BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
+
+  const char url[] = "https://d.giesecke.tk";
+
+  int scheme_len, ext_len = 1, i, idx, url_idx;
+  char *ret_data;
+  int url_len = strlen(url);
+
+  ret_data = (char *)calloc(1, url_len + 13);
+
+  ret_data[0] = 2;   // Len
+  ret_data[1] = 0x01;  // Type Flags
+  ret_data[2] = 0x06;  // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
+  ret_data[3] = 3;   // Len
+  ret_data[4] = 0x03;  // Type 16-Bit UUID
+  ret_data[5] = 0xAA;  // Eddystone UUID 2 -> 0xFEAA LSB
+  ret_data[6] = 0xFE;  // Eddystone UUID 1 MSB
+  ret_data[7] = 19; // Length of Beacon Data
+  ret_data[8] = 0x16;  // Type Service Data
+  ret_data[9] = 0xAA;  // Eddystone UUID 2 -> 0xFEAA LSB
+  ret_data[10] = 0xFE; // Eddystone UUID 1 MSB
+  ret_data[11] = 0x10; // Eddystone Frame Type
+  ret_data[12] = 0xF4; // Beacons TX power at 0m
+
+  i = 0, idx = 13, url_idx = 0;
+
+  //replace prefix
+  scheme_len = 0;
+  while (eddystone_url_prefix_subs[i] != NULL)
+  {
+    if ((scheme_len = string_begin_with(url, eddystone_url_prefix_subs[i])) > 0)
+    {
+      ret_data[idx] = i;
+      idx++;
+      url_idx += scheme_len;
+      break;
+    }
+    i++;
+  }
+  while (url_idx < url_len)
+  {
+    i = 0;
+    ret_data[idx] = url[url_idx];
+    ext_len = 1;
+    while (eddystone_url_suffix_subs[i] != NULL)
+    {
+      if ((ext_len = string_begin_with(&url[url_idx], eddystone_url_suffix_subs[i])) > 0)
+      {
+        ret_data[idx] = i;
+        break;
+      }
+      else
+      {
+        ext_len = 1; //inc 1
+      }
+      i++;
+    }
+    url_idx += ext_len;
+    idx++;
+  }
+  ret_data[7] = idx - 8;
+
+  Serial.printf("struct size %d url size %d reported len %d\n",
+                url_len + 13,
+                url_len, ret_data[7]);
+
+  Serial.printf("URL in data %s\n", &ret_data[13]);
+
+  std::string eddyStoneData(ret_data);
+
+  oAdvertisementData.addData(eddyStoneData);
+  oScanResponseData.setName("URLBeacon");
+  pAdvertising->setAdvertisementData(oAdvertisementData);
+  pAdvertising->setScanResponseData(oScanResponseData);
+}
+
+void setup()
+{
+
+  Serial.begin(115200);
+  gettimeofday(&now, NULL);
+
+  Serial.printf("start ESP32 %d\n", bootcount++);
+
+  Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", now.tv_sec, now.tv_sec - last);
+
+  last = now.tv_sec;
+
+  // Create the BLE Device
+  BLEDevice::init("URLBeacon");
+
+  BLEDevice::setPower(ESP_PWR_LVL_N12);
+
+  // Create the BLE Server
+  // BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage
+
+  pAdvertising = BLEDevice::getAdvertising();
+
+  setBeacon();
+  // Start advertising
+  pAdvertising->start();
+  Serial.println("Advertizing started...");
+  delay(10000);
+  pAdvertising->stop();
+  Serial.printf("enter deep sleep\n");
+  esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
+  Serial.printf("in deep sleep\n");
+}
+
+void loop()
+{
+}
diff --git a/libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.md b/libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.md
new file mode 100644
index 00000000000..2baf1cc526f
--- /dev/null
+++ b/libraries/BLE/examples/BLE_EddystoneURL_Beacon/BLE_EddystoneURL_Beacon.md
@@ -0,0 +1,14 @@
+## Eddystone URL beacon
+EddystoneURL beacon by BeeGee based on
+[pcbreflux ESP32 Eddystone URL deepsleep](https://github.com/pcbreflux/espressif/tree/master/esp32/arduino/sketchbook/ESP32_Eddystone_URL_deepsleep)
+
+[EddystoneURL frame specification](https://github.com/google/eddystone/blob/master/eddystone-url/README.md)
+
+   Create a BLE server that will send periodic Eddystone URL frames.
+   The design of creating the BLE server is:
+   1. Create a BLE Server
+   2. Create advertising data
+   3. Start advertising.
+   4. wait
+   5. Stop advertising.
+   6. deep sleep
diff --git a/libraries/BLE/src/BLEEddystoneTLM.cpp b/libraries/BLE/src/BLEEddystoneTLM.cpp
index 1ab794932e2..a45fa21cccf 100644
--- a/libraries/BLE/src/BLEEddystoneTLM.cpp
+++ b/libraries/BLE/src/BLEEddystoneTLM.cpp
@@ -3,6 +3,11 @@
  *
  *  Created on: Mar 12, 2018
  *      Author: pcbreflux
+ *  Edited on: Mar 20, 2020 by beegee-tokyo
+ *  Fix temperature value (8.8 fixed format)
+ *  Fix time stamp (0.1 second resolution)
+ *  Fixes based on EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
+ * 
  */
 #include "sdkconfig.h"
 #if defined(CONFIG_BT_ENABLED)
@@ -20,7 +25,7 @@ BLEEddystoneTLM::BLEEddystoneTLM() {
 	m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE;
 	m_eddystoneData.version = 0;
 	m_eddystoneData.volt = 3300; // 3300mV = 3.3V
-	m_eddystoneData.temp = (uint16_t) ((float) 23.00);
+	m_eddystoneData.temp = (uint16_t) ((float) 23.00)/256;
 	m_eddystoneData.advCount = 0;
 	m_eddystoneData.tmil = 0;
 } // BLEEddystoneTLM
@@ -38,19 +43,19 @@ uint8_t BLEEddystoneTLM::getVersion() {
 } // getVersion
 
 uint16_t BLEEddystoneTLM::getVolt() {
-	return m_eddystoneData.volt;
+	return ENDIAN_CHANGE_U16(m_eddystoneData.volt);
 } // getVolt
 
 float BLEEddystoneTLM::getTemp() {
-	return (float)m_eddystoneData.temp;
+	return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f;
 } // getTemp
 
 uint32_t BLEEddystoneTLM::getCount() {
-	return m_eddystoneData.advCount;
+	return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
 } // getCount
 
 uint32_t BLEEddystoneTLM::getTime() {
-	return m_eddystoneData.tmil;
+	return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10;
 } // getTime
 
 std::string BLEEddystoneTLM::toString() {
@@ -58,21 +63,30 @@ std::string BLEEddystoneTLM::toString() {
   uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
   char val[6];
 
-  out += "Version " + m_eddystoneData.version;
+  out += "Version "; // + std::string(m_eddystoneData.version);
+  snprintf(val, sizeof(val), "%d", m_eddystoneData.version);
+  out += val;
   out += "\n";
-  out += "Battery Voltage " + ENDIAN_CHANGE_U16(m_eddystoneData.volt);
+  out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt);
+  snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt));
+  out += val;
   out += " mV\n";
 
   out += "Temperature ";
-  snprintf(val, sizeof(val), "%d", m_eddystoneData.temp);
+  snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
   out += val;
-  out += ".0 °C\n";
+  out += " C\n";
 
   out += "Adv. Count ";
   snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
   out += val;
   out += "\n";
 
+  out += "Time in seconds ";
+  snprintf(val, sizeof(val), "%d", rawsec/10);
+  out += val;
+  out += "\n";
+
   out += "Time ";
 
   snprintf(val, sizeof(val), "%04d", rawsec / 864000);

From 1fa29cf72af9faefc8d538d39e3d3325fcd8d51c Mon Sep 17 00:00:00 2001
From: Bernd Giesecke <bernd@giesecke.tk>
Date: Mon, 23 Mar 2020 17:52:44 +0800
Subject: [PATCH 2/2] Fix buffer size for .toString()

---
 libraries/BLE/src/BLEEddystoneTLM.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libraries/BLE/src/BLEEddystoneTLM.cpp b/libraries/BLE/src/BLEEddystoneTLM.cpp
index a45fa21cccf..accc4db1bb3 100644
--- a/libraries/BLE/src/BLEEddystoneTLM.cpp
+++ b/libraries/BLE/src/BLEEddystoneTLM.cpp
@@ -61,7 +61,7 @@ uint32_t BLEEddystoneTLM::getTime() {
 std::string BLEEddystoneTLM::toString() {
   std::string out = "";
   uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
-  char val[6];
+  char val[12];
 
   out += "Version "; // + std::string(m_eddystoneData.version);
   snprintf(val, sizeof(val), "%d", m_eddystoneData.version);