blob: 13728d604a6855c7af9936c8310bcd7f346ef0c5 [file] [log] [blame]
/*
* 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(&current_time);
time_info = localtime(&current_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, "pronto")){
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("vendor.qcom.bluetooth.soc", soc_type, "pronto");
#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(soc_type, "pronto")) {
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;
}
//----------------------------------------------------------------------------