コード例 #1
0
////////////////////////////////////////////////////////////////////
//  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;
}
コード例 #2
0
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;
}
コード例 #3
0
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();
}
コード例 #4
0
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;
}
コード例 #5
0
   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;
   }
コード例 #6
0
ファイル: ant_rx.c プロジェクト: ant-wireless/Linux_ant-hal
/*
 * 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
}
コード例 #7
0
   /**********************************************************************
    *                              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;
   }
コード例 #8
0
/*
 * 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;
}
コード例 #9
0
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;
}
コード例 #10
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
}
コード例 #11
0
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;
}
コード例 #12
0
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;
}
コード例 #13
0
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);
コード例 #14
0
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;
}
コード例 #15
0
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;
}