Merge d478e6b35e6bfe6acf3edd08d447d10aedc3015d on remote branch
Change-Id: I54669fb0959fe423072ec07e0907b095212ebf9b
diff --git a/Android.mk b/Android.mk
index cd2c3ae..a4bfb20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,3 +1,15 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+TMP_LOCAL_PATH := $(LOCAL_PATH)
+
ifeq ($(call is-vendor-board-platform,QCOM),true)
-include $(call all-named-subdir-makefiles,libbt-vendor)
+include $(TMP_LOCAL_PATH)/libbt-vendor/Android.mk
endif # is-vendor-board-platform
+
+include $(TMP_LOCAL_PATH)/tools/Android.mk
+
+ifeq ($(TARGET_USE_QTI_BT_STACK),true)
+include $(TMP_LOCAL_PATH)/bthost_ipc/Android.mk
+endif #TARGET_USE_QTI_BT_STACK
diff --git a/bthost_ipc/Android.mk b/bthost_ipc/Android.mk
new file mode 100644
index 0000000..649f2b4
--- /dev/null
+++ b/bthost_ipc/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -Wno-unused-variable
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wno-format
+LOCAL_CFLAGS += -Wno-sign-compare
+LOCAL_CFLAGS += -Wno-format-extra-args
+LOCAL_CFLAGS += -Wno-sometimes-uninitialized
+LOCAL_CFLAGS += -Wno-sign-compare
+LOCAL_CFLAGS += -Wno-unused-function
+
+LOCAL_SRC_FILES := bthost_ipc.c
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/bthost_ipc.h
+
+LOCAL_MODULE := libbthost_if
+LOCAL_MODULE_SUFFIX := .so
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_HEADER_LIBRARIES := libhardware_headers
+LOCAL_MODULE_TAGS := optional
+ifdef TARGET_2ND_ARCH
+LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib
+LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64
+else
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_SHARED_LIBRARIES)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/bthost_ipc/bthost_ipc.c b/bthost_ipc/bthost_ipc.c
new file mode 100644
index 0000000..f0a2897
--- /dev/null
+++ b/bthost_ipc/bthost_ipc.c
@@ -0,0 +1,1569 @@
+/* Copyright (C) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *****************************************************************************/
+/*****************************************************************************
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+/* bthost_ipc.c
+ *
+ * Description: Implements IPC interface between HAL and BT host
+ *
+ *****************************************************************************/
+#include <time.h>
+#include <unistd.h>
+
+#include "ldac_level_bit_rate_lookup.h"
+#include "bthost_ipc.h"
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware/hardware.h>
+#include <log/log.h>
+#include <cutils/properties.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "bthost_ipc"
+
+static int bt_split_a2dp_enabled = 0;
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+/* Below two values adds up to 8 sec retry to address IOT issues*/
+#define STREAM_START_MAX_RETRY_COUNT 10
+#define STREAM_START_MAX_RETRY_LOOPER 8
+#define CTRL_CHAN_RETRY_COUNT 3
+#define CHECK_A2DP_READY_MAX_COUNT 20
+
+#define CASE_RETURN_STR(const) case const: return #const;
+
+#define FNLOG() ALOGW(LOG_TAG, "%s", __FUNCTION__);
+#define DEBUG(fmt, ...) ALOGD(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define INFO(fmt, ...) ALOGI(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define WARN(fmt, ...) ALOGW(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+#define ERROR(fmt, ...) ALOGE(LOG_TAG, "%s: " fmt,__FUNCTION__, ## __VA_ARGS__)
+
+#define ASSERTC(cond, msg, val) if (!(cond)) {ERROR("### ASSERT : %s line %d %s (%d) ###", __FILE__, __LINE__, msg, val);}
+
+/*****************************************************************************
+** Local type definitions
+******************************************************************************/
+
+struct a2dp_stream_common audio_stream;
+bt_lib_callback_t *stack_cb = NULL;
+static volatile unsigned char ack_recvd = 0;
+pthread_cond_t ack_cond = PTHREAD_COND_INITIALIZER;
+static int test = 0;
+static bool update_initial_sink_latency = false;
+int wait_for_stack_response(uint8_t time_to_wait);
+bool resp_received = false;
+static char a2dp_hal_imp[PROPERTY_VALUE_MAX] = "false";
+/*****************************************************************************
+** Static functions
+******************************************************************************/
+
+audio_sbc_encoder_config_t sbc_codec;
+audio_aptx_encoder_config_t aptx_codec;
+audio_aptx_tws_encoder_config_t aptx_tws_codec;
+audio_aac_encoder_config_t aac_codec;
+audio_ldac_encoder_config_t ldac_codec;
+audio_celt_encoder_config_t celt_codec;
+/*****************************************************************************
+** Functions
+******************************************************************************/
+void a2dp_open_ctrl_path(struct a2dp_stream_common *common);
+void ldac_codec_parser(uint8_t *codec_cfg);
+/*****************************************************************************
+** Miscellaneous helper functions
+******************************************************************************/
+static const char* dump_a2dp_ctrl_event(char event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(A2DP_CTRL_CMD_NONE)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_READY)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_START)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_STOP)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_SUSPEND)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_SUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_CMD_CHECK_STREAM_STARTED)
+ CASE_RETURN_STR(A2DP_CTRL_GET_CODEC_CONFIG)
+ CASE_RETURN_STR(A2DP_CTRL_GET_MULTICAST_STATUS)
+ CASE_RETURN_STR(A2DP_CTRL_GET_CONNECTION_STATUS)
+ default:
+ return "UNKNOWN MSG ID";
+ }
+}
+
+static const char* dump_a2dp_ctrl_ack(tA2DP_CTRL_ACK resp)
+{
+ switch(resp)
+ {
+ CASE_RETURN_STR(A2DP_CTRL_ACK_SUCCESS)
+ CASE_RETURN_STR(A2DP_CTRL_ACK_FAILURE)
+ CASE_RETURN_STR(A2DP_CTRL_ACK_INCALL_FAILURE)
+ CASE_RETURN_STR(A2DP_CTRL_ACK_UNSUPPORTED)
+ CASE_RETURN_STR(A2DP_CTRL_ACK_PENDING)
+ CASE_RETURN_STR(A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS)
+ CASE_RETURN_STR(A2DP_CTRL_ACK_PREVIOUS_COMMAND_PENDING)
+ CASE_RETURN_STR(A2DP_CTRL_SKT_DISCONNECTED)
+ CASE_RETURN_STR(A2DP_CTRL_ACK_UNKNOWN)
+ default:
+ return "UNKNOWN ACK ID";
+ }
+}
+
+static const char* dump_a2dp_hal_state(int event)
+{
+ switch(event)
+ {
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STARTING)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STARTED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STOPPING)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STOPPED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_SUSPENDED)
+ CASE_RETURN_STR(AUDIO_A2DP_STATE_STANDBY)
+ default:
+ return "UNKNOWN STATE ID";
+ }
+}
+static void* a2dp_codec_parser(uint8_t *codec_cfg, audio_format_t *codec_type,
+ uint32_t *sample_freq)
+{
+ char byte,len;
+ uint8_t *p_cfg = codec_cfg;
+ ALOGW("%s",__func__);
+ ALOGW("%s: codec_type = %x",__func__, codec_cfg[CODEC_OFFSET]);
+ if (codec_cfg[CODEC_OFFSET] == CODEC_TYPE_PCM)
+ {
+ *codec_type = AUDIO_FORMAT_PCM_16_BIT;
+ //For the time being Audio does not require any param to be passed for PCM so returning null
+ return NULL;
+ }
+ else if (codec_cfg[CODEC_OFFSET] == CODEC_TYPE_SBC)
+ {
+ memset(&sbc_codec,0,sizeof(audio_sbc_encoder_config_t));
+ p_cfg++;//skip dev idx
+ len = *p_cfg++;
+ p_cfg++;//skip media type
+ len--;
+ p_cfg++;
+ len--;
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_SBC_FREQ_MASK)
+ {
+ case A2D_SBC_SAMP_FREQ_48:
+ sbc_codec.sampling_rate = 48000;
+ break;
+ case A2D_SBC_SAMP_FREQ_44:
+ sbc_codec.sampling_rate = 44100;
+ break;
+ case A2D_SBC_SAMP_FREQ_32:
+ sbc_codec.sampling_rate = 3200;
+ break;
+ case A2D_SBC_SAMP_FREQ_16:
+ sbc_codec.sampling_rate = 16000;
+ break;
+ default:
+ ALOGE("SBC:Unkown sampling rate");
+ }
+
+ switch (byte & A2D_SBC_CHN_MASK)
+ {
+ case A2D_SBC_CH_MD_JOINT:
+ sbc_codec.channels = 3;
+ break;
+ case A2D_SBC_CH_MD_STEREO:
+ sbc_codec.channels = 2;
+ break;
+ case A2D_SBC_CH_MD_DUAL:
+ sbc_codec.channels = 1;
+ break;
+ case A2D_SBC_CH_MD_MONO:
+ sbc_codec.channels = 0;
+ break;
+ default:
+ ALOGE("SBC:Unknow channel mode");
+ }
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_SBC_BLK_MASK)
+ {
+ case A2D_SBC_BLOCKS_16:
+ sbc_codec.blk_len = 16;
+ break;
+ case A2D_SBC_BLOCKS_12:
+ sbc_codec.blk_len = 12;
+ break;
+ case A2D_SBC_BLOCKS_8:
+ sbc_codec.blk_len = 8;
+ break;
+ case A2D_SBC_BLOCKS_4:
+ sbc_codec.blk_len = 4;
+ break;
+ default:
+ ALOGE("SBD:Unknown block length");
+ }
+
+ switch (byte & A2D_SBC_SUBBAND_MASK)
+ {
+ case A2D_SBC_SUBBAND_8:
+ sbc_codec.subband = 8;
+ break;
+ case A2D_SBC_SUBBAND_4:
+ sbc_codec.subband = 4;
+ break;
+ default:
+ ALOGE("SBD:Unknown subband");
+ }
+ switch (byte & A2D_SBC_ALLOC_MASK)
+ {
+ case A2D_SBC_ALLOC_MD_L:
+ sbc_codec.alloc = 1;
+ break;
+ case A2D_SBC_ALLOC_MD_S:
+ sbc_codec.alloc = 2;
+ default:
+ ALOGE("SBD:Unknown alloc method");
+ }
+ sbc_codec.min_bitpool = *p_cfg++;
+ len--;
+ sbc_codec.max_bitpool = *p_cfg++;
+ len--;
+ if (len == 0)
+ {
+ ALOGW("Copied codec config");
+ }
+ p_cfg += 2; //skip mtu
+ sbc_codec.bitrate = *p_cfg++;
+ sbc_codec.bitrate |= (*p_cfg++ << 8);
+ sbc_codec.bitrate |= (*p_cfg++ << 16);
+ sbc_codec.bitrate |= (*p_cfg++ << 24);
+ *codec_type = AUDIO_FORMAT_SBC;
+
+ if(sample_freq) *sample_freq = sbc_codec.sampling_rate;
+
+ ALOGW("SBC: Done copying full codec config");
+ return ((void *)(&sbc_codec));
+ } else if (codec_cfg[CODEC_OFFSET] == CODEC_TYPE_AAC)
+ {
+ uint16_t aac_samp_freq = 0;
+ uint32_t aac_bit_rate = 0;
+ memset(&aac_codec,0,sizeof(audio_aac_encoder_config_t));
+ p_cfg++;//skip dev idx
+ len = *p_cfg++;
+ p_cfg++;//skip media type
+ len--;
+ p_cfg++;//skip codec type
+ len--;
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_AAC_IE_OBJ_TYPE_MSK)
+ {
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_LC;
+ break;
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LC:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_LC;
+ break;
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LTP:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_LTP;
+ break;
+ case A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_SCA:
+ aac_codec.enc_mode = AUDIO_FORMAT_AAC_SUB_SCALABLE;
+ break;
+ default:
+ ALOGE("AAC:Unknown encoder mode");
+ }
+ //USE 0 (AAC_LC) as hardcoded value till Audio
+ //define constants
+ aac_codec.enc_mode = 0;
+ //USE LOAS(1) or LATM(4) hardcoded values till
+ //Audio define proper constants
+ aac_codec.format_flag = 4;
+ byte = *p_cfg++;
+ len--;
+ aac_samp_freq = byte << 8; //1st byte of sample_freq
+ byte = *p_cfg++;
+ len--;
+ aac_samp_freq |= byte & 0x00F0; //1st nibble of second byte of samp_freq
+
+ switch (aac_samp_freq) {
+ case 0x8000: aac_codec.sampling_rate = 8000; break;
+ case 0x4000: aac_codec.sampling_rate = 11025; break;
+ case 0x2000: aac_codec.sampling_rate = 12000; break;
+ case 0x1000: aac_codec.sampling_rate = 16000; break;
+ case 0x0800: aac_codec.sampling_rate = 22050; break;
+ case 0x0400: aac_codec.sampling_rate = 24000; break;
+ case 0x0200: aac_codec.sampling_rate = 32000; break;
+ case 0x0100: aac_codec.sampling_rate = 44100; break;
+ case 0x0080: aac_codec.sampling_rate = 48000; break;
+ case 0x0040: aac_codec.sampling_rate = 64000; break;
+ case 0x0020: aac_codec.sampling_rate = 88200; break;
+ case 0x0010: aac_codec.sampling_rate = 96000; break;
+ default:
+ ALOGE("Invalid sample_freq: %x", aac_samp_freq);
+ }
+
+ switch (byte & A2D_AAC_IE_CHANNELS_MSK)
+ {
+ case A2D_AAC_IE_CHANNELS_1:
+ aac_codec.channels = 1;
+ break;
+ case A2D_AAC_IE_CHANNELS_2:
+ aac_codec.channels = 2;
+ break;
+ default:
+ ALOGE("AAC:Unknown channel mode");
+ }
+ byte = *p_cfg++; //Move to VBR byte
+ len--;
+ switch (byte & A2D_AAC_IE_VBR_MSK)
+ {
+ case A2D_AAC_IE_VBR:
+ break;
+ default:
+ ALOGE("AAC:VBR not supported");
+ }
+ aac_bit_rate = 0x7F&byte;
+ //Move it 2nd byte of 32 bit word. leaving the VBR bit
+ aac_bit_rate = aac_bit_rate << 16;
+ byte = *p_cfg++; //Move to 2nd byteof bitrate
+ len--;
+
+ //Move it to 3rd byte of 32bit word
+ aac_bit_rate |= 0x0000FF00 & (((uint32_t)byte)<<8);
+ byte = *p_cfg++; //Move to 3rd byte of bitrate
+ len--;
+
+ aac_bit_rate |= 0x000000FF & (((uint32_t)byte));
+ aac_codec.bitrate = aac_bit_rate;
+
+ *codec_type = AUDIO_FORMAT_AAC;
+
+ if(sample_freq) *sample_freq = aac_codec.sampling_rate;
+ ALOGW("AAC: Done copying full codec config");
+ return ((void *)(&aac_codec));
+ }
+ else if (codec_cfg[CODEC_OFFSET] == NON_A2DP_CODEC_TYPE)
+ {
+ uint32_t vendor_ldac_id = 0x0;
+ vendor_ldac_id = (codec_cfg[VENDOR_ID_OFFSET] & 0x000000FF) |
+ ((codec_cfg[VENDOR_ID_OFFSET + 1]) << 8 & 0x0000FF00) |
+ ((codec_cfg[VENDOR_ID_OFFSET + 2]) << 16 & 0x00FF0000) |
+ ((codec_cfg[VENDOR_ID_OFFSET + 3]) << 24 & 0xFF000000);
+
+ if (codec_cfg[VENDOR_ID_OFFSET] == VENDOR_APTX &&
+ codec_cfg[CODEC_ID_OFFSET] == APTX_CODEC_ID)
+ {
+ ALOGW("AptX-classic codec");
+ *codec_type = AUDIO_FORMAT_APTX;
+ }
+ if (codec_cfg[VENDOR_ID_OFFSET] == VENDOR_APTX_HD &&
+ codec_cfg[CODEC_ID_OFFSET] == APTX_HD_CODEC_ID)
+ {
+ ALOGW("AptX-HD codec");
+ *codec_type = AUDIO_FORMAT_APTX_HD;
+ }
+
+ if (vendor_ldac_id == VENDOR_LDAC &&
+ codec_cfg[CODEC_ID_OFFSET] == LDAC_CODEC_ID)
+ {
+ ALOGW("LDAC codec");
+ *codec_type = AUDIO_FORMAT_LDAC;
+ ldac_codec_parser(codec_cfg);
+ if (sample_freq) *sample_freq = ldac_codec.sampling_rate;
+ return ((void *)&ldac_codec);
+ }
+ if (codec_cfg[VENDOR_ID_OFFSET] == VENDOR_APTX_HD &&
+ codec_cfg[CODEC_ID_OFFSET] == APTX_TWS_CODEC_ID)
+ {
+ ALOGW("AptX-TWS codec");
+ *codec_type = ENC_CODEC_TYPE_APTX_DUAL_MONO;
+ //aptx_codec.sync_mode = 0x01;
+ }
+ memset(&aptx_codec,0,sizeof(audio_aptx_encoder_config_t));
+ p_cfg++; //skip dev_idx
+ len = *p_cfg++;//LOSC
+ p_cfg++; // Skip media type
+ len--;
+ p_cfg++; //codec_type
+ len--;
+ p_cfg+=4;//skip vendor id
+ len -= 4;
+ p_cfg += 2; //skip codec id
+ len -= 2;
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_APTX_SAMP_FREQ_MASK)
+ {
+ case A2D_APTX_SAMP_FREQ_48:
+ aptx_codec.sampling_rate = 48000;
+ break;
+ case A2D_APTX_SAMP_FREQ_44:
+ aptx_codec.sampling_rate = 44100;
+ break;
+ default:
+ ALOGE("Unknown sampling rate");
+ }
+ switch (byte & A2D_APTX_CHAN_MASK)
+ {
+ case A2D_APTX_CHAN_STEREO:
+ case A2D_APTX_TWS_CHAN_MODE:
+ aptx_codec.channels = 2;
+ break;
+ case A2D_APTX_CHAN_MONO:
+ aptx_codec.channels = 1;
+ break;
+ default:
+ ALOGE("Unknown channel mode");
+ }
+ if (*codec_type == AUDIO_FORMAT_APTX_HD) {
+ p_cfg += 4;
+ len -= 4;//ignore 4 bytes not used
+ }
+ if (len == 0)
+ {
+ ALOGW("Codec config copied");
+ }
+ p_cfg += 2; //skip mtu
+
+ aptx_codec.bitrate = *p_cfg++;
+ aptx_codec.bitrate |= (*p_cfg++ << 8);
+ aptx_codec.bitrate |= (*p_cfg++ << 16);
+ aptx_codec.bitrate |= (*p_cfg++ << 24);
+
+ if(sample_freq) *sample_freq = aptx_codec.sampling_rate;
+ ALOGW("APTx: Done copying full codec config");
+ if (*codec_type == ENC_CODEC_TYPE_APTX_DUAL_MONO)
+ {
+ memset(&aptx_tws_codec, 0, sizeof(audio_aptx_tws_encoder_config_t));
+ memcpy(&aptx_tws_codec, &aptx_codec, sizeof(aptx_codec));
+ aptx_tws_codec.sync_mode = 0x02;
+ return ((void *)&aptx_tws_codec);
+ }
+ return ((void *)&aptx_codec);
+ }
+ else if (codec_cfg[CODEC_OFFSET] == CODEC_TYPE_CELT)
+ {
+ uint8_t celt_samp_freq = 0;
+ uint32_t celt_bit_rate = 0;
+ memset(&celt_codec,0,sizeof(audio_celt_encoder_config_t));
+ switch(codec_cfg[4] & A2D_CELT_SAMP_FREQ_MASK)
+ {
+ case A2D_CELT_SAMP_FREQ_48:
+ celt_codec.sampling_rate = 48000;
+ break;
+ case A2D_CELT_SAMP_FREQ_44:
+ celt_codec.sampling_rate = 44100;
+ break;
+ case A2D_CELT_SAMP_FREQ_32:
+ celt_codec.sampling_rate = 32000;
+ break;
+ default:
+ ALOGE("CELT: unknown sampl freq");
+ }
+ switch(codec_cfg[4] & A2D_CELT_CHANNEL_MASK)
+ {
+ case A2D_CELT_CH_MONO:
+ celt_codec.channels = 1;
+ break;
+ case A2D_CELT_CH_STEREO:
+ celt_codec.channels = 2;
+ break;
+ default:
+ ALOGE("CELT: unknown channel");
+ }
+ switch(codec_cfg[5] & A2D_CELT_FRAME_SIZE_MASK)
+ {
+ case A2D_CELT_FRAME_SIZE_64:
+ celt_codec.frame_size = 64;
+ break;
+ case A2D_CELT_FRAME_SIZE_128:
+ celt_codec.frame_size = 128;
+ break;
+ case A2D_CELT_FRAME_SIZE_256:
+ celt_codec.frame_size = 256;
+ break;
+ case A2D_CELT_FRAME_SIZE_512:
+ celt_codec.frame_size = 512;
+ break;
+ default:
+ ALOGE("CELT: unknown frame size");
+ }
+ celt_codec.complexity = codec_cfg[5] & A2D_CELT_COMPLEXITY_MASK;
+ celt_codec.prediction_mode =
+ (codec_cfg[6] & A2D_CELT_PREDICTION_MODE_MASK) >> 4;
+ celt_codec.vbr_flag = codec_cfg[6] & A2D_CELT_VBR_MASK;
+
+ celt_codec.bitrate |= codec_cfg[7];
+ celt_codec.bitrate = celt_codec.bitrate << 8;
+ celt_codec.bitrate |= codec_cfg[8];
+ celt_codec.bitrate = celt_codec.bitrate << 8;
+ celt_codec.bitrate |= codec_cfg[9];
+ celt_codec.bitrate = celt_codec.bitrate << 8;
+ celt_codec.bitrate |= codec_cfg[10];
+ *codec_type = AUDIO_CODEC_TYPE_CELT;
+
+ ALOGE("CELT Bitrate: 0%x", celt_codec.bitrate);
+ ALOGE("CELT channel: 0%x", celt_codec.channels);
+ ALOGE("CELT complexity: 0%x", celt_codec.complexity);
+ ALOGE("CELT frame_size: 0%x", celt_codec.frame_size);
+ ALOGE("CELT prediction_mode: 0%x", celt_codec.prediction_mode);
+ ALOGE("CELT sampl_freq: 0%x", celt_codec.sampling_rate);
+ ALOGE("CELT vbr_flag: 0%x", celt_codec.vbr_flag);
+ ALOGE("CELT codec_type: 0%x", codec_type);
+ return ((void *)(&celt_codec));
+ }
+ return NULL;
+}
+
+int a2dp_read_codec_config(struct a2dp_stream_common *common,uint8_t idx)
+{
+ char cmd[2];//,ack;
+ int i,len = 0;
+ uint8_t *p_codec_cfg = common->codec_cfg;
+ cmd[0] = A2DP_CTRL_GET_CODEC_CONFIG;
+ cmd[1] = idx;
+ ALOGW("%s",__func__);
+ memset(p_codec_cfg,0,MAX_CODEC_CFG_SIZE);
+ tA2DP_CTRL_ACK status = A2DP_CTRL_ACK_FAILURE;
+
+ if(stack_cb)
+ {
+ ALOGW("Calling get_codec_cfg_cb");
+ resp_received = false;
+ stack_cb->get_codec_cfg_cb();
+ ack_recvd = 0;
+ if (resp_received == false)
+ {
+ ALOGW("%s: stack resp not received",__func__);
+ wait_for_stack_response(1);
+ }
+ status = common->ack_status;
+ common->ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ ALOGW("get_codec_cfg_cb returned: status = %s",dump_a2dp_ctrl_ack(status));
+ }
+ return status;
+}
+
+void a2dp_get_multicast_status(uint8_t *mcast_status)
+{
+ ALOGW("%s",__func__);
+ if (stack_cb)
+ {
+ resp_received = false;
+ stack_cb->get_mcast_status_cb();
+ ack_recvd = 0;
+ if (resp_received == false)
+ {
+ ALOGW("%s: stack resp not received",__func__);
+ wait_for_stack_response(1);
+ }
+ *mcast_status = audio_stream.multicast;
+ }
+ else
+ *mcast_status = 0;
+}
+
+void a2dp_get_num_connected_devices(uint8_t *num_dev)
+{
+ ALOGW("%s",__func__);
+ if (stack_cb)
+ {
+ resp_received = false;
+ stack_cb->get_connected_device_cb();
+ ack_recvd = 0;
+ if (resp_received == false)
+ {
+ ALOGW("%s: stack resp not received",__func__);
+ wait_for_stack_response(1);
+ }
+ *num_dev = 1;
+ }
+}
+/*****************************************************************************
+**
+** AUDIO DATA PATH
+**
+*****************************************************************************/
+
+void a2dp_stream_common_init(struct a2dp_stream_common *common)
+{
+ pthread_mutexattr_t lock_attr;
+
+ //FNLOG();
+ ALOGW("%s",__func__);
+
+ pthread_mutexattr_init(&lock_attr);
+ pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&common->lock, &lock_attr);
+ pthread_mutexattr_destroy(&lock_attr);
+ common->state = AUDIO_A2DP_STATE_STOPPED;
+ common->sink_latency = A2DP_DEFAULT_SINK_LATENCY;
+
+ bt_split_a2dp_enabled = false;
+}
+
+int wait_for_stack_response(uint8_t time_to_wait)
+{
+ ALOGW("wait_for_stack_response");
+ struct timespec now,wait_time;
+ uint8_t retry = 0;
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ if (stack_cb == NULL)
+ {
+ ALOGE("stack deinitialized");
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+ return retry;
+ }
+ // in race condition, ack_status is updated as SUCCESS
+ // without ack_recvd made 0.
+ if (audio_stream.ack_status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ ALOGE("ACK Success, no need to wait");
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+ return retry;
+ }
+ while (retry < CTRL_CHAN_RETRY_COUNT &&
+ ack_recvd == 0)
+ {
+ ALOGW("entering coditional wait: retry = %d, ack_recvd = %d",retry,ack_recvd);
+ clock_gettime(CLOCK_REALTIME, &now);
+ now.tv_sec += time_to_wait;
+ pthread_cond_timedwait(&ack_cond, &audio_stream.ack_lock, &now);
+ retry++;
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+ if (ack_recvd) {
+ ALOGV("wait_for_stack_response: ack received");
+ }
+ ALOGV("wait_for_stack_response returning retry = %d",retry);
+ return retry;
+}
+static void copy_status(tA2DP_CTRL_ACK status)
+{
+ ALOGW("copy_status: status = %d",status);
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ audio_stream.ack_status = status;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+void bt_stack_init(bt_lib_callback_t *lib_cb)
+{
+ ALOGW("bt_stack_init");
+ int ret = 0;
+ stack_cb = lib_cb;
+}
+void bt_stack_deinit(tA2DP_CTRL_ACK status)
+{
+ ALOGW("bt_stack_deinit");
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ stack_cb = NULL;
+ audio_stream.ack_status = status;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+
+void bt_stack_on_stream_started(tA2DP_CTRL_ACK status)
+{
+ ALOGW("bt_stack_on_stream_started: status = %d",status);
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ if ((audio_stream.ack_status != A2DP_CTRL_ACK_UNKNOWN) && (status == A2DP_CTRL_ACK_PENDING)) {
+ ALOGW("status already changed to = %d, don't update pending",audio_stream.ack_status);
+ }
+ else {
+ audio_stream.ack_status = status;
+ }
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+
+void bt_stack_on_stream_suspended(tA2DP_CTRL_ACK status)
+{
+ ALOGW("bt_stack_on_stream_suspended status = %d, ack_status = %d ", status, audio_stream.ack_status);
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ if ((audio_stream.ack_status != A2DP_CTRL_ACK_UNKNOWN) && (status == A2DP_CTRL_ACK_PENDING)) {
+ ALOGW("status already changed to = %d, don't update pending",audio_stream.ack_status);
+ }
+ else {
+ audio_stream.ack_status = status;
+ ALOGW("bt_stack_on_stream_suspended updating ack_status = %d ", audio_stream.ack_status);
+ }
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ ALOGW("bt_stack_on_stream_suspended signalling pthread ");
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+ ALOGW("bt_stack_on_stream_suspended mutex unlocked ");
+}
+
+void bt_stack_on_stream_stopped(tA2DP_CTRL_ACK status)
+{
+ ALOGW("bt_stack_on_stream_stopped");
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ if ((audio_stream.ack_status != A2DP_CTRL_ACK_UNKNOWN) && (status == A2DP_CTRL_ACK_PENDING)) {
+ ALOGW("status already changed to = %d, don't update pending",audio_stream.ack_status);
+ }
+ else {
+ audio_stream.ack_status = status;
+ }
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+
+void bt_stack_on_get_codec_cfg(tA2DP_CTRL_ACK status, const char *p_cfg,
+ size_t len)
+{
+ ALOGW("bt_stack_on_get_codec_config status %s",dump_a2dp_ctrl_ack(status));
+ if (status != A2DP_CTRL_ACK_PENDING)
+ {
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ audio_stream.ack_status = status;
+ ALOGW("bt_stack_on_get_codec_config len = %d",len);
+ if (len > MAX_CODEC_CFG_SIZE) {
+ ALOGE("codec config length > MAX_CODEC_CFG_SIZE");
+ status = A2DP_CTRL_ACK_FAILURE;
+ }
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ memcpy(audio_stream.codec_cfg,p_cfg,len);
+ for (int i = 0; i < len; i++) {
+ ALOGV("audio_stream.codec_cfg[%d] = %x",i,audio_stream.codec_cfg[i]);
+ }
+ }
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+ }
+ else
+ {
+ ALOGW("bt_stack_on_get_codec_cfg status pending");
+ }
+}
+
+void bt_stack_on_get_mcast_status(uint8_t status)
+{
+ ALOGW("bt_stack_on_get_mcast_status");
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ audio_stream.multicast = status;
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+
+void bt_stack_on_get_num_connected_devices(uint8_t num_dev)
+{
+ ALOGW("bt_stack_on_get_num_connected_devices");
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ audio_stream.num_conn_dev = num_dev;
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+
+void bt_stack_on_get_connection_status(tA2DP_CTRL_ACK status)
+{
+ ALOGW("bt_stack_on_get_connection_status");
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ audio_stream.ack_status = status;
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+void bt_stack_on_check_a2dp_ready(tA2DP_CTRL_ACK status)
+{
+ ALOGW("bt_stack_on_check_a2dp_ready");
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ audio_stream.ack_status = status;
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+
+void bt_stack_on_get_sink_latency(uint16_t latency)
+{
+ ALOGW("bt_stack_on_get_sink_latency");
+ pthread_mutex_lock(&audio_stream.ack_lock);
+ audio_stream.sink_latency = latency;
+ resp_received = true;
+ if (!ack_recvd)
+ {
+ ack_recvd = 1;
+ pthread_cond_signal(&ack_cond);
+ }
+ pthread_mutex_unlock(&audio_stream.ack_lock);
+}
+
+int audio_start_stream()
+{
+ int i, j, ack_ret;
+ tA2DP_CTRL_ACK status = A2DP_CTRL_ACK_SUCCESS;
+ ALOGW("%s: state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state == AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ ALOGW("stream suspended");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true"))
+ {
+ if (audio_stream.state == AUDIO_A2DP_STATE_STARTED)
+ {
+ INFO("stream already started");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ }
+ for (j = 0; j <STREAM_START_MAX_RETRY_LOOPER; j++) {
+ for (i = 0; i < STREAM_START_MAX_RETRY_COUNT; i++)
+ {
+ if (stack_cb)
+ {
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ resp_received = false;
+ stack_cb->start_req_cb();
+ ack_recvd = 0;
+ if (!resp_received)
+ {
+ ack_ret = wait_for_stack_response(1);
+ if (ack_ret == CTRL_CHAN_RETRY_COUNT && !ack_recvd)
+ {
+ ALOGE("audio_start_stream: Failed to get ack from stack");
+ status = -1;
+ goto end;
+ }
+ }
+ status = audio_stream.ack_status;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ ALOGW("audio_start_stream status = %s",dump_a2dp_ctrl_ack(status));
+ if (status == A2DP_CTRL_ACK_PENDING)
+ {
+ ALOGW("waiting in pending");
+ ack_recvd = 0;
+ if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true"))
+ {
+ wait_for_stack_response(1);
+ if (audio_stream.ack_status == A2DP_CTRL_ACK_UNKNOWN)
+ {
+ ALOGW("audio_start_stream ack not received, fake as success");
+ status = A2DP_CTRL_ACK_SUCCESS;
+ }
+ else
+ {
+ status = audio_stream.ack_status;
+ }
+ }
+ else
+ {
+ wait_for_stack_response(5);
+ status = audio_stream.ack_status;
+ }
+ ALOGW("done waiting in pending status = %s",dump_a2dp_ctrl_ack(status));
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ }
+
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ ALOGW("a2dp stream started successfully");
+ audio_stream.state = AUDIO_A2DP_STATE_STARTED;
+ goto end;
+ }
+ else if (status == A2DP_CTRL_ACK_INCALL_FAILURE ||
+ status == A2DP_CTRL_ACK_UNSUPPORTED ||
+ status == A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS ||
+ status == A2DP_CTRL_ACK_UNKNOWN)
+ {
+ ALOGW("a2dp stream start failed: status = %s",dump_a2dp_ctrl_ack(status));
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ goto end;
+ }
+ else if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true") &&
+ status == A2DP_CTRL_ACK_PREVIOUS_COMMAND_PENDING)
+ {
+ ALOGW("a2dp stream start exited as prev command is pending, fake as success");
+ audio_stream.state = AUDIO_A2DP_STATE_STARTED;
+ goto end;
+ }
+ else if (status == A2DP_CTRL_ACK_FAILURE)
+ {
+ ALOGW("a2dp stream start failed: generic failure");
+ }
+ }
+ else
+ {
+ ALOGW("%s:Stack shutdown",__func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return A2DP_CTRL_SKT_DISCONNECTED;
+ }
+ ALOGW("%s: a2dp stream not started,wait 100mse & retry", __func__);
+ usleep(100000);
+ }
+ ALOGW("%s: Check if valid connection is still up or not", __func__);
+
+ // For every 1 sec check if a2dp is still up, to avoid
+ // blocking the audio thread forever if a2dp connection is closed
+ // for some reason
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ resp_received = false;
+ stack_cb->get_connection_status_cb();
+ ack_recvd = 0;
+ if (!resp_received)
+ {
+ ack_ret = wait_for_stack_response(1);
+ if (ack_ret == CTRL_CHAN_RETRY_COUNT && !ack_recvd)
+ {
+ ALOGE("audio_start_stream: Failed to get ack from stack");
+ status = -1;
+ goto end;
+ }
+ }
+ status = audio_stream.ack_status;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ if (status != A2DP_CTRL_ACK_SUCCESS)
+ {
+ ALOGE("%s: No valid a2dp connection\n", __func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ }
+end:
+ if (audio_stream.state != AUDIO_A2DP_STATE_STARTED)
+ {
+ ALOGE("%s: Failed to start a2dp stream", __func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return status;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ INFO("stream successfully started");
+ return status;
+}
+
+int audio_stream_open()
+{
+ ALOGW("%s",__func__);
+ a2dp_stream_common_init(&audio_stream);
+ bt_split_a2dp_enabled = true;
+ if (stack_cb != NULL)
+ {
+ ALOGW("audio_stream_open: Success");
+ return 0;
+ }
+ ALOGW("audio_stream_open: Failed");
+ return -1;
+}
+
+int audio_stream_close()
+{
+ ALOGW("%s",__func__);
+ tA2DP_CTRL_ACK status = A2DP_CTRL_ACK_SUCCESS;
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state == AUDIO_A2DP_STATE_STARTED ||
+ audio_stream.state == AUDIO_A2DP_STATE_STOPPING)
+ {
+ ALOGW("%s: Suspending audio stream",__func__);
+ if (stack_cb)
+ {
+ int ack_ret = 0;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ resp_received = false;
+ stack_cb->suspend_req_cb();
+ ack_recvd = 0;
+ if (!resp_received)
+ {
+ ack_ret = wait_for_stack_response(1);
+ if (ack_ret == 3 &&
+ audio_stream.ack_status == A2DP_CTRL_ACK_UNKNOWN)
+ {
+ ALOGE("audio_stream_close: Failed to get ack from stack");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ }
+ }
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+}
+int audio_stop_stream()
+{
+ ALOGW("%s",__func__);
+ int ret = -1;
+ tA2DP_CTRL_ACK status;
+ pthread_mutex_lock(&audio_stream.lock);
+ if (stack_cb)
+ {
+ if (audio_stream.state != AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ int ack_ret = 0;
+ ack_recvd = 0;
+ resp_received = false;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ stack_cb->suspend_req_cb();
+ if (!resp_received)
+ {
+ ack_ret = wait_for_stack_response(1);
+ if (ack_ret == CTRL_CHAN_RETRY_COUNT && !ack_recvd)
+ {
+ ALOGE("audio_stop_stream: Failed to get ack from stack");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ }
+ status = audio_stream.ack_status;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ ALOGW("audio_stop_stream: ack status = %s",dump_a2dp_ctrl_ack(status));
+ if (status == A2DP_CTRL_ACK_PENDING)
+ {
+ ack_recvd = 0;
+ if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true"))
+ {
+ wait_for_stack_response(1);
+ }
+ else
+ {
+ wait_for_stack_response(5);
+ }
+ status = audio_stream.ack_status;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ if (status == A2DP_CTRL_ACK_SUCCESS) ret = 0;
+ }
+ else if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ ALOGW("audio stop stream successful");
+ audio_stream.state = AUDIO_A2DP_STATE_STANDBY;
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ else if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true") &&
+ status == A2DP_CTRL_ACK_PREVIOUS_COMMAND_PENDING)
+ {
+ ALOGW("a2dp stream stop exited as prev command is pending, fake as success");
+ audio_stream.state = AUDIO_A2DP_STATE_STANDBY;
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ else
+ {
+ ALOGW("audio stop stream failed");
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ }
+ }
+ else
+ ALOGW("stack is down");
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ pthread_mutex_unlock(&audio_stream.lock);
+ return ret;
+}
+
+int audio_suspend_stream()
+{
+ ALOGW("%s",__func__);
+ tA2DP_CTRL_ACK status;
+
+ pthread_mutex_lock(&audio_stream.lock);
+ if (stack_cb)
+ {
+ if (audio_stream.state != AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ int ack_ret = 0;
+ ack_recvd = 0;
+ resp_received = false;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ stack_cb->suspend_req_cb();
+ if (!resp_received)
+ {
+ ack_ret = wait_for_stack_response(1);
+ if (ack_ret == CTRL_CHAN_RETRY_COUNT && !ack_recvd)
+ {
+ ALOGE("audio_suspend_stream: Failed to get ack from stack");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ }
+ status = audio_stream.ack_status;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ ALOGW("audio_suspend_stream: ack status = %s",dump_a2dp_ctrl_ack(status));
+ if (status == A2DP_CTRL_ACK_PENDING)
+ {
+ //TODO wait for the response;
+ ack_recvd = 0;
+ if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true"))
+ {
+ wait_for_stack_response(1);
+ }
+ else
+ {
+ wait_for_stack_response(5);
+ }
+ status = audio_stream.ack_status;
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ }
+ else if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ ALOGW("audio suspend stream successful");
+ pthread_mutex_unlock(&audio_stream.lock);
+ audio_stream.state = AUDIO_A2DP_STATE_SUSPENDED;
+ return 0;
+ }
+ else if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true") &&
+ status == A2DP_CTRL_ACK_PREVIOUS_COMMAND_PENDING)
+ {
+ ALOGW("a2dp stream suspend exited as prev command is pending, fake as success");
+ pthread_mutex_unlock(&audio_stream.lock);
+ audio_stream.state = AUDIO_A2DP_STATE_SUSPENDED;
+ return 0;
+ }
+ else
+ {
+ ALOGW("audio suspend stream failed");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+ }
+ }
+ }
+ else
+ ALOGW("stack is down");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return -1;
+}
+
+void audio_handoff_triggered()
+{
+ ALOGW("%s state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state != AUDIO_A2DP_STATE_STOPPED ||
+ audio_stream.state != AUDIO_A2DP_STATE_STOPPING)
+ {
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+}
+
+void clear_a2dpsuspend_flag()
+{
+ ALOGW("%s: state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ pthread_mutex_lock(&audio_stream.lock);
+ if (audio_stream.state == AUDIO_A2DP_STATE_SUSPENDED)
+ audio_stream.state = AUDIO_A2DP_STATE_STOPPED;
+ pthread_mutex_unlock(&audio_stream.lock);
+}
+
+void * audio_get_codec_config(uint8_t *multicast_status, uint8_t *num_dev,
+ audio_format_t *codec_type)
+{
+ int i, status;
+ ALOGW("%s: state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+
+ pthread_mutex_lock(&audio_stream.lock);
+ a2dp_get_multicast_status(multicast_status);
+ if (*multicast_status)
+ {
+ a2dp_get_num_connected_devices(num_dev);
+ }
+ else
+ *num_dev = 1;
+ ALOGW("got multicast status = %d dev = %d",*multicast_status,*num_dev);
+ update_initial_sink_latency = true;
+
+ for (i = 0; i < STREAM_START_MAX_RETRY_COUNT; i++)
+ {
+ status = a2dp_read_codec_config(&audio_stream, 0);
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ pthread_mutex_unlock(&audio_stream.lock);
+ if (stack_cb == NULL) {
+ ALOGW("get codec config returned due to stack deinit");
+ return NULL;
+ }
+ return (a2dp_codec_parser(&audio_stream.codec_cfg[0], codec_type, NULL));
+ }
+ INFO("%s: a2dp stream not configured,wait 100mse & retry", __func__);
+ usleep(100000);
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return NULL;
+}
+
+void* audio_get_next_codec_config(uint8_t idx, audio_format_t *codec_type)
+{
+ int i, status;
+ ALOGW("%s",__func__);
+ pthread_mutex_lock(&audio_stream.lock);
+ for (i = 0; i < STREAM_START_MAX_RETRY_COUNT; i++)
+ {
+ status = a2dp_read_codec_config(&audio_stream,idx);
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ pthread_mutex_unlock(&audio_stream.lock);
+ return (a2dp_codec_parser(&audio_stream.codec_cfg[0], codec_type, NULL));
+ }
+ INFO("%s: a2dp stream not configured,wait 100mse & retry", __func__);
+ usleep(100000);
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return NULL;
+}
+
+int audio_check_a2dp_ready()
+{
+ int i;
+ ALOGW("audio_check_a2dp_ready: state %s", dump_a2dp_hal_state(audio_stream.state));
+ tA2DP_CTRL_ACK status;
+ pthread_mutex_lock(&audio_stream.lock);
+ if (property_get("persist.vendor.bt.a2dp.hal.implementation", a2dp_hal_imp, "false") &&
+ !strcmp(a2dp_hal_imp, "true") &&
+ audio_stream.state == AUDIO_A2DP_STATE_SUSPENDED)
+ {
+ INFO("stream not ready to start");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ if (stack_cb != NULL)
+ {
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ stack_cb->a2dp_check_ready_cb();
+ ack_recvd = 0;
+ status = audio_stream.ack_status;
+ if (status == A2DP_CTRL_ACK_UNKNOWN)
+ {
+ for (i = 0; i < CHECK_A2DP_READY_MAX_COUNT; i++)
+ {
+ wait_for_stack_response(1);
+ status = audio_stream.ack_status;
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ ALOGW("audio_check_a2dp_ready : %s",dump_a2dp_ctrl_ack(status));
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 1;
+ }
+ ALOGW("audio_check_a2dp_ready(): a2dp stream not ready, wait 200msec & retry");
+ usleep(200000);
+ }
+ }
+ audio_stream.ack_status = A2DP_CTRL_ACK_UNKNOWN;
+ ALOGW("audio_check_a2dp_ready = %s",dump_a2dp_ctrl_ack(status));
+ }
+ else
+ {
+ ALOGW("audio_check_a2dp_ready = NOT ready - callbacks not registered");
+ pthread_mutex_unlock(&audio_stream.lock);
+ return 0;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return status == A2DP_CTRL_ACK_SUCCESS;
+}
+
+uint16_t audio_get_a2dp_sink_latency()
+{
+ ALOGW("%s: state = %s",__func__,dump_a2dp_hal_state(audio_stream.state));
+ pthread_mutex_lock(&audio_stream.lock);
+ if (update_initial_sink_latency)
+ {
+ if (stack_cb)
+ {
+ resp_received = false;
+ stack_cb->get_sink_latency_cb();
+ ack_recvd = 0;
+ if (resp_received == false)
+ wait_for_stack_response(1);
+ }
+ else
+ audio_stream.sink_latency = A2DP_DEFAULT_SINK_LATENCY;
+ update_initial_sink_latency = false;
+ }
+ pthread_mutex_unlock(&audio_stream.lock);
+ return audio_stream.sink_latency;
+}
+
+bool audio_is_scrambling_enabled(void)
+{
+ audio_format_t codec_type;
+ int i;
+ char value[PROPERTY_VALUE_MAX];
+ uint8_t *codec_cfg = NULL;
+ uint32_t sample_freq = 0;
+ memset(value, '\0', sizeof(char)*PROPERTY_VALUE_MAX);
+ ALOGW("audio_is_scrambling_enabled: state %s",
+ dump_a2dp_hal_state(audio_stream.state));
+ tA2DP_CTRL_ACK status = A2DP_CTRL_ACK_UNKNOWN;
+
+ if (stack_cb == NULL)
+ {
+ ALOGW("audio_is_scrambling_enabled returned false due to stack deinit");
+ return false;
+ }
+
+ if( property_get("persist.vendor.bluetooth.soc.scram_freqs", value, "false") &&
+ !strcmp(value, "false"))
+ {
+ property_get("persist.vendor.bt.soc.scram_freqs", value, "false");
+ if(!strcmp(value, "false"))
+ {
+ ALOGW("persist.vendor.bt.soc.scram_freqs is not set");
+ return false;
+ }
+ }
+ else
+ {
+ ALOGE("Error in fetching persist.vendor.bluetooth.soc.scram_freqs property");
+ return false;
+ }
+
+ pthread_mutex_lock(&audio_stream.lock);
+ for (i = 0; i < STREAM_START_MAX_RETRY_COUNT; i++)
+ {
+ status = a2dp_read_codec_config(&audio_stream, 0);
+ if (status == A2DP_CTRL_ACK_SUCCESS)
+ {
+ if(!a2dp_codec_parser(&audio_stream.codec_cfg[0],
+ &codec_type, &sample_freq)) {
+ status = A2DP_CTRL_ACK_UNKNOWN;
+ }
+ break;
+ }
+ INFO("%s: a2dp stream not configured,wait 100mse & retry", __func__);
+ usleep(100000);
+ }
+ if (codec_type == ENC_CODEC_TYPE_APTX_DUAL_MONO) {
+ INFO("%s:TWSP codec, return false",__func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return false;
+ }
+ if(status == A2DP_CTRL_ACK_SUCCESS) {
+
+ if (codec_type == CODEC_TYPE_CELT) {
+ INFO("%s: BA going on,return false", __func__);
+ pthread_mutex_unlock(&audio_stream.lock);
+ return false;
+ }
+
+ ALOGW("audio_is_scrambling_enabled sample_freq %ld",sample_freq);
+ switch (sample_freq) {
+ case 44100:
+ if(!strstr(value, "441")) status = A2DP_CTRL_ACK_UNKNOWN;
+ break;
+ case 48000:
+ if(!strstr(value, "48")) status = A2DP_CTRL_ACK_UNKNOWN;
+ break;
+ case 88200:
+ if(!strstr(value, "882")) status = A2DP_CTRL_ACK_UNKNOWN;
+ break;
+ case 96000:
+ if(!strstr(value, "96")) status = A2DP_CTRL_ACK_UNKNOWN;
+ break;
+ case 176400:
+ if(!strstr(value, "1764")) status = A2DP_CTRL_ACK_UNKNOWN;
+ break;
+ case 192000:
+ if(!strstr(value, "192")) status = A2DP_CTRL_ACK_UNKNOWN;
+ break;
+ default:
+ ALOGE("Invalid sampling freqency, return A2DP_CTRL_ACK_UNKNOWN");
+ status = A2DP_CTRL_ACK_UNKNOWN;
+ break;
+ }
+ }
+ ALOGW("audio_is_scrambling_enabled = %s",dump_a2dp_ctrl_ack(status));
+ pthread_mutex_unlock(&audio_stream.lock);
+ return status == A2DP_CTRL_ACK_SUCCESS;
+}
+
+void ldac_codec_parser(uint8_t *codec_cfg)
+{
+ char byte,len;
+ uint8_t *p_cfg = codec_cfg;
+ memset(&ldac_codec,0,sizeof(audio_ldac_encoder_config_t));
+ p_cfg++; //skip dev_idx
+ len = *p_cfg++;//LOSC
+ p_cfg++; // Skip media type
+ len--;
+ p_cfg++; //codec_type
+ len--;
+ p_cfg+=4;//skip vendor id
+ len -= 4;
+ p_cfg += 2; //skip codec id
+ len -= 2;
+ byte = *p_cfg++;
+ len--;
+ switch (byte & A2D_LDAC_SAMP_FREQ_MASK)
+ {
+ case A2D_LDAC_SAMP_FREQ_44:
+ ldac_codec.sampling_rate = 44100;
+ break;
+ case A2D_LDAC_SAMP_FREQ_48:
+ ldac_codec.sampling_rate = 48000;
+ break;
+ case A2D_LDAC_SAMP_FREQ_88:
+ ldac_codec.sampling_rate = 88200;
+ break;
+ case A2D_LDAC_SAMP_FREQ_96:
+ ldac_codec.sampling_rate = 96000;
+ break;
+ case A2D_LDAC_SAMP_FREQ_176:
+ ldac_codec.sampling_rate = 176400;
+ break;
+ case A2D_LDAC_SAMP_FREQ_192:
+ ldac_codec.sampling_rate = 192000;
+ break;
+ default:
+ ALOGE("Unknown sampling rate");
+ }
+ ALOGW("%s: LDAC: sample rate: %lu", __func__, ldac_codec.sampling_rate);
+ byte = *p_cfg++;
+ len--;
+ ldac_codec.channel_mode = (byte & A2D_LDAC_CHAN_MASK);
+ if (len == 0)
+ {
+ ALOGW("Codec config copied");
+ }
+ ldac_codec.mtu = DEFAULT_MTU_SIZE;
+ p_cfg += 2;
+
+ ldac_codec.bitrate = *p_cfg++;
+ ldac_codec.bitrate |= (*p_cfg++ << 8);
+ ldac_codec.bitrate |= (*p_cfg++ << 16);
+ ldac_codec.bitrate |= (*p_cfg++ << 24);
+
+ ldac_codec.is_abr_enabled = (ldac_codec.bitrate == 0);
+
+ ALOGW("Create Lookup for %d with ABR %d", ldac_codec.sampling_rate, ldac_codec.is_abr_enabled);
+ if (ldac_codec.sampling_rate == 44100 ||
+ ldac_codec.sampling_rate == 88200) {
+ int num_of_level_entries =
+ sizeof(bit_rate_level_44_1k_88_2k_database)/sizeof(bit_rate_level_44_1k_88_2k_table_t);
+ ldac_codec.level_to_bitrate_map.num_levels = num_of_level_entries;
+ if (ldac_codec.is_abr_enabled) {
+ ldac_codec.bitrate = bit_rate_level_44_1k_88_2k_database[0].bit_rate_value;
+ ALOGW("Send start highest bit-rate value %d", ldac_codec.bitrate);
+ }
+ for (int i = 0; i < num_of_level_entries; i++) {
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].link_quality_level =
+ bit_rate_level_44_1k_88_2k_database[i].level_value;
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].bitrate =
+ bit_rate_level_44_1k_88_2k_database[i].bit_rate_value;
+ ALOGW("Level: %d, bit-rate: %d",
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].link_quality_level,
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].bitrate);
+ }
+ } else if (ldac_codec.sampling_rate == 48000 ||
+ ldac_codec.sampling_rate == 96000) {
+ int num_of_level_entries =
+ sizeof(bit_rate_level_48k_96k_database)/sizeof(bit_rate_level_48k_96k_table_t);
+ ldac_codec.level_to_bitrate_map.num_levels = num_of_level_entries;
+ if (ldac_codec.is_abr_enabled) {
+ ldac_codec.bitrate = bit_rate_level_48k_96k_database[0].bit_rate_value;
+ ALOGW("Send start highest bit-rate value %d", ldac_codec.bitrate);
+ }
+ for (int i = 0; i < num_of_level_entries; i++) {
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].link_quality_level =
+ bit_rate_level_48k_96k_database[i].level_value;
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].bitrate =
+ bit_rate_level_48k_96k_database[i].bit_rate_value;
+ ALOGW("Level: %d, bit-rate: %d",
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].link_quality_level,
+ ldac_codec.level_to_bitrate_map.bit_rate_level_map[i].bitrate);
+ }
+ } else {
+ ALOGW("Unsupported Invalid frequency");
+ }
+ ALOGW("%s: LDAC: bitrate: %lu", __func__, ldac_codec.bitrate);
+ ALOGW("LDAC: Done copying full codec config");
+}
diff --git a/bthost_ipc/bthost_ipc.h b/bthost_ipc/bthost_ipc.h
new file mode 100644
index 0000000..a962c0d
--- /dev/null
+++ b/bthost_ipc/bthost_ipc.h
@@ -0,0 +1,378 @@
+/******************************************************************************
+ * Copyright (C) 2016-2017, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *****************************************************************************/
+/*****************************************************************************
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename: audio_a2dp_hw.h
+ *
+ * Description:
+ *
+ *****************************************************************************/
+#ifndef BT_HOST_IPC_H
+#define BT_HOST_IPC_H
+#include <system/audio.h>
+/*****************************************************************************
+** Constants & Macros
+******************************************************************************/
+#define BT_AUDIO_HARDWARE_INTERFACE "libbthost"
+
+#define MAX_LEVELS 5
+
+typedef enum {
+ A2DP_CTRL_CMD_NONE,
+ A2DP_CTRL_CMD_CHECK_READY,
+ A2DP_CTRL_CMD_CHECK_STREAM_STARTED,
+ A2DP_CTRL_CMD_START,
+ A2DP_CTRL_CMD_STOP,
+ A2DP_CTRL_CMD_SUSPEND,
+ A2DP_CTRL_GET_AUDIO_CONFIG,
+ A2DP_CTRL_CMD_OFFLOAD_START,
+ A2DP_CTRL_CMD_OFFLOAD_SUPPORTED,
+ A2DP_CTRL_CMD_OFFLOAD_NOT_SUPPORTED,
+} tA2DP_CTRL_CMD;
+
+typedef enum {
+ A2DP_CTRL_ACK_SUCCESS,
+ A2DP_CTRL_ACK_FAILURE,
+ A2DP_CTRL_ACK_INCALL_FAILURE, /* Failure when in Call*/
+ A2DP_CTRL_ACK_UNSUPPORTED,
+ A2DP_CTRL_ACK_PENDING,
+ A2DP_CTRL_ACK_DISCONNECT_IN_PROGRESS,
+ A2DP_CTRL_ACK_PREVIOUS_COMMAND_PENDING,
+ A2DP_CTRL_SKT_DISCONNECTED,
+ A2DP_CTRL_ACK_UNKNOWN,
+} tA2DP_CTRL_ACK;
+
+
+typedef enum {
+ AUDIO_A2DP_STATE_STARTING,
+ AUDIO_A2DP_STATE_STARTED,
+ AUDIO_A2DP_STATE_STOPPING,
+ AUDIO_A2DP_STATE_STOPPED,
+ AUDIO_A2DP_STATE_SUSPENDED, /* need explicit set param call to resume (suspend=false) */
+ AUDIO_A2DP_STATE_STANDBY /* allows write to autoresume */
+} a2dp_state_t;
+
+typedef enum {
+ A2DP_CTRL_GET_CODEC_CONFIG = 15,
+ A2DP_CTRL_GET_MULTICAST_STATUS,
+ A2DP_CTRL_GET_CONNECTION_STATUS,
+} tA2DP_CTRL_EXT_CMD;
+
+#define MAX_CODEC_CFG_SIZE 30
+struct a2dp_config {
+ uint32_t rate;
+ uint32_t channel_flags;
+ int format;
+};
+struct a2dp_stream_common {
+ pthread_mutex_t lock;
+ pthread_mutex_t ack_lock;
+ //int ctrl_fd;
+ //int audio_fd;
+ //size_t buffer_sz;
+ //struct a2dp_config cfg;
+ a2dp_state_t state;
+ tA2DP_CTRL_ACK ack_status;
+ uint8_t multicast;
+ uint8_t num_conn_dev;
+ uint8_t codec_cfg[MAX_CODEC_CFG_SIZE];
+ uint16_t sink_latency;
+};
+/*
+codec specific definitions
+*/
+#define AUDIO_CODEC_TYPE_CELT 603979776u // 0x24000000UL
+#define ENC_CODEC_TYPE_APTX_DUAL_MONO 570425344u // 0x22000000UL
+#define CODEC_TYPE_SBC 0x00
+#define CODEC_TYPE_AAC 0x02
+#define CODEC_TYPE_CELT 0xEF
+#define NON_A2DP_CODEC_TYPE 0xFF
+#define CODEC_OFFSET 3
+#define VENDOR_ID_OFFSET 4
+#define CODEC_ID_OFFSET (VENDOR_ID_OFFSET + 4)
+#define CODEC_TYPE_PCM 0x05
+
+#ifndef VENDOR_APTX
+#define VENDOR_APTX 0x4F
+#endif
+#ifndef VENDOR_APTX_HD
+#define VENDOR_APTX_HD 0xD7
+#endif
+#ifndef VENDOR_APTX_LL
+#define VENDOR_APTX_LL 0x0A
+#endif
+#ifndef APTX_CODEC_ID
+#define APTX_CODEC_ID 0x01
+#endif
+#ifndef APTX_HD_CODEC_ID
+#define APTX_HD_CODEC_ID 0x24
+#endif
+#ifndef APTX_TWS_CODEC_ID
+#define APTX_TWS_CODEC_ID 0x25
+#endif
+
+#ifndef VENDOR_LDAC
+#define VENDOR_LDAC 0x12D
+#endif
+#ifndef LDAC_CODEC_ID
+#define LDAC_CODEC_ID 0xAA
+#endif
+
+#define DEFAULT_MTU_SIZE 663
+
+#define A2D_SBC_FREQ_MASK 0xF0
+#define A2D_SBC_CHN_MASK 0x0F
+#define A2D_SBC_BLK_MASK 0xF0
+#define A2D_SBC_SUBBAND_MASK 0x0C
+#define A2D_SBC_ALLOC_MASK 0x03
+#define A2D_SBC_SAMP_FREQ_16 0x80 /* b7:16 kHz */
+#define A2D_SBC_SAMP_FREQ_32 0x40 /* b6:32 kHz */
+#define A2D_SBC_SAMP_FREQ_44 0x20 /* b5:44.1kHz */
+#define A2D_SBC_SAMP_FREQ_48 0x10 /* b4:48 kHz */
+#define A2D_SBC_CH_MD_MONO 0x08 /* b3: mono */
+#define A2D_SBC_CH_MD_DUAL 0x04 /* b2: dual */
+#define A2D_SBC_CH_MD_STEREO 0x02 /* b1: stereo */
+#define A2D_SBC_CH_MD_JOINT 0x01 /* b0: joint stereo */
+#define A2D_SBC_BLOCKS_4 0x80 /* 4 blocks */
+#define A2D_SBC_BLOCKS_8 0x40 /* 8 blocks */
+#define A2D_SBC_BLOCKS_12 0x20 /* 12blocks */
+#define A2D_SBC_BLOCKS_16 0x10 /* 16blocks */
+#define A2D_SBC_SUBBAND_4 0x08 /* b3: 4 */
+#define A2D_SBC_SUBBAND_8 0x04 /* b2: 8 */
+#define A2D_SBC_ALLOC_MD_S 0x02 /* b1: SNR */
+#define A2D_SBC_ALLOC_MD_L 0x01 /* b0: loundess */
+
+/* APTX bitmask helper */
+#define A2D_APTX_SAMP_FREQ_MASK 0xF0
+#define A2D_APTX_SAMP_FREQ_48 0x10
+#define A2D_APTX_SAMP_FREQ_44 0x20
+#define A2D_APTX_CHAN_MASK 0x0F
+#define A2D_APTX_CHAN_STEREO 0x02
+#define A2D_APTX_CHAN_MONO 0x01
+#define A2D_APTX_TWS_CHAN_MODE 0x08
+
+
+/* LDAC bitmask helper */
+#define A2D_LDAC_SAMP_FREQ_MASK 0x3F
+#define A2D_LDAC_SAMP_FREQ_44 0x20
+#define A2D_LDAC_SAMP_FREQ_48 0x10
+#define A2D_LDAC_SAMP_FREQ_88 0x08
+#define A2D_LDAC_SAMP_FREQ_96 0x04
+#define A2D_LDAC_SAMP_FREQ_176 0x02
+#define A2D_LDAC_SAMP_FREQ_192 0x01
+
+#define A2D_LDAC_CHAN_MASK 0x07
+#define A2D_LDAC_CHAN_STEREO 0x01
+#define A2D_LDAC_CHAN_MONO 0x04
+#define A2D_LDAC_CHAN_DUAL 0x02
+
+
+#define A2D_AAC_IE_OBJ_TYPE_MSK 0xF0 /* b7-b4 Object Type */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_2_AAC_LC 0x80 /* b7:MPEG-2 AAC LC */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LC 0x40 /* b7:MPEG-4 AAC LC */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_LTP 0x20 /* b7:MPEG-4 AAC LTP */
+#define A2D_AAC_IE_OBJ_TYPE_MPEG_4_AAC_SCA 0x10 /* b7:MPEG-4 AAC SCALABLE */
+
+#define A2D_AAC_IE_CHANNELS_MSK 0x0C
+#define A2D_AAC_IE_CHANNELS_1 0x08 /* Channel 1 */
+#define A2D_AAC_IE_CHANNELS_2 0x04 /* Channel 2 */
+
+#define A2D_AAC_IE_VBR_MSK 0x80
+#define A2D_AAC_IE_VBR 0x80 /* supported */
+
+#define A2DP_DEFAULT_SINK_LATENCY 0
+
+
+// CELT Codec config in order.
+// 7-4 bits of first byte of codec_info element
+#define A2D_CELT_SAMP_FREQ_MASK 0xF0
+#define A2D_CELT_SAMP_FREQ_48 0x10
+#define A2D_CELT_SAMP_FREQ_44 0x20
+#define A2D_CELT_SAMP_FREQ_32 0x40
+// 0-3 bits of first byte of codec_info element
+#define A2D_CELT_CHANNEL_MASK 0x0F
+#define A2D_CELT_CH_MONO 0x01
+#define A2D_CELT_CH_STEREO 0x02
+// 7-4 bits of second byte: frame size
+#define A2D_CELT_FRAME_SIZE_MASK 0xF0
+#define A2D_CELT_FRAME_SIZE_64 0x10
+#define A2D_CELT_FRAME_SIZE_128 0x20
+#define A2D_CELT_FRAME_SIZE_256 0x40
+#define A2D_CELT_FRAME_SIZE_512 0x80
+//0-3 bits of second byte: actual value of complexity
+#define A2D_CELT_COMPLEXITY_MASK 0x0F
+// 7-4 bits of third byte: prediction mode
+#define A2D_CELT_PREDICTION_MODE_MASK 0xF0
+// 0th bit of third byte: vbr flag
+#define A2D_CELT_VBR_MASK 0x01
+
+// next 2 bytes is actual frame size
+// next 1 bytes is actual complexity
+typedef struct {
+ uint32_t subband; /* 4, 8 */
+ uint32_t blk_len; /* 4, 8, 12, 16 */
+ uint16_t sampling_rate; /*44.1khz,48khz*/
+ uint8_t channels; /*0(Mono),1(Dual_mono),2(Stereo),3(JS)*/
+ uint8_t alloc; /*0(Loudness),1(SNR)*/
+ uint8_t min_bitpool; /* 2 */
+ uint8_t max_bitpool; /*53(44.1khz),51 (48khz) */
+ uint32_t bitrate; /* 320kbps to 512kbps */
+} audio_sbc_encoder_config_t;
+
+
+/* Information about BT APTX encoder configuration
+ * This data is used between audio HAL module and
+ * BT IPC library to configure DSP encoder
+ */
+typedef struct {
+ uint16_t sampling_rate;
+ uint8_t channels;
+ uint32_t bitrate;
+} audio_aptx_encoder_config_t;
+
+struct bit_rate_level_map_t {
+ uint32_t link_quality_level;
+ uint32_t bitrate;
+};
+
+struct quality_level_to_bitrate_info {
+ uint32_t num_levels;
+ struct bit_rate_level_map_t bit_rate_level_map[MAX_LEVELS];
+};
+/* Information about BT APTX encoder configuration
+ * This data is used between audio HAL module and
+ * BT IPC library to configure DSP encoder
+ */
+typedef struct {
+ uint16_t sampling_rate;
+ uint8_t channels;
+ uint32_t bitrate;
+ uint8_t sync_mode;
+} audio_aptx_tws_encoder_config_t;
+
+/* Information about BT LDAC encoder configuration
+ * This data is used between audio HAL module and
+ * BT IPC library to configure DSP encoder
+ */
+typedef struct {
+ uint32_t sampling_rate;
+ uint32_t bitrate;
+ uint16_t channel_mode;
+ uint16_t mtu;
+ bool is_abr_enabled;
+ struct quality_level_to_bitrate_info level_to_bitrate_map;
+} audio_ldac_encoder_config_t;
+
+/* Information about BT AAC encoder configuration
+ * This data is used between audio HAL module and
+ * BT IPC library to configure DSP encoder
+ */
+typedef struct {
+ uint32_t enc_mode; /* LC, SBR, PS */
+ uint16_t format_flag; /* RAW, ADTS */
+ uint16_t channels; /* 1-Mono, 2-Stereo */
+ uint32_t sampling_rate;
+ uint32_t bitrate;
+} audio_aac_encoder_config_t;
+
+typedef struct {
+ uint32_t sampling_rate; /* 32000 - 48000, 48000 */
+ uint16_t channels; /* 1-Mono, 2-Stereo, 2*/
+ uint16_t frame_size; /* 64-128-256-512, 512 */
+ uint16_t complexity; /* 0-10, 1 */
+ uint16_t prediction_mode; /* 0-1-2, 0 */
+ uint16_t vbr_flag; /* 0-1, 0*/
+ uint32_t bitrate; /*32000 - 1536000, 139500*/
+} audio_celt_encoder_config_t;
+
+//HIDL callbacks to invoke callback to BT stack
+typedef void (*bt_ipc_start_stream_req_cb)(void);
+typedef void (*bt_ipc_suspend_stream_req_cb)(void);
+typedef void (*bt_ipc_stop_stream_req_cb)(void);
+typedef void (*bt_ipc_a2dp_check_ready_cb)(void);
+typedef void (*bt_ipc_get_codec_config_cb)(void);
+typedef void (*bt_ipc_get_multicast_status_cb)(void);
+typedef void (*bt_ipc_get_connected_devices_cb)(void);
+typedef void (*bt_ipc_get_connection_status_cb)(void);
+typedef void (*bt_ipc_get_sink_latency_cb)(void);
+
+typedef struct {
+ bt_ipc_start_stream_req_cb start_req_cb;
+ bt_ipc_suspend_stream_req_cb suspend_req_cb;
+ bt_ipc_stop_stream_req_cb stop_req_cb;
+ bt_ipc_a2dp_check_ready_cb a2dp_check_ready_cb;
+ bt_ipc_get_multicast_status_cb get_mcast_status_cb;
+ bt_ipc_get_connected_devices_cb get_connected_device_cb;
+ bt_ipc_get_connection_status_cb get_connection_status_cb;
+ bt_ipc_get_codec_config_cb get_codec_cfg_cb;
+ bt_ipc_get_sink_latency_cb get_sink_latency_cb;
+}bt_lib_callback_t;
+
+void bt_stack_init(bt_lib_callback_t *lib_cb);
+void bt_stack_deinit(tA2DP_CTRL_ACK status);
+void bt_stack_on_stream_started(tA2DP_CTRL_ACK status);
+void bt_stack_on_stream_suspended(tA2DP_CTRL_ACK status);
+void bt_stack_on_stream_stopped(tA2DP_CTRL_ACK status);
+void bt_stack_on_get_codec_cfg(tA2DP_CTRL_ACK status, const char *config, size_t len);
+void bt_stack_on_get_mcast_status(uint8_t status);
+void bt_stack_on_get_num_connected_devices(uint8_t num);
+void bt_stack_on_get_connection_status(tA2DP_CTRL_ACK status);
+void bt_stack_on_check_a2dp_ready(tA2DP_CTRL_ACK status);
+void bt_stack_on_get_sink_latency(uint16_t latency);
+
+int audio_stream_open(void);
+int audio_stream_close(void);
+int audio_start_stream(void);
+int audio_stop_stream(void);
+int audio_suspend_stream(void);
+void* audio_get_codec_config(uint8_t *mcast, uint8_t *num_dev, audio_format_t *codec_type);
+void audio_handoff_triggered(void);
+void clear_a2dpsuspend_flag(void);
+void* audio_get_next_codec_config(uint8_t idx, audio_format_t *codec_type);
+int audio_check_a2dp_ready(void);
+uint16_t audio_get_a2dp_sink_latency();
+bool audio_is_scrambling_enabled(void);
+int wait_for_stack_response(uint8_t duration);
+#endif
+
diff --git a/bthost_ipc/ldac_level_bit_rate_lookup.h b/bthost_ipc/ldac_level_bit_rate_lookup.h
new file mode 100644
index 0000000..f8ec160
--- /dev/null
+++ b/bthost_ipc/ldac_level_bit_rate_lookup.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+typedef struct {
+ int level_value;
+ int bit_rate_value;
+} bit_rate_level_48k_96k_table_t;
+
+static const bit_rate_level_48k_96k_table_t bit_rate_level_48k_96k_database[] = {
+ /* Level to Bit rate for 48k, 96k sample freq, in kbps */
+ {5, 990000},
+ {4, 660000},
+ {3, 492000},
+ {2, 396000},
+ {1, 330000},
+};
+
+
+typedef struct {
+ int level_value;
+ int bit_rate_value;
+} bit_rate_level_44_1k_88_2k_table_t;
+
+static const bit_rate_level_44_1k_88_2k_table_t bit_rate_level_44_1k_88_2k_database[] = {
+ /* Level to Bit rate for 44.1k, 88.2k sample freq, in kbps */
+ {5, 909000},
+ {4, 606000},
+ {3, 452000},
+ {2, 363000},
+ {1, 303000},
+};
+
+
diff --git a/libbt-vendor/Android.mk b/libbt-vendor/Android.mk
index d30f78c..f15bb04 100644
--- a/libbt-vendor/Android.mk
+++ b/libbt-vendor/Android.mk
@@ -45,7 +45,7 @@
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include \
external/bluetooth/bluedroid/hci/include \
- vendor/qcom/opensource/system/bt/hci/include \
+ vendor/qcom/opensource/commonsys/system/bt/hci/include \
$(TARGET_OUT_HEADERS)/bt/hci_qcomm_init \
$(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
diff --git a/tools/Android.mk b/tools/Android.mk
new file mode 100644
index 0000000..f5bcfc6
--- /dev/null
+++ b/tools/Android.mk
@@ -0,0 +1,8 @@
+LOCAL_PATH:= $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
+LOCAL_CFLAGS += -Wno-unused-variable
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wno-sometimes-uninitialized
+LOCAL_CFLAGS += -Wno-macro-redefined
+LOCAL_CFLAGS += -Wno-format
diff --git a/tools/btconfig/Android.mk b/tools/btconfig/Android.mk
new file mode 100644
index 0000000..2865a42
--- /dev/null
+++ b/tools/btconfig/Android.mk
@@ -0,0 +1,26 @@
+#ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS += -Wno-unused-variable
+LOCAL_CFLAGS += -Wno-sometimes-uninitialized
+LOCAL_CFLAGS += -Wno-format
+
+LOCAL_C_INCLUDES := system/bt/hci/include
+
+LOCAL_SRC_FILES:= \
+ btconfig.c
+
+LOCAL_MULTILIB := 32
+LOCAL_MODULE_TAGS := debug optional
+LOCAL_MODULE :=btconfig
+
+LOCAL_SHARED_LIBRARIES += libcutils \
+ libutils \
+ libdl
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_EXECUTABLES)
+include $(BUILD_EXECUTABLE)
+#endif
diff --git a/tools/btconfig/Makefile b/tools/btconfig/Makefile
new file mode 100644
index 0000000..c3a8c3e
--- /dev/null
+++ b/tools/btconfig/Makefile
@@ -0,0 +1,11 @@
+CC := gcc
+
+all: btconfig
+
+btconfig: btconfig.c
+ $(CC) -Wall -g btconfig.c -o btconfig
+ # cp btconfig /usr/bin
+clean:
+ rm btconfig
+ rm /usr/bin/btconfig
+
diff --git a/tools/btconfig/btconfig.c b/tools/btconfig/btconfig.c
new file mode 100644
index 0000000..2963040
--- /dev/null
+++ b/tools/btconfig/btconfig.c
@@ -0,0 +1,7537 @@
+/*
+ * Copyright (c) 2013,2016 The Linux Foundation. All rights reserved.
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <cutils/sockets.h>
+#include <linux/un.h>
+#include <sys/time.h>
+#include <linux/types.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdbool.h>
+
+#ifdef ANDROID
+#include <cutils/properties.h>
+#include <termios.h>
+#include "bt_vendor_lib.h"
+#else
+#include <sys/termios.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#endif
+
+#include "btconfig.h"
+#include "masterblaster.h"
+
+
+#define PRONTO_SOC TRUE
+#define QCA_DEBUG TRUE
+#define Inquiry_Complete_Event 0x01
+
+#define WDS_SOCK "wdssock"
+
+static char prop[100] = {0};
+static char soc_type[100] = {0};
+static bool nopatch = true;
+static int g_rome_ver = 0;
+bool is_qca_transport_uart = false;
+
+#ifdef ANDROID
+static bt_vendor_interface_t * p_btf=NULL;
+#endif
+void baswap(bdaddr_t *dst, const bdaddr_t *src)
+{
+ register unsigned char *d = (unsigned char *) dst;
+ register const unsigned char *s = (const unsigned char *) src;
+ register int i;
+
+ for (i = 0; i < 6; i++)
+ d[i] = s[5-i];
+}
+
+int bachk(const char *str)
+{
+ if (!str)
+ return -1;
+
+ if (strlen(str) != 17)
+ return -1;
+
+ while (*str) {
+ if (!isxdigit(*str++))
+ return -1;
+
+ if (!isxdigit(*str++))
+ return -1;
+
+ if (*str == 0)
+ break;
+
+ if (*str++ != ':')
+ return -1;
+ }
+
+ return 0;
+}
+
+int ba2str(const bdaddr_t *ba, char *str)
+{
+ return snprintf(str, 18,"%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
+}
+
+int str2ba(const char *str, bdaddr_t *ba)
+{
+ bdaddr_t b;
+ int i;
+
+ if (bachk(str) < 0) {
+ memset(ba, 0, sizeof(*ba));
+ return -1;
+ }
+
+ for (i = 0; i < 6; i++, str += 3)
+ b.b[i] = strtol(str, NULL, 16);
+
+ baswap(ba, &b);
+
+ return 0;
+}
+
+/* Redefine a small buffer for our simple text config files */
+#undef BUFSIZ
+#define BUFSIZ 128
+
+ssize_t
+getline(char ** __restrict buf, size_t * __restrict buflen,
+ FILE * __restrict fp)
+{
+ size_t bytes, newlen;
+ char *newbuf, *p;
+
+ if (buf == NULL || buflen == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (*buf == NULL)
+ *buflen = 0;
+
+ bytes = 0;
+ do {
+ if (feof(fp))
+ break;
+ if (*buf == NULL || bytes != 0) {
+ newlen = *buflen + BUFSIZ;
+ newbuf = realloc(*buf, newlen);
+ if (newbuf == NULL)
+ return -1;
+ *buf = newbuf;
+ *buflen = newlen;
+ }
+ p = *buf + bytes;
+ memset(p, 0, BUFSIZ);
+ if (fgets(p, BUFSIZ, fp) == NULL)
+ break;
+ bytes += strlen(p);
+ } while (bytes == 0 || *(*buf + (bytes - 1)) != '\n');
+ if (bytes == 0)
+ return -1;
+ return bytes;
+}
+
+#ifdef QCA_DEBUG
+static int qca_debug_dump(uint8_t *cmd, int size)
+{
+ int i;
+
+ printf("dump : ");
+ for (i = 0; i < size; i++)
+ printf(" %02x", cmd[i]);
+ printf("\n");
+
+ return 0;
+}
+#endif
+
+/* Global Variables */
+//static int Patch_Count = 0;
+static BOOL CtrlCBreak = FALSE;
+bdaddr_t BdAddr;
+/* Function Declarations */
+static void LoadPSHeader(UCHAR *HCI_PS_Command,UCHAR opcode,int length,int index);
+static BOOL SU_LERxTest(int uart_fd, UCHAR channel);
+static BOOL SU_LETxTest(int uart_fd, UCHAR channel, UCHAR length, UCHAR payload);
+static void usage(void);
+static int writeHciCommand(int uart_fd, uint16_t ogf, uint16_t ocf, uint8_t plen, UCHAR *buf);
+static int MemBlkRead(int uart_fd, UINT32 Address,UCHAR *pBuffer, UINT32 Length);
+static int Dut(int uart_fd);
+static int ReadAudioStats(int uart_fd);
+static int ReadGlobalDMAStats(int uart_fd);
+static int ResetGlobalDMAStats(int uart_fd);
+static int ReadTpcTable(int uart_fd);
+static int ReadHostInterest(int uart_fd,tBtHostInterest *pHostInt);
+static int ReadMemoryBlock(int uart_fd, int StartAddress,UCHAR *pBufToWrite, int Length );
+static int WriteMemoryBlock(int uart_fd, int StartAddress,UCHAR *pBufToWrite, int Length );
+static int write_otpRaw(int uart_fd, int address, int length, UCHAR *data);
+static int read_otpRaw(int uart_fd, int address, int length, UCHAR *data);
+static void dumpHex(UCHAR *buf, int length, int col);
+static void sig_term(int sig);
+static UCHAR LEMode = 0;
+
+int read_hci_event(int fd, unsigned char* buf, int size);
+int set_speed(int fd, struct termios *ti, int speed);
+
+static struct option main_options[] = {
+ { "help", 0, 0, 'h' },
+ { "soc", 1, 0, 's' },
+ { "initialize", 0, 0, 'i' },
+ { 0, 0, 0, 0 }
+};
+
+int connect_to_wds_server()
+{
+ struct sockaddr_un serv_addr;
+ int sock, ret = -1, i, addr_len;
+
+ sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if (sock < 0) {
+ printf("%s, client socket creation failed: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+
+ memset(&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sun_family = AF_LOCAL;
+ strlcpy(&serv_addr.sun_path[1], WDS_SOCK, strlen(WDS_SOCK) + 1);
+ addr_len = strlen(WDS_SOCK) + 1;
+ addr_len += sizeof(serv_addr.sun_family);
+
+ ret = connect(sock, (struct sockaddr*)&serv_addr, addr_len);
+ if (ret < 0) {
+ printf("%s, failed to connect to WDS server: %s\n", __func__, strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ printf("%s, Connected to WDS server, socket fd: %d\n", __func__, sock);
+ return sock;
+}
+
+unsigned int uGetInputDataFormat(char **str, struct ST_PS_DATA_FORMAT *pstFormat)
+{
+ char *pCharLine = *str;
+ if(pCharLine[0] != '[') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ return TRUE;
+ }
+ switch(pCharLine[1]) {
+ case 'H':
+ case 'h':
+ if(pCharLine[2]==':') {
+ if((pCharLine[3]== 'a') || (pCharLine[3]== 'A')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 5;
+ *str += 5;
+ return TRUE;
+ }
+ else {
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n"); //[H:A
+ return FALSE;
+ }
+ }
+ if((pCharLine[3]== 'S') || (pCharLine[3]== 's')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = FALSE;
+ //pCharLine += 5;
+ *str += 5;
+ //printf("\nDEBUG H-1:%s\n",pCharLine);
+ return TRUE;
+ }
+ else {
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n"); //[H:A
+ return FALSE;
+ }
+ }
+ else if(pCharLine[3] == ']') { //[H:]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 4;
+ *str += 4;
+ return TRUE;
+ }
+ else { //[H:
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");
+ return FALSE;
+ }
+ }
+ else if(pCharLine[2]==']') { //[H]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 3;
+ *str += 5;
+ return TRUE;
+ }
+ else { //[H
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");
+ return FALSE;
+ }
+ break;
+
+ case 'A':
+ case 'a':
+ if(pCharLine[2]==':') {
+ if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 5;
+ *str += 5;
+ return TRUE;
+ }
+ else {
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n"); //[A:H
+ return FALSE;
+ }
+ }
+ else if(pCharLine[3]== ']') { //[A:]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 4;
+ *str += 5;
+ return TRUE;
+ }
+ else { //[A:
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");
+ return FALSE;
+ }
+ }
+ else if(pCharLine[2]==']') { //[H]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 3;
+ *str += 5;
+ return TRUE;
+ }
+ else { //[H
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");
+ return FALSE;
+
+ }
+ break;
+
+ case 'S':
+ case 's':
+ if(pCharLine[2]==':') {
+ if((pCharLine[3]== 'h') || (pCharLine[3]== 'H')) {
+ if(pCharLine[4] == ']') {
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 5;
+ *str += 5;
+ return TRUE;
+ }
+ else {
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");//[A:H
+ return FALSE;
+ }
+ }
+ else if(pCharLine[3]== ']') { //[A:]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 4;
+ *str += 5;
+ return TRUE;
+ }
+ else { //[A:
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");
+ return FALSE;
+ }
+ }
+ else if(pCharLine[2]==']') { //[H]
+ pstFormat->eDataType = eHex;
+ pstFormat->bIsArray = TRUE;
+ //pCharLine += 3;
+ *str += 5;
+ return TRUE;
+ }
+ else { //[H
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");
+ return FALSE;
+ }
+ break;
+
+ default:
+ printf("\nuGetInputDataFormat - Invalid Data Format \r\n");
+ return FALSE;
+ }
+}
+
+unsigned int uReadDataInSection(char *pCharLine, struct ST_PS_DATA_FORMAT stPS_DataFormat)
+{
+ if(stPS_DataFormat.eDataType == eHex) {
+ if(stPS_DataFormat.bIsArray == TRUE) {
+ //Not implemented
+ printf("\nNO IMP\n");
+ return (0x0FFF);
+ }
+ else {
+ //printf("\nDEBUG H-2 %d\n",strtol(pCharLine, NULL, 16));
+ return (strtol(pCharLine, NULL, 16));
+ }
+ }
+ else {
+ //Not implemented
+ printf("\nNO IMP-1\n");
+ return (0x0FFF);
+ }
+}
+
+static void LoadPSHeader(UCHAR *HCI_PS_Command,UCHAR opcode,int length,int index) {
+
+ HCI_PS_Command[0]= opcode;
+ HCI_PS_Command[1]= (index & 0xFF);
+ HCI_PS_Command[2]= ((index>>8) & 0xFF);
+ HCI_PS_Command[3] = length;
+}
+
+/* HCI functions that require open device
+ * dd - Device descriptor returned by hci_open_dev. */
+
+int hci_send_cmd(int uart_fd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param)
+{
+ uint8_t type = 0x01; //HCI_COMMAND_PKT
+ uint8_t hci_command_buf[256] = {0};
+ uint8_t * p_buf = &hci_command_buf[0];
+ uint8_t head_len = 3;
+ hci_command_hdr *ch;
+
+ if( is_qca_transport_uart || (!strcasecmp(soc_type, "300x"))) { // cherokee/rome/ar3002/qca3003 uart
+ *p_buf++ = type;
+ head_len ++;
+ }
+
+ ch = (void*)p_buf;
+ ch->opcode = htobs(HCI_OPCODE_PACK(ogf, ocf));
+ ch->plen = plen;
+ p_buf += HCI_COMMAND_HEADER_SIZE;
+
+ if(plen) {
+ memcpy(p_buf, (uint8_t*) param, plen);
+ }
+
+#ifdef QCA_DEBUG
+ printf("SEND -> ");
+ qca_debug_dump(hci_command_buf, plen+head_len);
+#endif
+
+ if(write(uart_fd, hci_command_buf, plen + head_len) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Read an HCI event from the given file descriptor.
+ */
+int read_hci_event(int fd, unsigned char* buf, int size)
+{
+ int remain, r;
+ int count = 0;
+
+ if (size <= 0)
+ return -1;
+
+ /* The first byte identifies the packet type. For HCI event packets, it
+ * should be 0x04, so we read until we get to the 0x04. */
+ while (1) {
+ r = read(fd, buf, 1);
+ if (r <= 0)
+ return -1;
+ if (buf[0] == 0x04) {
+ break;
+ }
+ }
+ count++;
+
+ /* The next two bytes are the event code and parameter total length. */
+ while (count < 3) {
+ r = read(fd, buf + count, 3 - count);
+ if (r <= 0)
+ return -1;
+ count += r;
+ }
+
+ /* Now we read the parameters. */
+ if (buf[2] < (size - 3))
+ remain = buf[2];
+ else
+ remain = size - 3;
+
+ while ((count - 3) < remain) {
+ r = read(fd, buf + count, remain - (count - 3));
+ if (r <= 0)
+ return -1;
+ count += r;
+ }
+
+ return count;
+}
+
+int read_event_modified(int fd, unsigned char* buf, int to)
+{
+ int r,size;
+ int count = 0;
+
+ UNUSED(to);
+ if( is_qca_transport_uart ||(!strcasecmp(soc_type, "300x"))){
+ /* The first byte identifies the packet type. For HCI event packets, it
+ * should be 0x04, so we read until we get to the 0x04. */
+ r = read(fd, buf, 1);
+ if(r<=0 || buf[0] != 4) return -1;
+ //count++;
+ }
+
+ while (count < 2) {
+ r = read(fd, buf + count, 2 - count);
+ if (r <= 0)
+ return -1;
+ count += r;
+ }
+
+ if (buf[1] == 0){
+ printf("Zero len , invalid \n");
+ return -1;
+ }
+ size = buf[1] + 2;
+ /* Now we read the parameters. */
+ while (count < size ) {
+ //printf("size =%d, count=%d , size-count= %d \n", size, count, size-count);
+ r = read(fd, buf + count, size-count);
+ if (r <= 0)
+ {
+ printf("read error \n");
+ return -1;
+ }
+ count += r;
+ }
+
+ //printf("\n*************Data read begin ************* \n");
+ //for (i=0 ; i< size ; i++)
+ // printf("[%02x]", buf[i]);
+ //printf("\n*************Data read end **************\n");
+
+#if DEBUG
+ // debugging purpose only. to get more packets after [04][10][01][02]
+ count = 0;
+ int timer = 0;
+ unsigned char dbuf[MAX_EVENT_SIZE];
+ memset(dbuf, 0, MAX_EVENT_SIZE);
+ while (timer < 30) {
+ r = read(fd, dbuf, 1);
+ if (r <= 0)
+ return -1;
+
+ if (dbuf[0] == 0x04){
+ printf("\n************ Debug begin ************* \n");
+ for(count; count < 2; count+=r){
+ printf("count: %d\n", count);
+ r = read(fd, dbuf + count, 2 - count);
+ printf("[%02x]", dbuf[count]);
+ if (r <= 0)
+ return -1;
+ }
+ while(count < dbuf[1] + 2){
+ r = read(fd, dbuf + count, dbuf[1] - count);
+ count += r;
+ }
+ }
+ count = 0;
+ for(count; count < dbuf[1] + 2; count++)
+ printf("[%02x]", dbuf[count]);
+ printf("\n************Debug end ************* \n");
+ sleep(3);
+ timer += 3;
+ }
+
+#endif /* The next two bytes are the event code and parameter total length. */
+
+ return count;
+}
+
+int read_incoming_events(int fd, unsigned char* buf, int to){
+ int r,size;
+ int count = 0;
+
+ UNUSED(to);
+ do{
+ if( is_qca_transport_uart || (!strcasecmp(soc_type, "300x"))){
+ // for cherokee/rome/ar3002/qca3003-uart, the 1st byte are packet type, should always be 4
+ r = read(fd, buf, 1);
+ if (r<=0 || buf[0] != 4) return -1;
+ }
+ /* The next two bytes are the event code and parameter total length. */
+ while (count < 2) {
+ r = read(fd, buf + count, 2 - count);
+ if (r <= 0)
+ {
+ printf("read error \n");
+ return -1;
+ }
+ count += r;
+ }
+
+
+ if (buf[1] == 0)
+ {
+ printf("Zero len , invalid \n");
+ return -1;
+ }
+ size = buf[1];
+
+ /* Now we read the parameters. */
+ while (count < size ) {
+ r = read(fd, buf + count, size);
+ if (r <= 0)
+ {
+ printf("read error :size = %d\n",size);
+ return -1;
+ }
+ count += r;
+ }
+
+ switch (buf[0])
+ {
+ int j=0;
+ case 0x0f:
+ printf("Command Status Received\n");
+ for (j=0 ; j< buf[1] + 2 ; j++)
+ printf("[%x]", buf[j]);
+ printf("\n");
+ if(buf[2] == 0x02)
+ {
+ printf("\nUnknown connection identifier");
+ return 0;
+ }
+ memset(buf , 0, MAX_EVENT_SIZE);
+ count = 0; size =0;
+ break;
+
+ case 0x02:
+ printf("INQ RESULT EVENT RECEIVED \n");
+ for (j=0 ; j< buf[1] + 2 ; j++)
+ printf("[%x]", buf[j]);
+ printf("\n");
+ memset(buf , 0, MAX_EVENT_SIZE);
+ count = 0; size =0;
+ break;
+ case 0x01:
+ printf("INQ COMPLETE EVENT RECEIVED\n");
+ printf("\n");
+ memset(buf , 0, MAX_EVENT_SIZE);
+ count = 0; size =0;
+ return 0;
+ case 0x03:
+ if(buf[2] == 0x00)
+ printf("CONNECTION COMPLETE EVENT RECEIVED WITH HANDLE: 0x%02x%02x \n",buf[4],buf[3]);
+ else
+ printf("CONNECTION COMPLETE EVENT RECEIVED WITH ERROR CODE 0x%x \n",buf[2]);
+ for (j=0 ; j< buf[1] + 2 ; j++)
+ printf("[%x]", buf[j]);
+ printf("\n");
+ memset(buf , 0, MAX_EVENT_SIZE);
+ count = 0; size =0;
+ return 0;
+ case 0x05:
+ printf("DISCONNECTION COMPLETE EVENT RECEIVED WITH REASON CODE: 0x%x \n",buf[5]);
+ for (j=0 ; j< buf[1] + 2 ; j++)
+ printf("[%x]", buf[j]);
+ printf("\n");
+ memset(buf , 0, MAX_EVENT_SIZE);
+ count = 0; size =0;
+ return 0;
+ default:
+ printf("Other event received, Breaking\n");
+#ifdef QCA_DEBUG
+ printf("RECV <- ");
+ qca_debug_dump(buf, buf[1] + 2);
+#else
+ for (j=0 ; j< buf[1] + 2 ; j++)
+ printf("[%x]", buf[j]);
+ printf("\n");
+#endif
+ memset(buf , 0, MAX_EVENT_SIZE);
+ count = 0; size =0;
+ return 0;
+ }
+
+ /* buf[1] should be the event opcode
+ * buf[2] shoudl be the parameter Len of the event opcode
+ */
+ }while (1);
+
+ return count;
+}
+
+static int writeHciCommand(int uart_fd, uint16_t ogf, uint16_t ocf, uint8_t plen, UCHAR *buf){
+ int count;
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+
+ printf("HCI Command: ogf 0x%02x, ocf 0x%04x, plen %d\n", ogf, ocf, plen);
+
+ count = hci_send_cmd(uart_fd, ogf, ocf, plen, buf);
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!count)
+ count = read_incoming_events(uart_fd, resultBuf, 0);
+ printf("\n");
+#ifdef QCA_DEBUG
+ printf("RECV <- ");
+ qca_debug_dump(resultBuf, count);
+#endif
+ return count;
+}
+
+static int MemBlkRead(int uart_fd,UINT32 Address,UCHAR *pBuffer, UINT32 Length){
+ UINT32 Size, ByteLeft;
+ UCHAR *pData,*pTemp=pBuffer;
+ int TempVal;
+
+ TempVal = (Length % 4);
+ if (TempVal !=0) {
+ Length = Length + (4- (Length%4));
+ }
+ ByteLeft = Length;
+ while (ByteLeft > 0)
+ {
+ Size = (ByteLeft > MEM_BLK_DATA_MAX) ? MEM_BLK_DATA_MAX : ByteLeft;
+ pData = (UCHAR *) malloc(Size + 6);
+ if(!pData){
+ printf("bt MemBlkRead: allocation failed! \n");
+ return -1;
+ }
+ pData[0]= 0x00;//depot/esw/projects/azure/AR3001_3_0/src/hci/Hci_Vsc_Proc.c
+ pData[1]= (Address & 0xFF);
+ pData[2]= ((Address >> 8) & 0xFF);
+ pData[3]= ((Address >> 16) & 0xFF);
+ pData[4]= ((Address >> 24) & 0xFF);
+ pData[5]= Size;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_MEMOP,6,pData);
+ if(pData[5]!= 0){
+ printf("\nwrite memory command failed due to reason 0x%X\n",pData[5]);
+ free(pData);
+ return FALSE;
+ }
+ if ((read(uart_fd, pData,MAX_EVENT_SIZE)) < 0) {
+ perror("Read failed");
+ exit(EXIT_FAILURE);
+ }
+
+ if(pData[3]!=3) {
+ perror("Read failed");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(pTemp,(pData+4),Size);
+ pTemp+=Size;
+ ByteLeft -= Size;
+ Address += Size;
+ free(pData);
+ }
+ return TRUE;
+}
+
+static int Dut(int uart_fd){
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if (is_qca_transport_uart) {
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0; // Not required
+ // OGF_HOST_CTL
+ // OCF_WRITE_AUTHENTICATION_ENABLE
+ writeHciCommand(uart_fd, 0x03, 0x0020, 1, buf);
+ if(buf[6] != 0){
+ printf("\nWrite authentication enable command failed due to reason 0x%X\n",buf[6]);
+ return FALSE;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0; // Not required
+ // OGF_HOST_CTL
+ // OCF_WRITE_ENCRYPTION_MODE
+ writeHciCommand(uart_fd, 0x03, 0x0022, 1, buf);
+ if(buf[6] != 0){
+ printf("\nWrite encryption mode command failed due to reason 0x%X\n",buf[6]);
+ return FALSE;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0x02; // connection setup
+ buf[1] = 0x00; // return responses from all devices during the inquiry process
+ buf[2] = 0x02; // allow connections from a device with specific BD_ADDR
+ // OGF_HOST_CTL
+ // OCF_SET_EVENT_FILTER
+ writeHciCommand(uart_fd, 0x03, 0x0005, 3, buf);
+ if(buf[6] != 0){
+ printf("\nWrite set_event_filter command failed due to reason 0x%X\n",buf[6]);
+ return FALSE;
+ }
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 3; //All scan enabled
+ // OGF_HOST_CTL
+ // OCF_WRITE_SCAN_ENABLE
+ writeHciCommand(uart_fd, 0x03, 0x001A, 1, buf);
+ if(buf[6] != 0){
+ printf("\nWrite scan mode command failed due to reason 0x%X\n",buf[6]);
+ return FALSE;
+ }
+
+ //sleep(1);
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ //OGF_TEST_CMD
+ //OCF_ENABLE_DEVICE_UNDER_TEST_MODE
+ writeHciCommand(uart_fd, 0x06, 0x0003, 0, buf);
+ if(buf[6] != 0){
+ printf("\nDUT mode command failed due to reason 0x%X\n",buf[6]);
+ return FALSE;
+ }
+
+#ifndef PRONTO_SOC
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0; //SEQN Track enable =0
+ // HCI_VENDOR_CMD_OGF
+ // OCF_TEST_MODE_SEQN_TRACKING
+ writeHciCommand(uart_fd, 0x3F, 0x0018, 1, buf);
+ if(buf[6] != 0){
+ printf("\nTest Mode seqn Tracking failed due to reason 0x%X\n",buf[6]);
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
+void Audio_DumpStats(tAudioStat *AudioStats)
+{
+ printf("\n\n");
+ printf(" Audio Statistics\n");
+ printf(">RxCmplt: %d\n",AudioStats->RxCmplt);
+ printf(">TxCmplt: %d\n",AudioStats->TxCmplt);
+ printf(">RxSilenceInsert: %d\n",AudioStats->RxSilenceInsert);
+ printf(">RxAirPktDump: %d\n",AudioStats->RxAirPktDump);
+ printf(">MaxPLCGenInterval: %d\n",AudioStats->MaxPLCGenInterval);
+ printf(">RxAirPktStatusGood: %d\n",AudioStats->RxAirPktStatusGood);
+ printf(">RxAirPktStatusError: %d\n",AudioStats->RxAirPktStatusError);
+ printf(">RxAirPktStatusLost: %d\n",AudioStats->RxAirPktStatusLost);
+ printf(">RxAirPktStatusPartial: %d\n",AudioStats->RxAirPktStatusPartial);
+ printf(">SampleMin: %d\n",AudioStats->SampleMin);
+ printf(">SampleMax: %d\n",AudioStats->SampleMax);
+ printf(">SampleCounter: %d\n",AudioStats->SampleCounter);
+ printf("\n\n");
+
+ memset((UCHAR *)AudioStats, 0, sizeof(tAudioStat));
+ AudioStats->SampleMax =SHRT_MIN;
+ AudioStats->SampleMin =SHRT_MAX;
+}
+
+static int ReadAudioStats(int uart_fd){
+
+ tBtHostInterest HostInt;
+ tAudioStat Stats;
+
+ ReadHostInterest(uart_fd, &HostInt);
+ if(!HostInt.AudioStatAddr || (HostInt.Version < 0x0300)){
+ printf("\nAudio Stat not present\n");
+ return FALSE;
+ }
+ ReadMemoryBlock(uart_fd,HostInt.AudioStatAddr,(UCHAR *)&Stats,sizeof(tAudioStat));
+ Audio_DumpStats(&Stats);
+ return TRUE;
+}
+
+void BRM_DumpStats(tBRM_Stats *Stats)
+{
+ printf("\n Link Controller Voice DMA Statistics\n");
+ printf(" %22s: %u\n", "VoiceTxDmaIntrs", Stats->VoiceTxDmaIntrs);
+ printf(" %22s: %u\n", "VoiceTxPktAvail", Stats->VoiceTxPktAvail);
+ printf(" %22s: %u\n", "VoiceTxPktDumped", Stats->VoiceTxPktDumped);
+ printf(" %22s: %u\n", "VoiceTxErrors", Stats->VoiceTxErrorIntrs);
+ printf(" %22s: %u\n", "VoiceTxDmaErrors", Stats->VoiceTxDmaErrorIntrs);
+ printf(" %22s: %u\n", "VoiceTxSilenceInserts", Stats->VoiceTxDmaSilenceInserts);
+ printf("\n");
+ printf(" %22s: %u\n", "VoiceRxDmaIntrs", Stats->VoiceRxDmaIntrs);
+ printf(" %22s: %u\n", "VoiceRxGoodPkts", Stats->VoiceRxGoodPkts);
+ printf(" %22s: %u\n", "VoiceRxPktDumped", Stats->VoiceRxPktDumped);
+ printf(" %22s: %u\n", "VoiceRxErrors", Stats->VoiceRxErrorIntrs);
+ printf(" %22s: %u\n", "VoiceRxCRC", Stats->VoiceRxErrCrc);
+ printf(" %22s: %u\n", "VoiceRxUnderOverFlow", Stats->VoiceRxErrUnderOverFlow);
+ printf("\n");
+ printf(" %22s: %u\n", "SchedOnVoiceError", Stats->SchedOnVoiceError);
+ printf(" %22s: %u\n", "VoiceTxReapOnError", Stats->VoiceTxReapOnError);
+ printf(" %22s: %u\n", "VoiceRxReapOnError", Stats->VoiceRxReapOnError);
+ printf(" %22s: %u\n", "VoiceSchedulingError", Stats->VoiceSchedulingError);
+
+ printf("\n Link Controller ACL DMA Statistics\n");
+ printf(" %22s: %u\n", "DmaIntrs", Stats->DmaIntrs);
+ printf(" %22s: %u\n", "ErrWrongLlid", Stats->ErrWrongLlid);
+ printf(" %22s: %u\n", "ErrL2CapLen", Stats->ErrL2CapLen);
+ printf(" %22s: %u\n", "ErrUnderOverFlow", Stats->ErrUnderOverFlow);
+ printf(" %22s: %u\n", "RxBufferDumped", Stats->RxBufferDumped);
+ printf(" %22s: %u\n", "ErrWrongLmpPktType", Stats->ErrWrongLmpPktType);
+ printf(" %22s: %u\n", "ErrWrongL2CapPktType", Stats->ErrWrongL2CapPktType);
+ printf(" %22s: %u\n", "IgnoredPkts", Stats->IgnoredPkts);
+ printf("\n");
+ printf(" %22s: %u\n", "Data TxBuffers", Stats->DataTxBuffers);
+ printf(" %22s: %u\n", "Data RxBuffers", Stats->DataRxBuffers);
+ printf(" %22s: %u\n", "LMP TxBuffers", Stats->LmpTxBuffers);
+ printf(" %22s: %u\n", "LMP RxBuffers", Stats->LmpRxBuffers);
+ printf(" %22s: %u\n", "HEC Errors", Stats->HecFailPkts);
+ printf(" %22s: %u\n", "CRC Errors", Stats->CrcFailPkts);
+
+ // Buffer Management
+ printf("\n Buffer Management Statistics\n");
+ printf(" %22s: %u\n", "CtrlErrNoLmpBufs", Stats->CtrlErrNoLmpBufs);
+
+ printf("\n Sniff Statistics\n");
+ printf(" %22s: %u\n", "SniffSchedulingError", Stats->SniffSchedulingError);
+ printf(" %22s: %u\n", "SniffIntervalNoCorr", Stats->SniffIntervalNoCorr);
+
+ // Other stats
+ printf("\n Other Statistics\n");
+ printf(" %22s: %u\n", "ForceOverQosJob", Stats->ForceOverQosJob);
+ //printf(" %22s: %u\n", "Temp 1", Stats->Temp1);
+ //printf(" %22s: %u\n", "Temp 2", Stats->Temp2);
+
+ // Test Mode Stats
+ printf("\n Test Mode Statistics\n");
+ printf(" %22s: %u\n", "TestModeDroppedTxPkts", Stats->TestModeDroppedTxPkts);
+ printf(" %22s: %u\n", "TestModeDroppedLmps", Stats->TestModeDroppedLmps);
+
+ // Error Stats
+ printf("\n General Error Statistics\n");
+ printf(" %22s: %u\n", "TimePassedIntrs", Stats->TimePassedIntrs);
+ printf(" %22s: %u\n", "NoCommandIntrs", Stats->NoCommandIntrs);
+}
+
+static int ReadGlobalDMAStats(int uart_fd){
+ tBtHostInterest HostInt;
+ tBRM_Stats Stats;
+
+ ReadHostInterest(uart_fd, &HostInt);
+ if(!HostInt.GlobalDmaStats || (HostInt.Version < 0x0100)){
+ printf("\nGlobal DMA stats not present\n");
+ return FALSE;
+ }
+ ReadMemoryBlock(uart_fd,HostInt.GlobalDmaStats,(UCHAR *)&Stats,sizeof(tBRM_Stats));
+ BRM_DumpStats(&Stats);
+ return TRUE;
+}
+
+static int ResetGlobalDMAStats(int uart_fd){
+ tBtHostInterest HostInt;
+ tBRM_Stats Stats;
+
+ ReadHostInterest(uart_fd, &HostInt);
+ if(!HostInt.GlobalDmaStats || (HostInt.Version < 0x0100)){
+ printf("\nGlobal DMA stats not present\n");
+ return FALSE;
+ }
+ memset(&Stats,0,sizeof(Stats));
+ printf("\nHarry\n");
+ WriteMemoryBlock(uart_fd,HostInt.GlobalDmaStats,(UCHAR *)&Stats,sizeof(tBRM_Stats));
+ printf("\nDMA stattestics has been reset\n");
+ return TRUE;
+}
+
+static int ReadTpcTable(int uart_fd){
+ tBtHostInterest HostInt;
+ tPsSysCfgTransmitPowerControlTable TpcTable;
+ int i;
+
+ ReadHostInterest(uart_fd, &HostInt);
+ if(!HostInt.TpcTableAddr || (HostInt.Version < 0x0100)){
+ printf("\nTPC table not present\n");
+ return FALSE;
+ }
+ ReadMemoryBlock(uart_fd,HostInt.TpcTableAddr,(UCHAR *)&TpcTable,sizeof(TpcTable));
+ for(i=0;i< TpcTable.NumOfEntries; i++){
+ printf("Level [%d] represents %3d dBm\n",i,TpcTable.t[i].TxPowerLevel);
+ }
+ return TRUE;
+}
+
+static const char *reset_help =
+"Usage:\n"
+"\n reset\n";
+
+static void cmd_reset(int uart_fd, int argc, char **argv){
+ int Length = 0;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if(argv) UNUSED(argv);
+ if(argc > 1) {
+ printf("\n%s\n",reset_help);
+ return;
+ }
+
+ memset(&buf,0,sizeof(buf));
+ Length = 0;
+
+ // OGF_HOST_CTL 0x03
+ // OCF_RESET 0x0003
+ writeHciCommand(uart_fd, HCI_CMD_OGF_HOST_CTL, HCI_CMD_OCF_RESET, Length, buf);
+ if(buf[6] != 0){
+ printf("\nError: HCI RESET failed due to reason 0x%X\n",buf[6]);
+ return;
+ }else{
+ printf("\nHCI Reset Pass");
+ }
+ printf("\nReset Done\n");
+}
+static const char *rba_help =
+"Usage:\n"
+"\n rba\n";
+
+static void cmd_rba(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int iRet;
+
+ if(argv) UNUSED(argv);
+ if(argc > 1){
+ printf("\n%s\n",rba_help);
+ return;
+ }
+ memset(&buf,0,MAX_EVENT_SIZE);
+
+ iRet = writeHciCommand(uart_fd, HCI_CMD_OGF_INFO_PARAM, HCI_CMD_OCF_READ_BD_ADDR, 0, buf);
+ printf("iRet: %d\n", iRet);
+ if(iRet>=MAX_EVENT_SIZE){
+ printf("\nread buffer size overflowed %d\n", iRet);
+ return;
+ }
+ if(buf[6] != 0){
+ printf("\nread bdaddr command failed due to reason 0x%X\n",buf[6] );
+ return;
+ }
+ printf("\nBD ADDRESS: \n");
+ int i;
+ for(i=iRet-1;i > 7;i--){
+ printf("%02X:",buf[i]);
+ }
+ printf("%02X\n\n",buf[7]);
+}
+
+static const char *dtx_help =
+"Usage:\n"
+"\n dtx\n";
+
+static void cmd_dtx(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if(argv) UNUSED(argv);
+ if(argc > 1){
+ printf("\n%s\n",dtx_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_DISABLE_TX, 0, buf);
+ if(buf[6] != 0){
+ printf("\nDisable TX command failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ else {
+ printf("\nDisable TX command passed\n");
+ }
+}
+
+static const char *ssm_help =
+"Usage:\n"
+"\n ssm [0|1]\n"
+"\nExample:\n"
+"\tssm 0\t(Sleep disabled)\n"
+"\tssm 1\t(Sleep enabled)\n";
+
+static void cmd_ssm(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if(argc != 2){
+ printf("\n%s\n",ssm_help);
+ return;
+ }
+
+ if(atoi(argv[1]) > 1){
+ printf("\nInvalid sleep mode :%d\n",atoi(argv[1]));
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = atoi(argv[1]);;
+
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE, 1, buf);
+ if(buf[6] != 0){
+ printf("\nSet sleep mode command failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ else {
+ printf("\nSet sleep mode command passed\n");
+ }
+}
+
+static const char *wba_help =
+"Usage:\n"
+"\n wba <bdaddr>\n"
+"\nExample:\n"
+"\n wba 00:03:ff:56:23:89\n";
+
+static void cmd_wba(int uart_fd, int argc, char **argv){
+ bdaddr_t bdaddr;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if(argc < 2){
+ printf("\n%s\n",wba_help);
+ return;
+ }
+
+ str2ba(argv[1],&bdaddr);
+ if((strlen(argv[1]) < 17)||(strlen(argv[1]) > 17)){
+ printf("\nInvalid BD address : %s\n",argv[1]);
+ printf("\n%s\n",wba_help);
+ return;
+ }
+ LoadPSHeader(buf,PS_WRITE,BD_ADDR_SIZE,BD_ADDR_PSTAG);
+ int i,j=0;
+ for(i= 0,j=4;i< BD_ADDR_SIZE;i++,j++){
+ buf[j] = bdaddr.b[i];
+ }
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS,BD_ADDR_SIZE + PS_COMMAND_HEADER, buf);
+ if (buf[6] != 0) {
+ printf("\nWrite BD address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ memset(&buf,0,sizeof(buf));
+ writeHciCommand(uart_fd, HCI_CMD_OGF_HOST_CTL, HCI_CMD_OCF_RESET, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nError: HCI RESET failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ memset(&buf,0,sizeof(buf));
+ writeHciCommand(uart_fd, HCI_CMD_OGF_INFO_PARAM, HCI_CMD_OCF_READ_BD_ADDR, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nError: read bdaddr command failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ printf("\nBD address changed successfully\n");
+}
+
+static const char *edutm_help =
+"Usage:\n"
+"\n edutm\n";
+
+static void cmd_edutm(int uart_fd, int argc, char **argv){
+ if(argv) UNUSED(argv);
+ if(argc > 1){
+ printf("\n%s\n",edutm_help);
+ return;
+ }
+ /*
+ Patch_Count = 20;
+ for(i=0; i < Patch_Count; i++){
+ RamPatch[i].Len = MAX_BYTE_LENGTH;
+ memset(&RamPatch[i].Data,0,MAX_BYTE_LENGTH);
+ }
+ printf("\nCMD DUT MODE\n");
+ */
+ if(!Dut(uart_fd)){
+ return;
+ }
+ printf("\nDevice is in test mode ...\n");
+ return;
+}
+
+
+static int ReadMemorySmallBlock(int uart_fd, int StartAddress,UCHAR *pBufToWrite, int Length ){
+ UCHAR *pData;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ pData = (UCHAR *) malloc(Length + 6);
+ if(!pData){
+ printf("bt ReadMemorySmallBlock: allocation failed! \n");
+ return -1;
+ }
+ memset(pData,0,Length+6);
+ pData[0]= 0x00; //Memory Read Opcode
+ pData[1]= (StartAddress & 0xFF);
+ pData[2]= ((StartAddress >> 8) & 0xFF);
+ pData[3]= ((StartAddress >> 16) & 0xFF);
+ pData[4]= ((StartAddress >> 24) & 0xFF);
+ pData[5]= Length;
+
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_MEMOP,Length+6,pData);
+ if(pData[6]!= 0){
+ printf("\nwrite memory command failed due to reason 0x%X\n",pData[6]);
+ free(pData);
+ return FALSE;
+ }
+ /*int plen =0;
+ do{
+ plen = read(uart_fd, buf,MAX_EVENT_SIZE);
+ if (plen < 0) {
+ free(pData);
+ perror("Read failed");
+ exit(EXIT_FAILURE);
+ }
+ }while (buf[HCI_EVENT_HEADER_SIZE] != DEBUG_EVENT_TYPE_MEMBLK);*/
+ memset(buf,0,MAX_EVENT_SIZE);
+ read_event_modified(uart_fd, buf, 0);
+
+ memcpy(pBufToWrite,(buf+HCI_EVENT_HEADER_SIZE+1),Length);
+ free(pData);
+ return TRUE;
+}
+
+static int ReadMemoryBlock(int uart_fd, int StartAddress, UCHAR *pBufToWrite, int Length ){
+
+ int ModResult,i;
+
+ if(Length > MEM_BLK_DATA_MAX){
+ ModResult = Length % MEM_BLK_DATA_MAX;
+ for(i=0;i < (Length - ModResult);i += MEM_BLK_DATA_MAX) {
+ ReadMemorySmallBlock(uart_fd, (StartAddress + i),(pBufToWrite + i), MEM_BLK_DATA_MAX);
+ }
+ if(ModResult){
+ ReadMemorySmallBlock(uart_fd, (StartAddress + i),(pBufToWrite + i), ModResult);
+ }
+ }
+ else{
+
+ ReadMemorySmallBlock(uart_fd, StartAddress, pBufToWrite, Length);
+ }
+ return TRUE;
+}
+
+static int WriteMemorySmallBlock(int uart_fd, int StartAddress,UCHAR *pBufToWrite, int Length ){
+ UCHAR *pData;
+
+ if(pBufToWrite) UNUSED(pBufToWrite);
+ printf("\nStart Address:%x Length:%x %x\n",StartAddress,Length,MEM_BLK_DATA_MAX);
+ /*if(Length <= MEM_BLK_DATA_MAX)
+ return FALSE; */
+ pData = (UCHAR *) malloc(Length + 6);
+ if(!pData){
+ printf("bt WriteMemorySmallBlock: allocation failed! \n");
+ return -1;
+ }
+ memset(pData,0,Length+6);
+ pData[0]= 0x01; //Write Read Opcode
+ pData[1]= (StartAddress & 0xFF);
+ pData[2]= ((StartAddress >> 8) & 0xFF);
+ pData[3]= ((StartAddress >> 16) & 0xFF);
+ pData[4]= ((StartAddress >> 24) & 0xFF);
+ pData[5]= Length;
+
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_MEMOP,Length+6,pData);
+ if(pData[6]!= 0){
+ printf("\nwrite memory command failed due to reason 0x%X\n",pData[6]);
+ free(pData);
+ return FALSE;
+ }
+ free(pData);
+ return TRUE;
+}
+
+
+static int WriteMemoryBlock(int uart_fd, int StartAddress,UCHAR *pBufToWrite, int Length ){
+
+ int ModResult,i;
+
+ if(Length > MEM_BLK_DATA_MAX){
+ ModResult = Length % MEM_BLK_DATA_MAX;
+ for(i=0;i < (Length - ModResult);i += MEM_BLK_DATA_MAX) {
+ WriteMemorySmallBlock(uart_fd, (StartAddress + i),(pBufToWrite + i), MEM_BLK_DATA_MAX);
+ }
+ if(ModResult){
+ WriteMemorySmallBlock(uart_fd, (StartAddress + i),(pBufToWrite + i), ModResult);
+ }
+ }
+ else{
+
+ WriteMemorySmallBlock(uart_fd, StartAddress, pBufToWrite, Length);
+ }
+ return TRUE;
+}
+
+
+static int ReadHostInterest(int uart_fd, tBtHostInterest *pHostInt){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int iRet;
+ int HostInterestAddress;
+ memset(&buf,0,MAX_EVENT_SIZE);
+ iRet = writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_HOST_INTEREST, 0, buf);
+ if(iRet < 4 || iRet>=MAX_EVENT_SIZE){
+ printf("\nread buffer size overflowed %d\n", iRet);
+ return FALSE;
+ }
+ if(buf[6] != 0){
+ printf("\nhost interest command failed due to reason 0x%X\n",buf[6]);
+ return FALSE;
+ }
+ HostInterestAddress = buf[iRet-1];
+ HostInterestAddress = ((HostInterestAddress << 8)|buf[iRet-2]);
+ HostInterestAddress = ((HostInterestAddress << 8)|buf[iRet-3]);
+ HostInterestAddress = ((HostInterestAddress << 8)|buf[iRet-4]);
+ ReadMemoryBlock(uart_fd, HostInterestAddress,(UCHAR*)pHostInt, sizeof(tBtHostInterest));
+
+ if(pHostInt->MagicNumber != HI_MAGIC_NUMBER){
+ if((pHostInt->MagicNumber != 0xFBAD)|| (pHostInt->Version != 0xDECA))
+ return 0;
+ }
+ return TRUE;
+}
+
+static int contRxAtGivenChannel(int uart_fd, UCHAR *pString){
+ int Address, Mask, Reg, RxFreq;
+ UCHAR buf[MAX_EVENT_SIZE];
+ //1. Disable all scans and set intervals and scan windows eually
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0; //All scan disabled
+ // OGF_HOST_CTL 0x03
+ // OCF_WRITE_SCAN_ENABLE 0x001A
+ writeHciCommand(uart_fd, 0x03, 0x001A, 1, buf);
+ if(buf[6] != 0){
+ printf("\nWrite scan mode command failed due to reason 0x%X\n",buf[6]);
+ return 0;
+ }
+ short int inq_scan = 0x1000;
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = (inq_scan&0xFF);
+ buf[1] = ((inq_scan >> 8)& 0xFF);
+ buf[2] = (inq_scan&0xFF);
+ buf[3] = ((inq_scan >> 8)& 0xFF);
+ // OGF_HOST_CTL 0x03
+ // OCF_WRITE_INQ_ACTIVITY 0x001E
+ writeHciCommand(uart_fd, 0x03, 0x001E, 4, buf);
+ if(buf[6] != 0){
+ printf("\nWrite inquiry scan activity command failed due to reason 0x%X\n",buf[6]);
+ return 0;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = (inq_scan&0xFF);
+ buf[1] = ((inq_scan >> 8)& 0xFF);
+ buf[2] = (inq_scan&0xFF);
+ buf[3] = ((inq_scan >> 8)& 0xFF);
+ // OGF_HOST_CTL 0x03
+ // OCF_WRITE_PAGE_ACTIVITY 0x001C
+ writeHciCommand(uart_fd, 0x03, 0x001C, 4, buf);
+ if(buf[6] != 0){
+ printf("\nWrite page scan activity command failed due to reason 0x%X\n",buf[6]);
+ return 0;
+ }
+ //2. Disbable AGC
+ Address = LC_JTAG_MODEM_REGS_ADDRESS + AGC_BYPASS_ADDRESS;
+ Mask = AGC_BYPASS_ENABLE_MASK;
+ Reg = AGC_BYPASS_ENABLE_SET(1);
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = (Address & 0xFF);
+ buf[1] = ((Address >>8) & 0xFF);
+ buf[2] = ((Address>>16) & 0xFF);
+ buf[3] = ((Address>>24) & 0xFF);
+ buf[4] = 0x04; //Memory width
+ buf[5] = (Reg & 0xFF);
+ buf[6] = ((Reg >> 8) & 0xFF);
+ buf[7] = ((Reg >> 16) & 0xFF);
+ buf[8] = ((Reg >> 24) & 0xFF);
+ buf[9] = (Mask & 0xFF);
+ buf[10] = ((Mask >>8) & 0xFF);
+ buf[11] = ((Mask>>16) & 0xFF);
+ buf[12] = ((Mask>>24) & 0xFF);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite to AGC bypass register failed due to reason 0x%X\n",buf[6]);
+ return 0;
+ }
+ // 3. Disable frequency hoping and set rx frequency
+ //RxFreq = (int)(pString); BEN: using pointer address is meaningless
+ RxFreq = (int)(*pString);
+
+ Address = LC_DEV_PARAM_CTL_ADDRESS;
+ Mask = LC_DEV_PARAM_CTL_FREQ_HOP_EN_MASK |
+ LC_DEV_PARAM_CTL_RX_FREQ_MASK |
+ LC_DEV_PARAM_CTL_WHITEN_EN_MASK;
+ Reg = LC_DEV_PARAM_CTL_RX_FREQ_SET(RxFreq);
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = (Address & 0xFF);
+ buf[1] = ((Address >>8) & 0xFF);
+ buf[2] = ((Address>>16) & 0xFF);
+ buf[3] = ((Address>>24) & 0xFF);
+ buf[4] = 0x04; //Memory width
+ buf[5] = (Reg & 0xFF);
+ buf[6] = ((Reg >> 8) & 0xFF);
+ buf[7] = ((Reg >> 16) & 0xFF);
+ buf[8] = ((Reg >> 24) & 0xFF);
+ buf[9] = (Mask & 0xFF);
+ buf[10] = ((Mask >>8) & 0xFF);
+ buf[11] = ((Mask>>16) & 0xFF);
+ buf[12] = ((Mask>>24) & 0xFF);
+
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite to Rx Freq register failed due to reason 0x%X\n",buf[6]);
+ return 0;
+ }
+ // 4. Enable page scan only (Note: the old way puts device into inq scan mode only ???)
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 2; //Page scan enabled
+ // OGF_HOST_CTL 0x03
+ // OCF_WRITE_SCAN_ENABLE 0x001A
+ writeHciCommand(uart_fd, 0x03, 0x001A, 1, buf);
+ if(buf[6] != 0){
+ printf("\nPage scan enable command failed due to reason 0x%X\n",buf[6]);
+ return 0;
+ }
+ // 5. Increase correlator
+ Address = LC_JTAG_MODEM_REGS_ADDRESS + CORR_PARAM1_ADDRESS;
+ Mask = CORR_PARAM1_TIM_THR_MASK;
+ Reg = CORR_PARAM1_TIM_THR_SET(0x3f);
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = (Address & 0xFF);
+ buf[1] = ((Address >>8) & 0xFF);
+ buf[2] = ((Address>>16) & 0xFF);
+ buf[3] = ((Address>>24) & 0xFF);
+ buf[4] = 0x04; //Memory width
+ buf[5] = (Reg & 0xFF);
+ buf[6] = ((Reg >> 8) & 0xFF);
+ buf[7] = ((Reg >> 16) & 0xFF);
+ buf[8] = ((Reg >> 24) & 0xFF);
+ buf[9] = (Mask & 0xFF);
+ buf[10] = ((Mask >>8) & 0xFF);
+ buf[11] = ((Mask>>16) & 0xFF);
+ buf[12] = ((Mask>>24) & 0xFF);
+
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite to Correlator register failed due to reason 0x%X\n",buf[6]);
+ return 0;
+ }
+
+ return TRUE;
+}
+static const char *cwrx_help =
+"Usage:\n"
+"\n cwrx <Channel>\n";
+
+static void cmd_cwrx(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR channel;
+ BOOL Ok = TRUE;
+ if(argc != 2){
+ printf("\n%s\n",cwrx_help);
+ return;
+ }
+
+ channel = atoi(argv[1]);
+ if(channel > 78 ){
+ printf("\nPlease enter channel 0-78!\n");
+ return;
+ }
+
+ // Disable sleep mode
+ memset(&buf,0,sizeof(buf));
+ buf[0] = 0;
+ writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0){
+ printf("\nError: Sleep mode failed due to reason 0x%X\n",buf[6]);
+ Ok = 0;
+ }
+ printf (" Continuoux Rx at channel %d\n",channel);
+ Ok = contRxAtGivenChannel(uart_fd, &channel);
+
+ // All modes come here
+ if (Ok) {
+ printf (" Continuoux Rx at channel %d Done...\n",channel);
+ }
+ else {
+ printf ("\nERROR ---> Could not enter continuous Rx mode\n");
+ }
+}
+
+int OCFRXTestMode(int uart_fd, tBRM_Control_packet *MasterBlaster, UCHAR SkipRxSlot)
+{
+ BOOL Ok = TRUE;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ memset(&buf,0,sizeof(buf));
+ buf[0] = 0;
+ writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0) {
+ printf ("\nERROR ---> Could not disable sleep mode\n");
+ return -1;
+ }
+ Ok = Dut(uart_fd);
+ if (!Ok) {
+ printf("\nERROR ---> Could not enter DUT mode\n");
+ return -1;
+ }
+ printf(".");
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = eBRM_TestMode_Rx;
+ buf[1] = MasterBlaster->testCtrl.Packet;
+ buf[2] = MasterBlaster->testCtrl.DataLen & 0xFF;
+ buf[3] = ((MasterBlaster->testCtrl.DataLen>>8) & 0xFF);
+ buf[4] = MasterBlaster->testCtrl.HopMode;
+ buf[5] = MasterBlaster->testCtrl.TxFreq;
+ buf[6] = MasterBlaster->testCtrl.Power;
+ buf[7] = MasterBlaster->testCtrl.RxFreq;
+ buf[8] = MasterBlaster->bdaddr[0];
+ buf[9] = MasterBlaster->bdaddr[1];
+ buf[10] = MasterBlaster->bdaddr[2];
+ buf[11] = MasterBlaster->bdaddr[3];
+ buf[12] = MasterBlaster->bdaddr[4];
+ buf[13] = MasterBlaster->bdaddr[5];
+ buf[14] = SkipRxSlot;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_RX_TESTER, 15, buf);
+ if (buf[6] != 0) {
+ printf("\nRx Tester command failed due to reason 0x%X\n",buf[6]);
+ printf("\nERROR --> Could not enable master blaster mode\n");
+ Ok = 0;
+ return MB_NO_TEST;
+ }
+ printf(" rx test is in progress. Press 's' to stop the test\n");
+ return MB_RX_TEST;
+}
+
+int OCFTXTestMode(int uart_fd, tBRM_Control_packet *MasterBlaster, UCHAR SkipRxSlot)
+{
+ BOOL Ok = TRUE;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ memset(&buf,0,sizeof(buf));
+ buf[0] = 0;
+ writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0) {
+ printf ("\nERROR ---> Could not disable sleep mode\n");
+ return -1;
+ }
+
+ printf (".");
+ Ok = Dut(uart_fd);
+ if (!Ok) {
+ printf("\nERROR ---> Could not enter DUT mode\n");
+ return -1;
+ }
+
+ printf(".");
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = MasterBlaster->testCtrl.Mode;
+ buf[1] = MasterBlaster->testCtrl.Packet;
+ buf[2] = MasterBlaster->testCtrl.DataLen & 0xFF;
+ buf[3] = ((MasterBlaster->testCtrl.DataLen>>8) & 0xFF);
+ buf[4] = MasterBlaster->testCtrl.HopMode;
+ buf[5] = MasterBlaster->testCtrl.TxFreq;
+ buf[6] = MasterBlaster->testCtrl.Power;
+ buf[7] = MasterBlaster->testCtrl.RxFreq;
+ buf[8] = MasterBlaster->bdaddr[0];
+ buf[9] = MasterBlaster->bdaddr[1];
+ buf[10] = MasterBlaster->bdaddr[2];
+ buf[11] = MasterBlaster->bdaddr[3];
+ buf[12] = MasterBlaster->bdaddr[4];
+ buf[13] = MasterBlaster->bdaddr[5];
+ buf[14] = SkipRxSlot;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_TX_TESTER, 15, buf);
+ if (buf[6] != 0) {
+ printf("\nTx Tester command failed due to reason 0x%X\n",buf[6]);
+ printf("\nERROR --> Could not enable master blaster mode\n");
+ return MB_NO_TEST;
+ }
+ printf(" tx test is in progress. Press 's' to stop the test\n");
+ return MB_TX_TEST;
+}
+
+int OCFContTXTestMode(int uart_fd, tBRM_Control_packet *MasterBlaster)
+{
+ BOOL Ok = TRUE;
+ UCHAR buf[MAX_EVENT_SIZE];
+ int address, width, value, mask;
+
+ memset(&buf,0,sizeof(buf));
+ buf[0] = 0;
+ writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0) {
+ printf ("\nERROR ---> Could not disable sleep mode\n");
+ return -1;
+ }
+
+ Ok = Dut(uart_fd);
+ if (!Ok) {
+ printf("\nERROR ---> Could not enter DUT mode\n");
+ return -1;
+ }
+
+ /* Enable master blaster mode */
+ printf(".");
+ /*
+ if (CW_Single_Tone == MasterBlaster.ContTxType)
+ setContTxType = Cont_Tx_Raw_1MHz;
+ else
+ setContTxType = MasterBlaster.ContTxType;
+ */
+ memset(&buf, 0, MAX_EVENT_SIZE);
+ buf[0] = MasterBlaster->testCtrl.Mode ;
+ buf[1] = MasterBlaster->testCtrl.Packet;
+ buf[2] = MasterBlaster->testCtrl.DataLen & 0xFF;
+ buf[3] = ((MasterBlaster->testCtrl.DataLen>>8) & 0xFF);
+ buf[4] = MasterBlaster->ContTxType;
+ buf[5] = MasterBlaster->testCtrl.TxFreq;
+ buf[6] = MasterBlaster->testCtrl.Power;
+ buf[7] = MasterBlaster->testCtrl.RxFreq;
+ buf[8] = MasterBlaster->bdaddr[0];
+ buf[9] = MasterBlaster->bdaddr[1];
+ buf[10] = MasterBlaster->bdaddr[2];
+ buf[11] = MasterBlaster->bdaddr[3];
+ buf[12] = MasterBlaster->bdaddr[4];
+ buf[13] = MasterBlaster->bdaddr[5];
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_CONT_TX_TESTER, 14, buf);
+ if(buf[6] != 0){
+ printf("\nContinious Tx Tester command failed due to reason 0x%X\n",buf[6]);
+ return MB_NO_TEST;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ address = 0x00022914;
+ value = 0x00200000;
+ mask = 0x00200000;
+ width = 4;
+ buf[0] = (address & 0xFF);
+ buf[1] = ((address >>8) & 0xFF);
+ buf[2] = ((address>>16) & 0xFF);
+ buf[3] = ((address>>24) & 0xFF);
+ buf[4] = width; //Memory width
+ buf[5] = (value & 0xFF);
+ buf[6] = ((value >> 8) & 0xFF);
+ buf[7] = ((value >> 16) & 0xFF);
+ buf[8] = ((value >> 24) & 0xFF);
+ buf[9] = (mask & 0xFF);
+ buf[10] = ((mask >>8) & 0xFF);
+ buf[11] = ((mask>>16) & 0xFF);
+ buf[12] = ((mask>>24) & 0xFF);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return MB_NO_TEST;
+ }
+ return MB_CONT_TX_TEST;
+}
+
+int OCFContRXTestMode(int uart_fd, tBRM_Control_packet *MasterBlaster)
+{
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ memset(&buf,0,sizeof(buf));
+ buf[0] = 0;
+ writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0) {
+ printf ("\nERROR ---> Could not disable sleep mode\n");
+ return -1;
+ }
+
+ UCHAR RxFreq = MasterBlaster->testCtrl.RxFreq;
+ contRxAtGivenChannel(uart_fd, &RxFreq);
+ return MB_CONT_RX_TEST;
+}
+
+static const char *cmdline_help =
+ "\n<BTConfig command v.1.2>"
+ "\n1. Usage for TX and Con TX:"
+ "\n btconfig cmdline [TestMode|DataPattern|PacketType|DataLen|HopMode|TxFreq|Power|RxFreq"
+ "\n [TestMode]"
+ "\n MB_NO_TEST : stop to transmit"
+ "\n MB_RX_TEST : reserve feature"
+ "\n MB_TX_TEST : TX mode"
+ "\n MB_CONT_RX_TEST : reserve feature"
+ "\n MB_CONT_TX_TEST : continuous TX"
+ "\n MB_LE_RX_TEST : reserve feature"
+ "\n MB_LE_TX_TEST : LE TX mode"
+ "\n [DataPattern]"
+ "\n 0 : eBRM_TestMode_Pause"
+ "\n 1 : eBRM_TestMode_TX_0"
+ "\n 2 : eBRM_TestMode_TX_1"
+ "\n 3 : eBRM_TestMode_TX_1010"
+ "\n 4 : eBRM_TestMode_TX_PRBS"
+ "\n 5 : eBRM_TestMode_Loop_ACL"
+ "\n 6 : eBRM_TestMode_Loop_SCO"
+ "\n 7 : eBRM_TestMode_Loop_ACL_No_Whitening"
+ "\n 8 : eBRM_TestMode_Loop_SCO_No_Whitening"
+ "\n 9 : eBRM_TestMode_TX_11110000"
+ //"\n 10: eBRM_TestMode_Rx"
+
+ //"\n 255 : eBRM_TestMode_Exit"
+
+ "\n [PacketType] DM1,DH1,DM3,DH3,DM5,DM5,2-DH1,2-DH3,2-DH5,3-DH1,3-DH3,3-DH5"
+ "\n [DataLen] length of data"
+ "\n [HopMode]"
+ "\n 0 => DISABLE"
+ "\n 1 => ENABLE"
+ "\n fixed to 0 for Continuous TX(1 MHz tone)"
+ "\n [TxFreq] 0~78(0=2402 MHz, 39=2441MHz, 78=2480MHz)"
+ "\n [Power] 1 ~ 8"
+ "\n 1 : -20 dbm"
+ "\n 2 : -16 dbm"
+ "\n 3 : -12 dbm"
+ "\n 4 : -8 dbm"
+ "\n 5 : -4 dbm"
+ "\n 6 : 0 dbm"
+ "\n 7 : 4 dbm"
+ "\n 8 : 8 dbm"
+ "\n [RxFreq] 0 ~ 78 (0=2402 MHz, 39=2441MHz, 78=2480MHz)"
+ "\nExample:"
+ "\tbtconfig cmdline MB_TX_TEST 4 DM1 100 0 39 0 39\t"
+ "\n TX Mode|DataPattern = PRBS|DM1|length=100 bytes|Hop OFF|TX ch=39|power=-20dbm|RX ch=39"
+ "\tbtconfig cmdline MB_CONT_TX_TEST 3 DM1 100 0 39 8 39\t"
+ "\n CONT TX Mode|DataPattern=1010|DM1|length=100bytes|Cont TX ON|TX ch=39|power=8dbm|RX ch=39"
+ "\n\n2. Usage for LE TX:"
+ "\n btconfig cmdline [TestMode|DataPattern|DataLen|TxFreq|"
+ "\n [TestMode]"
+ "\n MB_LE_TX_TEST : LE TX mode"
+ "\n [DataPattern] data pattern from 0 to 7"
+ "\n 0 => PRBS9"
+ "\n 1 => 11110000"
+ "\n 2 => 10101010"
+ "\n 3 => PRBS15"
+ "\n 4 => 11111111"
+ "\n 5 => 00000000"
+ "\n 6 => 00001111"
+ "\n 7 => 01010101"
+ "\n [DataLen] 0 to 37 bytes"
+ "\n [TxFreq] 0 ~ 39"
+ "\nExample:"
+ "\n btconfig cmdline MB_LE_TX_TEST 0 30 20"
+ "\n LE TX mode|DataPattern=PRBS9|length=30bytes|TX ch=20"
+ "\n\n3. Usage for STOP/INITIAL TX:"
+ "\n btconfig cmdline [TestMode]"
+ "\nExample:"
+ "\tbtconfig cmdline MB_NO_TEST\t";
+
+//add by Austin for automatic manufacture tool
+
+static void cmdline(int uart_fd, int argc, char **argv){
+ int iRet,address,width,value,mask;
+ bdaddr_t bdaddr;
+ tBRM_Control_packet MasterBlaster;
+ UCHAR SkipRxSlot;
+ UCHAR buf[HCI_MAX_EVENT_SIZE];
+ BOOL TestEnabled = 0,Ok = TRUE;
+ UINT8 setContTxType;
+ tBtHostInterest HostInt;
+ fd_set master, read_fds;
+ //struct timeval timeout;
+ char BdAddr[18];
+
+ printf("\nrunning command line");
+ if(argc < 2){
+ printf("\n%s\n",cmdline_help);
+ return;
+ }
+
+ memset(&buf,0,HCI_MAX_EVENT_SIZE);
+ iRet = writeHciCommand(uart_fd, HCI_CMD_OGF_INFO_PARAM, HCI_CMD_OCF_READ_BD_ADDR, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nread bdaddr command failed due to reason 0x%X",buf[6]);
+ return;
+ }else{
+ printf("\nread bdaddr command successfully");
+ }
+
+ int i,j;
+ char bda[18];
+ for (i=iRet-1,j=0;i>7;i--,j+=3) {
+ snprintf(&bda[j],sizeof(bda[j]),"%X",((buf[i]>>4)&0xFF));
+ snprintf(&bda[j+1],sizeof(bda[j+1]),"%X",(buf[i]&0x0F));
+ bda[j+2]=':';
+ }
+ snprintf(&bda[15],sizeof(bda[15]),"%X",((buf[7]>>4)&0xFF));
+ snprintf(&bda[16],sizeof(bda[16]),"%X",(buf[7]&0x0F));
+ bda[17] ='\0';
+ str2ba(bda,&bdaddr);
+ printf("\nBDAddr = %s",bda);
+
+ InitMasterBlaster(&MasterBlaster, &bdaddr, &SkipRxSlot);
+#ifndef DUMP_DEBUG
+
+ Ok = ReadHostInterest(uart_fd, &HostInt);
+ if(Ok) {
+ if (HostInt.TpcTableAddr && (HostInt.Version >= 0x0100)) {
+ Ok = ReadMemoryBlock(uart_fd, HostInt.TpcTableAddr, (UCHAR *)&TpcTable, sizeof(TpcTable));
+ MasterBlaster.testCtrl.Power = TpcTable.NumOfEntries - 1;
+ }
+ }
+ if(!Ok) {
+ printf ("\nCould not load TPC table.");
+ sleep (2);
+ Ok = TRUE;
+ }
+#endif
+
+ FD_ZERO(&master);
+ FD_ZERO(&read_fds);
+ FD_SET(0, &master);
+
+ //======================
+
+ //disable Sleep Mode
+
+ //======================
+
+ memset(&buf,0,sizeof(buf));
+ buf[0] = 0; //disable Sleep mode
+
+ iRet = writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0) {
+ printf("\nError: Sleep mode failed due to reason 0x%X",buf[6]);
+ }else{
+ printf("\nDisable Sleep mode successfully");
+ }
+
+ //======================
+
+ //Enable TX Mode
+
+ //======================
+
+ if (strcmp("MB_TX_TEST", argv[1]) == 0){
+ if(argc < 9){
+ printf("\n%s\n",cmdline_help);
+ return;
+ }
+ printf("\nEnable TX Mode\n");
+
+ //==================================
+
+ // check it is under test mode
+
+ //==================================
+
+ Ok = Dut(uart_fd);
+ if (!Ok) {
+ printf("\nERROR ---> Could not enter DUT mode\n");
+ }
+
+ memset(&buf,0,HCI_MAX_EVENT_SIZE);
+
+ buf[0] = atoi(argv[2]); //Data Pattern
+
+ if (strcmp("DM1", argv[3]) == 0) //PacketType
+
+ buf[1] = 0x03;
+ else if (strcmp("DH1", argv[3]) == 0)
+ buf[1] = 0x04;
+ else if (strcmp("DM3", argv[3]) == 0)
+ buf[1] = 0x0A;
+ else if (strcmp("DH3", argv[3]) == 0)
+ buf[1] = 0x0B;
+ else if (strcmp("DM5", argv[3]) == 0)
+ buf[1] = 0x0E;
+ else if (strcmp("DH5", argv[3]) == 0)
+ buf[1] = 0x0F;
+ else if (strcmp("2-DH1", argv[3]) == 0)
+ buf[1] = 0x24;
+ else if (strcmp("2-DH3", argv[3]) == 0)
+ buf[1] = 0x2A;
+ else if (strcmp("2-DH5", argv[3]) == 0)
+ buf[1] = 0x2E;
+ else if (strcmp("3-DH1", argv[3]) == 0)
+ buf[1] = 0x28;
+ else if (strcmp("3-DH3", argv[3]) == 0)
+ buf[1] = 0x2B;
+ else if (strcmp("3-DH5", argv[3]) == 0)
+ buf[1] = 0x2F;
+ buf[2] = (atoi(argv[4]) & 0xFF); //DataLen
+
+ buf[3] = (atoi(argv[4])>>8 & 0xFF); //DataLen
+
+ buf[4] = atoi(argv[5]); //HopMode
+
+ buf[5] = atoi(argv[6]); //TxFreq
+
+ buf[6] = atoi(argv[7]); //Power
+
+ buf[7] = atoi(argv[8]); //RxFreq
+
+ buf[8] = MasterBlaster.bdaddr[0];
+ buf[9] = MasterBlaster.bdaddr[1];
+ buf[10] = MasterBlaster.bdaddr[2];
+ buf[11] = MasterBlaster.bdaddr[3];
+ buf[12] = MasterBlaster.bdaddr[4];
+ buf[13] = MasterBlaster.bdaddr[5];
+ buf[14] = SkipRxSlot;
+
+ ba2str((const bdaddr_t *)MasterBlaster.bdaddr, BdAddr);
+
+ if (strcmp("0", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Pause |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("1", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=all 0 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("2", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=all 1 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("3", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=1010 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("4", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=PRBS |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("5", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_ACL |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("6", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_SCO |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("7", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_ACL_No_Whitening |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("8", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_SCO_No_Whitening |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("9", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=11110000 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+
+ iRet = writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_TX_TESTER, 15, buf);
+ if (buf[6] != 0) {
+ printf("\nTx Tester command failed due to reason 0x%X",buf[6]);
+ printf("\nERROR --> Could not enable master blaster mode");
+ TestEnabled = MB_NO_TEST;
+ Ok = 0;
+ } else {
+ printf("\ntx test is in progress. Press type 'btconfig cmdline MB_NO_TEST' to stop the test");
+ TestEnabled = MB_TX_TEST;
+ }
+ }
+ //===========================
+
+ //Enable Continuous TX Mode
+
+ //===========================
+
+ else if (strcmp("MB_CONT_TX_TEST", argv[1]) == 0){
+ if(argc < 9){
+ printf("\n%s\n",cmdline_help);
+ return;
+ }
+ printf("\nEnable Continuous TX Mode");
+
+ Ok = Dut(uart_fd);
+ if (!Ok)
+ printf("\nERROR ---> Could not enter DUT mode");
+
+ /* Enable master blaster mode */
+ if (CW_Single_Tone == MasterBlaster.ContTxType)
+ setContTxType = Cont_Tx_Raw_1MHz;
+ else
+ setContTxType = MasterBlaster.ContTxType;
+
+ memset(&buf, 0, HCI_MAX_EVENT_SIZE);
+ buf[0] = atoi(argv[2]); //Data Pattern
+
+ if (strcmp("DM1", argv[3]) == 0) //PacketType
+
+ buf[1] = 0x03;
+ else if (strcmp("DH1", argv[3]) == 0)
+ buf[1] = 0x04;
+ else if (strcmp("DM3", argv[3]) == 0)
+ buf[1] = 0x0A;
+ else if (strcmp("DH3", argv[3]) == 0)
+ buf[1] = 0x0B;
+ else if (strcmp("DM5", argv[3]) == 0)
+ buf[1] = 0x0E;
+ else if (strcmp("DH5", argv[3]) == 0)
+ buf[1] = 0x0F;
+ else if (strcmp("2-DH1", argv[3]) == 0)
+ buf[1] = 0x24;
+ else if (strcmp("2-DH3", argv[3]) == 0)
+ buf[1] = 0x2A;
+ else if (strcmp("2-DH5", argv[3]) == 0)
+ buf[1] = 0x2E;
+ else if (strcmp("3-DH1", argv[3]) == 0)
+ buf[1] = 0x28;
+ else if (strcmp("3-DH3", argv[3]) == 0)
+ buf[1] = 0x2B;
+ else if (strcmp("3-DH5", argv[3]) == 0)
+ buf[1] = 0x2F;
+ buf[2] = (atoi(argv[4]) & 0xFF);//DataLen
+
+ buf[3] = (atoi(argv[4])>>8 & 0xFF);//DataLen
+
+ buf[4] = atoi(argv[5]);//Continuous TX which is fixed to "Cont_Tx_Raw_1MHz"
+
+ buf[5] = atoi(argv[6]);//TxFreq
+
+ buf[6] = atoi(argv[7]);//Power
+
+ buf[7] = atoi(argv[8]);//RxFreq
+
+ buf[8] = MasterBlaster.bdaddr[0];
+ buf[9] = MasterBlaster.bdaddr[1];
+ buf[10] = MasterBlaster.bdaddr[2];
+ buf[11] = MasterBlaster.bdaddr[3];
+ buf[12] = MasterBlaster.bdaddr[4];
+ buf[13] = MasterBlaster.bdaddr[5];
+ ba2str((const bdaddr_t *)MasterBlaster.bdaddr, BdAddr);
+
+ if (strcmp("0", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Pause |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("1", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=all 0 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("2", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=all 1 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("3", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=1010 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("4", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=PRBS |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("5", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_ACL |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("6", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_SCO |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("7", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_ACL_No_Whitening |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("8", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=Loop_SCO_No_Whitening |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+ if (strcmp("9", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=11110000 |PacketType=%s | DataLen=%d | HopMode=%d | TxFreq=%d | Power level=%d | RxFreq=%d | BdAddr=0x%s", argv[1], argv[3], atoi(argv[4]), buf[4], buf[5], buf[6], buf[7], BdAddr);
+
+ iRet = writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_CONT_TX_TESTER, 14, buf);
+ if(buf[6] != 0){
+ printf("\nContinious Tx Tester command failed due to reason 0x%X",buf[6]);
+ Ok = FALSE;
+ } else
+ Ok = TRUE;
+ memset(&buf,0,HCI_MAX_EVENT_SIZE);
+ address = 0x00022914;
+ value = 0x00200000;
+ mask = 0x00200000;
+ width = 4;
+ buf[0] = (address & 0xFF);
+ buf[1] = ((address >>8) & 0xFF);
+ buf[2] = ((address>>16) & 0xFF);
+ buf[3] = ((address>>24) & 0xFF);
+ buf[4] = width; //Memory width
+
+ buf[5] = (value & 0xFF);
+ buf[6] = ((value >> 8) & 0xFF);
+ buf[7] = ((value >> 16) & 0xFF);
+ buf[8] = ((value >> 24) & 0xFF);
+ buf[9] = (mask & 0xFF);
+ buf[10] = ((mask >>8) & 0xFF);
+ buf[11] = ((mask>>16) & 0xFF);
+ buf[12] = ((mask>>24) & 0xFF);
+ iRet = writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X",buf[6]);
+ Ok = FALSE;
+ } else
+ Ok = TRUE;
+ TestEnabled = MB_CONT_TX_TEST;
+ if (Ok) {
+ printf("\nContinuous Test is in progress. Press type 'btconfig cmdline MB_NO_TEST' to stop the test");
+ } else {
+ printf("\nERROR ---> Could not enable master blaster mode");
+ TestEnabled = MB_NO_TEST;
+ }
+ }
+ //======================
+
+ //Enable LE TX Mode
+
+ //======================
+
+ else if (strcmp("MB_LE_TX_TEST", argv[1]) == 0){
+ if(argc < 5){
+ printf("\n%s\n",cmdline_help);
+ return;
+ }
+ printf("\nEnable LE TX Mode");
+
+ buf[0] = atoi(argv[2]);//Data Pattern
+
+ buf[2] = atoi(argv[3]);//Data Length
+
+ buf[5] = atoi(argv[4]);//TX Freq
+
+
+ if (strcmp("0", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=PRBS9 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+ else if (strcmp("1", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=11110000 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+ else if (strcmp("2", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=10101010 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+ else if (strcmp("3", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=PRBS15 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+ else if (strcmp("4", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=11111111 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+ else if (strcmp("5", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=00000000 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+ else if (strcmp("6", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=00001111 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+ else if (strcmp("7", argv[2]) == 0)
+ printf("\nTestMode=%s | DataPattern=01010101 | DataLen=%s | TxFreq=%s", argv[1], argv[3], argv[4]);
+
+ //BOOL SU_LETxTest(int dev_id, UCHAR channel, UCHAR length, UCHAR payload);
+
+ Ok = SU_LETxTest(uart_fd, buf[5], buf[2], buf[0]);
+
+ if (Ok) {
+ printf("\nLE Test is in progress. Press type 'btconfig cmdline MB_NO_TEST' to stop the test");
+ TestEnabled = MB_LE_TX_TEST;
+ } else {
+ printf("\nERROR ---> Could not enable master blaster mode");
+ TestEnabled = MB_NO_TEST;
+ }
+ }
+ //=========================
+
+ //Stop to transmit package
+
+ //=========================
+
+ else if (strcmp("MB_NO_TEST", argv[1]) == 0){
+ if(argc > 2){
+ printf("\n%s\n",cmdline_help);
+ return;
+ }
+ printf("\nStop to transmit package");
+
+ //================================================
+
+ //set BT to Sleep mode which is default setting
+
+ //================================================
+
+ memset(&buf,0,HCI_MAX_EVENT_SIZE);
+ buf[0] = 1;
+ iRet = writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0) {
+ printf("\nError: Sleep mode failed due to reason 0x%X",buf[6]);
+ }else{
+ printf("\nEnable Sleep mode successfully");
+ }
+
+ //=================================================================
+
+ //send "HCI Reset" command to terminate the package transmission
+
+ //=================================================================
+
+ memset(&buf,0,sizeof(buf));
+ iRet = writeHciCommand(uart_fd, HCI_CMD_OGF_HOST_CTL, HCI_CMD_OCF_RESET, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nError: HCI RESET failed due to reason 0x%X",buf[6]);
+ Ok = FALSE;
+ } else
+ Ok = TRUE;
+ if (!Ok) {
+ printf ("\nERROR ---> Could not stop test mode");
+ }
+ TestEnabled = MB_NO_TEST;
+ }else{
+ printf("\nWrong command");
+ }
+
+ UNUSED(TestEnabled);
+ UNUSED(setContTxType);
+ printf("\nDone\n");
+}
+
+static const char *mb_help = "Usage:\n\n mb\n";
+
+static void cmd_mb(int uart_fd, int argc, char **argv){
+ printf("Enter master blaster mode\n");
+
+ int FieldNum,iRet,iDataSize, fdmax, k, l, i, j;
+ bdaddr_t bdaddr;
+ tBRM_Control_packet MasterBlaster;
+ UCHAR SkipRxSlot;
+ UCHAR buf[MAX_EVENT_SIZE];
+ char FieldAlias;
+ BOOL TestEnabled = 0, Ok = TRUE;
+ tBtHostInterest HostInt;
+ fd_set master, read_fds;
+ uint32_t m_BerTotalBits, m_BerGoodBits;
+ uint8_t m_pattern[16];
+ uint16_t m_pPatternlength;
+ struct timeval timeout;
+ int bytesRead = 0;
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ iRet = writeHciCommand(uart_fd, HCI_CMD_OGF_INFO_PARAM, HCI_CMD_OCF_READ_BD_ADDR, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nread bdaddr command failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ char bda[18];
+ for (i = iRet-1, j=0; i>7; i--,j+=3) {
+ snprintf(&bda[j],sizeof(bda[j]),"%X",((buf[i]>>4)&0xFF));
+ snprintf(&bda[j+1],sizeof(bda[j+1]),"%X",(buf[i]&0x0F));
+ bda[j+2] = ':';
+ }
+ snprintf(&bda[15],sizeof(bda[15]),"%X",((buf[7]>>4)&0xFF));
+ snprintf(&bda[16],sizeof(bda[16]),"%X",(buf[7]&0x0F));
+ bda[17] ='\0';
+ str2ba(bda,&bdaddr);
+ InitMasterBlaster(&MasterBlaster, &bdaddr, &SkipRxSlot);
+#ifndef DUMP_DEBUG
+ Ok = ReadHostInterest(uart_fd,&HostInt);
+ if(Ok) {
+ if (HostInt.TpcTableAddr && (HostInt.Version >= 0x0100)) {
+ Ok = ReadMemoryBlock(uart_fd, HostInt.TpcTableAddr, (UCHAR *)&TpcTable, sizeof(TpcTable));
+ MasterBlaster.testCtrl.Power = TpcTable.NumOfEntries - 1;
+ }
+ }
+ if(!Ok){
+ printf ("\nCould not load TPC table.\n");
+ sleep (2);
+ Ok = TRUE;
+ }
+#endif
+#ifdef DEBUG
+ int x = 0;
+ for(x ; x < argc; x++)
+ printf("@@@ %s ", argv[x]);
+ printf("\n");
+#endif
+
+ if (is_qca_transport_uart) {
+ printf("\nCannot support MB mode on %s\n",soc_type);
+ return;
+ }
+
+ if (argv[1] && !strncmp(argv[1],"cmd",3)) {
+ MasterBlaster.testCtrl.Power = atoi(argv[2]);
+ MasterBlaster.testCtrl.RxFreq = atoi(argv[3]);
+ MasterBlaster.testCtrl.TxFreq = atoi(argv[3]);
+ for (i = 0; i < (int)(sizeof(PacketTypeOption)/sizeof(tMasterBlasterOption)); ++i)
+ {
+ printf("%s %s\n",argv[4],PacketTypeOption[i].Name);
+ if (!strcmp(argv[4],PacketTypeOption[i].Name)) {
+ MasterBlaster.testCtrl.Packet = PacketTypeOption[i].Value;
+ MasterBlaster.testCtrl.DataLen = MaxDataLenOption[i];
+ printf("%s %s\n",argv[4],PacketTypeOption[i].Name);
+ break;
+ }
+ }
+ if (!strncmp(argv[5],"Tx",2)) {
+ OCFTXTestMode(uart_fd, &MasterBlaster, SkipRxSlot);
+ printf("Tx\n");
+ }
+ else if (!strncmp(argv[5],"Rx",2)) {
+ OCFRXTestMode(uart_fd, &MasterBlaster, SkipRxSlot);
+ printf("Rx\n");
+ }
+ getchar();
+ memset(&buf,0,sizeof(buf));
+ // OGF_HOST_CTL 0x03
+ // OCF_RESET 0x0003
+ writeHciCommand(uart_fd, 0x03, 0x0003,0,buf);
+ if (buf[6] != 0) {
+ printf("\nError: HCI RESET failed due to reason 0x%X\n",buf[6]);
+ }
+ return;
+ }
+ else if (argc > 1) {
+ printf("\n%s\n", mb_help);
+ return;
+ }
+
+ PrintMasterBlasterMenu (&MasterBlaster);
+ m_BerGoodBits = 0;
+ m_BerTotalBits = 0;
+ m_pattern[0] = 0x0f;
+ m_pPatternlength = 1;
+
+ FD_ZERO(&master);
+ FD_ZERO(&read_fds);
+ FD_SET(0, &master);
+ FD_SET(uart_fd, &master);
+ fdmax = uart_fd;
+
+ printf("Enter master blaster loop\n");
+ while (1) {
+ read_fds = master;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ iRet = select(fdmax+1, &read_fds, NULL, NULL, &timeout);
+ if (iRet == -1) {
+ perror("cmd_mb select() error!");
+ goto exits_mb;
+ }
+ if (iRet == 0) continue;
+
+ for(i = 0; i <= fdmax; i++) {
+ if(FD_ISSET(i, &read_fds)) {
+ if (i==0) {// input
+ scanf("%s",buf);
+ FieldAlias = (char)buf[0];
+ FieldNum = CheckField(MasterBlaster, &FieldAlias);
+ if (FieldNum == INVALID_MASTERBLASTER_FIELD) {
+ printf ("\nERROR ---> Invalid command. Try again.\n");
+ printf ("mb>");
+ continue;
+ }
+
+ if (!strncmp(&FieldAlias, MasterBlasterMenu[EXX].Alias, 1)) {
+ printf("\nExit the Master Blaster Mode without reset\n");
+ goto exits_mb;
+ }
+
+ // if the test is in rx and the key is neither 'd' nor 'g', then stop the test, renew the option, and procced
+ // if the test is in tx and the key is not 'e', then stop the test, renew the option, and procced
+ // if the test is in (LE) continuous rx/tx and the key is not 'j' , then stop the test, renew the option, and procced
+ if (((TestEnabled == MB_RX_TEST) &&
+ strncmp(&FieldAlias, MasterBlasterMenu[RX].Alias, 1) &&
+ strncmp(&FieldAlias, MasterBlasterMenu[GB].Alias, 1)) ||
+
+ ((TestEnabled == MB_TX_TEST) &&
+ strncmp(&FieldAlias, MasterBlasterMenu[TX].Alias, 1)) ||
+
+ ((TestEnabled == MB_CONT_RX_TEST || TestEnabled == MB_CONT_TX_TEST ||
+ TestEnabled == MB_LE_RX_TEST || TestEnabled == MB_LE_TX_TEST) &&
+ (strncmp(&FieldAlias, MasterBlasterMenu[EN].Alias, 1)))) {
+ printf (" ... Please wait ...");
+ if (MasterBlaster.ContTxMode) {
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 255;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_CONT_TX_TESTER, 14, buf);
+ if(buf[6] != 0) {
+ printf("\nContinious Tx Tester command failed due to reason 0x%X\n",buf[6]);
+ Ok = 0;
+ } else
+ Ok = TRUE;
+ }
+
+ memset(&buf,0,sizeof(buf));
+ // The default setting is sleep mode enabled
+ buf[0] = 1;
+ iRet = writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if(buf[6] != 0) {
+ printf("\nError: Sleep mode failed due to reason 0x%X\n",buf[6]);
+ }
+
+ // OGF_HOST_CTL 0x03
+ // OCF_RESET 0x0003
+ memset(&buf, 0, sizeof(buf));
+ writeHciCommand(uart_fd,0x03,0x0003,0,buf);
+ if (buf[6] != 0) {
+ printf("\nError: HCI RESET failed due to reason 0x%X\n",buf[6]);
+ Ok = FALSE;
+ } else
+ Ok = TRUE;
+ if (!Ok) {
+ printf ("\nERROR ---> Could not stop test mode\n");
+ } else if (!strncmp(&FieldAlias, MasterBlasterMenu[RX].Alias, 1) ||
+ !strncmp(&FieldAlias, MasterBlasterMenu[TX].Alias, 1) ||
+ ((TestEnabled != MB_NO_TEST) &&
+ (!strncmp(&FieldAlias, MasterBlasterMenu[CR].Alias, 1) ||
+ !strncmp(&FieldAlias, MasterBlasterMenu[CT].Alias, 1) ||
+ !strncmp(&FieldAlias, MasterBlasterMenu[LR].Alias, 1) ||
+ !strncmp(&FieldAlias, MasterBlasterMenu[LT].Alias, 1))) ||
+ !strncmp(&FieldAlias, MasterBlasterMenu[EN].Alias, 1)) {
+ TestEnabled = MB_NO_TEST;
+ }
+ sleep(1);
+ }
+ if (!strncmp(&FieldAlias,MasterBlasterMenu[EX].Alias,1)){// Exit
+ TestEnabled = MB_NO_TEST;
+ printf ("\n Exit ..\n");
+ goto exits_mb;
+ } else if (!strncmp(&FieldAlias,MasterBlasterMenu[ST].Alias,1)) {// Stop Test
+ TestEnabled = MB_NO_TEST;
+ PrintMasterBlasterMenu (&MasterBlaster);
+ continue;
+ } else if (!strncmp(&FieldAlias,MasterBlasterMenu[GB].Alias,1)) {// get BER
+ printf("\n\tGoodBits %d, total is %d\n", m_BerGoodBits, m_BerTotalBits);
+ printf("mb>\n");
+ continue;
+ } else if (!strncmp(&FieldAlias,MasterBlasterMenu[PO].Alias,1)) {// set Power
+ MasterBlasterMenu[FieldNum].pFunc (&MasterBlaster, (tMasterBlasterOption*)&FieldAlias);
+ } else if (!MasterBlasterMenu[FieldNum].pFunc (&MasterBlaster, MasterBlasterMenu[FieldNum].Options)) {
+ printf ("\nERROR ---> Invalid option. Try again.\n");
+ printf ("mb>");
+ continue;
+ }
+ PrintMasterBlasterMenu(&MasterBlaster);
+
+ // Enable RX test mode
+ if ((!strncmp(&FieldAlias, MasterBlasterMenu[RX].Alias, 1) &&
+ (TestEnabled == MB_NO_TEST)) ||
+ (strncmp(&FieldAlias, MasterBlasterMenu[RX].Alias, 1) &&
+ (TestEnabled == MB_RX_TEST))) {
+ iRet = OCFRXTestMode(uart_fd, &MasterBlaster, SkipRxSlot);
+ if (iRet != -1)
+ TestEnabled = iRet;
+ printf("mb>");
+ continue;
+ } else if ((!strncmp(&FieldAlias, MasterBlasterMenu[RX].Alias, 1)) && (TestEnabled == MB_RX_TEST)) {
+ printf(" rx test is in progress. Press 's' to stop the test\n");
+ printf("mb>");
+ continue;
+ }
+
+ // Enable TX test mode
+ if ((!strncmp(&FieldAlias, MasterBlasterMenu[TX].Alias, 1) &&
+ (TestEnabled == MB_NO_TEST)) ||
+ (strncmp(&FieldAlias, MasterBlasterMenu[TX].Alias, 1) &&
+ (TestEnabled == MB_TX_TEST))) {
+ // Disable sleep mode
+ printf (".");
+ Ok = TRUE;
+ iRet = OCFTXTestMode(uart_fd, &MasterBlaster, SkipRxSlot);
+ if (iRet != -1)
+ TestEnabled = iRet;
+ printf("mb>");
+ continue;
+ } else if ((!strncmp(&FieldAlias, MasterBlasterMenu[TX].Alias, 1)) && TestEnabled == MB_TX_TEST) {
+ printf(" tx test is in progress. Press 's' to stop the test\n");
+ printf("mb>");
+ continue;
+ }
+
+ /* Enable (LE) continuous tx/rx test modes */
+ if (((!strncmp(&FieldAlias, MasterBlasterMenu[EN].Alias, 1)) &&
+ (TestEnabled == MB_NO_TEST)) ||
+ (strncmp(&FieldAlias, MasterBlasterMenu[EN].Alias, 1) &&
+ (TestEnabled == MB_CONT_RX_TEST ||
+ TestEnabled == MB_CONT_TX_TEST ||
+ TestEnabled == MB_LE_RX_TEST ||
+ TestEnabled == MB_LE_TX_TEST))) {
+
+ if (MasterBlaster.ContTxMode == ENABLE) {
+ printf(".");
+ iRet = OCFContTXTestMode(uart_fd, &MasterBlaster);
+ if (iRet != -1) {
+ TestEnabled = iRet;
+ }
+ printf("mb>");
+ continue;
+ } else if (MasterBlaster.ContRxMode == ENABLE) {
+ printf(".");
+ iRet = OCFContRXTestMode(uart_fd, &MasterBlaster);
+ if (iRet != -1) {
+ TestEnabled = iRet;
+ }
+ printf("mb>");
+ continue;
+ }
+
+ // Disable sleep mode
+ printf (".");
+ Ok = TRUE;
+ memset(&buf,0,sizeof(buf));
+ buf[0] = 0;
+ writeHciCommand(uart_fd,HCI_VENDOR_CMD_OGF,OCF_SLEEP_MODE,1,buf);
+ if (buf[6] != 0) {
+ printf("\nError: Sleep mode failed due to reason 0x%X\n",buf[6]);
+ Ok = 0;
+ }
+
+ if (!Ok) {
+ printf ("\nERROR ---> Could not disable sleep mode\n");
+ printf ("mb>");
+ continue;
+ }
+
+ /* LE Rx Mode */
+ if (MasterBlaster.LERxMode == ENABLE) {
+ Ok = SU_LERxTest(uart_fd, MasterBlaster.testCtrl.RxFreq);
+ TestEnabled = MB_LE_RX_TEST;
+ } else if (MasterBlaster.LETxMode == ENABLE) {
+ Ok = SU_LETxTest(uart_fd, MasterBlaster.testCtrl.TxFreq, MasterBlaster.testCtrl.DataLen,
+ MasterBlaster.LETxParms.PktPayload);
+ TestEnabled = MB_LE_TX_TEST;
+ }
+ if (Ok) {
+ printf("Test is in progress. Press 's' to stop the test\n");
+ } else {
+ printf("\nERROR ---> Could not enable master blaster mode\n");
+ TestEnabled = MB_NO_TEST;
+ }
+ printf("mb>");
+ continue;
+ } else if ((!strncmp(&FieldAlias, MasterBlasterMenu[EN].Alias, 1)) && TestEnabled) {
+ printf (" Test mode is in progress. Press 's' to stop the test\n");
+ printf ("mb>");
+ continue;
+ }
+ }
+ else if (i == uart_fd) {
+ bytesRead += read(i, buf, sizeof(buf)-bytesRead);
+ if (buf[0] != 0x02) {
+ printf("OUT OF SYNC\n");
+ iRet = bytesRead;
+ bytesRead = 0;
+ continue;
+ }
+ if (bytesRead < (buf[3] | (buf[4] << 8)) &&
+ bytesRead < (int)sizeof(buf)) {
+ printf("read %d bytes, reading more\n", bytesRead);
+ continue;
+ } else {
+ iRet = bytesRead;
+ bytesRead = 0;
+ }
+
+ iDataSize = iRet - 5;
+ printf("b[0]=%2x\tb[1]=%2x\tb[2]=%2x\tb[3]=%2x\tb[4]=%2x\n",
+ buf[0],buf[1],buf[2],buf[3],buf[4]);
+ printf("first:%x,nbyte:%d, packet:%d, pattern:%x\n",
+ buf[0], iRet, (uint16_t)(buf[3] | (buf[4] << 8)), buf[5]);
+
+ if (buf[0] == 0x2) { // ACL data
+ m_BerTotalBits = m_BerTotalBits + iDataSize * 8;
+ if (iDataSize > MAX_EVENT_SIZE - 9)
+ iDataSize = MAX_EVENT_SIZE - 9;
+ for(j=0,l=0;j<iDataSize;j++,l++) {
+ if (l == m_pPatternlength)
+ l = 0;
+ for(k=0;k<8;k++) {
+ // Austin 0916,
+ // change initial offset from 8 to 5
+ if((m_pattern[l]&(1<<k)) == (buf[5+j]&(1<<k)))
+ m_BerGoodBits++;
+ }
+ printf("byte#:%d, bytet:%x, pattern:%x\n", l, buf[5+j], m_pattern[l]);
+ }
+ }
+ }
+ }
+ }
+ }
+exits_mb:
+
+ return;
+}
+/*
+ static void cmd_gid(int uart_fd, int argc, char **argv){
+ printf("\nFeature not implemented\n");
+ }
+ */
+static const char *wsm_help =
+"Usage:\n"
+"\n wsm [0|1|2|3]\n"
+"\nExample:\n"
+"\twsm 0\t(Scan disabled)\n"
+"\twsm 1\t(Inquiry scan enabled)\n"
+"\twsm 2\t(Page scan enabled)\n"
+"\twsm 3\t(Inquiry and Page scan enabled)\n";
+
+static void cmd_wsm(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ if(argc < 2){
+ printf("\n%s\n",wsm_help);
+ return;
+ }
+ if(atoi(argv[1]) > 3){
+ printf("\nInvalid scan mode :%d\n",atoi(argv[1]));
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = atoi(argv[1]);
+ // OGF_HOST_CTL 0x03
+ // OCF_WRITE_SCAN_ENABLE 0x001A
+ writeHciCommand(uart_fd, 0x03, 0x001A, 1, buf);
+ if(buf[6] != 0){
+ printf("\nWrite scan mode command failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ printf("\nScan Mode set to :%d\n",atoi(argv[1]));
+}
+
+static void dumpHex(UCHAR *buf, int length, int col)
+{
+ int i;
+ for (i = 0; i < length; i++) {
+ printf("0x%02x ", buf[i]);
+ if (((i+1) % col) == 0 && i != 0)
+ printf("\n");
+ }
+ if (((i+1) % col) != 0) printf("\n");
+}
+
+static void ReverseHexString(char *pStr)
+{
+ int i, j;
+ char temp;
+ int len = strlen(pStr);
+
+ for (i = 0; pStr[i] == ' ' || pStr[i] == '\t'; i++);
+
+ if (pStr[i] == '0' && pStr[i+1] == 'x')
+ i += 2;
+
+ for (j = len - 1; i < j - 2; i += 2, j -= 2) {
+ temp = pStr[i];
+ pStr[i] = pStr[j - 1];
+ pStr[j - 1] = temp;
+ temp = pStr[i + 1];
+ pStr[i + 1] = pStr[j];
+ pStr[j] = temp;
+ }
+}
+
+static void GetByteSeq(UCHAR *pDst, UCHAR *pSrc, int Size)
+{
+ UCHAR LowNibble, Nibble = 0;
+ UCHAR *pLastHex;
+ UCHAR *pStr = pSrc;
+
+ while (*pStr == ' ' || *pStr == '\t') pStr++;
+
+ if ((pStr[0] == '0') && (pStr[1] == 'x'))
+ pStr += 2;
+
+ pLastHex = pStr - 1;
+ while (IS_HEX(*(pLastHex + 1)))
+ pLastHex++;
+
+ LowNibble = 0;
+
+ while (Size > 0) {
+ if (pStr <= pLastHex) {
+ Nibble = CONV_HEX_DIGIT_TO_VALUE(*pStr);
+ pStr++;
+ } else {
+ Nibble = 0;
+ }
+
+ if (LowNibble) {
+ *pDst |= (UCHAR)(Nibble & 0x0F);
+ LowNibble = 0;
+ pDst++;
+ Size--;
+ } else {
+ *pDst = (UCHAR)((Nibble << 4) & 0xF0);
+ LowNibble = 1;
+ }
+ }
+}
+
+unsigned int GetUInt(char **ppLine, unsigned int DefaultValue)
+{
+ char *pStr = *ppLine;
+ unsigned int Value = 0;
+
+ // Is it a hex value?
+ if ((*pStr == '0') && (*(pStr+1) == 'x'))
+ {
+ // We have a hex value
+
+ pStr += 2;
+
+ while (IS_HEX(*pStr))
+ {
+ Value = CONV_HEX_DIGIT_TO_VALUE(*pStr) + (Value*16);
+ pStr++;
+ }
+
+ }
+ else if (IS_DIGIT(*pStr))
+ {
+ // We have a decimal value
+ while (IS_DIGIT(*pStr))
+ {
+ Value = CONV_DEC_DIGIT_TO_VALUE(*pStr) + (Value*10);
+ pStr++;
+ }
+ }
+ else
+ {
+ // We don't have a value at all - return default value
+ return DefaultValue;
+ }
+
+ // Update the BtString ptr
+ *ppLine = pStr;
+ return Value;
+}
+
+static const char *mbr_help =
+"Usage:\n"
+"\n mbr <address> <length> \n"
+"\n Example \n"
+"\n mbr 0x00004FFC 10 \n"
+"\n mbr 0x00004FFC 0x10 \n";
+
+static void cmd_mbr(int uart_fd, int argc, char **argv){
+
+ UCHAR buf[MAX_EVENT_SIZE*20];
+
+ if(argc != 3){
+ printf("\n%s\n",mbr_help);
+ return;
+ }
+
+ int length = GetUInt(&(argv[2]),0);
+ int address = GetUInt(&(argv[1]),0);
+
+ if ((address == 0) || (length==0)){
+ return;
+ }
+ memset(&buf,0,MAX_EVENT_SIZE*20);
+ if(!MemBlkRead(uart_fd,address,buf, length)) {
+ printf("\nmemory bulk read command failed\n");
+ return;
+ }
+ printf("\ndata: \n");
+ int i;
+ for(i=0;i < length;i+=4){
+ printf("%08X: ",address+i);
+ printf("%08X",*((int*)(buf+i)));
+ printf("\n");
+ }
+ printf("\n");
+}
+
+static const char *psr_help =
+"Usage:\n"
+"\n psr \n";
+
+static void cmd_psr(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ if(argv) UNUSED(argv);
+ if(argc > 1){
+ printf("\n%s\n",psr_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ LoadPSHeader(buf,PS_RESET,0,0);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS,PS_COMMAND_HEADER+2, buf);
+ if(buf[7] != 0){ /* Check for status */
+ printf("\n PS Reset failed\n");
+ return;
+ }
+ printf("PS reset done\n");
+}
+
+static const char *rpst_help =
+"Usage:\n"
+"\n rpst <tag id> <tag length> \n"
+"\n Example:\n"
+"\n rpst 1 6 \n";
+
+static void cmd_rpst(int uart_fd, int argc, char **argv){
+ int iRet;
+ UCHAR buf[MAX_EVENT_SIZE];
+ int tag_id,tag_len,i,j;
+ if(argc != 3){
+ printf("\n%s\n",rpst_help);
+ return;
+ }
+ memset(&buf,0,MAX_EVENT_SIZE);
+ tag_id = GetUInt(&(argv[1]),0);
+ tag_len = GetUInt(&(argv[2]),0);
+ LoadPSHeader(buf,PS_READ,tag_len,tag_id);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, PS_COMMAND_HEADER, buf);
+ if(buf[6] != 0){
+ printf("\n read PS tag failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ iRet = read(uart_fd,&buf,MAX_EVENT_SIZE);
+ if(iRet < 0){
+ printf("\n read PS tag failed\n");
+ return;
+ }
+ printf("\nTag ID :%X\nTag Length:%X\nTag Data:\n",tag_id,tag_len);
+ for(i=4,j=1;i<iRet;i++,j++){
+ printf("%02X ",buf[i]);
+ if(j%16 == 0)
+ printf("\n");
+ }
+ printf("\n\n");
+}
+static const char *wpst_help =
+"Usage:\n"
+"\n wpst <tag id> <tag length> <tag data>\n"
+"\n Example:\n"
+"\n wpst 1 6 00 03 F4 55 AB 77 \n";
+
+static void cmd_wpst(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int tag_id,tag_len,i;
+ if(argc < 4){
+ printf("\n%s\n",wpst_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ tag_id = GetUInt(&(argv[1]),0);
+ tag_len = GetUInt(&(argv[2]),0);
+ if(argc < tag_len+3){
+ printf("\n Tag Data is less than Tag Length\n");
+ return;
+ }
+ LoadPSHeader(buf,PS_WRITE,tag_len,tag_id);
+ for(i=0;i<tag_len;i++){
+ buf[i+4] = strtol(argv[i+3], NULL, 16);
+ }
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, PS_COMMAND_HEADER + tag_len, buf);
+ if(buf[6] != 0){
+ printf("\n Write PS tag failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+}
+
+static const char *setam_help =
+"Usage:\n"
+"\nsetam <storage medium> <access mode>\n"
+"\nstorage medium: 0-RAM 1-EEPROM\n"
+"\naccess mode: 0-Read-only 1-Write-only 2-Read-Write 3- Disabled\n"
+"\nExample:\n"
+"\nsetam 0 3\n";
+static void cmd_setam(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int medium,mode;
+ if(argc !=3){
+ printf("\n%s\n",setam_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ medium = GetUInt(&(argv[1]),0);
+ mode = GetUInt(&(argv[2]),0);
+ LoadPSHeader(buf,PS_SET_ACCESS_MODE,mode,medium);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, PS_COMMAND_HEADER, buf);
+ if(buf[6] != 0){
+ printf("\nSet Access mode failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ printf("\nAccess mode changed successfully!\n");
+}
+
+static const char *setap_help =
+"Usage:\n"
+"\nsetap <storage medium> <priority>\n"
+"\nstorage medium: 0-RAM 1-EEPROM\n"
+"\npriority: #Highest number corresponds to highest priority\n"
+"\nExample:\n"
+"\nsetap 0 1\n";
+
+static void cmd_setap(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int medium,priority;
+ if(argc !=3){
+ printf("\n%s\n",setap_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ medium = GetUInt(&(argv[1]),0);
+ priority = GetUInt(&(argv[2]),0);
+ LoadPSHeader(buf,PS_SET_ACCESS_MODE,priority,medium);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, PS_COMMAND_HEADER, buf);
+ if(buf[6] != 0){
+ printf("\nSet Access priority failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ printf("\nPriority changed successfully!\n");
+}
+
+static const char *rpsraw_help =
+"Usage:\n"
+"\n rpsraw <offset> <length> \n"
+"\n Example:\n"
+"\n rpsraw 0x012c 10\n";
+static void cmd_rpsraw(int uart_fd, int argc, char **argv){
+ int iRet;
+ UCHAR buf[MAX_EVENT_SIZE];
+ int offset,len,i,j;
+ if(argc != 3){
+ printf("\n%s\n",rpsraw_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ offset = GetUInt(&(argv[1]),0);
+ len = GetUInt(&(argv[2]),0);
+ LoadPSHeader(buf,PS_READ_RAW,len,offset);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, PS_COMMAND_HEADER, buf);
+ if(buf[6] != 0){
+ printf("\n read PS raw failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ iRet = read(uart_fd,&buf,MAX_EVENT_SIZE);
+ if(iRet < 0){
+ printf("\n read PS raw failed\n");
+ return;
+ }
+ printf("\nOffset :%X\nLength:%X\nData:\n",offset,len);
+
+ for(i=4,j=1;i<iRet;i++,j++){
+ printf("%02X ",buf[i]);
+ if(j%16 == 0)
+ printf("\n");
+ }
+ printf("\n\n");
+
+}
+static const char *wpsraw_help =
+"Usage:\n"
+"\n wpsraw <offset> <length> <data>\n"
+"\n Example:\n"
+"\n wpsraw 0x012C 6 00 03 F4 55 AB 77 \n";
+
+static void cmd_wpsraw(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int offset,len,i;
+ if(argc < 4){
+ printf("\n%s\n",wpsraw_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ offset = GetUInt(&(argv[1]),0);
+ len = GetUInt(&(argv[2]),0);
+ if(argc < len+3){
+ printf("\nData is less than Length\n");
+ return;
+ }
+ LoadPSHeader(buf,PS_WRITE_RAW,len,offset);
+ for(i=0;i<len;i++){
+ buf[i+4] = strtol(argv[i+3], NULL, 16);
+ }
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, PS_COMMAND_HEADER + len, buf);
+ if(buf[6] != 0){
+ printf("\n Write PS tag failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+}
+
+static const char *peek_help =
+"\nUsage:"
+"\npeek <address> <width>\n"
+"\nExample:\n"
+"\npeek 0x00004FFC 5\n";
+static void cmd_peek(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int address,width,value;
+ if(argc < 2){
+ printf("\n%s\n",peek_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ address = GetUInt(&(argv[1]),0);
+ if(argc == 3)
+ width = GetUInt(&(argv[2]),0x4);
+ else
+ width = 4;
+
+ buf[0] = (address & 0xFF);
+ buf[1] = ((address >>8) & 0xFF);
+ buf[2] = ((address>>16) & 0xFF);
+ buf[3] = ((address>>24) & 0xFF);
+ buf[4] = (UCHAR)width; //Memory width
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_READ_MEMORY, 5, buf);
+ if(buf[6] != 0){
+ printf("\nRead Memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ value = buf[10];
+ value = ((value << 8) | buf[9]);
+ value = ((value << 8) | buf[8]);
+ value = ((value << 8) | buf[7]);
+ printf("\n0x%X : 0x%X \n",address,value);
+
+}
+
+static const char *cwtx_help =
+"\nUsage:"
+"\ncwtx <channel number>\n"
+"\nExample:\n"
+"\ncwtx 40"
+"\n\n";
+
+static void cmd_cwtx(int uart_fd, int argc, char **argv){
+ int Length = 0;
+ UCHAR buf[MAX_EVENT_SIZE];
+ int channel;
+ if(argc != 2){
+ printf("\n%s\n",cwtx_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ channel = atoi(argv[1]);
+ if(channel > 78 || channel < 0){
+ printf("\nPlease enter channel 0-78!\n");
+ return;
+ }
+ memset(&buf,0,MAX_EVENT_SIZE);
+ // OGF_HOST_CTL 0x03
+ // OCF_RESET 0x0003
+ writeHciCommand(uart_fd, 0x03,0x0003,Length,buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0x80;
+ buf[1] = 0x20;
+ buf[2] = 0x02;
+ buf[3] = 0x00;
+ buf[4] = 0x04;
+ buf[5] = 0xFF;
+ buf[6] = 0x08;
+ buf[7] = 0xC0;
+ buf[8] = 0x00;
+ buf[9] = 0xFF;
+ buf[10] = 0xFF;
+ buf[11] = 0xFF;
+ buf[12] = 0xFF;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ /* hcitool cmd 0x3F 0x06 0x34 0x20 0x02 0x00 0x04 0x88 0xA0 0x00 0x02 0xFF 0xFF 0xFF 0xFF */
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0x34;
+ buf[1] = 0x20;
+ buf[2] = 0x02;
+ buf[3] = 0x00;
+ buf[4] = 0x04;
+ buf[5] = 0x88;
+ buf[6] = 0xA0;
+ buf[7] = 0x00;
+ buf[8] = 0x02;
+ buf[9] = 0xFF;
+ buf[10] = 0xFF;
+ buf[11] = 0xFF;
+ buf[12] = 0xFF;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ /* hcitool cmd 0x3F 0x06 0x28 0x20 0x02 0x00 0x04 0x00 0x90 0x05 0x20 0xFF 0xFF 0xFF 0xFF */
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0x28;
+ buf[1] = 0x20;
+ buf[2] = 0x02;
+ buf[3] = 0x00;
+ buf[4] = 0x04;
+ buf[5] = 0x00;
+ buf[6] = 0x90;
+ buf[7] = 0x05;
+ buf[8] = 0x20;
+ buf[9] = 0xFF;
+ buf[10] = 0xFF;
+ buf[11] = 0xFF;
+ buf[12] = 0xFF;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ /* hcitool cmd 0x3F 0x06 0x7C 0x08 0x02 0x00 0x04 0x01 0x00 0x00 0x4B 0xFF 0xFF 0xFF 0xFF */
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0x7C;
+ buf[1] = 0x08;
+ buf[2] = 0x02;
+ buf[3] = 0x00;
+ buf[4] = 0x04;
+ buf[5] = 0x01;
+ buf[6] = 0x00;
+ buf[7] = 0x00;
+ buf[8] = 0x4B;
+ buf[9] = 0xFF;
+ buf[10] = 0xFF;
+ buf[11] = 0xFF;
+ buf[12] = 0xFF;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+
+ /* hcitool cmd 0x3F 0x06 0x00 0x08 0x02 0x00 0x04 $number 0x00 0x00 0x00 0xFF 0xFF 0xFF 0xFF */
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = 0x00;
+ buf[1] = 0x08;
+ buf[2] = 0x02;
+ buf[3] = 0x00;
+ buf[4] = 0x04;
+ buf[5] = (UCHAR)channel; /* Num */
+ buf[6] = 0x00;
+ buf[7] = 0x00;
+ buf[8] = 0x00;
+ buf[9] = 0xFF;
+ buf[10] = 0xFF;
+ buf[11] = 0xFF;
+ buf[12] = 0xFF;
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF,OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ printf("\nEntering continuous wave Tx on channel %d\n",channel);
+
+}
+
+
+static const char *poke_help =
+"\nUsage:"
+"\npoke <address> <value> <mask> <width>\n"
+"\nExample:\n"
+"\npoke 0x580000 0x22005FF 0xFFFFFFFF 4"
+"\n\n";
+
+static void cmd_poke(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ int address,width,value,mask;
+ if(argc < 2){
+ printf("\n%s\n",poke_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ address = GetUInt(&(argv[1]),0);
+ value = GetUInt(&(argv[2]),0);
+ printf("\nARGC :%d\n",argc);
+ if(argc < 4)
+ mask = 0xffffffff;
+ else
+ mask = GetUInt(&(argv[3]),0xFFFFFFFF);
+ if(argc < 5)
+ width = 4;
+ else
+ width = GetUInt(&(argv[4]),0x4);
+ buf[0] = (address & 0xFF);
+ buf[1] = ((address >>8) & 0xFF);
+ buf[2] = ((address>>16) & 0xFF);
+ buf[3] = ((address>>24) & 0xFF);
+ buf[4] = width; //Memory width
+ buf[5] = (value & 0xFF);
+ buf[6] = ((value >> 8) & 0xFF);
+ buf[7] = ((value >> 16) & 0xFF);
+ buf[8] = ((value >> 24) & 0xFF);
+ buf[9] = (mask & 0xFF);
+ buf[10] = ((mask >>8) & 0xFF);
+ buf[11] = ((mask>>16) & 0xFF);
+ buf[12] = ((mask>>24) & 0xFF);
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_WRITE_MEMORY, 13, buf);
+ if(buf[6] != 0){
+ printf("\nWrite memory address failed due to reason 0x%X\n",buf[6]);
+ return;
+ }
+ printf("\nPoke successful!\n");
+}
+
+
+
+static const char *dump_help =
+"\nUsage:"
+"\ndump audio - Display Audio statistics\n"
+"\ndump dma- Display DMA statistics\n"
+"\ndump dma r - Display and Reset DMA statistics\n"
+"\ndump tpc - Dump TPC tables\n"
+"\nExample:\n"
+"\ndump audio"
+"\ndump dma"
+"\ndump dma r"
+"\ndump tpc"
+"\n";
+
+
+static void cmd_dump(int uart_fd, int argc, char **argv){
+
+ if(argc < 2){
+ printf("\n%s\n",dump_help);
+ return;
+ }
+
+ if(!strncmp(argv[1],"audio",5)){
+ ReadAudioStats(uart_fd);
+ }
+ else if(!strncmp(argv[1],"dma",3)){
+ ReadGlobalDMAStats(uart_fd);
+ if(argc == 3 && !strncmp(argv[2],"r",1)){
+ ResetGlobalDMAStats(uart_fd);
+ }
+ }
+ else if(!strncmp(argv[1],"tpc",3)){
+ ReadTpcTable(uart_fd);
+ }
+ else{
+ printf("\nInvalid option");
+ printf("\n%s\n",dump_help);
+ }
+
+ return;
+}
+
+static const char *rafh_help =
+"\nUsage:"
+"\nrafh <connection handle>\n"
+"\nExample:\n"
+"\nrafh 0x15"
+"\n\n";
+
+static void cmd_rafh(int uart_fd, int argc, char **argv){
+ int iRet;
+ UCHAR buf[MAX_EVENT_SIZE];
+ short int handle;
+
+ if(argc < 2){
+ printf("\n%s\n",rafh_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ handle = GetUInt(&(argv[1]),0);
+ buf[0] = (handle & 0xFF);
+ buf[1] = ((handle >>8) & 0xFF);
+ // OGF_STATUS_PARAM 0x05
+ // OCF_READ_AFH_MAP 0x0006
+ iRet = writeHciCommand(uart_fd, 0x05,0x0006, 2, buf);
+ if(iRet>=MAX_EVENT_SIZE){
+ printf("\nread buffer size overflowed %d\n", iRet);
+ return;
+ }
+ if(buf[6] != 0){
+ printf("\nRead AFH failed due to reason :0x%X\n",buf[6]);
+ return;
+ }
+
+ if(buf[9] == 0)
+ printf(" AFH is disabled");
+ else
+ printf(" AFH is enabled");
+
+ handle = (buf[7] | (buf[8] << 8));
+ printf("\n AFH chaneel classification for handle: 0x%X",handle);
+ int i;
+ printf("\n Channel Classification Map :");
+ for(i=iRet-1; i>9 ; i--){
+ printf("%X",buf[i]);
+ }
+ printf("\n");
+
+}
+
+static const char *safh_help =
+"\nUsage:"
+"\nsafh <host channel classification>\n"
+"\nExample:\n"
+"\nsafh 0x7FFFFFFFFFFFFFFFFFFF"
+"\n\n";
+
+static void cmd_safh(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if(argc < 2){
+ printf("\n%s\n",safh_help);
+ return;
+ }
+ int i,j;
+ i = strlen(argv[1]);
+ if(i > 20 || i < 20){
+ printf("\n%s\n",safh_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ const char *map = argv[1];
+ char byte[3];
+ int data;
+ for (i = 0,j=9; i < 20 ; i+=2,j--) {
+ memcpy(byte,&map[i],2);
+ byte[2] = '\0';
+ data = strtol(byte, NULL, 16);
+ buf[j] = (data & 0xFF);
+ }
+ // OGF_HOST_CTL 0x03
+ // OCF_SET_AFH_CLASSIFICATION 0x003F
+ writeHciCommand(uart_fd, 0x03,0x003F,10, buf);
+ if(buf[6] != 0){
+ printf("\nSet AFH failed due to reason :0x%X\n",buf[6]);
+ return;
+ }
+ printf("\nSet AFH successful!\n");
+}
+
+static const char *wotp_help =
+"\nUsage:"
+"\nwotp <address> <data> [length=1]\n"
+"\nExample:\n"
+"\nwotp 0x15 0x2020 2"
+"\n\n";
+
+static void cmd_wotp(int uart_fd, int argc, char **argv)
+{
+ UINT32 address, length;
+
+ if (argc < 3) {
+ printf("\n%s\n", wotp_help);
+ return;
+ }
+ if (argc == 4)
+ length = GetUInt(&argv[3], 1);
+ else
+ length = 1;
+ address = GetUInt(&argv[1], 0xffffffff);
+ if (address == 0xffffffff) {
+ printf("\n%s\n", wotp_help);
+ return;
+ }
+ ReverseHexString(argv[2]);
+ if (!write_otpRaw(uart_fd, address, length, (UCHAR *)argv[2]))
+ printf("Write to OTP sucessful!\n");
+}
+
+static int write_otpRaw(int uart_fd, int address, int length, UCHAR *data)
+{
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ memset(&buf, 0, MAX_EVENT_SIZE);
+ buf[0] = 0x12;/* write RAW OTP */
+ buf[1] = address & 0xFF;/* PS tag */
+ buf[2] = (address >> 8) & 0xFF;
+ buf[3] = length;/* Entry Size */
+ GetByteSeq(buf + 4, data, 244);/* Entry Data */
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, 244 + PS_COMMAND_HEADER, buf);
+ if (buf[6] != 0) {
+ printf("\nWrite to OTP failed due to reason :0x%X\n", buf[6]);
+ return buf[6];
+ }
+ return 0;
+}
+
+static const char *rotp_help =
+"\nUsage:"
+"\nrotp <address> [length=1]\n"
+"\nExample:\n"
+"\nrotp 0x15 2"
+"\n\n";
+
+static void cmd_rotp(int uart_fd, int argc, char **argv)
+{
+ UINT32 address, length;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if (argc < 2) {
+ printf("\n%s\n", rotp_help);
+ return;
+ }
+ if (argc == 3)
+ length = GetUInt(&argv[2], 1);
+ else
+ length = 1;
+ address = GetUInt(&argv[1], 0xffffffff);
+ if (address == 0xffffffff) {
+ printf("\n%s\n", rotp_help);
+ return;
+ }
+ if (!read_otpRaw(uart_fd, address, length, buf))
+ dumpHex(buf, length, 8);
+}
+
+static int read_otpRaw(int uart_fd, int address, int length, UCHAR *data)
+{
+ int plen;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ memset(&buf, 0, MAX_EVENT_SIZE);
+ buf[0] = 0x11;/* read OTP */
+ buf[1] = address & 0xFF;/* PS tag */
+ buf[2] = (address >> 8) & 0xFF;
+ buf[3] = length;/* Entry Size */
+ buf[4] = 0x00; /* Entry Data */
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_PS, 244 + PS_COMMAND_HEADER, buf);
+ if (buf[6] != 0) {
+ printf("\nRead from OTP failed due to reason :0x%X\n", buf[6]);
+ return buf[6];
+ }
+ do {
+ plen = read(uart_fd, buf, MAX_EVENT_SIZE);
+ if (plen < 0) {
+ perror("Read OTP error\n");
+ exit(EXIT_FAILURE);
+ }
+ } while (buf[HCI_EVENT_HEADER_SIZE] != DEBUG_EVENT_TYPE_PS);
+ memcpy(data, buf + HCI_EVENT_HEADER_SIZE + 1, length);
+ return 0;
+}
+
+static int SU_GetId(int uart_fd, char *pStr, tSU_RevInfo *pRetRevInfo)
+{
+ tSU_RevInfo RevInfo;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ RevInfo.RomVersion = 0x99999999;
+ RevInfo.BuildVersion = 0x99999999;
+ RevInfo.RadioFormat = 0xffff;
+ RevInfo.SysCfgFormat = 0xffff;
+
+ if(pStr) UNUSED(pStr);
+ memset(buf, 0, MAX_EVENT_SIZE);
+
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_READ_VERSION, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nRead version failed due to reason :0x%X\n", buf[6]);
+ return buf[6];
+ }
+ RevInfo.RomVersion = buf[7] + (buf[8]<<8) + (buf[9]<<16) + (buf[10]<<24);
+ RevInfo.BuildVersion = buf[11] + (buf[12]<<8) + (buf[13]<<16) + (buf[14]<<24);
+
+ memcpy(pRetRevInfo, &RevInfo, sizeof(tSU_RevInfo));
+
+ return 0;
+}
+
+/*static const char *otp_help =
+ "\nUsage:"
+ "\notp [dump|imp|exp|test|rpid|wpid|rvid|wvid|rba|wba|hid|cpw|cpw|pwridx|ledo] [file]\n"
+ "\notp wba <BdAddr>:\n"
+ "\n\n";
+ */
+
+static void cmd_otp(int uart_fd, int argc, char **argv)
+{
+ UCHAR buf[512], format[16];
+ FILE *pF = NULL;
+ UINT32 data;
+ int i;
+
+ if (argc == 1 || !strcmp(argv[1], "dump")) {
+ printf("dump:\n");
+ for (i = 0; i < 4; i++) {
+ if (read_otpRaw(uart_fd, 128 * i, 128, &buf[128*i])) {
+ printf("read failed\n");
+ return;
+ }
+ }
+ dumpHex(buf, 512, 8);
+ } else if (!strcmp(argv[1], "test")) {
+ printf("test:\n");
+ printf("To be continue.\n");
+ } else if (!strcmp(argv[1], "imp")) {
+ if (argc < 3 || !*argv[2]) {
+ printf("Import file content into OTP. File name is required\n");
+ return;
+ }
+ printf("Import from %s into OTP:\n", argv[2]);
+ if (!(pF = fopen(argv[2], "rb"))) {
+ printf("Open file failed\n");
+ return;
+ }
+ fread(&buf[0], sizeof(buf), 1, pF);
+ fclose(pF);
+ for (i = 0; i < 512; i += 4) {
+ data = buf[i];
+ data <<= 8;
+ data += buf[i+1];
+ data <<= 8;
+ data += buf[i+2];
+ data <<= 8;
+ data += buf[i+3];
+ snprintf((char *)&format, sizeof(format), "0x%08x", data);
+ if (write_otpRaw(uart_fd, i, 4, (UCHAR *)format)) {
+ printf("Failed!(%d)\n", i);
+ return;
+ }
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "exp")) {
+ for (i = 0; i < 4; i++) {
+ if (read_otpRaw(uart_fd, 128 * i, 128, &buf[128*i])) {
+
+ printf("Failed\n");
+ return;
+ }
+ }
+ if (argc < 3 || !*argv[2] || (!(pF = fopen(argv[2], "wb")))) {
+ /* export the content to the screen */
+ dumpHex(buf, 512, 8);
+ } else {
+ /* export the content to the file */
+ fwrite(&buf[0], sizeof(buf), 1, pF);
+ fclose(pF);
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "ledo")) {
+ int opendrain;
+ tSU_RevInfo RevInfo;
+ memset((void*)&RevInfo, 0, sizeof(tSU_RevInfo));
+ if (SU_GetId(uart_fd, NULL, &RevInfo))
+ return;
+
+ printf("RomVer:%02X.%02X.%02X.%02X \n", (UINT8)((RevInfo.RomVersion >> (8*3)) & 0xff),
+ (UINT8)((RevInfo.RomVersion >> (8*2)) & 0xff),
+ (UINT8)((RevInfo.RomVersion >> 8) & 0xff),
+ (UINT8)(RevInfo.RomVersion & 0xff));
+ if (((UINT8)((RevInfo.RomVersion >> (8*3)) & 0xff) == 0x01) &&
+ ((UINT8)((RevInfo.RomVersion >> (8*2)) & 0xff) == 0x02) &&
+ ((UINT8)((RevInfo.RomVersion >> 8) & 0xff) == 0x02) &&
+ ((UINT8)(RevInfo.RomVersion & 0xff) == 0x00)) {
+ UINT8 LedValue[] = {0xCE, 0xDA, 0x04, 0x0C, 0x58,
+ 0x04, 0x05, 0x06, 0xff, 0x50,
+ 0x40, 0x01, 0x24, 0x08, 0x00,
+ 0x00};
+ for (opendrain = 112; opendrain < 128; opendrain++) {
+ if (write_otpRaw(uart_fd, opendrain, 1, &LedValue[opendrain-112])) {
+ printf("Failed\n");
+ return;
+ }
+ }
+ printf("OTP led opendrain done\n");
+ } else {
+ printf("Wrong RomVer\n");
+ }
+ } else if (!strcmp(argv[1], "cpw")) {
+ UINT32 cin_value = 0, cout_value = 0;
+ char tempStr[8];
+
+ if (argc < 3) {
+ printf("\n Enter cin_value : ");
+ scanf("%d", &cin_value);
+ } else
+ cin_value = GetUInt(&argv[2], 0);
+ if (cin_value > 128) {
+ printf("Invalid cin_value = %d\n", cin_value);
+ return;
+ }
+ if (argc < 4) {
+ printf("\n Enter cout_value : ");
+ scanf("%d", &cout_value);
+ } else
+ cout_value = GetUInt(&argv[3], 0);
+ if (cout_value > 128) {
+ printf("Invalid cout_value = %d\n", cout_value);
+ return;
+ }
+ if (cout_value & 0x01) cin_value += 0x80;
+ snprintf(tempStr, sizeof(tempStr), "0x%02x", cin_value);
+ if (write_otpRaw(uart_fd, 4, 1, (UCHAR *)tempStr)) {
+ printf("CapTune Error\n");
+ return;
+ }
+ snprintf(tempStr, sizeof(tempStr), "0x%02x", cout_value >> 1);
+ if (write_otpRaw(uart_fd, 5, 1, (UCHAR *)tempStr)) {
+ printf("CapTune Error\n");
+ return;
+ }
+ snprintf(tempStr, sizeof(tempStr), "0x40");
+ if (write_otpRaw(uart_fd, 5, 1, (UCHAR *)tempStr)) {
+ printf("CapTune Error\n");
+ return;
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "pwridx")) {
+ char tempStr[8];
+ snprintf(tempStr, sizeof(tempStr), "0x02");
+ if (write_otpRaw(uart_fd, 21, 1, (UCHAR *)tempStr)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "hid")) {
+ char tempStr[8];
+ UINT32 value = 0;
+ if (argc < 3 || !*argv[2]) {
+ printf("\n Enter HID value(0|1) : ");
+ scanf("%d", &value);
+ } else
+ value = GetUInt(&argv[2], 0);
+ if (value != 0 && value != 1) {
+ printf("\n Error: Syntax \"otp hid 0x00|0x01\"\n");
+ return;
+ }
+ snprintf(tempStr, sizeof(tempStr), "0x%02x", value);
+ if (write_otpRaw(uart_fd, 12, 1, (UCHAR *)tempStr)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "wpid")) {
+ UINT32 offset = 134;
+ size_t len = 0;
+ char pid[8] = {0};
+ char *ofs = NULL;
+ printf("\n Enter OTP_PID_OFFSET(default 134) : ");
+ getline(&ofs, &len, stdin);
+ if(!ofs){
+ printf("Error: ofs is NULL !\n");
+ return;
+ }
+ sscanf(ofs, "%d", &offset);
+ if (ofs) free(ofs);
+ memset(pid, 0, sizeof(pid));
+ if (argc < 3 || !*argv[2]) {
+ printf("\n Enter PID : ");
+ fgets((char *)pid, 7, stdin);
+ } else
+ strlcpy((char *)pid, argv[2], 7);
+ len = strlen(pid) - 1;
+ if (pid[len] == '\n' || pid[len] == '\r')
+ pid[len] = 0;
+ ReverseHexString(pid);
+ if (write_otpRaw(uart_fd, offset, 4, (UCHAR *)pid)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "rpid")) {
+ UINT32 offset = 134;
+ size_t len = 0;
+ UCHAR Data[2];
+ char *ofs = NULL;
+ printf("\n Enter OTP_PID_OFFSET(default 134) : ");
+ getline(&ofs, &len, stdin);
+ if(!ofs){
+ printf("Failed! getline return NULL ofs!\n");
+ return;
+ }
+ sscanf(ofs, "%d", &offset);
+ if (ofs) free(ofs);
+ if (read_otpRaw(uart_fd, offset, 2, Data)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("The OTP PID is 0x%02x%02x\n", Data[1], Data[0]);
+ } else if (!strcmp(argv[1], "wvid")) {
+ UINT32 offset = 136;
+ size_t len = 0;
+ char vid[8] = {0};
+ char *ofs = NULL;
+ printf("\n Enter OTP_VID_OFFSET(default 136) : ");
+ getline(&ofs, &len, stdin);
+ if(!ofs){
+ printf("Failed! getline return NULL ofs!\n");
+ return;
+ }
+ sscanf(ofs, "%d", &offset);
+ if (ofs) free(ofs);
+ memset(vid, 0, sizeof(vid));
+ if (argc < 3 || !*argv[2]) {
+ printf("\n Enter VID : ");
+ fgets(vid, 8, stdin);
+ } else
+ strlcpy(vid, argv[2], 7);
+ len = strlen(vid) - 1;
+ if (vid[len] == '\n' || vid[len] == '\r')
+ vid[len] = 0;
+ ReverseHexString(vid);
+ if (write_otpRaw(uart_fd, offset, 2, (UCHAR *)vid)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "rvid")) {
+ UINT32 offset = 136;
+ size_t len = 0;
+ char *ofs = NULL;
+ UCHAR Data[2];
+ printf("\n Enter OTP_VID_OFFSET(default 136) : ");
+ getline(&ofs, &len, stdin);
+ if(!ofs){
+ printf("Failed! getline return NULL ofs!\n");
+ return;
+ }
+ sscanf(ofs, "%d", &offset);
+ if (ofs) free(ofs);
+ if (read_otpRaw(uart_fd, offset, 2, Data)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("The OTP VID is 0x%02x%02x\n", Data[1], Data[0]);
+ } else if (!strcmp(argv[1], "wba")) {
+ UINT32 offset = 128;
+ size_t len = 0;
+ char bdaddr[16] = {0};
+ char *ofs = NULL;
+ printf("\n Enter OTP_BDA_OFFSET(default 128) : ");
+ getline(&ofs, &len, stdin);
+ if(!ofs){
+ printf("Failed! getline return NULL ofs!\n");
+ return;
+ }
+ sscanf(ofs, "%d", &offset);
+ if (ofs) free(ofs);
+ memset(bdaddr, 0, sizeof(bdaddr));
+ if (argc < 3 || !*argv[2]) {
+ printf("\n Enter BDADDR : ");
+ fgets(bdaddr, 16, stdin);
+ } else
+ strlcpy(bdaddr, argv[2], 15);
+ len = strlen(bdaddr) - 1;
+ if (bdaddr[len] == '\n' || bdaddr[len] == '\r')
+ bdaddr[len] = 0;
+ ReverseHexString(bdaddr);
+ if (write_otpRaw(uart_fd, offset, 6, (UCHAR *)bdaddr)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("Done\n");
+ } else if (!strcmp(argv[1], "rba")) {
+ UINT32 offset = 128;
+ size_t len = 0;
+ char *ofs = NULL;
+ UCHAR Data[6];
+ printf("\n Enter OTP_BDA_OFFSET(default 128) : ");
+ getline(&ofs, &len, stdin);
+ if(!ofs){
+ printf("Failed! getline return NULL ofs!\n");
+ return;
+ }
+ sscanf(ofs, "%d", &offset);
+ if (ofs) free(ofs);
+ if (read_otpRaw(uart_fd, offset, 6, Data)) {
+ printf("Failed\n");
+ return;
+ }
+ printf("The OTP BDADDR is 0x%02x%02x%02x%02x%02x%02x\n",
+ Data[5], Data[4], Data[3], Data[2], Data[1], Data[0]);
+ }
+}
+
+
+static void cmd_plb(int uart_fd, int argc, char **argv)
+{
+ int enable;
+ UCHAR buf[MAX_EVENT_SIZE];
+ if (argc < 2)
+ enable = 1;
+ else
+ enable = GetUInt(&argv[1], 1);
+
+ memset(buf, 0, MAX_EVENT_SIZE);
+ buf[0] = 0x09;/* audio commmand opcode */
+ buf[4] = (enable == 0) ? 0x00 : 0x01;/* audio command param */
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_AUDIO_CMD, 8, buf);
+ if (buf[6] != 0) {
+ printf("\nError in setting PCM CODEC loopback :0x%X\n", buf[6]);
+ return;
+ }
+ printf("\nPCM CODEC loopback is %s\n", (enable == 0) ? "OFF" : "ON");
+
+}
+
+
+static void cmd_psw(int uart_fd, int argc, char **argv)
+{
+ int enable, freq;
+ UCHAR buf[MAX_EVENT_SIZE];
+ if (argc < 2) {
+ enable = 1;
+ freq = 440;
+ }
+ else if (argc < 3) {
+ printf("aa\n");
+ enable = GetUInt(&argv[1], 1);
+ freq = 440;
+ } else {
+ enable = GetUInt(&argv[1], 1);
+ freq = GetUInt(&argv[2], 440);
+ }
+ if (freq > 3700) {
+ printf("Invalid frequency. It should be in the range of 0 to 3700\n");
+ return;
+ }
+
+ memset(buf, 0, MAX_EVENT_SIZE);
+ buf[0] = 0x0a;/* audio command opcode */
+ buf[4] = (enable == 0) ? 0x00 : 0x01;/* audio command param */
+ buf[5] = 0x00;
+ buf[6] = freq & 0xff;
+ buf[7] = (freq >> 8) & 0xff;
+
+ writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, OCF_AUDIO_CMD, 8, buf);
+ if (buf[6] != 0) {
+ printf("\nError in running PCM sine wave playback :0x%X\n", buf[6]);
+
+ return;
+ }
+ printf("PCM CODEC PCM sine wave playback is %s\n", (enable == 0) ? "OFF" : "ON");
+
+}
+
+static const char *lert_help=
+"\nUsage:"
+"\nlert <rx_channel>\n"
+"\nlert 30 \n"
+"\n\n";
+
+static void cmd_lert(int uart_fd, int argc, char **argv)
+{
+ UCHAR channel;
+ if (argc < 2) {
+ printf("\n%s\n", lert_help);
+ return;
+ }
+ channel = (UCHAR)GetUInt(&argv[1], 0);
+
+ SU_LERxTest(uart_fd, channel);
+
+}
+
+static BOOL SU_LERxTest(int uart_fd, UCHAR channel)
+{
+ UCHAR buf[MAX_EVENT_SIZE];
+ int channel_val = channel;
+ if (channel_val < MB_MIN_FREQUENCY_LE || channel_val > MB_MAX_FREQUENCY_LE) {
+ printf("Invalid rx channel_val. It should be in the range of %d to %d\n",
+ MB_MIN_FREQUENCY_LE, MB_MAX_FREQUENCY_LE);
+ return FALSE;
+ }
+
+ memset(buf, 0, MAX_EVENT_SIZE);
+ buf[0] = channel_val;/* rx_channel */
+ // OGF_LE_CTL 0x08
+ // OCF_LE_RECEIVER_TEST 0x001D
+ writeHciCommand(uart_fd, 0x08, 0x001D, 1, buf);
+ if (buf[6] != 0) {
+ printf("\nError in putting the device into LE RX mode\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static const char *lett_help=
+"\nUsage:"
+"\nlett <rx_channel> <length> <packet_payload>\n"
+"\nlett 30 30 5\n"
+"\n\n";
+
+static void cmd_lett(int uart_fd, int argc, char **argv)
+{
+ UCHAR channel, length, payload;
+ if (argc < 4) {
+ printf("\n%s\n", lett_help);
+ return;
+ }
+ channel = (UCHAR)GetUInt(&argv[1], 0);
+ length = (UCHAR)GetUInt(&argv[2], 0);
+ payload = (UCHAR)GetUInt(&argv[3], 0);
+
+
+ SU_LETxTest(uart_fd, channel, length, payload);
+
+}
+
+static BOOL SU_LETxTest(int uart_fd, UCHAR channel, UCHAR length, UCHAR payload)
+{
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ int channel_val = channel;
+ int length_val = length;
+ if (channel_val < MB_MIN_FREQUENCY_LE || channel_val > MB_MAX_FREQUENCY_LE) {
+ printf("Invalid tx channel. It should be in the range of %d to %d\n",
+ MB_MIN_FREQUENCY_LE, MB_MAX_FREQUENCY_LE);
+ return FALSE;
+ }
+ if (length_val < MB_MIN_DATALEN_LE || length_val > MB_MAX_DATALEN_LE) {
+ printf("Invalid data length_val. It should be in the range of %d to %d\n",
+ MB_MIN_DATALEN_LE, MB_MAX_DATALEN_LE);
+ return FALSE;
+ }
+ if (payload > 7) {
+ printf("Invalid packet payload. It should be in the range of 0 to 7\n");
+ return FALSE;
+ }
+
+ memset(buf, 0, MAX_EVENT_SIZE);
+ buf[0] = channel_val;/* tx_channel */
+ buf[1] = length_val;/* length of test data */
+ buf[2] = payload;/* packet payload */
+ // OGF_LE_CTL 0x08
+ // OCF_LE_TRANSMITTER_TEST 0x001E
+ writeHciCommand(uart_fd, 0x08, 0x001E, 3, buf);
+ if (buf[6] != 0) {
+ printf("\nError in putting the device into LE TX mode\n");
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static void cmd_lete(int uart_fd, int argc, char **argv)
+{
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ UNUSED(argc);
+ if(argv) UNUSED(argv);
+ memset(buf, 0, MAX_EVENT_SIZE);
+ // OGF_LE_CTL 0x08
+ // OCF_LE_TEST_END 0x001F
+ writeHciCommand(uart_fd, 0x08, 0x001F, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nError in ending LE test\n");
+ return;
+ }
+ printf("Number of packets = %d\n", buf[7] | (buf[8] << 8));
+
+}
+
+#if 0
+static const char *tputs_help =
+"\nUsage:"
+"\ntput-s [BD_Addr] [Judgment value] Logfile times"
+"\ntput-s 11:22:33:44:55:66 150 log.txt 10"
+"\n\n";
+
+
+static void CalculateTput(int uart_fd, UINT16 hci_handle, char *filename, double threshold, int tx_size)
+{
+ time_t start, checkbreak;
+ UCHAR buf[1009];
+ FILE *fp = NULL;
+ int aclnum = 8;
+ int retval;
+ unsigned long sentnum = 0;
+ double TimeResult = 0;
+ fd_set rfds;
+ struct timeval tv1, tv2, timeout;
+ unsigned long long start_utime, end_utime, time_diff;
+ unsigned long long throughput;
+
+ start = time(NULL);
+ gettimeofday(&tv1, NULL);
+ start_utime = tv1.tv_sec*1000000 + tv1.tv_usec;
+ while (sentnum < 1024 * tx_size) {
+ while (aclnum > 0) {
+ aclnum--;
+ buf[0] = 0x02; // HCI_ACLDATA_PKT 0x02
+ /* ACL packet header */
+ buf[1] = hci_handle & 0xFF;
+ buf[2] = ((hci_handle >> 8) & 0x0E);
+ buf[3] = 1004 & 0xff;
+ buf[4] = (1004 >> 8) & 0xff;
+ /* L2CAP packet header */
+ buf[5] = 1000 & 0xff;
+ buf[6] = (1000 >> 8) & 0xff;
+ buf[7] = 0x40 & 0xff;
+ buf[8] = 0;
+
+ memset(buf+9, sentnum++, 1000);
+ while (write(uart_fd, (const void *)buf, 1009) < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ perror("HCI send packet failed");
+ exit(EXIT_FAILURE);
+ }
+ }
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ FD_ZERO(&rfds);
+ FD_SET(uart_fd, &rfds);
+ retval = select(uart_fd+1, &rfds, NULL, NULL, &timeout);
+ if (retval == -1) {
+ perror("select()");
+ exit(EXIT_FAILURE);
+ } else if (retval) {
+ /* Data is available now */
+ ssize_t plen;
+ UCHAR buffer[64];
+ int i;
+ plen = read(uart_fd, buffer, 64);
+ if (plen < 0) {
+ perror("HCI read buffer failed");
+ exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < buffer[HCI_EVENT_HEADER_SIZE]; i++)
+ aclnum += (buffer[HCI_EVENT_HEADER_SIZE+(i+1)*2+1] | (buffer[HCI_EVENT_HEADER_SIZE+(i+1)*2+2] << 8));
+ }
+ checkbreak = time(NULL);
+ if ((checkbreak - start) >= 300) break;
+ }
+ gettimeofday(&tv2, NULL);
+ end_utime = tv2.tv_sec*1000000 + tv2.tv_usec;
+ time_diff = end_utime - start_utime;
+ throughput = time_diff/1000;
+ throughput = (sentnum * 1000)/throughput;
+ printf("Transfer Completed! throughput [%0d KB/s]", (int)throughput);
+ printf(" result [%s]\n", threshold > throughput ? " Fail " : " Pass ");
+ if (filename && *filename)
+ fp = fopen(filename, "at+");
+ if (fp) {
+ fprintf(fp, "Transfer Completed! throughput [%.0f KB/s]", TimeResult);
+ fprintf(fp, " result [%s]\n", threshold > TimeResult ? " Fail " : " Pass ");
+ fclose(fp);
+ }
+}
+#endif
+
+static void cmd_tputs(int uart_fd, int argc, char **argv)
+{
+ if(argv) UNUSED(argv);
+ UNUSED(argc);
+ UNUSED(uart_fd);
+
+#if 0
+ int j, iRet, loop = 1, tx_test_size = 1;
+ UINT16 Ps_EntrySize = 0;
+ UINT16 hci_handle = 0;
+ double threshold = 0.0;
+ char *filename = NULL;
+ struct sigaction sa;
+ FILE *fp = NULL;
+ bdaddr_t bdaddr;
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR Ps_Data[MAX_EVENT_SIZE];
+ UINT16 *pPs_Data;
+ BOOL Ok = FALSE;
+ char timeString[9] = {0};
+ char dateString[15] = {0};
+ time_t current_time;
+ struct tm *time_info;
+ tSU_RevInfo RevInfo;
+
+ if (argc < 3) {
+ printf("\n%s\n", tputs_help);
+ return;
+ }
+
+ if (str2ba(argv[1],&bdaddr)) {
+ printf("\nPlease input valid bdaddr.\n");
+ return;
+ }
+ threshold = atof(argv[2]);
+ if (!threshold) {
+ printf("\nPlease input valid throughput threshold.\n");
+ return;
+ }
+ if (argc > 3)
+ filename = strdup(argv[3]);
+ if (argc > 4)
+ loop = GetUInt(&argv[4], 1);
+ if (argc > 5)
+ tx_test_size = GetUInt(&argv[5],1);
+
+ CtrlCBreak = FALSE;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ PSInit(uart_fd);
+ memset(buf, 0, sizeof(buf));
+ iRet = writeHciCommand(uart_fd, OGF_HOST_CTL, OCF_RESET, 0, buf);
+ if (buf[6] != 0) {
+ printf("Error: HCI RESET failed.\n");
+ return;
+ }
+ sleep(1);
+ for (j = 0; j < loop; j++) {
+ int i = 0;
+ if (!j) sleep(1);
+ printf("\n-----------------------------------");
+ printf("\nTimes %d/%d\n", j + 1, loop);
+
+ time(¤t_time);
+ time_info = localtime(¤t_time);
+ strftime(timeString, sizeof(timeString), "%H %M %S", time_info);
+ strftime(dateString, sizeof(dateString), "%b %d %Y", time_info);
+ if (j == 0) {
+ if (filename && *filename)
+ fp = fopen(filename, "at+");
+ if (fp != NULL)
+ fprintf(fp, "\n[%s %s] \nCMD : TPUT-S %s %f %s %d\n",
+ dateString, timeString, argv[1], threshold, filename, loop);
+ /* SFLAGS FW */
+ Ok = PSOperations(uart_fd, PS_GET_LENGTH, PSTAG_RF_TEST_BLOCK_START, (UINT32 *)&Ps_EntrySize);
+ if (Ok) {
+ Ps_Data[0] = Ps_EntrySize & 0xff;
+ Ps_Data[1] = (Ps_EntrySize >> 8) & 0xff;
+ Ok = PSOperations(uart_fd, PS_READ, PSTAG_RF_TEST_BLOCK_START, (UINT32 *)&Ps_Data);
+ if (Ok) {
+ pPs_Data = (UINT16 *)&Ps_Data[0];
+ if (*pPs_Data == BT_SOC_INIT_TOOL_START_MAGIC_WORD) {
+ RevInfo.RadioFormat = *(pPs_Data + 1);
+ RevInfo.RadioContent = *(pPs_Data + 2);
+ }
+ }
+ }
+
+ /* Get syscfg info */
+ Ok = PSOperations(uart_fd, PS_GET_LENGTH, PSTAG_SYSCFG_PARAM_TABLE0, (UINT32 *)&Ps_EntrySize);
+ if (Ok) {
+ Ps_Data[0] = Ps_EntrySize & 0xff;
+ Ps_Data[1] = (Ps_EntrySize >> 8) & 0xff;
+ Ok = PSOperations(uart_fd, PS_READ, PSTAG_SYSCFG_PARAM_TABLE0, (UINT32 *)&Ps_Data);
+ if (Ok) {
+ pPs_Data = (UINT16 *)&Ps_Data[0];
+ if (*pPs_Data == 0xC1C1) {
+ RevInfo.SysCfgFormat = *(pPs_Data + 1);
+ RevInfo.SysCfgContent = *(pPs_Data + 2);
+ }
+
+ }
+ }
+
+ if (RevInfo.SysCfgFormat != 0xff) {
+ printf("SysCfg - Format: %d.%d\n",((RevInfo.SysCfgFormat >> 4) & 0xfff), (RevInfo.SysCfgFormat & 0xf));
+ printf(" Content: %d\n", RevInfo.SysCfgContent);
+ if (fp) {
+ fprintf(fp, "SysCfg - Format: %d.%d\n",((RevInfo.SysCfgFormat >> 4) & 0xfff),
+ (RevInfo.SysCfgFormat & 0xf));
+ fprintf(fp, " Content: %d\n", RevInfo.SysCfgContent);
+ }
+ } else {
+ printf("SysCfg - N/A\n");
+ if(fp)
+ fprintf(fp, "SysCfg - N/A\n");
+ }
+
+ /* bd addr */
+ memset(&buf, 0, sizeof(buf));
+ iRet = writeHciCommand(uart_fd, OGF_INFO_PARAM, HCI_CMD_OCF_READ_BD_ADDR, 0, buf);
+ if (buf[6] != 0) {
+ printf("\nCould not read the BD_ADDR (time out)\n");
+ } else {
+ char temp[16] = {0};
+ memset(temp, 0, sizeof(temp));
+ snprintf(temp, sizeof(temp), "%02X%02X%02X%02X%02X%02X", buf[iRet-1], buf[iRet-2],
+ buf[iRet-3], buf[iRet-4], buf[iRet-5], buf[iRet-6]);
+ printf("\nLocal BDAddress : 0x%s\n", temp);
+ if (fp)
+ fprintf(fp, "Local BDAddress : 0x%s\n", temp);
+ }
+
+ if (fp) {
+ fclose(fp);
+ fp = NULL;
+ }
+ }
+ printf("Sending packages to 0x%s\n", argv[1]);
+ while (i++ < 3) {
+ iRet = hci_create_connection(uart_fd, &bdaddr, 0xCC18, 0, 0, &hci_handle, 0);
+ if (!iRet || CtrlCBreak) break;
+ }
+
+ if (iRet) {
+ if (filename && *filename) {
+ fp = fopen(filename, "at+");
+ if (fp) {
+ fprintf(fp, "Transfer Failed! \n");
+ fclose(fp);
+ fp = NULL;
+ }
+ }
+ printf("Transfer Failed! \n");
+ CtrlCBreak = TRUE;
+
+ return;
+ }
+ CalculateTput(uart_fd, hci_handle, filename, threshold, tx_test_size);
+
+ hci_disconnect(uart_fd, hci_handle, 0, 30);
+
+ if (CtrlCBreak) break;
+ }
+ CtrlCBreak = TRUE;
+#endif
+}
+
+static void cmd_tputr(int uart_fd, int argc, char **argv)
+{
+ ssize_t plen;
+ UINT16 hci_handle = 0;
+ UCHAR buf[MAX_EVENT_SIZE];
+ struct sigaction sa;
+
+ UNUSED(argc);
+ if(argv) UNUSED(argv);
+ CtrlCBreak = FALSE;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ memset(buf, 0, sizeof(buf));
+ // OGF_HOST_CTL 0x03
+ // OCF_RESET 0x0003
+ writeHciCommand(uart_fd, 0x03, 0x0003, 0, buf);
+ if (buf[6] != 0) {
+ printf("Error: HCI RESET failed.\n");
+ return;
+ }
+ sleep(1);
+ memset(buf, 0, sizeof(buf));
+ buf[0] = 0x02;
+ // OGF_HOST_CTL 0x03
+ // OCF_WRITE_SCAN_ENABLE 0x001A
+ writeHciCommand(uart_fd, 0x03, 0x001A, 1, buf);
+ if (buf[6] != 0) {
+ printf("Error: Write scan failed\n");
+ return;
+ }
+ printf("Start listening ...\n");
+ do {
+ plen = read(uart_fd, buf, MAX_EVENT_SIZE);
+ if (plen < 0) {
+ printf("reading failed...\n");
+ if (errno == EAGAIN || errno == EINTR) continue;
+ else {
+ perror("HCI read failed");
+ exit(EXIT_FAILURE);
+ }
+ }
+ // EVT_CONN_REQUEST 0x04
+ if (buf[1] == 0x04) {
+ int i, j;
+ ssize_t plen = 0;
+ printf("Connection come in\n");
+ for (i = 0, j = 3; i < BD_ADDR_SIZE; i++, j++)
+ buf[i] = buf[j];
+ buf[BD_ADDR_SIZE] = 0x01;
+ // OGF_LINK_CTL 0x01
+ // OCF_ACCEPT_CONN_REQ 0x0009
+ if (hci_send_cmd(uart_fd, 0x01, 0x0009, 7, buf)) {
+ printf("Accept connection error\n");
+ return;
+ }
+ do {
+ plen = read(uart_fd, buf, MAX_EVENT_SIZE);
+ if (plen < 0) {
+ perror("Read failed");
+ exit(EXIT_FAILURE);
+ }
+ // EVT_CONN_COMPLETE 0x03
+ } while (buf[1] != 0x03);
+ if (buf[3] == 0) {
+ printf("Connection up\n");
+ } else {
+ printf("Connection failed\n");
+ }
+ hci_handle = (buf[4] | (buf[5] << 8)) & 0x0EFF;
+ // EVT_DISCONN_COMPLETE 0x05
+ } else if (buf[1] == 0x05) {
+ UINT16 hdl = buf[4] | (buf[5] << 8);
+ printf("Disconnect...\n");
+ if (hdl == hci_handle) {
+ break;
+ }
+ } else if (CtrlCBreak) {
+ printf("CtrlBreak...\n");
+ break;
+ }
+ } while (plen >= 0);
+ CtrlCBreak = TRUE;
+
+}
+
+int sock_recv(int sockid, unsigned char *buf, int buflen)
+{
+ int recvbytes;
+ recvbytes = recv(sockid, buf, buflen, 0);
+ if (recvbytes == 0) {
+ printf("Connection close!? zero bytes received\n");
+ return -1;
+ } else if (recvbytes > 0) {
+ return recvbytes;
+ }
+ return -1;
+}
+
+int sock_send(int sockid, unsigned char *buf, int bytes)
+{
+ int cnt;
+ unsigned char* bufpos = buf;
+ while (bytes) {
+ cnt = write(sockid, bufpos, bytes);
+ if (cnt != bytes)
+ printf("cnt:%d,bytes:%d\n",cnt, bytes);
+
+ if (!cnt) {
+ break;
+ }
+ if (cnt == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ return -1;
+ }
+ }
+
+ bytes -= cnt;
+ bufpos += cnt;
+ }
+ return (bufpos - buf);
+}
+
+static void cmd_btagent(int uart_fd, int argc, char **argv)
+{
+ int i, j, k, l, iRet, rx_enable, iDataSize;
+ uint32_t m_BerTotalBits, m_BerGoodBits;
+ uint8_t m_pattern[16];
+ uint16_t m_pPatternlength;
+ int port = BT_PORT;
+ struct sigaction sa;
+ unsigned char buf[1024];
+ struct timeval timeout;
+
+ /* master file descriptor list */
+ fd_set master;
+ fd_set read_fds;
+
+ /* server address */
+ struct sockaddr_in serveraddr;
+
+ int fdmax;
+
+ /* listening socket descriptor */
+ int listener = -1;
+
+ /* newly accept()ed socket descriptor */
+ int newfd = -1;
+
+ int nbytes;
+
+ /* for setsockopt() SO_REUSEADDR, below */
+ int yes = 1;
+
+ socklen_t addrlen;
+
+ if (argc > 1)
+ port = atoi(argv[1]);
+ if (port == 0)
+ port = BT_PORT;
+ else if (port < 0 || port >65534) {
+ perror("\nERROR: Invalid port number\n");
+ return;
+ }
+
+ CtrlCBreak = FALSE;
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = sig_term;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+
+ /* clear the master and temp sets */
+ FD_ZERO(&master);
+ FD_ZERO(&read_fds);
+
+ /* get the listener */
+ if((listener = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+ perror("Server-socket() error lol!");
+ return;
+ }
+
+ if(setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(int)) == -1) {
+ perror("Server-setsockopt() error lol!");
+ close(listener);
+ return;
+ }
+
+ if(setsockopt(listener, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(int)) == -1) {
+ perror("Server-setsockopt() error TCP_NODELAY\n");
+ close(listener);
+ return;
+ }
+
+ /* bind */
+ serveraddr.sin_family = AF_INET;
+ serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ serveraddr.sin_port = htons(port);
+ memset(&(serveraddr.sin_zero), 0, 8);
+
+ if(bind(listener, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1) {
+ perror("Server-bind() error lol!");
+ close(listener);
+ return;
+ }
+
+ /* listen */
+ if(listen(listener, 10) == -1) {
+ perror("Server-listen() error lol!");
+ close(listener);
+ return;
+ }
+
+ /* add the listener to the master set */
+ FD_SET(listener, &master);
+
+ /* add hci handler to the master set */
+ FD_SET(uart_fd, &master);
+
+ FD_SET(0, &master);
+ /* keep track of the biggest file descriptor */
+ fdmax = listener;
+ if (uart_fd > listener) fdmax = uart_fd;
+
+ printf("Start BtAgent, press 'q' to exit.\n");
+
+ rx_enable = 0;
+ m_BerGoodBits = 0;
+ m_BerTotalBits = 0;
+ m_pattern[0] = 0x0f;
+ m_pPatternlength = 1;
+
+ while (1) {
+ read_fds = master;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ iRet = select(fdmax+1, &read_fds, NULL, NULL, &timeout);
+ if (iRet == -1) {
+ perror("Server-select() error lol!");
+ if (newfd > 0) close(newfd);
+ close(listener);
+ goto exits;
+ }
+ if (CtrlCBreak) break;
+ if (iRet == 0) continue;
+
+ /*run through the existing connections looking for data to be read*/
+ for(i = 0; i <= fdmax; i++) {
+ if(FD_ISSET(i, &read_fds)) {
+
+ if(i == 0) {
+ printf("Shutting down btagent\n");
+ iRet = getchar();
+ if (iRet == 'q') goto exits;
+ continue;
+ }
+
+ if(i == listener) {
+ /* handle new connections */
+ addrlen = sizeof(struct sockaddr_in);
+ if((newfd = accept(listener, (struct sockaddr *)&serveraddr, &addrlen)) == -1) {
+ perror("Server-accept() error lol!");
+ goto exits;
+ }
+ else {
+ printf("Server-accept() is OK...%d\n",newfd);
+ FD_SET(newfd, &master); /* add to master set */
+ if(newfd > fdmax)
+ fdmax = newfd;
+ }
+ }
+ else if (i == newfd) {
+ /* handle data from a client */
+ if((nbytes = sock_recv(i, buf, sizeof(buf))) < 0) {
+ /* got error or connection closed by client */
+ close(i);
+ /* remove from master set */
+ FD_CLR(i, &master);
+ }
+ else {
+
+ for (j=0; j<nbytes; j++)
+ printf("%x ",buf[j]);
+ printf("\n");
+ if (buf[0] == 0x7) { // BTAGENT_CMD_EVENT
+ if (buf[3] == 0x01) { // BTAGENT_CMD_EVENT_GETBER
+ buf[11] = (m_BerTotalBits & 0xff000000) >> 24;
+ buf[10] = (m_BerTotalBits & 0xff0000) >> 16;
+ buf[9] = (m_BerTotalBits & 0xff00) >> 8;
+ buf[8] = m_BerTotalBits & 0xff;
+ buf[7] = (m_BerGoodBits & 0xff000000) >> 24;
+ buf[6] = (m_BerGoodBits & 0xff0000) >> 16;
+ buf[5] = (m_BerGoodBits & 0xff00) >> 8;
+ buf[4] = m_BerGoodBits & 0xff;
+ buf[3] = 1;// BTAGENT_CMD_EVENT_GETBER
+ buf[2] = 0;
+ buf[1] = 9;
+ buf[0] = 7;
+ sock_send(newfd, buf, 9+3);
+ usleep(2000);
+ }
+ else if (buf[3] == 0x02) {// BTAGENT_CMD_EVENT_PATTERN
+ m_pPatternlength = (uint16_t)(buf[1] | (buf[2] << 8));
+ m_pPatternlength --;
+ if (m_pPatternlength > 16) m_pPatternlength = 16;
+ memcpy(m_pattern,&buf[4],m_pPatternlength);
+ printf("PatternLength:%d,%x\n",m_pPatternlength,buf[4]);
+ }
+ continue;
+ }
+
+ if (rx_enable == 1) {
+ if ((buf[4] == 0x03) && (buf[5] == 0x0c))
+ rx_enable = 0;
+ }
+ write(uart_fd, &buf[3], nbytes - 3);
+ }
+ }
+ else if (i == uart_fd) {
+ nbytes = read(uart_fd, &buf[3], sizeof(buf) - 3);
+ iDataSize = nbytes - 6;
+ // printf("nbyte:%d, packet:%d, pattern:%x\n",nbytes, (uint16_t)(buf[6] | (buf[7] << 8)), buf[8]);
+ if (buf[3] == 0x2) { // ACL data
+ if (rx_enable) {
+ m_BerTotalBits = m_BerTotalBits + iDataSize * 8;
+ for(j=0,l=0;j<iDataSize;j++,l++) {
+ if (l == m_pPatternlength) l = 0;
+ for(k=0;k<8;k++){
+ if((m_pattern[l]&(1<<k)) == (buf[8+j]&(1<<k)))
+ m_BerGoodBits++;
+ }
+ }
+ }
+ }
+ else {
+ if ((buf[7] == 0x5b) && (buf[8] == 0xfc)) {// Rx start CMD's event
+ rx_enable = 1;
+ m_BerTotalBits = 0;
+ m_BerGoodBits = 0;
+ }
+ buf[2] = 0;
+ buf[1] = (uint16_t)nbytes;
+ buf[0] = 3;
+ if (newfd > 0) {
+ sock_send(newfd, buf, nbytes+3);
+ usleep(2000);
+ }
+ }
+ }
+ }
+ }
+ }
+exits:
+
+ if (listener > 0) close(listener);
+ if (newfd > 0) close(newfd);
+ printf("Total:%d,Good:%d\n",m_BerTotalBits, m_BerGoodBits);
+}
+
+/* SMD cmds */
+static const char *hciinq_help =
+"Usage:\n"
+"\n hciinq\n";
+
+static void cmd_hciinq(int uart_fd, int argc, char **argv){
+ int iRet, i;
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+ unsigned long val32;
+
+ if(argc < 2) {
+ printf("\n%s\n",hciinq_help);
+ return;
+ }
+
+ printf( "inq command ++ argc = %d argv = %s %s %s %s %s \n", argc,argv[1],argv[2] ,argv[3] ,argv[4] ,argv[5] );
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ // INQUIRY_CP_SIZE 5
+ for (i = 1; i <= 5; i++)
+ {
+ UCHAR *tmp;
+ val32 = strtol ((char*)argv[i], NULL, 16);
+ tmp = ((unsigned char*)&val32);
+ buf[i-1] = *tmp;
+ }
+
+ // OGF_LINK_CTL 0x01
+ // OCF_INQUIRY 0x0001
+ // INQUIRY_CP_SIZE 5
+ iRet = hci_send_cmd( uart_fd, 0x01, 0x0001, 5, buf);
+
+ printf("\nINQUIRY: \n");
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!iRet)
+ read_incoming_events(uart_fd, resultBuf, 0);
+
+ printf("\n");
+}
+
+static const char *hciinqcnl_help =
+"Usage:\n"
+"\n hciinqcnl\n";
+
+static void cmd_hciinqcnl(int uart_fd, int argc, char **argv){
+ UCHAR buf[MAX_EVENT_SIZE];
+ if(argv) UNUSED(argv);
+ if(argc > 1){
+ printf("\n%s\n",hciinqcnl_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ // OGF_LINK_CTL 0x01
+ // OCF_INQUIRY_CANCEL 0x0002
+ writeHciCommand(uart_fd, 0x01, 0x0002, 0, buf);
+ if(buf[6] != 0){
+ printf("\nError: Inquiry cancel failed due to the reason 0X%X\n", buf[6]);
+ return;
+ }
+ printf("\nINQUIRY CANCEL\n");
+}
+
+static const char *hcisetevtflt_help =
+"Usage:\n"
+"\n hcisetevtflt\n";
+
+static void cmd_hcisetevtflt(int uart_fd, int argc, char **argv){
+ int i;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if(argc < 2){
+ printf("\n%s\n",hcisetevtflt_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ // SET_EVENT_FLT_CP_SIZE 2
+ for (i = 0; i < 2; i++)
+ buf[i] = atoi(argv[i + 1]);
+ // OGF_HOST_CTL 0x03
+ // OCF_SET_EVENT_FLT 0x0005
+ writeHciCommand(uart_fd, 0x03, 0x0005,
+ 2, buf);
+ if(buf[6] != 0){
+ printf("\nError: Set Event Filter failed due to the reason 0X%X\n", buf[6]);
+ return;
+ }
+ printf("\nSet Event Filter\n");
+}
+
+static const char *pinconntest_help =
+"Usage:\n"
+"\n pinconntest\n";
+
+static void cmd_pinconntest(int uart_fd, int argc, char **argv){
+ int iRet;
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+ unsigned long val32;
+ if(argc < 2){
+ printf("\n%s\n",pinconntest_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ UCHAR *tmp ;
+ val32 = strtol ((char*)argv[1], NULL, 16);
+ tmp = ((unsigned char*)&val32);
+ buf[0] =*tmp;
+ iRet = hci_send_cmd(uart_fd, HCI_VENDOR_CMD_OGF, 0x0C, 1, buf);
+
+ printf("\nPIN CONNECTIVITY TEST: \n");
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!iRet)
+ read_incoming_events(uart_fd, resultBuf, 0);
+
+ printf("\n");
+}
+
+static const char *conntest_help =
+"Usage:\n"
+"\n conn < bdaddress >\n";
+
+static void cmd_createconnection(int uart_fd, int argc, char **argv){
+ int iRet, i,j;
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+ bdaddr_t bdaddr;
+ uint16_t clk_offset;
+ uint8_t role, pscan_rep_mode;
+ unsigned char ptype[2] = {0x18 , 0xcc};
+
+ pscan_rep_mode = 0; // R0
+ clk_offset = 0;
+ role = 0x01; // Master/Slave
+
+ if(argc < 2){
+ printf("\n%s\n",conntest_help);
+ return;
+ }
+ str2ba(argv[1],&bdaddr);
+ if((strlen(argv[1]) < 17)||(strlen(argv[1]) > 17)){
+ printf("\nInvalid BD address : %s\n",argv[1]);
+ printf("\n%s\n",wba_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+
+ for(i= 0,j=0; i< BD_ADDR_SIZE;i++,j++){
+ buf[j] = bdaddr.b[i];
+ }
+ buf[6] = ptype[0];
+ buf[7] = ptype[1];
+ buf[8] = pscan_rep_mode;
+ buf[9] = 0x00; // reserved
+ buf[10] = (clk_offset & 0xFF);
+ buf[11] = ((clk_offset >> 8) & 0xFF);
+ buf[12] = role;
+
+ // OGF_LINK_CTL 0x01
+ // OCF_CREATE_CONN 0x0005
+ iRet = hci_send_cmd( uart_fd, 0x01, 0x0005,13 , buf);
+ printf("\n Connect test \n");
+ for(i = 0; i < 1;i++){
+ printf("%02X:",buf[i]);
+ }
+
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!iRet)
+ read_incoming_events(uart_fd, resultBuf, 0);
+}
+
+static const char *disc_help =
+"Usage:\n"
+"\n disc <handle in 2 octets Hex><reason in hex>";
+
+static void cmd_disc(int uart_fd, int argc, char **argv){
+ int iRet;
+ unsigned long val32;
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+ if(argc < 3){
+ printf("\n%s\n",disc_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ val32 = strtol ((char*)argv[1], NULL, 16);
+ buf[0] = val32 & 0xff ;
+ buf[1] = (val32 & 0xff00) >>8;
+ val32 = strtol ((char*)argv[2], NULL, 16);
+ buf[2] = *(UCHAR *)&val32;
+ printf("\nHCI_Disconnect: Handle :%s Reason Code: 0x%x\n",argv[1],buf[2]);
+ // OGF_LINK_CTL 0x01
+ // OCF_DISCONNECT 0x0006
+ iRet = hci_send_cmd(uart_fd, 0x01, 0x0006 ,3 , buf);
+
+
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!iRet)
+ read_incoming_events(uart_fd, resultBuf, 0);
+
+ printf("\n");
+}
+
+static const char *venspeccmd_help =
+"Usage:\n"
+"\n venspeccmd [3|6]\n";
+
+static void cmd_venspeccmd(int uart_fd, int argc, char **argv){
+ int iRet,i;
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+ unsigned long val32;
+ if(argc < 2){
+ printf("\n%s\n",venspeccmd_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ for (i = 1; i < argc; i++)
+ {
+ UCHAR *tmp;
+ val32 = strtol ((char*)argv[i], NULL, 16);
+ tmp = ((unsigned char*)&val32);
+ buf[i-1] = *tmp;
+ }
+
+ iRet = hci_send_cmd( uart_fd, HCI_VENDOR_CMD_OGF, 0x00, i-1, buf);
+
+ printf("Vendor Specific command\n");
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!iRet)
+ read_incoming_events(uart_fd, resultBuf, 0);
+ printf("\n");
+}
+
+static const char *rawcmd_help =
+"Usage:\n"
+"\n rawcmd ogf ocf <bytes> \n";
+
+static void cmd_rawcmd(int uart_fd, int argc, char **argv){
+ int iRet,i,j;
+ UCHAR buf[MAX_EVENT_SIZE];
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+ uint16_t ogf, ocf;
+ unsigned long val32;
+ unsigned char *pval8;
+
+ if(argc < 2){
+ printf("\n%s\n",rawcmd_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+
+ val32 = strtol((char*)argv[1], NULL, 16);
+ pval8 = ((unsigned char*)&val32);
+ ogf = (unsigned short)*pval8;
+
+ val32 = strtol((char*)argv[2], NULL, 16);
+ pval8 = ((unsigned char*)&val32);
+ ocf = (unsigned short)*pval8;
+
+ for (i = 3; i < argc; i++)
+ {
+ UCHAR *tmp;
+ val32 = strtol ((char*)argv[i], NULL, 16);
+ tmp = ((unsigned char*)&val32);
+ buf[i-3] = *tmp;
+ }
+
+ printf("RAW HCI command: ogf 0x%x ocf 0x%x\n Params: ", ogf, ocf);
+
+ for (j = 0; j < i-3; j++) {
+ printf("0x%x ", buf[j]);
+ }
+ printf("\n");
+
+ iRet = hci_send_cmd( uart_fd, ogf, ocf, i-3, buf);
+
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!iRet)
+ read_incoming_events(uart_fd, resultBuf, 0);
+ printf("\n");
+}
+
+static const char *hciinvcmd1_help =
+"Usage:\n"
+"\n hciinvcmd1\n";
+
+static void cmd_hciinvcmd1(int uart_fd, int argc, char **argv){
+ int iRet;
+ UCHAR buf[MAX_EVENT_SIZE];
+
+ if(argc > 1){
+ printf("\n%s\n",hciinvcmd1_help);
+ return;
+ }
+
+ memset(&buf,0,MAX_EVENT_SIZE);
+ buf[0] = atoi(argv[1]);
+ iRet = writeHciCommand(uart_fd, HCI_VENDOR_CMD_OGF, 0x00, 1, buf);
+ if(iRet>=MAX_EVENT_SIZE){
+ printf("\nread buffer size overflowed %d\n", iRet);
+ return;
+ }
+ if(buf[6] != 0){
+ printf("\nError: Invalid HCI cmd due to the reason 0X%X\n", buf[6]);
+ return;
+ }
+ printf("\nINVALID HCI COMMAND: \n");
+ int i;
+ for(i=iRet-1;i > 6;i--){
+ printf("%02X:",buf[i]);
+ }
+ printf("%2X\n\n",buf[6]);
+}
+
+/* EOF SMD cmds */
+static void sig_term(int sig)
+{
+ UNUSED(sig);
+ if (CtrlCBreak) return;
+ CtrlCBreak = TRUE;
+}
+
+static struct {
+ char *cmd;
+ char *cmd_option;
+ void (*func)(int uart_fd, int argc, char **argv);
+ char *doc;
+} command[] = {
+ { "reset"," ", cmd_reset, "Reset Target" },
+ { "rba"," ", cmd_rba, "Read BD Address" },
+ { "wba","<bdaddr> ", cmd_wba, "Write BD Address" },
+ { "edutm"," ", cmd_edutm, "Enter DUT Mode" },
+ { "wsm","<mode> ", cmd_wsm, "Write Scan Mode" },
+ { "mb"," ", cmd_mb, "Enter Master Blaster Mode" },
+ { "mbr","<address> <length> ", cmd_mbr, "Block memory read" },
+ { "peek","<address> <width> ", cmd_peek, "Read Value of an Address" },
+ { "poke","<address> <value> <mask> <width> ", cmd_poke, "Write Value to an Address" },
+ { "cwtx","<channel number> ", cmd_cwtx, "Enter Continuous wave Tx" },
+ { "cwrx","<channel number> ", cmd_cwrx, "Enter Continuous wave Rx" },
+ { "rpst","<length> <id> ", cmd_rpst, "Read PS Tag" },
+ { "wpst","<length> <id> <data> ", cmd_wpst, "Write PS Tag" },
+ { "psr"," ", cmd_psr, "PS Reset" },
+ { "setap","<storage medium> <priority>", cmd_setap, "Set Access Priority" },
+ { "setam","<storage medium> <access mode>", cmd_setam, "Set Access Mode" },
+ { "rpsraw","<offset> <length> ", cmd_rpsraw, "Read Raw PS" },
+ { "wpsraw","<offset> <length> <data>", cmd_wpsraw, "Write Raw PS" },
+ { "ssm","<disable|enable> ", cmd_ssm, "Set Sleep Mode" },
+ { "dtx"," ", cmd_dtx, "Disable TX" },
+ { "dump","<option> ", cmd_dump, "Display Host Controller Information" },
+ { "rafh","<connection handle> ", cmd_rafh, "Read AFH channel Map" },
+ { "safh","<channel classification> ", cmd_safh, "Set AFH Host Channel Classification" },
+ { "wotp", "<address> <data> [length=1]", cmd_wotp, "Write Length (default 1) bytes of Data to OTP started at Address" },
+ { "rotp", "<address> [length=1]", cmd_rotp, "Read Length (default 1) bytes of Data to OTP started at Address"},
+ { "otp", "[dump|imp|exp|test|rpid|wpid|rvid|wvid|rba|wba|hid|cpw|pwridx|ledo] [file]; opt wba <BdAddr>",
+ cmd_otp, "Misc OTP operation: dump/import otp content; imp file content into otp; test otp; otp wba <BdAddr>"},
+ { "plb", "[1|0]", cmd_plb, "Enable/disable PCM CODEC loopback"},
+ { "psw", "[1|0] [Frequency]", cmd_psw, "Enable/disable PCM sine wave playback at frequency (0..3700)"},
+ { "lert", "<rx_channel>", cmd_lert, "Put unit in LE RX mode at rx_channel (0..39)"},
+ { "lett", "<tx_channel> <length> <packet_payload>", cmd_lett, "Put unit in LE TX mode at tx_channel (0..39) with packet of given length (0..37) and packet_payload"},
+ { "lete", " ", cmd_lete, "End LE test"},
+ { "tput-s", "[BD_Addr] [Judgment value] Logfile times data_size", cmd_tputs, "Throughput test - sender side"},
+ { "tput-r", " ", cmd_tputr, "Throughput test - receiver side"},
+ { "btagent","<port number>", cmd_btagent, "BT Agent for IQFact" },
+ { "pinconntest", " ", cmd_pinconntest, "Pin Connectivity Test"},
+ { "hciinq", " ", cmd_hciinq, "Inquiry start"},
+ { "hciinqcnl", " ", cmd_hciinqcnl, "Inquiry Cancel"},
+ { "hcisetevtflt", " ", cmd_hcisetevtflt, "Set Event Filter"},
+ { "conn", " ", cmd_createconnection, "ACL Connection Test" },
+ { "venspeccmd", " ", cmd_venspeccmd, "Vendor Specific Command"},
+ { "disc", " ", cmd_disc, "HCI disconnect Command"},
+ { "hciinvcmd1", " ", cmd_hciinvcmd1, "Invalid HCI Command"},
+ { "rawcmd", " ", cmd_rawcmd, "RAW HCI Command ex) rawcmd ogf ocf <bytes>"},
+ { "cmdline","<port number>", cmdline, "command line for Enable TX test mode" },
+ { NULL, NULL, NULL, NULL }
+};
+/*
+ { "get_id", cmd_gid, "Get Chip Identification Number" },
+ */
+static void usage(void)
+{
+ int i;
+
+ printf("btconfig - BTCONFIG Tool ver %s\n", VERSION);
+ if(is_qca_transport_uart){
+ printf("Usage:\n"
+ "\tbtconfig [options] <command> [command parameters]\n");
+ } else {
+ printf("Usage:\n"
+ "\tbtconfig [options] <tty> <speed> <command> [command parameters]\n");
+ }
+ printf("Options:\n"
+ "\t--help\tDisplay help\n"
+ "\t--soc\tController type: rome or 300x\n"
+ "\t--initialize\tRun rampatch download\n");
+ if(is_qca_transport_uart){ // this parameter is not needed for ROME/CHEROKEE
+ printf("tty:\n"
+ "\t/dev/ttyHS1\n");
+ }
+ printf("Commands:\n");
+ for (i = 0; command[i].cmd; i++)
+ printf("\t%-8s %-40s\t%s\n", command[i].cmd,command[i].cmd_option,command[i].doc);
+ printf("\n"
+ "For more information on the usage of each command use:\n"
+ "\tbtconfig <command> --help\n" );
+}
+
+struct ps_cfg_entry {
+ uint32_t id;
+ uint32_t len;
+ uint8_t *data;
+};
+
+struct ps_entry_type {
+ unsigned char type;
+ unsigned char array;
+};
+
+struct ps_cfg_entry ps_list[MAX_TAGS];
+
+static void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
+{
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(HCI_OPCODE_PACK(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = len + PS_HDR_LEN;
+ cmd += HCI_COMMAND_HEADER_SIZE;
+
+ cmd[0] = ps_op;
+ cmd[1] = index;
+ cmd[2] = index >> 8;
+ cmd[3] = len;
+}
+
+/*
+ * Send HCI command and wait for command complete event.
+ * The event buffer has to be freed by the caller.
+ */
+static int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
+{
+ int count;
+ uint8_t *hci_event;
+ uint8_t pkt_type = 0x01; // HCI_COMMAND_PKT;
+
+ if (len == 0)
+ return len;
+
+#ifdef QCA_DEBUG
+ printf("SEND -> ");
+ qca_debug_dump(cmd, len);
+#endif
+
+ if (write(dev, &pkt_type, 1) != 1)
+ return -EILSEQ;
+ if (write(dev, (unsigned char *)cmd, len) != len)
+ return -EILSEQ;
+
+ hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
+ if (!hci_event)
+ return -ENOMEM;
+
+ count = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
+ if (count < 0) {
+ free(hci_event);
+ return -EILSEQ;
+ }
+
+#ifdef QCA_DEBUG
+ printf("RECV <- ");
+ qca_debug_dump(hci_event, count);
+#endif
+
+ *event = hci_event;
+ return count;
+
+}
+
+static int read_ps_event(uint8_t *event, uint16_t ocf)
+{
+ hci_event_hdr *eh;
+ uint16_t opcode = htobs(HCI_OPCODE_PACK(HCI_VENDOR_CMD_OGF, ocf));
+
+ eh = (hci_event_hdr*) (event + 1);
+ event += HCI_EVENT_HEADER_SIZE;
+
+ // EVT_CMD_COMPLETE 0x0E
+ if (eh->evt == 0x0E) {
+ evt_cmd_complete *cc = (void *)event;
+
+ // EVT_CMD_COMPLETE_SIZE 3
+ event += 3;
+
+ //printf("cc->opcode: %04x\n", cc->opcode);
+ //printf("opcode: %04x\n", opcode);
+ //printf("event[0]: %02x\n", event[0]);
+
+ if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
+ return 0;
+ else
+ return -EILSEQ;
+ }
+
+ printf("read_ps_cmd_complete_fails\n");
+ return -EILSEQ;
+}
+
+static int write_cmd(int fd, uint8_t *buffer, int len)
+{
+ uint8_t *event = NULL;
+ int err;
+
+ err = send_hci_cmd_sync(fd, buffer, len, &event);
+ if (err < 0 || !event){
+ if(event) free(event);
+ event = NULL;
+ return err;
+ }
+
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+
+ free(event);
+ event = NULL;
+ return err;
+}
+
+/* Sends PS commands using vendor specficic HCI commands */
+static int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
+{
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ uint32_t i;
+
+ switch (opcode) {
+ case ENABLE_PATCH:
+ load_hci_ps_hdr(cmd, opcode, 0, 0x00);
+
+ if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
+ return -EILSEQ;
+ break;
+
+ case PS_RESET:
+ load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
+
+ cmd[7] = 0x00;
+ cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
+ cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
+
+ if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
+ return -EILSEQ;
+ break;
+
+ case PS_WRITE:
+ for (i = 0; i < ps_param; i++) {
+ load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
+ ps_list[i].id);
+
+ memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
+ ps_list[i].len);
+
+ if (write_cmd(fd, cmd, ps_list[i].len +
+ HCI_PS_CMD_HDR_LEN) < 0)
+ return -EILSEQ;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+#define __is_delim(ch) ((ch) == ':')
+#define MAX_PREAMBLE_LEN 4
+
+/* Parse PS entry preamble of format [X:X] for main type and subtype */
+static int get_ps_type(char *ptr, int index, char *type, char *sub_type)
+{
+ int i;
+ int delim = FALSE;
+
+ if (index > MAX_PREAMBLE_LEN)
+ return -EILSEQ;
+
+ for (i = 1; i < index; i++) {
+ if (__is_delim(ptr[i])) {
+ delim = TRUE;
+ continue;
+ }
+
+ if (isalpha(ptr[i])) {
+ if (delim == FALSE)
+ (*type) = toupper(ptr[i]);
+ else
+ (*sub_type) = toupper(ptr[i]);
+ }
+ }
+
+ return 0;
+}
+
+#define ARRAY 'A'
+#define STRING 'S'
+#define DECIMAL 'D'
+#define BINARY 'B'
+
+#define PS_HEX 0
+#define PS_DEC 1
+
+static int get_input_format(char *buf, struct ps_entry_type *format)
+{
+ char *ptr = NULL;
+ char type = '\0';
+ char sub_type = '\0';
+
+ format->type = PS_HEX;
+ format->array = TRUE;
+
+ if (strstr(buf, "[") != buf)
+ return 0;
+
+ ptr = strstr(buf, "]");
+ if (!ptr)
+ return -EILSEQ;
+
+ if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
+ return -EILSEQ;
+
+ /* Check is data type is of array */
+ if (type == ARRAY || sub_type == ARRAY)
+ format->array = TRUE;
+
+ if (type == STRING || sub_type == STRING)
+ format->array = FALSE;
+
+ if (type == DECIMAL || type == BINARY)
+ format->type = PS_DEC;
+ else
+ format->type = PS_HEX;
+
+ return 0;
+}
+
+#define UNDEFINED 0xFFFF
+
+static unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
+{
+ char *ptr = buf;
+
+ if (!buf)
+ return UNDEFINED;
+
+ if (buf == strstr(buf, "[")) {
+ ptr = strstr(buf, "]");
+ if (!ptr)
+ return UNDEFINED;
+
+ ptr++;
+ }
+
+ if (type.type == PS_HEX && type.array != TRUE)
+ return strtol(ptr, NULL, 16);
+
+ return UNDEFINED;
+}
+
+struct tag_info {
+ unsigned section;
+ unsigned line_count;
+ unsigned char_cnt;
+ unsigned byte_count;
+};
+
+static inline int update_char_count(const char *buf)
+{
+ char *end_ptr;
+
+ if (strstr(buf, "[") == buf) {
+ end_ptr = strstr(buf, "]");
+ if (!end_ptr)
+ return 0;
+ else
+ return (end_ptr - buf) + 1;
+ }
+
+ return 0;
+}
+
+/* Read PS entries as string, convert and add to Hex array */
+static void update_tag_data(struct ps_cfg_entry *tag,
+ struct tag_info *info, const char *ptr)
+{
+ char buf[3];
+
+ buf[2] = '\0';
+
+ strlcpy(buf, &ptr[info->char_cnt], 2);
+ tag->data[info->byte_count] = strtol(buf, NULL, 16);
+ info->char_cnt += 3;
+ info->byte_count++;
+
+ strlcpy(buf, &ptr[info->char_cnt], 2);
+ tag->data[info->byte_count] = strtol(buf, NULL, 16);
+ info->char_cnt += 3;
+ info->byte_count++;
+}
+
+#define PS_UNDEF 0
+#define PS_ID 1
+#define PS_LEN 2
+#define PS_DATA 3
+
+#define PS_MAX_LEN 500
+#define ENTRY_PER_LINE 16
+
+#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
+#define __skip_space(str) while (*(str) == ' ') ((str)++)
+
+static int ath_parse_ps(FILE *stream)
+{
+ char buf[LINE_SIZE_MAX + 1];
+ char *ptr;
+ uint8_t tag_cnt = 0;
+ uint8_t tagPlatformConfig = 0;
+ int16_t byte_count = 0;
+ struct ps_entry_type format;
+ struct tag_info status = { 0, 0, 0, 0 };
+
+ do {
+ int read_count;
+ struct ps_cfg_entry *tag;
+
+ ptr = fgets(buf, LINE_SIZE_MAX, stream);
+ if (!ptr)
+ break;
+
+ __skip_space(ptr);
+ if (__check_comment(ptr))
+ continue;
+
+ /* Lines with a '#' will be followed by new PS entry */
+ if (ptr == strstr(ptr, "#")) {
+ if (status.section != PS_UNDEF) {
+ return -EILSEQ;
+ } else {
+ status.section = PS_ID;
+ continue;
+ }
+ }
+
+ tag = &ps_list[tag_cnt];
+
+ switch (status.section) {
+ case PS_ID:
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ tag->id = read_data_in_section(ptr, format);
+ if (tag->id == 0x21) /* Platform Config */
+ tagPlatformConfig = 1;
+ status.section = PS_LEN;
+ break;
+
+ case PS_LEN:
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ byte_count = read_data_in_section(ptr, format);
+ if (byte_count > PS_MAX_LEN)
+ return -EILSEQ;
+
+ tag->len = byte_count;
+ tag->data = (uint8_t *)malloc(byte_count);
+
+ status.section = PS_DATA;
+ status.line_count = 0;
+ break;
+
+ case PS_DATA:
+ if (status.line_count == 0)
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ __skip_space(ptr);
+
+ status.char_cnt = update_char_count(ptr);
+
+ read_count = (byte_count > ENTRY_PER_LINE) ?
+ ENTRY_PER_LINE : byte_count;
+
+ if (format.type == PS_HEX && format.array == TRUE) {
+ while (read_count > 0) {
+ update_tag_data(tag, &status, ptr);
+ read_count -= 2;
+ }
+
+ if (tagPlatformConfig == 1) {
+ tagPlatformConfig = 0;
+ tag->data[0] &= 0x7f;
+ }
+
+ if (byte_count > ENTRY_PER_LINE)
+ byte_count -= ENTRY_PER_LINE;
+ else
+ byte_count = 0;
+ }
+
+ status.line_count++;
+
+ if (byte_count == 0)
+ memset(&status, 0x00, sizeof(struct tag_info));
+
+ if (status.section == PS_UNDEF)
+ tag_cnt++;
+
+ if (tag_cnt == MAX_TAGS)
+ return -EILSEQ;
+ break;
+ }
+ } while (ptr);
+
+ return tag_cnt;
+}
+
+#define MAX_PATCH_CMD 244
+struct patch_entry {
+ int16_t len;
+ uint8_t data[MAX_PATCH_CMD];
+};
+
+#define SET_PATCH_RAM_ID 0x0D
+#define SET_PATCH_RAM_CMD_SIZE 11
+#define ADDRESS_LEN 4
+static int set_patch_ram(int dev, char *patch_loc, int len)
+{
+ int err;
+ uint8_t cmd[20];
+ int i, j;
+ char loc_byte[3];
+ uint8_t *event = NULL;
+ uint8_t *loc_ptr = &cmd[7];
+ UNUSED(len);
+ if (!patch_loc)
+ return -1;
+
+ loc_byte[2] = '\0';
+
+ load_hci_ps_hdr(cmd, SET_PATCH_RAM_ID, ADDRESS_LEN, 0);
+
+ for (i = 0, j = 3; i < 4; i++, j--) {
+ loc_byte[0] = patch_loc[0];
+ loc_byte[1] = patch_loc[1];
+ loc_ptr[j] = strtol(loc_byte, NULL, 16);
+ patch_loc += 2;
+ }
+
+ err = send_hci_cmd_sync(dev, cmd, SET_PATCH_RAM_CMD_SIZE, &event);
+ if (err < 0 || !event){
+ if(event) free(event);
+ event = NULL;
+ return err;
+ }
+
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+
+ free(event);
+ event = NULL;
+ return err;
+}
+
+#define PATCH_LOC_KEY "DA:"
+#define PATCH_LOC_STRING_LEN 8
+static int ps_patch_download(int fd, FILE *stream)
+{
+ char byte[3];
+ char ptr[MAX_PATCH_CMD + 1];
+ int byte_cnt;
+ int patch_count = 0;
+ char patch_loc[PATCH_LOC_STRING_LEN + 1];
+
+ byte[2] = '\0';
+
+ while (fgets(ptr, MAX_PATCH_CMD, stream)) {
+ if (strlen(ptr) <= 1)
+ continue;
+ else if (strstr(ptr, PATCH_LOC_KEY) == ptr) {
+ strlcpy(patch_loc, &ptr[sizeof(PATCH_LOC_KEY) - 1],
+ PATCH_LOC_STRING_LEN);
+ if (set_patch_ram(fd, patch_loc, sizeof(patch_loc)) < 0)
+ return -1;
+ } else if (isxdigit(ptr[0]))
+ break;
+ else
+ return -1;
+ }
+
+ byte_cnt = strtol(ptr, NULL, 16);
+
+ while (byte_cnt > 0) {
+ int i;
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ struct patch_entry patch;
+
+ if (byte_cnt > MAX_PATCH_CMD)
+ patch.len = MAX_PATCH_CMD;
+ else
+ patch.len = byte_cnt;
+
+ for (i = 0; i < patch.len; i++) {
+ if (!fgets(byte, 3, stream))
+ return -1;
+
+ patch.data[i] = strtoul(byte, NULL, 16);
+ }
+
+ load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
+ memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
+
+ if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
+ return -1;
+
+ patch_count++;
+ byte_cnt = byte_cnt - MAX_PATCH_CMD;
+ }
+
+ if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
+ return -1;
+
+ return patch_count;
+}
+
+static int ps_config_download(int fd, int tag_count)
+{
+ if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
+ return -1;
+
+ if (tag_count > 0)
+ if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
+ return -1;
+ return 0;
+}
+
+static void get_ps_file_name(uint32_t devtype, uint32_t rom_version,
+ char *path)
+{
+ char *filename;
+
+ if (devtype == ROM_DEV_TYPE)
+ filename = PS_ASIC_FILE;
+ else
+ filename = PS_FPGA_FILE;
+
+ snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH_AR, rom_version, filename);
+}
+
+static void get_patch_file_name(uint32_t dev_type, uint32_t rom_version,
+ uint32_t build_version, char *path)
+{
+ if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE &&
+ dev_type != 0 && build_version == 1)
+ path[0] = '\0';
+ else
+ snprintf(path, MAXPATHLEN, "%s%x/%s",
+ FW_PATH_AR, rom_version, PATCH_FILE);
+}
+
+#define VERIFY_CRC 9
+#define PS_REGION 1
+#define PATCH_REGION 2
+
+static int get_ath3k_crc(int dev)
+{
+ uint8_t cmd[7];
+ uint8_t *event = NULL;
+ int err;
+
+ load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
+
+ err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+ if (err < 0 || !event){
+ if(event) free(event);
+ event = NULL;
+ return err;
+ }
+
+ /* Send error code if CRC check patched */
+ if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
+ err = -EILSEQ;
+
+ free(event);
+ event = NULL;
+ return err;
+}
+
+#define DEV_REGISTER 0x4FFC
+#define GET_DEV_TYPE_OCF 0x05
+
+static int get_device_type(int dev, uint32_t *code)
+{
+ uint8_t cmd[8];
+ uint8_t *event = NULL;
+ uint32_t reg;
+ int err;
+ uint8_t *ptr = cmd;
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(HCI_OPCODE_PACK(HCI_VENDOR_CMD_OGF,
+ GET_DEV_TYPE_OCF));
+ ch->plen = 5;
+ ptr += HCI_COMMAND_HEADER_SIZE;
+
+ ptr[0] = (uint8_t)DEV_REGISTER;
+ ptr[1] = (uint8_t)((DEV_REGISTER >> 8)&0xFF);
+ ptr[2] = (uint8_t)((DEV_REGISTER >> 16)&0xFF);
+ ptr[3] = (uint8_t)((DEV_REGISTER >> 24)&0xFF);
+ ptr[4] = 0x04;
+
+ err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+ if (err < 0 || !event){
+ if(event) free(event);
+ event = NULL;
+ return err;
+ }
+
+ err = read_ps_event(event, GET_DEV_TYPE_OCF);
+ if (err < 0)
+ goto cleanup;
+
+ reg = event[10];
+ reg = (reg << 8) | event[9];
+ reg = (reg << 8) | event[8];
+ reg = (reg << 8) | event[7];
+ *code = reg;
+
+cleanup:
+ free(event);
+ event = NULL;
+ return err;
+}
+
+static int read_ath3k_version(int pConfig, uint32_t *rom_version,
+ uint32_t *build_version)
+{
+ uint8_t cmd[3];
+ uint8_t *event = NULL;
+ int err;
+ int status;
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(HCI_OPCODE_PACK(HCI_VENDOR_CMD_OGF,
+ OCF_READ_VERSION));
+ ch->plen = 0;
+
+ err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+ if (err < 0 || !event){
+ if(event) free(event);
+ event = NULL;
+ return err;
+ }
+
+ err = read_ps_event(event, OCF_READ_VERSION);
+ if (err < 0)
+ goto cleanup;
+
+ status = event[10];
+ status = (status << 8) | event[9];
+ status = (status << 8) | event[8];
+ status = (status << 8) | event[7];
+ *rom_version = status;
+
+ status = event[14];
+ status = (status << 8) | event[13];
+ status = (status << 8) | event[12];
+ status = (status << 8) | event[11];
+
+ *build_version = status;
+
+cleanup:
+ free(event);
+ event = NULL;
+ return err;
+}
+
+static void convert_bdaddr(char *str_bdaddr, char *bdaddr)
+{
+ char bdbyte[3];
+ char *str_byte = str_bdaddr;
+ int i, j;
+ int colon_present = 0;
+
+ if (strstr(str_bdaddr, ":"))
+ colon_present = 1;
+
+ bdbyte[2] = '\0';
+
+ /* Reverse the BDADDR to LSB first */
+ for (i = 0, j = 5; i < 6; i++, j--) {
+ bdbyte[0] = str_byte[0];
+ bdbyte[1] = str_byte[1];
+ bdaddr[j] = strtol(bdbyte, NULL, 16);
+
+ if (colon_present == 1)
+ str_byte += 3;
+ else
+ str_byte += 2;
+ }
+}
+
+static int write_bdaddr(int pConfig, char *bdaddr)
+{
+ uint8_t *event = NULL;
+ int err;
+ uint8_t cmd[13];
+ uint8_t *ptr = cmd;
+ hci_command_hdr *ch = (void *)cmd;
+
+ memset(cmd, 0, sizeof(cmd));
+
+ ch->opcode = htobs(HCI_OPCODE_PACK(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = 10;
+ ptr += HCI_COMMAND_HEADER_SIZE;
+
+ ptr[0] = 0x01;
+ ptr[1] = 0x01;
+ ptr[2] = 0x00;
+ ptr[3] = 0x06;
+
+ convert_bdaddr(bdaddr, (char *)&ptr[4]);
+
+ err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+ if (err < 0 || !event){
+ if(event) free(event);
+ event = NULL;
+ return err;
+ }
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+
+ free(event);
+ event = NULL;
+
+ return err;
+}
+
+static void write_bdaddr_from_file(int rom_version, int fd)
+{
+ FILE *stream;
+ char bdaddr[PATH_MAX];
+ char bdaddr_file[PATH_MAX];
+
+ snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
+ FW_PATH_AR, rom_version, BDADDR_FILE);
+
+ stream = fopen(bdaddr_file, "r");
+ if (!stream)
+ return;
+
+ if (fgets(bdaddr, PATH_MAX - 1, stream))
+ write_bdaddr(fd, bdaddr);
+
+ fclose(stream);
+}
+
+static int ath_ps_download(int fd)
+{
+ int err = 0;
+ int tag_count = 0;
+ int patch_count = 0;
+ uint32_t rom_version = 0;
+ uint32_t build_version = 0;
+ uint32_t dev_type = 0;
+ char patch_file[PATH_MAX];
+ char ps_file[PATH_MAX];
+ FILE *stream;
+
+ if (nopatch) {
+ printf("patch sequences\t\tSKIP\n");
+ err = 0;
+ goto download_cmplete;
+ }
+
+ /*
+ * Verfiy firmware version. depending on it select the PS
+ * config file to download.
+ */
+ if (get_device_type(fd, &dev_type) < 0) {
+ err = -1;
+ goto download_cmplete;
+ }
+ printf("dev_type \t\t0x%x\n", dev_type);
+
+ if (read_ath3k_version(fd, &rom_version, &build_version) < 0) {
+ err = -2;
+ goto download_cmplete;
+ }
+ printf("dev_version \t\trom: 0x%x build: 0x%x\n", rom_version, build_version);
+
+ /* Do not download configuration if CRC passes */
+ if (get_ath3k_crc(fd) < 0) {
+ err = 0;
+ goto download_cmplete;
+ }
+ printf("crc \t\t\tsuccess\n");
+
+ get_ps_file_name(dev_type, rom_version, ps_file);
+ get_patch_file_name(dev_type, rom_version, build_version, patch_file);
+
+ printf("PS file : \t\t%s\n", ps_file);
+ printf("PATCH file : \t\t%s\n", patch_file);
+
+ stream = fopen(ps_file, "r");
+
+ if (!stream) {
+ printf("firmware file open error:%s, ver:%x\n",ps_file, rom_version);
+ if (rom_version == 0x1020201)
+ err = 0;
+ else
+ err = -3;
+ goto download_cmplete;
+ }
+ else {
+ tag_count = ath_parse_ps(stream);
+ fclose(stream);
+ }
+
+ if (tag_count < 0) {
+ err = -4;
+ goto download_cmplete;
+ }
+
+ /*
+ * It is not necessary that Patch file be available,
+ * continue with PS Operations if patch file is not available.
+ */
+ if (patch_file[0] == '\0')
+ err = 0;
+
+ stream = fopen(patch_file, "r");
+ if (!stream)
+ err = 0;
+ else {
+ patch_count = ps_patch_download(fd, stream);
+ fclose(stream);
+
+ if (patch_count < 0) {
+ err = -5;
+ goto download_cmplete;
+ }
+ }
+
+ err = ps_config_download(fd, tag_count);
+
+download_cmplete:
+ printf("download_cmplete;\terr: %d\n", err);
+ if (!err)
+ write_bdaddr_from_file(rom_version, fd);
+
+ return err;
+}
+
+static int uart_speed(int s)
+{
+ switch (s) {
+ case 9600:
+ return B9600;
+ case 19200:
+ return B19200;
+ case 38400:
+ return B38400;
+ case 57600:
+ return B57600;
+ case 115200:
+ return B115200;
+ case 230400:
+ return B230400;
+ case 460800:
+ return B460800;
+ case 500000:
+ return B500000;
+ case 576000:
+ return B576000;
+ case 921600:
+ return B921600;
+ case 1000000:
+ return B1000000;
+ case 1152000:
+ return B1152000;
+ case 1500000:
+ return B1500000;
+ case 2000000:
+ return B2000000;
+#ifdef B2500000
+ case 2500000:
+ return B2500000;
+#endif
+ case 3000000:
+ return B3000000;
+#ifdef B3500000
+ case 3500000:
+ return B3500000;
+#endif
+#ifdef B4000000
+ case 4000000:
+ return B4000000;
+#endif
+ default:
+ return B57600;
+ }
+}
+
+int set_speed(int fd, struct termios *ti, int speed)
+{
+ if (cfsetospeed(ti, uart_speed(speed)) < 0)
+ return -errno;
+
+ if (cfsetispeed(ti, uart_speed(speed)) < 0)
+ return -errno;
+
+ if (tcsetattr(fd, TCSANOW, ti) < 0)
+ return -errno;
+
+ //tcflush(fd, TCIOFLUSH);
+ return 0;
+}
+
+static int set_cntrlr_baud(int fd, int speed)
+{
+ int baud, count;
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[MAX_CMD_LEN], rsp[MAX_EVENT_SIZE];
+ unsigned char *ptr = cmd + 1;
+ hci_command_hdr *ch = (void *)ptr;
+
+ cmd[0] = 0x01; //HCI_COMMAND_PKT;
+
+ /* set controller baud rate to user specified value */
+ ptr = cmd + 1;
+ ch->opcode = htobs(HCI_OPCODE_PACK(HCI_VENDOR_CMD_OGF,
+ HCI_CHG_BAUD_CMD_OCF));
+ ch->plen = 2;
+ ptr += HCI_COMMAND_HEADER_SIZE;
+
+ baud = speed/100;
+ ptr[0] = (char)baud;
+ ptr[1] = (char)(baud >> 8);
+
+#ifdef QCA_DEBUG
+ printf("SEND -> ");
+ qca_debug_dump(cmd, WRITE_BAUD_CMD_LEN);
+#endif
+
+ //if (!local) {
+ if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
+ perror("Failed to write change baud rate command");
+ return -ETIMEDOUT;
+ }
+
+ nanosleep(&tm, NULL);
+ //}
+
+ /* Change local UART baudrate */
+ //if (qca_set_speed(fd, ti, speed) < 0) {
+ // fprintf(stderr, "Can't set host baud rate");
+ // return -EPROTO;
+ //}
+
+ //tcflush(fd, TCIOFLUSH);
+
+ //if (!local) {
+ count = read_hci_event(fd, rsp, sizeof(rsp));
+
+ if (count < 0) {
+ printf("Failed to read event after changing baud rate\n");
+ return -ETIMEDOUT;
+ }
+ //}
+
+#ifdef QCA_DEBUG
+ printf("RECV <- ");
+ qca_debug_dump(rsp, count);
+#endif
+
+ return 0;
+}
+
+
+
+/* Initialize SMD driver */
+static int wcn_init_smd(char *dev)
+{
+ int retry = 0;
+ struct termios term;
+ int fd = -1;
+
+ fd = open(dev, (O_RDWR | O_NOCTTY));
+
+ while ((-1 == fd) && (retry < 3)) {
+ perror("Cannot open device. Retry after 2 seconds");
+ usleep(2000000);
+ fd = open(dev, (O_RDWR | O_NOCTTY));
+ retry++;
+ }
+
+ if (-1 == fd) {
+ perror("Cannot open device, will exit");
+ return -1;
+ }
+
+ usleep(500000);
+
+ if (tcflush(fd, TCIOFLUSH) < 0) {
+ perror("Cannot flush device");
+ close(fd);
+ return -1;
+ }
+
+ if (tcgetattr(fd, &term) < 0) {
+ perror("Error while getting attributes");
+ close(fd);
+ return -1;
+ }
+
+ cfmakeraw(&term);
+ term.c_cflag |= (CRTSCTS | CLOCAL);
+
+ if (tcsetattr(fd, TCSANOW, &term) < 0) {
+ perror("Error while getting attributes");
+ close(fd);
+ return -1;
+ }
+
+ printf("Done intiailizing fd = %s \n", dev);
+ return fd;
+}
+
+static uint8_t qca_get_baudrate(uint32_t speed)
+{
+ switch(speed) {
+ case 9600:
+ return QCA_BAUDRATE_9600;
+ case 19200:
+ return QCA_BAUDRATE_19200;
+ case 38400:
+ return QCA_BAUDRATE_38400;
+ case 57600:
+ return QCA_BAUDRATE_57600;
+ case 115200:
+ return QCA_BAUDRATE_115200;
+ case 230400:
+ return QCA_BAUDRATE_230400;
+ case 460800:
+ return QCA_BAUDRATE_460800;
+ case 500000:
+ return QCA_BAUDRATE_500000;
+ case 921600:
+ return QCA_BAUDRATE_921600;
+ case 1000000:
+ return QCA_BAUDRATE_1000000;
+ case 2000000:
+ return QCA_BAUDRATE_2000000;
+ case 3000000:
+ return QCA_BAUDRATE_3000000;
+ case 3500000:
+ return QCA_BAUDRATE_3500000;
+ default:
+ return QCA_BAUDRATE_AUTO;
+ }
+}
+
+static int qca_vs_read_event(uint8_t *rsp, int size)
+{
+ uint32_t product_id, soc_id;
+ uint16_t patch_ver, rome_ver;
+
+ if(rsp[1] != EVT_VENDOR && rsp[1] != EVT_CMD_COMPLETE) {
+ fprintf(stderr, "Fail to receive HCI Vendor Specific event\n");
+ return -EIO;
+ }
+
+ UNUSED(size);
+ printf("Parameter Length: 0x%x\n", rsp[2]);
+ printf("Command Response: 0x%x\n", rsp[3]);
+ printf("Response Type: 0x%x\n", rsp[4]);
+
+ /* check the status of the operation */
+ switch (rsp[3]) {
+ case EDL_CMD_REQ_RES_EVT:
+ switch (rsp[4]) {
+ case EDL_PATCH_VER_RES_EVT:
+ case EDL_APP_VER_RES_EVT:
+ product_id = *(uint32_t*)le32toh(rsp + 5);
+ patch_ver = *(uint16_t*)le16toh(rsp + 9);
+ rome_ver = *(uint16_t*)le16toh(rsp + 11);
+ soc_id = *(uint32_t*)le32toh(rsp + 13);
+
+ printf("\t Current Product ID\t\t: 0x%08x\n",
+ product_id);
+ printf("\t Current Patch Version\t\t: 0x%04x\n",
+ patch_ver);
+ printf("\t Current ROM Build Version\t: 0x%04x\n",
+ rome_ver);
+ printf("\t Current SOC Version\t\t: 0x%08x\n",
+ soc_id);
+
+ /* ROME chipset Version can be decided by patch and SOC
+ * Version, combination with upper 2 bytes from soc
+ * and lower 2 bytes from patch will be used
+ */
+ g_rome_ver = (soc_id << 16) | (rome_ver & 0x0000ffff);
+ break;
+
+ case EDL_TVL_DNLD_RES_EVT:
+ case EDL_CMD_EXE_STATUS_EVT:
+ if (rsp[5] != HCI_CMD_SUCCESS) {
+ fprintf(stderr, "Fail to download packet %d\n",
+ rsp[5]);
+ return -EIO;
+ }
+ break;
+
+ default:
+ return -EIO;
+ }
+ break;
+
+ case EDL_SET_BAUDRATE_RSP_EVT:
+ if (rsp[4] != BAUDRATE_CHANGE_SUCCESS) {
+ fprintf(stderr, "Set Baudrate request failed 0x%x\n",
+ rsp[5]);
+ return -EIO;
+
+ }
+ break;
+
+ case EDL_NVM_ACCESS_CODE_EVT:
+ break;
+
+ default:
+ fprintf(stderr, "Not a valid status\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int qca_set_speed(int fd, struct termios *ti, uint32_t speed)
+{
+ if (cfsetospeed(ti, uart_speed(speed)) < 0)
+ return -errno;
+
+ if (cfsetispeed(ti, uart_speed(speed)) < 0)
+ return -errno;
+
+ /* don't change speed until last write done */
+ if (tcsetattr(fd, TCSADRAIN, ti) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int qca_set_baudrate(int fd, int flags, uint32_t speed, struct termios *ti, bool local)
+{
+ uint8_t cmd[] = { HCI_COMMAND_PKT, 0x48, 0xfc, 0x01, 0x00 };
+ uint8_t resp[HCI_MAX_EVENT_SIZE];
+ int count;
+
+ if (speed > 3000000)
+ return -EINVAL;
+
+ printf("Set Controller UART speed to %d\n", speed);
+
+ cmd[4] = qca_get_baudrate(speed);
+
+ if (flags & FLOW_CTL) {
+ /* disable flow control while changing speed */
+ ti->c_cflag |= (CLOCAL|CREAD);
+ ti->c_cflag &= ~CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, ti) < 0) {
+ fprintf(stderr, "Can't set port settings");
+ return -EPROTO;
+ }
+ }
+
+ /* Send Vendor Specific command to set UART baudrate to chipset */
+ if (!local && write(fd, cmd, 5) != 5) {
+ fprintf(stderr, "Failed to write update baudrate command\n");
+ return -EIO;
+ }
+
+ /* Change local UART baudrate */
+ if (qca_set_speed(fd, ti, speed) < 0) {
+ fprintf(stderr, "Can't set host baud rate");
+ return -EPROTO;
+ }
+
+ if (flags & FLOW_CTL) {
+ /* flow on after changing local uart baudrate */
+ ti->c_cflag |= (CLOCAL|CREAD);
+ ti->c_cflag |= CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, ti) < 0) {
+ fprintf(stderr, "Can't set port settings");
+ return -EPROTO;
+ }
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ /* check for response from the chipset */
+ if (!local) {
+ count = read_hci_event(fd, resp, HCI_MAX_EVENT_SIZE);
+ if (count < 0)
+ return -EIO;
+
+ if (qca_vs_read_event(resp, count) < 0)
+ return -EPROTO;
+
+ /* number of command complete event */
+ if (read_hci_event(fd, resp, HCI_MAX_EVENT_SIZE) < CC_MIN_SIZE) {
+ fprintf(stderr, "Failed to update baudrate, "
+ "invalid HCI event\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int qca_reset_req(int fd)
+{
+ uint8_t cmd[] = { HCI_COMMAND_PKT, 0x03, 0x0C, 0x00 };
+ uint8_t rsp[HCI_MAX_EVENT_SIZE];
+ int err;
+
+ printf("HCI Reset\n");
+
+ err = write(fd, cmd, sizeof(cmd));
+ if (err != sizeof(cmd)) {
+ fprintf(stderr, "Send failed with ret value %d\n", err);
+ return -1;
+ }
+
+ err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
+ if (err < 7) {
+ fprintf(stderr, "Failed to reset, invalid HCI event\n");
+ return -1;
+ }
+
+ if (rsp[4] != cmd[1] || rsp[5] != cmd[2] || rsp[6] != HCI_CMD_SUCCESS) {
+ fprintf(stderr, "Failed to reset, command failure\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int qca_vs_send_cmd(int fd, uint8_t *cmd, uint8_t *rsp, int size)
+{
+ int ret, count;
+
+#ifdef QCA_DEBUG
+ printf("SEND -> ");
+ qca_debug_dump(cmd, size);
+#endif
+ ret = write(fd, cmd, size);
+ if (ret != size) {
+ fprintf(stderr, "Send failed with ret %d\n", ret);
+ return -1;
+ }
+
+ /* check for response from the chipset */
+ count = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
+ if (count < 0)
+ return -1;
+
+#ifdef QCA_DEBUG
+ printf("RECV <- ");
+ qca_debug_dump(rsp, count);
+#endif
+ ret = qca_vs_read_event(rsp, count);
+ if (ret < 0)
+ return -1;
+
+ return count;
+}
+
+static void frame_hci_pkt(uint8_t *cmd, int eld_cmd, uint8_t *data, int size)
+{
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = HCI_PATCH_CMD_OCF & 0xff;
+ cmd[2] = HCI_VENDOR_CMD_OGF << 2 | HCI_PATCH_CMD_OCF >> 8;
+ cmd[3] = size;
+ cmd[4] = eld_cmd;
+
+ switch(eld_cmd) {
+ case EDL_PATCH_VER_REQ_CMD:
+ printf("Sending EDL_PATCH_VER_REQ_CMD\n");
+ break;
+
+ case EDL_PATCH_TLV_REQ_CMD:
+ printf("Sending EDL_PATCH_TLV_REQ_CMD\n");
+ /* parameter total length */
+ cmd[3] = size + 2; // adding size of eld_cmd & length
+ /* TLV segment length */
+ cmd[5] = size;
+ /* put data */
+ memcpy(cmd + 6, data, size);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown EDL CMD\n");
+ break;
+ }
+
+ return;
+}
+
+static int qca_rome_patch_ver_req(int fd)
+{
+ int size, err;
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ uint8_t rsp[HCI_MAX_EVENT_SIZE];
+
+ /* Generate packet to read chipset version */
+ frame_hci_pkt(cmd, EDL_PATCH_VER_REQ_CMD, 0,
+ EDL_PATCH_CMD_LEN);
+ /* size of length: CMD + opcode + len */
+ size = 4 + EDL_PATCH_CMD_LEN;
+
+ /* Send HCI command to controller */
+ err = qca_vs_send_cmd(fd, cmd, rsp, size);
+ if (err < 0) {
+ fprintf(stderr, "Failed to read version of soc (%x)\n",
+ err);
+ return err;
+ }
+
+ /* Command complete event */
+ err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
+ if (err < 7) {
+ fprintf(stderr, "Failed to read, invalid HCI event\n");
+ return -1;
+ }
+
+#ifdef QCA_DEBUG
+ printf("RECV <- ");
+ qca_debug_dump(rsp, 10);
+#endif
+ return 0;
+}
+
+static int qca_tlv_dnld_segment(int fd, int idx, int seg_size, uint8_t *data,
+ bool wt_evt)
+{
+ int size, err;
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ uint8_t rsp[HCI_MAX_EVENT_SIZE];
+
+ printf("Download segment no %d size %d\n", idx, seg_size);
+
+ /* Frame the HCI CMD PKT to be sent to controller */
+ frame_hci_pkt(cmd, EDL_PATCH_TLV_REQ_CMD, data, seg_size);
+ /* total size of packet: cmd + opcode + len + cmd[3] */
+ size = 4 + cmd[3];
+
+ err = qca_vs_send_cmd(fd, cmd, rsp, size);
+ if (err < 0) {
+ fprintf(stderr, "Failed to send patch payload to soc %x\n",
+ err);
+ return err;
+ }
+
+ if (wt_evt) {
+ err = read_hci_event(fd, rsp, HCI_MAX_EVENT_SIZE);
+ if (err < 0) {
+ fprintf(stderr, "Failed to download patch segment %d\n",
+ idx);
+ return err;
+ }
+#ifdef QCA_DEBUG
+ printf("RECV <- ");
+ qca_debug_dump(rsp, 10);
+#endif
+ }
+
+ printf("Succeed downloading segment %d\n", idx);
+
+ return 0;
+}
+
+static int qca_tlv_dnld_req(int fd, struct patch_data *pdata)
+{
+ int total_segment, remain_size;
+ int err, w_cmd, i;
+ uint8_t *buffer;
+
+ if (!pdata)
+ return -EINVAL;
+
+ total_segment = pdata->len / MAX_SIZE_PER_TLV_SEGMENT;
+ remain_size = (pdata->len < MAX_SIZE_PER_TLV_SEGMENT)? pdata->len :
+ pdata->len % MAX_SIZE_PER_TLV_SEGMENT;
+
+ printf("Total size %ld, total segment num %d, remain size %d\n",
+ pdata->len, total_segment, remain_size);
+
+ for (i = 0; i < total_segment; i++) {
+ // Last patch segment does not generate command_complete event
+ if (pdata->type == TLV_TYPE_PATCH && !remain_size &&
+ i+1 == total_segment)
+ w_cmd = false;
+ else
+ w_cmd = true;
+
+ buffer = pdata->data + i * MAX_SIZE_PER_TLV_SEGMENT;
+ err = qca_tlv_dnld_segment(fd, i, MAX_SIZE_PER_TLV_SEGMENT,
+ buffer, w_cmd);
+ if (err < 0)
+ return -EIO;
+ }
+
+ if (remain_size) {
+ // Last patch segment does not generate command_complete event
+ if (pdata->type == TLV_TYPE_PATCH)
+ w_cmd = false;
+ else
+ w_cmd = true;
+
+ buffer = pdata->data + total_segment * MAX_SIZE_PER_TLV_SEGMENT;
+ err = qca_tlv_dnld_segment(fd, total_segment, remain_size,
+ buffer, w_cmd);
+ if (err < 0)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void qca_print_file_data(int type, uint8_t *file_data)
+{
+ uint8_t *data;
+ int i, idx, length, tlv;
+ uint16_t tag_id, tag_len;
+
+ data = file_data;
+
+ printf("===================================================\n");
+ tlv = *(uint32_t*)le32toh(data);
+ printf("TLV Type\t\t : 0x%x\n", tlv & 0x000000ff);
+ length = (tlv >> 8) & 0x00ffffff;
+ printf("Length\t\t\t : %d bytes \n", length);
+ data += sizeof(uint32_t);
+
+ switch (type) {
+ case TLV_TYPE_PATCH:
+ printf("Total Length\t\t : %d bytes\n",
+ *(uint32_t*)le32toh(data));
+ data += sizeof(uint32_t);
+ printf("Patch Data Length\t : %d bytes\n",
+ *(uint32_t*)le32toh(data));
+ data += sizeof(uint32_t);
+ printf("Signing Format Version\t : 0x%x\n", *(char*)data);
+ data += sizeof(uint8_t);
+ printf("Signature Algorithm\t : 0x%x\n", *(char*)data);
+ data += sizeof(uint8_t);
+ printf("Reserved\t\t : 0x%x\n", *(uint16_t*)le16toh(data));
+ data += sizeof(uint16_t);
+ printf("Product ID\t\t : 0x%04x\n", *(uint16_t*)le16toh(data));
+ data += sizeof(uint16_t);
+ printf("Rom Build Version\t : 0x%04x\n",
+ *(uint16_t*)le16toh(data));
+ data += sizeof(uint16_t);
+ printf("Patch Version\t\t : 0x%04x\n",
+ *(uint16_t*)le16toh(data));
+ data += sizeof(uint16_t);
+ printf("Reserved\t\t : 0x%x\n", *(uint16_t*)le16toh(data));
+ data += sizeof(uint16_t);
+ printf("Patch Entry Address\t : 0x%x\n",
+ *(uint32_t*)le32toh(data));
+ break;
+
+ case TLV_TYPE_NVM:
+ idx = 0;
+ do {
+ tag_id = *(uint16_t*)le16toh(data);
+ data += sizeof(uint16_t);
+ tag_len = *(uint16_t*)le16toh(data);
+ data += sizeof(uint16_t);
+
+ // skip tag pointer & ex_flag; 4 bytes each
+ data += 8;
+
+ printf("TAG ID\t\t : %d\n", tag_id);
+ printf("TAG Length\t\t : %d\n", tag_len);
+ printf("TAG Data\t\t : ");
+
+ switch (tag_id) {
+ case 17: // HCI Transport Layer Parameters
+ // Disable Software Inband Sleep
+ data[0] &= 0x7F;
+ break;
+
+ case 27: // Sleep Enable Mask
+ // Disable deep sleep mode
+ data[0] &= 0xFE;
+ break;
+ }
+
+ for (i = 0; i < tag_len; i++, data++)
+ printf("%.02x ", *data);
+ printf("\n");
+
+ idx += (sizeof(uint16_t) + sizeof(uint16_t) + 8 +
+ tag_len);
+ } while (idx < length);
+ break;
+
+ default:
+ printf("unknown TLV type %d\n", type);
+ break;
+ }
+
+ printf("===================================================\n");
+
+ return;
+}
+
+static int qca_get_tlv_file(char *path, struct patch_data *pdata)
+{
+ FILE *stream;
+ int read_size, ret = 0;
+
+ printf("file open %s\n", path);
+
+ if (!path || !pdata)
+ return -EINVAL;
+
+ stream = fopen(path, "r");
+ if (!stream)
+ return -EIO;
+
+ /* get file size */
+ fseek(stream, 0, SEEK_END);
+ pdata->len = ftell(stream);
+ rewind(stream);
+
+ pdata->data = (uint8_t *)malloc(pdata->len);
+ if (!pdata->data) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ /* copy file into allocated buffer*/
+ read_size = fread(pdata->data, 1, pdata->len, stream);
+
+ if (read_size != pdata->len) {
+ printf("read file size %d not matched with actual size %ld\n",
+ read_size, pdata->len);
+ ret = -EILSEQ;
+ goto done;
+ }
+
+ qca_print_file_data(pdata->type, pdata->data);
+
+done:
+ if (stream)
+ fclose(stream);
+
+ if (ret < 0 && pdata->data)
+ free(pdata->data);
+
+ return ret;
+}
+
+static int qca_download_tlv_file(int fd, uint8_t type, char *file_name)
+{
+ struct patch_data data;
+ int ret = 0;
+
+ data.type = type;
+ data.data = NULL;
+ ret = qca_get_tlv_file(file_name, &data);
+ if (ret < 0) {
+ fprintf(stderr, "fail to get patch %s %d\n", file_name, ret);
+ goto done;
+ }
+
+ ret = qca_tlv_dnld_req(fd, &data);
+ if (ret < 0) {
+ fprintf(stderr, "fail to download %s %d\n", file_name, ret);
+ goto done;
+ }
+
+done:
+ if (data.data)
+ free(data.data);
+
+ return ret;
+}
+
+int qca_rome_init(int fd, int flags, int speed, struct termios *ti)
+{
+ char patch_name[NAME_MAX], nvm_name[NAME_MAX];
+ int err;
+
+ printf("qca_rome_init\n");
+
+ /* Change baudrate from 115.2kbps to High Speed UART */
+ err = qca_set_baudrate(fd, flags, speed, ti, nopatch);
+ if (err < 0)
+ return -1;
+
+ /* Get ROME version information */
+ err = qca_rome_patch_ver_req(fd);
+ if (err < 0 || g_rome_ver == 0) {
+ fprintf(stderr, "Fail to get ROME version 0x%x\n", err);
+ return -1;
+ }
+
+ printf("ROME controller version 0x%08x \n", g_rome_ver);
+
+ snprintf(patch_name, NAME_MAX, "%s/rampatch_%08x.bin",
+ FW_PATH_ROME, g_rome_ver);
+ snprintf(nvm_name, NAME_MAX, "%s/nvm_%08x.bin",
+ FW_PATH_ROME, g_rome_ver);
+
+ if (nopatch) {
+ printf("patch sequences\t\tSKIP\n");
+ return 0;
+ }
+
+ /* Download rampatch file */
+ err = qca_download_tlv_file(fd, TLV_TYPE_PATCH, patch_name);
+ if (err < 0)
+ return -1;
+
+ /* Download NVM file */
+ err = qca_download_tlv_file(fd, TLV_TYPE_NVM, nvm_name);
+ if (err < 0)
+ return -1;
+
+ /* Perform HCI reset */
+ err = qca_reset_req(fd);
+ if (err < 0)
+ return -1;
+
+ return 0;
+}
+/*
+ * Atheros AR300x specific initialization and configuration file
+ * download
+ */
+int ath3k_init(int fd, int flags, int speed, int init_speed, char *bdaddr,
+ struct termios *ti)
+{
+ int r;
+ int err = 0;
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[MAX_CMD_LEN], rsp[MAX_EVENT_SIZE];
+ unsigned char *ptr = cmd + 1;
+ hci_command_hdr *ch = (void *)ptr;
+
+ UNUSED(flags);
+ cmd[0] = 0x01; //HCI_COMMAND_PKT;
+
+ /* set both controller and host baud rate to maximum possible value */
+ printf("ath3k_init_set_baud, speed=%d, init_speed=%d\n", speed, init_speed);
+ err = set_cntrlr_baud(fd, speed);
+ if (err < 0)
+ return err;
+ printf("set_cntrlr_baud\t\tsuccess\n");
+
+ err = set_speed(fd, ti, speed);
+ if (err < 0) {
+ perror("Can't set required baud rate");
+ return err;
+ }
+ printf("set_speed %d\tdone\n", speed);
+
+ /* Download PS and patch */
+ r = ath_ps_download(fd);
+ if (r < 0) {
+ perror("Failed to Download configuration");
+ err = -ETIMEDOUT;
+ goto failed;
+ }
+
+ /* Write BDADDR */
+ if (bdaddr) {
+ ch->opcode = htobs(HCI_OPCODE_PACK(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = 10;
+ ptr += HCI_COMMAND_HEADER_SIZE;
+
+ ptr[0] = 0x01;
+ ptr[1] = 0x01;
+ ptr[2] = 0x00;
+ ptr[3] = 0x06;
+ str2ba(bdaddr, (bdaddr_t *)(ptr + 4));
+
+ if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
+ WRITE_BDADDR_CMD_LEN) {
+ perror("Failed to write BD_ADDR command\n");
+ err = -ETIMEDOUT;
+ goto failed;
+ }
+
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+ perror("Failed to set BD_ADDR\n");
+ err = -ETIMEDOUT;
+ goto failed;
+ }
+ }
+
+ /* Send HCI Reset */
+ cmd[1] = 0x03; // OCF_RESET
+ cmd[2] = 0x0C;
+ cmd[3] = 0x00;
+
+ r = write(fd, cmd, 4);
+ if (r != 4) {
+ err = -ETIMEDOUT;
+ goto failed;
+ }
+
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+ err = -ETIMEDOUT;
+ goto failed;
+ }
+
+ err = set_cntrlr_baud(fd, speed);
+ if (err < 0)
+ return err;
+
+failed:
+ if (err < 0) {
+ set_cntrlr_baud(fd, init_speed);
+ set_speed(fd, ti, init_speed);
+ }
+ //sleep(2);
+ return err;
+}
+
+/* Initialize UART driver */
+static int init_uart(char *dev, int user_specified_speed)
+{
+ struct termios ti;
+ int fd, err;
+ unsigned long flags = 0;
+
+ fd = open(dev, O_RDWR | O_NOCTTY);
+ if (fd < 0) {
+ perror("Can't open serial port");
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+ if (tcgetattr(fd, &ti) < 0) {
+ perror("Can't get port settings");
+ return -1;
+ }
+
+ cfmakeraw(&ti);
+
+ ti.c_cflag |= CLOCAL;
+ ti.c_cflag |= CRTSCTS;
+
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ close(fd);
+ return -1;
+ }
+
+ /* Set initial baudrate */
+ if (set_speed(fd, &ti, 115200) < 0) {
+ perror("Can't set initial baud rate");
+ close(fd);
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+
+ if (ioctl(fd, TIOCMGET, &flags) < 0) {
+ perror("TIOCMGET failed in init\n");
+ close(fd);
+ return -1;
+ }
+
+ flags |= TIOCM_RTS;
+ if (ioctl(fd, TIOCMSET, &flags) < 0) {
+ perror("TIOCMSET failed in init: HW Flow-on error\n");
+ close(fd);
+ return -1;
+ }
+
+ tcflush(fd, TCIOFLUSH);
+
+
+ /*char cmd[5], rsp[PS_EVENT_LEN];
+ int r, err;
+ struct timespec tm = { 0, 5000000 };
+
+ // Send reset to poke SOC
+ cmd[1] = 0x3F; // OCF_RESET
+ cmd[2] = 0x1E;
+ cmd[3] = 0x00;
+ r = write(fd, cmd, 4);
+ nanosleep(&tm, NULL);
+ if (r != 4) {
+ err = -ETIMEDOUT;
+ return -1;
+ }
+*/
+ //sleep(1);
+
+// if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+// err = -ETIMEDOUT;
+ // Firmware not ready, reconfig baud & download firmware
+ if (!strcasecmp(soc_type, "rome")) {
+ err = qca_rome_init(fd, flags, user_specified_speed, &ti);
+ if (err < 0) {
+ close(fd);
+ return -1;
+ }
+ printf("\n==== The initialization of QCA61x4 is succeed ====\n\n");
+ } else if (!strcasecmp(soc_type, "300x")) {
+ err = ath3k_init(fd, flags, user_specified_speed,115200, NULL, &ti);
+ if (err < 0) {
+ close(fd);
+ return -1;
+ }
+ printf("\n==== The initialization of ATH3K is succeed ====\n\n");
+ }
+
+ return fd;
+}
+
+void disable_soc_logging(int fd)
+{
+ int iRet;
+ UCHAR resultBuf[MAX_EVENT_SIZE];
+ if (!strcasecmp(soc_type, "smd")){
+ UCHAR buf[5] = {(unsigned char)0x10, (unsigned char)0x02,( unsigned char)0x0,(unsigned char) 0x0,( unsigned char)0x01 };
+ iRet = hci_send_cmd( fd, HCI_VENDOR_CMD_OGF, 0x17, 5, buf);
+ }
+ else if (!strcasecmp(soc_type, "cherokee")){
+ UCHAR buf[2] = {(unsigned char)0x14, (unsigned char)0x0};
+ iRet = hci_send_cmd( fd, HCI_VENDOR_CMD_OGF, 0x17, 2, buf);
+ }
+ else
+ return;
+ printf("sending command to disable logging\n");
+
+ memset(&resultBuf,0,MAX_EVENT_SIZE);
+ if (!iRet)
+ read_incoming_events( fd, resultBuf, 0);
+ printf("\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int opt, i, min_para = 2;
+ static int fd = -1;
+
+ while ((opt=getopt_long(argc, argv, "hs:n", main_options, NULL)) != -1) {
+ switch (opt) {
+ case 'h':
+ usage();
+ exit(0);
+ case 's':
+ strcpy(soc_type, optarg);
+ continue;
+ case 'i':
+ nopatch = false;
+ continue;
+ }
+ }
+
+#ifdef ANDROID
+ property_get("ro.vendor.qti.bt.hci_transport", prop, NULL);
+ property_get("vendor.qti.bluetooth.soc", soc_type, NULL);
+#endif
+
+ if((!strcasecmp(soc_type, "rome")) || (!strcasecmp(soc_type, "cherokee")))
+ is_qca_transport_uart = true;
+
+ if(is_qca_transport_uart) min_para = 1;
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ if (argc < min_para) {
+ usage();
+ exit(0);
+ }
+
+ if (!strcasecmp(prop, "smd")) {
+ printf("SOC is WCN\n");
+
+ fd = wcn_init_smd(argv[optind]);
+ // skip interface entry
+ argv += 1;
+ argc -= 1;
+ } else if (is_qca_transport_uart){
+ if(!strcasecmp(soc_type, "rome"))
+ printf("SOC is ROME\n");
+ else
+ printf("SOC is CHEROKEE\n");
+#ifdef ANDROID
+ fd = connect_to_wds_server();
+ if(fd < 0) {
+ perror("connection to WDS server failed");
+ exit(1);
+ }
+#else
+ if ((fd = init_uart(argv[optind], ((atoi(argv[optind+1]) != 115200) ? 3000000 : atoi(argv[optind+1])) )) < 0) {
+ perror("Device is not available");
+ exit(1);
+ }
+
+ //Move to next argv if <speed> inputed.
+ if (atoi(argv[optind+1]) >= 115200)
+ {
+ argv +=1;
+ argc -=1;
+ }
+#endif
+ } else {
+ strcpy(soc_type, "300x");
+ printf("SOC is AR300x\n");
+
+ //btconfig [options] <tty> <speed> <command> [command parameters]
+ //<speed> uses default 115200 if no buadrate inputed. Should no need to have Max speed detection.
+ if ((fd = init_uart(argv[optind], ((atoi(argv[optind+1]) < 115200) ? 115200 : atoi(argv[optind+1])) )) < 0) {
+ perror("Device is not available");
+ exit(1);
+ }
+
+ //Move to next argv if <speed> inputed.
+ if (atoi(argv[optind+1]) >= 115200)
+ {
+ argv +=1;
+ argc -=1;
+ }
+ }
+
+ disable_soc_logging(fd);
+
+ for (i = 0; command[i].cmd; i++) {
+ if (strcmp(command[i].cmd, argv[0]))
+ continue;
+ command[i].func(fd, argc, argv);
+ break;
+ }
+ close(fd);
+ return 0;
+}
+
+
+// MAster BLaster fucntions
+tMasterBlasterField MasterBlasterMenu[] =
+{
+ {"ContRxMode", "n", "toggle coNtinuous Rx", 0, ContRxModeOption, SetMasterBlasterContRxMode},
+ {"ContTxMode", "c", "toggle Continuous Tx", 0, ContTxModeOption, SetMasterBlasterContTxMode},
+ {"LERxMode", "q", "toggle LE Rx mode", 0, ContRxModeOption, SetMasterBlasterLERxMode},
+ {"LETxMode", "w", "toggle LE Tx mode", 0, ContTxModeOption, SetMasterBlasterLETxMode},
+ {"LETxPktPayload", "y", "set LE Tx packet payload", 0, LETxPktPayloadOption, SetMasterBlasterLETxPktPayload},
+ {"ContTxType", "u", "toggle continUous Tx Type", Cont_Tx_Raw_1MHz, ContTxTypeOption, SetMasterBlasterContTxType},
+ {"TestMode", "m", "toggle test Mode", eBRM_TestMode_TX_1010, TestModeOption, SetMasterBlasterTestMode},
+ {"HopMode", "h", "toggle Hop mode", 0, HopModeOption, SetMasterBlasterHopMode},
+ {"TxFreq", "t", "set Tx freq", 39, NULL, SetMasterBlasterTxFreq},
+ {"RxFreq", "r", "set Rx freq", 39, NULL, SetMasterBlasterRxFreq},
+ {"PacketType", "p", "toggle Packet type", TxTest_PktType_DH1, PacketTypeOption, SetMasterBlasterPacketType},
+ {"DataLen", "l", "set data Length", 15, NULL, SetMasterBlasterDataLen},
+ {"Power", "o", "toggle pOwer", 9, NULL, SetMasterBlasterPower},
+ {"BdAddr", "a", "set bdAddr", 0, NULL, SetMasterBlasterBdAddr},
+ {"SetBERType", "k", "set BER type", eBRM_BERMode_ALL_DATA, BERPacketTypeOption,SetMasterBlasterBERType},
+ {"GetBER", "g", "get BER type", 0, NULL, SetMasterBlasterNothing},
+ {"EnableRxTest", "d", "Enable rx test mode", 0, NULL, SetMasterBlasterNothing},
+ {"EnableTxTest", "e", "Enable tx test mode", 0, NULL, SetMasterBlasterNothing},
+ {"EnableTest", "j", "Start test mode", 0, NULL, SetMasterBlasterNothing},
+ {"StopTest", "s", "Stop test mode", 0, NULL, SetMasterBlasterNothing},
+ {"Exit", "x", "eXit", 0, NULL, SetMasterBlasterNothing},
+ {"ExitWithoutReset", "b", "Exit without reset", 0, NULL, SetMasterBlasterNothing},
+};
+
+tPsSysCfgTransmitPowerControlTable TpcTable;
+
+//----------------------------------------------------------------------------
+
+void InitMasterBlaster (tBRM_Control_packet *MasterBlaster, bdaddr_t *BdAddr, UCHAR *SkipRxSlot)
+{
+ *SkipRxSlot = 0x01;
+ MasterBlaster->testCtrl.Mode = MasterBlasterMenu[TM].Default;
+ MasterBlaster->testCtrl.HopMode = MasterBlasterMenu[HM].Default;
+ MasterBlaster->testCtrl.Packet = MasterBlasterMenu[PT].Default;
+ MasterBlaster->testCtrl.TxFreq = MasterBlasterMenu[TF].Default;
+ MasterBlaster->testCtrl.RxFreq = MasterBlasterMenu[RF].Default;
+ MasterBlaster->testCtrl.Power = MasterBlasterMenu[PO].Default;
+ MasterBlaster->testCtrl.DataLen = MasterBlasterMenu[DL].Default;
+ MasterBlaster->ContTxMode = MasterBlasterMenu[CT].Default;
+ MasterBlaster->ContTxType = MasterBlasterMenu[CX].Default;
+ MasterBlaster->ContRxMode = MasterBlasterMenu[CR].Default;
+ MasterBlaster->BERType = MasterBlasterMenu[SB].Default;
+ MasterBlaster->LERxMode = MasterBlasterMenu[LR].Default;
+ MasterBlaster->LETxMode = MasterBlasterMenu[LT].Default;
+ MasterBlaster->LETxParms.PktPayload = MasterBlasterMenu[LTM].Default;
+ memcpy(MasterBlaster->bdaddr,&BdAddr->b[0],6);
+
+ TpcTable.NumOfEntries = 0;
+}
+
+//----------------------------------------------------------------------------
+
+int CheckField (tBRM_Control_packet MasterBlaster, char *FieldAlias)
+{
+ if (((!strncmp(FieldAlias,MasterBlasterMenu[HM].Alias,1)) && MasterBlaster.ContTxMode) ||
+ (((!strncmp(FieldAlias,MasterBlasterMenu[TF].Alias,1)) || (!strncmp(FieldAlias,MasterBlasterMenu[RF].Alias,1))) && MasterBlaster.testCtrl.HopMode == 1) ||
+ ((!strncmp(FieldAlias,MasterBlasterMenu[CX].Alias,1)) && MasterBlaster.ContTxMode == 0))
+ {
+ return INVALID_MASTERBLASTER_FIELD;
+ }
+ unsigned int i;
+ for (i = 0; i < sizeof(MasterBlasterMenu)/sizeof(tMasterBlasterField); ++i)
+ {
+ if (!strncmp(FieldAlias,MasterBlasterMenu[i].Alias,1))
+ {
+ return i;
+ }
+ }
+
+ return INVALID_MASTERBLASTER_FIELD;
+}
+
+//----------------------------------------------------------------------------
+
+int GetTestModeOptionIndex (int Value)
+{
+ unsigned int i;
+ for (i = 0; i < sizeof(TestModeOption)/sizeof(tMasterBlasterOption); ++i)
+ {
+ if (Value == TestModeOption[i].Value)
+ {
+ return i;
+ }
+ }
+ // assert (0);
+ return -1;
+}
+
+//----------------------------------------------------------------------------
+
+int GetPacketTypeOptionIndex (int Value)
+{
+ unsigned int i;
+ for (i = 0; i < sizeof(PacketTypeOption)/sizeof(tMasterBlasterOption); ++i)
+ {
+ if (Value == PacketTypeOption[i].Value)
+ {
+ return i;
+ }
+ }
+ //assert (0);
+ return -1;
+}
+
+//----------------------------------------------------------------------------
+
+void PrintMasterBlasterMenu(tBRM_Control_packet *MasterBlaster)
+{
+ unsigned int i;
+ printf ("\n---------- Master Blaster Mode ----------\n\n");
+ for (i = 0; i < sizeof(MasterBlasterMenu)/sizeof(tMasterBlasterField); ++i)
+ {
+ if (((i == HM || i == RF) && (MasterBlaster->ContTxMode == ENABLE)) ||
+ ((i == TF || i == RF) && (MasterBlaster->testCtrl.HopMode == 1)) ||
+ ((i == CX) && (MasterBlaster->ContTxMode == DISABLE)) ||
+ ((i == CX || i == HM || i == TF || i == PT || i == DL || i == PO || i == BA) &&
+ (MasterBlaster->ContRxMode == ENABLE)))
+ {
+ continue;
+ }
+
+ printf ("\t%s - %s\n", MasterBlasterMenu[i].Alias, MasterBlasterMenu[i].Usage);
+ }
+ printf ("\n-----------------------------------------\n\n");
+
+ char BdAddr[18];
+ //strcpy(MasterBlaster.bdaddr,BdAddr);
+
+ printf ("ContRxMode: %s\n", ContRxModeOption[MasterBlaster->ContRxMode].Name);
+ printf ("ContTxMode: %s\n", ContTxModeOption[MasterBlaster->ContTxMode].Name);
+ printf ("LERxMode: %s\n", ContTxModeOption[MasterBlaster->LERxMode].Name);
+ printf ("LETxMode: %s\n", ContTxModeOption[MasterBlaster->LETxMode].Name);
+
+ // LE Rx mode
+ if (MasterBlaster->LERxMode == ENABLE)
+ {
+ if (MasterBlaster->testCtrl.RxFreq > MB_MAX_FREQUENCY_LE)
+ MasterBlaster->testCtrl.RxFreq = MB_MAX_FREQUENCY_LE;
+ printf("RxFreq: %d\n", MasterBlaster->testCtrl.RxFreq);
+ }
+ // LE Tx mode
+ if (MasterBlaster->LETxMode == ENABLE)
+ {
+ if (MasterBlaster->testCtrl.DataLen > MB_MAX_DATALEN_LE)
+ MasterBlaster->testCtrl.DataLen = MB_MAX_DATALEN_LE;
+ printf("TxFreq: %d\n", MasterBlaster->testCtrl.TxFreq);
+ printf("DataLen: %d\n", MasterBlaster->testCtrl.DataLen);
+ printf("PktPayload: %s\n", LETxPktPayloadOption[MasterBlaster->LETxParms.PktPayload].Name);
+ }
+ // Continous Rx mode
+ else if (MasterBlaster->ContRxMode == ENABLE)
+ {
+ printf ("BER Type: %s\n",BERPacketTypeOption[MasterBlaster->BERType].Name);
+ printf ("RxFreq: %d\n", MasterBlaster->testCtrl.RxFreq);
+ }
+ // Continous Tx mode and Tx test mode
+ else
+ {
+ printf ("BER Type: %s\n",BERPacketTypeOption[MasterBlaster->BERType].Name);
+ if (MasterBlaster->ContTxMode == ENABLE)
+ {
+ printf ("ContTxType: %s\n", ContTxTypeOption[MasterBlaster->ContTxType].Name);
+ if (ContTxTypeOption[MasterBlaster->ContTxType].Value != CW_Single_Tone){
+ int index = GetTestModeOptionIndex(MasterBlaster->testCtrl.Mode);
+ if(index < 0) printf("Unable to find the matching Test Mode! %d \n", MasterBlaster->testCtrl.Mode);
+ else printf ("TestMode: %s\n", TestModeOption[index].Name);
+ }
+ printf ("TxFreq: %d\n", MasterBlaster->testCtrl.TxFreq);
+ }
+ else
+ {
+ int index = GetTestModeOptionIndex(MasterBlaster->testCtrl.Mode);
+ if(index < 0) printf("Unable to find the matching Test Mode! %d \n", MasterBlaster->testCtrl.Mode);
+ else printf ("TestMode: %s\n", TestModeOption[index].Name);
+ printf ("HopMode: %s\n", HopModeOption[MasterBlaster->testCtrl.HopMode].Name);
+
+ if (MasterBlaster->testCtrl.HopMode == 0)
+ {
+ printf ("TxFreq: %d\n", MasterBlaster->testCtrl.TxFreq);
+ printf ("RxFreq: %d\n", MasterBlaster->testCtrl.RxFreq);
+ }
+ }
+ if (TpcTable.NumOfEntries > 0)
+ {
+ printf ("Power: Step = %d/%d; Level = %d dBm\n", MasterBlaster->testCtrl.Power+1,
+ TpcTable.NumOfEntries, TpcTable.t[MasterBlaster->testCtrl.Power].TxPowerLevel);
+ }
+ else
+ {
+ printf ("Power: Step = Max; Level = N/A\n");
+ }
+ if ((MasterBlaster->ContTxMode == ENABLE && ContTxTypeOption[MasterBlaster->ContTxType].Value == Cont_Tx_Regular) ||
+ (MasterBlaster->ContTxMode == DISABLE))
+ {
+ int index = GetPacketTypeOptionIndex(MasterBlaster->testCtrl.Packet);
+ if(index < 0){
+ printf("Unable to find the matching Packet Type Option Index! %d \n", MasterBlaster->testCtrl.Packet);
+ return;
+ }
+ printf ("PacketType: %s\n", PacketTypeOption[index].Name);
+ printf ("DataLen: %d\n", MasterBlaster->testCtrl.DataLen);
+ }
+ if (ContTxTypeOption[MasterBlaster->ContTxType].Value != CW_Single_Tone) {//for single tone, no bdaddr
+ ba2str((const bdaddr_t *)MasterBlaster->bdaddr, BdAddr);
+ printf ("BdAddr: 0x%s\n\n",BdAddr);
+ }
+ }
+ printf ("\nmb>\n");
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterTestMode(tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = (int)MasterBlaster->testCtrl.Mode;
+
+ if (ToggleOption (&Value, Option, TestModeOption,
+ sizeof(TestModeOption)/sizeof(tMasterBlasterOption), TM,1))
+ {
+ MasterBlaster->testCtrl.Mode = (UCHAR)Value;
+ // Enable continous Tx should disable continous Rx
+ MasterBlaster->ContRxMode = DISABLE;
+ MasterBlaster->ContTxMode = DISABLE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterHopMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = (int)MasterBlaster->testCtrl.HopMode;
+
+ if (ToggleOption (&Value, Option, HopModeOption,
+ sizeof(HopModeOption)/sizeof(tMasterBlasterOption), HM,1))
+ {
+ MasterBlaster->testCtrl.HopMode = (UCHAR)Value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterTxFreq (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ //char Buffer[20];
+ tMasterBlasterOption NewValue;
+ int LoopCount = 4;
+ int Value = (int)MasterBlaster->testCtrl.TxFreq;
+ int MaxFreq = LEMode ? MB_MAX_FREQUENCY_LE : MB_MAX_FREQUENCY;
+ int MinFreq = LEMode ? MB_MIN_FREQUENCY_LE : MB_MIN_FREQUENCY;
+
+ UNUSED(Option);
+ while (--LoopCount > 0)
+ {
+ printf ("\n Enter Tx frequency (%d..%d): ", MinFreq, MaxFreq);
+ scanf("%d",&NewValue.Value);
+ // fgets(NewValue,3,stdin);
+ if (MinMaxOption (&Value, &NewValue, MinFreq, MaxFreq))
+ {
+ MasterBlaster->testCtrl.TxFreq = (UCHAR)Value;
+ return TRUE;
+ }
+ else if (LoopCount > 1)
+ {
+ printf ("\n ERROR ---> Invalid Tx frequency.\n");
+ }
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterRxFreq (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ tMasterBlasterOption NewValue;
+ int LoopCount = 4;
+ int Value = (int)MasterBlaster->testCtrl.RxFreq;
+ int MaxFreq = LEMode ? MB_MAX_FREQUENCY_LE : MB_MAX_FREQUENCY;
+ int MinFreq = LEMode ? MB_MIN_FREQUENCY_LE : MB_MIN_FREQUENCY;
+
+ UNUSED(Option);
+ while (--LoopCount > 0)
+ {
+ printf ("\n Enter Rx frequency (%d..%d): ", MinFreq, MaxFreq);
+ scanf("%d",&NewValue.Value);
+ if (MinMaxOption (&Value, &NewValue, MinFreq, MaxFreq))
+ {
+ MasterBlaster->testCtrl.RxFreq = (UCHAR)Value;
+ return TRUE;
+ }
+ else if (LoopCount > 1)
+ {
+ printf ("\n ERROR ---> Invalid Rx frequency.\n");
+ }
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterPacketType (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = (int)MasterBlaster->testCtrl.Packet;
+
+ if (ToggleOption (&Value, Option, PacketTypeOption,
+ sizeof(PacketTypeOption)/sizeof(tMasterBlasterOption), PT,1))
+ {
+ MasterBlaster->testCtrl.Packet = (UCHAR)Value;
+ int index = GetPacketTypeOptionIndex(Value);
+ if(index<0){
+ printf("Fail to Get Packet Type Option Index Value(%d) Index(%d)\n", Value, index);
+ return FALSE;
+ }
+ MasterBlaster->testCtrl.DataLen = MaxDataLenOption[index];
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterDataLen (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ tMasterBlasterOption NewValue;
+ int LoopCount = 4;
+ int MaxLen = LEMode ? MB_MAX_DATALEN_LE : MB_MAX_DATALEN;
+ int MinLen = LEMode ? MB_MIN_DATALEN_LE : MB_MIN_DATALEN;
+
+ UNUSED(Option);
+ while (--LoopCount > 0)
+ {
+ printf ("\n Enter data length (%d..%d): ", MinLen, MaxLen);
+ scanf("%d",&NewValue.Value);
+ if (MinMaxOption (&MasterBlaster->testCtrl.DataLen, &NewValue, MinLen, MaxLen))
+ {
+ return TRUE;
+ }
+ else if (LoopCount > 1)
+ {
+ printf ("\n ERROR ---> Invalid data length.\n");
+ }
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterPower (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ char *opt = (char*)Option;
+
+ if (TpcTable.NumOfEntries > MAX_TRANSMIT_POWER_CONTROL_ENTRIES)
+ {
+ printf ("\nNumber of entries in TPC table exceeds the limit.\n");
+ sleep(3);
+ return TRUE;
+ }
+
+ if (TpcTable.NumOfEntries == 0)
+ {
+ printf ("\nThere is no entry in TPC table.\n");
+ sleep(3);
+ return TRUE;
+ }
+
+ int Value = (int)MasterBlaster->testCtrl.Power;
+
+ if (ToggleMinMaxOption (&Value, opt, PO, 0, TpcTable.NumOfEntries-1,1))
+ {
+ MasterBlaster->testCtrl.Power = (UCHAR)Value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterBdAddr (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ char Buffer[20];
+ bdaddr_t bdaddr;
+ UNUSED(Option);
+ printf ("\n Enter BdAddr: ");
+ // gets(Buffer);
+ scanf("%s",Buffer);
+ str2ba(Buffer,&bdaddr);
+ memcpy(MasterBlaster->bdaddr,bdaddr.b,6);
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterContTxMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = (int)MasterBlaster->ContTxMode;
+
+ if (ToggleOption (&Value, Option, ContTxModeOption,
+ sizeof(ContTxModeOption)/sizeof(tMasterBlasterOption), CT,1))
+ {
+ MasterBlaster->ContTxMode = (UCHAR)Value;
+ if (MasterBlaster->ContTxMode == ENABLE)
+ {
+ // Enable continous Tx should disable continous Rx
+ MasterBlaster->ContRxMode = DISABLE;
+ MasterBlaster->LERxMode = DISABLE;
+ MasterBlaster->LETxMode = DISABLE;
+ LEMode = FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterContTxType (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = (int)MasterBlaster->ContTxType;
+
+ if (ToggleOption (&Value, Option, ContTxTypeOption,
+ sizeof(ContTxTypeOption)/sizeof(tMasterBlasterOption), CX,1))
+ {
+ MasterBlaster->ContTxType = (UCHAR)Value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterLERxMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = MasterBlaster->LERxMode;
+
+ if (ToggleOption (&Value, Option, ContRxModeOption,
+ sizeof(ContRxModeOption)/sizeof(tMasterBlasterOption), LR, 1))
+ {
+ MasterBlaster->LERxMode = (UCHAR)Value;
+ if (MasterBlaster->LERxMode == ENABLE)
+ {
+ /* Enable continous Tx should disable other modes */
+ MasterBlaster->LETxMode = DISABLE;
+ MasterBlaster->ContTxMode = DISABLE;
+ MasterBlaster->ContRxMode = DISABLE;
+ if (MasterBlaster->testCtrl.RxFreq > 39)
+ {
+ MasterBlaster->testCtrl.RxFreq = 39;
+ }
+ LEMode = TRUE;
+ }
+ else
+ {
+ LEMode = FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterLETxMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = MasterBlaster->LETxMode;
+
+ if (ToggleOption (&Value, Option, ContTxModeOption,
+ sizeof(ContTxModeOption)/sizeof(tMasterBlasterOption), LT, 1))
+ {
+ MasterBlaster->LETxMode = (UCHAR)Value;
+ if (MasterBlaster->LETxMode == ENABLE)
+ {
+ /* Enable continous Tx should disable other modes */
+ MasterBlaster->LERxMode = DISABLE;
+ MasterBlaster->ContTxMode = DISABLE;
+ MasterBlaster->ContRxMode = DISABLE;
+ if (MasterBlaster->testCtrl.TxFreq > MB_MAX_FREQUENCY_LE)
+ {
+ MasterBlaster->testCtrl.TxFreq = 39;
+ }
+ LEMode = TRUE;
+ }
+ else
+ {
+ LEMode = FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterLETxPktPayload(tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = MasterBlaster->LETxParms.PktPayload;
+
+ if (ToggleOption(&Value, Option, LETxPktPayloadOption,
+ sizeof(LETxPktPayloadOption)/sizeof(tMasterBlasterOption), LTM, 1))
+ {
+ MasterBlaster->LETxParms.PktPayload = (UCHAR)Value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterContRxMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = (int)MasterBlaster->ContRxMode;
+ printf("\n N op\n");
+ if (ToggleOption (&Value, Option, ContRxModeOption,
+ sizeof(ContRxModeOption)/sizeof(tMasterBlasterOption), CR,1))
+ {
+ MasterBlaster->ContRxMode = (UCHAR)Value;
+ if (MasterBlaster->ContRxMode == ENABLE)
+ {
+ // Enable continous Tx should disable continous Rx
+ MasterBlaster->ContTxMode = DISABLE;
+ MasterBlaster->LERxMode = DISABLE;
+ MasterBlaster->LETxMode = DISABLE;
+ LEMode = FALSE;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+int SetMasterBlasterBERType (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ int Value = (int)MasterBlaster->BERType;
+ if (ToggleOption (&Value, Option, BERPacketTypeOption,
+ sizeof(BERPacketTypeOption)/sizeof(tMasterBlasterOption), SB, 1))
+ {
+ MasterBlaster->BERType = (UCHAR)Value;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int SetMasterBlasterNothing (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option)
+{
+ UNUSED(MasterBlaster);
+ UNUSED(Option);
+
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+
+int ToggleOption (int *Value, tMasterBlasterOption *Option, tMasterBlasterOption *OptionArray,
+ int Size, int FieldID, int Step)
+{
+ char Opt = Option->Name[0];
+
+ int Backward = ((Opt - 'A' + 'a') == MasterBlasterMenu[FieldID].Alias[0]);
+ int i;
+ for (i = 0; i < Size; ++i)
+ {
+ if (*Value == OptionArray[i].Value)
+ {
+ if (Backward)
+ {
+ i = ((i - Step) < 0) ? (Size - Step + i) : (i - Step);
+ }
+ else
+ {
+ i = (i + Step) % Size;
+ }
+ *Value = OptionArray[i].Value;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+//----------------------------------------------------------------------------
+
+int MinMaxOption (int *Value, tMasterBlasterOption *Option, int Min, int Max)
+{
+ int NewValue = Option->Value;
+
+ if (NewValue < Min || NewValue > Max)
+ {
+ return FALSE;
+ }
+ *Value = NewValue;
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+
+int ToggleMinMaxOption (int *Value, char *Option, int FieldID, int Min, int Max, int Step)
+{
+ char Opt = *Option;
+ int Backward = ((Opt - 'A' + 'a') == MasterBlasterMenu[FieldID].Alias[0]);
+
+ if (Backward)
+ {
+ *Value = ((*Value - Step) < Min) ? (Max + 1 - (Step - (*Value - Min))) : (*Value - Step);
+ }
+ else
+ {
+ *Value = ((*Value + Step) > Max) ? (Min + (Step - (Max + 1 - *Value))) : (*Value + Step);
+ }
+ return TRUE;
+
+}
+
+//----------------------------------------------------------------------------
+
diff --git a/tools/btconfig/btconfig.h b/tools/btconfig/btconfig.h
new file mode 100644
index 0000000..18c856a
--- /dev/null
+++ b/tools/btconfig/btconfig.h
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2013,2016 The Linux Foundation. All rights reserved.
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef _BTCONFIG_H_
+#define _BTCONFIG_H_
+#define VERSION "2.14"
+//#define DUMP_DEBUG 1
+//#define DEBUG 1 // @@ boyi @@
+#ifdef ANDROID
+#define FW_PATH_AR "/etc/firmware/ar3k/"
+#else
+#define FW_PATH_AR "/lib/firmware/ar3k/"
+#endif
+#define BDADDR_FILE "ar3kbdaddr.pst"
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+#define PATCH_FILE "RamPatch.txt"
+#define ROM_DEV_TYPE 0xdeadc0de
+#define FPGA_ROM_VERSION 0x99999999
+
+#define PS_RAM_SIZE 2048
+#define TRUE 1
+#define FALSE 0
+#define LINE_SIZE_MAX 3000
+#define PS_RESET 2
+
+#define PS_WRITE 1
+#define HCI_PS_CMD_HDR_LEN 7
+
+#define PS_RESET_PARAM_LEN 6
+#define HCI_MAX_CMD_SIZE 260
+#define PS_RESET_CMD_LEN (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
+
+#define PS_ID_MASK 0xFF
+
+#define HCI_VENDOR_CMD_OGF 0x3F
+#define HCI_PS_CMD_OCF 0x0B
+#define HCI_CHG_BAUD_CMD_OCF 0x0C
+#define HCI_CMD_OGF_HOST_CTL 0x03
+#define HCI_CMD_OGF_INFO_PARAM 0x04
+
+#define HCI_CMD_OCF_RESET 0x0003
+#define HCI_CMD_OCF_READ_BD_ADDR 0x0009
+
+#define WRITE_BDADDR_CMD_LEN 14
+#define WRITE_BAUD_CMD_LEN 6
+#define MAX_CMD_LEN WRITE_BDADDR_CMD_LEN
+
+#define BD_ADDR_SIZE 6
+#define BD_ADDR_PSTAG 1
+#define PS_READ 0
+#define PS_READ_RAW 3
+
+#define WRITE_PATCH 8
+#define ENABLE_PATCH 11
+
+
+#define PS_WRITE_RAW 4
+#define PS_GET_LENGTH 5
+#define PS_SET_ACCESS_MODE 6
+#define PS_SET_ACCESS_PRIORITY 7
+#define PS_WRITE 1
+#define PS_DYNMEM_OVERRIDE 10
+#define PS_VERIFY_CRC 9
+#define CHANGE_BDADDR 15
+#define PS_COMMAND_HEADER 4
+#define HCI_EVENT_SIZE 7
+#define PS_RETRY_COUNT 3
+#define RAM_PS_REGION (1<<0)
+#define RAM_PATCH_REGION (1<<1)
+#define RAM_DYN_MEM_REGION (1<<2)
+#define RAMPS_MAX_PS_DATA_PER_TAG 244
+#define RAMPS_MAX_PS_TAGS_PER_FILE 50
+#define PSTAG_RF_TEST_BLOCK_START (300)
+#define PSTAG_SYSTEM_BLOCK_START (1)
+#define BT_SOC_INIT_TOOL_START_MAGIC_WORD 0xB1B1
+#define PSTAG_RF_PARAM_TABLE0 (PSTAG_RF_TEST_BLOCK_START+0)
+#define PSTAG_SYSCFG_PARAM_TABLE0 (PSTAG_SYSTEM_BLOCK_START+18)
+#define PATCH_MAX_LEN 20000
+#define DYN_MEM_MAX_LEN 40
+#define SKIP_BLANKS(str) while (*str == ' ') str++
+#define MAX_RADIO_CFG_TABLE_SIZE 1000
+#define MAX_BYTE_LENGTH 244
+#define DEBUG_EVENT_TYPE_PS 0x02
+#define DEBUG_EVENT_TYPE_MEMBLK 0x03
+#define HCI_EVENT_HEADER_SIZE 0x03
+#define HI_MAGIC_NUMBER ((const unsigned short int) 0xFADE)
+#define HI_VERSION (0x0300) //Version 3.0
+#define EEPROM_CONFIG 0x00020C00
+#define FPGA_REGISTER 0x4FFC
+#define MAX_EVENT_SIZE 260
+
+// Vendor specific command OCF
+#define OCF_PS 0x000B
+#define OCF_MEMOP 0x0014
+#define OGF_TEST_CMD 0x06
+#define OCF_HOST_INTEREST 0x000A
+#define OCF_CONT_TX_TESTER 0x0023
+#define OCF_TX_TESTER 0x001B
+#define OCF_SLEEP_MODE 0x0004
+#define OCF_READ_MEMORY 0x0005
+#define OCF_WRITE_MEMORY 0x0006
+#define OCF_DISABLE_TX 0x002D
+#define OCF_TEST_MODE_SEQN_TRACKING 0x0018
+#define OCF_READ_VERSION 0x001E
+#define OCF_AUDIO_CMD 0x0013
+#define OCF_GET_BERTYPE 0x005C
+#define OCF_RX_TESTER 0x005B
+
+#define UCHAR unsigned char
+#define BOOL unsigned short
+#define UINT16 unsigned short int
+#define UINT32 unsigned int
+#define SINT16 signed short int
+#define UINT8 unsigned char
+#define SINT8 signed char
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define htobs(d) (d)
+#define htobl(d) (d)
+#define btohs(d) (d)
+#define btohl(d) (d)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define htobs(d) bswap_16(d)
+#define htobl(d) bswap_32(d)
+#define btohs(d) bswap_16(d)
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define btohl(d) bswap_32(d)
+#else
+#error "Unknown byte order"
+#endif
+#define MAX_TAGS 50
+#define PS_HDR_LEN 4
+#define HCI_VENDOR_CMD_OGF 0x3F
+#define HCI_PS_CMD_OCF 0x0B
+#define PS_EVENT_LEN 100
+#define HCI_EV_SUCCESS 0x00
+
+#define BT_PORT 2398
+
+/* For ROME QCA61x4 chipset */
+#define EVT_VENDOR (0xFF)
+#define EVT_CMD_COMPLETE (0x0E)
+#define HCI_COMMAND_PKT (0x01)
+#define HCI_MAX_EVENT_SIZE (260)
+
+#define MAX_SIZE_PER_TLV_SEGMENT (243)
+#define EDL_PATCH_CMD_LEN (1)
+
+#define EDL_PATCH_VER_REQ_CMD (0x19)
+#define EDL_PATCH_TLV_REQ_CMD (0x1E)
+
+#define EDL_CMD_REQ_RES_EVT (0x00)
+#define EDL_PATCH_VER_RES_EVT (0x19)
+#define EDL_APP_VER_RES_EVT (0x02)
+#define EDL_TVL_DNLD_RES_EVT (0x04)
+#define EDL_CMD_EXE_STATUS_EVT (0x00)
+#define EDL_SET_BAUDRATE_RSP_EVT (0x92)
+#define EDL_NVM_ACCESS_CODE_EVT (0x0B)
+
+#define HCI_PATCH_CMD_OCF (0)
+
+#define FW_PATH_ROME "/lib/firmware/qca"
+#define FLOW_CTL (0x0001)
+#define BAUDRATE_CHANGE_SUCCESS (0x01)
+#define CC_MIN_SIZE (0x7)
+#define HCI_CMD_SUCCESS (0x0)
+
+enum qca_bardrate_type {
+ QCA_BAUDRATE_115200 = 0,
+ QCA_BAUDRATE_57600,
+ QCA_BAUDRATE_38400,
+ QCA_BAUDRATE_19200,
+ QCA_BAUDRATE_9600,
+ QCA_BAUDRATE_230400,
+ QCA_BAUDRATE_250000,
+ QCA_BAUDRATE_460800,
+ QCA_BAUDRATE_500000,
+ QCA_BAUDRATE_720000,
+ QCA_BAUDRATE_921600,
+ QCA_BAUDRATE_1000000,
+ QCA_BAUDRATE_1250000,
+ QCA_BAUDRATE_2000000,
+ QCA_BAUDRATE_3000000,
+ QCA_BAUDRATE_4000000,
+ QCA_BAUDRATE_1600000,
+ QCA_BAUDRATE_3200000,
+ QCA_BAUDRATE_3500000,
+ QCA_BAUDRATE_AUTO = 0xFE,
+ QCA_BAUDRATE_RESERVED
+};
+
+enum qca_tlv_type {
+ TLV_TYPE_PATCH = 1,
+ TLV_TYPE_NVM
+};
+
+struct patch_data {
+ int8_t type;
+ int64_t len;
+ uint8_t *data;
+};
+#ifndef ANDROID
+size_t
+strlcpy(char *dst, const char *src, size_t size)
+{
+ const char *s = src;
+ size_t n = size;
+
+ if (n && --n)
+ do {
+ if (!(*dst++ = *src++))
+ break;
+ } while (--n);
+
+ if (!n) {
+ if (size)
+ *dst = '\0';
+ while (*src++);
+ }
+ return src - s - 1;
+}
+#endif //strlcpy is present on the string.h on android but not on the x86. hence use this instead.
+typedef struct tPsTagEntry
+{
+ int TagId;
+ UCHAR TagLen;
+ UCHAR TagData[RAMPS_MAX_PS_DATA_PER_TAG];
+} tPsTagEntry, *tpPsTagEntry;
+
+typedef struct tRamPatch
+{
+ int Len;
+ UCHAR Data[PATCH_MAX_LEN];
+} tRamPatch, *ptRamPatch;
+
+typedef struct tRamDynMemOverride
+{
+ int Len;
+ UCHAR Data[DYN_MEM_MAX_LEN];
+} tRamDynMemOverride, *ptRamDynMemOverride;
+
+tPsTagEntry PsTagEntry[RAMPS_MAX_PS_TAGS_PER_FILE];
+tRamPatch RamPatch[50];
+tRamDynMemOverride RamDynMemOverride;
+
+enum MB_FILEFORMAT {
+ MB_FILEFORMAT_PS,
+ MB_FILEFORMAT_PATCH,
+ MB_FILEFORMAT_DY,
+};
+enum RamPsSection
+{
+ RAM_PS_SECTION,
+ RAM_PATCH_SECTION,
+ RAM_DYN_MEM_SECTION
+};
+
+enum eType {
+ eHex,
+ edecimal,
+};
+
+struct ST_PS_DATA_FORMAT {
+ enum eType eDataType;
+ BOOL bIsArray;
+};
+#define CONV_DEC_DIGIT_TO_VALUE(c) ((c) - '0')
+#define IS_HEX(c) (IS_BETWEEN((c), '0', '9') || IS_BETWEEN((c), 'a', 'f') || IS_BETWEEN((c), 'A', 'F'))
+#define IS_BETWEEN(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
+#define IS_DIGIT(c) (IS_BETWEEN((c), '0', '9'))
+#define CONV_HEX_DIGIT_TO_VALUE(c) (IS_DIGIT(c) ? ((c) - '0') : (IS_BETWEEN((c), 'A', 'Z') ? ((c) - 'A' + 10) : ((c) - 'a' + 10)))
+#define BYTES_OF_PS_DATA_PER_LINE 16
+struct ST_READ_STATUS {
+ unsigned uTagID;
+ unsigned uSection;
+ unsigned uLineCount;
+ unsigned uCharCount;
+ unsigned uByteCount;
+};
+
+//DUT MODE related
+#define MC_BCAM_COMPARE_ADDRESS 0x00008080
+#define HCI_3_PATCH_SPACE_LENGTH_1 (0x80)
+#define HCI_3_PATCH_SPACE_LENGTH_2 (0x279C)
+#define MEM_BLK_DATA_MAX (244)
+#define MC_BCAM_VALID_ADDRESS 0x00008100
+
+//Audio stat
+
+typedef struct tAudio_Stat {
+ UINT16 RxSilenceInsert;
+ UINT16 RxAirPktDump;
+ UINT16 RxCmplt;
+ UINT16 TxCmplt;
+ UINT16 MaxPLCGenInterval;
+ UINT16 RxAirPktStatusGood;
+ UINT16 RxAirPktStatusError;
+ UINT16 RxAirPktStatusLost;
+ UINT16 RxAirPktStatusPartial;
+ SINT16 SampleMin;
+ SINT16 SampleMax;
+ UINT16 SampleCounter;
+ UINT16 SampleStatEnable;
+} tAudioStat;
+
+//DMA stats
+
+typedef struct tBRM_Stats {
+ // DMA Stats
+ UINT32 DmaIntrs;
+
+ // Voice Stats
+ UINT16 VoiceTxDmaIntrs;
+ UINT16 VoiceTxErrorIntrs;
+ UINT16 VoiceTxDmaErrorIntrs;
+ UINT16 VoiceTxPktAvail;
+ UINT16 VoiceTxPktDumped;
+ UINT16 VoiceTxDmaSilenceInserts;
+
+ UINT16 VoiceRxDmaIntrs;
+ UINT16 VoiceRxErrorIntrs;
+ UINT16 VoiceRxGoodPkts;
+ UINT16 VoiceRxErrCrc;
+ UINT16 VoiceRxErrUnderOverFlow;
+ UINT16 VoiceRxPktDumped;
+
+ UINT16 VoiceTxReapOnError;
+ UINT16 VoiceRxReapOnError;
+ UINT16 VoiceSchedulingError;
+ UINT16 SchedOnVoiceError;
+
+ UINT16 Temp1;
+ UINT16 Temp2;
+
+ // Control Stats
+ UINT16 ErrWrongLlid;
+ UINT16 ErrL2CapLen;
+ UINT16 ErrUnderOverFlow;
+ UINT16 RxBufferDumped;
+ UINT16 ErrWrongLmpPktType;
+ UINT16 ErrWrongL2CapPktType;
+ UINT16 HecFailPkts;
+ UINT16 IgnoredPkts;
+ UINT16 CrcFailPkts;
+ UINT16 HwErrRxOverflow;
+
+ UINT16 CtrlErrNoLmpBufs;
+
+ // ACL Stats
+ UINT16 DataTxBuffers;
+ UINT16 DataRxBuffers;
+ UINT16 DataRxErrCrc;
+ UINT16 DataRxPktDumped;
+ UINT16 LmpTxBuffers;
+ UINT16 LmpRxBuffers;
+ UINT16 ForceOverQosJob;
+
+ // Sniff Stats
+ UINT16 SniffSchedulingError;
+ UINT16 SniffIntervalNoCorr;
+
+ // Test Mode Stats
+ UINT16 TestModeDroppedTxPkts;
+ UINT16 TestModeDroppedLmps;
+
+ // Error Stats
+ UINT16 TimePassedIntrs;
+ UINT16 NoCommandIntrs;
+
+} tBRM_Stats;
+
+typedef struct tSYSUTIL_ChipId {
+ char *pName;
+ UINT32 HwRev;
+} tSYSUTIL_ChipId;
+
+typedef struct tSU_RevInfo {
+ tSYSUTIL_ChipId *pChipId;
+ tSYSUTIL_ChipId *pChipRadioId;
+ UINT32 ChipRadioId;
+ UINT32 SubRadioId;
+ UINT32 RomVersion;
+ UINT32 RomBuildNumber;
+ UINT32 BuildVersion;
+ UINT32 BuildNumber;
+ UINT16 RadioFormat;
+ UINT16 RadioContent;
+ UINT16 SysCfgFormat;
+ UINT16 SysCfgContent;
+ UINT8 ProductId;
+} tSU_RevInfo;
+
+typedef struct {
+ UINT8 b[6];
+} __attribute__((packed)) bdaddr_t;
+
+typedef struct {
+ UINT16 opcode; /* OCF & OGF */
+ UINT8 plen;
+} __attribute__((packed)) hci_command_hdr;
+
+typedef struct {
+ UINT8 evt;
+ UINT8 plen;
+} __attribute__((packed)) hci_event_hdr;
+
+typedef struct {
+ UINT8 ncmd;
+ UINT16 opcode;
+} __attribute__ ((packed)) evt_cmd_complete;
+
+#define HCI_COMMAND_HEADER_SIZE 3
+#define HCI_OPCODE_PACK(ogf, ocf) (UINT16)((ocf & 0x03ff)|(ogf << 10))
+
+#endif
+
diff --git a/tools/btconfig/commands_btconfig.txt b/tools/btconfig/commands_btconfig.txt
new file mode 100644
index 0000000..4f585c1
--- /dev/null
+++ b/tools/btconfig/commands_btconfig.txt
@@ -0,0 +1,213 @@
+Command complete event
+[0]: 04
+[1]: 0E
+[2]: Following parameter length
+[3]: Number of HCI comand. Usually [01]
+[4]: OCF
+[5]: OGF
+[6]: Return status. [00] means successfully executed
+
+Master blaster mode
+[0] mb
+[1] cmd
+[2] power = 3
+[3] freq = 3
+[4] packet = DM1
+[5] {Tx|Rx}
+[6]
+
+btconfig /dev/ttyHS0 mb cmd 3 3 DM1 TX
+
+General format
+For ROME over UART: #btconfig <command , parameters >
+FOR smd based devices: #btconfig /dev/smd3 <command , parameters >
+
+==================RESET COMMAND=================
+127|root@android:/ # btconfig /dev/smd3 reset
+btconfig /dev/smd3 reset
+Done intiailizing fd = /dev/smd3
+ 03
+ 0c
+ 00
+
+*************Data read begin *************
+[e][4][1][3][c][0]
+*************Data read end **************
+
+HCI Reset Pass
+Reset Done
+==================================================
+
+
+================INQUIRY ==========================
+
+root@android:/ # btconfig /dev/smd3 hciinq 33 8b 9e 12 5
+btconfig /dev/smd3 hciinq 33 8b 9e 12 5
+Done intiailizing fd = /dev/smd3
+inq command ++ argc = 6 argv = 33 8b 9e 12 5
+
+INQUIRY:
+Command Status Received
+[f][4][0][1][1][4]
+INQ RESULT EVENT RECEIVED
+[2][f][1][4d][35][67][15][19][0][0][2][0][4][1][12][84][33]
+INQ RESULT EVENT RECEIVED
+[2][f][1][9b][92][64][15][19][0][1][2][0][8][4][34][36][2b]
+INQ RESULT EVENT RECEIVED
+[2][f][1][35][2][7d][8c][3][0][1][2][0][4][1][6e][65][39]
+INQ RESULT EVENT RECEIVED
+[2][f][1][50][60][89][c6][a0][0][1][2][0][c][2][5a][eb][4d]
+INQ RESULT EVENT RECEIVED
+[2][f][1][99][61][80][80][20][10][1][2][0][c][2][5c][84][40]
+INQ COMPLETE EVENT RECEIVED
+
+=================================================
+
+
+================READ BD ADDRESS ==================
+root@android:/ # btconfig /dev/smd3 rba
+btconfig /dev/smd3 rba
+Done intiailizing fd = /dev/smd3
+
+*************Data read begin *************
+[e][a][1][9][10][0][22][44][66][56][55][99]
+*************Data read end **************
+iRet: 12
+
+BD ADDRESS:
+99:55:56:66:44
+=================================================
+
+
+================WRITE BD ADDRESS ==================
+root@android:/ # btconfig /dev/smd3 wba 00:55:77:77:88:00
+btconfig /dev/smd3 wba 00:55:77:77:88:00
+Done intiailizing fd = /dev/smd3
+
+*************Data read begin *************
+[e][4][1][3][c][0]
+*************Data read end **************
+
+*************Data read begin *************
+[e][a][1][9][10][0][0][88][77][77][55][0]
+*************Data read end **************
+
+BD address changed
+=================================================
+
+
+
+================CREATE CONNECTION ==================
+root@android:/ # btconfig /dev/smd3 conn 00:15:83:64:B3:14
+btconfig /dev/smd3 conn 00:15:83:64:B3:14
+Done intiailizing fd = /dev/smd3
+
+ Connect test
+14:Command Status Received
+[f][4][0][1][5][4]
+Other event received, Breaking
+[12][8][0][14][b3][64][83][15][0][1]
+CONNECTION COMPLETE EVENT RECEIVED WITH HANDLE: 0x0001
+[3][b][0][1][0][14][b3][64][83][15][0][1][0]
+=================================================
+
+================DISCONNECTION REQ ==================
+root@android:/ # btconfig /dev/smd3 disc 0001 16
+btconfig /dev/smd3 disc 0001 16
+Done intiailizing fd = /dev/smd3
+
+HCI_Disconnect: Handle :0001 Reason Code: 0x16
+Command Status Received
+[f][4][0][1][6][4]
+DISCONNECTION COMPLETE EVENT RECEIVED WITH REASON CODE: 0x16
+[5][4][0][1][0][16]
+=================================================
+
+================SET EVENT FILTER ==================
+
+root@android:/ # btconfig /dev/smd3 hcisetevtflt 01 00
+btconfig /dev/smd3 hcisetevtflt 01 00
+Done intiailizing fd = /dev/smd3
+
+*************Data read begin *************
+[e][4][1][5][c][0]
+*************Data read end **************
+
+Set Event Filter
+=================================================
+
+
+================ENABLE DUT MODE =================
+root@android:/ # btconfig /dev/smd3 edutm
+btconfig /dev/smd3 edutm
+Done intiailizing fd = /dev/smd3
+
+*************Data read begin *************
+[e][4][1][1a][c][0]
+*************Data read end **************
+
+*************Data read begin *************
+[e][4][1][3][18][0]
+*************Data read end **************
+
+Device is in test mode ...
+
+=================================================
+
+================WRITE SCAN MODE =================
+root@android:/ # btconfig /dev/smd3 wsm
+btconfig /dev/smd3 wsm
+Done intiailizing fd = /dev/smd3
+
+Usage:
+
+ wsm [0|1|2|3]
+
+Example:
+ wsm 0 (Scan disabled)
+ wsm 1 (Inquiry scan enabled)
+ wsm 2 (Page scan enabled)
+ wsm 3 (Inquiry and Page scan enabled)
+
+root@android:/ # btconfig /dev/smd3 wsm 2
+btconfig /dev/smd3 wsm 2
+Done intiailizing fd = /dev/smd3
+
+*************Data read begin *************
+[e][4][1][1a][c][0]
+*************Data read end **************
+
+Scan Mode set to :2
+=================================================
+===========PIN CONNECTIVITY TEST=================
+Usage:
+pinconntest 0B
+
+root@android:/ # btconfig /dev/smd3 pinconntest 0B
+btconfig /dev/smd3 pinconntest 0B
+Done intiailizing fd = /dev/smd3
+
+
+PIN CONNECTIVITY TEST:
+Other event received, Breaking
+[e][f][1][c][fc][0][b][3][2][0][0][3][0][0][4][0][0]
+Other event received, Breaking
+[e][4][1][0][0][0]
+
+=================================================
+===========VENDOR SPECIFIC COMMAND===============
+usage:
+venspeccmd arg[1] arg[2] ........
+
+
+
+root@android:/ # btconfig /dev/smd3 venspeccmd 03
+btconfig /dev/smd3 venspeccmd 03
+Done intiailizing fd = /dev/smd3
+Vendor Specific command
+Other event received, Breaking
+[ff][5][0][0][0][8][3]
+Other event received, Breaking
+[e][4][1][0][0][0]
+Please note that
+
diff --git a/tools/btconfig/masterblaster.h b/tools/btconfig/masterblaster.h
new file mode 100644
index 0000000..2cd58a2
--- /dev/null
+++ b/tools/btconfig/masterblaster.h
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2013,2016 The Linux Foundation. All rights reserved.
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef _MASTERBLASTER_H_
+#define _MASTERBLASTER_H_
+#include "btconfig.h"
+
+#define INVALID_MASTERBLASTER_FIELD (-1)
+#define UNUSED(x) (x=x)
+// Bluetooth Packet Type Identifiers
+#define MAX_TRANSMIT_POWER_CONTROL_ENTRIES 15
+
+#define LC_JTAG_MODEM_REGS_ADDRESS 0x00020800
+#define AGC_BYPASS_ADDRESS 0x0000040c
+#define AGC_BYPASS_ENABLE_MASK 0x00000001
+#define AGC_BYPASS_ENABLE_LSB 0
+#define AGC_BYPASS_ENABLE_SET(x) (((x) << AGC_BYPASS_ENABLE_LSB) & AGC_BYPASS_ENABLE_MASK)
+#define LC_DEV_PARAM_CTL_ADDRESS 0x00020010
+#define LC_DEV_PARAM_CTL_FREQ_HOP_EN_MASK 0x00000001
+#define LC_DEV_PARAM_CTL_RX_FREQ_MASK 0x00007f00
+#define LC_DEV_PARAM_CTL_WHITEN_EN_MASK 0x00008000
+#define LC_DEV_PARAM_CTL_RX_FREQ_SET(x) (((x) << LC_DEV_PARAM_CTL_RX_FREQ_LSB) & LC_DEV_PARAM_CTL_RX_FREQ_MASK)
+#define LC_DEV_PARAM_CTL_RX_FREQ_LSB 8
+
+#define CORR_PARAM1_ADDRESS 0x00000048
+#define CORR_PARAM1_TIM_THR_MASK 0xfc000000
+#define CORR_PARAM1_TIM_THR_LSB 26
+#define CORR_PARAM1_TIM_THR_SET(x) (((x) << CORR_PARAM1_TIM_THR_LSB) & CORR_PARAM1_TIM_THR_MASK)
+
+typedef struct tBtHost_Interest {
+ UINT16 MagicNumber;
+ UINT16 Version;
+ UINT32 TraceDataAddr;
+ UINT32 GlobalDmaStats; // BRM Global DMA Statistics
+ UINT32 TpcTableAddr; // SysCfg Transmit power table
+ UINT32 AudioStatAddr;
+ UINT32 AudioInternalAddr;
+ UINT32 SysCfgAddr;
+ UINT32 ReservedRamAddr;
+ UINT32 HostConfigAddr;
+ UINT32 RamVersionAddr;
+ // Version 1.01
+ UINT32 BrmGlobalDataAddr; // BRM Global Context pointer
+ UINT32 LeGlobalDataAddr; // LE Global Context pointer
+ // Version 1.02
+ UINT32 MmGlobalDataAddr;
+} tBtHostInterest;
+
+typedef struct PsSysCfgTransmitPowerControlEntry {
+ SINT8 TxPowerLevel;
+ UINT32 RadioConfig;
+ UINT32 EdrRadioConfig;
+ SINT16 Slope;
+ SINT16 EdrSlope;
+ UINT8 TxFreqCorr;
+ UINT8 EdrTxFreqCorr;
+} tPsSysCfgTransmitPowerControlEntry;
+
+typedef struct PsSysCfgTransmitPowerControlTable {
+ int NumOfEntries;
+ tPsSysCfgTransmitPowerControlEntry t[MAX_TRANSMIT_POWER_CONTROL_ENTRIES];
+} tPsSysCfgTransmitPowerControlTable;
+typedef UCHAR tBRM_PktType;
+
+enum {
+ TxTest_PktType_NULL = 0x00,
+ TxTest_PktType_POLL = 0x01,
+ TxTest_PktType_FHS = 0x02,
+ TxTest_PktType_DM1 = 0x03,
+ TxTest_PktType_DH1 = 0x04,
+ TxTest_PktType_HV1 = 0x05,
+ TxTest_PktType_HV2 = 0x06,
+ TxTest_PktType_HV3 = 0x07,
+ TxTest_PktType_DV = 0x08,
+ TxTest_PktType_AUX1 = 0x09,
+ TxTest_PktType_DM3 = 0x0A,
+ TxTest_PktType_DH3 = 0x0B,
+ TxTest_PktType_DM5 = 0x0E,
+ TxTest_PktType_DH5 = 0x0F,
+ TxTest_PktType_2DH1 = 0x24,
+ TxTest_PktType_2DH3 = 0x2A,
+ TxTest_PktType_2DH5 = 0x2E,
+ TxTest_PktType_3DH1 = 0x28,
+ TxTest_PktType_3DH3 = 0x2B,
+ TxTest_PktType_3DH5 = 0x2F,
+ TxTest_PktType_Invalid = 0xff,
+};
+
+typedef UCHAR tBRM_eSCO_PktType;
+
+enum {
+ TxTest_PktType_EV3 = 0x17,
+ TxTest_PktType_EV4 = 0x1C,
+ TxTest_PktType_EV5 = 0x1D,
+ TxTest_PktType_2EV3 = 0x36,
+ TxTest_PktType_2EV5 = 0x3C,
+ TxTest_PktType_3EV3 = 0x37,
+ TxTest_PktType_3EV5 = 0x3D,
+};
+
+typedef UCHAR tBRM_PktMode;
+
+enum {
+ eBRM_Mode_Basic = 0,
+ eBRM_Mode_2Mbps = 2,
+ eBRM_Mode_3Mbps = 3
+};
+
+// tBRM_TestMode
+enum {
+ eBRM_TestMode_Pause = 0,
+ eBRM_TestMode_TX_0,
+ eBRM_TestMode_TX_1,
+ eBRM_TestMode_TX_1010,
+ eBRM_TestMode_TX_PRBS,
+ eBRM_TestMode_Loop_ACL,
+ eBRM_TestMode_Loop_SCO,
+ eBRM_TestMode_Loop_ACL_No_Whitening,
+ eBRM_TestMode_Loop_SCO_No_Whitening,
+ eBRM_TestMode_TX_11110000,
+ eBRM_TestMode_Rx,
+ eBRM_TestMode_Exit = 255,
+};
+enum {
+ Cont_Tx_Raw_1MHz = 0,
+ Cont_Tx_Raw_2MHz,
+ Cont_Tx_Raw_3MHz,
+ Cont_Tx_Regular,
+ CW_Single_Tone,
+};
+typedef UCHAR tBRM_TestMode;
+
+typedef struct tBRM_TestControl {
+ tBRM_TestMode Mode;
+ UCHAR HopMode;
+ UCHAR TxFreq;
+ UCHAR RxFreq;
+ UCHAR Power;
+// UCHAR PollPeriod;
+ UCHAR Packet;
+ UCHAR SkipRxSlot;
+ int DataLen;
+} tBRM_TestControl;
+
+typedef struct tLE_TxParms {
+ UCHAR PktPayload;
+} tLE_TxParms;
+
+typedef struct tBRM_Control_packet {
+ tBRM_TestControl testCtrl;
+ UCHAR bdaddr[6];
+ UCHAR ContTxMode; // Continuous TX Mode
+ UCHAR ContTxType;
+ UCHAR ContRxMode; // Continuous RX Mode
+ UCHAR BERType;
+ UCHAR LERxMode;
+ UCHAR LETxMode;
+ tLE_TxParms LETxParms;
+} tBRM_Control_packet;
+
+
+#define DM1_MAX_PAYLOAD 17
+#define DH1_MAX_PAYLOAD 27
+#define DM3_MAX_PAYLOAD 121
+#define DH3_MAX_PAYLOAD 183
+#define DM5_MAX_PAYLOAD 224
+#define DH5_MAX_PAYLOAD 339
+#define AUX1_MAX_PAYLOAD 29
+#define E2_DH1_MAX_PAYLOAD 54
+#define E2_DH3_MAX_PAYLOAD 367
+#define E2_DH5_MAX_PAYLOAD 679
+#define E3_DH1_MAX_PAYLOAD 83
+#define E3_DH3_MAX_PAYLOAD 552
+#define E3_DH5_MAX_PAYLOAD 1021
+
+enum E_MasterBlasterFieldID
+{
+ CR = 0,
+ CT,
+ LR,
+ LT,
+ LTM,
+ CX,
+ TM,
+ HM,
+ TF,
+ RF,
+ PT,
+ DL,
+ PO,
+ BA,
+ SB,
+ GB,
+ RX,
+ TX,
+ EN,
+ ST,
+ EX,
+ EXX,
+};
+
+enum E_MasterBlasterTestFlag
+{
+ MB_NO_TEST = 0,
+ MB_RX_TEST,
+ MB_TX_TEST,
+ MB_CONT_RX_TEST,
+ MB_CONT_TX_TEST,
+ MB_LE_RX_TEST,
+ MB_LE_TX_TEST,
+};
+
+enum E_DisableEnable
+{
+ DISABLE = 0,
+ ENABLE = 1,
+};
+
+#define MB_MIN_DATALEN 0
+#define MB_MAX_DATALEN 1021
+#define MB_MIN_FREQUENCY 0
+#define MB_MAX_FREQUENCY 79
+#define MB_MIN_FREQUENCY_LE 0
+#define MB_MAX_FREQUENCY_LE 39
+#define MB_MIN_DATALEN_LE 0
+#define MB_MAX_DATALEN_LE 37
+typedef struct STR_MasterBlasterOption
+{
+ char *Name;
+ int Value;
+} tMasterBlasterOption;
+
+typedef struct STR_MasterBlasterField
+{
+ char *Name;
+ char *Alias;
+ char *Usage;
+ int Default;
+ tMasterBlasterOption *Options;
+ int (*pFunc)(tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+} tMasterBlasterField;
+
+static tMasterBlasterOption TestModeOption[] =
+{
+ {"TX_0", eBRM_TestMode_TX_0},
+ {"TX_1", eBRM_TestMode_TX_1},
+ {"TX_1010", eBRM_TestMode_TX_1010},
+ {"TX_PRBS", eBRM_TestMode_TX_PRBS},
+ {"TX_11110000", eBRM_TestMode_TX_11110000},
+ {"RX", eBRM_TestMode_Rx},
+};
+
+static tMasterBlasterOption HopModeOption[] =
+{
+ {"Disable", DISABLE},
+ {"Enable", ENABLE},
+};
+
+static tMasterBlasterOption PacketTypeOption[] =
+{
+ {"DM1", TxTest_PktType_DM1},
+ {"DM3", TxTest_PktType_DM3},
+ {"DM5", TxTest_PktType_DM5},
+ {"DH1", TxTest_PktType_DH1},
+ {"DH3", TxTest_PktType_DH3},
+ {"DH5", TxTest_PktType_DH5},
+ {"2-DH1", TxTest_PktType_2DH1},
+ {"2-DH3", TxTest_PktType_2DH3},
+ {"2-DH5", TxTest_PktType_2DH5},
+ {"3-DH1", TxTest_PktType_3DH1},
+ {"3-DH3", TxTest_PktType_3DH3},
+ {"3-DH5", TxTest_PktType_3DH5},
+};
+
+static int MaxDataLenOption[] =
+{
+ DM1_MAX_PAYLOAD,
+ DM3_MAX_PAYLOAD,
+ DM5_MAX_PAYLOAD,
+ DH1_MAX_PAYLOAD,
+ DH3_MAX_PAYLOAD,
+ DH5_MAX_PAYLOAD,
+ E2_DH1_MAX_PAYLOAD,
+ E2_DH3_MAX_PAYLOAD,
+ E2_DH5_MAX_PAYLOAD,
+ E3_DH1_MAX_PAYLOAD,
+ E3_DH3_MAX_PAYLOAD,
+ E3_DH5_MAX_PAYLOAD,
+};
+
+enum {
+ eBRM_BERMode_ALL = 0, // ALL type
+ eBRM_BERMode_ALL_DATA, // All type except dm1,dm3,dm5
+ eBRM_BERMode_DM1,
+ eBRM_BERMode_DM3,
+ eBRM_BERMode_DM5,
+ eBRM_BERMode_DH1,
+ eBRM_BERMode_DH3,
+ eBRM_BERMode_DH5,
+ eBRM_BERMode_2DH1,
+ eBRM_BERMode_2DH3,
+ eBRM_BERMode_2DH5,
+ eBRM_BERMode_3DH1,
+ eBRM_BERMode_3DH3,
+ eBRM_BERMode_3DH5,
+};
+
+static tMasterBlasterOption BERPacketTypeOption[] =
+{
+ {"ALL", eBRM_BERMode_ALL},
+ {"ALL_DATA", eBRM_BERMode_ALL_DATA},
+ {"DM1", eBRM_BERMode_DM1},
+ {"DM3", eBRM_BERMode_DM3},
+ {"DM5", eBRM_BERMode_DM5},
+ {"DH1", eBRM_BERMode_DH1},
+ {"DH3", eBRM_BERMode_DH3},
+ {"DH5", eBRM_BERMode_DH5},
+ {"2DH1", eBRM_BERMode_2DH1},
+ {"2DH3", eBRM_BERMode_2DH3},
+ {"2DH5", eBRM_BERMode_2DH5},
+ {"3DH1", eBRM_BERMode_3DH1},
+ {"3DH3", eBRM_BERMode_3DH3},
+ {"3DH5", eBRM_BERMode_3DH5},
+};
+
+static tMasterBlasterOption ContTxModeOption[] =
+{
+ {"Disable", DISABLE},
+ {"Enable", ENABLE},
+};
+
+static tMasterBlasterOption ContTxTypeOption[] =
+{
+ {"Raw_1MHz", Cont_Tx_Raw_1MHz},
+ {"Raw_2MHz", Cont_Tx_Raw_2MHz},
+ {"Raw_3MHz", Cont_Tx_Raw_3MHz},
+ {"Regular_BT_Packet_Format", Cont_Tx_Regular},
+ {"CW_Single_Tone", CW_Single_Tone},
+};
+
+static tMasterBlasterOption ContRxModeOption[] =
+{
+ {"Disable", DISABLE},
+ {"Enable", ENABLE},
+};
+
+static tMasterBlasterOption LETxPktPayloadOption[] =
+{
+ {"Random_9", 0},
+ {"11110000", 1},
+ {"10101010", 2},
+ {"Random_15", 3},
+ {"11111111", 4},
+ {"00000000", 5},
+ {"00001111", 6},
+ {"01010101", 7},
+};
+
+//----------------------------------------------------------------------------
+// Prototypes
+//----------------------------------------------------------------------------
+
+void InitMasterBlaster (tBRM_Control_packet *MasterBlaster, bdaddr_t *BdAddr, UCHAR *SkipRxSlot);
+
+int CheckField (tBRM_Control_packet MasterBlaster, char *FieldAlias);
+int GetTestModeOptionIndex (int Mode);
+int GetPacketTypeOptionIndex (int PacketType);
+
+void PrintMasterBlasterMenu (tBRM_Control_packet *MasterBlaster);
+int SetMasterBlasterTestMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterHopMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterPacketType (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterTxFreq (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterRxFreq (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterPower (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterDataLen (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterBdAddr (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterContTxMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterContTxType (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterNothing (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterContRxMode (tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterLERxMode(tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterLETxMode(tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterLETxPktPayload(tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+int SetMasterBlasterBERType(tBRM_Control_packet *MasterBlaster, tMasterBlasterOption *Option);
+
+int ToggleOption (int *Value, tMasterBlasterOption *Option, tMasterBlasterOption *OptionArray,
+ int Size, int FieldID, int Step);
+int MinMaxOption (int *Value, tMasterBlasterOption *Option, int Min, int Max);
+int ToggleMinMaxOption (int *Value, char *Option, int FieldID, int Min, int Max, int Step);
+
+//----------------------------------------------------------------------------
+// Variables
+//----------------------------------------------------------------------------
+
+extern tMasterBlasterField MasterBlasterMenu[];
+extern tPsSysCfgTransmitPowerControlTable TpcTable;
+
+#endif // _MASTERBLASTER_H_
+
diff --git a/tools/hidl_client/Android.mk b/tools/hidl_client/Android.mk
new file mode 100644
index 0000000..8dab06a
--- /dev/null
+++ b/tools/hidl_client/Android.mk
@@ -0,0 +1,31 @@
+LOCAL_PATH:= $(call my-dir)
+
+
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ src/hidl_client.cpp \
+ src/client_reader.cpp
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/inc
+
+LOCAL_CFLAGS += -Wno-unused-variable
+LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wno-macro-redefined
+
+LOCAL_MODULE:= libbt-hidlclient
+LOCAL_MODULE_SUFFIX:= .so
+LOCAL_SHARED_LIBRARIES += libutils
+LOCAL_SHARED_LIBRARIES += libhidlbase
+LOCAL_SHARED_LIBRARIES += libhidltransport
+LOCAL_SHARED_LIBRARIES += android.hardware.bluetooth@1.0
+LOCAL_SHARED_LIBRARIES += com.qualcomm.qti.ant@1.0
+LOCAL_SHARED_LIBRARIES += vendor.qti.hardware.fm@1.0
+LOCAL_SHARED_LIBRARIES += liblog
+
+LOCAL_MODULE_PATH_32 := $(TARGET_OUT_VENDOR)/lib
+LOCAL_MODULE_PATH_64 := $(TARGET_OUT_VENDOR)/lib64
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tools/hidl_client/inc/hci_internals.h b/tools/hidl_client/inc/hci_internals.h
new file mode 100644
index 0000000..160794c
--- /dev/null
+++ b/tools/hidl_client/inc/hci_internals.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+
+// HCI UART transport packet types (Volume 4, Part A, 2)
+
+#define BT_PACKET_TYPE_UNKNOWN 0
+#define BT_PACKET_TYPE_COMMAND 1
+#define BT_PACKET_TYPE_ACL_DATA 2
+#define BT_PACKET_TYPE_SCO_DATA 3
+#define BT_PACKET_TYPE_EVENT 4
+#define ANT_PACKET_TYPE_CTRL 0x0c
+#define ANT_PACKET_TYPE_DATA 0x0e
+#define FM_PACKET_TYPE_CMD 0x11
+#define FM_PACKET_TYPE_EVENT 0x14
+
+// Re-run |fn| system call until the system call doesn't cause EINTR.
+#define CLIENT_NO_INTR(fn) do {} while ((fn) == -1 && errno == EINTR)
+
+#define LOG_TAG "bt_hidl_client"
+
+// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
+const int BT_COMMAND_PREAMBLE_SIZE = 3;
+const int BT_LENGTH_OFFSET_CMD = 2;
+
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.2)
+const int BT_ACL_PREAMBLE_SIZE = 4;
+const int BT_LENGTH_OFFSET_ACL = 2;
+
+// 2 bytes for handle, 1 byte for data length (Volume 2, Part E, 5.4.3)
+const int BT_SCO_PREAMBLE_SIZE = 3;
+const int BT_LENGTH_OFFSET_SCO = 2;
+
+// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
+const int BT_EVENT_PREAMBLE_SIZE = 2;
+const int BT_LENGTH_OFFSET_EVT = 1;
+
+const int ANT_COMMAND_PREAMBLE_SIZE = 1;
+const int ANT_LENGTH_OFFSET_CMD = 0;
+
+const int FM_COMMAND_PREAMBLE_SIZE = 3;
+const int FM_LENGTH_OFFSET_CMD = 2;
+
+const int FM_EVENT_PREAMBLE_SIZE = 2;
+const int FM_LENGTH_OFFSET_EVT = 1;
+
+const int PREAMBLE_SIZE_MAX = BT_ACL_PREAMBLE_SIZE;
+
diff --git a/tools/hidl_client/inc/hidl_client.h b/tools/hidl_client/inc/hidl_client.h
new file mode 100644
index 0000000..0cb7285
--- /dev/null
+++ b/tools/hidl_client/inc/hidl_client.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+bool hidl_client_initialize(int mode, int *tools_fd);
+void hidl_client_close();
+
+#ifdef __cplusplus
+}
+#endif
+
+#define MODE_BT (0)
+#define MODE_ANT (1)
+#define MODE_FM (2)
+
diff --git a/tools/hidl_client/src/client_reader.cpp b/tools/hidl_client/src/client_reader.cpp
new file mode 100644
index 0000000..d904c61
--- /dev/null
+++ b/tools/hidl_client/src/client_reader.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+
+#include <com/qualcomm/qti/ant/1.0/IAntHci.h>
+#include <com/qualcomm/qti/ant/1.0/IAntHciCallbacks.h>
+#include <com/qualcomm/qti/ant/1.0/types.h>
+
+#include <vendor/qti/hardware/fm/1.0/IFmHci.h>
+#include <vendor/qti/hardware/fm/1.0/IFmHciCallbacks.h>
+#include <vendor/qti/hardware/fm/1.0/types.h>
+
+#include <sys/socket.h>
+#include <cutils/sockets.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <utils/Log.h>
+#include <sys/select.h>
+#include "hci_internals.h"
+
+using android::hardware::bluetooth::V1_0::IBluetoothHci;
+using ::android::hardware::hidl_vec;
+using com::qualcomm::qti::ant::V1_0::IAntHci;
+using vendor::qti::hardware::fm::V1_0::IFmHci;
+
+extern android::sp<IBluetoothHci> btHci;
+extern android::sp<IAntHci> antHci;
+extern android::sp<IFmHci> fmHci;
+
+extern int server_fd;
+
+static int get_preamble_length(char packet_type);
+static int get_pkt_len_offset(char packet_type);
+static int get_payload_len(char packet_type, unsigned char *preamble);
+static int safe_read(int server_fd, unsigned char* buf, int read_len);
+
+void *process_tool_data(void *arg) {
+
+ int retval;
+ int preamble_len, payload_len;
+ unsigned char preamble[PREAMBLE_SIZE_MAX];
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(server_fd, &readfds);
+ unsigned char packet_type;
+
+ hidl_vec<uint8_t> *data;
+ data = new hidl_vec<uint8_t>;
+
+ do {
+ retval = select(server_fd + 1, &readfds, NULL, NULL, NULL);
+ if (retval == -1) {
+ ALOGE("select failed, Error: %s (%d)\n", strerror(errno),
+ errno);
+ break;
+ }
+
+ if (safe_read(server_fd, &packet_type, 1) == -1) {
+ ALOGE("%s: failed to read the packet from tools", __func__);
+ break;
+ }
+ ALOGI("%s: Packet type :%d", __func__,packet_type);
+ if ((preamble_len = get_preamble_length(packet_type))== -1) {
+ ALOGE("%s: Unsupported preamble_len packet type %d",__func__, packet_type);
+ break;
+ }
+ if (safe_read(server_fd, preamble, preamble_len) == -1) {
+ ALOGE("%s: failed to read the packet from tools", __func__);
+ break;
+ }
+ if ((payload_len = get_payload_len(packet_type, preamble)) == -1) {
+ ALOGE("%s: Invalid payload length ", __func__);
+ break;
+ }
+ data->resize(preamble_len + payload_len);
+ memcpy(data->data(), preamble, preamble_len);
+ if (safe_read(server_fd, data->data() + preamble_len, payload_len) == -1) {
+ ALOGE("%s: failed to read the packet from tool", __func__);
+ break;
+ }
+ switch (packet_type) {
+ case BT_PACKET_TYPE_COMMAND:
+ btHci->sendHciCommand(*data);
+ break;
+
+ case BT_PACKET_TYPE_ACL_DATA:
+ btHci->sendAclData(*data);
+ break;
+
+ case BT_PACKET_TYPE_SCO_DATA:
+ btHci->sendScoData(*data);
+ break;
+
+ case ANT_PACKET_TYPE_CTRL:
+ antHci->sendAntControl(*data);
+ break;
+
+ case ANT_PACKET_TYPE_DATA:
+ antHci->sendAntData(*data);
+ break;
+
+ case FM_PACKET_TYPE_CMD:
+ ALOGI("%s: Send FM Cmd ", __func__);
+ fmHci->sendHciCommand(*data);
+ break;
+ default:
+ ALOGE("%s: Unsupported packet type: %d", __func__, packet_type);
+ }
+ } while (1);
+ free(data);
+ return NULL;
+}
+
+static int get_preamble_length(char packet_type) {
+
+ int preamble_len = -1;
+ switch (packet_type) {
+ case BT_PACKET_TYPE_COMMAND:
+ preamble_len = BT_COMMAND_PREAMBLE_SIZE;
+ break;
+
+ case BT_PACKET_TYPE_ACL_DATA:
+ preamble_len = BT_ACL_PREAMBLE_SIZE;
+ break;
+
+ case BT_PACKET_TYPE_SCO_DATA:
+ preamble_len = BT_SCO_PREAMBLE_SIZE;
+ break;
+
+ case BT_PACKET_TYPE_EVENT:
+ preamble_len = BT_EVENT_PREAMBLE_SIZE;
+ break;
+
+ case ANT_PACKET_TYPE_CTRL:
+ preamble_len = ANT_COMMAND_PREAMBLE_SIZE;
+ break;
+
+ case ANT_PACKET_TYPE_DATA:
+ preamble_len = ANT_COMMAND_PREAMBLE_SIZE;
+ break;
+
+ case FM_PACKET_TYPE_CMD:
+ preamble_len = FM_COMMAND_PREAMBLE_SIZE;
+ break;
+
+ case FM_PACKET_TYPE_EVENT:
+ preamble_len = FM_EVENT_PREAMBLE_SIZE;
+ break;
+
+ default:
+ break;
+ }
+ return preamble_len;
+};
+
+static int get_pkt_len_offset(char packet_type) {
+
+ int len_offset = -1;
+ switch (packet_type) {
+ case BT_PACKET_TYPE_COMMAND:
+ len_offset = BT_LENGTH_OFFSET_CMD;
+ break;
+
+ case BT_PACKET_TYPE_ACL_DATA:
+ len_offset = BT_LENGTH_OFFSET_ACL;
+ break;
+
+ case BT_PACKET_TYPE_SCO_DATA:
+ len_offset = BT_LENGTH_OFFSET_SCO;
+ break;
+
+ case BT_PACKET_TYPE_EVENT:
+ len_offset = BT_LENGTH_OFFSET_EVT;
+ break;
+
+ case ANT_PACKET_TYPE_CTRL:
+ len_offset = ANT_LENGTH_OFFSET_CMD;
+ break;
+
+ case ANT_PACKET_TYPE_DATA:
+ len_offset = ANT_LENGTH_OFFSET_CMD;
+ break;
+
+ case FM_PACKET_TYPE_CMD:
+ len_offset = FM_LENGTH_OFFSET_CMD;
+ break;
+
+ case FM_PACKET_TYPE_EVENT:
+ len_offset = FM_LENGTH_OFFSET_EVT;
+ break;
+
+ default:
+ break;
+ }
+ return len_offset;
+}
+
+static int get_payload_len(char packet_type, unsigned char *preamble) {
+
+ int len_offset;
+ if ((len_offset = get_pkt_len_offset(packet_type)) == -1) {
+ ALOGE("%s: Unsupported packet type, failed to get length", __func__);
+ return len_offset;
+ }
+
+ if (packet_type != BT_PACKET_TYPE_ACL_DATA) return preamble[len_offset];
+ return (((preamble[len_offset + 1]) << 8) | preamble[len_offset]);
+}
+
+static int safe_read(int server_fd, unsigned char* buf, int read_len) {
+
+ int bytes_read = 0;
+ int ret = 0;
+
+ if (buf == NULL) {
+ ALOGE("%s: The buffer is NULL", __func__);
+ return -1;
+ }
+
+ if (!read_len) {
+ ALOGE("%s: No data to read", __func__);
+ return 0;
+ }
+
+ while (read_len > 0) {
+ CLIENT_NO_INTR(ret = read(server_fd, buf+bytes_read, read_len));
+ if (ret < 0) {
+ ALOGE("%s: Read error: (%s)", __func__, strerror(errno));
+ return -1;
+ } else if (ret == 0) {
+ ALOGE("%s: read returned 0, err = %s, read bytes: %d",
+ __func__, strerror(errno), (unsigned int)(bytes_read));
+ return -1;
+ } else {
+ read_len -= ret;
+ bytes_read += ret;
+ }
+ }
+ return bytes_read;
+}
diff --git a/tools/hidl_client/src/hidl_client.cpp b/tools/hidl_client/src/hidl_client.cpp
new file mode 100644
index 0000000..f73edfb
--- /dev/null
+++ b/tools/hidl_client/src/hidl_client.cpp
@@ -0,0 +1,440 @@
+/******************************************************************************
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+#include "android/hardware/bluetooth/1.0/IBluetoothHci.h"
+#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
+#include <android/hardware/bluetooth/1.0/types.h>
+#include <hwbinder/ProcessState.h>
+
+#include <com/qualcomm/qti/ant/1.0/IAntHci.h>
+#include <com/qualcomm/qti/ant/1.0/IAntHciCallbacks.h>
+#include <com/qualcomm/qti/ant/1.0/types.h>
+
+
+#include <vendor/qti/hardware/fm/1.0/IFmHci.h>
+#include <vendor/qti/hardware/fm/1.0/IFmHciCallbacks.h>
+#include <vendor/qti/hardware/fm/1.0/types.h>
+
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <utils/Log.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include "hidl_client.h"
+#include "hci_internals.h"
+
+using android::hardware::bluetooth::V1_0::IBluetoothHci;
+using android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
+using android::hardware::bluetooth::V1_0::HciPacket;
+using android::hardware::bluetooth::V1_0::Status;
+
+using com::qualcomm::qti::ant::V1_0::IAntHci;
+using com::qualcomm::qti::ant::V1_0::IAntHciCallbacks;
+
+using vendor::qti::hardware::fm::V1_0::IFmHci;
+using vendor::qti::hardware::fm::V1_0::IFmHciCallbacks;
+
+using android::hardware::ProcessState;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+
+extern void initialization_complete();
+extern void *process_tool_data(void *arg);
+static int safe_write(int server_fd, unsigned char* buf, int write_len);
+
+static pthread_t client_rthread;
+
+#define BT_CMD_PACKET_TYPE 0x01
+#define BT_ACL_PACKET_TYPE 0x02
+#define BT_SCO_PACKET_TYPE 0x03
+#define BT_EVT_PACKET_TYPE 0x04
+
+#define ANT_CTRL_PACKET_TYPE 0x0c
+#define ANT_DATA_PACKET_TYPE 0x0e
+
+#define FM_CMD_PACKET_TYPE 0x11
+#define FM_EVT_PACKET_TYPE 0x14
+
+#define INVALID_FD (-1)
+
+static sem_t s_cond;
+static int mode_type;
+static volatile bool hidl_init = false;
+int server_fd = -1;
+int client_fd = -1;
+
+android::sp<IBluetoothHci> btHci;
+android::sp<IAntHci> antHci;
+android::sp<IFmHci> fmHci;
+
+class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
+
+ public:
+ Return<void> initializationComplete(Status status) {
+ if (status == Status::SUCCESS) {
+ hidl_init = true;
+ } else {
+ ALOGE("Error in HIDL initialization");
+ }
+ sem_post(&s_cond);
+ return Void();
+ }
+
+ Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+ int len = static_cast<int>(event.size());
+ unsigned char val = BT_EVT_PACKET_TYPE;
+ if (safe_write(server_fd, &val, 1) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+
+ if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+ return Void();
+ }
+
+ Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
+ int len = static_cast<int>(data.size());
+ unsigned char val = BT_ACL_PACKET_TYPE;
+ if (safe_write(server_fd, &val, 1) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+
+ if (safe_write(server_fd, const_cast<unsigned char*>(data.data()), len) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+ return Void();
+ }
+
+ Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
+ int len = static_cast<int>(data.size());
+ unsigned char val = BT_SCO_PACKET_TYPE;
+ if (safe_write(server_fd, &val, 1) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+
+ if (safe_write(server_fd, const_cast<unsigned char*>(data.data()), len) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+ return Void();
+ }
+};
+
+namespace
+{
+using com::qualcomm::qti::ant::V1_0::AntPacket;
+using com::qualcomm::qti::ant::V1_0::Status;
+
+class AntHciCallbacks : public IAntHciCallbacks {
+ public:
+ AntHciCallbacks() {};
+ virtual ~AntHciCallbacks() = default;
+
+ Return<void> initializationComplete(Status status)
+ {
+ ALOGI("%s: start ", __func__);
+ if (status == Status::SUCCESS) {
+ hidl_init = true;
+ } else {
+ ALOGE("Error in HIDL initialization");
+ }
+ sem_post(&s_cond);
+ ALOGI("%s:end", __func__);
+ return Void();
+ }
+
+ Return<void> antControlReceived(const hidl_vec<uint8_t>& event)
+ {
+ int len = static_cast<int>(event.size());
+ unsigned char val = ANT_CTRL_PACKET_TYPE;
+ if (safe_write(server_fd, &val, 1) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+ if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+ return Void();
+ }
+
+ Return<void> antDataReceived(const hidl_vec<uint8_t>& event)
+ {
+ int len = static_cast<int>(event.size());
+ unsigned char val = ANT_DATA_PACKET_TYPE;
+ if (safe_write(server_fd, &val, 1) == -1) {
+ return Void();
+ }
+ if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+ return Void();
+ }
+};
+
+namespace
+{
+ using vendor::qti::hardware::fm::V1_0::HciPacket;
+ using vendor::qti::hardware::fm::V1_0::Status;
+ class FmHciCallbacks : public IFmHciCallbacks {
+ public:
+ FmHciCallbacks() {
+ };
+ virtual ~FmHciCallbacks() = default;
+
+ Return<void> initializationComplete(Status status) {
+ ALOGV("%s: start ", __func__);
+ if (status == Status::SUCCESS) {
+ hidl_init = true;
+ } else {
+ ALOGE("Error in HIDL initialization");
+ }
+ sem_post(&s_cond);
+ ALOGI("%s:end", __func__);
+ return Void();
+ }
+
+ Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+ int len = static_cast<int>(event.size());
+ ALOGV("%s: start ", __func__);
+ unsigned char val = FM_EVT_PACKET_TYPE;
+ if (safe_write(server_fd, &val, 1) == -1) {
+ return Void();
+ }
+ if (safe_write(server_fd, const_cast<unsigned char*>(event.data()), len) == -1) {
+ ALOGE("%s: failed to write event to tool socket", __func__);
+ return Void();
+ }
+ return Void();
+ }
+};
+}
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+bool hidl_client_initialize(int mode, int *tool_fd) {
+
+ mode_type = mode;
+
+ if (tool_fd == NULL) {
+ ALOGE("%s: Invalid tool FD", __func__);
+ return false;
+ }
+ switch (mode) {
+ case MODE_BT:
+ ALOGI("%s: Initialize the HIDL with Mode BT", __func__);
+ btHci = IBluetoothHci::getService();
+ // If android.hardware.bluetooth* is not found, Bluetooth can not continue.
+ if (btHci != nullptr) {
+ ALOGI("%s: IBluetoothHci::getService() returned %p (%s)",
+ __func__, btHci.get(), (btHci->isRemote() ? "remote" : "local"));
+ } else {
+ ALOGE("Unable to initialize the HIDL");
+ return false;
+ }
+ {
+ android::sp<IBluetoothHciCallbacks> callbacks = new BluetoothHciCallbacks();
+ hidl_init = false;
+ sem_init(&s_cond, 0, 0);
+ btHci->initialize(callbacks);
+ // waiting for initialisation callback
+ sem_wait(&s_cond);
+ }
+
+ if (hidl_init == true) {
+ break;
+ } else {
+ ALOGE("%s: HIDL failed to initialize, sending invalid FD to tool", __func__);
+ return false;
+ }
+
+ case MODE_ANT:
+ ALOGI("%s: Initialize the HIDL with Mode ANT", __func__);
+ antHci = IAntHci::getService();
+ if (antHci != nullptr) {
+ ALOGI("%s: IAntHci::getService() returned %p (%s)",
+ __func__, antHci.get(), (antHci->isRemote() ? "remote" : "local"));
+ } else {
+ ALOGE("Unable to initialize the HIDL");
+ return false;
+ }
+ {
+ android::sp<IAntHciCallbacks> callbacks = new AntHciCallbacks();
+ hidl_init = false;
+ sem_init(&s_cond, 0, 0);
+ antHci->initialize(callbacks);
+ // waiting for initialisation callback
+ ALOGV("%s: Wait for initialisation callback", __func__);
+ sem_wait(&s_cond);
+ }
+ if (hidl_init == true) {
+ break;
+ } else {
+ ALOGE("%s: HIDL failed to initialize, sending invalid FD to tool", __func__);
+ return false;
+ }
+
+ case MODE_FM:
+ ALOGI("%s: Initialize the HIDL with Mode FM", __func__);
+ fmHci = IFmHci::getService();
+ if (fmHci != nullptr) {
+ ALOGI("%s: IFmHci::getService() returned %p (%s)",
+ __func__, fmHci.get(), (fmHci->isRemote() ? "remote" : "local"));
+ } else {
+ ALOGE("Unable to initialize the HIDL");
+ return false;
+ }
+ {
+ android::sp<IFmHciCallbacks> callbacks = new FmHciCallbacks();
+ hidl_init = false;
+ sem_init(&s_cond, 0, 0);
+ fmHci->initialize(callbacks);
+ // waiting for initialisation callback
+ ALOGV("%s: Wait for initialisation callback", __func__);
+ sem_wait(&s_cond);
+ }
+ if (hidl_init == true) {
+ if (client_fd > 0) {
+ *tool_fd = client_fd;
+ return true;
+ }
+ break;
+ } else {
+ ALOGE("%s: HIDL failed to initialize, sending invalid FD to tool", __func__);
+ return false;
+ }
+ break;
+ default:
+ ALOGE("Unsupported mode");
+ return false;
+ }
+
+ // creating a scoket pair
+ int fds[2] = {INVALID_FD, INVALID_FD};
+
+ if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == -1) {
+ ALOGE("%s error creating socketpair: %s", __func__,strerror(errno));
+ return false;
+ }
+ server_fd = fds[0];
+ if (pthread_create(&client_rthread, NULL, process_tool_data, NULL) != 0) {
+ ALOGE("%s:Unable to create pthread err = %s", __func__, strerror(errno));
+ close(server_fd);
+ close(fds[1]);
+ return false;
+ }
+ client_fd = fds[1];
+ ALOGE("Server FD=%d Client FD: %d\n",server_fd,client_fd);
+ *tool_fd = client_fd;
+ return true;
+}
+
+// Close HIDL Client to prevent callbacks.
+void hidl_client_close() {
+
+ if (hidl_init == false) {
+ return;
+ }
+
+ if (server_fd != -1) {
+ close(server_fd);
+ }
+
+ pthread_join(client_rthread, NULL);
+ server_fd = -1;
+
+ switch (mode_type) {
+ case MODE_BT:
+ ALOGI("%s: Close HIDL with Mode BT", __func__);
+ btHci->close();
+ btHci = nullptr;
+ break;
+
+ case MODE_ANT:
+ ALOGI("%s: Close HIDL with Mode ANT", __func__);
+ antHci->close();
+ antHci = nullptr;
+ break;
+
+ case MODE_FM:
+ ALOGI("%s: Close HIDL with Mode FM", __func__);
+ fmHci->close();
+ fmHci = nullptr;
+ break;
+
+ default:
+ ALOGE("Unsupported mode");
+ break;
+ }
+ return;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+static int safe_write(int server_fd, unsigned char* buf, int write_len) {
+
+ int bytes_written = 0;
+ int ret;
+
+ if (buf == NULL) {
+ ALOGE("%s: The buffer is NULL", __func__);
+ return -1;
+ }
+
+ if (!write_len) {
+ ALOGE("%s: No data to write", __func__);
+ return 0;
+ }
+
+ while (write_len > 0) {
+ CLIENT_NO_INTR(ret = write(server_fd, buf+bytes_written, write_len));
+ if (ret < 0) {
+ ALOGE("%s: Write error: (%s)", __func__, strerror(errno));
+ return -1;
+ } else if (ret == 0) {
+ ALOGE("%s: Write returned 0, err = %s, bytes written: %d",
+ __func__, strerror(errno), (unsigned int)(bytes_written));
+ return -1;
+ } else {
+ write_len -= ret;
+ bytes_written += ret;
+ }
+ }
+ return bytes_written;
+}