diff options
author | James Bootsma <james.bootsma@thisisant.com> | 2014-03-13 16:12:54 -0600 |
---|---|---|
committer | James Bootsma <james.bootsma@thisisant.com> | 2014-03-13 16:15:19 -0600 |
commit | 105c80aa7cade5e0b1389b3ffe9bc6ab25a04b2a (patch) | |
tree | a547fdc029fb548af30fbabef18247248c8014cc | |
parent | 7eabf6784467e0b06512c691c13327d38275cec4 (diff) | |
download | android_external_ant-wireless_ant_native-105c80aa7cade5e0b1389b3ffe9bc6ab25a04b2a.tar.gz android_external_ant-wireless_ant_native-105c80aa7cade5e0b1389b3ffe9bc6ab25a04b2a.tar.bz2 android_external_ant-wireless_ant_native-105c80aa7cade5e0b1389b3ffe9bc6ab25a04b2a.zip |
Version 1.8.0
- Send keepalive message to chip on poll timeout, monitor for response.
- Fixed a race condition during reset that could cause the ARS to get
stuck in a bad state.
-rw-r--r-- | src/bt-vendor_vfs/ant_rx_chardev.c | 73 | ||||
-rw-r--r-- | src/bt-vendor_vfs/inc/ant_rx_chardev.h | 2 | ||||
-rw-r--r-- | src/common/inc/ant_version.h | 2 | ||||
-rw-r--r-- | src/vfs/ant_rx_chardev.c | 73 | ||||
-rw-r--r-- | src/vfs/inc/ant_rx_chardev.h | 2 |
5 files changed, 121 insertions, 31 deletions
diff --git a/src/bt-vendor_vfs/ant_rx_chardev.c b/src/bt-vendor_vfs/ant_rx_chardev.c index a8f150c..69656b2 100644 --- a/src/bt-vendor_vfs/ant_rx_chardev.c +++ b/src/bt-vendor_vfs/ant_rx_chardev.c @@ -45,6 +45,7 @@ extern ANTStatus ant_tx_message_flowcontrol_none(ant_channel_type eTxPath, ANT_U #define LOG_TAG "antradio_rx" #define ANT_POLL_TIMEOUT ((int)30000) +#define KEEPALIVE_TIMEOUT ((int)5000) static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; @@ -56,15 +57,18 @@ static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; // Defines for use with the poll() call #define EVENT_DATA_AVAILABLE (POLLIN|POLLRDNORM) -#define EVENT_DISABLE (POLLHUP) +#define EVENT_CHIP_SHUTDOWN (POLLHUP) #define EVENT_HARD_RESET (POLLERR|POLLPRI|POLLRDHUP) -#define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_DISABLE|EVENT_HARD_RESET) +#define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_CHIP_SHUTDOWN|EVENT_HARD_RESET) // Plus one is for the eventfd shutdown signal. #define NUM_POLL_FDS (NUM_ANT_CHANNELS + 1) #define EVENTFD_IDX NUM_ANT_CHANNELS +static ANT_U8 KEEPALIVE_MESG[] = {0x01, 0x00, 0x00}; +static ANT_U8 KEEPALIVE_RESP[] = {0x03, 0x40, 0x00, 0x00, 0x28}; + void doReset(ant_rx_thread_info_t *stRxThreadInfo); int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo); @@ -86,6 +90,17 @@ ANT_BOOL areAllFlagsSet(short value, short flags) } /* + * This thread is run occasionally as a detached thread in order to send a keepalive message to the + * chip. + */ +void *fnKeepAliveThread(void *unused) +{ + ANT_DEBUG_V("Sending dummy keepalive message."); + ant_tx_message(sizeof(KEEPALIVE_MESG)/sizeof(ANT_U8), KEEPALIVE_MESG); + return NULL; +} + +/* * This thread waits for ANT messages from a VFS file. */ void *fnRxThread(void *ant_rx_thread_info) @@ -106,12 +121,32 @@ void *fnRxThread(void *ant_rx_thread_info) astPollFd[EVENTFD_IDX].fd = stRxThreadInfo->iRxShutdownEventFd; astPollFd[EVENTFD_IDX].events = POLL_IN; + // Reset the waiting for response, since we don't want a stale value if we were reset. + stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_FALSE; + /* continue running as long as not terminated */ while (stRxThreadInfo->ucRunThread) { - /* Wait for data available on any file (transport path) */ - iPollRet = poll(astPollFd, NUM_POLL_FDS, ANT_POLL_TIMEOUT); + /* Wait for data available on any file (transport path), shorter wait if we just timed out. */ + int timeout = stRxThreadInfo->bWaitingForKeepaliveResponse ? KEEPALIVE_TIMEOUT : ANT_POLL_TIMEOUT; + iPollRet = poll(astPollFd, NUM_POLL_FDS, timeout); if (!iPollRet) { - ANT_DEBUG_V("poll timed out, checking exit cond"); + if(!stRxThreadInfo->bWaitingForKeepaliveResponse) + { + stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_TRUE; + // Keep alive is done on a separate thread so that rxThread can handle flow control during + // the message. + pthread_t thread; + // Don't care if it failed as the consequence is just a missed keep-alive. + pthread_create(&thread, NULL, fnKeepAliveThread, NULL); + // Detach the thread so that we don't need to join it later. + pthread_detach(thread); + ANT_DEBUG_V("poll timed out, checking exit cond"); + } else + { + ANT_DEBUG_E("No response to keepalive, attempting recovery."); + doReset(stRxThreadInfo); + goto out; + } } else if (iPollRet < 0) { ANT_ERROR("unhandled error: %s, attempting recovery.", strerror(errno)); doReset(stRxThreadInfo); @@ -123,18 +158,20 @@ void *fnRxThread(void *ant_rx_thread_info) stRxThreadInfo->astChannels[eChannel].pcDevicePath); doReset(stRxThreadInfo); goto out; - } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DISABLE)) { - /* chip reported it was disabled, either unexpectedly or due to us closing the file */ + } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_CHIP_SHUTDOWN)) { + /* chip reported it was unexpectedly disabled */ ANT_DEBUG_D( "poll hang-up from %s. exiting rx thread", stRxThreadInfo->astChannels[eChannel].pcDevicePath); - // set flag to exit out of Rx Loop - stRxThreadInfo->ucRunThread = 0; - + doReset(stRxThreadInfo); + goto out; } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DATA_AVAILABLE)) { ANT_DEBUG_D("data on %s. reading it", stRxThreadInfo->astChannels[eChannel].pcDevicePath); + // Doesn't matter what data we received, we know the chip is alive. + stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_FALSE; + if (readChannelMsg(eChannel, &stRxThreadInfo->astChannels[eChannel]) < 0) { // set flag to exit out of Rx Loop stRxThreadInfo->ucRunThread = 0; @@ -233,6 +270,7 @@ void doReset(ant_rx_thread_info_t *stRxThreadInfo) ANT_ERROR("chip was reset, getting state mutex failed: %s", strerror(iMutexLockResult)); stRxThreadInfo->stRxThread = 0; + stRxThreadInfo->ucChipResetting = 0; } else { ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); @@ -241,7 +279,10 @@ void doReset(ant_rx_thread_info_t *stRxThreadInfo) ant_disable(); - if (ant_enable()) { /* failed */ + int enableResult = ant_enable(); + + stRxThreadInfo->ucChipResetting = 0; + if (enableResult) { /* failed */ if (g_fnStateCallback) { g_fnStateCallback(RADIO_STATUS_DISABLED); } @@ -256,8 +297,6 @@ void doReset(ant_rx_thread_info_t *stRxThreadInfo) ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); } - stRxThreadInfo->ucChipResetting = 0; - ANT_FUNC_END(); } @@ -398,11 +437,15 @@ int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo) } else #endif // ANT_MESG_FLOW_CONTROL { - if (pstChnlInfo->fnRxCallback != NULL) { + ANT_U8 *msg = aucRxBuffer[eChannel] + iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET; + ANT_BOOL bIsKeepAliveResponse = memcmp(msg, KEEPALIVE_RESP, sizeof(KEEPALIVE_RESP)/sizeof(ANT_U8)) == 0; + if (bIsKeepAliveResponse) { + ANT_DEBUG_V("Filtered out keepalive response."); + } else if (pstChnlInfo->fnRxCallback != NULL) { // Loop through read data until all HCI packets are written to callback pstChnlInfo->fnRxCallback(iHciDataSize, \ - &aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET]); + msg); } else { ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath); } diff --git a/src/bt-vendor_vfs/inc/ant_rx_chardev.h b/src/bt-vendor_vfs/inc/ant_rx_chardev.h index 1024dac..12ba629 100644 --- a/src/bt-vendor_vfs/inc/ant_rx_chardev.h +++ b/src/bt-vendor_vfs/inc/ant_rx_chardev.h @@ -86,6 +86,8 @@ typedef struct { ant_channel_info_t astChannels[NUM_ANT_CHANNELS]; /* Event file descriptor used to interrupt the poll() loop in the rx thread. */ int iRxShutdownEventFd; + /* Indicates whether thread is waiting for a keepalive response. */ + ANT_BOOL bWaitingForKeepaliveResponse; } ant_rx_thread_info_t; extern ANTNativeANTStateCb g_fnStateCallback; // TODO State callback should be inside ant_rx_thread_info_t. diff --git a/src/common/inc/ant_version.h b/src/common/inc/ant_version.h index 3620908..834603c 100644 --- a/src/common/inc/ant_version.h +++ b/src/common/inc/ant_version.h @@ -20,7 +20,7 @@ #define __ANT_VERSION_H
#define LIBANT_STACK_MAJOR "1"
-#define LIBANT_STACK_MINOR "7"
+#define LIBANT_STACK_MINOR "8"
#define LIBANT_STACK_INCRE "0"
#endif // __ANT_VERSION_H
diff --git a/src/vfs/ant_rx_chardev.c b/src/vfs/ant_rx_chardev.c index aa51825..94c09b1 100644 --- a/src/vfs/ant_rx_chardev.c +++ b/src/vfs/ant_rx_chardev.c @@ -45,6 +45,7 @@ extern ANTStatus ant_tx_message_flowcontrol_none(ant_channel_type eTxPath, ANT_U #define LOG_TAG "antradio_rx" #define ANT_POLL_TIMEOUT ((int)30000) +#define KEEPALIVE_TIMEOUT ((int)5000) static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; @@ -56,15 +57,18 @@ static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; // Defines for use with the poll() call #define EVENT_DATA_AVAILABLE (POLLIN|POLLRDNORM) -#define EVENT_DISABLE (POLLHUP) +#define EVENT_CHIP_SHUTDOWN (POLLHUP) #define EVENT_HARD_RESET (POLLERR|POLLPRI|POLLRDHUP) -#define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_DISABLE|EVENT_HARD_RESET) +#define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_CHIP_SHUTDOWN|EVENT_HARD_RESET) // Plus one is for the eventfd shutdown signal. #define NUM_POLL_FDS (NUM_ANT_CHANNELS + 1) #define EVENTFD_IDX NUM_ANT_CHANNELS +static ANT_U8 KEEPALIVE_MESG[] = {0x01, 0x00, 0x00}; +static ANT_U8 KEEPALIVE_RESP[] = {0x03, 0x40, 0x00, 0x00, 0x28}; + void doReset(ant_rx_thread_info_t *stRxThreadInfo); int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo); @@ -86,6 +90,17 @@ ANT_BOOL areAllFlagsSet(short value, short flags) } /* + * This thread is run occasionally as a detached thread in order to send a keepalive message to the + * chip. + */ +void *fnKeepAliveThread(void *unused) +{ + ANT_DEBUG_V("Sending dummy keepalive message."); + ant_tx_message(sizeof(KEEPALIVE_MESG)/sizeof(ANT_U8), KEEPALIVE_MESG); + return NULL; +} + +/* * This thread waits for ANT messages from a VFS file. */ void *fnRxThread(void *ant_rx_thread_info) @@ -106,12 +121,32 @@ void *fnRxThread(void *ant_rx_thread_info) astPollFd[EVENTFD_IDX].fd = stRxThreadInfo->iRxShutdownEventFd; astPollFd[EVENTFD_IDX].events = POLL_IN; + // Reset the waiting for response, since we don't want a stale value if we were reset. + stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_FALSE; + /* continue running as long as not terminated */ while (stRxThreadInfo->ucRunThread) { - /* Wait for data available on any file (transport path) */ - iPollRet = poll(astPollFd, NUM_POLL_FDS, ANT_POLL_TIMEOUT); + /* Wait for data available on any file (transport path), shorter wait if we just timed out. */ + int timeout = stRxThreadInfo->bWaitingForKeepaliveResponse ? KEEPALIVE_TIMEOUT : ANT_POLL_TIMEOUT; + iPollRet = poll(astPollFd, NUM_POLL_FDS, timeout); if (!iPollRet) { - ANT_DEBUG_V("poll timed out, checking exit cond"); + if(!stRxThreadInfo->bWaitingForKeepaliveResponse) + { + stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_TRUE; + // Keep alive is done on a separate thread so that rxThread can handle flow control during + // the message. + pthread_t thread; + // Don't care if it failed as the consequence is just a missed keep-alive. + pthread_create(&thread, NULL, fnKeepAliveThread, NULL); + // Detach the thread so that we don't need to join it later. + pthread_detach(thread); + ANT_DEBUG_V("poll timed out, checking exit cond"); + } else + { + ANT_DEBUG_E("No response to keepalive, attempting recovery."); + doReset(stRxThreadInfo); + goto out; + } } else if (iPollRet < 0) { ANT_ERROR("unhandled error: %s, attempting recovery.", strerror(errno)); doReset(stRxThreadInfo); @@ -123,18 +158,20 @@ void *fnRxThread(void *ant_rx_thread_info) stRxThreadInfo->astChannels[eChannel].pcDevicePath); doReset(stRxThreadInfo); goto out; - } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DISABLE)) { - /* chip reported it was disabled, either unexpectedly or due to us closing the file */ + } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_CHIP_SHUTDOWN)) { + /* chip reported it was unexpectedly disabled */ ANT_DEBUG_D( "poll hang-up from %s. exiting rx thread", stRxThreadInfo->astChannels[eChannel].pcDevicePath); - // set flag to exit out of Rx Loop - stRxThreadInfo->ucRunThread = 0; - + doReset(stRxThreadInfo); + goto out; } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DATA_AVAILABLE)) { ANT_DEBUG_D("data on %s. reading it", stRxThreadInfo->astChannels[eChannel].pcDevicePath); + // Doesn't matter what data we received, we know the chip is alive. + stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_FALSE; + if (readChannelMsg(eChannel, &stRxThreadInfo->astChannels[eChannel]) < 0) { // set flag to exit out of Rx Loop stRxThreadInfo->ucRunThread = 0; @@ -233,6 +270,7 @@ void doReset(ant_rx_thread_info_t *stRxThreadInfo) ANT_ERROR("chip was reset, getting state mutex failed: %s", strerror(iMutexLockResult)); stRxThreadInfo->stRxThread = 0; + stRxThreadInfo->ucChipResetting = 0; } else { ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); @@ -241,7 +279,10 @@ void doReset(ant_rx_thread_info_t *stRxThreadInfo) ant_disable(); - if (ant_enable()) { /* failed */ + int enableResult = ant_enable(); + + stRxThreadInfo->ucChipResetting = 0; + if (enableResult) { /* failed */ if (g_fnStateCallback) { g_fnStateCallback(RADIO_STATUS_DISABLED); } @@ -256,8 +297,6 @@ void doReset(ant_rx_thread_info_t *stRxThreadInfo) ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); } - stRxThreadInfo->ucChipResetting = 0; - ANT_FUNC_END(); } @@ -398,11 +437,15 @@ int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo) } else #endif // ANT_MESG_FLOW_CONTROL { - if (pstChnlInfo->fnRxCallback != NULL) { + ANT_U8 *msg = aucRxBuffer[eChannel] + iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET; + ANT_BOOL bIsKeepAliveResponse = memcmp(msg, KEEPALIVE_RESP, sizeof(KEEPALIVE_RESP)/sizeof(ANT_U8)) == 0; + if (bIsKeepAliveResponse) { + ANT_DEBUG_V("Filtered out keepalive response."); + } else if (pstChnlInfo->fnRxCallback != NULL) { // Loop through read data until all HCI packets are written to callback pstChnlInfo->fnRxCallback(iHciDataSize, \ - &aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET]); + msg); } else { ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath); } diff --git a/src/vfs/inc/ant_rx_chardev.h b/src/vfs/inc/ant_rx_chardev.h index a3481b0..d76184e 100644 --- a/src/vfs/inc/ant_rx_chardev.h +++ b/src/vfs/inc/ant_rx_chardev.h @@ -86,6 +86,8 @@ typedef struct { ant_channel_info_t astChannels[NUM_ANT_CHANNELS];
/* Event file descriptor used to interrupt the poll() loop in the rx thread. */
int iRxShutdownEventFd;
+ /* Indicates whether thread is waiting for a keepalive response. */
+ ANT_BOOL bWaitingForKeepaliveResponse;
} ant_rx_thread_info_t;
extern ANTNativeANTStateCb g_fnStateCallback; // TODO State callback should be inside ant_rx_thread_info_t.
|