/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include "common/time_util.h" #define BTM_PKT_STATUS_LEN 64 #define BTM_PKT_STATUS_WBS_FRAME_US 7500 /* Object to log consecutive packets' status */ struct tBTM_SCO_PKT_STATUS { // Bytes to store packets' status. uint8_t data[BTM_PKT_STATUS_LEN]; // Total number of bits in |data|. int size; // Position of the next bit to log packet status. int offset; // Whether the ring buffer is full to be wrapped. bool is_full; // The timestamp of the first bit of |data|'s last update. uint64_t ts; public: void init() { std::fill(std::begin(data), std::end(data), 0); size = BTM_PKT_STATUS_LEN * 8; offset = 0; is_full = false; ts = 0; } void update(bool is_lost) { if (is_lost) { data[offset / 8] |= 1UL << (offset % 8); } else { data[offset / 8] &= ~(1UL << (offset % 8)); } if (offset == 0) { ts = bluetooth::common::time_gettimeofday_us(); } offset++; if (offset == size) { offset = 0; is_full = true; } } /* Rewinds logger's time stamp to calculate the beginning. * If logger's ring buffer hasn't wrapped, simply return ts. * Otherwise begin_ts = ts - WBS_FRAME_US * (size - offset) */ uint64_t begin_ts_raw_us() { return !is_full ? ts : ts - BTM_PKT_STATUS_WBS_FRAME_US * (size - offset); } /* Fast-forwards the logger's time stamp to calculate the end. * In other words, end_ts = logger_ts + WBS_FRAME_US * wp */ uint64_t end_ts_raw_us() { return ts + BTM_PKT_STATUS_WBS_FRAME_US * offset; } std::string data_to_hex_string() { int i; int len = is_full ? size : offset; int head = is_full ? offset : 0; uint8_t byte = 0; std::stringstream oss; for (i = 0; i < len; ++i) { int j = (head + i) % size; byte |= (1U << (j % 8)) & data[j / 8]; if ((i + 1) % 8 == 0) { // +(byte) to prevent an uint8_t to be interpreted as a char oss << std::hex << std::setw(2) << std::setfill('0') << +(byte); byte = 0; } } if (i % 8) { oss << std::hex << std::setw(2) << std::setfill('0') << +(byte); } return oss.str(); } std::string data_to_binary_string() { int head = is_full ? offset : 0; int len = is_full ? size : offset; std::string s; for (int i = 0; i < len; ++i) { int j = (head + i) % size; s += std::to_string((data[j / 8] >> (j % 8)) & 1U); } return s; } };