Android_System_ANT-HAL_1-6-2
diff --git a/src/common/inc/ant_version.h b/src/common/inc/ant_version.h
index 0b8988b..21f3660 100644
--- a/src/common/inc/ant_version.h
+++ b/src/common/inc/ant_version.h
@@ -21,7 +21,7 @@
#define LIBANT_STACK_MAJOR "1"
#define LIBANT_STACK_MINOR "6"
-#define LIBANT_STACK_INCRE "1"
+#define LIBANT_STACK_INCRE "2"
#endif // __ANT_VERSION_H
diff --git a/src/vfs/ant_native_chardev.c b/src/vfs/ant_native_chardev.c
index df209c2..2b49a8c 100644
--- a/src/vfs/ant_native_chardev.c
+++ b/src/vfs/ant_native_chardev.c
@@ -30,6 +30,9 @@
#include <fcntl.h> /* for open() */
#include <linux/ioctl.h> /* For hard reset */
#include <pthread.h>
+#include <stdint.h> /* for uint64_t */
+#include <sys/eventfd.h> /* For eventfd() */
+#include <unistd.h> /* for read(), write(), and close() */
#include "ant_types.h"
#include "ant_native.h"
@@ -37,7 +40,7 @@
#include "antradio_power.h"
#include "ant_rx_chardev.h"
-#include "ant_driver_defines.h"
+#include "ant_hci_defines.h"
#include "ant_log.h"
#if ANT_HCI_SIZE_SIZE > 1
@@ -58,6 +61,8 @@
static pthread_cond_t stFlowControlCond = PTHREAD_COND_INITIALIZER;
ANTNativeANTStateCb g_fnStateCallback;
+static const uint64_t EVENT_FD_PLUS_ONE = 1L;
+
static void ant_channel_init(ant_channel_info_t *pstChnlInfo, const char *pcCharDevName);
////////////////////////////////////////////////////////////////////
@@ -69,13 +74,14 @@
// -
//
// Returns:
-// ANT_STATUS_SUCCESS
+// ANT_STATUS_SUCCESS if intialize completed, else ANT_STATUS_FAILED
//
// Psuedocode:
/*
Set variables to defaults
Initialise each supported path to chip
-RESULT = ANT_STATUS_SUCCESS
+Setup eventfd object.
+RESULT = ANT_STATUS_SUCCESS if no problems else ANT_STATUS_FAILED
*/
////////////////////////////////////////////////////////////////////
ANTStatus ant_init(void)
@@ -96,7 +102,16 @@
ant_channel_init(&stRxThreadInfo.astChannels[DATA_CHANNEL], ANT_DATA_DEVICE_NAME);
#endif // Separate data/command paths
- status = ANT_STATUS_SUCCESS;
+ // Make the eventfd. Want it non blocking so that we can easily reset it by reading.
+ stRxThreadInfo.iRxShutdownEventFd = eventfd(0, EFD_NONBLOCK);
+
+ // Check for error case
+ if(stRxThreadInfo.iRxShutdownEventFd == -1)
+ {
+ ANT_ERROR("ANT init failed. Could not create event fd. Reason: %s", strerror(errno));
+ } else {
+ status = ANT_STATUS_SUCCESS;
+ }
ANT_FUNC_END();
return status;
@@ -105,7 +120,7 @@
////////////////////////////////////////////////////////////////////
// ant_deinit
//
-// Doesn't actually do anything.
+// clean up eventfd object
//
// Parameters:
// -
@@ -123,7 +138,12 @@
ANTStatus result_status = ANT_STATUS_FAILED;
ANT_FUNC_START();
- result_status = ANT_STATUS_SUCCESS;
+ if(close(stRxThreadInfo.iRxShutdownEventFd) < 0)
+ {
+ ANT_ERROR("Could not close eventfd in deinit. Reason: %s", strerror(errno));
+ } else {
+ result_status = ANT_STATUS_SUCCESS;
+ }
ANT_FUNC_END();
return result_status;
@@ -838,6 +858,16 @@
ant_channel_type eChannel;
ANT_FUNC_START();
+ // Reset the shutdown signal.
+ uint64_t counter;
+ ssize_t result = read(stRxThreadInfo.iRxShutdownEventFd, &counter, sizeof(counter));
+ // EAGAIN result indicates that the counter was already 0 in non-blocking mode.
+ if(result < 0 && errno != EAGAIN)
+ {
+ ANT_ERROR("Could not clear shutdown signal in enable. Reason: %s", strerror(errno));
+ goto out;
+ }
+
stRxThreadInfo.ucRunThread = 1;
for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) {
@@ -878,11 +908,14 @@
stRxThreadInfo.ucRunThread = 0;
- for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) {
- ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]);
- }
-
if (stRxThreadInfo.stRxThread != 0) {
+ ANT_DEBUG_I("Sending shutdown signal to rx thread.");
+ if(write(stRxThreadInfo.iRxShutdownEventFd, &EVENT_FD_PLUS_ONE, sizeof(EVENT_FD_PLUS_ONE)) < 0)
+ {
+ ANT_ERROR("failed to signal rx thread with eventfd. Reason: %s", strerror(errno));
+ goto out;
+ }
+ ANT_DEBUG_I("Waiting for rx thread to finish.");
if (pthread_join(stRxThreadInfo.stRxThread, NULL) < 0) {
ANT_ERROR("failed to join rx thread: %s", strerror(errno));
goto out;
@@ -891,6 +924,10 @@
ANT_DEBUG_D("rx thread is not running");
}
+ for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) {
+ ant_disable_channel(&stRxThreadInfo.astChannels[eChannel]);
+ }
+
iRet = 0;
out:
diff --git a/src/vfs/ant_rx_chardev.c b/src/vfs/ant_rx_chardev.c
index b38757f..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()
@@ -60,6 +61,11 @@
#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);
/*
@@ -87,7 +93,7 @@
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();
@@ -96,29 +102,27 @@
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;
/* 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 (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_HARD_RESET)) {
- ANT_ERROR("poll error from %s. exiting rx thread",
+ 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;
-
- if (g_fnStateCallback) {
- g_fnStateCallback(RADIO_STATUS_RESETTING);
- }
-
- goto reset;
+ 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(
@@ -135,12 +139,36 @@
// 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;
+ }
}
}
@@ -177,15 +205,26 @@
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
+}
-reset:
+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__);
@@ -220,9 +259,6 @@
stRxThreadInfo->ucChipResetting = 0;
ANT_FUNC_END();
-#ifdef ANDROID
- return NULL;
-#endif
}
////////////////////////////////////////////////////////////////////
diff --git a/src/vfs/inc/ant_hci_defines.h b/src/vfs/inc/ant_hci_defines.h
new file mode 100644
index 0000000..3ffe672
--- /dev/null
+++ b/src/vfs/inc/ant_hci_defines.h
@@ -0,0 +1,53 @@
+/*
+ * ANT Stack
+ *
+ * Copyright 2013 Dynastream Innovations
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*******************************************************************************\
+*
+* FILE NAME: ant_hci_defines.h
+*
+* BRIEF:
+* This file defines ANT specific HCI values used by the ANT chip that are
+* not specific to the underlying chip. These should not need to be modified,
+* but should be verified they are correct.
+*
+\*******************************************************************************/
+
+#ifndef __VFS_INDEPENDENT_H
+#define __VFS_INDEPENDENT_H
+
+// ANT HCI Packet Structure
+// -----------------------------------------
+// | Header | Data | Footer |
+// |----------------------|-----------------|
+// |Optional| Data | Opt. | ... | Optional |
+// | Opcode | Size | Sync | | Checksum |
+// Data may include any number of ANT packets, with no sync byte or checksum.
+// A read from the driver may return any number of ANT HCI packets.
+
+#include "ant_driver_defines.h"
+
+#define ANT_HCI_HEADER_SIZE ((ANT_HCI_OPCODE_SIZE) + (ANT_HCI_SIZE_SIZE) + (ANT_HCI_SYNC_SIZE))
+#define ANT_HCI_FOOTER_SIZE (ANT_HCI_CHECKSUM_SIZE)
+
+#define ANT_HCI_OPCODE_OFFSET 0
+#define ANT_HCI_SIZE_OFFSET ((ANT_HCI_OPCODE_OFFSET) + (ANT_HCI_OPCODE_SIZE))
+#define ANT_HCI_SYNC_OFFSET ((ANT_HCI_SIZE_OFFSET) + (ANT_HCI_SIZE_SIZE))
+#define ANT_HCI_DATA_OFFSET (ANT_HCI_HEADER_SIZE)
+
+#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10
+
+#endif /* ifndef __VFS_INDEPENDENT_H */
diff --git a/src/vfs/inc/ant_rx_chardev.h b/src/vfs/inc/ant_rx_chardev.h
index 526070c..1024dac 100644
--- a/src/vfs/inc/ant_rx_chardev.h
+++ b/src/vfs/inc/ant_rx_chardev.h
@@ -32,7 +32,7 @@
#define __ANT_RX_NATIVE_H
#include "ant_native.h"
-#include "ant_driver_defines.h"
+#include "ant_hci_defines.h"
/* same as HCI_MAX_EVENT_SIZE from hci.h, but hci.h is not included for vfs */
#define ANT_HCI_MAX_MSG_SIZE 260
@@ -84,6 +84,8 @@
pthread_mutex_t *pstEnabledStatusLock;
/* ANT channels */
ant_channel_info_t astChannels[NUM_ANT_CHANNELS];
+ /* Event file descriptor used to interrupt the poll() loop in the rx thread. */
+ int iRxShutdownEventFd;
} ant_rx_thread_info_t;
extern ANTNativeANTStateCb g_fnStateCallback; // TODO State callback should be inside ant_rx_thread_info_t.
diff --git a/src/vfs/prerelease/ant_driver_defines.h b/src/vfs/prerelease/ant_driver_defines.h
index f2e843b..692de0d 100644
--- a/src/vfs/prerelease/ant_driver_defines.h
+++ b/src/vfs/prerelease/ant_driver_defines.h
@@ -82,17 +82,4 @@
// That signals Flow Stop:
#define ANT_FLOW_STOP ((ANT_U8)0x80)
-// ---------------------- NOT CHIP SPECIFIC
-// These should not need to be modified, but should be verified they are correct
-
-#define ANT_HCI_HEADER_SIZE ((ANT_HCI_OPCODE_SIZE) + (ANT_HCI_SIZE_SIZE) + (ANT_HCI_SYNC_SIZE))
-#define ANT_HCI_FOOTER_SIZE (ANT_HCI_CHECKSUM_SIZE)
-
-#define ANT_HCI_OPCODE_OFFSET 0
-#define ANT_HCI_SIZE_OFFSET ((ANT_HCI_OPCODE_OFFSET) + (ANT_HCI_OPCODE_SIZE))
-#define ANT_HCI_SYNC_OFFSET ((ANT_HCI_SIZE_OFFSET) + (ANT_HCI_SIZE_SIZE))
-#define ANT_HCI_DATA_OFFSET (ANT_HCI_HEADER_SIZE)
-
-#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10
-
#endif /* ifndef __VFS_PRERELEASE_H */
diff --git a/src/vfs/ste/cg29xx/ant_driver_defines.h b/src/vfs/ste/cg29xx/ant_driver_defines.h
index aa75ffa..c47415d 100644
--- a/src/vfs/ste/cg29xx/ant_driver_defines.h
+++ b/src/vfs/ste/cg29xx/ant_driver_defines.h
@@ -79,17 +79,4 @@
// That signals Flow Stop:
#define ANT_FLOW_STOP ((ANT_U8)0x80)
-
-// ---------------------- NOT CHIP SPECIFIC
-// These should not need to be modified, but should be verified they are correct
-
-#define ANT_HCI_HEADER_SIZE ((ANT_HCI_OPCODE_SIZE) + (ANT_HCI_SIZE_SIZE) + (ANT_HCI_SYNC_SIZE))
-
-#define ANT_HCI_OPCODE_OFFSET 0
-#define ANT_HCI_SIZE_OFFSET ((ANT_HCI_OPCODE_OFFSET) + (ANT_HCI_OPCODE_SIZE))
-#define ANT_HCI_SYNC_OFFSET ((ANT_HCI_SIZE_OFFSET) + (ANT_HCI_SIZE_SIZE))
-#define ANT_HCI_DATA_OFFSET (ANT_HCI_HEADER_SIZE)
-
-#define ANT_FLOW_GO_WAIT_TIMEOUT_SEC 10
-
#endif /* ifndef __VFS_PRERELEASE_H */