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 <sys/time.h>
21 #include <time.h>
22 
23 #include <list>
24 #include <variant>
25 
26 #include "common/time_util.h"
27 #include "has_ctp.h"
28 
29 /* Journal and journal entry classes used by the state dumping functionality. */
30 namespace bluetooth::le_audio {
31 namespace has {
32 static constexpr uint8_t kHasJournalNumRecords = 20;
33 
34 struct HasJournalRecord {
35   /* Indicates which value the `event` contains (due to ambiguous uint8_t) */
36   bool is_operation : 1, is_notification : 1, is_features_change : 1, is_active_preset_change : 1;
37   std::variant<HasCtpOp, HasCtpNtf, uint8_t> event;
38   struct timespec timestamp;
39 
40   /* Operation context handle to match on GATT write response */
41   void* op_context_handle;
42 
43   /* Status of the operation to be set once it gets completed */
44   uint8_t op_status;
45 
HasJournalRecordHasJournalRecord46   HasJournalRecord(const HasCtpOp& op, void* context) : event(op), op_context_handle(context) {
47     clock_gettime(CLOCK_REALTIME, &timestamp);
48     is_operation = true;
49     is_notification = false;
50     is_features_change = false;
51     is_active_preset_change = false;
52   }
53 
HasJournalRecordHasJournalRecord54   HasJournalRecord(const HasCtpNtf& ntf) : event(ntf) {
55     clock_gettime(CLOCK_REALTIME, &timestamp);
56     is_operation = false;
57     is_notification = true;
58     is_features_change = false;
59     is_active_preset_change = false;
60   }
61 
HasJournalRecordHasJournalRecord62   HasJournalRecord(uint8_t value, bool is_feat_change) : event(value) {
63     clock_gettime(CLOCK_REALTIME, &timestamp);
64     is_operation = false;
65     is_notification = false;
66     if (is_feat_change) {
67       is_active_preset_change = false;
68       is_features_change = true;
69     } else {
70       is_active_preset_change = true;
71       is_features_change = false;
72     }
73   }
74 };
75 std::ostream& operator<<(std::ostream& os, const HasJournalRecord& r);
76 
77 template <class valT, size_t cache_max>
78 class CacheList {
79 public:
Append(valT data)80   valT& Append(valT data) {
81     items_.push_front(std::move(data));
82 
83     if (items_.size() > cache_max) {
84       items_.pop_back();
85     }
86 
87     return items_.front();
88   }
89 
90   using iterator = typename std::list<valT>::iterator;
begin(void)91   iterator begin(void) { return items_.begin(); }
end(void)92   iterator end(void) { return items_.end(); }
93 
94   using const_iterator = typename std::list<valT>::const_iterator;
begin(void)95   const_iterator begin(void) const { return items_.begin(); }
end(void)96   const_iterator end(void) const { return items_.end(); }
97 
Erase(iterator it)98   void Erase(iterator it) {
99     if (it != items_.end()) {
100       items_.erase(it);
101     }
102   }
103 
Clear(void)104   void Clear(void) { items_.clear(); }
isEmpty(void)105   bool isEmpty(void) { return items_.empty(); }
106 
107 private:
108   typename std::list<valT> items_;
109 };
110 
111 using HasJournal = CacheList<HasJournalRecord, kHasJournalNumRecords>;
112 }  // namespace has
113 }  // namespace bluetooth::le_audio
114