1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <cstdint> 20 #include <iomanip> 21 #include <iostream> 22 #include <sstream> 23 #include <string> 24 25 #include "common/time_util.h" 26 27 #define BTM_PKT_STATUS_LEN 64 28 #define BTM_PKT_STATUS_WBS_FRAME_US 7500 29 30 /* Object to log consecutive packets' status */ 31 struct tBTM_SCO_PKT_STATUS { 32 // Bytes to store packets' status. 33 uint8_t data[BTM_PKT_STATUS_LEN]; 34 // Total number of bits in |data|. 35 int size; 36 // Position of the next bit to log packet status. 37 int offset; 38 // Whether the ring buffer is full to be wrapped. 39 bool is_full; 40 // The timestamp of the first bit of |data|'s last update. 41 uint64_t ts; 42 43 public: inittBTM_SCO_PKT_STATUS44 void init() { 45 std::fill(std::begin(data), std::end(data), 0); 46 size = BTM_PKT_STATUS_LEN * 8; 47 offset = 0; 48 is_full = false; 49 ts = 0; 50 } 51 updatetBTM_SCO_PKT_STATUS52 void update(bool is_lost) { 53 if (is_lost) { 54 data[offset / 8] |= 1UL << (offset % 8); 55 } else { 56 data[offset / 8] &= ~(1UL << (offset % 8)); 57 } 58 if (offset == 0) { 59 ts = bluetooth::common::time_gettimeofday_us(); 60 } 61 offset++; 62 if (offset == size) { 63 offset = 0; 64 is_full = true; 65 } 66 } 67 68 /* Rewinds logger's time stamp to calculate the beginning. 69 * If logger's ring buffer hasn't wrapped, simply return ts. 70 * Otherwise begin_ts = ts - WBS_FRAME_US * (size - offset) 71 */ begin_ts_raw_ustBTM_SCO_PKT_STATUS72 uint64_t begin_ts_raw_us() { 73 return !is_full ? ts : ts - BTM_PKT_STATUS_WBS_FRAME_US * (size - offset); 74 } 75 76 /* Fast-forwards the logger's time stamp to calculate the end. 77 * In other words, end_ts = logger_ts + WBS_FRAME_US * wp 78 */ end_ts_raw_ustBTM_SCO_PKT_STATUS79 uint64_t end_ts_raw_us() { return ts + BTM_PKT_STATUS_WBS_FRAME_US * offset; } 80 data_to_hex_stringtBTM_SCO_PKT_STATUS81 std::string data_to_hex_string() { 82 int i; 83 int len = is_full ? size : offset; 84 int head = is_full ? offset : 0; 85 uint8_t byte = 0; 86 std::stringstream oss; 87 88 for (i = 0; i < len; ++i) { 89 int j = (head + i) % size; 90 byte |= (1U << (j % 8)) & data[j / 8]; 91 92 if ((i + 1) % 8 == 0) { 93 // +(byte) to prevent an uint8_t to be interpreted as a char 94 oss << std::hex << std::setw(2) << std::setfill('0') << +(byte); 95 byte = 0; 96 } 97 } 98 99 if (i % 8) oss << std::hex << std::setw(2) << std::setfill('0') << +(byte); 100 101 return oss.str(); 102 } 103 data_to_binary_stringtBTM_SCO_PKT_STATUS104 std::string data_to_binary_string() { 105 int head = is_full ? offset : 0; 106 int len = is_full ? size : offset; 107 std::string s; 108 109 for (int i = 0; i < len; ++i) { 110 int j = (head + i) % size; 111 s += std::to_string(((data[j / 8] >> (j % 8)) & 1U)); 112 } 113 114 return s; 115 } 116 }; 117