aboutsummaryrefslogtreecommitdiffstats
path: root/src/vfs/ant_rx_chardev.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vfs/ant_rx_chardev.c')
-rw-r--r--src/vfs/ant_rx_chardev.c130
1 files changed, 99 insertions, 31 deletions
diff --git a/src/vfs/ant_rx_chardev.c b/src/vfs/ant_rx_chardev.c
index 2f0cc33..aa51825 100644
--- a/src/vfs/ant_rx_chardev.c
+++ b/src/vfs/ant_rx_chardev.c
@@ -29,11 +29,12 @@
#include <errno.h>
#include <poll.h>
#include <pthread.h>
+#include <stdint.h> /* for uint64_t */
#include "ant_types.h"
#include "antradio_power.h"
#include "ant_rx_chardev.h"
-#include "ant_driver_defines.h"
+#include "ant_hci_defines.h"
#include "ant_log.h"
#include "ant_native.h" // ANT_HCI_MAX_MSG_SIZE, ANT_MSG_ID_OFFSET, ANT_MSG_DATA_OFFSET,
// ant_radio_enabled_status()
@@ -53,9 +54,38 @@ static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE];
static int iRxBufferLength[NUM_ANT_CHANNELS] = {0, 0};
#endif //
+// Defines for use with the poll() call
+#define EVENT_DATA_AVAILABLE (POLLIN|POLLRDNORM)
+#define EVENT_DISABLE (POLLHUP)
+#define EVENT_HARD_RESET (POLLERR|POLLPRI|POLLRDHUP)
+
+#define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_DISABLE|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
+
+void doReset(ant_rx_thread_info_t *stRxThreadInfo);
int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo);
/*
+ * Function to check that all given flags are set in a particular value.
+ * Designed for use with the revents field of pollfds filled out by poll().
+ *
+ * Parameters:
+ * - value: The value that will be checked to contain all flags.
+ * - flags: Bitwise-or of the flags that value should be checked for.
+ *
+ * Returns:
+ * - true IFF all the bits that are set in 'flags' are also set in 'value'
+ */
+ANT_BOOL areAllFlagsSet(short value, short flags)
+{
+ value &= flags;
+ return (value == flags);
+}
+
+/*
* This thread waits for ANT messages from a VFS file.
*/
void *fnRxThread(void *ant_rx_thread_info)
@@ -63,67 +93,97 @@ void *fnRxThread(void *ant_rx_thread_info)
int iMutexLockResult;
int iPollRet;
ant_rx_thread_info_t *stRxThreadInfo;
- struct pollfd astPollFd[NUM_ANT_CHANNELS];
+ struct pollfd astPollFd[NUM_POLL_FDS];
ant_channel_type eChannel;
ANT_FUNC_START();
stRxThreadInfo = (ant_rx_thread_info_t *)ant_rx_thread_info;
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) {
astPollFd[eChannel].fd = stRxThreadInfo->astChannels[eChannel].iFd;
- astPollFd[eChannel].events = POLLIN | POLLRDNORM;
+ astPollFd[eChannel].events = EVENTS_TO_LISTEN_FOR;
}
+ // Fill out poll request for the shutdown signaller.
+ astPollFd[EVENTFD_IDX].fd = stRxThreadInfo->iRxShutdownEventFd;
+ astPollFd[EVENTFD_IDX].events = POLL_IN;
/* continue running as long as not terminated */
while (stRxThreadInfo->ucRunThread) {
/* Wait for data available on any file (transport path) */
- iPollRet = poll(astPollFd, NUM_ANT_CHANNELS, ANT_POLL_TIMEOUT);
+ iPollRet = poll(astPollFd, NUM_POLL_FDS, ANT_POLL_TIMEOUT);
if (!iPollRet) {
ANT_DEBUG_V("poll timed out, checking exit cond");
} else if (iPollRet < 0) {
- ANT_ERROR("read thread exiting, unhandled error: %s", strerror(errno));
+ ANT_ERROR("unhandled error: %s, attempting recovery.", strerror(errno));
+ doReset(stRxThreadInfo);
+ goto out;
} else {
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) {
- if (astPollFd[eChannel].revents & (POLLERR | POLLPRI | POLLRDHUP)) {
- ANT_ERROR("poll error from %s. exiting rx thread",
+ if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_HARD_RESET)) {
+ ANT_ERROR("Hard reset indicated by %s. Attempting recovery.",
stRxThreadInfo->astChannels[eChannel].pcDevicePath);
- /* Chip was reset or other error, only way to recover is to
- * close and open ANT chardev */
- stRxThreadInfo->ucChipResetting = 1;
+ 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 */
+ ANT_DEBUG_D(
+ "poll hang-up from %s. exiting rx thread", stRxThreadInfo->astChannels[eChannel].pcDevicePath);
- if (g_fnStateCallback) {
- g_fnStateCallback(RADIO_STATUS_RESETTING);
- }
+ // set flag to exit out of Rx Loop
+ stRxThreadInfo->ucRunThread = 0;
- goto reset;
- } else if (astPollFd[eChannel].revents & (POLLIN | POLLRDNORM)) {
+ } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DATA_AVAILABLE)) {
ANT_DEBUG_D("data on %s. reading it",
stRxThreadInfo->astChannels[eChannel].pcDevicePath);
if (readChannelMsg(eChannel, &stRxThreadInfo->astChannels[eChannel]) < 0) {
- goto out;
+ // set flag to exit out of Rx Loop
+ stRxThreadInfo->ucRunThread = 0;
}
+ } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLNVAL)) {
+ ANT_ERROR("poll was called on invalid file descriptor %s. Attempting recovery.",
+ stRxThreadInfo->astChannels[eChannel].pcDevicePath);
+ doReset(stRxThreadInfo);
+ goto out;
+ } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLERR)) {
+ ANT_ERROR("Unknown error from %s. Attempting recovery.",
+ stRxThreadInfo->astChannels[eChannel].pcDevicePath);
+ doReset(stRxThreadInfo);
+ goto out;
} else if (astPollFd[eChannel].revents) {
ANT_DEBUG_W("unhandled poll result %#x from %s",
astPollFd[eChannel].revents,
stRxThreadInfo->astChannels[eChannel].pcDevicePath);
}
}
+ // Now check for shutdown signal
+ if(areAllFlagsSet(astPollFd[EVENTFD_IDX].revents, POLLIN))
+ {
+ ANT_DEBUG_I("rx thread caught shutdown signal.");
+ // reset the counter by reading.
+ uint64_t counter;
+ read(stRxThreadInfo->iRxShutdownEventFd, &counter, sizeof(counter));
+ // don't care if read error, going to close the thread anyways.
+ stRxThreadInfo->ucRunThread = 0;
+ } else if (astPollFd[EVENTFD_IDX].revents != 0) {
+ ANT_ERROR("Shutdown event descriptor had unexpected event: %#x. exiting rx thread.",
+ astPollFd[EVENTFD_IDX].revents);
+ stRxThreadInfo->ucRunThread = 0;
+ }
}
}
-out:
- stRxThreadInfo->ucRunThread = 0;
-
- /* Try to get stEnabledStatusLock.
- * if you get it then noone is enabling or disabling
- * if you can't get it assume something made you exit */
+ /* disable ANT radio if not already disabling */
+ // Try to get stEnabledStatusLock.
+ // if you get it then no one is enabling or disabling
+ // if you can't get it assume something made you exit
ANT_DEBUG_V("try getting stEnabledStatusLock in %s", __FUNCTION__);
iMutexLockResult = pthread_mutex_trylock(stRxThreadInfo->pstEnabledStatusLock);
if (!iMutexLockResult) {
ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__);
ANT_WARN("rx thread has unexpectedly crashed, cleaning up");
- stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't
- * try to join ourselves in disable */
+
+ // spoof our handle as closed so we don't try to join ourselves in disable
+ stRxThreadInfo->stRxThread = 0;
if (g_fnStateCallback) {
g_fnStateCallback(RADIO_STATUS_DISABLING);
@@ -145,15 +205,26 @@ out:
ANT_DEBUG_V("stEnabledStatusLock busy");
}
- // FIXME This is not the end of the function
- // Probably because goto:reset is a bad implementation; can have a reset function.
- // Will only end here on Android.
+ out:
ANT_FUNC_END();
#ifdef ANDROID
return NULL;
#endif
+}
+
+void doReset(ant_rx_thread_info_t *stRxThreadInfo)
+{
+ int iMutexLockResult;
+
+ ANT_FUNC_START();
+ /* Chip was reset or other error, only way to recover is to
+ * close and open ANT chardev */
+ stRxThreadInfo->ucChipResetting = 1;
+
+ if (g_fnStateCallback) {
+ g_fnStateCallback(RADIO_STATUS_RESETTING);
+ }
-reset:
stRxThreadInfo->ucRunThread = 0;
ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__);
@@ -188,9 +259,6 @@ reset:
stRxThreadInfo->ucChipResetting = 0;
ANT_FUNC_END();
-#ifdef ANDROID
- return NULL;
-#endif
}
////////////////////////////////////////////////////////////////////