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
diff --git a/Android.mk b/Android.mk
index 5b79fbf..fc3a54e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,6 +19,7 @@
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 @@
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 @@
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_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 @@
/* 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;
+ 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;
- }
+ 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);
+ /*
+ * 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;
+ //credits = command_credits;
- TX_Q *temp = new_first;
- while(temp != NULL) {
+ 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);
+ 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);
+ /* 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__);
+ 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);
+ 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--;
+ /* 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--;
+ /* 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;
+ /* 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;
- }
- }
+ ALOGI("\n\n\t\tFalse wakeup: Yet to get COMMAND CREDITS from CONTROLLER\n\n");
+ goto wait_for_cmd_credits;
+ }
+ }
}
@@ -218,30 +224,29 @@
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 @@
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 @@
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 @@
/* 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 @@
} //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 void *userial_read_thread(void *arg)
{
- int length;
+ int length;
- FM_EVT_HDR *evt_buf = (FM_EVT_HDR *) malloc(sizeof(FM_EVT_HDR) + MAX_FM_EVT_PARAMS);
+ 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;
+ 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* fmHCITask(void *arg)
{
- static uint16_t events;
+ 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);
- while (lib_running) {
- pthread_mutex_lock(&fmHCIControlBlock.event_lock);
- while (ready_events == 0) {
- pthread_cond_wait(&fmHCIControlBlock.event_cond, &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");
+ }
+ }
- 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;
+ 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 @@
void enqueue_fm_tx_cmd(FM_HDR *pbuf)
{
- pthread_mutex_lock(&fmHCIControlBlock.tx_q_lock);
+ 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;
+ 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 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 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 @@
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 @@
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 (*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 @@
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 @@
#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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
// 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 @@
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 @@
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 @@
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 @@
#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 @@
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 (*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 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 @@
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 @@
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 @@
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;
}