Files
2026-08-24 10:03:24 +08:00

1247 lines
50 KiB
C
Executable File

/* Copyright Statement:
*
* This software/firmware and related documentation ("MediaTek Software") are
* protected under relevant copyright laws. The information contained herein is
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
* the prior written permission of MediaTek inc. and/or its licensors, any
* reproduction, modification, use or disclosure of MediaTek Software, and
* information contained herein, in whole or in part, shall be strictly
* prohibited.
*
* MediaTek Inc. (C) 2010. All rights reserved.
*
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
*
* The following software/firmware and/or related documentation ("MediaTek
* Software") have been modified by MediaTek Inc. All revisions are subject to
* any receiver's applicable license agreements with MediaTek Inc.
*/
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <pthread.h>
#include "bperf_util.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#include "common.h"
#ifdef OS_FRTOS
#include "osi_frtos.h"
#else
#include "osi_linux.h"
#endif
#define BPERF_LIBRARY_VERSION "700.0.19011501"
#define LOG_TAG "bperf"
#define MAX_BPERF_EVENTS_IN_A_SECOND 500
#define MAX_BPERF_LE_SCAN_ENTRY 64
#define MAX_BPERF_BT_SCAN_ENTRY 64
#ifdef OS_FRTOS
static SemaphoreHandle_t event_data_lock;
#else
static PTHREAD_MUTEX_T event_data_lock;
#endif
static PTHREAD_T bperf_thread_main;
static unsigned int bperf_main_thread_status;
static unsigned int bperf_main_thread_should_stop;
static unsigned int bperf_global_counter;
static uint8_t bperf_global_bitpool;
static uint8_t bperf_global_voble_codec; /* 0: ADPCM, 1:OPUS */
static unsigned char bperf_a2dp_string_interval[64];
static unsigned char bperf_a2dp_string_throughput[64];
static unsigned char bperf_a2dp_string_bitpool[64];
static unsigned int bperf_average_accumulate;
static unsigned int bperf_average_total_time;
static unsigned int bperf_average_total_time_index;
static int event_len_summary_rc_fw_upgrade = 0;
static int event_len_summary_voice = 0;
static int event_len_summary_voice_drop = 0;
static int event_len_summary_a2dp = 0;
static int event_len_summary_a2dp_glitch_warning = 0;
static int event_counter_summary_hid = 0;
static int event_counter_summary_hid_cursor = 0;
static int event_counter_summary_hogp = 0;
static int event_counter_summary_hogp_cursor = 0;
static int event_counter_summary_hid_delta_time_max = 0;
static int event_counter_summary_hid_cursor_delta_time_max = 0;
static int event_counter_summary_hogp_delta_time_max = 0;
static int event_counter_summary_hogp_cursor_delta_time_max = 0;
static int event_counter_summary_ble_adv = 0;
static struct bperf_event *bperf_event_voice, *bperf_event_voice_analysis;
static struct bperf_event *bperf_event_rc_fw_upgrade, *bperf_event_rc_fw_upgrade_analysis;
static struct bperf_event *bperf_event_hid, *bperf_event_hid_analysis;
static struct bperf_event *bperf_event_hid_cursor, *bperf_event_hid_cursor_analysis;
static struct bperf_event *bperf_event_hogp, *bperf_event_hogp_analysis;
static struct bperf_event *bperf_event_hogp_cursor, *bperf_event_hogp_cursor_analysis;
static struct bperf_event *bperf_event_a2dp, *bperf_event_a2dp_analysis;
static struct bperf_event *bperf_event_ble_scan, *bperf_event_ble_scan_analysis;
static unsigned int _bperf_get_microseconds(void)
{
struct timeval now;
gettimeofday(&now, NULL);
return (now.tv_sec * 1000000 + now.tv_usec);
}
static void _bperf_mem_record_event(struct bperf_event* event, const uint8_t *buf, const unsigned int buf_len)
{
int i;
(void)buf;
for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
{
if ( event[i].id == 0 && event[i].time == 0 )
{
osi_pthread_mutex_lock(&event_data_lock);
event[i].id = 1+i;
event[i].time = _bperf_get_microseconds();
event[i].buf_len = buf_len;
/* BLE ADV Report, save event type */
if ( buf[0] == 0x3e && buf[2] == 0x02 )
{
event[i].extra_info = buf[4];
}
/* HT RC Voice Search (2640)(BLE Data Length Extension) */
else if ( buf_len == 111 && buf[2] == 0x6b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x3f && buf[10] == 0x00 )
{
event[i].extra_info = ((buf[11] >>3 )& 0x1F);
}
osi_pthread_mutex_unlock(&event_data_lock);
break;
}
}
}
static void _bperf_mem_reset()
{
if ( bperf_event_voice )
memset(bperf_event_voice, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_rc_fw_upgrade )
memset(bperf_event_rc_fw_upgrade, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hid )
memset(bperf_event_hid, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hid_cursor )
memset(bperf_event_hid_cursor, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hogp )
memset(bperf_event_hogp, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hogp_cursor )
memset(bperf_event_hogp_cursor, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_a2dp )
memset(bperf_event_a2dp, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_ble_scan )
memset(bperf_event_ble_scan, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
}
static void _bperf_mem_reset_analysis()
{
if ( bperf_event_voice_analysis )
memset(bperf_event_voice_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_rc_fw_upgrade_analysis )
memset(bperf_event_rc_fw_upgrade_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hid_analysis )
memset(bperf_event_hid_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hid_cursor_analysis )
memset(bperf_event_hid_cursor_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hogp_analysis )
memset(bperf_event_hogp_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hogp_cursor_analysis )
memset(bperf_event_hogp_cursor_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_a2dp_analysis )
memset(bperf_event_a2dp_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_ble_scan_analysis )
memset(bperf_event_ble_scan_analysis, 0, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
}
void bperf_mem_init(int init_type)
{
printf("%s init_type (%d)\n", __func__, init_type);
switch (init_type) {
case BPERF_VOICE:
if ( bperf_event_voice == NULL )
bperf_event_voice = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_voice_analysis == NULL )
bperf_event_voice_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
break;
case BPERF_RC:
if ( bperf_event_rc_fw_upgrade == NULL )
bperf_event_rc_fw_upgrade = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_rc_fw_upgrade_analysis == NULL )
bperf_event_rc_fw_upgrade_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
break;
case BPERF_HID:
if ( bperf_event_hid == NULL )
bperf_event_hid = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hid_cursor == NULL )
bperf_event_hid_cursor = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hid_analysis == NULL )
bperf_event_hid_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hid_cursor_analysis == NULL )
bperf_event_hid_cursor_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
break;
case BPERF_HOGP:
if ( bperf_event_hogp == NULL )
bperf_event_hogp = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hogp_cursor == NULL )
bperf_event_hogp_cursor= malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hogp_analysis == NULL )
bperf_event_hogp_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_hogp_cursor_analysis == NULL )
bperf_event_hogp_cursor_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
break;
case BPERF_A2DP:
if ( bperf_event_a2dp == NULL )
bperf_event_a2dp = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_a2dp_analysis == NULL )
bperf_event_a2dp_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
break;
case BPERF_BLE_SCAN:
if ( bperf_event_ble_scan == NULL )
bperf_event_ble_scan = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if ( bperf_event_ble_scan_analysis == NULL )
bperf_event_ble_scan_analysis = malloc(sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
break;
default:
printf("%s init_type error (%d)", __func__, init_type);
}
_bperf_mem_reset();
_bperf_mem_reset_analysis();
}
static void _bperf_mem_free()
{
if ( bperf_event_voice )
free(bperf_event_voice);
if ( bperf_event_rc_fw_upgrade )
free(bperf_event_rc_fw_upgrade);
if ( bperf_event_hid )
free(bperf_event_hid);
if ( bperf_event_hid_cursor )
free(bperf_event_hid_cursor);
if ( bperf_event_hogp )
free(bperf_event_hogp);
if ( bperf_event_hogp_cursor )
free(bperf_event_hogp_cursor);
if ( bperf_event_a2dp )
free(bperf_event_a2dp);
if ( bperf_event_ble_scan )
free(bperf_event_ble_scan);
if ( bperf_event_voice_analysis )
free(bperf_event_voice_analysis);
if ( bperf_event_rc_fw_upgrade_analysis )
free(bperf_event_rc_fw_upgrade_analysis);
if ( bperf_event_hid_analysis )
free(bperf_event_hid_analysis);
if ( bperf_event_hid_cursor_analysis )
free(bperf_event_hid_cursor_analysis);
if ( bperf_event_hogp_analysis )
free(bperf_event_hogp_analysis);
if ( bperf_event_hogp_cursor_analysis )
free(bperf_event_hogp_cursor_analysis);
if ( bperf_event_a2dp_analysis )
free(bperf_event_a2dp_analysis);
if ( bperf_event_ble_scan_analysis )
free(bperf_event_ble_scan_analysis);
}
static void _bperf_mem_copy()
{
if (bperf_event_voice_analysis && bperf_event_voice)
memcpy(bperf_event_voice_analysis, bperf_event_voice, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if (bperf_event_rc_fw_upgrade_analysis && bperf_event_rc_fw_upgrade)
memcpy(bperf_event_rc_fw_upgrade_analysis, bperf_event_rc_fw_upgrade, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if (bperf_event_hid_analysis && bperf_event_hid)
memcpy(bperf_event_hid_analysis, bperf_event_hid, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if (bperf_event_hid_cursor_analysis && bperf_event_hid_cursor)
memcpy(bperf_event_hid_cursor_analysis, bperf_event_hid_cursor, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if (bperf_event_hogp_analysis && bperf_event_hogp)
memcpy(bperf_event_hogp_analysis, bperf_event_hogp, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if (bperf_event_hogp_cursor_analysis && bperf_event_hogp_cursor)
memcpy(bperf_event_hogp_cursor_analysis, bperf_event_hogp_cursor, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if (bperf_event_a2dp_analysis && bperf_event_a2dp)
memcpy(bperf_event_a2dp_analysis, bperf_event_a2dp, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
if (bperf_event_ble_scan_analysis && bperf_event_ble_scan)
memcpy(bperf_event_ble_scan_analysis, bperf_event_ble_scan, sizeof(struct bperf_event) * MAX_BPERF_EVENTS_IN_A_SECOND);
}
static void _bperf_analysis_rc_fw_upgrade(struct bperf_event *bperf_event)
{
if ( bperf_event )
{
int i;
int event_counter=0;
int event_len_total=0;
for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
{
if ( bperf_event[i].id )
{
event_counter++;
event_len_total += (bperf_event[i].buf_len - 4); /* 4 byte hci header should be removed */
}
else
{
break;
}
}
if ( i > 0 )
{
if ( bperf_average_accumulate == 1 )
{
event_len_summary_rc_fw_upgrade += event_len_total;
}
printf("[bperf](%d) RC FW Upgrade Num(%d), Throughput (%d bps)\n", bperf_global_counter, event_counter, (event_len_total<<3));
}
}
}
static void _bperf_analysis_voice(struct bperf_event *bperf_event)
{
if ( bperf_event )
{
int i;
int event_counter = 0;
int event_len_total = 0;
int event_len_voice = 0;
int event_counter_packet_drop = 0;
int event_counter_packet_not_in_time = 0;
int event_delta_time = 0;
int event_max_delta_time = 0;
static int latest_voice_data_seq = 0;
static int latest_voice_data_timestamp = 0;
for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
{
if ( bperf_event[i].id )
{
event_counter++;
/* Voice data packet contains 4 bytes hci header, 4 bytes l2cap header, 3 bytes ATT header, 1 bytes rc header, 19 bytes audio data */
event_len_total += (bperf_event[i].buf_len - 4);
event_len_voice += (bperf_event[i].buf_len - 11);
if ( i > 0 )
{
/* check sequence num */
if ( bperf_event[i].extra_info != 0 && bperf_event[i].extra_info - bperf_event[i-1].extra_info != 1 )
{
event_counter_packet_drop++;
}
else if ( bperf_event[i].extra_info == 0 && bperf_event[i-1].extra_info != 0 && bperf_event[i-1].extra_info != 31 )
{
event_counter_packet_drop++;
}
/* check delta time */
event_delta_time = bperf_event[i].time - bperf_event[i-1].time;
if ( event_delta_time > 30000 )
{
event_counter_packet_not_in_time++;
}
latest_voice_data_seq = bperf_event[i].extra_info;
latest_voice_data_timestamp = bperf_event[i].time;
}
else if ( i == 0 )
{
/* check sequence num */
if ( bperf_event[i].extra_info != 0 && bperf_event[i].extra_info - latest_voice_data_seq != 1 )
{
event_counter_packet_drop++;
}
else if ( bperf_event[i].extra_info == 0 && latest_voice_data_seq != 0 && latest_voice_data_seq != 31 )
{
event_counter_packet_drop++;
}
/* check delta time */
event_delta_time = bperf_event[i].time - latest_voice_data_timestamp;
if ( bperf_event[i].time - latest_voice_data_timestamp > 30000 )
{
event_counter_packet_not_in_time++;
}
event_max_delta_time = event_delta_time;
}
/* check max delta time */
if ( event_delta_time > event_max_delta_time )
{
event_max_delta_time = event_delta_time;
}
}
else
{
break;
}
}
if ( i > 0 )
{
if ( bperf_average_accumulate == 1 )
{
event_len_summary_voice += event_len_voice;
event_len_summary_voice_drop += event_counter_packet_drop;
}
if (bperf_global_voble_codec == 0) /* codec : ADPCM */
{
/* Normal ADPCM voice data rate is abount 66,400 bps. */
printf("[bperf](%d) VOICE Num(%d), " LIGHT_BLUE ", Voice Data Rate%s(%d bps), Packet Drop%s(%d), Not in time%s(%d), Max Latency%s(%dms)\n",
bperf_global_counter,
event_counter,
(event_len_voice<<3)<60000?LIGHT_RED:GREEN,
(event_len_voice<<3),
event_counter_packet_drop>0?LIGHT_RED:GREEN,
event_counter_packet_drop,
event_counter_packet_not_in_time>0?YELLOW:GREEN,
event_counter_packet_not_in_time,
event_max_delta_time>30000?YELLOW:GREEN,
event_max_delta_time/1000);
}
else /* codec : OPUS */
{
/* Normal ADPCM voice data rate is abount 16,800 bps. */
printf("[bperf](%d) VOICE Num(%d), Voice Data Rate %s(%d bps)\n",
bperf_global_counter,
event_counter,
(event_len_voice<<3)<1500?LIGHT_RED:GREEN,
(event_len_voice<<3));
}
}
}
}
static void _bperf_analysis_hid_hogp(struct bperf_event *bperf_event)
{
if ( bperf_event )
{
int i;
int event_counter=0;
int delta_time=0;
int delta_time_max=0;
for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
{
if ( bperf_event[i].id )
{
event_counter++;
if ( i == 0 )
{
delta_time = 0;
delta_time_max = 0;
}
else
{
delta_time = bperf_event[i].time - bperf_event[i-1].time;
if ( delta_time > delta_time_max )
delta_time_max = delta_time;
}
}
else
{
break;
}
}
if ( i > 0 )
{
if ( bperf_event == bperf_event_hid_analysis )
{
if ( bperf_average_accumulate == 1 )
{
event_counter_summary_hid += event_counter;
if ( delta_time_max > event_counter_summary_hid_delta_time_max )
event_counter_summary_hid_delta_time_max = delta_time_max;
}
printf("[bperf](%d) %sHID Input Report Num%s(%d) %sMax_Delta_Time%s(%dms)\n",
bperf_global_counter,
CYAN, NONECOLOR, event_counter,
CYAN, NONECOLOR, delta_time_max/1000);
}
else if ( bperf_event == bperf_event_hid_cursor_analysis )
{
if ( bperf_average_accumulate == 1 )
{
event_counter_summary_hid_cursor += event_counter;
if ( delta_time_max > event_counter_summary_hid_cursor_delta_time_max )
event_counter_summary_hid_cursor_delta_time_max = delta_time_max;
}
printf("[bperf](%d) %sHID_Mouse Input Report Num%s(%d) %sMax_Delta_Time%s(%dms)\n",
bperf_global_counter,
CYAN, NONECOLOR, event_counter,
CYAN, NONECOLOR, delta_time_max/1000);
}
else if ( bperf_event == bperf_event_hogp_analysis )
{
if ( bperf_average_accumulate == 1 )
{
event_counter_summary_hogp += event_counter;
if ( delta_time_max > event_counter_summary_hogp_delta_time_max )
event_counter_summary_hogp_delta_time_max = delta_time_max;
}
printf("[bperf](%d) %sHOGP Input Report Num%s(%d) %sMax_Delta_Time%s(%dms)\n",
bperf_global_counter,
CYAN, NONECOLOR, event_counter,
CYAN, NONECOLOR, delta_time_max/1000);
}
else if ( bperf_event == bperf_event_hogp_cursor_analysis )
{
if ( bperf_average_accumulate == 1 )
{
event_counter_summary_hogp_cursor += event_counter;
if ( delta_time_max > event_counter_summary_hogp_cursor_delta_time_max )
event_counter_summary_hogp_cursor_delta_time_max = delta_time_max;
}
printf("[bperf](%d) %sHOGP_Mouse Input Report Num%s(%d) %sMax_Delta_Time%s(%dms)\n",
bperf_global_counter,
CYAN, NONECOLOR, event_counter,
CYAN, NONECOLOR, delta_time_max/1000);
}
}
}
}
static void _bperf_analysis_a2dp(struct bperf_event *bperf_event)
{
if ( bperf_event )
{
int i;
int event_counter=0;
int delta_time_max=0;
int delta_time_min=0;
int delta_time_average=0;
int delta_time=0;
int event_len_total=0;
for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
{
if ( bperf_event[i].id )
{
event_counter++;
/* A2DP data packet contains 4byte HCI header, 4 byte L2CAP header, 12 byte AVDTP header*/
event_len_total += (bperf_event[i].buf_len - 20);
if ( i == 0 )
{
delta_time_max = delta_time_average = 0;
delta_time_min = 999999999;
}
else
{
if ( bperf_event[i].time > bperf_event[i-1].time )
delta_time = bperf_event[i].time - bperf_event[i-1].time;
else
delta_time = 0;
if ( delta_time > delta_time_max )
delta_time_max = delta_time;
if ( delta_time < delta_time_min )
delta_time_min = delta_time;
delta_time_average += delta_time;
}
}
else
{
break;
}
}
if ( i > 0 )
{
if ( bperf_average_accumulate == 1 )
{
event_len_summary_a2dp += event_len_total;
}
delta_time_average = delta_time_average/i;
memset(bperf_a2dp_string_interval, 0, sizeof(bperf_a2dp_string_interval));
memset(bperf_a2dp_string_throughput, 0, sizeof(bperf_a2dp_string_throughput));
memset(bperf_a2dp_string_bitpool, 0, sizeof(bperf_a2dp_string_bitpool));
/* bitpool */
if ( bperf_global_bitpool != 51 && bperf_global_bitpool != 53 )
snprintf((char*)bperf_a2dp_string_bitpool, sizeof(bperf_a2dp_string_bitpool), "%sBitpool%s(%d)%s", LIGHT_PURPLE, YELLOW, bperf_global_bitpool, NONECOLOR);
else
snprintf((char*)bperf_a2dp_string_bitpool, sizeof(bperf_a2dp_string_bitpool), "%sBitpool%s(%d)%s", LIGHT_PURPLE, NONECOLOR, bperf_global_bitpool, NONECOLOR);
/* delta time */
if (delta_time_max > 150000)
{
snprintf((char*)bperf_a2dp_string_interval, sizeof(bperf_a2dp_string_interval), "%sMaxInterval%s(%dms)%s", LIGHT_PURPLE, LIGHT_RED, delta_time_max/1000, NONECOLOR);
event_len_summary_a2dp_glitch_warning++;
}
else if (delta_time_max <= 150000 && delta_time_max > 100000)
snprintf((char*)bperf_a2dp_string_interval, sizeof(bperf_a2dp_string_interval), "%sMaxInterval%s(%dms)%s", LIGHT_PURPLE, YELLOW, delta_time_max/1000, NONECOLOR);
else
snprintf((char*)bperf_a2dp_string_interval, sizeof(bperf_a2dp_string_interval), "%sMaxInterval%s(%dms)%s", LIGHT_PURPLE, NONECOLOR, delta_time_max/1000, NONECOLOR);
/* data rate */
/* 90% : 328*1024*0.9 = 302285 */
/* 85% : 328*1024*0.85 = 285491 */
if ((event_len_total<<3) < 285491)
{
event_len_summary_a2dp_glitch_warning++;
snprintf((char*)bperf_a2dp_string_throughput, sizeof(bperf_a2dp_string_throughput), "%sThroughput%s(%d kbps)%s", LIGHT_PURPLE, LIGHT_RED, (event_len_total>>7), NONECOLOR);
}
else if ((event_len_total<<3) >= 285491 && (event_len_total<<3) < 302285)
snprintf((char*)bperf_a2dp_string_throughput, sizeof(bperf_a2dp_string_throughput), "%sThroughput%s(%d kbps)%s", LIGHT_PURPLE, YELLOW, (event_len_total>>7), NONECOLOR);
else
snprintf((char*)bperf_a2dp_string_throughput, sizeof(bperf_a2dp_string_throughput), "%sThroughput%s(%d kbps)%s", LIGHT_PURPLE, NONECOLOR, (event_len_total>>7), NONECOLOR);
printf("[bperf](%d) %sA2DP Num%s(%d), %s, %s, %s\n",
bperf_global_counter, LIGHT_PURPLE, NONECOLOR, event_counter, bperf_a2dp_string_bitpool, bperf_a2dp_string_interval, bperf_a2dp_string_throughput);
}
}
}
static void _bperf_analysis_ble_scan(struct bperf_event *bperf_event)
{
if ( bperf_event )
{
int i;
int event_counter = 0;
int event_counter_connectable_undirected = 0;
int event_counter_connectable_directed = 0;
int event_counter_scannable_directed = 0;
int event_counter_non_connectable_undirected = 0;
int event_counter_scan_response = 0;
for ( i = 0 ; i < MAX_BPERF_EVENTS_IN_A_SECOND ; i++ )
{
if ( bperf_event[i].id )
{
event_counter++;
if ( bperf_event[i].extra_info == BPERF_BLE_ADV_TYPE_CONNECTABLE_UNDIRECTED )
event_counter_connectable_undirected++;
else if ( bperf_event[i].extra_info == BPERF_BLE_ADV_TYPE_CONNECTABLE_DIRECTED )
event_counter_connectable_directed++;
else if ( bperf_event[i].extra_info == BPERF_BLE_ADV_TYPE_SCANNABLE_DIRECTED )
event_counter_scannable_directed++;
else if ( bperf_event[i].extra_info == BPERF_BLE_ADV_TYPE_NON_CONNECTABLE_UNDIRECTED )
event_counter_non_connectable_undirected++;
else if ( bperf_event[i].extra_info == BPERF_BLE_ADV_TYPE_SCAN_RESPONSE )
event_counter_scan_response++;
}
else
{
break;
}
}
if ( i > 0 )
{
if ( bperf_average_accumulate == 1 )
{
event_counter_summary_ble_adv += event_counter;
}
printf("[bperf](%d) %sBLE ADV Num%s(%d) (%sconn_undir%s:%d)(%sconn_dir%s:%d)(%ssca_dir%s:%d)(%snon-conn_undir%s:%d)(%sscan_resp%s:%d)\n",
bperf_global_counter,
LIGHT_GREEN, NONECOLOR,
event_counter,
LIGHT_GREEN, NONECOLOR,
event_counter_connectable_undirected,
NONECOLOR, NONECOLOR,
event_counter_connectable_directed,
NONECOLOR, NONECOLOR,
event_counter_scannable_directed,
NONECOLOR, NONECOLOR,
event_counter_non_connectable_undirected,
LIGHT_GREEN, NONECOLOR,
event_counter_scan_response);
}
}
}
static void _bperf_analysis_inquiry(const uint8_t *buf, const unsigned int buf_len)
{
int i;
int entry_found = MAX_BPERF_BT_SCAN_ENTRY;
int entry_empty = MAX_BPERF_BT_SCAN_ENTRY;
int entry_used = MAX_BPERF_BT_SCAN_ENTRY;
int save_entry = 0;
static unsigned int bt_scan_start_time;
static unsigned int bt_scan_result_time[MAX_BPERF_BT_SCAN_ENTRY][3];
static uint8_t bt_scan_result_address[MAX_BPERF_BT_SCAN_ENTRY][6];
/* HCI_INQUIRY */
if ( buf_len == 8 && buf[0] == 0x01 && buf[1] == 0x04 && buf[2] == 0x05 )
{
printf("[bperf] %sHCI_INQUIRY%s Started (Inquiry_Length:%.2fs)(0ms)\n",
BLUE, NONECOLOR, (buf[6]*1.28));
bt_scan_start_time = _bperf_get_microseconds();
for ( i = 0 ; i < MAX_BPERF_LE_SCAN_ENTRY ; i++ )
{
bt_scan_result_time[i][0] = 0;
bt_scan_result_time[i][1] = 0;
bt_scan_result_time[i][2] = 0;
bt_scan_result_address[i][0] = 0;
bt_scan_result_address[i][1] = 0;
bt_scan_result_address[i][2] = 0;
bt_scan_result_address[i][3] = 0;
bt_scan_result_address[i][4] = 0;
bt_scan_result_address[i][5] = 0;
}
}
/* HCI_EXTEND_INQUIRY_RESULT || HCI_REMOTE_NAME_REQUEST ||HCI_REMOTE_NAME_REQUEST_COMPLETE*/
else if ( (buf[0] == 0x2f && buf[1] == 0xff && buf[2] == 0x01) ||
(buf_len == 13 && buf[0] == 0x19 && buf[1] == 0x04 && buf[2] == 0x0a) ||
(buf[0] == 0x07 && buf[1] == 0xff && buf[2] == 0x00) )
{
for ( i = 0 ; i < MAX_BPERF_BT_SCAN_ENTRY ; i++ )
{
if ( bt_scan_result_address[i][0] == 0 && bt_scan_result_address[i][1] == 0 && bt_scan_result_address[i][2] == 0 &&
bt_scan_result_address[i][3] == 0 && bt_scan_result_address[i][4] == 0 && bt_scan_result_address[i][5] == 0 )
{
entry_empty = i;
break;
}
}
for ( i = 0 ; i < MAX_BPERF_BT_SCAN_ENTRY ; i++ )
{
if ( strncmp((char*)(&bt_scan_result_address[i][0]), (char*)(&buf[3]), 6) == 0 )
{
entry_found = i;
break;
}
}
/* Entry found */
if ( entry_found != MAX_BPERF_BT_SCAN_ENTRY )
{
save_entry = 1;
entry_used = entry_found;
}
/* Entry not found, use empty entry */
else if ( entry_found == MAX_BPERF_BT_SCAN_ENTRY && entry_empty != MAX_BPERF_BT_SCAN_ENTRY )
{
save_entry = 1;
entry_used = entry_empty;
}
/* Entry full */
else
{
save_entry = 0;
printf("[bperf] HCI_EXTEND_INQUIRY_RESULT Entry FULL!! (%d)\n", MAX_BPERF_BT_SCAN_ENTRY);
}
if ( save_entry )
{
/* HCI_EXTEND_INQUIRY_RESULT */
if ( buf[0] == 0x2f && buf[1] == 0xff && buf[2] == 0x01 )
{
strncpy((char*)(&bt_scan_result_address[entry_used][0]), (char*)(&buf[3]), 6);
bt_scan_result_time[entry_used][0] = _bperf_get_microseconds();
printf("[bperf] %sHCI_EXTEND_INQUIRY_RESULT%s (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)\n",
LIGHT_BLUE, NONECOLOR,
entry_used, buf[8], buf[7], buf[6], buf[5], buf[4], buf[3],
(int)((bt_scan_result_time[entry_used][0]-bt_scan_start_time)/1000));
}
/* HCI_REMOTE_NAME_REQUEST */
else if ( buf_len == 13 && buf[0] == 0x19 && buf[1] == 0x04 && buf[2] == 0x0a )
{
bt_scan_result_time[entry_used][1] = _bperf_get_microseconds();
printf("[bperf] %sHCI_REMOTE_NAME_REQUEST%s (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)\n",
LIGHT_BLUE, NONECOLOR,
entry_used, buf[8], buf[7], buf[6], buf[5], buf[4], buf[3],
(int)((bt_scan_result_time[entry_used][1]-bt_scan_start_time)/1000));
}
/* HCI_REMOTE_NAME_REQUEST_COMPLETE */
else if ( buf[0] == 0x07 && buf[1] == 0xff && buf[2] == 0x00 )
{
bt_scan_result_time[entry_used][2] = _bperf_get_microseconds();
printf("[bperf] %sHCI_REMOTE_NAME_REQUEST_COMPLETE%s (%d)(%02x:%02x:%02x:%02x:%02x:%02x)(%dms)(%s)\n",
LIGHT_BLUE, NONECOLOR,
entry_used, buf[8], buf[7], buf[6], buf[5], buf[4], buf[3],
(int)((bt_scan_result_time[entry_used][2]-bt_scan_start_time)/1000),
(char*)(&buf[9]));
}
}
/* Duplicate, skip it */
else
{}
}
/* HCI_INQUIRY_COMPLETE */
else if ( buf_len == 3 && buf[0] == 0x01 && buf[1] == 0x01 && buf[2] == 0x00 )
{
printf("[bperf] %sHCI_INQUIRY_COMPLETE%s (%dms)\n",
BLUE, NONECOLOR, ((_bperf_get_microseconds()-bt_scan_start_time)/1000));
}
}
static void _bperf_analysis()
{
if ( bperf_event_ble_scan_analysis )
{
_bperf_analysis_ble_scan(bperf_event_ble_scan_analysis);
}
if ( bperf_event_a2dp_analysis )
{
_bperf_analysis_a2dp(bperf_event_a2dp_analysis);
}
if ( bperf_event_voice_analysis )
{
_bperf_analysis_voice(bperf_event_voice_analysis);
}
if ( bperf_event_rc_fw_upgrade_analysis )
{
_bperf_analysis_rc_fw_upgrade(bperf_event_rc_fw_upgrade_analysis);
}
if ( bperf_event_hid_analysis )
{
_bperf_analysis_hid_hogp(bperf_event_hid_analysis);
}
if ( bperf_event_hid_cursor_analysis )
{
_bperf_analysis_hid_hogp(bperf_event_hid_cursor_analysis);
}
if ( bperf_event_hogp_analysis )
{
_bperf_analysis_hid_hogp(bperf_event_hogp_analysis);
}
if ( bperf_event_hogp_cursor_analysis )
{
_bperf_analysis_hid_hogp(bperf_event_hogp_cursor_analysis);
}
if ( bperf_average_accumulate == 1 && bperf_average_total_time > 0 )
{
if ( bperf_average_total_time_index == 0 )
{
if ( bperf_average_total_time )
{
if ( event_counter_summary_ble_adv )
{
printf("[bperf] %sBLE ADV Num(average)%s(%ds) (%d)\n",
YELLOW, NONECOLOR,
bperf_average_total_time, (event_counter_summary_ble_adv/bperf_average_total_time));
event_counter_summary_ble_adv = 0;
}
if ( event_len_summary_a2dp )
{
printf("[bperf] %sA2DP(average)%s(%ds) Throughput (%d kbps) Audio Glitch Warning%s(%d)%s\n",
YELLOW, NONECOLOR,
bperf_average_total_time, (event_len_summary_a2dp<<3)/bperf_average_total_time/1000,
event_len_summary_a2dp_glitch_warning==0?NONECOLOR:LIGHT_RED,
event_len_summary_a2dp_glitch_warning,
NONECOLOR);
event_len_summary_a2dp = 0;
event_len_summary_a2dp_glitch_warning = 0;
}
if ( event_counter_summary_hid )
{
printf("[bperf] %sHID(average)%s(%ds) Input Report Num (%d) Max_Delta_Time(%dms)\n",
YELLOW, NONECOLOR,
bperf_average_total_time,
event_counter_summary_hid/bperf_average_total_time,
event_counter_summary_hid_delta_time_max/1000);
event_counter_summary_hid = 0;
event_counter_summary_hid_delta_time_max = 0;
}
if ( event_counter_summary_hid_cursor )
{
printf("[bperf] %sHID_Mouse(average)%s(%ds) Input Report Num (%d) Max_Delta_Time(%dms)\n",
YELLOW, NONECOLOR,
bperf_average_total_time,
event_counter_summary_hid_cursor/bperf_average_total_time,
event_counter_summary_hid_cursor_delta_time_max/1000);
event_counter_summary_hid_cursor = 0;
event_counter_summary_hid_cursor_delta_time_max = 0;
}
if ( event_counter_summary_hogp )
{
printf("[bperf] %sHOGP(average)%s(%ds) Input Report Num (%d) Max_Delta_Time(%dms)\n",
YELLOW, NONECOLOR,
bperf_average_total_time,
event_counter_summary_hogp/bperf_average_total_time,
event_counter_summary_hogp_delta_time_max/1000);
event_counter_summary_hogp = 0;
event_counter_summary_hogp_delta_time_max = 0;
}
if ( event_counter_summary_hogp_cursor )
{
printf("[bperf] %sHOGP_Mouse(average)%s(%ds) Input Report Num (%d) Max_Delta_Time(%dms)\n",
YELLOW, NONECOLOR,
bperf_average_total_time,
event_counter_summary_hogp_cursor/bperf_average_total_time,
event_counter_summary_hogp_cursor_delta_time_max/1000);
event_counter_summary_hogp_cursor = 0;
event_counter_summary_hogp_cursor_delta_time_max = 0;
}
if ( event_len_summary_voice )
{
printf("[bperf] %sVOICE(average)%s(%ds) Voice Data Rate (%d bps) Total Packet Drop (%d)\n" ,
YELLOW, NONECOLOR,
bperf_average_total_time, (event_len_summary_voice<<3)/bperf_average_total_time, event_len_summary_voice_drop);
event_len_summary_voice = 0;
event_len_summary_voice_drop = 0;
}
if ( event_len_summary_rc_fw_upgrade )
{
printf("[bperf] %sFW_UPGRADE(average)%s(%ds) Voice Data Rate (%d bps)\n",
YELLOW, NONECOLOR,
bperf_average_total_time, (event_len_summary_rc_fw_upgrade<<3)/bperf_average_total_time);
event_len_summary_rc_fw_upgrade = 0;
}
}
bperf_average_total_time_index = bperf_average_total_time;
}
bperf_average_total_time_index--;
}
}
#ifdef OS_FRTOS
int *_bperf_thread_main(void *arg)
#else
static void *_bperf_thread_main(void *arg)
#endif
{
unsigned int time_begin;
unsigned int time_end;
unsigned int time_sleep;
(void)arg;
printf("Thread Started\n");
bperf_main_thread_status = BPERF_STATE_THREAD_RUNNING;
while(!bperf_main_thread_should_stop)
{
time_begin = _bperf_get_microseconds();
osi_pthread_mutex_lock(&event_data_lock);
_bperf_mem_copy();
_bperf_mem_reset();
osi_pthread_mutex_unlock(&event_data_lock);
_bperf_analysis();
_bperf_mem_reset_analysis();
time_end = _bperf_get_microseconds();
time_sleep = 1000000-(time_end-time_begin);
osi_usleep(time_sleep);
bperf_global_counter++;
}
bperf_main_thread_should_stop = 0;
bperf_main_thread_status = BPERF_STATE_THREAD_STOPPED;
printf("Thread Stopped\n");
return 0;
}
static void _bperf_thread_start()
{
if ( bperf_main_thread_status != BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop)
{
printf("Create thread\n");
osi_pthread_create(&bperf_thread_main, NULL, _bperf_thread_main, NULL);
}
}
static void _bperf_thread_stop()
{
bperf_main_thread_should_stop = 1;
}
static void _bperf_notify_le_scan(const uint8_t *buf, const unsigned int buf_len)
{
static unsigned int le_scan_start_time;
/* HCI_LE_SCAN_ENABLE */
if ( buf_len == 5 && buf[0] == 0x0c && buf[1] == 0x20 && buf[2] == 0x02 )
{
/* HCI_LE_SCAN_ENABLE Started */
if ( buf[3] == 1 )
{
le_scan_start_time = _bperf_get_microseconds();
printf("[bperf] %sHCI_LE_SCAN_ENABLE%s Started (%sDuplicate_Filter%s:%02x)(0ms)\n",
GREEN, NONECOLOR, GREEN, NONECOLOR, buf[4]);
}
/* HCI_LE_SCAN_ENABLE Stopped */
else if ( buf[3] == 0 )
{
printf("[bperf] %sHCI_LE_SCAN_ENABLE%s Stopped (Duplicate_Filter:%02x) (Total_Scan_Time:%dms)\n",
GREEN, NONECOLOR, buf[4],
((_bperf_get_microseconds()-le_scan_start_time)/1000));
le_scan_start_time = 0;
}
}
/* HCI_LE_SET_SCAN_PARAMETER */
else if ( buf_len == 10 && buf[0] == 0x0b && buf[1] == 0x20 && buf[2] == 0x07 )
{
float le_scan_interval = (buf[4] + (buf[5]<<8))*0.625;
float le_scan_window = (buf[6] + (buf[7]<<8))*0.625;
printf("[bperf] %sHCI_LE_SET_SCAN_PARAMETER%s (%scan_window%s:%.2fms) (%sscan_interval%s:%.2fms)\n",
GREEN, NONECOLOR, GREEN, NONECOLOR, le_scan_window, GREEN, NONECOLOR, le_scan_interval);
}
/* HCI_LE_ADVERTISING_REPORT */
else
{
_bperf_mem_record_event(bperf_event_ble_scan, buf, buf_len);
}
}
void bperf_notify_cmd(const uint8_t *buf, const unsigned int buf_len)
{
if ( bperf_main_thread_status == BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop )
{
/* HCI_LE_SCAN_ENABLE */
if ( buf_len == 5 && buf[0] == 0x0c && buf[1] == 0x20 && buf[2] == 0x02 )
{
_bperf_notify_le_scan(buf, buf_len);
}
/* HCI_LE_SET_SCAN_PARAMETER */
else if ( buf_len == 10 && buf[0] == 0x0b && buf[1] == 0x20 && buf[2] == 0x07 )
{
_bperf_notify_le_scan(buf, buf_len);
}
/* HCI_INQUIRY */
else if ( buf_len == 8 && buf[0] == 0x01 && buf[1] == 0x04 && buf[2] == 0x05 )
{
_bperf_analysis_inquiry(buf, buf_len);
}
/* HCI_REMOTE_NAME_REQUEST */
else if ( buf_len == 13 && buf[0] == 0x19 && buf[1] == 0x04 && buf[2] == 0x0a )
{
_bperf_analysis_inquiry(buf, buf_len);
}
}
}
void bperf_notify_event(const uint8_t *buf, const unsigned int buf_len)
{
if ( bperf_main_thread_status == BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop )
{
/* HCI_LE_ADVERTISING_REPORT */
if ( (buf_len > 12) && buf[0] == 0x3e && buf[2] == 0x02 && buf[3] == 0x01 )
{
_bperf_notify_le_scan(buf, buf_len);
}
/* HCI_INQUIRY_COMPLETE */
else if ( buf_len == 3 && buf[0] == 0x01 && buf[1] == 0x01 && buf[2] == 0x00 )
{
_bperf_analysis_inquiry(buf, buf_len);
}
/* HCI_REMOTE_NAME_REQUEST_COMPLETE */
else if ( buf[0] == 0x07 && buf[1] == 0xff && buf[2] == 0x00 )
{
_bperf_analysis_inquiry(buf, buf_len);
}
/* HCI_EXTEND_INQUIRY_RESULT */
else if ( buf[0] == 0x2f && buf[1] == 0xff && buf[2] == 0x01 )
{
_bperf_analysis_inquiry(buf, buf_len);
}
}
}
void bperf_notify_acl(const uint8_t *buf, const unsigned int buf_len)
{
if ( bperf_main_thread_status == BPERF_STATE_THREAD_RUNNING && !bperf_main_thread_should_stop )
{
/* A2DP Sink */
if ( buf[8] == 0x80 && buf[9] == 0x60 )
{
_bperf_mem_record_event(bperf_event_a2dp, buf, buf_len);
if ( buf[20] == 0x00 ) /* SCMS-T */
bperf_global_bitpool = buf[24];
else
bperf_global_bitpool = buf[23];
}
/* A2DP Src */
else if ( buf_len == 587 && buf[8] == 0x80 && buf[9] == 0x60 && buf[20] == 0x00 )
{
_bperf_mem_record_event(bperf_event_a2dp, buf, buf_len);
bperf_global_bitpool = buf[24];
}
/* HID_Mouse : Microsoft Sculpt Comfort Mouse */
else if ( buf_len == 19 && buf[2] == 0x0f && buf[3] == 0x00 && buf[4] == 0x0b && buf[5] == 0x00 && buf[9] == 0x1a )
{
_bperf_mem_record_event(bperf_event_hid_cursor, buf, buf_len);
}
/* HID_Mouse : Logitech M557 */
else if ( buf_len == 16 && buf[2] == 0x0c && buf[3] == 0x00 && buf[4] == 0x08 && buf[5] == 0x00 && buf[8] == 0xa1 )
{
_bperf_mem_record_event(bperf_event_hid_cursor, buf, buf_len);
}
/* HID_Mouse : Logitech M558 */
else if ( buf_len == 17 && buf[2] == 0x0d && buf[3] == 0x00 && buf[4] == 0x09 && buf[5] == 0x00 && buf[8] == 0xa1 )
{
_bperf_mem_record_event(bperf_event_hid_cursor, buf, buf_len);
}
/* HOGP_Mouse : Microsoft Designer BLE Mouse*/
else if ( buf_len == 20 && buf[2] == 0x10 && buf[3] == 0x00 && buf[4] == 0x0c && buf[5] == 0x00 && buf[8] == 0x1b )
{
_bperf_mem_record_event(bperf_event_hogp_cursor, buf, buf_len);
}
/* HOGP_Mouse : Elecom BLE Mouse */
else if ( buf_len == 17 && buf[2] == 0x0d && buf[3] == 0x00 && buf[4] == 0x09 && buf[5] == 0x00 && buf[8] == 0x1b )
{
_bperf_mem_record_event(bperf_event_hogp_cursor, buf, buf_len);
}
/* HID : Logitech Keyboard */
else if ( buf_len == 18 && buf[2] == 0x0e && buf[3] == 0x00 && buf[4] == 0x0a && buf[5] == 0x00 && buf[8] == 0xa1 )
{
_bperf_mem_record_event(bperf_event_hid, buf, buf_len);
}
/* HID : SNOW RC */
else if ( buf_len == 13 && buf[2] == 0x09 && buf[3] == 0x00 && buf[4] == 0x05 && buf[5] == 0x00 && buf[8] == 0xa1 )
{
_bperf_mem_record_event(bperf_event_hid, buf, buf_len);
}
/* HID : HT RC Button */
else if ( buf_len == 12 && buf[2] == 0x08 && buf[3] == 0x00 && buf[4] == 0x04 && buf[5] == 0x00 && buf[8] == 0x1b )
{
_bperf_mem_record_event(bperf_event_hogp, buf, buf_len);
}
/* HID : HT RC Button */
else if ( buf_len == 13 && buf[2] == 0x09 && buf[3] == 0x00 && buf[4] == 0x05 && buf[5] == 0x00 && buf[8] == 0x1b )
{
_bperf_mem_record_event(bperf_event_hogp, buf, buf_len);
}
/* GATT : HT RC Voice Search (2541) */
if ( (buf_len == 12 || buf_len == 31) &&
(buf[2] == 0x08 || buf[2] == 0x1b) && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x35 && buf[10] == 0x00 )
{
bperf_global_voble_codec = 0;
_bperf_mem_record_event(bperf_event_voice, buf, buf_len);
}
/* GATT : HT RC Voice Search (2640) */
else if ( buf_len == 31 && buf[2] == 0x1b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x3f && buf[10] == 0x00 )
{
bperf_global_voble_codec = 0;
_bperf_mem_record_event(bperf_event_voice, buf, buf_len);
}
/* GATT : HT RC Voice Search (2640)(BLE Data Length Extension) */
else if ( buf_len == 111 && buf[2] == 0x6b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x3f && buf[10] == 0x00 )
{
bperf_global_voble_codec = 0;
_bperf_mem_record_event(bperf_event_voice, buf, buf_len);
}
/* GATT : Airoha Voice Search */
else if ( buf_len == 31 && buf[2] == 0x1b && buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x29 && buf[10] == 0x00 )
{
bperf_global_voble_codec = 0;
_bperf_mem_record_event(bperf_event_voice, buf, buf_len);
}
/* GATT : Nordic Voice Search, Turnkey */
else if ( buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x1d && buf[10] == 0x00 )
{
bperf_global_voble_codec = 1;
_bperf_mem_record_event(bperf_event_voice, buf, buf_len);
}
/* GATT : Nordic Voice Search, Huitong */
else if ( buf[3] == 0x00 && buf[8] == 0x1b && buf[9] == 0x23 && buf[10] == 0x00 )
{
bperf_global_voble_codec = 1;
_bperf_mem_record_event(bperf_event_voice, buf, buf_len);
}
/* GATT : HT RC FW Upgrade */
else if ( buf_len == 29 && buf[2] == 0x19 && buf[3] == 0x00 && buf[4] == 0x15 && buf[5] == 0x00 && buf[9] == 0x48 && buf[10] == 0x00 )
{
_bperf_mem_record_event(bperf_event_rc_fw_upgrade, buf, buf_len);
}
#if 0
/* HID : DS4 */
else if ( buf_len == 19 && buf[2] == 0x0f && buf[3] == 0x00 && buf[4] == 0x0b && buf[5] == 0x00 && buf[8] == 0xa1 )
{
_bperf_mem_record_event(bperf_event_hid, buf, buf_len);
}
#endif
}
}
void bperf_set_average_timer(const unsigned int average_timer)
{
printf("[bperf] average timer length is set to %d secondsd\n", average_timer);
bperf_average_total_time_index = average_timer;
bperf_average_total_time = average_timer;
bperf_average_accumulate = 1;
}
void bperf_init()
{
printf("[bperf] Version : %s\n", BPERF_LIBRARY_VERSION);
bperf_global_counter = 0;
osi_pthread_mutex_init(&event_data_lock, NULL);
_bperf_thread_start();
return;
}
void bperf_uninit()
{
_bperf_thread_stop();
_bperf_mem_free();
osi_pthread_mutex_destroy(&event_data_lock);
return;
}