Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 1 | /* |
| 2 | * ANT Stack |
| 3 | * |
| 4 | * Copyright 2011 Dynastream Innovations |
| 5 | * |
| 6 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 7 | * you may not use this file except in compliance with the License. |
| 8 | * You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, software |
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | * See the License for the specific language governing permissions and |
| 16 | * limitations under the License. |
| 17 | */ |
| 18 | /******************************************************************************\ |
| 19 | * |
| 20 | * FILE NAME: ant_rx_chardev.c |
| 21 | * |
| 22 | * BRIEF: |
| 23 | * This file implements the receive thread function which will loop reading |
| 24 | * ANT messages until told to exit. |
| 25 | * |
| 26 | * |
| 27 | \******************************************************************************/ |
| 28 | |
| 29 | #include <errno.h> |
Naveen Kumar | 09c3957 | 2015-08-20 19:49:28 +0530 | [diff] [blame] | 30 | #include <string.h> |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 31 | #include <poll.h> |
| 32 | #include <pthread.h> |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 33 | #include <stdint.h> /* for uint64_t */ |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 34 | |
| 35 | #include "ant_types.h" |
| 36 | #include "antradio_power.h" |
| 37 | #include "ant_rx_chardev.h" |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 38 | #include "ant_hci_defines.h" |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 39 | #include "ant_log.h" |
| 40 | #include "ant_native.h" // ANT_HCI_MAX_MSG_SIZE, ANT_MSG_ID_OFFSET, ANT_MSG_DATA_OFFSET, |
| 41 | // ant_radio_enabled_status() |
| 42 | |
| 43 | extern ANTStatus ant_tx_message_flowcontrol_none(ant_channel_type eTxPath, ANT_U8 ucMessageLength, ANT_U8 *pucTxMessage); |
| 44 | |
| 45 | #undef LOG_TAG |
| 46 | #define LOG_TAG "antradio_rx" |
| 47 | |
| 48 | #define ANT_POLL_TIMEOUT ((int)30000) |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 49 | #define KEEPALIVE_TIMEOUT ((int)5000) |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 50 | |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 51 | static ANT_U8 aucRxBuffer[NUM_ANT_CHANNELS][ANT_HCI_MAX_MSG_SIZE]; |
| 52 | |
| 53 | #ifdef ANT_DEVICE_NAME // Single transport path |
| 54 | static int iRxBufferLength[NUM_ANT_CHANNELS] = {0}; |
| 55 | #else |
| 56 | static int iRxBufferLength[NUM_ANT_CHANNELS] = {0, 0}; |
| 57 | #endif // |
| 58 | |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 59 | // Defines for use with the poll() call |
| 60 | #define EVENT_DATA_AVAILABLE (POLLIN|POLLRDNORM) |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 61 | #define EVENT_CHIP_SHUTDOWN (POLLHUP) |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 62 | #define EVENT_HARD_RESET (POLLERR|POLLPRI|POLLRDHUP) |
| 63 | |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 64 | #define EVENTS_TO_LISTEN_FOR (EVENT_DATA_AVAILABLE|EVENT_CHIP_SHUTDOWN|EVENT_HARD_RESET) |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 65 | |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 66 | // Plus one is for the eventfd shutdown signal. |
| 67 | #define NUM_POLL_FDS (NUM_ANT_CHANNELS + 1) |
| 68 | #define EVENTFD_IDX NUM_ANT_CHANNELS |
| 69 | |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 70 | static ANT_U8 KEEPALIVE_MESG[] = {0x01, 0x00, 0x00}; |
| 71 | static ANT_U8 KEEPALIVE_RESP[] = {0x03, 0x40, 0x00, 0x00, 0x28}; |
| 72 | |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 73 | void doReset(ant_rx_thread_info_t *stRxThreadInfo); |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 74 | int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo); |
| 75 | |
| 76 | /* |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 77 | * Function to check that all given flags are set in a particular value. |
| 78 | * Designed for use with the revents field of pollfds filled out by poll(). |
| 79 | * |
| 80 | * Parameters: |
| 81 | * - value: The value that will be checked to contain all flags. |
| 82 | * - flags: Bitwise-or of the flags that value should be checked for. |
| 83 | * |
| 84 | * Returns: |
| 85 | * - true IFF all the bits that are set in 'flags' are also set in 'value' |
| 86 | */ |
| 87 | ANT_BOOL areAllFlagsSet(short value, short flags) |
| 88 | { |
| 89 | value &= flags; |
| 90 | return (value == flags); |
| 91 | } |
| 92 | |
| 93 | /* |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 94 | * This thread is run occasionally as a detached thread in order to send a keepalive message to the |
| 95 | * chip. |
| 96 | */ |
| 97 | void *fnKeepAliveThread(void *unused) |
| 98 | { |
| 99 | ANT_DEBUG_V("Sending dummy keepalive message."); |
| 100 | ant_tx_message(sizeof(KEEPALIVE_MESG)/sizeof(ANT_U8), KEEPALIVE_MESG); |
| 101 | return NULL; |
| 102 | } |
| 103 | |
| 104 | /* |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 105 | * This thread waits for ANT messages from a VFS file. |
| 106 | */ |
| 107 | void *fnRxThread(void *ant_rx_thread_info) |
| 108 | { |
| 109 | int iMutexLockResult; |
| 110 | int iPollRet; |
| 111 | ant_rx_thread_info_t *stRxThreadInfo; |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 112 | struct pollfd astPollFd[NUM_POLL_FDS]; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 113 | ant_channel_type eChannel; |
| 114 | ANT_FUNC_START(); |
| 115 | |
| 116 | stRxThreadInfo = (ant_rx_thread_info_t *)ant_rx_thread_info; |
| 117 | for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { |
| 118 | astPollFd[eChannel].fd = stRxThreadInfo->astChannels[eChannel].iFd; |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 119 | astPollFd[eChannel].events = EVENTS_TO_LISTEN_FOR; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 120 | } |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 121 | // Fill out poll request for the shutdown signaller. |
| 122 | astPollFd[EVENTFD_IDX].fd = stRxThreadInfo->iRxShutdownEventFd; |
| 123 | astPollFd[EVENTFD_IDX].events = POLL_IN; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 124 | |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 125 | // Reset the waiting for response, since we don't want a stale value if we were reset. |
| 126 | stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_FALSE; |
| 127 | |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 128 | /* continue running as long as not terminated */ |
| 129 | while (stRxThreadInfo->ucRunThread) { |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 130 | /* Wait for data available on any file (transport path), shorter wait if we just timed out. */ |
| 131 | int timeout = stRxThreadInfo->bWaitingForKeepaliveResponse ? KEEPALIVE_TIMEOUT : ANT_POLL_TIMEOUT; |
| 132 | iPollRet = poll(astPollFd, NUM_POLL_FDS, timeout); |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 133 | if (!iPollRet) { |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 134 | if(!stRxThreadInfo->bWaitingForKeepaliveResponse) |
| 135 | { |
| 136 | stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_TRUE; |
| 137 | // Keep alive is done on a separate thread so that rxThread can handle flow control during |
| 138 | // the message. |
| 139 | pthread_t thread; |
| 140 | // Don't care if it failed as the consequence is just a missed keep-alive. |
| 141 | pthread_create(&thread, NULL, fnKeepAliveThread, NULL); |
| 142 | // Detach the thread so that we don't need to join it later. |
| 143 | pthread_detach(thread); |
| 144 | ANT_DEBUG_V("poll timed out, checking exit cond"); |
| 145 | } else |
| 146 | { |
| 147 | ANT_DEBUG_E("No response to keepalive, attempting recovery."); |
| 148 | doReset(stRxThreadInfo); |
| 149 | goto out; |
| 150 | } |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 151 | } else if (iPollRet < 0) { |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 152 | ANT_ERROR("unhandled error: %s, attempting recovery.", strerror(errno)); |
| 153 | doReset(stRxThreadInfo); |
| 154 | goto out; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 155 | } else { |
| 156 | for (eChannel = 0; eChannel < NUM_ANT_CHANNELS; eChannel++) { |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 157 | if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_HARD_RESET)) { |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 158 | ANT_ERROR("Hard reset indicated by %s. Attempting recovery.", |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 159 | stRxThreadInfo->astChannels[eChannel].pcDevicePath); |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 160 | doReset(stRxThreadInfo); |
| 161 | goto out; |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 162 | } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_CHIP_SHUTDOWN)) { |
| 163 | /* chip reported it was unexpectedly disabled */ |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 164 | ANT_DEBUG_D( |
| 165 | "poll hang-up from %s. exiting rx thread", stRxThreadInfo->astChannels[eChannel].pcDevicePath); |
| 166 | |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 167 | doReset(stRxThreadInfo); |
| 168 | goto out; |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 169 | } else if (areAllFlagsSet(astPollFd[eChannel].revents, EVENT_DATA_AVAILABLE)) { |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 170 | ANT_DEBUG_D("data on %s. reading it", |
| 171 | stRxThreadInfo->astChannels[eChannel].pcDevicePath); |
| 172 | |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 173 | // Doesn't matter what data we received, we know the chip is alive. |
| 174 | stRxThreadInfo->bWaitingForKeepaliveResponse = ANT_FALSE; |
| 175 | |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 176 | if (readChannelMsg(eChannel, &stRxThreadInfo->astChannels[eChannel]) < 0) { |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 177 | // set flag to exit out of Rx Loop |
| 178 | stRxThreadInfo->ucRunThread = 0; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 179 | } |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 180 | } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLNVAL)) { |
| 181 | ANT_ERROR("poll was called on invalid file descriptor %s. Attempting recovery.", |
| 182 | stRxThreadInfo->astChannels[eChannel].pcDevicePath); |
| 183 | doReset(stRxThreadInfo); |
| 184 | goto out; |
| 185 | } else if (areAllFlagsSet(astPollFd[eChannel].revents, POLLERR)) { |
| 186 | ANT_ERROR("Unknown error from %s. Attempting recovery.", |
| 187 | stRxThreadInfo->astChannels[eChannel].pcDevicePath); |
| 188 | doReset(stRxThreadInfo); |
| 189 | goto out; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 190 | } else if (astPollFd[eChannel].revents) { |
| 191 | ANT_DEBUG_W("unhandled poll result %#x from %s", |
| 192 | astPollFd[eChannel].revents, |
| 193 | stRxThreadInfo->astChannels[eChannel].pcDevicePath); |
| 194 | } |
| 195 | } |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 196 | // Now check for shutdown signal |
| 197 | if(areAllFlagsSet(astPollFd[EVENTFD_IDX].revents, POLLIN)) |
| 198 | { |
| 199 | ANT_DEBUG_I("rx thread caught shutdown signal."); |
| 200 | // reset the counter by reading. |
| 201 | uint64_t counter; |
| 202 | read(stRxThreadInfo->iRxShutdownEventFd, &counter, sizeof(counter)); |
| 203 | // don't care if read error, going to close the thread anyways. |
| 204 | stRxThreadInfo->ucRunThread = 0; |
| 205 | } else if (astPollFd[EVENTFD_IDX].revents != 0) { |
| 206 | ANT_ERROR("Shutdown event descriptor had unexpected event: %#x. exiting rx thread.", |
| 207 | astPollFd[EVENTFD_IDX].revents); |
| 208 | stRxThreadInfo->ucRunThread = 0; |
| 209 | } |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 210 | } |
| 211 | } |
| 212 | |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 213 | /* disable ANT radio if not already disabling */ |
| 214 | // Try to get stEnabledStatusLock. |
| 215 | // if you get it then no one is enabling or disabling |
| 216 | // if you can't get it assume something made you exit |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 217 | ANT_DEBUG_V("try getting stEnabledStatusLock in %s", __FUNCTION__); |
| 218 | iMutexLockResult = pthread_mutex_trylock(stRxThreadInfo->pstEnabledStatusLock); |
| 219 | if (!iMutexLockResult) { |
| 220 | ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); |
| 221 | ANT_WARN("rx thread has unexpectedly crashed, cleaning up"); |
Khurshid | e1e6966 | 2013-09-27 10:27:48 -0600 | [diff] [blame] | 222 | |
| 223 | // spoof our handle as closed so we don't try to join ourselves in disable |
| 224 | stRxThreadInfo->stRxThread = 0; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 225 | |
| 226 | if (g_fnStateCallback) { |
| 227 | g_fnStateCallback(RADIO_STATUS_DISABLING); |
| 228 | } |
| 229 | |
| 230 | ant_disable(); |
| 231 | |
| 232 | if (g_fnStateCallback) { |
| 233 | g_fnStateCallback(ant_radio_enabled_status()); |
| 234 | } |
| 235 | |
| 236 | ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); |
| 237 | pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); |
| 238 | ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); |
| 239 | } else if (iMutexLockResult != EBUSY) { |
| 240 | ANT_ERROR("rx thread closing code, trylock on state lock failed: %s", |
| 241 | strerror(iMutexLockResult)); |
| 242 | } else { |
| 243 | ANT_DEBUG_V("stEnabledStatusLock busy"); |
| 244 | } |
| 245 | |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 246 | out: |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 247 | ANT_FUNC_END(); |
| 248 | #ifdef ANDROID |
| 249 | return NULL; |
| 250 | #endif |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 251 | } |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 252 | |
Khurshid | 4d09cf1 | 2013-10-01 16:45:34 -0600 | [diff] [blame] | 253 | void doReset(ant_rx_thread_info_t *stRxThreadInfo) |
| 254 | { |
| 255 | int iMutexLockResult; |
| 256 | |
| 257 | ANT_FUNC_START(); |
| 258 | /* Chip was reset or other error, only way to recover is to |
| 259 | * close and open ANT chardev */ |
| 260 | stRxThreadInfo->ucChipResetting = 1; |
| 261 | |
| 262 | if (g_fnStateCallback) { |
| 263 | g_fnStateCallback(RADIO_STATUS_RESETTING); |
| 264 | } |
| 265 | |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 266 | stRxThreadInfo->ucRunThread = 0; |
| 267 | |
| 268 | ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); |
| 269 | iMutexLockResult = pthread_mutex_lock(stRxThreadInfo->pstEnabledStatusLock); |
| 270 | if (iMutexLockResult < 0) { |
| 271 | ANT_ERROR("chip was reset, getting state mutex failed: %s", |
| 272 | strerror(iMutexLockResult)); |
| 273 | stRxThreadInfo->stRxThread = 0; |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 274 | stRxThreadInfo->ucChipResetting = 0; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 275 | } else { |
| 276 | ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); |
| 277 | |
| 278 | stRxThreadInfo->stRxThread = 0; /* spoof our handle as closed so we don't |
| 279 | * try to join ourselves in disable */ |
| 280 | |
| 281 | ant_disable(); |
| 282 | |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 283 | int enableResult = ant_enable(); |
| 284 | |
| 285 | stRxThreadInfo->ucChipResetting = 0; |
| 286 | if (enableResult) { /* failed */ |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 287 | if (g_fnStateCallback) { |
| 288 | g_fnStateCallback(RADIO_STATUS_DISABLED); |
| 289 | } |
| 290 | } else { /* success */ |
| 291 | if (g_fnStateCallback) { |
| 292 | g_fnStateCallback(RADIO_STATUS_RESET); |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); |
| 297 | pthread_mutex_unlock(stRxThreadInfo->pstEnabledStatusLock); |
| 298 | ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); |
| 299 | } |
| 300 | |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 301 | ANT_FUNC_END(); |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 302 | } |
| 303 | |
| 304 | //////////////////////////////////////////////////////////////////// |
| 305 | // setFlowControl |
| 306 | // |
| 307 | // Sets the flow control "flag" to the value provided and signals the transmit |
| 308 | // thread to check the value. |
| 309 | // |
| 310 | // Parameters: |
| 311 | // pstChnlInfo the details of the channel being updated |
| 312 | // ucFlowSetting the value to use |
| 313 | // |
| 314 | // Returns: |
| 315 | // Success: |
| 316 | // 0 |
| 317 | // Failure: |
| 318 | // -1 |
| 319 | //////////////////////////////////////////////////////////////////// |
| 320 | int setFlowControl(ant_channel_info_t *pstChnlInfo, ANT_U8 ucFlowSetting) |
| 321 | { |
| 322 | int iRet = -1; |
| 323 | int iMutexResult; |
| 324 | ANT_FUNC_START(); |
| 325 | |
| 326 | ANT_DEBUG_V("getting stFlowControlLock in %s", __FUNCTION__); |
| 327 | iMutexResult = pthread_mutex_lock(pstChnlInfo->pstFlowControlLock); |
| 328 | if (iMutexResult) { |
| 329 | ANT_ERROR("failed to lock flow control mutex during response: %s", strerror(iMutexResult)); |
| 330 | } else { |
| 331 | ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__); |
| 332 | |
| 333 | pstChnlInfo->ucFlowControlResp = ucFlowSetting; |
| 334 | |
| 335 | ANT_DEBUG_V("releasing stFlowControlLock in %s", __FUNCTION__); |
| 336 | pthread_mutex_unlock(pstChnlInfo->pstFlowControlLock); |
| 337 | ANT_DEBUG_V("released stFlowControlLock in %s", __FUNCTION__); |
| 338 | |
| 339 | pthread_cond_signal(pstChnlInfo->pstFlowControlCond); |
| 340 | |
| 341 | iRet = 0; |
| 342 | } |
| 343 | |
| 344 | ANT_FUNC_END(); |
| 345 | return iRet; |
| 346 | } |
| 347 | |
| 348 | int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo) |
| 349 | { |
| 350 | int iRet = -1; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 351 | int iRxLenRead; |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 352 | int iCurrentHciPacketOffset; |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 353 | int iHciDataSize; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 354 | ANT_FUNC_START(); |
| 355 | |
| 356 | // Keep trying to read while there is an error, and that error is EAGAIN |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 357 | while (((iRxLenRead = read(pstChnlInfo->iFd, &aucRxBuffer[eChannel][iRxBufferLength[eChannel]], (sizeof(aucRxBuffer[eChannel]) - iRxBufferLength[eChannel]))) < 0) |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 358 | && errno == EAGAIN) |
| 359 | ; |
| 360 | |
| 361 | if (iRxLenRead < 0) { |
| 362 | if (errno == ENODEV) { |
| 363 | ANT_ERROR("%s not enabled, exiting rx thread", |
| 364 | pstChnlInfo->pcDevicePath); |
| 365 | |
| 366 | goto out; |
| 367 | } else if (errno == ENXIO) { |
| 368 | ANT_ERROR("%s there is no physical ANT device connected", |
| 369 | pstChnlInfo->pcDevicePath); |
| 370 | |
| 371 | goto out; |
| 372 | } else { |
| 373 | ANT_ERROR("%s read thread exiting, unhandled error: %s", |
| 374 | pstChnlInfo->pcDevicePath, strerror(errno)); |
| 375 | |
| 376 | goto out; |
| 377 | } |
| 378 | } else { |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 379 | ANT_SERIAL(aucRxBuffer[eChannel], iRxLenRead, 'R'); |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 380 | |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 381 | iRxLenRead += iRxBufferLength[eChannel]; // add existing data on |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 382 | |
| 383 | // if we didn't get a full packet, then just exit |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 384 | if (iRxLenRead < (aucRxBuffer[eChannel][ANT_HCI_SIZE_OFFSET] + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE)) { |
| 385 | iRxBufferLength[eChannel] = iRxLenRead; |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 386 | iRet = 0; |
| 387 | goto out; |
| 388 | } |
Jeremy Friesen | e6e7a81 | 2013-05-01 09:10:37 -0600 | [diff] [blame] | 389 | |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 390 | iRxBufferLength[eChannel] = 0; // reset buffer length here since we should have a full packet |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 391 | |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 392 | #if ANT_HCI_OPCODE_SIZE == 1 // Check the different message types by opcode |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 393 | ANT_U8 opcode = aucRxBuffer[eChannel][ANT_HCI_OPCODE_OFFSET]; |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 394 | |
| 395 | if(ANT_HCI_OPCODE_COMMAND_COMPLETE == opcode) { |
| 396 | // Command Complete, so signal a FLOW_GO |
| 397 | if(setFlowControl(pstChnlInfo, ANT_FLOW_GO)) { |
| 398 | goto out; |
| 399 | } |
| 400 | } else if(ANT_HCI_OPCODE_FLOW_ON == opcode) { |
| 401 | // FLow On, so resend the last Tx |
| 402 | #ifdef ANT_FLOW_RESEND |
| 403 | // Check if there is a message to resend |
| 404 | if(pstChnlInfo->ucResendMessageLength > 0) { |
| 405 | ant_tx_message_flowcontrol_none(eChannel, pstChnlInfo->ucResendMessageLength, pstChnlInfo->pucResendMessage); |
| 406 | } else { |
| 407 | ANT_DEBUG_D("Resend requested by chip, but tx request cancelled"); |
| 408 | } |
| 409 | #endif // ANT_FLOW_RESEND |
| 410 | } else if(ANT_HCI_OPCODE_ANT_EVENT == opcode) |
| 411 | // ANT Event, send ANT packet to Rx Callback |
| 412 | #endif // ANT_HCI_OPCODE_SIZE == 1 |
| 413 | { |
| 414 | // Received an ANT packet |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 415 | iCurrentHciPacketOffset = 0; |
| 416 | |
| 417 | while(iCurrentHciPacketOffset < iRxLenRead) { |
| 418 | |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 419 | // TODO Allow HCI Packet Size value to be larger than 1 byte |
| 420 | // This currently works as no size value is greater than 255, and little endian |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 421 | iHciDataSize = aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_SIZE_OFFSET]; |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 422 | |
Jeremy Friesen | 2d96a12 | 2013-05-01 09:29:08 -0600 | [diff] [blame] | 423 | if ((iHciDataSize + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE + iCurrentHciPacketOffset) > |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 424 | iRxLenRead) { |
| 425 | // we don't have a whole packet |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 426 | iRxBufferLength[eChannel] = iRxLenRead - iCurrentHciPacketOffset; |
| 427 | memcpy(aucRxBuffer[eChannel], &aucRxBuffer[eChannel][iCurrentHciPacketOffset], iRxBufferLength[eChannel]); |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 428 | // the increment at the end should push us out of the while loop |
| 429 | } else |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 430 | #ifdef ANT_MESG_FLOW_CONTROL |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 431 | if (aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET] == |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 432 | ANT_MESG_FLOW_CONTROL) { |
| 433 | // This is a flow control packet, not a standard ANT message |
| 434 | if(setFlowControl(pstChnlInfo, \ |
Jeremy Friesen | bc43659 | 2013-05-07 14:44:01 -0600 | [diff] [blame] | 435 | aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET + ANT_MSG_DATA_OFFSET])) { |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 436 | goto out; |
| 437 | } |
| 438 | } else |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 439 | #endif // ANT_MESG_FLOW_CONTROL |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 440 | { |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 441 | ANT_U8 *msg = aucRxBuffer[eChannel] + iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET; |
| 442 | ANT_BOOL bIsKeepAliveResponse = memcmp(msg, KEEPALIVE_RESP, sizeof(KEEPALIVE_RESP)/sizeof(ANT_U8)) == 0; |
| 443 | if (bIsKeepAliveResponse) { |
| 444 | ANT_DEBUG_V("Filtered out keepalive response."); |
| 445 | } else if (pstChnlInfo->fnRxCallback != NULL) { |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 446 | |
| 447 | // Loop through read data until all HCI packets are written to callback |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 448 | pstChnlInfo->fnRxCallback(iHciDataSize, \ |
James Bootsma | 105c80a | 2014-03-13 16:12:54 -0600 | [diff] [blame] | 449 | msg); |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 450 | } else { |
| 451 | ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath); |
Jeremy Friesen | e6e7a81 | 2013-05-01 09:10:37 -0600 | [diff] [blame] | 452 | } |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 453 | } |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 454 | |
Jeremy Friesen | ddde26e | 2013-04-17 16:40:52 -0600 | [diff] [blame] | 455 | iCurrentHciPacketOffset = iCurrentHciPacketOffset + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE + iHciDataSize; |
Jeremy Friesen | f8b491f | 2013-04-05 15:58:20 -0600 | [diff] [blame] | 456 | } |
Rohan Martin | af8cf68 | 2012-11-16 21:11:07 -0700 | [diff] [blame] | 457 | } |
| 458 | |
| 459 | iRet = 0; |
| 460 | } |
| 461 | |
| 462 | out: |
| 463 | ANT_FUNC_END(); |
| 464 | return iRet; |
| 465 | } |