linuxOS_AP06/external/rkwifibt/tools/rk-hciattach/hciclient.c
2025-06-03 12:28:32 +08:00

355 lines
9.4 KiB
C

/******************************************************************************
*
* Copyright (C) 2020-2021 Rockchip Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#include <netdb.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <utils/Log.h>
#include <android/log.h>
#ifndef LOG_TAG
#define LOG_TAG "zdm"
#endif
#define HCI_GRP_LINK_CONTROL_CMDS (0x01 << 10) /* 0x0400 */
#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */
/* Commands of HCI_GRP_HOST_CONT_BASEBAND_CMDS */
#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
/* Commands of HCI_GRP_LINK_CONTROL_CMDS group */
#define HCI_Change_Connection_Packet_Type (0x000F | HCI_GRP_LINK_CONTROL_CMDS)
#define HCIC_PARAM_SIZE_CHANGE_CONN_TYPE 4
#define HCIC_HEADER_SIZE 3//opcode(2)+paralen(1)
/* Command opcode pack/unpack */
#define cmd_opcode_pack(ogf, ocf) ((uint16_t)((ocf & 0x03ff)|(ogf << 10)))
#define MAXSLEEP 4
static const int SERV_ADDR = 0x7f000001;
static const uint16_t SERV_PORT = 8873;
#define BIT(x) (1<<x)
#define NO_2_DH1 BIT(1)
#define NO_3_DH1 BIT(2)
#define DM1 BIT(3) //always enable
#define DH1 BIT(4)
//#define HV1 BIT(5)
//#define HV2 BIT(6)
//#define HV3 BIT(7)
#define NO_2_DH3 BIT(8)
#define NO_3_DH3 BIT(9)
#define DM3 BIT(10)
#define DH3 BIT(11)
#define NO_2_DH5 BIT(12)
#define NO_3_DH5 BIT(13)
#define DM5 BIT(14)
#define DH5 BIT(15)
#define b_NOALL (DM1|NO_2_DH1|NO_3_DH1|NO_2_DH3|NO_3_DH3|NO_2_DH5|NO_3_DH5)//keep DM1 available
/*#define b_DM1 (b_NOALL|DM1)//always enabled
#define b_DH1 (b_NOALL|DH1)
#define b_2DH1 (b_NOALL&~NO_2_DH1)
#define b_3DH1 (b_NOALL&~NO_3_DH1)
#define b_DM3 (b_NOALL|DM3)
#define b_DH3 (b_NOALL|DH3)
#define b_2DH3 (b_NOALL&~NO_2_DH3)
#define b_3DH3 (b_NOALL&~NO_3_DH5)
#define b_DM5 (b_NOALL|DM5)
#define b_DH5 (b_NOALL|DH5)
#define b_2DH5 (b_NOALL&~NO_2_DH5)
#define b_3DH5 (b_NOALL&~NO_3_DH5)*/
#define LOGI(param, ...) do { ALOGI(param, ##__VA_ARGS__); printf(param, ##__VA_ARGS__);}while(0)
#define LOGD(param, ...) do { ALOGD(param, ##__VA_ARGS__); printf(param, ##__VA_ARGS__);}while(0)
#define LOGW(param, ...) do { ALOGW(param, ##__VA_ARGS__); printf(param, ##__VA_ARGS__);}while(0)
#define LOGE(param, ...) do { ALOGE(param, ##__VA_ARGS__); printf(param, ##__VA_ARGS__); }while(0)
struct bredr_t {
char *type;
uint16_t mask;
bool inverse;
};
struct bredr_t bredr[]={
{"DM1" ,DM1 , false },
{"DH1" ,DH1 , false },
{"2-DH1" ,NO_2_DH1 , true },
{"3-DH1" ,NO_3_DH1 , true },
{"DM3" ,DM3 , false },
{"DH3" ,DH3 , false },
{"2-DH3" ,NO_2_DH3 , true },
{"3-DH3" ,NO_3_DH3 , true },
{"DM5" ,DM5 , false },
{"DH5" ,DH5 , false },
{"2-DH5" ,NO_2_DH5 , true },
{"3-DH5" ,NO_3_DH5 , true },
{ NULL ,0 , false }
};
static bool findBrEdrType(const char *string, bool* inverse, uint16_t* bitmask)
{
if (!string)
goto FAIL;
for(int i=0; bredr[i].type; i++){
if(!strcasecmp(bredr[i].type, string)){
LOGD(" %s\n", bredr[i].type);
*inverse = bredr[i].inverse;
*bitmask = bredr[i].mask;
return true;
}
}
FAIL:
return false;
}
int connect_retry(int domain, int type, int protocol, const struct sockaddr *addr, socklen_t alen)
{
int numsec, fd;
/*Try to connect with exponentail backoff*/
for(numsec = 1; numsec <= MAXSLEEP; numsec <<= 1) {
if((fd = socket(domain, type, protocol)) < 0)
return -1;
}
if(connect(fd, addr, alen) ==0) {
/*connection accept*/
return (fd);
}
close(fd);
/* Delay before trying again*/
if(numsec <= MAXSLEEP/2){
sleep(numsec);
}
return -1;
}
static void usage(void)
{
LOGD("bluedroidhci --- HCI tool to send hci command\n");
LOGD("Usage:\n");
LOGD("\tbluedroidhci [-h handle] [-i airtype(uint16)] [-t airtype1 airtype2 ...(string)] [--help]\n\tor\n");
LOGD("\tbluedroidhci [-c|--cmd ogf ocf para....]\n");
LOGD("\tavailable airtype:DM1 DH1 2-DH1 3-DH1 DM3 DH3 2-DH3 3-DH3 DM5 DH5 2-DH5 3-DH5\n");
LOGD("\texample :bluedroidhci -h 0x80 -t DM1 DH1 2-DH3 3-DH3 2-DH5\n");
LOGD("\texample :bluedroidhci -h 0x80 -i 0x380e\n");
LOGD("\texample :to send hci raw command(hci reset, etc):\n");
LOGD("\t\t bluedroidhci --cmd 0x03 0x0003\n");
}
static struct option long_options[] = {
{"help", 0, 0, 0 },
{"cmd", required_argument, 0, 'c'},
{0, 0, 0, 0 }
};
int main(int argc, char *argv[])
{
struct sockaddr_in serverAdd;
int fd;
int total, opt, n;
bool hciReset =0, hcicmd =0, inverse;
uint16_t airType=b_NOALL, handle = 0x80, bitmask;
int option_index = 0;
uint16_t ocf, opcode;
uint8_t ogf;
unsigned char cmd[260] = {0}, *ptr = cmd;;//{ 0x01, 0x00, 0x03, 0x03, 0x0C, 0x00 };
if(argc < 2){
usage();
//while(1){printf("while zdm, error = %d\n", errno);};
exit(1);
}
memset(&serverAdd, 0, sizeof(struct sockaddr_in));
serverAdd.sin_family = AF_INET;
serverAdd.sin_addr.s_addr = htonl(SERV_ADDR);
serverAdd.sin_port = htons(SERV_PORT);
fd = connect_retry(AF_INET, SOCK_STREAM, IPPROTO_TCP, (struct sockaddr *)&serverAdd, sizeof(serverAdd));
if(fd < 0){
printf("connection fail, error = %d\n", errno);
goto MAIN_EXIT;
}
LOGD("connection successful!!!\n");
while (1) {
opt=getopt_long(argc, argv, "c:h:t:i:", long_options, &option_index);
if (opt == -1)
break;
switch(opt) {
case 0:
LOGD("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
usage();
goto MAIN_EXIT;
break;
case 'h':
//printf("option %s\n", optarg);
handle = (uint16_t)strtol(optarg, NULL, 16);
break;
case 't':
LOGD("airType strings:");
LOGD("%s ", optarg);
if(findBrEdrType(optarg, &inverse, &bitmask)){
if(inverse)
airType&=~bitmask;
else
airType|=bitmask;
}
break;
case 'i':
//printf("airType strings:%s \n", optarg);
airType = (uint16_t)strtol(optarg, NULL, 16);
printf("airType:0x%04x \n", airType);
break;
case 'c':
hcicmd = 1;
ogf = strtol(optarg, NULL, 16);
break;
default:
usage();
goto MAIN_EXIT;
}
}
//n = argc - optind;
/*if (n < 1) {
usage();
exit(1);
}*/
if(hcicmd){
int i, len, paralen;
ocf = strtol(argv[optind++], NULL, 16);
opcode = cmd_opcode_pack(ogf, ocf);
len = argc - optind;
cmd[0] = 0x01;//cmd
cmd[1] = (HCIC_HEADER_SIZE+ len)&0xff;//paralen
cmd[2] = (HCIC_HEADER_SIZE+ len)>>8&0xff;//paralen
cmd[3] = opcode&0xff;//opcode
cmd[4] = opcode>>8&0xff;
cmd[5] = len; //para len
total = 3 + HCIC_HEADER_SIZE + cmd[5];
ptr = &cmd[6];
for(i= optind, paralen = 0; i < argc && paralen < (int)sizeof(cmd); i++, paralen++){
*ptr++ = (uint8_t) strtol(argv[optind++], NULL, 16);
}
LOGD("paralen:%d , len =%d, %s\n", paralen, len, (paralen == len)?"ok":"some error!");
LOGD("hci command:%02x (%02x %02x)", cmd[0], cmd[1], cmd[2]);
for(int i = 0; i < len+3; i++){
printf(" %02x", cmd[3+i]);
}
printf("\n");
}
else{
//printf("optind:%d argc:%d", optind, argc);
while (optind < argc) {
const char *opt = argv[optind];
printf("%s ", opt);
if(findBrEdrType(opt, &inverse, &bitmask)){
if(inverse)
airType&=~bitmask;
else
airType|=bitmask;
}
optind++;
}
}
LOGD("\n final airType :0x%04x, handle=0x%02x\n", airType, handle);
if(hcicmd){
#if 0
cmd[0] = 0x01;//cmd
cmd[1] = (HCIC_HEADER_SIZE+0)&0xff;//len
cmd[2] = (HCIC_HEADER_SIZE+0)>>8&0xff;
cmd[3] = HCI_RESET&0xff;//opcode
cmd[4] = HCI_RESET>>8&0xff;
cmd[5] = 0; //para
total = 3 + HCIC_HEADER_SIZE;
#endif
if (write(fd, cmd, total) != total) {
fprintf(stderr, "Failed to write reset command\n");
goto MAIN_EXIT;
}
}
else{
cmd[0] = 0x01;//cmd
cmd[1] = (HCIC_HEADER_SIZE+HCIC_PARAM_SIZE_CHANGE_CONN_TYPE)&0xff;//len
cmd[2] = (HCIC_HEADER_SIZE+HCIC_PARAM_SIZE_CHANGE_CONN_TYPE)>>8&0xff;
cmd[3] = HCI_Change_Connection_Packet_Type&0xff;//opcode
cmd[4] = HCI_Change_Connection_Packet_Type>>8&0xff;
cmd[5] = HCIC_PARAM_SIZE_CHANGE_CONN_TYPE;//opcode
cmd[6] = handle&0xff;//opcode
cmd[7] = handle>>8&0xff;
cmd[8] = airType&0xff;//opcode
cmd[9] = airType>>8&0xff;
total = 3 + HCIC_HEADER_SIZE + HCIC_PARAM_SIZE_CHANGE_CONN_TYPE;
if (write(fd, cmd, total) != total) {
fprintf(stderr, "Failed to write reset command\n");
goto MAIN_EXIT;
}
}
//while(1);
//usage();
close(fd);
LOGD("exit successful!!!\n");
//usage();
exit(0);//return 0;
MAIN_EXIT:
close(fd);
LOGD("exit unsuccessful!!!\n");
//usage();
exit(1);
}