//////////////////////////////////////////////////////////////////// // setFlowControl // // Sets the flow control "flag" to the value provided and signals the transmit // thread to check the value. // // Parameters: // pstChnlInfo the details of the channel being updated // ucFlowSetting the value to use // // Returns: // Success: // 0 // Failure: // -1 //////////////////////////////////////////////////////////////////// int setFlowControl(ant_channel_info_t *pstChnlInfo, ANT_U8 ucFlowSetting) { int iRet = -1; int iMutexResult; ANT_FUNC_START(); ANT_DEBUG_V("getting stFlowControlLock in %s", __FUNCTION__); iMutexResult = pthread_mutex_lock(pstChnlInfo->pstFlowControlLock); if (iMutexResult) { ANT_ERROR("failed to lock flow control mutex during response: %s", strerror(iMutexResult)); } else { ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__); pstChnlInfo->ucFlowControlResp = ucFlowSetting; ANT_DEBUG_V("releasing stFlowControlLock in %s", __FUNCTION__); pthread_mutex_unlock(pstChnlInfo->pstFlowControlLock); ANT_DEBUG_V("released stFlowControlLock in %s", __FUNCTION__); pthread_cond_signal(pstChnlInfo->pstFlowControlCond); iRet = 0; } ANT_FUNC_END(); return iRet; }
ANTStatus ant_disable_radio(void) { int iLockResult; ANTStatus ret = ANT_STATUS_FAILED; ANT_FUNC_START(); ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); iLockResult = pthread_mutex_lock(&stEnabledStatusLock); if(iLockResult) { ANT_ERROR("disable failed to get state lock: %s", strerror(iLockResult)); goto out; } ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); if (g_fnStateCallback) { g_fnStateCallback(RADIO_STATUS_DISABLING); } ant_disable(); if (g_fnStateCallback) { g_fnStateCallback(ant_radio_enabled_status()); } ret = ANT_STATUS_SUCCESS; ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); pthread_mutex_unlock(&stEnabledStatusLock); ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); out: ANT_FUNC_END(); return ret; }
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(); }
ANTStatus ant_radio_hard_reset(void) { ANTStatus result_status = ANT_STATUS_NOT_SUPPORTED; ANT_FUNC_START(); #ifdef ANT_IOCTL_RESET ant_channel_type eChannel; int iLockResult; result_status = ANT_STATUS_FAILED; ANT_DEBUG_V("getting stEnabledStatusLock in %s", __FUNCTION__); iLockResult = pthread_mutex_lock(&stEnabledStatusLock); if(iLockResult) { ANT_ERROR("enable failed to get state lock: %s", strerror(iLockResult)); goto out; } ANT_DEBUG_V("got stEnabledStatusLock in %s", __FUNCTION__); stRxThreadInfo.ucChipResetting = 1; if (g_fnStateCallback) g_fnStateCallback(RADIO_STATUS_RESETTING); #ifdef ANT_IOCTL_RESET_PARAMETER ioctl(stRxThreadInfo.astChannels[0].iFd, ANT_IOCTL_RESET, ANT_IOCTL_RESET_PARAMETER); #else ioctl(stRxThreadInfo.astChannels[0].iFd, ANT_IOCTL_RESET); #endif // ANT_IOCTL_RESET_PARAMETER ant_disable(); if (ant_enable()) { /* failed */ if (g_fnStateCallback) g_fnStateCallback(RADIO_STATUS_DISABLED); } else { /* success */ if (g_fnStateCallback) g_fnStateCallback(RADIO_STATUS_RESET); result_status = ANT_STATUS_SUCCESS; } stRxThreadInfo.ucChipResetting = 0; ANT_DEBUG_V("releasing stEnabledStatusLock in %s", __FUNCTION__); pthread_mutex_unlock(&stEnabledStatusLock); ANT_DEBUG_V("released stEnabledStatusLock in %s", __FUNCTION__); out: #endif // ANT_IOCTL_RESET ANT_FUNC_END(); return result_status; }
void nativeJAnt_StateCallback(ANTRadioEnabledStatus uiNewState) { JNIEnv* env = NULL; jint jNewState = uiNewState; ANT_BOOL iShouldDetach = ANT_FALSE; ANT_FUNC_START(); g_jVM->GetEnv((void**) &env, JNI_VERSION_1_4); if (env == NULL) { ANT_DEBUG_D("nativeJAnt_StateCallback: called from rx thread, attaching to VM"); g_jVM->AttachCurrentThread((&env), NULL); if (env == NULL) { ANT_DEBUG_E("nativeJAnt_StateCallback: failed to attach rx thread to VM"); return; } iShouldDetach = ANT_TRUE; } else { ANT_DEBUG_D("nativeJAnt_StateCallback: called from java enable/disable" ", already attached, don't detach"); } ANT_DEBUG_V("nativeJAnt_StateCallback: Calling java state callback"); env->CallStaticVoidMethod(g_sJClazz, g_sMethodId_nativeCb_AntStateChange, jNewState); ANT_DEBUG_V("nativeJAnt_StateCallback: Called java state callback"); if (env->ExceptionOccurred()) { ANT_ERROR("nativeJAnt_StateCallback: Calling Java nativeCb_AntStateChange failed"); env->ExceptionDescribe(); env->ExceptionClear(); } if (iShouldDetach) { ANT_DEBUG_D("nativeJAnt_StateCallback: env was attached, detaching"); g_jVM->DetachCurrentThread(); } ANT_FUNC_END(); return; }
/* * This thread opens a Bluez HCI socket and waits for ANT messages. */ void *ANTHCIRxThread(void *pvHCIDevice) { int ret = ANT_STATUS_SUCCESS; int rxSocket; int len; unsigned char buf[HCI_MAX_EVENT_SIZE]; int result; struct hci_filter eventVendorFilter; ANT_FUNC_START(); (void)pvHCIDevice; //unused waring ANT_DEBUG_D("Entering ANTHCIRxThread"); rxSocket = create_hci_sock(); if (rxSocket < 0) { ANT_DEBUG_E("can't open HCI socket in rx thread: %s", strerror(errno)); ret = ANT_STATUS_FAILED; goto out; } eventVendorFilter.type_mask = TYPE_MASK_EVENT_PACKET; eventVendorFilter.event_mask[0] = 0; eventVendorFilter.event_mask[1] = EVENT_MASK_1_EVENT_VENDOR; eventVendorFilter.opcode = htobs(ANT_EVENT_VENDOR_CODE); if (setsockopt(rxSocket, SOL_HCI, HCI_FILTER, &eventVendorFilter, sizeof(eventVendorFilter)) < 0) { ANT_ERROR("failed to set socket options: %s", strerror(errno)); ret = ANT_STATUS_FAILED; goto close; } /* continue running as long as not terminated */ while (get_and_set_radio_status() == RADIO_STATUS_ENABLED) { struct pollfd p; int n; p.fd = rxSocket; p.events = POLLIN; ANT_DEBUG_V(" RX: Polling HCI for data..."); /* poll socket, wait for ANT messages */ while ((n = poll(&p, 1, 2500)) == -1) { if (errno == EAGAIN || errno == EINTR) continue; ANT_ERROR("failed to poll socket: %s", strerror(errno)); ret = ANT_STATUS_FAILED; goto close; } /* we timeout once in a while */ /* this let's us the chance to check if we were terminated */ if (0 == n) { ANT_DEBUG_V(" RX: Timeout"); continue; } ANT_DEBUG_D("New HCI data available, reading..."); /* read newly arrived data */ /* TBD: rethink assumption about single arrival */ while ((len = read(rxSocket, buf, sizeof(buf))) < 0) { if (errno == EAGAIN || errno == EINTR) continue; ANT_ERROR("failed to read socket: %s", strerror(errno)); ret = ANT_STATUS_FAILED; goto close; } hci_event_packet_t *event_packet = (hci_event_packet_t *)buf; int hci_payload_len = validate_hci_event_packet(event_packet, len); if (hci_payload_len == -1) { // part of the message is incorrect, ignore it. validate_event_packet will log error continue; } ANT_SERIAL(event_packet->hci_payload, hci_payload_len, 'R'); if(RxParams.pfRxCallback != NULL) { RxParams.pfRxCallback(hci_payload_len, event_packet->hci_payload); } else { ANT_ERROR("Can't send rx message - no callback registered"); } } close: result = pthread_mutex_trylock(&enableLock); ANT_DEBUG_D("rx thread close: trylock enableLock returned %d", result); if (result == 0) { ANT_DEBUG_W("rx thread socket has unexpectedly crashed"); #if USE_EXTERNAL_POWER_LIBRARY if (RxParams.pfStateCallback) RxParams.pfStateCallback(RADIO_STATUS_DISABLING); ant_disable(); get_and_set_radio_status(); #else radio_status = RADIO_STATUS_DISABLED; #endif RxParams.thread = 0; pthread_mutex_unlock(&enableLock); } else if (result == EBUSY) { ANT_DEBUG_V("rx thread socket was closed"); } else { ANT_ERROR("rx thread close: trylock failed: %s", strerror(result)); } if (-1 == close(rxSocket)) { ANT_ERROR("failed to close hci device (socket handle=%#x): %s", rxSocket, strerror(errno)); } else { ANT_DEBUG_D("closed hci device (socket handle=%#x)", rxSocket); } out: ANT_FUNC_END(); pthread_exit((void *)ret); #if defined(ANDROID) return 0; #endif }
/********************************************************************** * Callback registration ***********************************************************************/ void nativeJAnt_RxCallback(ANT_U8 ucLen, ANT_U8* pucData) { JNIEnv* env = NULL; jbyteArray jAntRxMsg = NULL; ANT_FUNC_START(); ANT_DEBUG_D( "got message %d bytes", ucLen); g_jVM->AttachCurrentThread((&env), NULL); if (env == NULL) { ANT_DEBUG_D("nativeJAnt_RxCallback: Entered, env is null"); return; // log error? cleanup? } else { ANT_DEBUG_D("nativeJAnt_RxCallback: jEnv %p", env); } jAntRxMsg = env->NewByteArray(ucLen); if (jAntRxMsg == NULL) { ANT_ERROR("nativeJAnt_RxCallback: Failed creating java byte[]"); goto CLEANUP; } env->SetByteArrayRegion(jAntRxMsg,0,ucLen,(jbyte*)pucData); if (env->ExceptionOccurred()) { ANT_ERROR("nativeJAnt_RxCallback: ExceptionOccurred during byte[] copy"); goto CLEANUP; } ANT_DEBUG_V("nativeJAnt_RxCallback: Calling java rx callback"); env->CallStaticVoidMethod(g_sJClazz, g_sMethodId_nativeCb_AntRxMessage, jAntRxMsg); ANT_DEBUG_V("nativeJAnt_RxCallback: Called java rx callback"); if (env->ExceptionOccurred()) { ANT_ERROR("nativeJAnt_RxCallback: Calling Java nativeCb_AntRxMessage failed"); goto CLEANUP; } //Delete the local references if (jAntRxMsg != NULL) { env->DeleteLocalRef(jAntRxMsg); } ANT_DEBUG_D("nativeJAnt_RxCallback: Exiting, Calling DetachCurrentThread at the END"); g_jVM->DetachCurrentThread(); ANT_FUNC_END(); return; CLEANUP: ANT_ERROR("nativeJAnt_RxCallback: Exiting due to failure"); if (jAntRxMsg != NULL) { env->DeleteLocalRef(jAntRxMsg); } if (env->ExceptionOccurred()) { env->ExceptionDescribe(); env->ExceptionClear(); } g_jVM->DetachCurrentThread(); return; }
/* * 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; }
int readChannelMsg(ant_channel_type eChannel, ant_channel_info_t *pstChnlInfo) { int iRet = -1; int iRxLenRead; int iCurrentHciPacketOffset; int iHciDataSize; ANT_FUNC_START(); // Keep trying to read while there is an error, and that error is EAGAIN while (((iRxLenRead = read(pstChnlInfo->iFd, &aucRxBuffer[eChannel][iRxBufferLength[eChannel]], (sizeof(aucRxBuffer[eChannel]) - iRxBufferLength[eChannel]))) < 0) && errno == EAGAIN) ; if (iRxLenRead < 0) { if (errno == ENODEV) { ANT_ERROR("%s not enabled, exiting rx thread", pstChnlInfo->pcDevicePath); goto out; } else if (errno == ENXIO) { ANT_ERROR("%s there is no physical ANT device connected", pstChnlInfo->pcDevicePath); goto out; } else { ANT_ERROR("%s read thread exiting, unhandled error: %s", pstChnlInfo->pcDevicePath, strerror(errno)); goto out; } } else { ANT_SERIAL(aucRxBuffer[eChannel], iRxLenRead, 'R'); iRxLenRead += iRxBufferLength[eChannel]; // add existing data on // if we didn't get a full packet, then just exit if (iRxLenRead < (aucRxBuffer[eChannel][ANT_HCI_SIZE_OFFSET] + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE)) { iRxBufferLength[eChannel] = iRxLenRead; iRet = 0; goto out; } iRxBufferLength[eChannel] = 0; // reset buffer length here since we should have a full packet #if ANT_HCI_OPCODE_SIZE == 1 // Check the different message types by opcode ANT_U8 opcode = aucRxBuffer[eChannel][ANT_HCI_OPCODE_OFFSET]; if(ANT_HCI_OPCODE_COMMAND_COMPLETE == opcode) { // Command Complete, so signal a FLOW_GO if(setFlowControl(pstChnlInfo, ANT_FLOW_GO)) { goto out; } } else if(ANT_HCI_OPCODE_FLOW_ON == opcode) { // FLow On, so resend the last Tx #ifdef ANT_FLOW_RESEND // Check if there is a message to resend if(pstChnlInfo->ucResendMessageLength > 0) { ant_tx_message_flowcontrol_none(eChannel, pstChnlInfo->ucResendMessageLength, pstChnlInfo->pucResendMessage); } else { ANT_DEBUG_D("Resend requested by chip, but tx request cancelled"); } #endif // ANT_FLOW_RESEND } else if(ANT_HCI_OPCODE_ANT_EVENT == opcode) // ANT Event, send ANT packet to Rx Callback #endif // ANT_HCI_OPCODE_SIZE == 1 { // Received an ANT packet iCurrentHciPacketOffset = 0; while(iCurrentHciPacketOffset < iRxLenRead) { // TODO Allow HCI Packet Size value to be larger than 1 byte // This currently works as no size value is greater than 255, and little endian iHciDataSize = aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_SIZE_OFFSET]; if ((iHciDataSize + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE + iCurrentHciPacketOffset) > iRxLenRead) { // we don't have a whole packet iRxBufferLength[eChannel] = iRxLenRead - iCurrentHciPacketOffset; memcpy(aucRxBuffer[eChannel], &aucRxBuffer[eChannel][iCurrentHciPacketOffset], iRxBufferLength[eChannel]); // the increment at the end should push us out of the while loop } else #ifdef ANT_MESG_FLOW_CONTROL if (aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET] == ANT_MESG_FLOW_CONTROL) { // This is a flow control packet, not a standard ANT message if(setFlowControl(pstChnlInfo, \ aucRxBuffer[eChannel][iCurrentHciPacketOffset + ANT_HCI_DATA_OFFSET + ANT_MSG_DATA_OFFSET])) { goto out; } } else #endif // ANT_MESG_FLOW_CONTROL { 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, \ msg); } else { ANT_WARN("%s rx callback is null", pstChnlInfo->pcDevicePath); } } iCurrentHciPacketOffset = iCurrentHciPacketOffset + ANT_HCI_HEADER_SIZE + ANT_HCI_FOOTER_SIZE + iHciDataSize; } } iRet = 0; } out: ANT_FUNC_END(); return iRet; }
/* * 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 }
ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) { // During a tx we must prepend a packet type byte. Thus HCI_PACKET_TYPE_SIZE is added // to all offsets when writing into the tx buffer. ANTStatus status = ANT_STATUS_FAILED; // TODO ANT_HCI_MAX_MSG_SIZE is transport (driver) dependent. ANT_U8 txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_MAX_MSG_SIZE]; // TODO Message length can be greater than ANT_U8 can hold. // Not changed as ANT_SERIAL takes length as ANT_U8. ANT_U8 txMessageLength = HCI_PACKET_TYPE_SIZE + ucLen + ANT_HCI_HEADER_SIZE; ANT_FUNC_START(); if (ant_radio_enabled_status() != RADIO_STATUS_ENABLED) { status = ANT_STATUS_FAILED_BT_NOT_INITIALIZED; goto out; } #if ANT_HCI_OPCODE_SIZE == 1 txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_OPCODE_OFFSET] = ANT_HCI_OPCODE_TX; #elif ANT_HCI_OPCODE_SIZE > 1 #error "Specified ANT_HCI_OPCODE_SIZE not currently supported" #endif #if ANT_HCI_SIZE_SIZE == 1 txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_SIZE_OFFSET] = ucLen; #elif ANT_HCI_SIZE_SIZE == 2 ANT_UTILS_StoreLE16(txBuffer + HCI_PACKET_TYPE_SIZE + ANT_HCI_SIZE_OFFSET, (ANT_U16)ucLen); #else #error "Specified ANT_HCI_SIZE_SIZE not currently supported" #endif memcpy(txBuffer + HCI_PACKET_TYPE_SIZE + ANT_HCI_HEADER_SIZE, pucMesg, ucLen); // We no longer do the serial logging here because the packet type byte is not yet written. //ANT_SERIAL(txBuffer, txMessageLength, 'T'); // We only do this if we are using single physical and logical channels. #if defined(ANT_DEVICE_NAME) && (HCI_PACKET_TYPE_SIZE == 0) // Single transport path ANT_SERIAL(txBuffer, txMessageLength, 'T'); status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); #else // Separate data/command paths // Each path follows this structure: // write the packet type if needed. // log the packet // Send using the appropriate physical channel, waiting for flow control for data commands. switch (txBuffer[HCI_PACKET_TYPE_SIZE + ANT_HCI_DATA_OFFSET + ANT_MSG_ID_OFFSET]) { case MESG_BROADCAST_DATA_ID: case MESG_ACKNOWLEDGED_DATA_ID: case MESG_BURST_DATA_ID: case MESG_EXT_BROADCAST_DATA_ID: case MESG_EXT_ACKNOWLEDGED_DATA_ID: case MESG_EXT_BURST_DATA_ID: case MESG_ADV_BURST_DATA_ID: ANT_DEBUG_V("Data Path"); #if HCI_PACKET_TYPE_SIZE == 1 txBuffer[0] = ANT_DATA_TYPE_PACKET; #elif HCI_PACKET_TYPE_SIZE > 1 #error "Specified HCI_PACKET_TYPE_SIZE not supported" #endif ANT_SERIAL(txBuffer, txMessageLength, 'T'); #ifdef ANT_DEVICE_NAME status = ant_tx_message_flowcontrol_wait(SINGLE_CHANNEL, SINGLE_CHANNEL, txMessageLength, txBuffer); #else status = ant_tx_message_flowcontrol_wait(DATA_CHANNEL, COMMAND_CHANNEL, txMessageLength, txBuffer); #endif break; default: ANT_DEBUG_V("Control Path"); #if HCI_PACKET_TYPE_SIZE == 1 txBuffer[0] = ANT_CMD_TYPE_PACKET; #elif HCI_PACKET_TYPE_SIZE > 1 #error "Specified HCI_PACKET_TYPE_SIZE not supported" #endif ANT_SERIAL(txBuffer, txMessageLength, 'T'); #ifdef ANT_DEVICE_NAME status = ant_tx_message_flowcontrol_none(SINGLE_CHANNEL, txMessageLength, txBuffer); #else status = ant_tx_message_flowcontrol_none(COMMAND_CHANNEL, txMessageLength, txBuffer); #endif } #endif // Separate data/command paths out: ANT_FUNC_END(); return status; }
ANTStatus ant_tx_message_flowcontrol_wait(ant_channel_type eTxPath, ant_channel_type eFlowMessagePath, ANT_U8 ucMessageLength, ANT_U8 *pucTxMessage) { int iMutexResult; int iResult; struct timespec stTimeout; int iCondWaitResult; ANTStatus status = ANT_STATUS_FAILED; ANT_FUNC_START(); ANT_DEBUG_V("getting stFlowControlLock in %s", __FUNCTION__); iMutexResult = pthread_mutex_lock(&stFlowControlLock); if (iMutexResult) { ANT_ERROR("failed to lock flow control mutex during tx: %s", strerror(iMutexResult)); goto out; } ANT_DEBUG_V("got stFlowControlLock in %s", __FUNCTION__); stRxThreadInfo.astChannels[eFlowMessagePath].ucFlowControlResp = ANT_FLOW_STOP; #ifdef ANT_FLOW_RESEND // Store Tx message so can resend it from Rx thread stRxThreadInfo.astChannels[eFlowMessagePath].ucResendMessageLength = ucMessageLength; stRxThreadInfo.astChannels[eFlowMessagePath].pucResendMessage = pucTxMessage; #endif // ANT_FLOW_RESEND iResult = write(stRxThreadInfo.astChannels[eTxPath].iFd, pucTxMessage, ucMessageLength); if (iResult < 0) { ANT_ERROR("failed to write data message to device: %s", strerror(errno)); } else if (iResult != ucMessageLength) { ANT_ERROR("bytes written and message size don't match up"); } else { stTimeout.tv_sec = time(0) + ANT_FLOW_GO_WAIT_TIMEOUT_SEC; stTimeout.tv_nsec = 0; while (stRxThreadInfo.astChannels[eFlowMessagePath].ucFlowControlResp != ANT_FLOW_GO) { iCondWaitResult = pthread_cond_timedwait(&stFlowControlCond, &stFlowControlLock, &stTimeout); if (iCondWaitResult) { ANT_ERROR("failed to wait for flow control response: %s", strerror(iCondWaitResult)); if (iCondWaitResult == ETIMEDOUT) { status = ANT_STATUS_HARDWARE_ERR; #ifdef ANT_FLOW_RESEND // Clear Tx message so will stop resending it from Rx thread stRxThreadInfo.astChannels[eFlowMessagePath].ucResendMessageLength = 0; stRxThreadInfo.astChannels[eFlowMessagePath].pucResendMessage = NULL; #endif // ANT_FLOW_RESEND } goto wait_error; } } status = ANT_STATUS_SUCCESS; } wait_error: ANT_DEBUG_V("releasing stFlowControlLock in %s", __FUNCTION__); pthread_mutex_unlock(&stFlowControlLock); ANT_DEBUG_V("released stFlowControlLock in %s", __FUNCTION__); out: ANT_FUNC_END(); return status; }
ANTStatus ant_tx_message(ANT_U8 ucLen, ANT_U8 *pucMesg) { ANTStatus status; /* Socket for sending HCI commands */ int tx_socket = -1; int lockResult; ANT_FUNC_START(); ANT_DEBUG_V("getting txLock in %s", __FUNCTION__); lockResult = pthread_mutex_lock(&txLock); if (lockResult) { ANT_ERROR("ant_tx_message, could not get txLock: %s", strerror(lockResult)); return ANT_STATUS_FAILED; } ANT_DEBUG_V("got txLock in %s", __FUNCTION__); if(RADIO_STATUS_ENABLED != get_and_set_radio_status()) { ANT_DEBUG_E("ant_tx_message, ANT not enabled - ABORTING. Radio status = %d", radio_status); ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); pthread_mutex_unlock(&txLock); ANT_DEBUG_V("released txLock in %s", __FUNCTION__); return ANT_STATUS_FAILED_BT_NOT_INITIALIZED; } // Open socket tx_socket = ant_open_tx_transport(); if(tx_socket < 0) { ANT_ERROR("Could not open Tx socket"); ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); pthread_mutex_unlock(&txLock); ANT_DEBUG_V("released txLock in %s", __FUNCTION__); return ANT_STATUS_FAILED; } // Send HCI packet ANT_BOOL retryRx; ANT_BOOL retryTx; status = ANT_STATUS_FAILED; int MAX_RETRIES_WRITE_FAIL = 10; int MAX_RETRY_TIME_SECS = 10; int commandWriteFailRetries = 0; // Start New timed retry code: time_t startTime = time(NULL); time_t endTime = 0; if((time_t)-1 != startTime) { endTime = startTime + MAX_RETRY_TIME_SECS; } else { ANT_ERROR("failed to get current time"); } do // while (retryTx) { retryTx = ANT_FALSE; if(ANT_STATUS_SUCCESS == write_data(pucMesg, ucLen)) { do // while (retryRx) { retryRx = ANT_FALSE; if(ANT_TRUE == wait_for_message(tx_socket)) { ANT_DEBUG_D("New HCI data available, reading..."); status = get_command_complete_result(tx_socket); switch (status) { case ANT_STATUS_NO_VALUE_AVAILABLE: { ANT_WARN("Did not get an expected response for write, trying again"); retryRx = ANT_TRUE; break; } case ANT_STATUS_FAILED: { ANT_ERROR("Command Complete: ANT_STATUS_FAILED"); break; } case ANT_STATUS_COMMAND_WRITE_FAILED: { ANT_ERROR("Command Complete: ANT_STATUS_WRITE_FAILED"); if(++commandWriteFailRetries < MAX_RETRIES_WRITE_FAIL) { ANT_DEBUG_D("Retrying. Retry count = %d", commandWriteFailRetries); retryTx = ANT_TRUE; } else { ANT_ERROR("Aborting. Retry count = %d. Max retries = %d", commandWriteFailRetries, MAX_RETRIES_WRITE_FAIL); } break; } case ANT_STATUS_TRANSPORT_UNSPECIFIED_ERROR: { ANT_DEBUG_D("Command Complete: ANT_STATUS_UNSPECIFIED_ERROR"); // Give the chip a break before we try to resend data. nanosleep((struct timespec[]) { { 0, 50000000 } }, NULL); time_t currentTime = time(NULL); if((time_t)-1 != currentTime) { if(currentTime < endTime) { ANT_DEBUG_V("Retrying. Current time = %d. " "End time = %d", (int)currentTime, (int)endTime); retryTx = ANT_TRUE; } else { ANT_ERROR("Command Complete: ANT_STATUS_UNSPECIFIED_ERROR"); ANT_ERROR("Aborting. Current time = %d. End Time = %d", (int)currentTime, (int)endTime); } } else { ANT_ERROR("Command Complete: failed to get current time"); } break; } case ANT_STATUS_SUCCESS: { break; } default: { ANT_ERROR("Unhandled command complete status"); break; } } } else { ANT_WARN("Command Complete: wait for message failed"); } } while (retryRx);
ANTStatus ant_disable_radio(void) { int result; int lockResult; ANTStatus ret = ANT_STATUS_FAILED; ANT_FUNC_START(); ANT_DEBUG_V("getting enableLock in %s", __FUNCTION__); lockResult = pthread_mutex_lock(&enableLock); if(lockResult) { ANT_ERROR("Disable failed to get enableLock mutex: %s", strerror(lockResult)); return ANT_STATUS_FAILED; } ANT_DEBUG_V("got enableLock in %s", __FUNCTION__); ANT_DEBUG_V("getting txLock in %s", __FUNCTION__); lockResult = pthread_mutex_lock(&txLock); if (lockResult) { ANT_ERROR("Disable txLock failed: %s", strerror(lockResult)); pthread_mutex_unlock(&enableLock); return ANT_STATUS_FAILED; } ANT_DEBUG_V("got txLock in %s", __FUNCTION__); #if USE_EXTERNAL_POWER_LIBRARY if (get_and_set_radio_status() != RADIO_STATUS_DISABLED) { ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_DISABLING); radio_status = RADIO_STATUS_DISABLING; if (RxParams.pfStateCallback) RxParams.pfStateCallback(radio_status); } result = ant_disable(); ANT_DEBUG_D("ant_disable() result is %d", result); #else radio_status = RADIO_STATUS_DISABLED; #endif // If rx thread exists ( != 0) if (RxParams.thread) { ANT_DEBUG_V("quit rx thread, joining"); pthread_join(RxParams.thread, NULL); RxParams.thread = 0; ANT_DEBUG_V("joined by rx thread"); } else { ANT_DEBUG_W("rx thread is 0 (not created?)"); } switch (get_and_set_radio_status()) { case RADIO_STATUS_DISABLED: ret = ANT_STATUS_SUCCESS; break; case RADIO_STATUS_ENABLED: ANT_ERROR("SERIOUS: ANT was disabled, rx thread quit, but ANT is enabled"); ret = ANT_STATUS_FAILED; break; default: ret = ANT_STATUS_NOT_DE_INITIALIZED; break; } ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); pthread_mutex_unlock(&txLock); ANT_DEBUG_V("released txLock in %s", __FUNCTION__); ANT_DEBUG_V("releasing enableLock in %s", __FUNCTION__); pthread_mutex_unlock(&enableLock); ANT_DEBUG_V("released enableLock in %s", __FUNCTION__); ANT_FUNC_END(); return ret; }
ANTStatus ant_enable_radio(void) { int result; int lockResult; ANTStatus result_status = ANT_STATUS_FAILED; ANT_FUNC_START(); ANT_DEBUG_V("getting enableLock in %s", __FUNCTION__); lockResult = pthread_mutex_lock(&enableLock); if(lockResult) { ANT_ERROR("Enable failed to get enableLock mutex: %s", strerror(lockResult)); return ANT_STATUS_FAILED; } ANT_DEBUG_V("got enableLock in %s", __FUNCTION__); if(RADIO_STATUS_DISABLED == radio_status) { radio_status = RADIO_STATUS_ENABLING; } ANT_DEBUG_V("getting txLock in %s", __FUNCTION__); lockResult = pthread_mutex_lock(&txLock); if (lockResult) { ANT_ERROR("Enable txLock failed: %s", strerror(lockResult)); pthread_mutex_unlock(&enableLock); return ANT_STATUS_FAILED; } ANT_DEBUG_V("got txLock in %s", __FUNCTION__); if (get_and_set_radio_status() != RADIO_STATUS_ENABLED) { if (RxParams.thread) { ANT_WARN("in enable call: rx thread still exists but radio crashed. trying to recover"); ANT_DEBUG_V("radio crashed, letting rx thread join"); pthread_join(RxParams.thread, NULL); RxParams.thread = 0; ANT_DEBUG_V("recovered. joined by rx thread"); } ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_ENABLING); radio_status = RADIO_STATUS_ENABLING; #if USE_EXTERNAL_POWER_LIBRARY if (RxParams.pfStateCallback) RxParams.pfStateCallback(radio_status); #endif } #if USE_EXTERNAL_POWER_LIBRARY result = ant_enable(); ANT_DEBUG_D("ant_enable() result is %d", result); #else result = 0; #endif if (result == 0) { if (RxParams.thread) { result_status = ANT_STATUS_SUCCESS; radio_status = RADIO_STATUS_ENABLED; // sanity assign, cant be enabling ANT_DEBUG_D("ANT radio re-enabled"); } else { result = pthread_create(&RxParams.thread, NULL, ANTHCIRxThread, NULL); if (result) { ANT_ERROR("Thread initialization failed: %s", strerror(result)); result_status = ANT_STATUS_FAILED; } else { result_status = ANT_STATUS_SUCCESS; #if USE_EXTERNAL_POWER_LIBRARY if (radio_status == RADIO_STATUS_ENABLING) { ANT_DEBUG_I("radio_status (%d -> %d)", radio_status, RADIO_STATUS_ENABLED); radio_status = RADIO_STATUS_ENABLED; if (RxParams.pfStateCallback) RxParams.pfStateCallback(radio_status); } else { ANT_WARN("radio was already enabled but rx thread was not running"); } #else radio_status = RADIO_STATUS_ENABLED; #endif } } } else { result_status = ANT_STATUS_TRANSPORT_INIT_ERR; } if (result_status != ANT_STATUS_SUCCESS) // ant_enable() or rx thread creating failed { #if USE_EXTERNAL_POWER_LIBRARY ant_disable(); #endif switch (get_and_set_radio_status()) { case RADIO_STATUS_ENABLED: ANT_ERROR("SERIOUS: enable failed, but ANT is enabled without a rx thread"); break; default: ANT_DEBUG_D("Enable failed, after cleanup chip is not enabled"); break; } } ANT_DEBUG_V("releasing txLock in %s", __FUNCTION__); pthread_mutex_unlock(&txLock); ANT_DEBUG_V("released txLock in %s", __FUNCTION__); ANT_DEBUG_V("releasing enableLock in %s", __FUNCTION__); pthread_mutex_unlock(&enableLock); ANT_DEBUG_V("released enableLock in %s", __FUNCTION__); ANT_FUNC_END(); return result_status; }