1 /*
2  * Copyright 2021 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #pragma once
19 
20 #include <bluetooth/log.h>
21 
22 #include <optional>
23 #include <string>
24 
25 #include "hardware/bt_has.h"
26 
27 namespace bluetooth::le_audio {
28 namespace has {
29 /* Represents preset instance. It stores properties such as preset name,
30  * preset index and if it supports renaming. Also stores all the needed
31  * GATT characteristics and descriptor informations.
32  */
33 class HasPreset {
34  private:
35   mutable std::string name_;
36   mutable uint8_t properties_;
37   uint8_t index_;
38 
39  public:
40   static constexpr size_t kCharValueMinSize = 1 /*index*/ + 1 /*properties*/;
41 
42   static constexpr uint8_t kPropertyWritable = 0x01;
43   static constexpr uint8_t kPropertyAvailable = 0x02;
44 
45   static constexpr uint8_t kPresetNameLengthLimit = 40;
46 
47   HasPreset(uint8_t index, uint8_t props = 0,
48             std::optional<std::string> name = std::nullopt)
properties_(props)49       : properties_(props), index_(index) {
50     name_ = name.value_or("");
51   }
HasPreset()52   HasPreset()
53       : name_(""),
54         properties_(0),
55         index_(bluetooth::has::kHasPresetIndexInvalid) {}
56 
GetName()57   auto& GetName() const { return name_; }
GetIndex()58   decltype(index_) GetIndex() const { return index_; }
GetProperties()59   decltype(properties_) GetProperties() const { return properties_; }
IsWritable()60   bool IsWritable() const { return properties_ & kPropertyWritable; }
IsAvailable()61   bool IsAvailable() const { return properties_ & kPropertyAvailable; }
62 
63   HasPreset& operator=(const HasPreset& other) {
64     log::assert_that(index_ == other.GetIndex(),
65                      "Assigning immutable preset index!");
66 
67     if ((this != &other) && (*this != other)) {
68       index_ = other.GetIndex();
69       name_ = other.GetName();
70     }
71     return *this;
72   }
73 
74   bool operator==(const HasPreset& b) const {
75     return (index_ == b.index_) && (properties_ == b.properties_) &&
76            (name_ == b.name_);
77   }
78   bool operator!=(const HasPreset& b) const {
79     return (index_ != b.index_) || (properties_ != b.properties_) ||
80            (name_ != b.name_);
81   }
82   bool operator<(const HasPreset& b) const { return index_ < b.index_; }
83   friend std::ostream& operator<<(std::ostream& os, const HasPreset& b);
84 
85   struct ComparatorDesc {
86     using is_transparent = void;
operatorComparatorDesc87     bool operator()(HasPreset const& a, int index) const {
88       return a.index_ < index;
89     }
operatorComparatorDesc90     bool operator()(int index, HasPreset const& a) const {
91       return index < a.index_;
92     }
operatorComparatorDesc93     bool operator()(HasPreset const& a, HasPreset const& b) const {
94       return a.index_ < b.index_;
95     }
96   };
97 
98   static std::optional<HasPreset> FromCharacteristicValue(uint16_t& len,
99                                                           const uint8_t* value);
100   void ToCharacteristicValue(std::vector<uint8_t>& value) const;
101 
102   /* Calculates buffer space that the preset will use when serialized */
SerializedSize()103   uint8_t SerializedSize() const {
104     return (sizeof(index_) + sizeof(properties_) + 1 /* name length */
105             + name_.length());
106   }
107   /* Serializes into binary blob for the persistent storage */
108   uint8_t* Serialize(uint8_t* p_out, size_t buffer_size) const;
109   /* Deserializes binary blob read from the persistent storage */
110   static const uint8_t* Deserialize(const uint8_t* p_in, size_t len,
111                                     HasPreset& preset);
112 };
113 
114 }  // namespace has
115 }  // namespace bluetooth::le_audio
116 
117 namespace fmt {
118 template <>
119 struct formatter<bluetooth::le_audio::has::HasPreset> : ostream_formatter {};
120 }  // namespace fmt
121