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); } stRxThreadInfo->ucRunThread = 0; ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); iMutexLockResult = pthread_mutex_lock(stRxThreadInfo->pstEnabledStatusLock); if (iMutexLockResult < 0) { 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__); stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't * try to join ourselves in disable */ ant_disable(); int enableResult = ant_enable(); stRxThreadInfo->ucChipResetting = 0; if (enableResult) { /* failed */ if (g_fnStateCallback) { g_fnStateCallback(RADIO_STATUS_DISABLED); } } else { /* success */ if (g_fnStateCallback) { g_fnStateCallback(RADIO_STATUS_RESET); } } ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); } ANT_FUNC_END(); }
/* * This thread waits for ANT messages from a VFS file. */ void *fnRxThread(void *ant_rx_thread_info) { int iMutexLockResult; int iPollRet; ant_rx_thread_info_t *stRxThreadInfo; 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 = EVENTS_TO_LISTEN_FOR; } // Fill out poll request for the shutdown signaller. 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), 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) { 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); goto out; } else { for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_HARD_RESET)) { ANT_ERROR("Hard reset indicated by %s. Attempting recovery.", stRxThreadInfo->astChannels[eChannel].pcDevicePath); doReset(stRxThreadInfo); goto out; } 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); 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; } } 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; } } } /* 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"); // 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); } ant_disable(); if (g_fnStateCallback) { g_fnStateCallback(ant_radio_enabled_status()); } ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); } else if (iMutexLockResult != EBUSY) { ANT_ERROR("rx thread closing code, trylock on state lock failed: %s", strerror(iMutexLockResult)); } else { ANT_DEBUG_V("stEnabledStatusLock busy"); } out: ANT_FUNC_END(); #ifdef ANDROID return NULL; #endif }