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;
}
Пример #2
0
static jint nativeJAnt_GetRadioEnabledStatus(JNIEnv *env, jobject obj)
{
   (void)env; //unused warning
   (void)obj; //unused warning
   ANT_FUNC_START();

   jint status = ant_radio_enabled_status();

   ANT_FUNC_END();
   return status;
}
Пример #3
0
/*
 * 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;
}