430 lines
18 KiB
C
430 lines
18 KiB
C
/* Copyright Statement:
|
|
*
|
|
* This software/firmware and related documentation ("MediaTek Software") are
|
|
* protected under relevant copyright laws. The information contained herein is
|
|
* confidential and proprietary to MediaTek Inc. and/or its licensors. Without
|
|
* the prior written permission of MediaTek inc. and/or its licensors, any
|
|
* reproduction, modification, use or disclosure of MediaTek Software, and
|
|
* information contained herein, in whole or in part, shall be strictly
|
|
* prohibited.
|
|
*
|
|
* MediaTek Inc. (C) 2016~2017. All rights reserved.
|
|
*
|
|
* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
|
|
* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
|
|
* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
|
|
* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL
|
|
* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
|
|
* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH
|
|
* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
|
|
* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES
|
|
* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
|
|
* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
|
|
* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK
|
|
* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE
|
|
* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
|
|
* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S
|
|
* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE
|
|
* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE
|
|
* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
|
|
* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
|
|
*
|
|
* The following software/firmware and/or related documentation ("MediaTek
|
|
* Software") have been modified by MediaTek Inc. All revisions are subject to
|
|
* any receiver's applicable license agreements with MediaTek Inc.
|
|
*/
|
|
|
|
//- vim: set ts=4 sts=4 sw=4 et: --------------------------------------------
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdint.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "boots.h"
|
|
#include "boots_pkt.h"
|
|
#include "boots_btif.h"
|
|
#include "boots_skt.h"
|
|
#include "boots_uart.h"
|
|
#include "boots_eth.h"
|
|
#include "boots_stress.h"
|
|
|
|
//---------------------------------------------------------------------------
|
|
#define LOG_TAG "boots_srv"
|
|
|
|
//---------------------------------------------------------------------------
|
|
static boots_if_s boots_srv_if;
|
|
static int cont = 1;
|
|
static int uart_speed = 0;
|
|
int fd[BOOTS_BTIF_ALL] = {-1};
|
|
int boots_loop_timer;
|
|
rssi_set_s rssi_setting;
|
|
|
|
/****************************************************************************
|
|
* F U N C T I O N D E C L A R A T I O N S *
|
|
****************************************************************************/
|
|
|
|
//---------------------------------------------------------------------------
|
|
static void boots_srv_sig_handler(int signum)
|
|
{
|
|
BPRINT_D("%s: signum: %d", __func__, signum);
|
|
cont = 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
static void boots_srv_help(void)
|
|
{
|
|
printf("Boots(server) - MTK Bluetooth Test Suite ver:%s\n", VERSION);
|
|
printf("Usage:\n");
|
|
printf(" boots_srv <[Input interface] [buadrate]> [BT Interface]\n");
|
|
printf("Input Interface:\n");
|
|
printf("\tCli/Srv connection by socket if you ignore this argument\n");
|
|
printf("\tttyX Specific UART for data issuer, baudate is for real port\n");
|
|
printf("\t ex: ./boots_srv ttyGS2\n");
|
|
printf("\t ex: ./boots_srv ttyUSB0 115200\n");
|
|
printf("\tethX Specific Eth for data issuer, need client IP\n");
|
|
printf("\t ex: ./boots_srv eth0 10.1.1.2\n");
|
|
printf("BT Interface:\n");
|
|
printf("\tAuto detect stpbt/HCI, if you ignore this argument\n");
|
|
printf("\tstpbt MTK stpbt Interface for BT controller, ex: ./boots_srv stpbt\n");
|
|
printf("\thci HCI Interface for BT controller\n");
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
static void boots_srv_chk_if(int argc, char **argv)
|
|
{
|
|
int i = 0;
|
|
#ifdef BOOTS_VERBOSE_MSG
|
|
BPRINT_D("%s: argc = %d", __func__, argc);
|
|
for (i = 0; i < argc; i++)
|
|
BPRINT_D("argv[%d]:%s", i, argv[i]);
|
|
i = 0;
|
|
#endif
|
|
|
|
while (i < argc) {
|
|
if (!memcmp(argv[i], "stpbt", strlen("stpbt"))) {
|
|
boots_srv_if.btif = BOOTS_BTIF_STPBT;
|
|
|
|
} else if (!memcmp(argv[i], "hci", strlen("hci"))) {
|
|
boots_srv_if.btif = BOOTS_BTIF_HCI;
|
|
|
|
} else if (!memcmp(argv[i], "tty", strlen("tty"))) {
|
|
boots_srv_if.csif = BOOTS_CSIF_UART;
|
|
snprintf(boots_srv_if.cs, sizeof(boots_srv_if.cs), "/dev/%s", argv[i]);
|
|
BPRINT_D("%s: %s", __func__, boots_srv_if.cs);
|
|
if (i + 1 < argc) {
|
|
uart_speed = atoi(argv[i + 1]);
|
|
BPRINT_D("%s: UART speed: %d", __func__, uart_speed);
|
|
i += 2;
|
|
continue;
|
|
}
|
|
|
|
} else if (!memcmp(argv[i], "eth", strlen("eth"))) {
|
|
boots_srv_if.csif = BOOTS_CSIF_ETH;
|
|
memcpy(boots_srv_if.cs, argv[i + 1],
|
|
strlen(argv[i + 1]) > (16 - 1) ? (16 - 1) : strlen(argv[i + 1]));
|
|
i++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
if (boots_srv_if.csif == BOOTS_IF_NONE)
|
|
boots_srv_if.csif = BOOTS_CSIF_SKT;
|
|
|
|
if (boots_srv_if.btif == BOOTS_IF_NONE) {
|
|
if (access(boots_btif[0].p, R_OK) == 0) {
|
|
boots_srv_if.btif = BOOTS_BTIF_STPBT;
|
|
} else {
|
|
boots_srv_if.btif = BOOTS_BTIF_HCI;
|
|
}
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
int main(int argc, char *argv[])
|
|
{
|
|
static uint8_t buf[HCI_BUF_SIZE] = {0};
|
|
int btfd = -1; // Interface file descriptor with BT controller
|
|
ssize_t len = 0;
|
|
struct sigaction sigact;
|
|
fd_set readfs;
|
|
rssi_set_s *temp_rssi_setting;
|
|
|
|
// For root permission
|
|
CHECK_USERID();
|
|
|
|
if (argc >= 2 && !memcmp("-h", argv[1], strlen("-h"))) {
|
|
boots_srv_help();
|
|
exit(0);
|
|
}
|
|
|
|
sigact.sa_handler = boots_srv_sig_handler;
|
|
sigact.sa_flags = 0;
|
|
sigemptyset(&sigact.sa_mask);
|
|
sigaction(SIGINT, &sigact, NULL);
|
|
sigaction(SIGTERM, &sigact, NULL);
|
|
sigaction(SIGQUIT, &sigact, NULL);
|
|
sigaction(SIGKILL, &sigact, NULL);
|
|
|
|
boots_srv_chk_if(argc - 1, &argv[1]);
|
|
|
|
/** Communication Interface with BT controller */
|
|
if (boots_srv_if.btif != BOOTS_IF_NONE)
|
|
btfd = boots_btif_open(boots_srv_if.btif);
|
|
if (btfd < 0) {
|
|
BPRINT_E("Set interface failed(%d), please check driver and controller", boots_srv_if.btif);
|
|
boots_srv_help();
|
|
exit(1);
|
|
} else {
|
|
// Please follow the boots_if_e
|
|
char *c_inf[] = {"None", "stpbt", "hci", "All", "Socket", "UART", "Ethernet",
|
|
"User", "Tester_UART"};
|
|
|
|
BPRINT_I("client <-> %s(%d) <-> %s(%d) <-> BT", c_inf[boots_srv_if.csif],
|
|
boots_srv_if.csif, c_inf[boots_srv_if.btif], boots_srv_if.btif);
|
|
}
|
|
|
|
/** open interface to connect upper layer */
|
|
if (boots_srv_if.csif == BOOTS_CSIF_SKT) {
|
|
int skfd_srv = -1; // Interface file descriptor with host
|
|
int skfd_cli = -1; // Interface file descriptor with host
|
|
int boots_stress_enabled = 0;
|
|
struct sockaddr_un skaddr_srv;
|
|
struct sockaddr_un skaddr_cli;
|
|
socklen_t sklen_srv = {0};
|
|
socklen_t sklen_cli = {0};
|
|
|
|
if (boots_sk_create(&skfd_srv, &skaddr_srv, &sklen_srv, BOOTS_SRVSK_NAME, 0)) {
|
|
BPRINT_E("%s: Create server socket failed", __func__);
|
|
goto BTOFF;
|
|
}
|
|
|
|
BPRINT_I("Local relaying...");
|
|
while (cont && btfd >= 0) {
|
|
FD_ZERO(&readfs);
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
if (btfd >= 0)
|
|
FD_SET(btfd, &readfs);
|
|
if (skfd_srv >= 0)
|
|
FD_SET(skfd_srv, &readfs);
|
|
|
|
if (select(MAX(btfd, skfd_srv) + 1, &readfs, NULL, NULL, NULL) > 0) {
|
|
// Process the event from BT controller, read
|
|
if (FD_ISSET(btfd, &readfs)) {
|
|
len = boots_btif_read(btfd, buf, sizeof(buf));
|
|
if (boots_stress_enabled &&
|
|
((buf[0] == 0x04 && buf[1] == 0x19) || // Write local name
|
|
(buf[0] == 0x04 && buf[1] == 0x0e) || // Write local name, FW bug
|
|
#if BOOTS_STRESS_MEASURE_LBT_TOTAL_LATENCY
|
|
(buf[0] == 0x02 && buf[1] == 0x32) // ACL
|
|
#else
|
|
(buf[0] == 0x04 && buf[1] == 0x13) // NOCP
|
|
#endif
|
|
)) {
|
|
boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_RECEIVE_EVENT_FINISH);
|
|
}
|
|
|
|
if (len > 0 && skfd_cli >= 0) {
|
|
boots_sk_send(skfd_cli, (void *)buf, len, &skaddr_cli, BOOTS_CLISK_NAME);
|
|
} else if (len > 0) {
|
|
boots_pkt_handler(buf, len, NULL);
|
|
} else if (len < 0) {
|
|
BPRINT_E("%s: Read data from chip failed", __func__);
|
|
btfd = -1;
|
|
break;
|
|
}
|
|
}
|
|
// Process the command from host, write
|
|
if (FD_ISSET(skfd_srv, &readfs)) {
|
|
// connect socket, server
|
|
if (skfd_cli == -1 &&
|
|
boots_sk_create(&skfd_cli, &skaddr_cli, &sklen_cli, BOOTS_CLISK_NAME, 1)) {
|
|
BPRINT_E("%s: Connect client socket failed", __func__);
|
|
boots_sk_close(&skfd_srv);
|
|
goto BTOFF;
|
|
}
|
|
len = boots_sk_recv(skfd_srv, buf, sizeof(buf), 0, NULL, NULL);
|
|
if (len < 0)
|
|
break;
|
|
|
|
if (!BOOTS_STRESS_MEASURE_IN_BOOTS &&
|
|
boots_stress_enabled == 0 &&
|
|
((buf[0] == 0x01 && buf[1] == 0x13 && buf[2] == 0x0c) ||// Write Local Name
|
|
(buf[0] == 0x01 && buf[1] == 0x02 && buf[2] == 0x18) // Write Loopback Mode
|
|
)) {
|
|
boots_stress_init();
|
|
boots_stress_enabled = 1;
|
|
}
|
|
if (boots_stress_enabled)
|
|
boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_SEND_CMD_START);
|
|
|
|
if (len == 4 && buf[0] == 's' && buf[1] == 'e' && buf[2] == 'n' && buf[3] == 'd') {
|
|
// client socket end
|
|
boots_sk_close(&skfd_cli);
|
|
skfd_cli = -1;
|
|
} else if (buf[0] == 0x01 && buf[1] == 0x01 && buf[2] == 0xFF) {
|
|
// read/write file
|
|
boots_file_wr(buf, &len);
|
|
boots_sk_send(skfd_cli, (void *)buf, len, &skaddr_cli, BOOTS_CLISK_NAME);
|
|
// write it to BT chip
|
|
} else if (buf[0] == SCRIPT_RSSI) {
|
|
temp_rssi_setting = (rssi_set_s *)(&buf[1]);
|
|
if (temp_rssi_setting->stop)
|
|
boots_pkt_cleanup_report_rssi(1);
|
|
else {
|
|
boots_pkt_cleanup_report_rssi(0);
|
|
memcpy(&rssi_setting, temp_rssi_setting, sizeof(rssi_set_s));
|
|
}
|
|
} else if (!boots_btif_write(btfd, buf, len)) {
|
|
BPRINT_E("Write data to chip failed, please check controller");
|
|
btfd = -1;
|
|
break;
|
|
}
|
|
if (boots_stress_enabled)
|
|
boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_SEND_CMD_FINISH);
|
|
}
|
|
}
|
|
}
|
|
if (boots_stress_enabled)
|
|
boots_stress_deinit();
|
|
if (skfd_cli >= 0) {
|
|
boots_sk_close(&skfd_cli);
|
|
}
|
|
if (skfd_srv >= 0) {
|
|
boots_sk_close(&skfd_srv);
|
|
}
|
|
} else if (boots_srv_if.csif == BOOTS_CSIF_UART) {
|
|
int uartfd = -1;
|
|
|
|
uartfd = boots_uart_init(boots_srv_if.cs, uart_speed);
|
|
if (uartfd < 0) {
|
|
BPRINT_E("%s: Open serial port:%s failed(%d)", __func__, boots_srv_if.cs, uartfd);
|
|
goto BTOFF;
|
|
}
|
|
|
|
BPRINT_I("With UART(%s) Relaying...", boots_srv_if.cs);
|
|
while (cont && btfd >= 0) {
|
|
FD_ZERO(&readfs);
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
if (btfd >= 0)
|
|
FD_SET(btfd, &readfs);
|
|
if (uartfd >= 0)
|
|
FD_SET(uartfd, &readfs);
|
|
|
|
if (select(MAX(btfd, uartfd) + 1, &readfs, NULL, NULL, NULL) > 0) {
|
|
// Process the event from BT controller, read
|
|
if (FD_ISSET(btfd, &readfs)) {
|
|
len = boots_btif_read(btfd, buf, sizeof(buf));
|
|
if (len > 0) {
|
|
boots_uart_write(uartfd, buf, len);
|
|
boots_pkt_handler(buf, len, NULL);
|
|
} else if (len < 0) {
|
|
BPRINT_E("%s: Read data from chip failed", __func__);
|
|
btfd = -1;
|
|
break;
|
|
}
|
|
}
|
|
// Process the command from host, write
|
|
if (FD_ISSET(uartfd, &readfs)) {
|
|
len = boots_uart_read(uartfd, buf, sizeof(buf));
|
|
if (len > 0) {
|
|
if (!boots_btif_write(btfd, buf, len)) {
|
|
BPRINT_E("%s: Write command to chip failed", __func__);
|
|
}
|
|
boots_pkt_handler(buf, len, NULL);
|
|
}
|
|
}
|
|
fsync(btfd);
|
|
fsync(uartfd);
|
|
} else {
|
|
BPRINT_D("%s(%d)", strerror(errno), errno);
|
|
}
|
|
}
|
|
close(uartfd);
|
|
} else if (boots_srv_if.csif == BOOTS_CSIF_ETH) {
|
|
int skfd_srv = -1; // Interface file descriptor with host
|
|
int skfd_cli = -1; // Interface file descriptor with host
|
|
struct sockaddr_in skaddr_srv;
|
|
struct sockaddr_in skaddr_cli;
|
|
|
|
if (boots_eth_create(&skfd_srv, &skaddr_srv, 0)) {
|
|
BPRINT_E("%s: Create server socket failed", __func__);
|
|
goto BTOFF;
|
|
}
|
|
|
|
BPRINT_I("Ethernet relaying...");
|
|
while (cont && btfd >= 0) {
|
|
FD_ZERO(&readfs);
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
if (btfd >= 0)
|
|
FD_SET(btfd, &readfs);
|
|
if (skfd_srv >= 0)
|
|
FD_SET(skfd_srv, &readfs);
|
|
|
|
if (select(MAX(btfd, skfd_srv) + 1, &readfs, NULL, NULL, NULL) > 0) {
|
|
// Process the event from BT controller, read
|
|
if (FD_ISSET(btfd, &readfs)) {
|
|
len = boots_btif_read(btfd, buf, sizeof(buf));
|
|
if (len > 0 && skfd_cli >= 0) {
|
|
skaddr_cli.sin_family = AF_INET;
|
|
skaddr_cli.sin_port = ETH_UDP_SRV_PORT;
|
|
skaddr_cli.sin_addr.s_addr = inet_addr(boots_srv_if.cs);
|
|
boots_eth_send(skfd_cli, (void *)buf, len, &skaddr_cli);
|
|
} else if (len > 0) {
|
|
boots_pkt_handler(buf, len, NULL);
|
|
} else if (len < 0) {
|
|
BPRINT_E("%s: Read data from chip failed", __func__);
|
|
btfd = -1;
|
|
break;
|
|
}
|
|
}
|
|
// Process the command from host, write
|
|
if (FD_ISSET(skfd_srv, &readfs)) {
|
|
// connect socket, server
|
|
if (skfd_cli == -1 &&
|
|
boots_eth_create(&skfd_cli, &skaddr_cli, 1)) {
|
|
BPRINT_E("%s: Connect client socket failed", __func__);
|
|
boots_eth_close(&skfd_srv);
|
|
goto BTOFF;
|
|
}
|
|
len = boots_eth_recv(skfd_srv, buf, sizeof(buf), 0);
|
|
if (len < 0) {
|
|
btfd = -1;
|
|
break;
|
|
} else if (len == 4 && buf[0] == 's' && buf[1] == 'e' && buf[2] == 'n' && buf[3] == 'd') {
|
|
// client socket end
|
|
boots_eth_close(&skfd_cli);
|
|
skfd_cli = -1;
|
|
} else if (buf[0] == 0x01 && buf[1] == 0x01 && buf[2] == 0xFF) {
|
|
// read/write file
|
|
boots_file_wr(buf, &len);
|
|
boots_eth_send(skfd_cli, (void *)buf, len, &skaddr_cli);
|
|
// write it to BT chip
|
|
} else if (!boots_btif_write(btfd, buf, len)) {
|
|
BPRINT_E("%s: Write command to chip failed", __func__);
|
|
btfd = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (skfd_cli >= 0) {
|
|
boots_eth_close(&skfd_cli);
|
|
}
|
|
if (skfd_srv >= 0) {
|
|
boots_eth_close(&skfd_srv);
|
|
}
|
|
}
|
|
|
|
BTOFF:
|
|
boots_btif_close(boots_srv_if.btif);
|
|
BPRINT_I("Service STOP!");
|
|
return 0;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|