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 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 }
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; }