|  | // Copyright 2018 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <stdio.h>  // snprintf | 
|  |  | 
|  | #include "beacons.h" | 
|  |  | 
|  | namespace ble = fuchsia::bluetooth::le; | 
|  |  | 
|  | namespace bt_beacon_reader { | 
|  |  | 
|  | std::unique_ptr<IBeaconDetection> IBeaconDetection::Create(const ble::RemoteDevice& device) { | 
|  | if (!device.advertising_data || | 
|  | device.advertising_data->manufacturer_specific_data->size() != 1) { | 
|  | return nullptr; | 
|  | } | 
|  | const std::vector<uint8_t>& data = | 
|  | *(*device.advertising_data->manufacturer_specific_data)[0].data; | 
|  | if (data[0] != 0x02) { | 
|  | return nullptr; | 
|  | } | 
|  | if (data[1] != data.size() - 2 || data.size() < 21) { | 
|  | return nullptr; | 
|  | } | 
|  | std::unique_ptr<IBeaconDetection> beacon(new IBeaconDetection); | 
|  | beacon->Read(data); | 
|  | return beacon; | 
|  | } | 
|  |  | 
|  | void IBeaconDetection::Read(const std::vector<uint8_t>& data) { | 
|  | char temp[3]; | 
|  | power_lvl_ = 0; | 
|  | uuid_.clear(); | 
|  | for (int i = 2; i < 18; ++i) { | 
|  | snprintf(temp, 3, "%02x", data[i]); | 
|  | uuid_.append(temp, 2); | 
|  | } | 
|  | major_ = (data[18] << 8) + data[19]; | 
|  | minor_ = (data[20] << 8) + data[21]; | 
|  | // The power level field seems to be optional... | 
|  | if (data.size() > 22) { | 
|  | power_lvl_ = data[22]; | 
|  | } | 
|  | } | 
|  |  | 
|  | std::unique_ptr<TiltDetection> TiltDetection::Create(const ble::RemoteDevice& device) { | 
|  | std::unique_ptr<IBeaconDetection> beacon = IBeaconDetection::Create(device); | 
|  | if (!beacon) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // All Tilt Hydrometers have uuids of the form: | 
|  | // a495bb-0c5b14b44b5121370f02d74de where the dash is 0-8, | 
|  | // corresponding to the 8 colors. | 
|  | if (beacon->uuid_.compare(0, 6, "a495bb") || | 
|  | beacon->uuid_.compare(8, 24, "c5b14b44b5121370f02d74de")) { | 
|  | return nullptr; | 
|  | } | 
|  | // OK, it is a tilt! | 
|  | std::unique_ptr<TiltDetection> tilt(new TiltDetection); | 
|  | tilt->Read(beacon); | 
|  | tilt->identifier_ = *device.identifier; | 
|  | return tilt; | 
|  | } | 
|  |  | 
|  | void TiltDetection::Print() { | 
|  | printf("Tilt %s: Temp: %dF, Gravity: %1.3f\n", color_string_.c_str(), temperature_F_, gravity_); | 
|  | } | 
|  |  | 
|  | void TiltDetection::Read(const std::unique_ptr<IBeaconDetection>& beacon) { | 
|  | temperature_F_ = beacon->major_; | 
|  | color_ = beacon->uuid_[6] - '0'; | 
|  | std::string colors[] = {"Invalid", "Red",  "Green",  "Black", "Purple", | 
|  | "Orange",  "Blue", "Yellow", "Pink"}; | 
|  | color_string_ = colors[color_ % 9]; | 
|  |  | 
|  | // negative gravities are just expressed as their value % 1000. | 
|  | // Since a specific gravity of beer at 1.5 is crazy, we'll draw the line | 
|  | // there. | 
|  | gravity_ = beacon->minor_ / 1000.0; | 
|  | if (beacon->minor_ < 500) { | 
|  | gravity_ += 1.0; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace bt_beacon_reader |