blob: bbcdb2b4383421630b5293aac09fdeec0c5c0fcf [file] [log] [blame]
// 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.
#ifndef GARNET_EXAMPLES_BLUETOOTH_BT_LE_HEART_RATE_PERIPHERAL_SERVICE_H_
#define GARNET_EXAMPLES_BLUETOOTH_BT_LE_HEART_RATE_PERIPHERAL_SERVICE_H_
#include <unordered_set>
#include <fuchsia/bluetooth/gatt/cpp/fidl.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/string.h>
#include <lib/fidl/cpp/vector.h>
#include <lib/fxl/memory/weak_ptr.h>
namespace bt_le_heart_rate {
class HeartModel;
class Service final : fuchsia::bluetooth::gatt::LocalServiceDelegate {
public:
// See assigned numbers for GATT services and characteristics.
// https://www.bluetooth.com/specifications/gatt/services
// https://www.bluetooth.com/specifications/gatt/characteristics
static constexpr char kServiceUuid[] = "0000180d-0000-1000-8000-00805f9b34fb";
static constexpr uint64_t kHeartRateMeasurementId = 0;
static constexpr char kHeartRateMeasurementUuid[] =
"00002a37-0000-1000-8000-00805f9b34fb";
static constexpr uint64_t kBodySensorLocationId = 1;
static constexpr char kBodySensorLocationUuid[] =
"00002a38-0000-1000-8000-00805f9b34fb";
static constexpr uint64_t kHeartRateControlPointId = 2;
static constexpr char kHeartRateControlPointUuid[] =
"00002a39-0000-1000-8000-00805f9b34fb";
// See Assigned Numbers for Heart Rate Service
// https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.service.heart_rate.xml
static constexpr fuchsia::bluetooth::gatt::ErrorCode
CONTROL_POINT_NOT_SUPPORTED =
static_cast<fuchsia::bluetooth::gatt::ErrorCode>(0x80);
// Heart Rate Service v1.0, 3.3.1 [Control Point] Characteristic Behavior.
static constexpr uint8_t kResetEnergyExpendedValue = 0x01;
explicit Service(std::unique_ptr<HeartModel> heart_model);
~Service() = default;
void PublishService(fuchsia::bluetooth::gatt::ServerPtr* gatt_server);
void set_measurement_interval(int msec) { measurement_interval_ = msec; }
private:
void NotifyMeasurement();
void ScheduleNotification();
// Implement LocalServiceDelegate.
void OnCharacteristicConfiguration(uint64_t characteristic_id,
std::string peer_id, bool notify,
bool indicate) override;
void OnReadValue(uint64_t id, int32_t offset,
OnReadValueCallback callback) override;
void OnWriteValue(uint64_t id, uint16_t offset,
std::vector<uint8_t> value,
OnWriteValueCallback callback) override;
void OnWriteWithoutResponse(uint64_t id, uint16_t offset,
std::vector<uint8_t> value) override;
std::unique_ptr<HeartModel> heart_model_;
fidl::Binding<fuchsia::bluetooth::gatt::LocalServiceDelegate> binding_;
fuchsia::bluetooth::gatt::LocalServicePtr service_;
// Peers that have enabled measurement notifications.
std::unordered_set<std::string> measurement_peers_;
bool notify_scheduled_;
// Interval of measurement notifications in milliseconds.
int measurement_interval_ = 2000;
fxl::WeakPtrFactory<Service> weak_factory_;
};
// Interface for heart rate measurement sensors
class HeartModel {
public:
struct Measurement {
bool contact; // True if measured while sensor was in contact.
int rate; // Heart rate in beats per minute (BPM).
int energy_expended; // Energy expended since reset in kilojoules (kJ).
};
virtual ~HeartModel() {}
virtual bool ReadMeasurement(Measurement* measurement) = 0;
virtual void ResetEnergyExpended() = 0;
};
enum class BodySensorLocation : uint8_t {
kOther = 0,
kChest = 1,
kWrist = 2,
kFinger = 3,
kHand = 4,
kEarLobe = 5,
kFoot = 6,
};
} // namespace bt_le_heart_rate
#endif // GARNET_EXAMPLES_BLUETOOTH_BT_LE_HEART_RATE_PERIPHERAL_SERVICE_H_