| /* 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 <unistd.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <signal.h> |
| #include <sys/time.h> |
| #include <sys/resource.h> |
| |
| #include "boots.h" |
| #include "boots_skt.h" |
| #include "boots_uart.h" |
| #include "boots_eth.h" |
| #include "boots_pkt.h" |
| #include "boots_stress.h" |
| #include "boots_country.h" |
| #include "boots_osi.h" |
| |
| //--------------------------------------------------------------------------- |
| #define LOG_TAG "boots" |
| |
| //--------------------------------------------------------------------------- |
| static boots_if_s boots_if; |
| static uint8_t boots_local_exe; |
| int boots_loop_timer; |
| rssi_set_s rssi_setting; |
| |
| //--------------------------------------------------------------------------- |
| static void boots_chk_if(int argc, char **argv) |
| { |
| // Please follow the boots_if_e |
| char *c_inf[] = {"None", "stpbt", "hci", "All", "Socket", "UART", "Ethernet", |
| "User", "Tester_UART"}; |
| 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 |
| |
| #if 0 |
| if (*argv[0] == '-') { |
| if (memcmp(argv[0], "-relay", strlen("-relay"))) { |
| boots_if.clif = BOOTS_CLIF_USER; |
| boots_if.csif = BOOTS_CSIF_SKT; |
| } else if (argc >= 2) { |
| // boots_srv as relayer in PC/NB |
| boots_if.csif = BOOTS_CSIF_UART; |
| if (argc == 2) |
| snprintf(boots_if.cs, sizeof(boots_if.cs), "%s", argv[1]); |
| else if (argc >= 3) |
| snprintf(boots_if.cs, sizeof(boots_if.cs), "%s %s", argv[1], argv[2]); |
| goto exit; |
| } |
| } else if (!memcmp(argv[0], "tty", strlen("tty"))) { |
| boots_if.csif = BOOTS_CSIF_UART; |
| snprintf(boots_if.cs, sizeof(boots_if.cs), "/dev/%s", argv[0]); |
| } else if (!memcmp(argv[0], "eth", strlen("eth"))) { |
| boots_if.csif = BOOTS_CSIF_ETH; |
| memcpy(boots_if.cs, argv[1], strlen(argv[1])); |
| } |
| |
| if (argc > 2 && !memcmp(argv[1], "-relay", strlen("-relay"))) { |
| boots_if.clif = BOOTS_CLIF_UART; |
| snprintf(boots_if.cli, sizeof(boots_if.cli), "/dev/%s", argv[2]); |
| } else { |
| boots_if.clif = BOOTS_CLIF_USER; |
| } |
| #else |
| while (i < argc) { |
| // check interface for BT side |
| if (!memcmp(argv[i], "tty", strlen("tty"))) { |
| if (i + 1 < argc) { |
| boots_if.csif = BOOTS_CSIF_UART; |
| if (memcmp(argv[i], "/dev/", strlen("/dev/"))) |
| snprintf(boots_if.cs, sizeof(boots_if.cs), "/dev/%s", argv[i]); |
| boots_if.cs_speed = strtol(argv[i + 1], NULL, 10); |
| BPRINT_D("cs_speed: %d", boots_if.cs_speed); |
| i += 2; |
| } else { |
| BPRINT_E("Lack a parameter for %s", argv[i]); |
| return; |
| } |
| } else if (!memcmp(argv[i], "eth", strlen("eth"))) { |
| boots_if.csif = BOOTS_CSIF_ETH; |
| long cp_len = strlen(argv[i + 1]) > sizeof(boots_if.cs) ? sizeof(boots_if.cs) : strlen(argv[i + 1]); |
| memcpy(boots_if.cs, argv[i + 1], cp_len); |
| i += 2; |
| } else if (!memcmp(argv[i], "-relay", strlen("-relay"))) { |
| if (boots_if.csif == BOOTS_IF_NONE) { |
| // boots_srv as relayer in PC/NB |
| if (i + 2 < argc && strtol(argv[i + 2], NULL, 10) != 0) { |
| snprintf(boots_if.cs, sizeof(boots_if.cs), "%s %s", argv[i + 1], argv[i + 2]); |
| i += 2; |
| } else if (i + 1 < argc) { |
| snprintf(boots_if.cs, sizeof(boots_if.cs), "%s", argv[i + 1]); |
| i++; |
| } else { |
| BPRINT_E("Lack a parameter for %s", argv[i]); |
| return; |
| } |
| boots_if.csif = BOOTS_CSIF_UART; |
| } else { |
| // boots CLI |
| if (i + 2 < argc && !memcmp(argv[i + 1], "tty", strlen("tty")) |
| && strtol(argv[i + 2], NULL, 10) != 0) { |
| snprintf(boots_if.cli, sizeof(boots_if.cli), "/dev/%s", argv[i + 1]); |
| boots_if.cli_speed = strtol(argv[i + 2], NULL, 10); |
| boots_if.clif = BOOTS_CLIF_UART; |
| i += 2; |
| } else { |
| BPRINT_E("Incorrect argument for %s", argv[i]); |
| return; |
| } |
| } |
| } else if (*argv[i] == '-') { |
| boots_if.clif = BOOTS_CLIF_USER; |
| i++; |
| } else { |
| i++; |
| } |
| } |
| |
| if (boots_if.csif == BOOTS_IF_NONE) { |
| boots_if.csif = BOOTS_CSIF_SKT; |
| boots_if.clif = BOOTS_CLIF_USER; |
| } |
| #endif |
| BPRINT_D("cs: %s, cs_speed: %d", boots_if.cs, boots_if.cs_speed); |
| BPRINT_I("%s(%d) <-> %s(%d) <-> server", c_inf[boots_if.clif], |
| boots_if.clif, c_inf[boots_if.csif], boots_if.csif); |
| } |
| |
| //--------------------------------------------------------------------------- |
| static char *boots_chk_btif(char *interface) |
| { |
| #define BOOTS_SRV_LOCAL "./boots_srv " |
| #define BOOTS_SRV "boots_srv " |
| #define BOOTS_AND " &" |
| |
| #define BTPROTO_HCI 1 |
| |
| int i = 0; |
| static char server[64] = {0}; |
| |
| if (*interface == '-') { // no assign btif or clif |
| // do auto detect |
| BPRINT_D("%s: DO auto detect", __func__); |
| if (access(boots_btif[0].p, R_OK) == 0) { |
| // STPBT |
| i = 0; |
| boots_if.btif = BOOTS_BTIF_STPBT; |
| } else if ((i = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) != -1) { |
| // HCI |
| BPRINT_D("%s: HCI: %d", __func__, i); |
| close(i); |
| i = 1; |
| boots_if.btif = BOOTS_BTIF_HCI; |
| } else { |
| BPRINT_E("%s: stpbt/HCI are all not exist", __func__); |
| return NULL; |
| } |
| } else { |
| BPRINT_D("%s: btif assigned %s", __func__, interface); |
| while (boots_btif[i].inf) { |
| if (!strcmp(interface, boots_btif[i].n)) |
| break; |
| i++; |
| } |
| boots_if.btif = boots_btif[i].inf; |
| if (i + 1 == ARRAY_SIZE(boots_btif)) { |
| BPRINT_E("%s: boots doesn't support \"%s\"", __func__, interface); |
| return NULL; |
| } |
| } |
| |
| if (boots_if.clif == BOOTS_IF_NONE && boots_if.csif == BOOTS_CSIF_UART && strlen(boots_if.cs)) { |
| snprintf(server, sizeof(server), boots_local_exe ? BOOTS_SRV_LOCAL "%s %s &" : BOOTS_SRV "%s %s &", boots_if.cs, boots_btif[i].n); |
| } else { |
| snprintf(server, sizeof(server), boots_local_exe ? BOOTS_SRV_LOCAL "%s &" : BOOTS_SRV "%s &", boots_btif[i].n); |
| } |
| BPRINT_D("%s: server: %s", __func__, server); |
| return server; |
| } |
| |
| //--------------------------------------------------------------------------- |
| static int boots_invoke_boots_srv(char *path) |
| { |
| int cont = 0; |
| if (path == NULL) return 0; |
| |
| // check boots_srv is running or not |
| if (osi_system("pidof boots_srv > /dev/null") != 0) { |
| if (osi_system(path) == 0) { |
| BPRINT_I("Server(%s) executing...", path); |
| while(access(BOOTS_SRVSK_NAME, F_OK) == -1) { |
| usleep(100 * 1000); |
| cont++; |
| if (cont > 20) { |
| BPRINT_E("access BOOTS_SRVSK_NAME(%s) failed: %s(%d)", BOOTS_SRVSK_NAME, strerror(errno), errno); |
| return 0; |
| } |
| } |
| } else { |
| BPRINT_E("***** WARNING: Please input # %s, if boots_srv isn't running *****", |
| path); |
| } |
| } |
| return 1; |
| } |
| |
| //--------------------------------------------------------------------------- |
| static int boots_killall_boots_srv(void) |
| { |
| int ret = -1; |
| |
| ret = osi_system("killall boots_srv > /dev/null"); |
| if (ret) { |
| BPRINT_W("*** Please input #killall boots_srv ***"); |
| BPRINT_D("%s: kill boots_srv(%d)", __func__, ret); |
| } |
| |
| return ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| static void boots_sig_handler(int signum) |
| { |
| UNUSED(signum); |
| if (BOOTS_STRESS_MEASURE_IN_BOOTS) |
| boots_stress_deinit(); |
| exit(0); |
| } |
| |
| //--------------------------------------------------------------------------- |
| static void boots_tell_socket_end(int fd, struct sockaddr_un *addr) |
| { |
| char skend[] = {'s', 'e', 'n', 'd'}; |
| |
| boots_sk_send(fd, (void *)skend, sizeof(skend), addr, BOOTS_SRVSK_NAME); |
| } |
| |
| static void boots_tell_ethernet_end(int fd, struct sockaddr_in *addr) |
| { |
| char skend[] = {'s', 'e', 'n', 'd'}; |
| addr->sin_family = AF_INET; |
| addr->sin_port = ETH_UDP_SRV_PORT; |
| addr->sin_addr.s_addr = inet_addr(boots_if.cs); |
| boots_eth_send(fd, (void *)skend, sizeof(skend), addr); |
| } |
| |
| //--------------------------------------------------------------------------- |
| #define USAGE_DETAILS (1 << 0) |
| #define USAGE_DETAILS_MTK (1 << 1) |
| static void boots_cmd_usage(uint8_t detail) |
| { |
| int i = 0; |
| extern boots_cmds_s commands[]; |
| |
| printf("Boots - MTK Bluetooth Test Suite ver:%s(rev:%s)\n", VERSION, REV); |
| printf("Modular Commands:\n"); |
| for (i = 0; commands[i].cmd; i++) { |
| if (commands[i].hidden == false) |
| printf(" "BLUE"%s"NONE" - %s\n", commands[i].cmd, commands[i].comment); |
| else if (detail & USAGE_DETAILS_MTK) |
| printf(" "BLUE"%s"NONE" - %s\n", commands[i].cmd, commands[i].comment); |
| |
| if (detail & USAGE_DETAILS && commands[i].details) { |
| if (commands[i].hidden == false) |
| printf("%s\n", commands[i].details); |
| else if (detail & USAGE_DETAILS_MTK) |
| printf("%s\n", commands[i].details); |
| } |
| } |
| printf("For specfic command details use: ./boots -c <CMD> -h\n"); |
| } |
| |
| //--------------------------------------------------------------------------- |
| static void boots_country_cmd_usage(uint8_t detail) |
| { |
| int i = 0; |
| extern boots_country_cmds_s country_commands[]; |
| |
| printf("Boots - MTK Bluetooth Test Suite ver:%s(rev:%s)\n", VERSION, REV); |
| printf("Power Limit Commands:\n"); |
| for (i = 0; country_commands[i].cmd; i++) { |
| if (country_commands[i].hidden == false) |
| printf(" "BLUE"%s"NONE" - %s\n", country_commands[i].cmd, country_commands[i].comment); |
| else if (detail & USAGE_DETAILS_MTK) |
| printf(" "BLUE"%s"NONE" - %s\n", country_commands[i].cmd, country_commands[i].comment); |
| |
| if (detail & USAGE_DETAILS && country_commands[i].details) { |
| if (country_commands[i].hidden == false) |
| printf("%s\n", country_commands[i].details); |
| else if (detail & USAGE_DETAILS_MTK) |
| printf("%s\n", country_commands[i].details); |
| } |
| } |
| printf("For specfic command details use: ./boots -c <CMD> -h\n"); |
| } |
| |
| //--------------------------------------------------------------------------- |
| static void boots_help(void) |
| { |
| printf("Boots - MTK Bluetooth Test Suite ver:%s(rev:%s)\n", VERSION, REV); |
| printf("Usage:\n"); |
| printf(BLUE" boots [BT Interface] <InputMethod/RelayMode> [parameters]\n"NONE); |
| printf(" NOTE: DO NOTE reorder\n"); |
| printf(" BT Interface:\n"); |
| printf("\tPlease ignore this if not through UART/Ethernet to connect platform(BT)\n"); |
| printf("\tttyX Through UART send to BT\n"); |
| printf("\t ex: ./boots ttyACM0 115200 ...\n"); |
| printf("\tethX Through Ethernet send to BT, need server IP\n"); |
| printf("\t ex: ./boots eth0 10.1.1.1 ...\n"); |
| printf(" InputMethod: [parameters]\n"); |
| printf("\t-f File, ex: ./boots -f test.boots\n"); |
| printf("\t-r Raw data, ex: ./boots -r CMD 03 0C 00\n"); |
| printf("\t-c Command, for more command information on the usage of everyone command use:\n"); |
| printf("\t ./boots -c [detail]\n"); |
| printf("\t-relay Through serial port to input\n"); |
| printf("\t ex: ./boots ttyACM0 115200 -relay ttyUSB0 115200\n"); |
| printf("\t ex: ./boots -relay ttyGS2\n"); |
| printf("\t ex: ./boots -relay eth0 10.1.1.1\n"); |
| printf(" Others:\n"); |
| printf("\tstop Stop service since boots_srv is running in background\n"); |
| } |
| |
| //--------------------------------------------------------------------------- |
| static ssize_t boots_read(int fd, void *buf, size_t buf_size, int inf) |
| { |
| ssize_t ret = 0; |
| |
| if (!buf || !buf_size || !inf) { |
| BPRINT_E("%s: Invalid argument(buf: %p, buf size: %d, inf: %d)", |
| __func__, buf, (int)buf_size, inf); |
| return -EINVAL; |
| } else if (fd < 0) { |
| BPRINT_E("%s: Bad file descriptor(%d)", __func__, fd); |
| return -EBADFD; |
| } |
| |
| if (inf == BOOTS_CSIF_SKT) { |
| ret = boots_sk_recv(fd, buf, buf_size, 0, NULL, NULL); |
| } else if (inf == BOOTS_CSIF_UART || inf == BOOTS_CLIF_UART) { |
| ret = boots_uart_read(fd, buf, buf_size); |
| } else if (inf == BOOTS_CSIF_ETH) { |
| ret = boots_eth_recv(fd, buf, buf_size, 0); |
| } else { |
| BPRINT_E("%s: Incorrect interface(%d)", __func__, inf); |
| } |
| return ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| static ssize_t boots_write(int fd, const void *buf, size_t len, int inf) |
| { |
| ssize_t ret = 0; |
| |
| if (!buf || !len || !inf) { |
| BPRINT_E("%s: Invalid argument(buf: %p, len: %d, inf: %d)", __func__, buf, (int)len, inf); |
| return -EINVAL; |
| } else if (fd < 0) { |
| BPRINT_E("%s: Bad file descriptor(%d)", __func__, fd); |
| return -EBADFD; |
| } |
| |
| if (inf == BOOTS_CSIF_SKT) { |
| ret = boots_sk_send(fd, buf, len, NULL, BOOTS_SRVSK_NAME); |
| } else if (inf == BOOTS_CSIF_UART || inf == BOOTS_CLIF_UART) { |
| ret = boots_uart_write(fd, buf, len); |
| } else if (inf == BOOTS_CSIF_ETH) { |
| struct sockaddr_in sockaddr; |
| sockaddr.sin_family = AF_INET; |
| sockaddr.sin_port = ETH_UDP_SRV_PORT; |
| sockaddr.sin_addr.s_addr = inet_addr(boots_if.cs); |
| ret = boots_eth_send(fd, buf, len, &sockaddr); |
| } else { |
| BPRINT_E("%s: Incorrect interface(%d)", __func__, inf); |
| } |
| return ret; |
| } |
| |
| //--------------------------------------------------------------------------- |
| void boots_chk_local_exe(char *argv) |
| { |
| if (argv == NULL) { |
| BPRINT_E("%s: argv should not NULL", __func__); |
| return; |
| } |
| |
| if (*argv == '.' && *(argv + 1) == '/') { |
| boots_local_exe = 1; |
| } else { |
| boots_local_exe = 0; |
| } |
| } |
| |
| //--------------------------------------------------------------------------- |
| int main(int argc, char *argv[]) |
| { |
| static pkt_list_s *pkt = NULL; |
| static script_set_s sfile = {NULL, 0, 0, 0, 0}; |
| static uint8_t buf[HCI_BUF_SIZE] = {0}; |
| static int cont = 0; |
| size_t len = 0; |
| ssize_t read_len = 0; |
| int csw_fd = -1; |
| int csr_fd = -1; |
| int cli_uartfd = -1; |
| int type = 0; |
| struct sockaddr_un skaddr_cli; |
| struct sockaddr_un skaddr_srv; |
| socklen_t sklen_cli = {0}; |
| socklen_t sklen_srv = {0}; |
| struct sockaddr_in ethaddr_cli; |
| struct sockaddr_in ethaddr_srv; |
| fd_set readfs; |
| struct sigaction sigact; |
| struct timeval time_start; |
| struct timeval time_end; |
| uint32_t diff_time; |
| int which = PRIO_PROCESS; |
| id_t pid; |
| int priority = -20; |
| int ret; |
| |
| // Register signal handler |
| sigact.sa_handler = boots_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); |
| |
| // For root permission |
| CHECK_USERID(); |
| |
| // Local execute or not |
| boots_chk_local_exe(argv[0]); |
| |
| if (argc == 2 && !memcmp("-c", argv[1], strlen("-c"))) { |
| // Print commands |
| boots_cmd_usage(0); |
| exit(0); |
| } else if (argc == 2 && !memcmp("-o", argv[1], strlen("-o"))) { |
| // Print commands |
| boots_country_cmd_usage(0); |
| exit(0); |
| } else if (argc == 3 && !memcmp("-c", argv[1], strlen("-c"))) { |
| if (!memcmp("detail", argv[2], strlen("detail"))) { |
| boots_cmd_usage(1); |
| exit(0); |
| } else if (!memcmp("mtk", argv[2], strlen("mtk"))) { |
| boots_cmd_usage(3); |
| exit(0); |
| } else { |
| // do nothing for command without any parameters. |
| } |
| } else if (argc == 2 && !memcmp("stop", argv[1], strlen("stop"))) { |
| boots_killall_boots_srv(); |
| return 0; |
| } else if (argc == 3 && !memcmp("-o", argv[1], strlen("-o"))) { |
| if (!memcmp("detail", argv[2], strlen("detail"))) { |
| boots_country_cmd_usage(1); |
| exit(0); |
| } else if (!memcmp("mtk", argv[2], strlen("mtk"))) { |
| boots_country_cmd_usage(3); |
| exit(0); |
| } else { |
| // do nothing for command without any parameters. |
| } |
| } else if (argc < 3) { |
| // Print help |
| boots_help(); |
| exit(0); |
| } |
| |
| /** country command set, because it's not related controller operation |
| * Only access file |
| */ |
| if (!memcmp("-o", argv[1], strlen("-o"))) { |
| boots_country_set_handler(argv + 2, argc - 2); |
| goto exit; |
| } |
| |
| // Confirm interface between client/server, upper layer |
| boots_chk_if(argc - 1, &argv[1]); |
| |
| /** Communication Interface with boots_srv */ |
| if (boots_if.csif == BOOTS_CSIF_SKT) { |
| // Check interface is support or not |
| if (!boots_invoke_boots_srv(boots_chk_btif(argv[1]))) |
| exit(1); |
| |
| // create socket |
| if (boots_sk_create(&csr_fd, &skaddr_cli, &sklen_cli, BOOTS_CLISK_NAME, 0)) { |
| BPRINT_E("Create socket failed"); |
| exit(1); |
| } |
| |
| // connect socket |
| if (boots_sk_create(&csw_fd, &skaddr_srv, &sklen_srv, BOOTS_SRVSK_NAME, 1)) { |
| BPRINT_E("Connect socket failed"); |
| boots_sk_close(&csr_fd); |
| exit(1); |
| } |
| |
| } else if (boots_if.csif == BOOTS_CSIF_UART) { |
| if (boots_if.clif == BOOTS_IF_NONE) { |
| // Maybe last time user use command ask BT into DUT mode |
| boots_killall_boots_srv(); |
| sleep(1); |
| // means boots_srv as relayer in PC/NB |
| boots_invoke_boots_srv(boots_chk_btif(argv[1])); |
| exit(1); |
| |
| } else { |
| // client/server communication interface |
| csw_fd = boots_uart_init(boots_if.cs, boots_if.cs_speed); |
| if (csw_fd < 0) { |
| BPRINT_E("%s: Open serial port:%s failed(%d)!", __func__, boots_if.cs, csw_fd); |
| exit(1); |
| } |
| csr_fd = csw_fd; |
| } |
| |
| } else if (boots_if.csif == BOOTS_CSIF_ETH) { |
| // create socket |
| if (boots_eth_create(&csr_fd, ðaddr_cli, 0)) { |
| BPRINT_E("Create socket failed"); |
| exit(1); |
| } |
| // connect socket |
| if (boots_eth_create(&csw_fd, ðaddr_srv, 1)) { |
| BPRINT_E("Connect socket failed"); |
| boots_eth_close(&csr_fd); |
| exit(1); |
| } |
| } else { |
| BPRINT_E("Unknown communication interface"); |
| exit(1); |
| } |
| |
| /** Input Interface for boots */ |
| if (boots_if.clif == BOOTS_CLIF_UART) { |
| cli_uartfd = boots_uart_init(boots_if.cli, boots_if.cli_speed); |
| if (cli_uartfd < 0) { |
| BPRINT_E("Open serial port:%s failed(%d)!!", boots_if.cli, cli_uartfd); |
| goto exit; |
| } |
| cont = 1; |
| |
| } else { |
| if ((type = getopt(argc, argv, "frco")) != -1) { |
| BPRINT_D("optopt: %d, opterr: %d, optind: %d", optopt, opterr, optind); |
| switch (type) { |
| case 'f': /** script file */ |
| sfile.script = boots_script_open(*(argv + optind)); |
| if (!sfile.script) { |
| goto exit; |
| } |
| break; |
| case 'r': /** raw data */ |
| pkt = boots_raw_cmd_handler(argv + optind, argc - optind); |
| break; |
| case 'c': /** command set */ |
| pkt = boots_cmd_set_handler(argv + optind, argc - optind); |
| break; |
| #if 0 /** process this in above */ |
| case 'o': |
| pkt = boots_country_set_handler(argv + optind, argc - optind); |
| break; |
| #endif |
| default: |
| BPRINT_W("Unknown type: %c", type); |
| break; |
| }; |
| if (!pkt && !sfile.script) goto exit; |
| } |
| } |
| |
| pid = getpid(); |
| ret = setpriority(which, pid, priority); |
| if (ret != 0) { |
| BPRINT_I("setpriority fail: %s(%d)", strerror(errno), errno); |
| } |
| |
| /** Process handler */ |
| do { |
| int ret = -1; |
| struct timeval timo; |
| |
| if (sfile.script) { |
| pkt = boots_script_get(sfile.script); |
| if (pkt == NULL) |
| break; // Could end of file |
| } |
| |
| // default timeout |
| if (sfile.timo) { |
| timo.tv_sec = sfile.timo / 1000; |
| timo.tv_usec = (sfile.timo % 1000) * 1000; |
| } else { |
| timo.tv_sec = 3; |
| timo.tv_usec = 0; |
| } |
| if (pkt) { |
| BPRINT_D("s_type: %d", pkt->s_type); |
| switch (pkt->s_type) { |
| case SCRIPT_NONE: // modular commands |
| case SCRIPT_CMD: // hci_cmd script |
| case SCRIPT_STRESS: // stress test script |
| case SCRIPT_LOOPBACK: // loopback test script |
| case SCRIPT_LPTIMER: // loopback test script with timer |
| pkt = boots_pkt_node_pop(pkt, buf, &len); |
| break; |
| case SCRIPT_TX: // combo tool script |
| pkt = boots_pkt_node_pop(pkt, buf, &len); |
| if (len) { |
| // Send command, if input by user or script |
| boots_write(csw_fd, (void *)buf, len, boots_if.csif); |
| boots_pkt_handler(buf, len, NULL); |
| memset(buf, 0, sizeof(buf)); |
| len = 0; |
| } |
| continue; |
| case SCRIPT_RX: |
| case SCRIPT_WAITRX: |
| FD_ZERO(&readfs); |
| if (csr_fd >= 0) |
| FD_SET(csr_fd, &readfs); |
| ret = select(csr_fd + 1, &readfs, NULL, NULL, &timo); |
| if (ret > 0) { |
| read_len = boots_read(csr_fd, buf, sizeof(buf), boots_if.csif); |
| if (read_len > 0) { |
| cont = boots_pkt_handler(buf, (size_t)read_len, pkt ? &pkt : NULL); |
| memset(buf, 0, sizeof(buf)); |
| read_len = 0; |
| } |
| } else if (ret == 0) { |
| goto exit; |
| } |
| continue; |
| case SCRIPT_TITLE: |
| case SCRIPT_PROC: |
| BPRINT_I("%s", pkt->u_cnt.msg); // Just print msg |
| pkt = boots_pkt_node_pop(pkt, NULL, NULL); |
| continue; |
| case SCRIPT_TIMEOUT: |
| if (pkt->u_cnt.timo) { |
| sfile.timo = pkt->u_cnt.timo; |
| } |
| pkt = boots_pkt_node_pop(pkt, NULL, NULL); |
| continue; |
| case SCRIPT_WAIT: |
| if (pkt->u_cnt.wait) { |
| (void)usleep(pkt->u_cnt.wait * 1000); |
| } |
| pkt = boots_pkt_node_pop(pkt, NULL, NULL); |
| continue; |
| case SCRIPT_USBALT: |
| // TODO |
| continue; |
| case SCRIPT_LOOP: |
| sfile.loop = pkt->u_cnt.loop; |
| if (sfile.script) |
| sfile.loop_pos = ftell(sfile.script); |
| pkt = boots_pkt_node_pop(pkt, NULL, NULL); |
| BPRINT_D("Looping"); |
| continue; |
| case SCRIPT_LOOPEND: |
| if (!sfile.loop) { |
| sfile.loop_pos = 0; |
| BPRINT_D("Loop End"); |
| } else { |
| if ((--sfile.loop) && sfile.script && sfile.loop_pos >= 0) |
| boots_script_loop(sfile.script, sfile.loop_pos); |
| } |
| pkt = boots_pkt_node_pop(pkt, NULL, NULL); |
| continue; |
| case SCRIPT_RSSI: // Background RSSI scan |
| if (pkt->u_cnt.rssi_s->stop) |
| boots_pkt_cleanup_report_rssi(1); |
| else { |
| boots_pkt_cleanup_report_rssi(0); |
| memcpy(&rssi_setting, pkt->u_cnt.rssi_s, sizeof(rssi_set_s)); |
| } |
| buf[0] = SCRIPT_RSSI; |
| memcpy(&buf[1], pkt->u_cnt.rssi_s, sizeof(rssi_set_s)); |
| len = sizeof(rssi_set_s) + 1; |
| boots_write(csw_fd, (void *)buf, len, boots_if.csif); |
| memset(buf, 0, sizeof(buf)); |
| len = 0; |
| pkt = boots_pkt_node_pop(pkt, NULL, NULL); |
| break; |
| case SCRIPT_END: |
| BPRINT_I("Script End"); |
| pkt = boots_pkt_node_pop(pkt, NULL, NULL); |
| boots_script_close(sfile.script); |
| sfile.script = NULL; |
| goto exit; |
| default: |
| break; |
| } |
| } |
| |
| if (len) { |
| if (pkt && (pkt->s_type == SCRIPT_STRESS || pkt->s_type == SCRIPT_LOOPBACK || pkt->s_type == SCRIPT_LPTIMER)) { |
| if (BOOTS_STRESS_MEASURE_IN_BOOTS) |
| boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_SEND_CMD_START); |
| } |
| |
| // Send command, if input by user or script |
| boots_write(csw_fd, (void *)buf, len, boots_if.csif); |
| |
| if (pkt && (pkt->s_type == SCRIPT_STRESS || pkt->s_type == SCRIPT_LOOPBACK || pkt->s_type == SCRIPT_LPTIMER)) { |
| if (BOOTS_STRESS_MEASURE_IN_BOOTS) |
| boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_SEND_CMD_FINISH); |
| if (BOOTS_STRESS_SHOW_ALL_CMD) |
| boots_pkt_handler(buf, len, NULL); |
| if (pkt->s_type == SCRIPT_LPTIMER) |
| gettimeofday(&time_start, NULL); |
| } else |
| boots_pkt_handler(buf, len, NULL); |
| memset(buf, 0, sizeof(buf)); |
| len = 0; |
| } |
| |
| FD_ZERO(&readfs); |
| |
| if (cli_uartfd >= 0) |
| FD_SET(cli_uartfd, &readfs); |
| if (csr_fd >= 0) |
| FD_SET(csr_fd, &readfs); |
| |
| ret = select(MAX(cli_uartfd, csr_fd) + 1, &readfs, NULL, NULL, &timo); |
| if (ret > 0) { |
| if (cli_uartfd >= 0 && FD_ISSET(cli_uartfd, &readfs)) { |
| // read from UART(CBT) |
| read_len = boots_read(cli_uartfd, buf, sizeof(buf), boots_if.clif); |
| if (read_len > 0) { |
| // write to platform |
| boots_write(csw_fd, (void *)buf, (size_t)read_len, boots_if.csif); |
| boots_pkt_handler(buf, (size_t)read_len, NULL); |
| memset(buf, 0, sizeof(buf)); |
| read_len = 0; |
| } |
| } |
| if (FD_ISSET(csr_fd, &readfs)) { |
| // read from platform |
| read_len = boots_read(csr_fd, buf, sizeof(buf), boots_if.csif); |
| |
| if (read_len > 0 && boots_if.clif == BOOTS_CLIF_USER) { |
| cont = boots_pkt_handler(buf, read_len, pkt ? &pkt : NULL); |
| } else if (read_len > 0 && boots_if.clif == BOOTS_CLIF_UART) { |
| // write to UART(CBT) |
| boots_write(cli_uartfd, (void *)buf, read_len, boots_if.clif); |
| boots_pkt_handler(buf, read_len, NULL); |
| } |
| |
| if (pkt && pkt->s_type == SCRIPT_STRESS) { |
| if (BOOTS_STRESS_MEASURE_IN_BOOTS) |
| boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_RECEIVE_EVENT_FINISH); |
| } else if (pkt && (pkt->s_type == SCRIPT_LOOPBACK || pkt->s_type == SCRIPT_LPTIMER)) { |
| if (BOOTS_STRESS_MEASURE_IN_BOOTS && !BOOTS_STRESS_MEASURE_LBT_TOTAL_LATENCY) |
| boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_RECEIVE_EVENT_FINISH); |
| if (buf[0] == HCI_EVENT_PKT && read_len == 8) { |
| // should read again (Titan:Why read again but not use it?) |
| boots_read(csr_fd, buf, sizeof(buf), boots_if.csif); |
| } else if (buf[0] == HCI_EVENT_PKT && buf[8] == HCI_ACL_PKT && ((size_t)read_len) == (8 + pkt->len)) { |
| // current loopback test iteration is finished |
| } else if (buf[0] == HCI_ACL_PKT) { |
| // current loopback test iteration is finished |
| } else { |
| BPRINT_E("Receive unknonw type %02X, len=%d(EVENT/ACL is expected)", buf[0], (int)read_len); |
| exit(0); |
| } |
| if (BOOTS_STRESS_MEASURE_IN_BOOTS && BOOTS_STRESS_MEASURE_LBT_TOTAL_LATENCY) |
| boots_stress_record_timestamp(BOOTS_STRESS_TIMESTAMP_RECEIVE_EVENT_FINISH); |
| if (pkt->s_type == SCRIPT_LPTIMER) { |
| gettimeofday(&time_end, NULL); |
| diff_time = (time_end.tv_usec + time_end.tv_sec * 1000000) - (time_start.tv_usec + time_start.tv_sec * 1000000); |
| if (boots_loop_timer > 0 && (unsigned int)boots_loop_timer > (diff_time / 1000)) |
| usleep(boots_loop_timer*1000 - diff_time); |
| } |
| } |
| memset(buf, 0, sizeof(buf)); |
| read_len = 0; |
| } |
| } else if (ret == 0) { |
| // timeout |
| if (boots_if.clif == BOOTS_CLIF_UART) |
| cont = 1; |
| else |
| cont = 0; |
| } else { |
| BPRINT_D("Unexpect return: %d", ret); |
| } |
| } while (cont || sfile.script); |
| |
| exit: |
| if (boots_if.csif == BOOTS_CSIF_SKT) { |
| if (csw_fd >= 0) |
| boots_tell_socket_end(csw_fd, &skaddr_srv); |
| (void)usleep(1000); |
| if (csw_fd >= 0) |
| boots_sk_close(&csw_fd); |
| if (csr_fd >= 0) |
| boots_sk_close(&csr_fd); |
| unlink(BOOTS_CLISK_NAME); |
| } else if (boots_if.csif == BOOTS_CSIF_UART) { |
| if (csw_fd >= 0) |
| close(csw_fd); |
| } else if (boots_if.csif == BOOTS_CSIF_ETH) { |
| if (csw_fd >= 0) |
| boots_tell_ethernet_end(csw_fd, ðaddr_srv); |
| (void)usleep(1000); |
| if (csw_fd >= 0) |
| boots_eth_close(&csw_fd); |
| if (csr_fd >= 0) |
| boots_eth_close(&csr_fd); |
| } |
| if (boots_if.clif == BOOTS_CLIF_UART) { |
| if (cli_uartfd >= 0) |
| close(cli_uartfd); |
| } |
| boots_pkt_list_destroy(pkt); |
| pkt = NULL; |
| boots_script_close(sfile.script); |
| BPRINT_D("Input End"); |
| return 0; |
| } |
| |
| //--------------------------------------------------------------------------- |