From 88832b9d5ba836a7535243a91a4822f08c30547c Mon Sep 17 00:00:00 2001 From: Satish kumar sugasi <ssugas@codeaurora.org> Date: Mon, 21 Dec 2015 18:52:29 -0800 Subject: [PATCH] FM : Add new hci commands and compile changes Added HAL changes for hci commands like peek, poke, get/set of SINR sample/threshold.Compile time changes for adding correct includes based on new bluetooth stack structure, code cleanup and indendation. Change-Id: I5e48f0c0dc6165d61335c6d8cc269891e26dd548 --- Android.mk | 2 +- fm_hci/Android.mk | 4 +- fm_hci/fm_hci.c | 357 +++++++++++++++++---------------- fm_hci/fm_hci.h | 1 + helium/radio-helium-commands.h | 16 ++ helium/radio-helium.h | 36 +++- helium/radio_helium_hal.c | 230 +++++++++++++++++++-- helium/radio_helium_hal_cmds.c | 74 +++++++ jni/android_hardware_fm.cpp | 26 ++- qcom/fmradio/FmRxRdsData.java | 1 + 10 files changed, 557 insertions(+), 190 deletions(-) diff --git a/Android.mk b/Android.mk index 5b79fbf..fc3a54e 100644 --- a/Android.mk +++ b/Android.mk @@ -19,6 +19,7 @@ include $(BUILD_JAVA_LIBRARY) include $(LOCAL_PATH)/jni/Android.mk LOCAL_PATH := $(LOCAL_DIR_PATH) include $(LOCAL_PATH)/fmapp2/Android.mk + #LOCAL_PATH := $(LOCAL_DIR_PATH) #include $(LOCAL_PATH)/FMRecord/Android.mk @@ -32,5 +33,4 @@ LOCAL_PATH := $(LOCAL_DIR_PATH) include $(LOCAL_PATH)/libfm_jni/Android.mk #endif # is-vendor-board-platform #endif # BOARD_HAVE_QCOM_FM - #endif # Not (TARGET_USES_AOSP) diff --git a/fm_hci/Android.mk b/fm_hci/Android.mk index 1c4b949..2546902 100644 --- a/fm_hci/Android.mk +++ b/fm_hci/Android.mk @@ -11,7 +11,7 @@ else bdroid_CFLAGS += -DHAS_NO_BDROID_BUILDCFG endif -BDROID_DIR:= external/bluetooth/bluedroid +BDROID_DIR:= system/bt LOCAL_CFLAGS += $(bdroid_CFLAGS) @@ -28,6 +28,8 @@ LOCAL_CFLAGS += -std=c99 LOCAL_C_INCLUDES += \ $(BDROID_DIR)/hci/include \ + $(BDROID_DIR)/stack/include \ + $(BDROID_DIR)/osi/include \ $(LOCAL_PATH)/../helium LOCAL_MODULE := libfm-hci diff --git a/fm_hci/fm_hci.c b/fm_hci/fm_hci.c index 1394565..e0294ee 100644 --- a/fm_hci/fm_hci.c +++ b/fm_hci/fm_hci.c @@ -34,18 +34,24 @@ #include "bt_hci_bdroid.h" #include "bt_vendor_lib.h" -#include "hci.h" #include "userial.h" -#include "utils.h" #include "fm_hci.h" #include "wcnss_hci.h" #include <dlfcn.h> #include <sys/eventfd.h> #include <errno.h> +#include <string.h> int fm_fd; fm_hal_cb *hal_cb; +// The set of events one can send to the userial read thread. +// Note that the values must be >= 0x8000000000000000 to guarantee delivery +// of the message (see eventfd(2) for details on blocking behaviour). +enum { + USERIAL_RX_EXIT = 0x8000000000000000ULL +}; + void event_notification(uint16_t event) { pthread_mutex_lock(&fmHCIControlBlock.event_lock); @@ -84,90 +90,90 @@ volatile uint16_t command_credits; /* De-queues the FM CMD from the TX_Q */ void dequeue_fm_tx_cmd() { - TX_Q *new_first, *new_last; - static int cmd_count = 0; - static uint8_t credits = 0; - uint8_t i; - uint8_t temp_1 = 0x11; - - if (cmd_count >= MAX_FM_CMD_CNT) { - ALOGI("\n\n\t\tReached Max. CMD COUNT!!\n\n"); - lib_running = 0; - return; - } - - /* - * Save the 'first' pointer and make it NULL. - * This is to allow the FM-HAL to enqueue more CMDs to the TX_Q - * without having to contend for the 'tx_q_lock' with the FM-HCI thread. - * Once the pointer to the 'first' element in the TX_Q is available, - * send all the commands in the queue to WCNSS FILTER based on the - * command credits provided by the Controller. If command credits are - * not available, then wait for the same. - */ - pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); - if (!fmHCIControlBlock.first) { - ALOGI("No FM CMD available in the Q\n"); - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); - return; - } - else { - new_first = fmHCIControlBlock.first; - new_last = fmHCIControlBlock.last; - fmHCIControlBlock.first = fmHCIControlBlock.last = NULL; - } - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); - - //credits = command_credits; - - TX_Q *temp = new_first; - while(temp != NULL) { + TX_Q *new_first, *new_last; + static int cmd_count = 0; + static uint8_t credits = 0; + uint8_t i; + uint8_t temp_1 = 0x11; + + if (cmd_count >= MAX_FM_CMD_CNT) { + ALOGI("\n\n\t\tReached Max. CMD COUNT!!\n\n"); + lib_running = 0; + return; + } + + /* + * Save the 'first' pointer and make it NULL. + * This is to allow the FM-HAL to enqueue more CMDs to the TX_Q + * without having to contend for the 'tx_q_lock' with the FM-HCI thread. + * Once the pointer to the 'first' element in the TX_Q is available, + * send all the commands in the queue to WCNSS FILTER based on the + * command credits provided by the Controller. If command credits are + * not available, then wait for the same. + */ + pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); + if (!fmHCIControlBlock.first) { + ALOGI("No FM CMD available in the Q\n"); + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + return; + } + else { + new_first = fmHCIControlBlock.first; + new_last = fmHCIControlBlock.last; + fmHCIControlBlock.first = fmHCIControlBlock.last = NULL; + } + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + + //credits = command_credits; + + TX_Q *temp = new_first; + while(temp != NULL) { wait_for_cmd_credits: - pthread_mutex_lock(&fmHCIControlBlock.credit_lock); - while (command_credits == 0) { - ALOGI("\n\n\t\tWaiting for COMMAND CREDITS from CONTROLLER\n\n"); - pthread_cond_wait(&fmHCIControlBlock.cmd_credits_cond, &fmHCIControlBlock.credit_lock); - } - pthread_mutex_unlock(&fmHCIControlBlock.credit_lock); - - /* Check if we really got the command credits */ - //REVISIT this area - //if (credits) { - if (command_credits) { - ALOGI("%s: Sending the FM-CMD(prot_byte: 0x%x): 0x%x dequeued from TX_Q\n", __func__, temp->hdr->protocol_byte, temp->hdr->opcode); - - if (temp->hdr->plen) { - ALOGI("%s: CMD-PARAMS:", __func__); - for (i = 0; i < temp->hdr->plen; i++) - ALOGI(" <0x%x> ", temp->hdr->cmd_params[i]); - } else - ALOGE("%s: NO CMD-PARAMS available for this command", __func__); - - ALOGE("%s: Sizeof FM_HDR: %d", __func__, (int)sizeof(temp->hdr)); - /* Use socket 'fd' to send the command down to WCNSS Filter */ - write(fm_fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen)); - //write(fd, &temp_1, 1); - - /* Decrement cmd credits by '1' after sending the cmd*/ - command_credits--; - - /* TODO: - * Initialize 'cmd_cnt' to MAX_FM_CMD(?). Should we have any limit on the - * number of outstanding commands in the TX-Q ?? - */ - cmd_count--; - - /* Fetch the next cmd to be sent */ - temp = temp->next; - } else { - if (!lib_running) - break; - - ALOGI("\n\n\t\tFalse wakeup: Yet to get COMMAND CREDITS from CONTROLLER\n\n"); - goto wait_for_cmd_credits; - } - } + pthread_mutex_lock(&fmHCIControlBlock.credit_lock); + while (command_credits == 0) { + ALOGI("\n\n\t\tWaiting for COMMAND CREDITS from CONTROLLER\n\n"); + pthread_cond_wait(&fmHCIControlBlock.cmd_credits_cond, &fmHCIControlBlock.credit_lock); + } + pthread_mutex_unlock(&fmHCIControlBlock.credit_lock); + + /* Check if we really got the command credits */ + //REVISIT this area + //if (credits) { + if (command_credits) { + ALOGI("%s: Sending the FM-CMD(prot_byte: 0x%x): 0x%x dequeued from TX_Q\n", __func__, temp->hdr->protocol_byte, temp->hdr->opcode); + + if (temp->hdr->plen) { + ALOGI("%s: CMD-PARAMS:", __func__); + for (i = 0; i < temp->hdr->plen; i++) + ALOGI(" <0x%x> ", temp->hdr->cmd_params[i]); + } else + ALOGE("%s: NO CMD-PARAMS available for this command", __func__); + + ALOGE("%s: Sizeof FM_HDR: %d", __func__, (int)sizeof(temp->hdr)); + /* Use socket 'fd' to send the command down to WCNSS Filter */ + write(fm_fd, (uint8_t *)temp->hdr, (sizeof(FM_HDR) + temp->hdr->plen)); + //write(fd, &temp_1, 1); + + /* Decrement cmd credits by '1' after sending the cmd*/ + command_credits--; + + /* TODO: + * Initialize 'cmd_cnt' to MAX_FM_CMD(?). Should we have any limit on the + * number of outstanding commands in the TX-Q ?? + */ + cmd_count--; + + /* Fetch the next cmd to be sent */ + temp = temp->next; + } else { + if (!lib_running) + break; + + ALOGI("\n\n\t\tFalse wakeup: Yet to get COMMAND CREDITS from CONTROLLER\n\n"); + goto wait_for_cmd_credits; + } + } } @@ -218,30 +224,29 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) FD_SET(event_fd, &readFds); int fd_max = (event_fd > fd ? event_fd : fd); - ALOGE("%s: Waiting for events from WCNSS FILTER...\n", __func__); + ALOGV("%s: Waiting for events from WCNSS FILTER...\n", __func__); /* Wait for event/data from WCNSS Filter */ n = select(fd_max+1, &readFds, NULL, NULL, NULL); if (n > 0) { /* Check if event is available or not */ -#if 1 if (FD_ISSET(fd, &readFds)) { ret = read(fd, (uint8_t *)pbuf, (size_t)(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS)); if (0 == ret) { - ALOGE("%s: read() returned '0' bytes\n", __func__); + ALOGD("%s: read() returned '0' bytes\n", __func__); } else { - ALOGE("%s: read() returned %d bytes of FM event/data\n", __func__, ret); + ALOGV("%s: read() returned %d bytes of FM event/data\n", __func__, ret); while (ret > 0) { if (pbuf->evt_code == FM_CMD_COMPLETE) { - ALOGE("\n\t%s: Received %d bytes of CC event data from WCNSS FILTER!!!\n\t" + ALOGV("\n\t%s: Received %d bytes of CC event data from WCNSS FILTER!!!\n\t" "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n", __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[2], pbuf->cmd_params[1], pbuf->cmd_params[0], pbuf->cmd_params[3]); evt_type = FM_CMD_COMPLETE; } else if (pbuf->evt_code == FM_CMD_STATUS) { - ALOGE("\n\t%s: Received %d bytes of CS event data from WCNSS FILTER!!!\n\t" + ALOGV("\n\t%s: Received %d bytes of CS event data from WCNSS FILTER!!!\n\t" "Evt type\t: 0x%x \n\tEvt Code\t: 0x%x \n\tEvt len\t\t: 0x%x \n\topcode\t\t: 0x%x%x \n\tCmd Credits\t: 0x%x \n\tStatus\t\t: 0x%x\n", __func__, ret, pbuf->protocol_byte, pbuf->evt_code, pbuf->evt_len, pbuf->cmd_params[3], pbuf->cmd_params[2], pbuf->cmd_params[1], pbuf->cmd_params[0]); @@ -251,7 +256,6 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) lib_running =0; // commented till bt vendor include added // fm_vnd_if->ssr_cleanup(); - } else { ALOGI("%s: Not CS/CC Event: Recvd. Event Code: 0x%2x", __func__, pbuf->evt_code); evt_type = -1; @@ -260,7 +264,7 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) evt_len = pbuf->evt_len; /* Notify 'fmHCITask' about availability of event or data */ - ALOGE("%s: \nNotifying 'fmHCITask' availability of FM event or data...\n", __func__); + ALOGI("%s: \nNotifying 'fmHCITask' availability of FM event or data...\n", __func__); event_notification(HC_EVENT_RX); if (hal_cb && hal_cb->fm_evt_notify != NULL) @@ -272,11 +276,11 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) /* Provide command credits to allow fmHCITask to send cmds */ pthread_mutex_lock(&fmHCIControlBlock.credit_lock); if (evt_type == FM_CMD_COMPLETE) { - ALOGE("\n%s: Command Credit(s): '%d' received as part of CC Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[0], + ALOGD("\n%s: Command Credit(s): '%d' received as part of CC Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[0], pbuf->cmd_params[2], pbuf->cmd_params[1]); command_credits = pbuf->cmd_params[0]; } else if (evt_type == FM_CMD_STATUS) { - ALOGE("\n%s: Command Credit(s): '%d' received as part of CS Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[1], + ALOGI("\n%s: Command Credit(s): '%d' received as part of CS Event for FM-CMD: 0x%x%x \n", __func__, pbuf->cmd_params[1], pbuf->cmd_params[3], pbuf->cmd_params[2]); command_credits = pbuf->cmd_params[1]; } @@ -297,8 +301,7 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) } //end of processing the event } else - ALOGE("%s: No data available, though select returned!!!\n", __func__); -#endif + ALOGV("%s: No data available, though select returned!!!\n", __func__); } else if (n < 0) { ALOGE("%s: select() failed with return value: %d", __func__, ret); @@ -313,19 +316,19 @@ static int read_fm_event(int fd, FM_EVT_HDR *pbuf, int len) static void *userial_read_thread(void *arg) { - int length; - - FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); - - ALOGE("%s: Wait for events from the WCNSS Filter", __func__); - length = read_fm_event(fm_fd, evt_buf, sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); - ALOGE("length=%d\n",length); - if(length <=0){ - lib_running =0; - } - ALOGE("%s: Leaving userial_read_thread()", __func__); - pthread_exit(NULL); - return arg; + int length; + + FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); + + ALOGE("%s: Wait for events from the WCNSS Filter", __func__); + length = read_fm_event(fm_fd, evt_buf, sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS); + ALOGE("length=%d\n",length); + if(length <=0) { + lib_running =0; + } + ALOGE("%s: Leaving userial_read_thread()", __func__); + pthread_exit(NULL); + return arg; } /* @@ -334,29 +337,37 @@ static void *userial_read_thread(void *arg) */ static void* fmHCITask(void *arg) { - static uint16_t events; - - while (lib_running) { - pthread_mutex_lock(&fmHCIControlBlock.event_lock); - while (ready_events == 0) { - pthread_cond_wait(&fmHCIControlBlock.event_cond, &fmHCIControlBlock.event_lock); - } - - events = ready_events; - ready_events = 0; - pthread_mutex_unlock(&fmHCIControlBlock.event_lock); - - if ((events & 0xFFF8) == HC_EVENT_TX) { - ALOGI("\n@@@@@ FM-HCI Task : EVENT_TX available @@@@@\n"); - dequeue_fm_tx_cmd(); - } - if ((events & 0xFFF4) == HC_EVENT_RX) { - ALOGI("\n##### FM-HCI Task : EVENT_RX available #####\n"); - //TODO: Notify FM-HAL about event/data availablity - } - } - ALOGE("%s: ##### Exiting fmHCITask Worker thread!!! #####", __func__); - return arg; + static uint16_t events; + uint16_t ret; + while (lib_running) { + pthread_mutex_lock(&fmHCIControlBlock.event_lock); + while (ready_events == 0) { + pthread_cond_wait(&fmHCIControlBlock.event_cond, &fmHCIControlBlock.event_lock); + } + events = ready_events; + ready_events = 0; + pthread_mutex_unlock(&fmHCIControlBlock.event_lock); + + if ((events & 0xFFF8) == HC_EVENT_TX) { + ALOGI("\n@@@@@ FM-HCI Task : EVENT_TX available @@@@@\n"); + dequeue_fm_tx_cmd(); + } + if ((events & 0xFFF4) == HC_EVENT_RX) { + ALOGI("\n##### FM-HCI Task : EVENT_RX available #####\n"); + } + } + + ALOGE("%s: ##### Exiting fmHCITask Worker thread!!! #####", __func__); + ret = pthread_mutex_unlock(&fmHCIControlBlock.credit_lock); + ALOGE("%s: credit lock ret value =%d #####", __func__, ret); + pthread_mutex_destroy(&fmHCIControlBlock.credit_lock); + ret = pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + ALOGE("%s: tx queue lock ret value =%d #####", __func__, ret); + pthread_mutex_destroy(&fmHCIControlBlock.tx_q_lock); + ret = pthread_mutex_unlock(&fmHCIControlBlock.event_lock); + ALOGE("%s: event lock ret value =%d #####", __func__, ret); + pthread_mutex_destroy(&fmHCIControlBlock.event_lock); + return arg; } int fm_hci_init(fm_hal_cb *p_cb) @@ -470,34 +481,34 @@ err: void enqueue_fm_tx_cmd(FM_HDR *pbuf) { - pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); - - if (!fmHCIControlBlock.first) { - fmHCIControlBlock.first = (TX_Q *) malloc(sizeof(TX_Q)); - if (!fmHCIControlBlock.first) { - printf("Failed to allocate memory for first!!\n"); - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); - return; - } - fmHCIControlBlock.first->hdr = pbuf; - fmHCIControlBlock.first->next = NULL; - fmHCIControlBlock.last = fmHCIControlBlock.first; + pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock); + + if (!fmHCIControlBlock.first) { + fmHCIControlBlock.first = (TX_Q *) malloc(sizeof(TX_Q)); + if (!fmHCIControlBlock.first) { + printf("Failed to allocate memory for first!!\n"); + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + return; + } + fmHCIControlBlock.first->hdr = pbuf; + fmHCIControlBlock.first->next = NULL; + fmHCIControlBlock.last = fmHCIControlBlock.first; ALOGI("%s: FM-CMD ENQUEUED SUCCESSFULLY", __func__); - } else { - TX_Q *element = (TX_Q *) malloc(sizeof(TX_Q)); - if (!element) { - printf("Failed to allocate memory for element!!\n"); - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); - return; - } - fmHCIControlBlock.last->next = element; - element->hdr = pbuf; - element->next = NULL; - fmHCIControlBlock.last = element; + } else { + TX_Q *element = (TX_Q *) malloc(sizeof(TX_Q)); + if (!element) { + printf("Failed to allocate memory for element!!\n"); + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + return; + } + fmHCIControlBlock.last->next = element; + element->hdr = pbuf; + element->next = NULL; + fmHCIControlBlock.last = element; ALOGI("%s: fm-cmd enqueued successfully", __func__); - } + } - pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); + pthread_mutex_unlock(&fmHCIControlBlock.tx_q_lock); } /** Transmit frame */ @@ -510,8 +521,8 @@ void transmit(FM_HDR *pbuf) void userial_close_reader(void) { // Join the reader thread if it is still running. if (lib_running) { - // send_event(USERIAL_RX_EXIT); - int result = pthread_join(&fmHCIControlBlock.fmRxTaskThreadId, NULL); + fm_send_event(USERIAL_RX_EXIT); + int result = pthread_join(fmHCIControlBlock.fmRxTaskThreadId, NULL); if (result) ALOGE("%s failed to join reader thread: %d", __func__, result); return; @@ -520,13 +531,23 @@ void userial_close_reader(void) { } void fm_userial_close(void) { - if (lib_running) { - int result = pthread_join(&fmHCIControlBlock.fmRxTaskThreadId, NULL); - if (result) - ALOGE("%s failed to join reader thread: %d", __func__, result); - } - fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); - // Free all buffers still waiting in the RX queue. - // TODO: use list data structure and clean this up. - fm_fd = -1; + + pthread_cond_signal(&fmHCIControlBlock.event_cond); + pthread_cond_destroy(&fmHCIControlBlock.event_cond); + pthread_cond_signal(&fmHCIControlBlock.cmd_credits_cond); + pthread_cond_destroy(&fmHCIControlBlock.cmd_credits_cond); + + // Join the reader thread if it's still running. + if (lib_running) { + fm_send_event(USERIAL_RX_EXIT); + int result = pthread_join(fmHCIControlBlock.fmRxTaskThreadId, NULL); + if (result) + ALOGE("%s failed to join reader thread: %d", __func__, result); + } + lib_running =0; + ALOGE("%s close fm userial ", __func__); + fm_vnd_if->op(BT_VND_OP_FM_USERIAL_CLOSE, NULL); + // Free all buffers still waiting in the RX queue. + // TODO: use list data structure and clean this up. + fm_fd = -1; } diff --git a/fm_hci/fm_hci.h b/fm_hci/fm_hci.h index 431179b..8ffbf04 100644 --- a/fm_hci/fm_hci.h +++ b/fm_hci/fm_hci.h @@ -102,6 +102,7 @@ void transmit(FM_HDR *pbuf); int fm_hci_init(fm_hal_cb *); void fm_power(fm_power_state state); int open_serial_port(void); +void fm_userial_close(void); typedef struct { pthread_mutex_t tx_q_lock; diff --git a/helium/radio-helium-commands.h b/helium/radio-helium-commands.h index c480ea0..f76b7d2 100644 --- a/helium/radio-helium-commands.h +++ b/helium/radio-helium-commands.h @@ -76,6 +76,22 @@ enum helium_cmd_t { HCI_FM_HELIUM_DO_CALIBRATION, HCI_FM_HELIUM_SRCH_ALGORITHM, HCI_FM_HELIUM_GET_SINR, + HCI_FM_HELIUM_INTF_LOW_THRESHOLD, + HCI_FM_HELIUM_INTF_HIGH_THRESHOLD, + HCI_FM_HELIUM_SINR_THRESHOLD, + HCI_FM_HELIUM_SINR_SAMPLES, + HCI_FM_HELIUM_SPUR_FREQ, + HCI_FM_HELIUM_SPUR_FREQ_RMSSI, + HCI_FM_HELIUM_SPUR_SELECTION, + HCI_FM_HELIUM_UPDATE_SPUR_TABLE, + HCI_FM_HELIUM_VALID_CHANNEL, + HCI_FM_HELIUM_AF_RMSSI_TH, + HCI_FM_HELIUM_AF_RMSSI_SAMPLES, + HCI_FM_HELIUM_GOOD_CH_RMSSI_TH, + HCI_FM_HELIUM_SRCHALGOTYPE, + HCI_FM_HELIUM_CF0TH12, + HCI_FM_HELIUM_SINRFIRSTSTAGE, + HCI_FM_HELIUM_RMSSIFIRSTSTAGE, HCI_FM_HELIUM_RXREPEATCOUNT, HCI_FM_HELIUM_RSSI_TH, HCI_FM_HELIUM_AF_JUMP_RSSI_TH, diff --git a/helium/radio-helium.h b/helium/radio-helium.h index 8599316..5c21bdd 100644 --- a/helium/radio-helium.h +++ b/helium/radio-helium.h @@ -160,6 +160,9 @@ typedef void (*ert_cb)(char *ert); typedef void (*disable_cb)(); typedef void (*callback_thread_event)(unsigned int evt); typedef void (*rds_grp_cntrs_cb)(char *rds_params); +typedef void (*fm_peek_cb)(char *peek_rsp); +typedef void (*fm_ssbi_peek_cb)(char *ssbi_peek_rsp); +typedef void (*fm_ch_det_th_cb)(char *ch_det_rsp); typedef struct { size_t size; @@ -179,6 +182,9 @@ typedef struct { ert_cb ert_update_cb; disable_cb disabled_cb; rds_grp_cntrs_cb rds_grp_cntrs_rsp_cb; + fm_peek_cb fm_peek_rsp_cb; + fm_ssbi_peek_cb fm_ssbi_peek_rsp_cb; + fm_ch_det_th_cb fm_ch_det_th_rsp_cb; callback_thread_event thread_evt_cb; } fm_vendor_callbacks_t; @@ -499,7 +505,6 @@ struct hci_fm_blend_table { #define HCI_EV_RADIO_TEXT_PLUS_TAG 0x19 #define HCI_EV_HW_ERR_EVENT 0x1A - #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 #define HCI_REQ_CANCELED 2 @@ -1157,5 +1162,34 @@ struct helium_device { enum hlm_region_t region; struct hci_fm_dbg_param_rsp st_dbg_param; struct hci_ev_srch_list_compl srch_st_result; + struct hci_fm_riva_poke riva_data_req; + struct hci_fm_ssbi_req ssbi_data_accs; + struct hci_fm_ssbi_peek ssbi_peek_reg; + struct hci_fm_ch_det_threshold ch_det_threshold; }; +int hci_fm_disable_recv_req(); +int helium_search_list(struct hci_fm_search_station_list_req *s_list); +int helium_search_rds_stations(struct hci_fm_search_rds_station_req *rds_srch); +int helium_search_stations(struct hci_fm_search_station_req *srch); +int helium_cancel_search_req(); +int hci_fm_set_recv_conf_req (struct hci_fm_recv_conf_req *conf); +int hci_fm_get_program_service_req (); +int hci_fm_get_rds_grpcounters_req (int val); +int hci_fm_set_notch_filter_req (int val); +int helium_set_sig_threshold_req(char th); +int helium_rds_grp_mask_req(struct hci_fm_rds_grp_req *rds_grp_msk); +int helium_rds_grp_process_req(int rds_grp); +int helium_set_event_mask_req(char e_mask); +int helium_set_antenna_req(char ant); +int helium_set_fm_mute_mode_req(struct hci_fm_mute_mode_req *mute); +int hci_fm_tune_station_req(int param); +int hci_set_fm_stereo_mode_req(struct hci_fm_stereo_mode_req *param); +int hci_peek_data(struct hci_fm_riva_data *data); +int hci_poke_data(struct hci_fm_riva_poke *data); +int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *data); +int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *data); +int hci_fm_get_ch_det_th(); +int set_ch_det_thresholds_req(struct hci_fm_ch_det_threshold *ch_det_th); + + #endif /* __UAPI_RADIO_HCI_CORE_H */ diff --git a/helium/radio_helium_hal.c b/helium/radio_helium_hal.c index a9aa9f0..fd673ab 100644 --- a/helium/radio_helium_hal.c +++ b/helium/radio_helium_hal.c @@ -29,6 +29,8 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdio.h> #include <unistd.h> +#include <stdlib.h> +#include <string.h> #include <utils/Log.h> #include "radio-helium-commands.h" #include "radio-helium.h" @@ -38,6 +40,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. fm_vendor_callbacks_t *jni_cb; int hci_fm_get_signal_threshold(); int hci_fm_enable_recv_req(); +int hci_fm_mute_mode_req(struct hci_fm_mute_mode_req ); struct helium_device *radio; static int oda_agt; static int grp_mask; @@ -98,14 +101,18 @@ static void hci_cc_fm_disable_rsp(char *ev_buff) ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__); return; } + ALOGE("%s:enetred %s calling ", LOG_TAG, __func__); status = (char) *ev_buff; radio_hci_req_complete(status); if (radio->mode == FM_TURNING_OFF) { jni_cb->disabled_cb(); radio->mode = FM_OFF; + jni_cb->disabled_cb(); + jni_cb->thread_evt_cb(1); //close the userial port and power off the chip - fm_userial_close(); - fm_power(FM_RADIO_DISABLE); + ALOGE("%s:calling fm userial close\n", LOG_TAG ); + fm_userial_close(); + // fm_power(FM_RADIO_DISABLE); } } @@ -138,6 +145,57 @@ static void hci_cc_rds_grp_cntrs_rsp(char *ev_buff) jni_cb->rds_grp_cntrs_rsp_cb(&ev_buff[1]); } +static void hci_cc_riva_peek_rsp(char *ev_buff) +{ + char status; + + if (ev_buff == NULL) { + ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__); + return; + } + status = ev_buff[0]; + ALOGE("%s:%s, status =%d\n", LOG_TAG, __func__,status); + if (status < 0) { + ALOGE("%s:%s, peek failed=%d\n", LOG_TAG, __func__, status); + } + jni_cb->fm_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]); + radio_hci_req_complete(status); +} + +static void hci_cc_ssbi_peek_rsp(char *ev_buff) +{ + char status; + + if (ev_buff == NULL) { + ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__); + return; + } + status = ev_buff[0]; + ALOGE("%s:%s, status =%d\n", LOG_TAG, __func__,status); + if (status < 0) { + ALOGE("%s:%s,ssbi peek failed=%d\n", LOG_TAG, __func__, status); + } + jni_cb->fm_ssbi_peek_rsp_cb(&ev_buff[PEEK_DATA_OFSET]); + radio_hci_req_complete(status); +} + +static void hci_cc_get_ch_det_threshold_rsp(char *ev_buff) +{ + char status; + + if (ev_buff == NULL) { + ALOGE("%s:%s, buffer is null\n", LOG_TAG, __func__); + return; + } + status = ev_buff[0]; + ALOGE("%s:%s, status =%d\n", LOG_TAG, __func__,status); + if (status < 0) { + ALOGE("%s:%s,ssbi peek failed=%d\n", LOG_TAG, __func__, status); + } + memcpy(&radio->ch_det_threshold, &ev_buff[1], + sizeof(struct hci_fm_ch_det_threshold)); + radio_hci_req_complete(status); +} static inline void hci_cmd_complete_event(char *buff) { @@ -192,12 +250,18 @@ static inline void hci_cmd_complete_event(char *buff) case hci_status_param_op_pack(HCI_OCF_FM_READ_GRP_COUNTERS): hci_cc_rds_grp_cntrs_rsp(pbuf); break; -/* case hci_common_cmd_op_pack(HCI_OCF_FM_GET_SPUR_TABLE): - hci_cc_get_spur_tbl(buff); + case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA): + hci_cc_riva_peek_rsp(buff); break; case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_SSBI_PEEK_REG): hci_cc_ssbi_peek_rsp(buff); break; + case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_CH_DET_THRESHOLD): + hci_cc_get_ch_det_threshold_rsp(buff); + break; +/* case hci_common_cmd_op_pack(HCI_OCF_FM_GET_SPUR_TABLE): + hci_cc_get_spur_tbl(buff); + break; case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_SIGNAL_THRESHOLD): hci_cc_sig_threshold_rsp(buff); break; @@ -222,10 +286,6 @@ static inline void hci_cmd_complete_event(char *buff) hci_cc_riva_read_default_rsp(buff); break; - case hci_diagnostic_cmd_op_pack(HCI_OCF_FM_PEEK_DATA): - hci_cc_riva_peek_rsp(buff); - break; - case hci_common_cmd_op_pack(HCI_OCF_FM_GET_FEATURE_LIST): hci_cc_feature_list_rsp(buff); break; @@ -240,9 +300,6 @@ static inline void hci_cmd_complete_event(char *buff) hci_cc_do_calibration_rsp(buff); break; - case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_CH_DET_THRESHOLD): - hci_cc_get_ch_det_threshold_rsp(buff); - break; case hci_recv_ctrl_cmd_op_pack(HCI_OCF_FM_GET_BLND_TBL): hci_cc_get_blend_tbl_rsp(buff); break; @@ -364,6 +421,7 @@ static inline void hci_ev_radio_text(char *buff) while ((buff[len+RDS_OFFSET] != 0x0d) && (len < MAX_RT_LENGTH)) len++; + ALOGV("%s:%s: radio text length=%d\n", LOG_TAG, __func__,len); data = malloc(len+RDS_OFFSET); if (!data) { ALOGE("%s:Failed to allocate memory", LOG_TAG); @@ -521,7 +579,8 @@ static void hci_ev_hw_error(char *buff) { ALOGE("%s:%s: start", LOG_TAG, __func__); jni_cb->disabled_cb(); - fm_userial_close(); + jni_cb->thread_evt_cb(1); + fm_userial_close(); } static void hci_buff_ert(struct rds_grp_data *rds_buf) @@ -646,7 +705,7 @@ static void hci_ev_raw_rds_group_data(char *buff) // hci_ev_rt_plus(temp); } else if (carrier == ert_carrier) { - ALOGE("%s:: calling event ert", __func__); + ALOGI("%s:: calling event ert", __func__); hci_buff_ert(&temp); } } @@ -711,9 +770,9 @@ void radio_hci_event_packet(char *evt_buf) case HCI_EV_RADIO_TEXT_PLUS_TAG: hci_ev_rt_plus_tag(((FM_EVT_HDR *)evt_buf)->cmd_params); break; - case HCI_EV_HW_ERR_EVENT: - hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params); - break; + case HCI_EV_HW_ERR_EVENT: + hci_ev_hw_error(((FM_EVT_HDR *)evt_buf)->cmd_params); + break; default: break; } @@ -1063,6 +1122,125 @@ static int set_fm_ctrl(int cmd, int val) radio->stereo_mode.stereo_mode = ~val; hci_set_fm_stereo_mode_req(&radio->stereo_mode); break; + case HCI_FM_HELIUM_RIVA_ACCS_ADDR: + radio->riva_data_req.cmd_params.start_addr = val; + break; + case HCI_FM_HELIUM_RIVA_ACCS_LEN: + if (is_valid_peek_len(val)) { + radio->riva_data_req.cmd_params.length = val; + } else { + ret = -1; + ALOGE("%s: riva access len is not valid\n", LOG_TAG); + goto END; + } + break; + case HCI_FM_HELIUM_RIVA_PEEK: + radio->riva_data_req.cmd_params.subopcode = RIVA_PEEK_OPCODE; + val = hci_peek_data(&radio->riva_data_req.cmd_params); + break; + case HCI_FM_HELIUM_RIVA_POKE: + if (radio->riva_data_req.cmd_params.length <= + MAX_RIVA_PEEK_RSP_SIZE) { + radio->riva_data_req.cmd_params.subopcode = + RIVA_POKE_OPCODE; + ret = hci_poke_data(&radio->riva_data_req); + } else { + ALOGE("%s: riva access len is not valid for poke\n", LOG_TAG); + ret = -1; + goto END; + } + break; + case HCI_FM_HELIUM_SSBI_ACCS_ADDR: + radio->ssbi_data_accs.start_addr = val; + break; + case HCI_FM_HELIUM_SSBI_POKE: + radio->ssbi_data_accs.data = val; + ret = hci_ssbi_poke_reg(&radio->ssbi_data_accs); + break; + case HCI_FM_HELIUM_SSBI_PEEK: + radio->ssbi_peek_reg.start_address = val; + hci_ssbi_peek_reg(&radio->ssbi_peek_reg); + break; + case HCI_FM_HELIUM_SINR_SAMPLES: + if (!is_valid_sinr_samples(val)) { + ALOGE("%s: sinr samples count is not valid\n", __func__); + ret = -1; + goto END; + } + ret = hci_fm_get_ch_det_th(); + if (ret < 0) { + ALOGE("Failed to get chnl det thresholds %d", ret); + goto END; + } + saved_val = radio->ch_det_threshold.sinr_samples; + radio->ch_det_threshold.sinr_samples = val; + ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + if (ret < 0) { + ALOGE("Failed to set SINR samples %d", ret); + radio->ch_det_threshold.sinr_samples = saved_val; + goto END; + } + break; + case HCI_FM_HELIUM_SINR_THRESHOLD: + if (!is_valid_sinr_th(val)) { + ALOGE("%s: sinr threshold is not valid\n"); + ret = -1; + goto END; + } + ret = hci_fm_get_ch_det_th(); + if (ret < 0) { + ALOGE("Failed to get chnl det thresholds %d", ret); + goto END; + } + saved_val = radio->ch_det_threshold.sinr; + radio->ch_det_threshold.sinr = val; + ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + if (ret < 0) { + ALOGE("Failed to set SINR threshold %d", ret); + radio->ch_det_threshold.sinr = saved_val; + goto END; + } + break; + case HCI_FM_HELIUM_INTF_LOW_THRESHOLD: + if (!is_valid_intf_det_low_th(val)) { + ALOGE("%s: intf det low threshold is not valid\n", __func__); + ret = -1; + goto END; + } + ret = hci_fm_get_ch_det_th(); + if (ret < 0) { + ALOGE("Failed to get chnl det thresholds %d", ret); + goto END; + } + saved_val = radio->ch_det_threshold.low_th; + radio->ch_det_threshold.low_th = val; + ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + if (ret < 0) { + ALOGE("Failed to Set Low det threshold %d", ret); + radio->ch_det_threshold.low_th = saved_val; + goto END; + } + break; + case HCI_FM_HELIUM_INTF_HIGH_THRESHOLD: + if (!is_valid_intf_det_hgh_th(val)) { + ALOGE("%s: intf high threshold is not valid\n", __func__); + ret = -1; + goto END; + } + ret = hci_fm_get_ch_det_th(); + if (ret < 0) { + ALOGE("Failed to get chnl det thresholds %d", ret); + goto END; + } + saved_val = radio->ch_det_threshold.high_th; + radio->ch_det_threshold.high_th = val; + ret = set_ch_det_thresholds_req(&radio->ch_det_threshold); + if (ret < 0) { + ALOGE("Failed to set High det threshold %d ", ret); + radio->ch_det_threshold.high_th = saved_val; + goto END; + } + break; default: ALOGE("%s:%s: Not a valid FM CMD!!", LOG_TAG, __func__); ret = 0; @@ -1088,6 +1266,26 @@ static void get_fm_ctrl(int cmd, int val) case HCI_FM_HELIUM_LOWER_BAND: val = radio->recv_conf.band_low_limit; break; + case HCI_FM_HELIUM_SINR_SAMPLES: + ret = hci_fm_get_ch_det_th(); + if (ret == 0) + val = radio->ch_det_threshold.sinr_samples; + break; + case HCI_FM_HELIUM_SINR_THRESHOLD: + ret = hci_fm_get_ch_det_th(); + if (ret == 0) + val = radio->ch_det_threshold.sinr; + break; + case HCI_FM_HELIUM_INTF_LOW_THRESHOLD: + ret = hci_fm_get_ch_det_th(); + if (ret == 0) + val = radio->ch_det_threshold.low_th; + break; + case HCI_FM_HELIUM_INTF_HIGH_THRESHOLD: + ret = hci_fm_get_ch_det_th(); + if (ret == 0) + val = radio->ch_det_threshold.high_th; + break; default: break; } diff --git a/helium/radio_helium_hal_cmds.c b/helium/radio_helium_hal_cmds.c index 1d422d1..df79d75 100644 --- a/helium/radio_helium_hal_cmds.c +++ b/helium/radio_helium_hal_cmds.c @@ -29,6 +29,9 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <stdio.h> #include <utils/Log.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> #include "radio-helium-commands.h" #include "radio-helium.h" #include "fm_hci.h" @@ -282,3 +285,74 @@ int hci_set_fm_stereo_mode_req(struct hci_fm_stereo_mode_req *param) stereo_mode_req); } +int hci_peek_data(struct hci_fm_riva_data *data) +{ + uint16_t opcode = 0; + + if (data == NULL) { + ALOGE("%s:%s, peek data req is null\n", LOG_TAG, __func__); + return -1; + } + opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ, + HCI_OCF_FM_PEEK_DATA); + return send_fm_cmd_pkt(opcode, sizeof((*data)), data); +} + +int hci_poke_data(struct hci_fm_riva_poke *data) +{ + uint16_t opcode = 0; + + if (data == NULL) { + ALOGE("%s:%s, poke data req is null\n", LOG_TAG, __func__); + return -1; + } + opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ, + HCI_OCF_FM_POKE_DATA); + return send_fm_cmd_pkt(opcode, sizeof((*data)), data); +} + +int hci_ssbi_poke_reg(struct hci_fm_ssbi_req *data) +{ + uint16_t opcode = 0; + + if (data == NULL) { + ALOGE("%s:%s,SSBI poke data req is null\n", LOG_TAG, __func__); + return -1; + } + opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ, + HCI_OCF_FM_SSBI_POKE_REG); + return send_fm_cmd_pkt(opcode, sizeof((*data)), data); +} + +int hci_ssbi_peek_reg(struct hci_fm_ssbi_peek *data) +{ + uint16_t opcode = 0; + + if (data == NULL) { + ALOGE("%s:%s,SSBI peek data req is null\n", LOG_TAG, __func__); + return -1; + } + opcode = hci_opcode_pack(HCI_OGF_FM_DIAGNOSTIC_CMD_REQ, + HCI_OCF_FM_SSBI_PEEK_REG); + return send_fm_cmd_pkt(opcode, sizeof((*data)), data); +} + +int hci_fm_get_ch_det_th() +{ + uint16_t opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ, + HCI_OCF_FM_GET_CH_DET_THRESHOLD); + return send_fm_cmd_pkt(opcode, 0, NULL); +} + +int set_ch_det_thresholds_req(struct hci_fm_ch_det_threshold *ch_det_th) +{ + uint16_t opcode = 0; + + if (ch_det_th == NULL) { + ALOGE("%s,%s channel det thrshld is null\n", LOG_TAG, __func__); + return -1; + } + opcode = hci_opcode_pack(HCI_OGF_FM_RECV_CTRL_CMD_REQ, + HCI_OCF_FM_SET_CH_DET_THRESHOLD); + return send_fm_cmd_pkt(opcode, sizeof((*ch_det_th)), ch_det_th); +} diff --git a/jni/android_hardware_fm.cpp b/jni/android_hardware_fm.cpp index 36199f6..7503ced 100644 --- a/jni/android_hardware_fm.cpp +++ b/jni/android_hardware_fm.cpp @@ -102,7 +102,9 @@ typedef void (*ert_cb)(char *ert); typedef void (*disable_cb)(); typedef void (*callback_thread_event)(unsigned int evt); typedef void (*rds_grp_cntrs_cb)(char *rds_params); - +typedef void (*fm_peek_cb)(char *peek_rsp); +typedef void (*fm_ssbi_peek_cb)(char *ssbi_peek_rsp); +typedef void (*fm_ch_det_th_cb)(char *ch_det_rsp); static JNIEnv *mCallbackEnv = NULL; static jobject mCallbacksObj = NULL; @@ -315,8 +317,20 @@ void rds_grp_cntrs_rsp_cb(char * evt_buffer) void fm_disabled_cb() { - ALOGE("DISABLE"); - mCallbackEnv->CallVoidMethod(mCallbacksObj, method_disableCallback); + ALOGE("DISABLE"); + mCallbackEnv->CallVoidMethod(mCallbacksObj, method_disableCallback); +} + +void fm_peek_rsp_cb(char *peek_rsp) { + ALOGE("fm_peek_rsp_cb"); +} + +void fm_ssbi_peek_rsp_cb(char *ssbi_peek_rsp){ + ALOGE("fm_ssbi_peek_rsp_cb"); +} + +void fm_ch_det_th_rsp_cb(char *ch_det_rsp){ + ALOGE("fm_ch_det_th_rsp_cb"); } static void fm_thread_evt_cb(unsigned int event) { @@ -355,6 +369,9 @@ typedef struct { ert_cb ert_update_cb; disable_cb disabled_cb; rds_grp_cntrs_cb rds_grp_cntrs_rsp_cb; + fm_peek_cb fm_peek_rsp_cb; + fm_ssbi_peek_cb fm_ssbi_peek_rsp_cb; + fm_ch_det_th_cb fm_ch_det_th_rsp_cb; callback_thread_event thread_evt_cb; } fm_vendor_callbacks_t; @@ -383,6 +400,9 @@ static fm_vendor_callbacks_t fm_callbacks = { fm_ert_update_cb, fm_disabled_cb, rds_grp_cntrs_rsp_cb, + fm_peek_rsp_cb, + fm_ssbi_peek_rsp_cb, + fm_ch_det_th_rsp_cb, fm_thread_evt_cb }; diff --git a/qcom/fmradio/FmRxRdsData.java b/qcom/fmradio/FmRxRdsData.java index a504007..f0e5b9e 100644 --- a/qcom/fmradio/FmRxRdsData.java +++ b/qcom/fmradio/FmRxRdsData.java @@ -149,6 +149,7 @@ public class FmRxRdsData { rds_group_mask = ((rdsMask & 0x000000FF)); + Log.d(LOGTAG, "In rdsOptions: rds_group_mask : " + rds_group_mask); re = FmReceiverJNI.setControlNative(mFd, V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, rds_group_mask); return re; } -- GitLab