/* This software is subject to the license described in the License.txt file included with this software distribution. You may not use this file except in compliance with this license. Copyright (c) Dynastream Innovations Inc. 2013 All rights reserved. */ #include "types.h" #include "dsi_framer_ant.hpp" #include "dsi_serial_generic.hpp" #include "dsi_thread.h" #include "dsi_timer.hpp" #include "dsi_convert.h" #include "crc.h" #include "antfs_client_channel.hpp" #include "antfsmessage.h" #include "config.h" #include "dsi_debug.hpp" #if defined(DEBUG_FILE) #include "macros.h" #endif #include #include #include #include ////////////////////////////////////////////////////////////////////////////////// // Private Definitions ////////////////////////////////////////////////////////////////////////////////// static const UCHAR caucNetworkKey[] = NETWORK_KEY; ////////////////////////////////////////////////////////////////////////////////// // Public Functions ////////////////////////////////////////////////////////////////////////////////// ANTFSClientChannel::ANTFSClientChannel() { bInitFailed = FALSE; bTimerRunning = FALSE; bKillThread = FALSE; bANTFSThreadRunning = FALSE; pclANT = (DSIFramerANT*) NULL; pbCancel = &bCancel; *pbCancel = FALSE; // Default channel configuration ucChannelNumber = ANTFS_CHANNEL; ucNetworkNumber = ANTFS_NETWORK; usRadioChannelID = ANTFS_CLIENT_NUMBER; ucTheDeviceType = ANTFS_DEVICE_TYPE; ucTheTransmissionType = ANTFS_TRANSMISSION_TYPE; usTheMessagePeriod = ANTFS_MESSAGE_PERIOD; usBeaconChannelPeriod = ANTFS_MESSAGE_PERIOD; memcpy(aucTheNetworkkey,caucNetworkKey,8); ucLinkTxPower = RADIO_TX_POWER_LVL_3; ucSessionTxPower = RADIO_TX_POWER_LVL_3; bCustomTxPower = FALSE; // Default beacon configuration SetDefaultBeacon(); memset(aucFriendlyName, 0, sizeof(aucFriendlyName)); memset(aucPassKey, 0, sizeof(aucPassKey)); ucPassKeySize = 0; ucFriendlyNameSize = 0; memset(&stHostDisconnectParams, 0, sizeof(stHostDisconnectParams)); eANTFSState = ANTFS_CLIENT_STATE_OFF; ResetClientState(); // Debugging is initialized by DSIANTDevice (or ANTDevice in Managed Lib) // Timer pclTimer = (DSITimer*)NULL; // Threading hANTFSThread = (DSI_THREAD_ID)NULL; // Handle for the ANTFS thread if (DSIThread_MutexInit(&stMutexCriticalSection) != DSI_THREAD_ENONE) { bInitFailed = TRUE; } if (DSIThread_MutexInit(&stMutexResponseQueue) != DSI_THREAD_ENONE) { bInitFailed = TRUE; } if (DSIThread_CondInit(&stCondANTFSThreadExit) != DSI_THREAD_ENONE) { bInitFailed = TRUE; } if (DSIThread_CondInit(&stCondRequest) != DSI_THREAD_ENONE) { bInitFailed = TRUE; } if (DSIThread_CondInit(&stCondRxEvent) != DSI_THREAD_ENONE) { bInitFailed = TRUE; } if (DSIThread_CondInit(&stCondWaitForResponse) != DSI_THREAD_ENONE) { bInitFailed = TRUE; } } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::~ANTFSClientChannel() { this->Close(); if (bInitFailed == FALSE) { DSIThread_MutexDestroy(&stMutexCriticalSection); DSIThread_MutexDestroy(&stMutexResponseQueue); DSIThread_CondDestroy(&stCondANTFSThreadExit); DSIThread_CondDestroy(&stCondRequest); DSIThread_CondDestroy(&stCondRxEvent); DSIThread_CondDestroy(&stCondWaitForResponse); } } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::Init(DSIFramerANT* pclANT_, UCHAR ucChannel_) { if (bInitFailed == TRUE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Init(): bInitFailed == TRUE"); #endif return FALSE; } ucChannelNumber = ucChannel_; pclANT = pclANT_; if(pclANT) { if(pclANT->GetCancelParameter() == (BOOL*) NULL) // If cancel parameter has not been configured in framer, use internal pclANT->SetCancelParameter(pbCancel); else // Use cancel parameter configured in framer pbCancel = pclANT->GetCancelParameter(); } return ReInitDevice(); } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::Close(void) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Closing ANTFS..."); #endif DSIThread_MutexLock(&stMutexCriticalSection); // Stop the threads. bKillThread = TRUE; *pbCancel = TRUE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): SetEvent(stCondWaitForResponse)."); #endif DSIThread_MutexLock(&stMutexResponseQueue); DSIThread_CondSignal(&stCondWaitForResponse); clResponseQueue.Clear(); DSIThread_MutexUnlock(&stMutexResponseQueue); if (hANTFSThread) { if (bANTFSThreadRunning == TRUE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): SetEvent(stCondRequest)."); #endif DSIThread_CondSignal(&stCondRequest); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): SetEvent(stCondRxEvent)."); #endif DSIThread_CondSignal(&stCondRxEvent); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Killing thread."); #endif if (DSIThread_CondTimedWait(&stCondANTFSThreadExit, &stMutexCriticalSection, 9000) != DSI_THREAD_ENONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Thread not dead."); DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Forcing thread termination..."); #endif DSIThread_DestroyThread(hANTFSThread); } else { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Thread terminated successfully."); #endif } } DSIThread_ReleaseThreadID(hANTFSThread); hANTFSThread = (DSI_THREAD_ID)NULL; } DSIThread_MutexUnlock(&stMutexCriticalSection); if (bTimerRunning) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Deleting Command Timer..."); #endif delete pclTimer; pclTimer = (DSITimer*)NULL; DSIThread_MutexDestroy(&stMutexPairingTimeout); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Deleted Timer."); #endif bTimerRunning = FALSE; } eANTFSState = ANTFS_CLIENT_STATE_OFF; pclANT = (DSIFramerANT*) NULL; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Close(): Closed."); #endif if (pucTransferBufferDynamic) { delete[] pucTransferBufferDynamic; pucTransferBufferDynamic = (UCHAR*)NULL; } } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::Cancel(void) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::Cancel(): Cancel current operation..."); #endif DSIThread_MutexLock(&stMutexCriticalSection); *pbCancel = TRUE; DSIThread_CondSignal(&stCondRxEvent); DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::ProcessDeviceNotification(ANT_DEVICE_NOTIFICATION eCode_, void* pvParameter_) { DSIThread_MutexLock(&stMutexCriticalSection); if(eCode_ != ANT_DEVICE_NOTIFICATION_RESET && eCode_ != ANT_DEVICE_NOTIFICATION_SHUTDOWN) { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char *) aucString, 256, "ANTFSClientChannel::ProcessDeviceNotification(): Unknown code %0", eCode_); DSIDebug::ThreadWrite((char *) aucString); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return; } if(eANTFSState <= ANTFS_CLIENT_STATE_IDLE) { // We do not need to do anything, since ANT-FS is already in idle state DSIThread_MutexUnlock(&stMutexCriticalSection); return; } #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ProcessDeviceNotification(): Resetting state..."); #endif *pbCancel = TRUE; eANTFSRequest = ANTFS_REQUEST_INIT; DSIThread_CondSignal(&stCondRxEvent); DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::ConfigureClientParameters(ANTFS_CLIENT_PARAMS* pstInitParams_) { DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState >= ANTFS_CLIENT_STATE_BEACONING) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ConfigureClientParameters(): Incorrect state."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } if(pstInitParams_->ucAuthType == AUTH_COMMAND_PAIR && pstInitParams_->bPairingEnabled) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ConfigureClientParameters(): Pairing was selected, but it is not supported."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } stInitParams = *pstInitParams_; ucActiveBeaconStatus1 = 0; ucActiveBeaconStatus1 |= ((stInitParams.ucLinkPeriod & BEACON_PERIOD_MASK) << BEACON_PERIOD_SHIFT); ucActiveBeaconStatus1 |= stInitParams.bPairingEnabled * PAIRING_AVAILABLE_FLAG_MASK; ucActiveBeaconStatus1 |= stInitParams.bUploadEnabled * UPLOAD_ENABLED_FLAG_MASK; ucActiveBeaconStatus1 |= stInitParams.bDataAvailable * DATA_AVAILABLE_FLAG_MASK; DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SetPairingEnabled(BOOL bEnable_) { DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState == ANTFS_CLIENT_STATE_AUTHENTICATING || eANTFSState == ANTFS_CLIENT_STATE_PAIRING_WAIT_FOR_RESPONSE || (eANTFSState == ANTFS_CLIENT_STATE_CONNECTED && ucLinkCommandInProgress != ANTFS_CMD_NONE)) { // Should not change the pairing capabilities while processing an authentication request #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SetPairingEnabled(): Busy processing an authentication request."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } stInitParams.bPairingEnabled = bEnable_; if(bEnable_) ucActiveBeaconStatus1 |= PAIRING_AVAILABLE_FLAG_MASK; else ucActiveBeaconStatus1 &= ~PAIRING_AVAILABLE_FLAG_MASK; DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SetUploadEnabled(BOOL bEnable_) { DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState == ANTFS_CLIENT_STATE_UPLOADING || eANTFSState == ANTFS_CLIENT_STATE_UPLOADING_WAIT_FOR_RESPONSE || (eANTFSState == ANTFS_CLIENT_STATE_TRANSPORT && ucLinkCommandInProgress != ANTFS_CMD_NONE)) { // Should not change the upload capabilities while processing an upload #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SetUploadEnabled(): Busy processing a transport request."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } stInitParams.bUploadEnabled = bEnable_; if(bEnable_) ucActiveBeaconStatus1 |= UPLOAD_ENABLED_FLAG_MASK; else ucActiveBeaconStatus1 &= ~UPLOAD_ENABLED_FLAG_MASK; DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SetDataAvailable(BOOL bDataAvailable_) { DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState == ANTFS_CLIENT_STATE_DOWNLOADING || eANTFSState == ANTFS_CLIENT_STATE_DOWNLOADING_WAIT_FOR_DATA || (eANTFSState == ANTFS_CLIENT_STATE_TRANSPORT && ucLinkCommandInProgress != ANTFS_CMD_NONE)) { // Should not change the data available bit while processing a download #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SetDataAvailable(): Busy processing a transport request."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } stInitParams.bDataAvailable = bDataAvailable_; if(bDataAvailable_) ucActiveBeaconStatus1 |= DATA_AVAILABLE_FLAG_MASK; else ucActiveBeaconStatus1 &= ~DATA_AVAILABLE_FLAG_MASK; DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetBeaconTimeout(UCHAR ucTimeout_) { stInitParams.ucBeaconTimeout = ucTimeout_; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetPairingTimeout(UCHAR ucTimeout_) { stInitParams.ucPairingTimeout = ucTimeout_; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SetFriendlyName(UCHAR* pucFriendlyName_, UCHAR ucFriendlyNameSize_) { DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState == ANTFS_CLIENT_STATE_AUTHENTICATING) { // Should not change the friendly name while sending an authentication response #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SetFriendlyName(): Busy authenticating."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } memset(aucFriendlyName, 0, sizeof(aucFriendlyName)); if(pucFriendlyName_) { ucFriendlyNameSize = ucFriendlyNameSize_; memcpy(aucFriendlyName, pucFriendlyName_, ucFriendlyNameSize); } else { ucFriendlyNameSize = 0; } DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SetPassKey(UCHAR* pucPassKey_, UCHAR ucPassKeySize_) { DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState == ANTFS_CLIENT_STATE_CONNECTED && ucLinkCommandInProgress != ANTFS_CMD_NONE) { // Should not change the passkey while we are processing a request and comparing the keys #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SetPassKey(): Busy processing an authentication request."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } memset(aucPassKey, 0, sizeof(aucPassKey)); if(pucPassKey_) { ucPassKeySize = ucPassKeySize_; memcpy(aucPassKey, pucPassKey_, ucPassKeySize); } else { ucPassKeySize = 0; } DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetChannelID(UCHAR ucDeviceType_, UCHAR ucTransmissionType_) { ucTheDeviceType = ucDeviceType_; ucTheTransmissionType = ucTransmissionType_; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetChannelPeriod(USHORT usChannelPeriod_) { usBeaconChannelPeriod = usChannelPeriod_; // TODO: Should we also change the content of the beacon? } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetNetworkKey(UCHAR ucNetwork_, UCHAR ucNetworkkey[]) { ucNetworkNumber = ucNetwork_; memcpy(aucTheNetworkkey,ucNetworkkey,8); } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetTxPower(UCHAR ucPairingLv_, UCHAR ucConnectedLv_) { ucLinkTxPower = ucPairingLv_; ucSessionTxPower = ucConnectedLv_; bCustomTxPower = TRUE; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::OpenBeacon() { DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest != ANTFS_REQUEST_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::OpenBeacon(): Request Busy."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } if (eANTFSState != ANTFS_CLIENT_STATE_IDLE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSCient::OpenBeacon(): Not in correct state."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::OpenBeacon(): Beacon starting..."); #endif memset(&stHostDisconnectParams, 0, sizeof(stHostDisconnectParams)); // Clear old disconnect parameters ConfigureClientParameters(&stInitParams); SetANTChannelPeriod(stInitParams.ucLinkPeriod); ucActiveBeaconFrequency = stInitParams.ucBeaconFrequency; if(stInitParams.ulSerialNumber & 0x0000FFFF) { usRadioChannelID = (USHORT) (stInitParams.ulSerialNumber & 0x0000FFFF); // make sure ANT device number is not zero } eANTFSRequest = ANTFS_REQUEST_OPEN_BEACON; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::OpenBeacon(): Open beacon request pending..."); #endif return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::CloseBeacon(BOOL bReturnToBroadcast_) { ANTFS_RETURN eReturn = ANTFS_RETURN_PASS; DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest != ANTFS_REQUEST_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::CloseBeacon(): Request Busy."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } if (eANTFSState < ANTFS_CLIENT_STATE_OPENING) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::CloseBeacon(): Beacon is already closed."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::CloseBeacon(): Beacon closing..."); #endif bReturnToBroadcast = bReturnToBroadcast_; eANTFSRequest = ANTFS_REQUEST_CLOSE_BEACON; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::CloseBeacon(): Close beacon request pending..."); #endif DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return eReturn; } /////////////////////////////////////////////////////////////////////// #define MESG_CHANNEL_OFFSET 0 #define MESG_EVENT_ID_OFFSET 1 #define MESG_EVENT_CODE_OFFSET 2 void ANTFSClientChannel::ProcessMessage(ANT_MESSAGE* pstMessage_, USHORT usMesgSize_) { UCHAR ucANTChannel; BOOL bProcessed = FALSE; if(!GetEnabled()) return; // Only process ANT messages if ANT-FS is on if (usMesgSize_ < DSI_FRAMER_TIMEDOUT) //if the return isn't DSI_FRAMER_TIMEDOUT or DSI_FRAMER_ERROR { ucANTChannel = pstMessage_->aucData[MESG_CHANNEL_OFFSET] & CHANNEL_NUMBER_MASK; if(!FilterANTMessages(pstMessage_, ucANTChannel)) return; switch (pstMessage_->ucMessageID) { case MESG_RESPONSE_EVENT_ID: if (pstMessage_->aucData[MESG_EVENT_ID_OFFSET] != MESG_EVENT_ID) // this is a response { memcpy(aucResponseBuf, pstMessage_->aucData, MESG_RESPONSE_EVENT_SIZE); bProcessed = ANTProtocolEventProcess(ucANTChannel, MESG_RESPONSE_EVENT_ID); } else // this is an event { memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, pstMessage_->aucData[MESG_EVENT_CODE_OFFSET]); // pass through any events not handled here } break; case MESG_BROADCAST_DATA_ID: //Call channel event function with Broadcast message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_BROADCAST); break; case MESG_ACKNOWLEDGED_DATA_ID: //Call channel event function with Acknowledged message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_ACKNOWLEDGED); break; case MESG_BURST_DATA_ID: //Call channel event function with Burst message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_BURST_PACKET); break; case MESG_EXT_BROADCAST_DATA_ID: //Call channel event function with Broadcast message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_EXT_BROADCAST); break; case MESG_EXT_ACKNOWLEDGED_DATA_ID: //Call channel event function with Acknowledged message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_EXT_ACKNOWLEDGED); break; case MESG_EXT_BURST_DATA_ID: //Call channel event function with Burst message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_EXT_BURST_PACKET); break; case MESG_RSSI_BROADCAST_DATA_ID: //Call channel event function with Broadcast message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_RSSI_BROADCAST); break; case MESG_RSSI_ACKNOWLEDGED_DATA_ID: //Call channel event function with Acknowledged message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_RSSI_ACKNOWLEDGED); break; case MESG_RSSI_BURST_DATA_ID: //Call channel event function with Burst message code memcpy(aucRxBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTChannelEventProcess(ucANTChannel, EVENT_RX_RSSI_BURST_PACKET); break; default: memcpy(aucResponseBuf, pstMessage_->aucData, usMesgSize_); bProcessed = ANTProtocolEventProcess(ucANTChannel, pstMessage_->ucMessageID ); break; } } return; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetEnabled() { if(eANTFSState < ANTFS_CLIENT_STATE_OPENING) { return FALSE; } return TRUE; } /////////////////////////////////////////////////////////////////////// ANTFS_CLIENT_STATE ANTFSClientChannel::GetStatus(void) { return eANTFSState; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetHostName(UCHAR *aucHostFriendlyName_, UCHAR *pucBufferSize_) { if(!stHostFriendlyName.bNameSet) { *pucBufferSize_ = 0; return FALSE; } memset(aucHostFriendlyName_, 0, *pucBufferSize_); if (stHostFriendlyName.ucSize < *pucBufferSize_) { *pucBufferSize_ = stHostFriendlyName.ucSize; } memcpy(aucHostFriendlyName_, stHostFriendlyName.acFriendlyName, *pucBufferSize_); return TRUE; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetRequestParameters(ANTFS_REQUEST_PARAMS* pstRequestParams_) { DSIThread_MutexLock(&stMutexCriticalSection); if(ucLinkCommandInProgress == ANTFS_CMD_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::GetRequestParameters(): No request in progress."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return FALSE; } DSIThread_MutexUnlock(&stMutexCriticalSection); // Make a copy of the request parameters memcpy(pstRequestParams_, &stHostRequestParams, sizeof(stHostRequestParams)); return TRUE; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetRequestedFileIndex(USHORT* pusIndex_) { DSIThread_MutexLock(&stMutexCriticalSection); if(ucLinkCommandInProgress == ANTFS_CMD_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::GetRequestedFileIndex(): No request in progress."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return FALSE; } DSIThread_MutexUnlock(&stMutexCriticalSection); *pusIndex_ = stHostRequestParams.usFileIndex; return TRUE; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetDownloadStatus(ULONG *pulByteProgress_, ULONG *pulTotalLength_) { DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSState < ANTFS_CLIENT_STATE_TRANSPORT) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::GetDownloadStatus(): Incorrect state."); #endif *pulTotalLength_ = 10; // Avoid division by zero when calculating progress *pulByteProgress_ = 0; DSIThread_MutexUnlock(&stMutexCriticalSection); return FALSE; } if (ulTransferFileSize == 0) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::GetDownloadStatus(): Download not in progress."); #endif *pulTotalLength_ = 10; // Avoid division by zero when calculating progress *pulByteProgress_ = 0; DSIThread_MutexUnlock(&stMutexCriticalSection); return FALSE; } *pulTotalLength_ = ulTransferBurstIndex + ulTransferBytesRemaining; *pulByteProgress_ = ulTransferBurstIndex; // initialize with the current location within the data block if (ulDownloadProgress >= 24) { *pulByteProgress_ = *pulByteProgress_ + ulDownloadProgress - 24; // do not count the 24 bytes of the header } if (ulDownloadProgress >= ulTransferBytesRemaining + 24) { *pulByteProgress_ = *pulByteProgress_ - 8; // do not count the 8 byte footer } #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::GetDownloadStatus(): %lu/%lu", *pulByteProgress_, *pulTotalLength_); DSIDebug::ThreadWrite((char*) aucString); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return TRUE; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetUploadStatus(ULONG *pulByteProgress_, ULONG *pulTotalLength_) { // TODO: Implement GetUploadStatus return FALSE; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetTransferData(ULONG *pulDataSize_ , void *pvData_) { // TODO: Implement GetTransferData return FALSE; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::GetDisconnectParameters(ANTFS_DISCONNECT_PARAMS* pstDisconnectParams_) { // Make a copy of the requested parameters memcpy(pstDisconnectParams_, &stHostDisconnectParams, sizeof(stHostDisconnectParams)); return TRUE; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SendPairingResponse(BOOL bAccept_) { DSIThread_MutexLock(&stMutexPairingTimeout); if(bTimeoutEvent) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendPairingResponse(): Pairing request timed out."); #endif DSIThread_MutexUnlock(&stMutexPairingTimeout); return ANTFS_RETURN_FAIL; } ucPairingTimeout = MAX_UCHAR; // Disable timeout DSIThread_MutexUnlock(&stMutexPairingTimeout); DSIThread_MutexLock(&stMutexCriticalSection); if(stInitParams.bPairingEnabled != TRUE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendPairingResponse(): Pairing not supported."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } if (eANTFSRequest != ANTFS_REQUEST_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendPairingResponse(): Request Busy."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } if (eANTFSState != ANTFS_CLIENT_STATE_PAIRING_WAIT_FOR_RESPONSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendPairingResponse(): Not in correct state."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } bAcceptRequest = bAccept_; ucLinkCommandInProgress = ANTFS_AUTHENTICATE_ID; eANTFSState = ANTFS_CLIENT_STATE_AUTHENTICATING; eANTFSRequest = ANTFS_REQUEST_AUTHENTICATE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SendDownloadResponse(UCHAR ucResponse_, ANTFS_DOWNLOAD_PARAMS* pstDownloadInfo_, ULONG ulDataLength_, void *pvData_) { DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest != ANTFS_REQUEST_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendDownloadResponse(): Request Busy."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } if (eANTFSState != ANTFS_CLIENT_STATE_DOWNLOADING_WAIT_FOR_DATA) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendDownloadResponse(): Not in correct state."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } if(pstDownloadInfo_ && usTransferDataFileIndex != pstDownloadInfo_->usFileIndex) { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::SendDownloadResponse(): This is not the file requested, expected %hu and got %hu", usTransferDataFileIndex, pstDownloadInfo_->usFileIndex); DSIDebug::ThreadWrite((char*) aucString); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } ucRequestResponse = ucResponse_; if(ucRequestResponse != DOWNLOAD_RESPONSE_OK) { // Download is being rejected, there are no other parameters to check ulTransferBytesRemaining = 0; ulTransferBurstIndex = 0; ulTransferFileSize = 0; eANTFSRequest = ANTFS_REQUEST_DOWNLOAD_RESPONSE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } ulTransferFileSize = ulDataLength_; // File size of the requested download pucDownloadData = (UCHAR*)pvData_; // Data block to download usTransferCrc = 0; // Initialize to zero, as application only receives the initial request ulDownloadProgress = 0; // No data burst yet ulTransferBurstIndex = stHostRequestParams.ulOffset; // Initialize current position in burst to offset requested by host if(ulTransferBurstIndex > ulTransferFileSize) { ulTransferBurstIndex = ulTransferFileSize; } ulTransferBytesRemaining = stHostRequestParams.ulBlockSize; // Initialize number of remaining bytes to host specified maximum block size if((stHostRequestParams.ulBlockSize == 0) || (ulTransferFileSize < stHostRequestParams.ulBlockSize)) // If the host is not limiting download size or the file size does not exceed the host's download size limit { ulTransferBytesRemaining = ulTransferFileSize; // Number of bytes remaining to be downloaded in this block is the file size } if((ulTransferFileSize - ulTransferBurstIndex) < ulTransferBytesRemaining) { ulTransferBytesRemaining = ulTransferFileSize - ulTransferBurstIndex; // Calculate number of remaining bytes in this block based on the offset } ulTransferBlockSize = pstDownloadInfo_->ulMaxBlockSize; if((pstDownloadInfo_->ulMaxBlockSize != 0) && (ulTransferBytesRemaining > pstDownloadInfo_->ulMaxBlockSize)) // If the application is limiting the block size { ulTransferBytesRemaining = pstDownloadInfo_->ulMaxBlockSize; // Number of remaining bytes in this block is the application defined block size } eANTFSRequest = ANTFS_REQUEST_DOWNLOAD_RESPONSE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SendUploadResponse(UCHAR ucResponse_, ANTFS_UPLOAD_PARAMS* pstUploadInfo_, ULONG ulDataLength_, void *pvData_) { DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest != ANTFS_REQUEST_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendUploadResponse(): Request Busy."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } if (eANTFSState != ANTFS_CLIENT_STATE_UPLOADING_WAIT_FOR_RESPONSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendUploadResponse(): Not in correct state."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } if(pstUploadInfo_ && usTransferDataFileIndex != pstUploadInfo_->usFileIndex) { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::SendUploadResponse(): This is not the file requested, expected %hu and got %hu", usTransferDataFileIndex, pstUploadInfo_->usFileIndex); DSIDebug::ThreadWrite((char*) aucString); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } ucRequestResponse = ucResponse_; if(ucRequestResponse != UPLOAD_RESPONSE_OK) { // Upload is being rejected, there are no other parameters to check ulTransferBlockOffset = 0; ulTransferMaxIndex = 0; ulTransferBlockSize = 0; usTransferCrc = 0; eANTFSRequest = ANTFS_REQUEST_UPLOAD_RESPONSE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } if(stHostRequestParams.ulMaxSize > pstUploadInfo_->ulMaxSize) ucRequestResponse = UPLOAD_RESPONSE_INSUFFICIENT_SPACE; if((stHostRequestParams.ulOffset > stHostRequestParams.ulMaxSize) && (stHostRequestParams.ulOffset != MAX_ULONG)) ucRequestResponse = UPLOAD_RESPONSE_REQUEST_INVALID; ulTransferMaxIndex = pstUploadInfo_->ulMaxSize; if(pstUploadInfo_->ulMaxBlockSize) ulTransferBlockSize = pstUploadInfo_->ulMaxBlockSize; else ulTransferBlockSize = ulTransferMaxIndex; ulTransferBurstIndex = 0; ulTransferBlockOffset = 0; usTransferCrc = 0; ulTransferBytesRemaining = ulTransferMaxIndex; if(stHostRequestParams.ulOffset != MAX_ULONG) { ulTransferBytesRemaining = stHostRequestParams.ulMaxSize - stHostRequestParams.ulOffset; ulTransferBlockOffset = stHostRequestParams.ulOffset; usTransferCrc = 0; // TODO: Validate that data was provided and calculate CRC. } eANTFSRequest = ANTFS_REQUEST_UPLOAD_RESPONSE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFS_RETURN ANTFSClientChannel::SendEraseResponse(UCHAR ucResponse_) { DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest != ANTFS_REQUEST_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendEraseResponse(): Request Busy."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_BUSY; } if (eANTFSState != ANTFS_CLIENT_STATE_ERASING) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SendEraseResponse(): Not in correct state."); #endif DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_FAIL; } ucRequestResponse = ucResponse_; ucLinkCommandInProgress = ANTFS_ERASE_ID; eANTFSState = ANTFS_CLIENT_STATE_ERASING; eANTFSRequest = ANTFS_REQUEST_ERASE_RESPONSE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return ANTFS_RETURN_PASS; } /////////////////////////////////////////////////////////////////////// //Returns a response if there is one ready, otherwise waits the specified time for one to occur ANTFS_CLIENT_RESPONSE ANTFSClientChannel::WaitForResponse(ULONG ulMilliseconds_) { ANTFS_CLIENT_RESPONSE stResponse = ANTFS_CLIENT_RESPONSE_NONE; if (bKillThread == TRUE) return ANTFS_CLIENT_RESPONSE_NONE; //Wait for response DSIThread_MutexLock(&stMutexResponseQueue); if(clResponseQueue.isEmpty()) { UCHAR ucResult = DSIThread_CondTimedWait(&stCondWaitForResponse, &stMutexResponseQueue, ulMilliseconds_); switch(ucResult) { case DSI_THREAD_ENONE: stResponse = clResponseQueue.GetResponse(); break; case DSI_THREAD_ETIMEDOUT: stResponse = ANTFS_CLIENT_RESPONSE_NONE; break; case DSI_THREAD_EOTHER: #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::WaitForResponse(): CondTimedWait() Failed!"); #endif stResponse = ANTFS_CLIENT_RESPONSE_NONE; break; default: #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::WaitForResponse(): Error Unknown..."); #endif stResponse = ANTFS_CLIENT_RESPONSE_NONE; break; } } else { stResponse = clResponseQueue.GetResponse(); } DSIThread_MutexUnlock(&stMutexResponseQueue); return stResponse; } ////////////////////////////////////////////////////////////////////////////////// // Private Functions ////////////////////////////////////////////////////////////////////////////////// DSI_THREAD_RETURN ANTFSClientChannel::ANTFSThreadStart(void *pvParameter_) { #if defined(DEBUG_FILE) DSIDebug::ThreadInit("ANTFSClient"); #endif ((ANTFSClientChannel *)pvParameter_)->ANTFSThread(); return 0; } /////////////////////////////////////////////////////////////////////// // ANTFS Task Thread /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::ANTFSThread(void) { ANTFS_CLIENT_RESPONSE eResponse; bANTFSThreadRunning = TRUE; while (bKillThread == FALSE) { eResponse = ANTFS_CLIENT_RESPONSE_NONE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Awaiting Requests..."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (*pbCancel) { *pbCancel = FALSE; if (eANTFSRequest != ANTFS_REQUEST_INIT && eANTFSRequest != ANTFS_REQUEST_HANDLE_SERIAL_ERROR) { eANTFSRequest = ANTFS_REQUEST_NONE; //Clear any other request } AddResponse(ANTFS_CLIENT_RESPONSE_CANCEL_DONE); } if ((eANTFSRequest == ANTFS_REQUEST_NONE) && (bKillThread == FALSE)) { UCHAR ucResult = DSIThread_CondTimedWait(&stCondRequest, &stMutexCriticalSection, (ULONG) (stInitParams.ucBeaconTimeout * 1000)); if (ucResult != DSI_THREAD_ENONE) { #if defined(DEBUG_FILE) if(ucResult == DSI_THREAD_EOTHER) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): CondTimedWait() Failed!"); #endif // If connected to a host, and we have not received any requests, go back to link state if ((eANTFSRequest == ANTFS_REQUEST_NONE) && (stInitParams.ucBeaconTimeout != CMD_TIMEOUT_DISABLED) && (eANTFSState >= ANTFS_CLIENT_STATE_CONNECTED) && (ucLinkCommandInProgress == ANTFS_CMD_NONE)) { eANTFSRequest = ANTFS_REQUEST_CONNECTION_LOST; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): No requests received, dropping back to link"); #endif } // If we are in link state, reload the beacon // We do this in order to be able to detect serial failures while in this state if((eANTFSState == ANTFS_CLIENT_STATE_BEACONING) && (eANTFSRequest == ANTFS_REQUEST_NONE)) { if(SwitchToLink() == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Serial error while beaconing"); #endif if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; } } // If ping is disabled, go back to transport state if we were waiting for an application response // We need to do this to avoid getting stuck in busy state if the application never sends a response if((stInitParams.ucBeaconTimeout == CMD_TIMEOUT_DISABLED) && (eANTFSRequest == ANTFS_REQUEST_NONE)) { if(eANTFSState == ANTFS_CLIENT_STATE_ERASING) { ucRequestResponse = ERASE_RESPONSE_REJECT; eANTFSRequest = ANTFS_REQUEST_ERASE_RESPONSE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): No response received for the erase request, rejecting..."); #endif } else if(eANTFSState == ANTFS_CLIENT_STATE_DOWNLOADING_WAIT_FOR_DATA) { ucRequestResponse = DOWNLOAD_RESPONSE_NOT_READY; ulTransferBytesRemaining = 0; ulTransferBurstIndex = 0; ulTransferFileSize = 0; usTransferCrc = 0; eANTFSRequest = ANTFS_REQUEST_DOWNLOAD_RESPONSE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): No response received for the download request, rejecting..."); #endif } else if(eANTFSState == ANTFS_CLIENT_STATE_UPLOADING_WAIT_FOR_RESPONSE) { ucRequestResponse = UPLOAD_RESPONSE_NOT_READY; ulTransferBlockOffset = 0; ulTransferMaxIndex = 0; ulTransferBlockSize = 0; usTransferCrc = 0; eANTFSRequest = ANTFS_REQUEST_UPLOAD_RESPONSE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): No response received for the upload request, rejecting..."); #endif } } } } DSIThread_MutexUnlock(&stMutexCriticalSection); if (bKillThread) break; if (eANTFSRequest != ANTFS_REQUEST_NONE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Request received"); #endif switch (eANTFSRequest) { case ANTFS_REQUEST_INIT: { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Idle."); #endif ResetClientState(); eANTFSState = ANTFS_CLIENT_STATE_IDLE; eResponse = ANTFS_CLIENT_RESPONSE_INIT_PASS; } // ANTFS_REQUEST_INIT break; case ANTFS_REQUEST_OPEN_BEACON: { RETURN_STATUS eReturn; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Opening beacon..."); #endif eANTFSState = ANTFS_CLIENT_STATE_OPENING; eReturn = AttemptOpenBeacon(); if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Open beacon serial error."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Opening beacon failed."); #endif eANTFSState = ANTFS_CLIENT_STATE_IDLE; } else if (eReturn == RETURN_STOP) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Opening beacon stopped."); #endif AttemptCloseBeacon(); eANTFSState = ANTFS_CLIENT_STATE_IDLE; } else if (eReturn == RETURN_PASS) { SwitchToLink(); eANTFSState = ANTFS_CLIENT_STATE_BEACONING; eResponse = ANTFS_CLIENT_RESPONSE_BEACON_OPEN; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Beacon Open..."); #endif } } // ANTFS_REQUEST_OPEN_BEACON break; case ANTFS_REQUEST_CLOSE_BEACON: { RETURN_STATUS eReturn; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Closing beacon..."); #endif eReturn = AttemptCloseBeacon(); if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Close beacon serial error."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else if (eReturn == RETURN_PASS) { ResetClientState(); eANTFSState = ANTFS_CLIENT_STATE_IDLE; eResponse = ANTFS_CLIENT_RESPONSE_BEACON_CLOSED; } } // ANTFS_CLOSE_BEACON break; case ANTFS_REQUEST_CONNECT: { RETURN_STATUS eReturn; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Connecting to host device..."); #endif eReturn = SwitchToAuthenticate(); if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Serial error while connecting to host device."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Connecting to host device failed."); #endif eANTFSState = ANTFS_CLIENT_STATE_BEACONING; eANTFSRequest = ANTFS_REQUEST_NONE; } else if (eReturn == RETURN_PASS) { eANTFSRequest = ANTFS_REQUEST_NONE; eANTFSState = ANTFS_CLIENT_STATE_CONNECTED; eResponse = ANTFS_CLIENT_RESPONSE_CONNECT_PASS; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Connected to host device..."); #endif } } // ANTFS_REQUEST_CONNECT break; case ANTFS_REQUEST_DISCONNECT: { RETURN_STATUS eReturn; ANTFS_CLIENT_STATE ePrevState = eANTFSState; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Disconnecting..."); #endif eReturn = SwitchToLink(); if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Serial error while disconnecting from host device."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Disconnecting from host device failed."); #endif eANTFSState = ePrevState; // Remain in previous state eANTFSRequest = ANTFS_REQUEST_NONE; } else if (eReturn == RETURN_PASS) { if(stHostDisconnectParams.ucCommandType == DISCONNECT_COMMAND_BROADCAST) { ResetClientState(); eANTFSRequest = ANTFS_REQUEST_NONE; eANTFSState = ANTFS_CLIENT_STATE_IDLE; eResponse = ANTFS_CLIENT_RESPONSE_DISCONNECT_PASS; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): End of ANT-FS session. Return to broadcast."); #endif } else { eANTFSRequest = ANTFS_REQUEST_NONE; eANTFSState = ANTFS_CLIENT_STATE_BEACONING; eResponse = ANTFS_CLIENT_RESPONSE_DISCONNECT_PASS; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Disconnected from host device..."); #endif } } } // ANTFS_REQUEST_DISCONNECT break; case ANTFS_REQUEST_PING: { // Do nothing eANTFSRequest = ANTFS_REQUEST_NONE; } // ANTFS_REQUEST_PING break; case ANTFS_REQUEST_PAIR: { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Pairing request."); #endif DSIThread_MutexLock(&stMutexPairingTimeout); eANTFSState = ANTFS_CLIENT_STATE_PAIRING_WAIT_FOR_RESPONSE; eResponse = ANTFS_CLIENT_RESPONSE_PAIRING_REQUEST; ucPairingTimeout = stInitParams.ucPairingTimeout; // Changed from PAIRING_TIMEOUT to match the timeout at host, but this might be too short DSIThread_MutexUnlock(&stMutexPairingTimeout); } // ANTFS_REQUEST_PAIR break; case ANTFS_REQUEST_AUTHENTICATE: { RETURN_STATUS eReturn; DSIThread_MutexLock(&stMutexPairingTimeout); if(bTimeoutEvent) { bAcceptRequest = FALSE; bTimeoutEvent = FALSE; AddResponse(ANTFS_CLIENT_RESPONSE_PAIRING_TIMEOUT); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Pairing timeout."); #endif } eANTFSState = ANTFS_CLIENT_STATE_AUTHENTICATING; DSIThread_MutexUnlock(&stMutexPairingTimeout); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Authenticating..."); #endif eReturn = AttemptAuthenticateResponse(); if (eReturn == RETURN_PASS) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Authentication request accepted."); #endif SwitchToTransport(); // We passed auth, so go to transport state eResponse = ANTFS_CLIENT_RESPONSE_AUTHENTICATE_PASS; } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Authentication failed."); #endif SwitchToAuthenticate(); // Stand by ready for retry } else if (eReturn == RETURN_REJECT) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Authentication request rejected."); #endif SwitchToLink(); // We failed auth, so go to link state eResponse = ANTFS_CLIENT_RESPONSE_AUTHENTICATE_REJECT; } else if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Authentication serial error."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else if (eReturn == RETURN_STOP) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Authentication stopped."); #endif SwitchToAuthenticate(); } else //RETURN_NA { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Authentication NA."); #endif SwitchToAuthenticate(); eResponse = ANTFS_CLIENT_RESPONSE_AUTHENTICATE_NA; } } // ANTFS_REQUEST_AUTHENTICATE break; case ANTFS_REQUEST_CHANGE_LINK: { RETURN_STATUS eReturn; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Changing radio frequency and channel period..."); #endif eReturn = SwitchLinkParameters(); if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Serial error while changing radio frequency/period."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Changing radio frequency and channel period failed."); #endif eANTFSRequest = ANTFS_REQUEST_NONE; } else if (eReturn == RETURN_PASS) { eANTFSRequest = ANTFS_REQUEST_NONE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Changed radio frequency and channel period."); #endif } } // ANTFS_REQUEST_CHANGE_LINK break; case ANTFS_REQUEST_ERASE: { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::ANTFSThread(): Erase request for index: %hu.", stHostRequestParams.usFileIndex); DSIDebug::ThreadWrite((char*) aucString); #endif eANTFSState = ANTFS_CLIENT_STATE_ERASING; eResponse = ANTFS_CLIENT_RESPONSE_ERASE_REQUEST; } // ANTFS_REQUEST_ERASE break; case ANTFS_REQUEST_ERASE_RESPONSE: { RETURN_STATUS eReturn; #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::ANTFSThread(): Erasing... Response: %u.", ucRequestResponse); DSIDebug::ThreadWrite((char*)aucString); #endif eReturn = AttemptEraseResponse(); if (eReturn == RETURN_PASS) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Erase complete."); #endif SwitchToTransport(); eResponse = ANTFS_CLIENT_RESPONSE_ERASE_PASS; } else if (eReturn == RETURN_REJECT) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Erase request rejected."); #endif SwitchToTransport(); eResponse = ANTFS_CLIENT_RESPONSE_ERASE_REJECT; } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Erase fail."); #endif SwitchToTransport(); eResponse = ANTFS_CLIENT_RESPONSE_ERASE_FAIL; } else if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Erase serial error."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else { SwitchToTransport(); } } // ANTFS_REQUEST_ERASE_RESPONSE break; case ANTFS_REQUEST_DOWNLOAD: { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::ANTFSThread(): Download request for index: %d.", stHostRequestParams.usFileIndex); DSIDebug::ThreadWrite((char*) aucString); #endif usTransferDataFileIndex = stHostRequestParams.usFileIndex; eANTFSState = ANTFS_CLIENT_STATE_DOWNLOADING_WAIT_FOR_DATA; eResponse = ANTFS_CLIENT_RESPONSE_DOWNLOAD_REQUEST; } // ANTFS_REQUEST_DOWNLOAD break; case ANTFS_REQUEST_DOWNLOAD_RESPONSE: { RETURN_STATUS eReturn; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Downloading..."); #endif eANTFSState = ANTFS_CLIENT_STATE_DOWNLOADING; eReturn = AttemptDownloadResponse(); if (eReturn == RETURN_PASS) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Download completed."); #endif SwitchToTransport(); eResponse = ANTFS_CLIENT_RESPONSE_DOWNLOAD_PASS; } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Download failed."); #endif SwitchToTransport(); eResponse = ANTFS_CLIENT_RESPONSE_DOWNLOAD_FAIL; } else if (eReturn == RETURN_REJECT) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Download request rejected."); #endif SwitchToTransport(); switch(ucRequestResponse) { case DOWNLOAD_RESPONSE_DOES_NOT_EXIST: eResponse = ANTFS_CLIENT_RESPONSE_DOWNLOAD_INVALID_INDEX; break; case DOWNLOAD_RESPONSE_NOT_DOWNLOADABLE: eResponse = ANTFS_CLIENT_RESPONSE_DOWNLOAD_FILE_NOT_READABLE; break; case DOWNLOAD_RESPONSE_NOT_READY: eResponse = ANTFS_CLIENT_RESPONSE_DOWNLOAD_NOT_READY; break; case DOWNLOAD_RESPONSE_REQUEST_INVALID: default: eResponse = ANTFS_CLIENT_RESPONSE_DOWNLOAD_REJECT; break; } } else if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Download serial error."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else { SwitchToTransport(); } } // ANTFS_REQUEST_DOWNLOAD_RESPONSE break; case ANTFS_REQUEST_UPLOAD: { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::ANTFSThread(): Upload request for index: %d.", stHostRequestParams.usFileIndex); DSIDebug::ThreadWrite((char*) aucString); #endif // TODO: Implement uploads - for now, all upload requests are rejected } // ANTFS_REQUEST_UPLOAD break; case ANTFS_REQUEST_UPLOAD_RESPONSE: { RETURN_STATUS eReturn; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Uploading..."); #endif eANTFSState = ANTFS_CLIENT_STATE_UPLOADING; eReturn = AttemptUploadResponse(); if (eReturn == RETURN_PASS) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Upload completed."); #endif SwitchToTransport(); eResponse = ANTFS_CLIENT_RESPONSE_UPLOAD_PASS; } else if (eReturn == RETURN_FAIL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Upload failed."); #endif SwitchToTransport(); eResponse = ANTFS_CLIENT_RESPONSE_UPLOAD_FAIL; } else if (eReturn == RETURN_REJECT) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Upload request rejected."); #endif SwitchToTransport(); switch(ucRequestResponse) { case UPLOAD_RESPONSE_DOES_NOT_EXIST: eResponse = ANTFS_CLIENT_RESPONSE_UPLOAD_INVALID_INDEX; break; case UPLOAD_RESPONSE_NOT_WRITEABLE: eResponse = ANTFS_CLIENT_RESPONSE_UPLOAD_FILE_NOT_WRITEABLE; break; case UPLOAD_RESPONSE_INSUFFICIENT_SPACE: eResponse = ANTFS_CLIENT_RESPONSE_UPLOAD_INSUFFICIENT_SPACE; break; case UPLOAD_RESPONSE_REQUEST_INVALID: default: eResponse = ANTFS_CLIENT_RESPONSE_UPLOAD_REJECT; break; } } else if (eReturn == RETURN_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Upload serial error."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; DSIThread_MutexUnlock(&stMutexCriticalSection); } else { SwitchToTransport(); } } // ANTFS_REQUEST_UPLOAD_RESPONSE break; default: break; } //This is where to handle the internal requests, because they can happen asyncronously. //We will also clear the request here. DSIThread_MutexLock(&stMutexCriticalSection); if (eResponse != ANTFS_CLIENT_RESPONSE_NONE) AddResponse(eResponse); if (eANTFSRequest == ANTFS_REQUEST_CONNECTION_LOST) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Connection lost."); #endif eANTFSRequest = ANTFS_REQUEST_NONE; if (eANTFSState >= ANTFS_CLIENT_STATE_CONNECTED) { SwitchToLink(); AddResponse(ANTFS_CLIENT_RESPONSE_CONNECTION_LOST); } else { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Connection lost - ignored."); #endif } } else if (eANTFSRequest == ANTFS_REQUEST_HANDLE_SERIAL_ERROR) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Serial error!"); #endif HandleSerialError(); AddResponse(ANTFS_CLIENT_RESPONSE_SERIAL_FAIL); } else if (eANTFSRequest == ANTFS_REQUEST_SERIAL_ERROR_HANDLED) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Serial error handled"); #endif ResetClientState(); eANTFSState = ANTFS_CLIENT_STATE_IDLE; eANTFSRequest = ANTFS_REQUEST_INIT; } else { eANTFSRequest = ANTFS_REQUEST_NONE; //Clear any other request } DSIThread_MutexUnlock(&stMutexCriticalSection); } } #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): Exiting thread."); #endif eANTFSRequest = ANTFS_REQUEST_NONE; DSIThread_MutexLock(&stMutexCriticalSection); bANTFSThreadRunning = FALSE; DSIThread_CondSignal(&stCondANTFSThreadExit); DSIThread_MutexUnlock(&stMutexCriticalSection); #if defined(__cplusplus) return; #else ExitThread(0); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTFSThread(): C code reaching return statement unexpectedly."); #endif return; // Code should not be reached. #endif } ///////////////////////////////////////////////////////////////////// // Returns: TRUE if the message is for the ANT-FS channel BOOL ANTFSClientChannel::FilterANTMessages(ANT_MESSAGE* pstMessage_, UCHAR ucANTChannel_) { // Some messages do not include the channel number in the response, so // they might get processed incorrectly if(pstMessage_->ucMessageID == MESG_RESPONSE_EVENT_ID) { if(pstMessage_->aucData[MESG_EVENT_ID_OFFSET] == MESG_NETWORK_KEY_ID) { if(pstMessage_->aucData[MESG_CHANNEL_OFFSET] == ucNetworkNumber) return TRUE; // this is the network we are using } else if(pstMessage_->aucData[MESG_EVENT_ID_OFFSET] == MESG_RADIO_TX_POWER_ID) { return TRUE; // configured by client if per channel settings not available } } else if(pstMessage_->ucMessageID == MESG_STARTUP_MESG_ID) { return TRUE; } if(ucANTChannel_ == ucChannelNumber) return TRUE; return FALSE; } /////////////////////////////////////////////////////////////////////// // Returns: TRUE if the message has been handled by ANT-FS client, FALSE otherwise BOOL ANTFSClientChannel::ANTProtocolEventProcess(UCHAR ucChannel_, UCHAR ucMessageCode_) { if ((ucMessageCode_ == MESG_RESPONSE_EVENT_ID) && (ucChannel_ == ucChannelNumber)) { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char *) aucString, 256, "ANTFSClientChannel::ANTProtocolEventProcess(): MESG_RESPONSE_EVENT_ID - 0x%02X", aucResponseBuf[1]); DSIDebug::ThreadWrite((char *) aucString); #endif if (aucResponseBuf[1] == MESG_BURST_DATA_ID) { if (aucResponseBuf[2] != RESPONSE_NO_ERROR) { #if defined(DEBUG_FILE) UCHAR aucString1[256]; SNPRINTF((char *) aucString1, 256, "ANTFSClientChannel::ANTProtocolEventProcess(): Burst transfer error: 0x%02X.", aucResponseBuf[2]); DSIDebug::ThreadWrite((char *) aucString1); #endif bTxError = TRUE; } } } //else if (ucMessageCode_ == MESG_SERIAL_ERROR_ID) //{ // #if defined(DEBUG_FILE) // { // UCHAR aucString[256]; // SNPRINTF((char *) aucString, 256, "ANTFSClientChannel::ANTProtocolEventProcess(): Serial Error."); // DSIDebug::ThreadWrite((char *) aucString); // } // #endif // DSIThread_MutexLock(&stMutexCriticalSection); // *pbCancel = TRUE; // DSIThread_CondSignal(&stCondRxEvent); // if (eANTFSRequest < ANTFS_REQUEST_HANDLE_SERIAL_ERROR) // eANTFSRequest = ANTFS_REQUEST_HANDLE_SERIAL_ERROR; // DSIThread_CondSignal(&stCondRequest); // DSIThread_MutexUnlock(&stMutexCriticalSection); //} return TRUE; } /////////////////////////////////////////////////////////////////////// // Returns: TRUE if the message has been handled by ANT-FS client, FALSE otherwise BOOL ANTFSClientChannel::ANTChannelEventProcess(UCHAR ucChannel_, UCHAR ucMessageCode_) { // Check that we're getting a message from the correct channel. if((ucChannel_ != ucChannelNumber) || ((aucRxBuf[0] & CHANNEL_NUMBER_MASK) != ucChannelNumber)) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): Message received on wrong channel."); #endif return FALSE; // message can get passed on to the application } switch (ucMessageCode_) { case EVENT_RX_BROADCAST: break; // we're not going to process broadcasts or pass them to the application case EVENT_RX_ACKNOWLEDGED: aucRxBuf[0] |= SEQUENCE_LAST_MESSAGE; // mark it as being the last message and process as burst case EVENT_RX_BURST_PACKET: // fall thru if (!bRxError) { if ((aucRxBuf[0] & SEQUENCE_NUMBER_ROLLOVER) == 0) // Start of a burst. { // Check that this is an ANT-FS message if(aucRxBuf[ANTFS_CONNECTION_OFFSET + 1] != ANTFS_COMMAND_ID) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): Invalid ANT-FS message."); #endif bRxError = TRUE; } else { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): Burst Rx started"); #endif } ulPacketCount = 1; bReceivedCommand = FALSE; if (aucRxBuf[0] & SEQUENCE_LAST_MESSAGE) { if((aucRxBuf[ANTFS_COMMAND_OFFSET + 1] == ANTFS_DOWNLOAD_ID) || (aucRxBuf[ANTFS_COMMAND_OFFSET + 1] == ANTFS_UPLOAD_REQUEST_ID) || (aucRxBuf[ANTFS_COMMAND_OFFSET + 1] == ANTFS_UPLOAD_DATA_ID)) // These should always be longer than one packet { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): Premature end of burst transfer."); #endif bRxError = TRUE; } else { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): Reception of burst complete. (0)"); #endif bReceivedCommand = TRUE; } } #if defined(DEBUG_FILE) else { DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): Receiving burst... (0)"); } #endif } else // Other packets in the burst { if (aucRxBuf[0] & SEQUENCE_LAST_MESSAGE) { #if defined(DEBUG_FILE) char szString[256]; SNPRINTF(szString, 256, "ANTFSClientChannel::ANTChannelEventProcess(): Reception of burst complete. (%lu).", ulPacketCount); DSIDebug::ThreadWrite(szString); #endif bReceivedCommand = TRUE; } else { #if defined(DEBUG_FILE) char szString[256]; SNPRINTF(szString, 256, "ANTFSClientChannel::ANTChannelEventProcess(): Receiving burst... (%lu).", ulPacketCount); DSIDebug::ThreadWrite(szString); #endif ulPacketCount++; } } // Process burst content if(eANTFSState == ANTFS_CLIENT_STATE_BEACONING) { DecodeLinkCommand(&aucRxBuf[1]); } else if((eANTFSState >= ANTFS_CLIENT_STATE_CONNECTED) && (eANTFSState < ANTFS_CLIENT_STATE_TRANSPORT)) { DecodeAuthenticateCommand(aucRxBuf[0], &aucRxBuf[1]); } else if(eANTFSState == ANTFS_CLIENT_STATE_UPLOADING) { UploadInputData(aucRxBuf[0], &aucRxBuf[1]); } else if(eANTFSState >= ANTFS_CLIENT_STATE_TRANSPORT) { DecodeTransportCommand(aucRxBuf[0], &aucRxBuf[1]); } } // if(!bRxError) if(aucRxBuf[0] & SEQUENCE_LAST_MESSAGE) { DSIThread_MutexLock(&stMutexCriticalSection); bReceivedBurst = TRUE; bNewRxEvent = TRUE; DSIThread_CondSignal(&stCondRxEvent); DSIThread_MutexUnlock(&stMutexCriticalSection); } break; case EVENT_TRANSFER_RX_FAILED: DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSRequest != ANTFS_REQUEST_NONE) { bRxError = TRUE; // No need to signal an error, as no request is being processed } bReceivedBurst = FALSE; bReceivedCommand = FALSE; ucLinkCommandInProgress = ANTFS_CMD_NONE; // Clear command, to allow the host to retry DSIThread_CondSignal(&stCondRxEvent); DSIThread_MutexUnlock(&stMutexCriticalSection); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): EVENT_TRANSFER_RX_FAILED"); #endif break; case EVENT_TRANSFER_TX_COMPLETED: #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): EVENT_TRANSFER_TX_COMPLETED"); #endif break; case EVENT_TRANSFER_TX_FAILED: #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): EVENT_TRANSFER_TX_FAILED"); #endif bTxError = TRUE; break; case EVENT_TRANSFER_TX_START: #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): EVENT_TRANSFER_TX_START"); #endif break; case EVENT_TX: LoadBeacon(); pclANT->SendBroadcastData(ucChannelNumber, aucBeacon); #if defined(DEBUG_FILE2) UCHAR aucString[256]; SNPRINTF((char *) aucString, 256, "ANTChannelEventProcess(): Beacon [0x%02X][0x%02X][0x%02X][0x%02X][0x%02X][0x%02X][0x%02X][0x%02X]", aucBeacon[0], aucBeacon[1], aucBeacon[2], aucBeacon[3], aucBeacon[4], aucBeacon[5], aucBeacon[6], aucBeacon[7]); DSIDebug::ThreadWrite((char*) aucString); #endif break; case EVENT_CHANNEL_CLOSED: #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ANTChannelEventProcess(): EVENT_CHANNEL_CLOSED"); #endif break; default: break; } return TRUE; // message has been handled, do not pass to application } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetDefaultBeacon(void) { stInitParams.ucBeaconFrequency = ANTFS_RF_FREQ; stInitParams.ucLinkPeriod = BEACON_PERIOD_8_HZ; stInitParams.ulSerialNumber = 0; // Use the USB device serial number by default stInitParams.usBeaconDeviceType = 1; stInitParams.usBeaconDeviceManufID = 1; stInitParams.bPairingEnabled = TRUE; stInitParams.bUploadEnabled = FALSE; stInitParams.bDataAvailable = FALSE; stInitParams.ucAuthType = AUTH_COMMAND_PAIR; stInitParams.ucBeaconTimeout = (UCHAR) (COMMAND_TIMEOUT/1000); // In seconds stInitParams.ucPairingTimeout = (UCHAR) (AUTH_TIMEOUT/1000); // In seconds } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::ResetClientState(void) { // Clear all state variables, while keeping the configuration *pbCancel = FALSE; ulPacketCount = 0; bTxError = FALSE; bRxError = FALSE; bReceivedBurst = FALSE; bReceivedCommand = FALSE; bNewRxEvent = FALSE; memset(aucResponseBuf, 0, sizeof(aucResponseBuf)); memset(aucRxBuf, 0, sizeof(aucRxBuf)); ucPairingTimeout = MAX_UCHAR; bTimeoutEvent = FALSE; bReturnToBroadcast = FALSE; ulHostSerialNumber = 0; stHostFriendlyName.bNameSet = FALSE; stHostFriendlyName.ucIndex = 0; stHostFriendlyName.ucSize = 0; memset(stHostFriendlyName.acFriendlyName, 0, FRIENDLY_NAME_MAX_LENGTH); ucPassKeyIndex = 0; ucAuthCommandType = MAX_UCHAR; bAcceptRequest = FALSE; memset(&stHostRequestParams, 0, sizeof(stHostRequestParams)); ucRequestResponse = MAX_UCHAR; usTransferDataFileIndex = 0; ulTransferFileSize = 0; ulTransferBurstIndex = 0; ulTransferBytesRemaining = 0; ulTransferMaxIndex = 0; ulTransferBlockSize = 0; ulTransferBlockOffset = 0; usTransferCrc = 0; ulTransferBufferSize = 0; ulDownloadProgress = 0; pucDownloadData = (UCHAR*) NULL; if(eANTFSState == ANTFS_CLIENT_STATE_OFF) { pucTransferBufferDynamic = (UCHAR*) NULL; } else { // Deallocate dynamically allocated memory if we had an error during a transfer if (pucTransferBufferDynamic) { delete[] pucTransferBufferDynamic; pucTransferBufferDynamic = (UCHAR*)NULL; } eANTFSState = ANTFS_CLIENT_STATE_IDLE; } eANTFSRequest = ANTFS_REQUEST_NONE; ucLinkCommandInProgress = ANTFS_CMD_NONE; } /////////////////////////////////////////////////////////////////////// BOOL ANTFSClientChannel::ReInitDevice(void) { if (eANTFSState != ANTFS_CLIENT_STATE_OFF) this->Close(); bKillThread = FALSE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::ReInitDevice(): Initializing"); #endif if (hANTFSThread == NULL) { hANTFSThread = DSIThread_CreateThread(&ANTFSClientChannel::ANTFSThreadStart, this); if (hANTFSThread == NULL) return FALSE; } if (!bTimerRunning) { if (DSIThread_MutexInit(&stMutexPairingTimeout) != DSI_THREAD_ENONE) { return FALSE; } pclTimer = new DSITimer(&ANTFSClientChannel::TimerStart, this, 1000, TRUE); if (pclTimer->NoError() == FALSE) { DSIThread_MutexDestroy(&stMutexPairingTimeout); return FALSE; } bTimerRunning = TRUE; } DSIThread_MutexLock(&stMutexResponseQueue); clResponseQueue.Clear(); // Should this be done in ResetClientState instead? DSIThread_MutexUnlock(&stMutexResponseQueue); DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_INIT; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); return TRUE; } /////////////////////////////////////////////////////////////////////// // Frequency: 1 Hz /////////////////////////////////////////////////////////////////////// DSI_THREAD_RETURN ANTFSClientChannel::TimerStart(void *pvParameter_) { #if defined(DEBUG_FILE) DSIDebug::ThreadInit("ANTFSClient_Timer"); #endif ((ANTFSClientChannel *)pvParameter_)->TimerCallback(); return 0; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::TimerCallback(void) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::TimerCallback(): Entering critical section."); #endif DSIThread_MutexLock(&stMutexPairingTimeout); if(eANTFSState == ANTFS_CLIENT_STATE_PAIRING_WAIT_FOR_RESPONSE) { if((ucPairingTimeout > 0) && (ucPairingTimeout != CMD_TIMEOUT_DISABLED)) { ucPairingTimeout--; } if(ucPairingTimeout == 0) // Timeout { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("Timeout event."); ucPairingTimeout = MAX_UCHAR; bTimeoutEvent = TRUE; #endif } } DSIThread_MutexUnlock(&stMutexPairingTimeout); #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::TimerCallback(): Left critical section."); #endif DSIThread_MutexLock(&stMutexCriticalSection); if((bTimeoutEvent == TRUE) && (eANTFSState == ANTFS_CLIENT_STATE_PAIRING_WAIT_FOR_RESPONSE)) { // Reject the authentication request eANTFSRequest = ANTFS_REQUEST_AUTHENTICATE; DSIThread_CondSignal(&stCondRequest); } DSIThread_MutexUnlock(&stMutexCriticalSection); } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::HandleSerialError(void) { // We ended up here because we did not receive the expected response to a serial message // Most likely, ANT was in the wrong state, so attempt to close the channel. // No errors raised from here, as we do not know what state we are in. UCHAR ucChannelStatus = 0; if(pclANT->CloseChannel(ucChannelNumber, ANT_CLOSE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::HandleSerialError(): Failed to close channel."); #endif } if(pclANT->UnAssignChannel(ucChannelNumber, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::HandleSerialError(): Failed to unassign channel."); #endif } if(pclANT->GetChannelStatus(ucChannelNumber, &ucChannelStatus, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::HandleSerialError(): Failed ANT_GetChannelStatus()."); #endif } #if defined(DEBUG_FILE) else if ((ucChannelStatus & STATUS_CHANNEL_STATE_MASK) != STATUS_UNASSIGNED_CHANNEL) { char szString[256]; SNPRINTF(szString, 256, "ANTFSClientChannel::HandleSerialError(): Channel state... 0x%x.", ucChannelStatus); DSIDebug::ThreadWrite(szString); } #endif DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_SERIAL_ERROR_HANDLED; // Reset state machine DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::AddResponse(ANTFS_CLIENT_RESPONSE eResponse_) { DSIThread_MutexLock(&stMutexResponseQueue); clResponseQueue.AddResponse(eResponse_); DSIThread_CondSignal(&stCondWaitForResponse); DSIThread_MutexUnlock(&stMutexResponseQueue); } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::LoadBeacon(void) { UCHAR ucBeaconStatus2; // Status Byte 2 if (ucLinkCommandInProgress == ANTFS_CMD_NONE) { if(eANTFSState < ANTFS_CLIENT_STATE_CONNECTED) { ucBeaconStatus2 = REMOTE_DEVICE_STATE_LINK ; } else if(eANTFSState < ANTFS_CLIENT_STATE_TRANSPORT) { ucBeaconStatus2 = REMOTE_DEVICE_STATE_AUTH; } else { ucBeaconStatus2 = REMOTE_DEVICE_STATE_TRANS; } } else { ucBeaconStatus2 = REMOTE_DEVICE_STATE_BUSY; } aucBeacon[ANTFS_CONNECTION_OFFSET] = ANTFS_BEACON_ID; // ANT-FS Beacon ID aucBeacon[STATUS1_OFFSET] = ucActiveBeaconStatus1; // Status Byte 1 aucBeacon[STATUS2_OFFSET] = ucBeaconStatus2; // Status Byte 2 aucBeacon[AUTHENTICATION_TYPE_OFFSET] = stInitParams.ucAuthType; // Authentication Type if (eANTFSState >= ANTFS_CLIENT_STATE_CONNECTED) // AUTH & TRANS { // Host serial number Convert_ULONG_To_Bytes(ulHostSerialNumber, &aucBeacon[AUTH_HOST_SERIAL_NUMBER_OFFSET+3], &aucBeacon[AUTH_HOST_SERIAL_NUMBER_OFFSET+2], &aucBeacon[AUTH_HOST_SERIAL_NUMBER_OFFSET+1], &aucBeacon[AUTH_HOST_SERIAL_NUMBER_OFFSET]); } else { // Device descriptor Convert_USHORT_To_Bytes(stInitParams.usBeaconDeviceType, &aucBeacon[DEVICE_TYPE_OFFSET_HIGH], &aucBeacon[DEVICE_TYPE_OFFSET_LOW]); // Device type Convert_USHORT_To_Bytes(stInitParams.usBeaconDeviceManufID, &aucBeacon[MANUFACTURER_ID_OFFSET_HIGH], &aucBeacon[MANUFACTURER_ID_OFFSET_LOW]); // Manufacturer } } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::AttemptOpenBeacon(void) { UCHAR ucChannelStatus; if(eANTFSState != ANTFS_CLIENT_STATE_OPENING) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Device is not in correct state."); #endif return RETURN_FAIL; } if(pclANT->GetChannelStatus(ucChannelNumber, &ucChannelStatus, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_GetChannelStatus()."); #endif return RETURN_SERIAL_ERROR; } if ((ucChannelStatus & STATUS_CHANNEL_STATE_MASK) == STATUS_TRACKING_CHANNEL) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): ANT-FS Broadcast mode, skipping channel initialization"); #endif return RETURN_PASS; } #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Full Init Begin"); #endif if ((ucChannelStatus & STATUS_CHANNEL_STATE_MASK) == STATUS_ASSIGNED_CHANNEL) { if(pclANT->UnAssignChannel(ucChannelNumber, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_UnAssignChannel()."); #endif return RETURN_SERIAL_ERROR; } } if (pclANT->SetNetworkKey(ucNetworkNumber, (UCHAR *) aucTheNetworkkey, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_SetNetworkKey()."); #endif return RETURN_SERIAL_ERROR; } if (pclANT->AssignChannel(ucChannelNumber, 0x10, ucNetworkNumber, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_AssignChannel()."); #endif return RETURN_SERIAL_ERROR; } if (pclANT->SetChannelPeriod(ucChannelNumber, usTheMessagePeriod, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_SetChannelPeriod()."); #endif return RETURN_SERIAL_ERROR; } if (pclANT->SetChannelRFFrequency(ucChannelNumber, ucActiveBeaconFrequency, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_SetChannelRFFreq()."); #endif return RETURN_SERIAL_ERROR; } if(bCustomTxPower) { if(pclANT->SetChannelTransmitPower(ucChannelNumber, ucLinkTxPower, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_SetChannelTransmitPower(), setting power level for all channels."); #endif if(pclANT->SetAllChannelsTransmitPower(ucLinkTxPower, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_SetAllChannelsTransmitPower()."); #endif return RETURN_SERIAL_ERROR; } } } if (pclANT->SetChannelID(ucChannelNumber, usRadioChannelID, ucTheDeviceType, ucTheTransmissionType, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_SetChannelId()."); #endif return RETURN_SERIAL_ERROR; } #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Opening channel..."); #endif if (pclANT->OpenChannel(ucChannelNumber, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptOpenBeacon(): Failed ANT_OpenChannel()."); #endif return RETURN_SERIAL_ERROR; } return RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::AttemptCloseBeacon(void) { if(bReturnToBroadcast == FALSE) { if(pclANT->CloseChannel(ucChannelNumber, ANT_CLOSE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptCloseBeacon(): Failed to close beacon channel"); #endif return RETURN_SERIAL_ERROR; } } bReturnToBroadcast = FALSE; eANTFSState = ANTFS_CLIENT_STATE_IDLE; eANTFSRequest = ANTFS_REQUEST_NONE; return RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::AttemptAuthenticateResponse(void) { RETURN_STATUS eReturn = RETURN_FAIL; UCHAR aucTxAuth[8 + TX_PASSWORD_MAX_LENGTH]; // Response + auth string UCHAR ucTxPasswordLength = 0; UCHAR ucTxRetries; ANTFS_DATA stHeader = {8, aucBeacon}; ANTFS_DATA stData; ANTFS_DATA stFooter = {0, NULL}; ANTFRAMER_RETURN eTxComplete; if((eANTFSState < ANTFS_CLIENT_STATE_CONNECTED) || (eANTFSState >= ANTFS_CLIENT_STATE_TRANSPORT)) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptAuthenticateResponse(): Device is not in correct state."); #endif return RETURN_FAIL; } memset(aucTxAuth,0x00,sizeof(aucTxAuth)); LoadBeacon(); aucTxAuth[ANTFS_CONNECTION_OFFSET] = ANTFS_RESPONSE_ID; aucTxAuth[ANTFS_RESPONSE_OFFSET] = ANTFS_RESPONSE_AUTH_ID ; if(ucAuthCommandType == AUTH_COMMAND_REQ_SERIAL_NUM) { aucTxAuth[AUTH_RESPONSE_OFFSET] = AUTH_RESPONSE_NA; if(ucFriendlyNameSize != 0) { ucTxPasswordLength = ucFriendlyNameSize; memcpy(&aucTxAuth[8], aucFriendlyName, ucTxPasswordLength); } eReturn = RETURN_NA; } else if(bAcceptRequest == TRUE) { aucTxAuth[AUTH_RESPONSE_OFFSET] = AUTH_RESPONSE_ACCEPT; if((ucAuthCommandType == AUTH_COMMAND_PAIR) && (ucPassKeySize != 0)) { ucTxPasswordLength = ucPassKeySize; memcpy(&aucTxAuth[8], aucPassKey, ucTxPasswordLength); } eReturn = RETURN_PASS; } else { aucTxAuth[AUTH_RESPONSE_OFFSET] = AUTH_RESPONSE_REJECT; eReturn = RETURN_REJECT; } aucTxAuth[AUTH_FRIENDLY_NAME_LENGTH_OFFSET] = ucTxPasswordLength; Convert_ULONG_To_Bytes(stInitParams.ulSerialNumber, &aucTxAuth[AUTH_REMOTE_SERIAL_NUMBER_OFFSET + 3], &aucTxAuth[AUTH_REMOTE_SERIAL_NUMBER_OFFSET + 2], &aucTxAuth[AUTH_REMOTE_SERIAL_NUMBER_OFFSET + 1], &aucTxAuth[AUTH_REMOTE_SERIAL_NUMBER_OFFSET]); stData.ulSize = ucTxPasswordLength + 8; stData.pucData = aucTxAuth; ucTxRetries = 8; do{ eTxComplete = pclANT->SendANTFSClientTransfer(ucChannelNumber, &stHeader, &stData, &stFooter, ACKNOWLEDGED_TIMEOUT, NULL); #if defined(DEBUG_FILE) if (eTxComplete == ANTFRAMER_FAIL) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptAuthenticateResponse(): Tx error."); else if (eTxComplete == ANTFRAMER_TIMEOUT) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptAuthenticateResponse(): Tx timeout."); #endif } while (eTxComplete == ANTFRAMER_FAIL && --ucTxRetries); if (eTxComplete != ANTFRAMER_PASS) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptAuthenticateResponse(): Tx failed."); #endif return RETURN_FAIL; } return eReturn; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::AttemptEraseResponse(void) { RETURN_STATUS eReturn = RETURN_FAIL; UCHAR aucBuffer[8]; ANTFS_DATA stHeader = {8, aucBeacon}; ANTFS_DATA stData = {8, aucBuffer}; ANTFS_DATA stFooter = {0, NULL}; ANTFRAMER_RETURN eTxComplete; if((eANTFSState < ANTFS_CLIENT_STATE_TRANSPORT)) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptEraseResponse(): Device is not in correct state."); #endif return RETURN_FAIL; } LoadBeacon(); memset(aucBuffer,0x00,sizeof(aucBuffer)); aucBuffer[ANTFS_CONNECTION_OFFSET] = ANTFS_RESPONSE_ID; aucBuffer[ANTFS_RESPONSE_OFFSET] = ANTFS_RESPONSE_ERASE_ID; aucBuffer[ERASE_RESPONSE_OFFSET] = ucRequestResponse; if(ucRequestResponse == ERASE_RESPONSE_OK) { eReturn = RETURN_PASS; } else { eReturn = RETURN_REJECT; } eTxComplete = pclANT->SendANTFSClientTransfer(ucChannelNumber, &stHeader, &stData, &stFooter, ACKNOWLEDGED_TIMEOUT, NULL); if (eTxComplete != ANTFRAMER_PASS) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptEraseResponse(): Tx failed."); if (eTxComplete == ANTFRAMER_FAIL) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptEraseResponse(): Tx error."); else if (eTxComplete == ANTFRAMER_TIMEOUT) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptEraseResponse(): Tx timeout."); #endif return RETURN_FAIL; } return eReturn; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::AttemptDownloadResponse() { RETURN_STATUS eReturn = RETURN_FAIL; UCHAR aucDownloadHeader[24]; // Beacon + Response UCHAR aucDownloadFooter[8]; // CRC footer ANTFS_DATA stHeader = {24, aucDownloadHeader}; ANTFS_DATA stFooter = {8, aucDownloadFooter}; ANTFS_DATA stData; USHORT usSavedCrc = 0; ULONG ulSavedOffset = 0; ANTFRAMER_RETURN eTxComplete; UCHAR ucNoRxTicks; BOOL bDone = FALSE; BOOL bStatus = FALSE; if((eANTFSState < ANTFS_CLIENT_STATE_TRANSPORT)) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Device is not in correct state."); #endif return RETURN_FAIL; } bReceivedCommand = FALSE; bReceivedBurst = FALSE; bRxError = FALSE; do { if(ucRequestResponse == DOWNLOAD_RESPONSE_OK) { // If this is not an initial request, verify the CRC if(stHostRequestParams.bInitialRequest == FALSE && stHostRequestParams.usCRCSeed != 0) { if(ulTransferBurstIndex < ulSavedOffset) { usTransferCrc = CRC_Calc16(pucDownloadData, ulTransferBurstIndex); } else { usTransferCrc = CRC_UpdateCRC16(usSavedCrc, &pucDownloadData[ulSavedOffset], ulTransferBurstIndex - ulSavedOffset); } if(usTransferCrc != stHostRequestParams.usCRCSeed) { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::AttemptDownloadResponse(): CRC Check Failed - Expected 0x%04X, Got 0x%04X", usTransferCrc, stHostRequestParams.usCRCSeed); DSIDebug::ThreadWrite((char*) aucString); #endif ucRequestResponse = DOWNLOAD_RESPONSE_CRC_FAILED; } } else // Use seed provided by host { usTransferCrc = stHostRequestParams.usCRCSeed; } } if ((!bReceivedBurst) &&(!bReceivedCommand)) //prevents us from sending requests until the Rx bursts have stopped and been cleared. { bRxError = FALSE; // Send out the download response LoadBeacon(); memset(aucDownloadHeader, 0, sizeof(aucDownloadHeader)); memcpy(aucDownloadHeader, aucBeacon, 8); aucDownloadHeader[ANTFS_CONNECTION_OFFSET + 8] = ANTFS_RESPONSE_ID; aucDownloadHeader[ANTFS_RESPONSE_OFFSET + 8] = ANTFS_RESPONSE_DOWNLOAD_ID; aucDownloadHeader[DOWNLOAD_RESPONSE_OFFSET + 8] = ucRequestResponse; Convert_ULONG_To_Bytes(ulTransferBytesRemaining, &aucDownloadHeader[DOWNLOAD_RESPONSE_BLOCK_SIZE_OFFSET + 3 + 8], &aucDownloadHeader[DOWNLOAD_RESPONSE_BLOCK_SIZE_OFFSET + 2 + 8], &aucDownloadHeader[DOWNLOAD_RESPONSE_BLOCK_SIZE_OFFSET + 1 + 8], &aucDownloadHeader[DOWNLOAD_RESPONSE_BLOCK_SIZE_OFFSET + 8]); Convert_ULONG_To_Bytes(ulTransferBurstIndex, &aucDownloadHeader[DOWNLOAD_RESPONSE_DATA_OFFSET_OFFSET + 3 + 16], &aucDownloadHeader[DOWNLOAD_RESPONSE_DATA_OFFSET_OFFSET + 2 + 16], &aucDownloadHeader[DOWNLOAD_RESPONSE_DATA_OFFSET_OFFSET + 1 + 16], &aucDownloadHeader[DOWNLOAD_RESPONSE_DATA_OFFSET_OFFSET + 16]); Convert_ULONG_To_Bytes(ulTransferFileSize, &aucDownloadHeader[DOWNLOAD_RESPONSE_FILE_SIZE_OFFSET + 3 + 16], &aucDownloadHeader[DOWNLOAD_RESPONSE_FILE_SIZE_OFFSET + 2 + 16], &aucDownloadHeader[DOWNLOAD_RESPONSE_FILE_SIZE_OFFSET + 1 + 16], &aucDownloadHeader[DOWNLOAD_RESPONSE_FILE_SIZE_OFFSET + 16]); if(ucRequestResponse == DOWNLOAD_RESPONSE_OK) { ULONG ulDownloadTimeout; if(ulTransferBytesRemaining > 0) { usSavedCrc = usTransferCrc; ulSavedOffset = ulTransferBurstIndex; usTransferCrc = CRC_UpdateCRC16(usTransferCrc, &pucDownloadData[ulTransferBurstIndex], ulTransferBytesRemaining); } memset(aucDownloadFooter, 0, sizeof(aucDownloadFooter)); Convert_USHORT_To_Bytes(usTransferCrc, &aucDownloadFooter[DOWNLOAD_RESPONSE_CRC_OFFSET + 1], &aucDownloadFooter[DOWNLOAD_RESPONSE_CRC_OFFSET]); stData.pucData = &pucDownloadData[ulTransferBurstIndex]; stData.ulSize = ulTransferBytesRemaining; // Figure out our timeout value from the size of the transfer ulDownloadTimeout = BROADCAST_TIMEOUT + (ulTransferBytesRemaining * 2); if(ulTransferBytesRemaining > ((MAX_ULONG / BROADCAST_TIMEOUT)/2)) ulDownloadTimeout = MAX_ULONG - 1; eTxComplete = pclANT->SendANTFSClientTransfer(ucChannelNumber, &stHeader, &stFooter, &stData, ulDownloadTimeout, &ulDownloadProgress); eReturn = RETURN_PASS; } else { eTxComplete = pclANT->SendTransfer(ucChannelNumber, aucDownloadHeader, 24, ACKNOWLEDGED_TIMEOUT); eReturn = RETURN_REJECT; } if (eTxComplete == ANTFRAMER_PASS) return eReturn; // Response transmitted successfully, we are done #if defined(DEBUG_FILE) if (eTxComplete == ANTFRAMER_FAIL) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Tx error sending download response."); else if (eTxComplete == ANTFRAMER_TIMEOUT) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Tx timeout sending download response."); DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Waiting for host to attempt retry..."); #endif } // Do not need to clear bReceivedBurst here because it will be done if the transfer fails or we timeout // Now we wait for a retry from the host ucLinkCommandInProgress = ANTFS_CMD_NONE; LoadBeacon(); // Reload beacon, to let host know we are ready for retry pclANT->SendBroadcastData(ucChannelNumber, aucBeacon); ucNoRxTicks = 5; bStatus = FALSE; while (bStatus == FALSE) { //Wait for an rxEvent before starting to check the data //Since this event is fired for many circumstances we manage all the error checking below and //just use this for the wait functionality. DSIThread_MutexLock(&stMutexCriticalSection); bNewRxEvent = FALSE; if ((bNewRxEvent == FALSE) && (*pbCancel == FALSE)) { DSIThread_CondTimedWait(&stCondRxEvent, &stMutexCriticalSection, MESSAGE_TIMEOUT); } DSIThread_MutexUnlock(&stMutexCriticalSection); if (*pbCancel == TRUE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Stopped."); #endif return RETURN_STOP; } if (!bReceivedBurst) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("-->Waiting for download request..."); #endif ucNoRxTicks--; if(ucNoRxTicks == 0) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Timeout while waiting for host request retry"); #endif return RETURN_FAIL; // Timeout } } if (bReceivedCommand) //If a command has been received, process it. { bReceivedCommand = FALSE; //Clear these for any potential retries bReceivedBurst = FALSE; //Clearing these for retries // Process request if(ucLinkCommandInProgress == ANTFS_DOWNLOAD_ID) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Resuming download..."); #endif bStatus = TRUE; if(stHostRequestParams.usFileIndex != usTransferDataFileIndex) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Invalid index requested."); #endif ucRequestResponse = DOWNLOAD_RESPONSE_REQUEST_INVALID; } if(ucRequestResponse == DOWNLOAD_RESPONSE_OK) { DSIThread_MutexLock(&stMutexCriticalSection); if(stHostRequestParams.ulOffset > ulTransferFileSize) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Invalid offset requested"); #endif ucRequestResponse = DOWNLOAD_RESPONSE_REQUEST_INVALID; } else { // Adjust response parameters ulTransferBurstIndex = stHostRequestParams.ulOffset; ulTransferBytesRemaining = ulTransferFileSize - ulTransferBurstIndex; ulDownloadProgress = 0; if((stHostRequestParams.ulBlockSize != 0) && (ulTransferBytesRemaining > stHostRequestParams.ulBlockSize)) { // Host is limiting block size ulTransferBytesRemaining = stHostRequestParams.ulBlockSize; } if((ulTransferBlockSize != 0) && (ulTransferBytesRemaining > ulTransferBlockSize)) { // Client is limiting block size ulTransferBytesRemaining = ulTransferBlockSize; } } DSIThread_MutexUnlock(&stMutexCriticalSection); } // ucRequestResponse == DOWNLOAD_RESPONSE_OK } // ucLinkCommandInProgress == ANTFS_DOWNLOAD_ID } // bReceivedCommand if(bRxError) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptDownloadResponse(): Rx error"); #endif bRxError = FALSE; } } // Rx command loop } while (!bDone); return eReturn; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::AttemptUploadResponse() { RETURN_STATUS eReturn = RETURN_FAIL; UCHAR aucBuffer[24]; ANTFS_DATA stHeader = {sizeof(aucBeacon), aucBeacon}; ANTFS_DATA stData = {sizeof(aucBuffer), aucBuffer}; ANTFS_DATA stFooter = {0, NULL}; ANTFRAMER_RETURN eTxComplete; if((eANTFSState < ANTFS_CLIENT_STATE_TRANSPORT)) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptUploadResponse(): Device is not in correct state."); #endif return RETURN_FAIL; } if(ucRequestResponse == UPLOAD_RESPONSE_OK) { // TODO: Uploads not supported yet, so for now, always reject ucRequestResponse = UPLOAD_RESPONSE_REQUEST_INVALID; } ulTransferBlockOffset = 0; ulTransferMaxIndex = 0; ulTransferBlockSize = 0; usTransferCrc = 0; eReturn = RETURN_REJECT; LoadBeacon(); memset(aucBuffer, 0, sizeof(aucBuffer)); aucBuffer[ANTFS_CONNECTION_OFFSET] = ANTFS_RESPONSE_ID; aucBuffer[ANTFS_RESPONSE_OFFSET] = ANTFS_RESPONSE_UPLOAD_ID; aucBuffer[UPLOAD_RESPONSE_OFFSET] = ucRequestResponse; Convert_ULONG_To_Bytes(ulTransferBlockOffset, &aucBuffer[UPLOAD_RESPONSE_LAST_OFFSET_OFFSET + 3], &aucBuffer[UPLOAD_RESPONSE_LAST_OFFSET_OFFSET + 2], &aucBuffer[UPLOAD_RESPONSE_LAST_OFFSET_OFFSET + 1], &aucBuffer[UPLOAD_RESPONSE_LAST_OFFSET_OFFSET]); Convert_ULONG_To_Bytes(ulTransferMaxIndex, &aucBuffer[UPLOAD_RESPONSE_MAX_SIZE_OFFSET + 3], &aucBuffer[UPLOAD_RESPONSE_MAX_SIZE_OFFSET + 2], &aucBuffer[UPLOAD_RESPONSE_MAX_SIZE_OFFSET + 1], &aucBuffer[UPLOAD_RESPONSE_MAX_SIZE_OFFSET]); Convert_ULONG_To_Bytes(ulTransferBlockSize, &aucBuffer[UPLOAD_RESPONSE_BLOCK_SIZE_OFFSET + 3], &aucBuffer[UPLOAD_RESPONSE_BLOCK_SIZE_OFFSET + 2], &aucBuffer[UPLOAD_RESPONSE_BLOCK_SIZE_OFFSET + 1], &aucBuffer[UPLOAD_RESPONSE_BLOCK_SIZE_OFFSET]); Convert_USHORT_To_Bytes(usTransferCrc, &aucBuffer[UPLOAD_RESPONSE_CRC_OFFSET + 1], &aucBuffer[UPLOAD_RESPONSE_CRC_OFFSET]); eTxComplete = pclANT->SendANTFSClientTransfer(ucChannelNumber, &stHeader, &stFooter, &stData, MESSAGE_TIMEOUT, NULL); if (eTxComplete != ANTFRAMER_PASS) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptUploadResponse(): Tx failed."); if (eTxComplete == ANTFRAMER_FAIL) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptUploadResponse(): Tx error."); else if (eTxComplete == ANTFRAMER_TIMEOUT) DSIDebug::ThreadWrite("ANTFSClientChannel::AttemptUploadResponse(): Tx timeout."); #endif return RETURN_FAIL; } return eReturn; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::DecodeLinkCommand(UCHAR *pucLinkCommand_) { UCHAR ucPeriod; if(pucLinkCommand_[ANTFS_CONNECTION_OFFSET] != ANTFS_COMMAND_ID) return; switch (pucLinkCommand_[ANTFS_COMMAND_OFFSET]) { case ANTFS_CONNECT_ID: { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeLinkCommand(): Received LINK request."); #endif ucActiveBeaconFrequency = pucLinkCommand_[TRANSPORT_CHANNEL_FREQ_OFFSET]; ucPeriod= pucLinkCommand_[TRANSPORT_CHANNEL_PERIOD]; SetANTChannelPeriod(ucPeriod); ulHostSerialNumber = Convert_Bytes_To_ULONG( pucLinkCommand_[HOST_ID_OFFSET+3], pucLinkCommand_[HOST_ID_OFFSET+2], pucLinkCommand_[HOST_ID_OFFSET+1], pucLinkCommand_[HOST_ID_OFFSET]); DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_CONNECT; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); break; } // CONNECT case ANTFS_DISCONNECT_ID: { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeLinkCommand(): Received DISCONNECT request"); #endif stHostDisconnectParams.ucCommandType = pucLinkCommand_[DISCONNECT_COMMAND_TYPE_OFFSET]; stHostDisconnectParams.ucTimeDuration = pucLinkCommand_[DISCONNECT_TIME_DURATION_OFFSET]; stHostDisconnectParams.ucAppSpecificDuration = pucLinkCommand_[DISCONNECT_APP_DURATION_OFFSET]; DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_DISCONNECT; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); break; } // DISCONNECT default: { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeLinkCommand(): Invalid command."); #endif break; } } } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::DecodeAuthenticateCommand(UCHAR ucControlByte_, UCHAR *pucAuthCommand_) { if (((ucControlByte_ & ~SEQUENCE_LAST_MESSAGE) == 0) && (ucLinkCommandInProgress != ANTFS_CMD_NONE)) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Received new request, but client is busy processing something already."); #endif return; } if(pucAuthCommand_[ANTFS_CONNECTION_OFFSET] == ANTFS_COMMAND_ID) { if(pucAuthCommand_[ANTFS_COMMAND_OFFSET] == ANTFS_AUTHENTICATE_ID) { ucLinkCommandInProgress = ANTFS_AUTHENTICATE_ID; ucAuthCommandType = pucAuthCommand_[AUTH_COMMAND_TYPE_OFFSET]; } } if((ucLinkCommandInProgress == ANTFS_AUTHENTICATE_ID)) { if((ucControlByte_ & SEQUENCE_NUMBER_ROLLOVER) == 0) // first packet { ULONG ulRxHostSerialNumber = Convert_Bytes_To_ULONG( pucAuthCommand_[HOST_ID_OFFSET+3], pucAuthCommand_[HOST_ID_OFFSET+2], pucAuthCommand_[HOST_ID_OFFSET+1], pucAuthCommand_[HOST_ID_OFFSET]); bAcceptRequest = TRUE; if(ulRxHostSerialNumber != ulHostSerialNumber) // Check host serial number { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Not the expected host"); #endif bAcceptRequest = FALSE; } } switch(ucAuthCommandType) { case AUTH_COMMAND_REQ_SERIAL_NUM: { if(ucControlByte_ & SEQUENCE_LAST_MESSAGE) // wait until the burst completes { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Received AUTH serial number request."); #endif DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_AUTHENTICATE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } break; } // AUTH_COMMAND_REQ_SERIAL_NUM case AUTH_COMMAND_GOTO_TRANSPORT: { if(ucControlByte_ & SEQUENCE_LAST_MESSAGE) // wait until the burst completes { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Received AUTH pass through request."); #endif if(stInitParams.ucAuthType != AUTH_COMMAND_GOTO_TRANSPORT) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Pass through authentication not supported."); #endif bAcceptRequest = FALSE; } DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_AUTHENTICATE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } break; } // AUTH_COMMAND_GOTO_TRANSPORT case AUTH_COMMAND_PAIR: { if((ucControlByte_ & SEQUENCE_NUMBER_ROLLOVER) == 0) // first packet { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Received AUTH pairing request."); #endif stHostFriendlyName.bNameSet = FALSE; stHostFriendlyName.ucIndex = 0; stHostFriendlyName.ucSize = pucAuthCommand_[AUTH_FRIENDLY_NAME_LENGTH_OFFSET]; if(stHostFriendlyName.ucSize > FRIENDLY_NAME_MAX_LENGTH) stHostFriendlyName.ucSize = FRIENDLY_NAME_MAX_LENGTH; memset(stHostFriendlyName.acFriendlyName, 0, FRIENDLY_NAME_MAX_LENGTH); } else // read host friendly name { if(stHostFriendlyName.ucIndex < FRIENDLY_NAME_MAX_LENGTH) { UCHAR ucNumBytes = FRIENDLY_NAME_MAX_LENGTH - stHostFriendlyName.ucIndex; if(ucNumBytes > 8) { ucNumBytes = 8; } memcpy((UCHAR*) &stHostFriendlyName.acFriendlyName[stHostFriendlyName.ucIndex], pucAuthCommand_, ucNumBytes); stHostFriendlyName.ucIndex += ucNumBytes; } } if(ucControlByte_ & SEQUENCE_LAST_MESSAGE) // last packet { ENUM_ANTFS_REQUEST eTheRequest; if(stInitParams.bPairingEnabled && (stInitParams.ucAuthType <= AUTH_COMMAND_PASSKEY) && bAcceptRequest) { if(stHostFriendlyName.ucSize > 0) { stHostFriendlyName.bNameSet = TRUE; } eTheRequest = ANTFS_REQUEST_PAIR; } else { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Pairing authentication not supported."); #endif bAcceptRequest = FALSE; eTheRequest = ANTFS_REQUEST_AUTHENTICATE; } DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = eTheRequest; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } break; } // AUTH_COMMAND_PAIR case AUTH_COMMAND_PASSKEY: { if ((ucControlByte_ & SEQUENCE_NUMBER_ROLLOVER) == 0) // initial packet { UCHAR ucPasswordSize = pucAuthCommand_[AUTH_PASSWORD_LENGTH_OFFSET]; // Passkey length #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Received AUTH passkey request."); #endif if(ucPasswordSize != ucPassKeySize) { bAcceptRequest = FALSE; // Reject if lengths do not match #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Incorrect string size"); #endif } else { ucPassKeyIndex = 0; } } else { UCHAR ucCounter; for (ucCounter = 0; ucCounter < 8; ucCounter++) { if (ucPassKeyIndex >= ucPassKeySize) break; if (aucPassKey[ucPassKeyIndex++] != pucAuthCommand_[ucCounter]) { bAcceptRequest = FALSE; // Reject if passkeys are different } } } if (ucControlByte_ & SEQUENCE_LAST_MESSAGE) // last packet { if((stInitParams.ucAuthType != AUTH_COMMAND_PASSKEY) && (stInitParams.ucAuthType != AUTH_COMMAND_GOTO_TRANSPORT) && (ucPassKeySize == 0)) { bAcceptRequest = FALSE; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Passkey authentication not supported."); #endif } if (ucPassKeyIndex < ucPassKeySize) { bAcceptRequest = FALSE; // Reject if we did not get the complete passkey #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Incomplete passkey."); #endif } DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_AUTHENTICATE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } break; } // AUTH_COMMAND_PASSKEY default: { if (ucControlByte_ & SEQUENCE_LAST_MESSAGE) // last packet { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "Received unknown AUTH request: %u", ucAuthCommandType); DSIDebug::ThreadWrite((char*) aucString); #endif DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_AUTHENTICATE; bAcceptRequest = FALSE; // Reject unknown auth requests DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } break; } } } // ANTFS_AUTHENTICATE_ID else if (pucAuthCommand_[ANTFS_COMMAND_OFFSET] == ANTFS_DISCONNECT_ID) { if (ucControlByte_ & SEQUENCE_LAST_MESSAGE) // don't do anything until the burst completes { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Received DISCONNECT request"); #endif stHostDisconnectParams.ucCommandType = pucAuthCommand_[DISCONNECT_COMMAND_TYPE_OFFSET]; stHostDisconnectParams.ucTimeDuration = pucAuthCommand_[DISCONNECT_TIME_DURATION_OFFSET]; stHostDisconnectParams.ucAppSpecificDuration = pucAuthCommand_[DISCONNECT_APP_DURATION_OFFSET]; DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_DISCONNECT; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } } // ANTFS_DISCONNECT_ID else if (pucAuthCommand_[ANTFS_COMMAND_OFFSET] == ANTFS_PING_ID) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeAuthenticateCommand(): Ping!"); #endif DSIThread_MutexLock(&stMutexCriticalSection); ucLinkCommandInProgress = ANTFS_CMD_NONE; eANTFSRequest = ANTFS_REQUEST_PING; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } // ANTFS_PING_ID else { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char *) aucString, 256, "ANTFSClientChannel::DecodeAuthenticateCommand(): Received invalid request: %u", pucAuthCommand_[ANTFS_COMMAND_OFFSET]); DSIDebug::ThreadWrite((char*) aucString); #endif ucLinkCommandInProgress = ANTFS_CMD_NONE; } // OTHER REQUESTS } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::DecodeTransportCommand(UCHAR ucControlByte_, UCHAR *pucTransCommand_) { if (((ucControlByte_ & ~SEQUENCE_LAST_MESSAGE) == 0) && (ucLinkCommandInProgress != ANTFS_CMD_NONE)) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeTransportCommand(): Received new request, but client is busy."); #endif return; } if(pucTransCommand_[ANTFS_CONNECTION_OFFSET] == ANTFS_COMMAND_ID) { ucLinkCommandInProgress = pucTransCommand_[ANTFS_COMMAND_OFFSET]; } switch(ucLinkCommandInProgress) { case ANTFS_PING_ID: { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeTransportCommand(): Ping!"); #endif DSIThread_MutexLock(&stMutexCriticalSection); ucLinkCommandInProgress = ANTFS_CMD_NONE; eANTFSRequest = ANTFS_REQUEST_PING; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } // ANTFS_PING_ID break; case ANTFS_DISCONNECT_ID: { if (ucControlByte_ & SEQUENCE_LAST_MESSAGE) // don't do anything until the burst completes { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeTransportCommand(): Received DISCONNECT request"); #endif stHostDisconnectParams.ucCommandType = pucTransCommand_[DISCONNECT_COMMAND_TYPE_OFFSET]; stHostDisconnectParams.ucTimeDuration = pucTransCommand_[DISCONNECT_TIME_DURATION_OFFSET]; stHostDisconnectParams.ucAppSpecificDuration = pucTransCommand_[DISCONNECT_APP_DURATION_OFFSET]; DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_DISCONNECT; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } } // ANTFS_DISCONNECT_ID break; case ANTFS_LINK_ID: { ULONG ulRxHostSerialNumber; #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeTransportCommand(): Received LINK request."); #endif ulRxHostSerialNumber = Convert_Bytes_To_ULONG( pucTransCommand_[HOST_ID_OFFSET+3], pucTransCommand_[HOST_ID_OFFSET+2], pucTransCommand_[HOST_ID_OFFSET+1], pucTransCommand_[HOST_ID_OFFSET]); if(ulHostSerialNumber == ulRxHostSerialNumber) { UCHAR ucPeriod= pucTransCommand_[TRANSPORT_CHANNEL_PERIOD]; ucActiveBeaconFrequency = pucTransCommand_[TRANSPORT_CHANNEL_FREQ_OFFSET]; SetANTChannelPeriod(ucPeriod); DSIThread_MutexLock(&stMutexCriticalSection); eANTFSRequest = ANTFS_REQUEST_CHANGE_LINK; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } ucLinkCommandInProgress = ANTFS_CMD_NONE; } // ANTFS_LINK_ID break; case ANTFS_ERASE_ID: { if(ucControlByte_ & SEQUENCE_LAST_MESSAGE) // don't do anything unless the burst completes { ucRequestResponse = ERASE_RESPONSE_REJECT; // set initial request parameters stHostRequestParams.usFileIndex = Convert_Bytes_To_USHORT( pucTransCommand_[DATA_INDEX_OFFSET + 1], pucTransCommand_[DATA_INDEX_OFFSET]); stHostRequestParams.bInitialRequest = FALSE; stHostRequestParams.ulBlockSize = 0; stHostRequestParams.ulOffset = 0; stHostRequestParams.usCRCSeed = 0; #if defined(DEBUG_FILE) { UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::DecodeTransportCommand: Received ERASE request (%hu)", stHostRequestParams.usFileIndex); DSIDebug::ThreadWrite((char*) aucString); } #endif DSIThread_MutexLock(&stMutexCriticalSection); ucLinkCommandInProgress = ANTFS_ERASE_ID; eANTFSRequest = ANTFS_REQUEST_ERASE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } } // ANTFS_ERASE_ID break; case ANTFS_DOWNLOAD_ID: { if((ucControlByte_ & SEQUENCE_NUMBER_ROLLOVER) == 0) // first packet { stHostRequestParams.usFileIndex = Convert_Bytes_To_USHORT( pucTransCommand_[DATA_INDEX_OFFSET + 1], pucTransCommand_[DATA_INDEX_OFFSET]); stHostRequestParams.ulOffset = Convert_Bytes_To_ULONG( pucTransCommand_[DOWNLOAD_DATA_OFFSET_OFFSET + 3], pucTransCommand_[DOWNLOAD_DATA_OFFSET_OFFSET + 2], pucTransCommand_[DOWNLOAD_DATA_OFFSET_OFFSET + 1], pucTransCommand_[DOWNLOAD_DATA_OFFSET_OFFSET]); #if defined(DEBUG_FILE) { UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::DecodeTransportCommand: Received DOWNLOAD request (%hu/%lu)", stHostRequestParams.usFileIndex, stHostRequestParams.ulOffset); DSIDebug::ThreadWrite((char*) aucString); } #endif } else if (ucControlByte_ & SEQUENCE_LAST_MESSAGE) // last (second) packet { stHostRequestParams.usCRCSeed = Convert_Bytes_To_USHORT( pucTransCommand_[DOWNLOAD_DATA_CRC_OFFSET + 1], pucTransCommand_[DOWNLOAD_DATA_CRC_OFFSET]); stHostRequestParams.ulBlockSize = Convert_Bytes_To_ULONG( pucTransCommand_[DOWNLOAD_DATA_SIZE_OFFSET + 3], pucTransCommand_[DOWNLOAD_DATA_SIZE_OFFSET + 2], pucTransCommand_[DOWNLOAD_DATA_SIZE_OFFSET + 1], pucTransCommand_[DOWNLOAD_DATA_SIZE_OFFSET]); stHostRequestParams.bInitialRequest = pucTransCommand_[DOWNLOAD_DATA_INITIAL_OFFSET] & 0x01; stHostRequestParams.ulMaxSize = 0; DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState == ANTFS_CLIENT_STATE_TRANSPORT) { ucLinkCommandInProgress = ANTFS_DOWNLOAD_ID; eANTFSRequest = ANTFS_REQUEST_DOWNLOAD; DSIThread_CondSignal(&stCondRequest); } DSIThread_MutexUnlock(&stMutexCriticalSection); } } // ANTFS_DOWNLOAD_ID break; case ANTFS_UPLOAD_REQUEST_ID: { if(stInitParams.bUploadEnabled) // Only process if we support uploads { if((ucControlByte_ & SEQUENCE_NUMBER_ROLLOVER) == 0) // first packet { stHostRequestParams.bInitialRequest = FALSE; stHostRequestParams.usFileIndex = Convert_Bytes_To_USHORT( pucTransCommand_[DATA_INDEX_OFFSET + 1], pucTransCommand_[DATA_INDEX_OFFSET]); stHostRequestParams.ulMaxSize = Convert_Bytes_To_ULONG( pucTransCommand_[UPLOAD_MAX_SIZE_OFFSET + 3], pucTransCommand_[UPLOAD_MAX_SIZE_OFFSET + 2], pucTransCommand_[UPLOAD_MAX_SIZE_OFFSET + 1], pucTransCommand_[UPLOAD_MAX_SIZE_OFFSET]); } else if (ucControlByte_ & SEQUENCE_LAST_MESSAGE) // last (second) packet { stHostRequestParams.ulOffset = Convert_Bytes_To_ULONG( pucTransCommand_[DATA_OFFSET_SMALL_OFFSET + 3], pucTransCommand_[DATA_OFFSET_SMALL_OFFSET + 2], pucTransCommand_[DATA_OFFSET_SMALL_OFFSET + 1], pucTransCommand_[DATA_OFFSET_SMALL_OFFSET]); stHostRequestParams.bInitialRequest = FALSE; stHostRequestParams.ulBlockSize = 0; stHostRequestParams.usCRCSeed = 0; #if defined(DEBUG_FILE) { UCHAR aucString[256]; SNPRINTF((char*) aucString, 256, "ANTFSClientChannel::DecodeTransportCommand: Received UPLOAD request (%hu/%lu)", stHostRequestParams.usFileIndex, stHostRequestParams.ulOffset); DSIDebug::ThreadWrite((char*) aucString); } #endif DSIThread_MutexLock(&stMutexCriticalSection); if(eANTFSState == ANTFS_CLIENT_STATE_TRANSPORT) { stHostRequestParams.bInitialRequest = TRUE; ucLinkCommandInProgress = ANTFS_UPLOAD_REQUEST_ID; //eANTFSRequest = ANTFS_REQUEST_UPLOAD; // TODO: Uploads not implemented, should send upload request to application // Reject the request, for now ucRequestResponse = UPLOAD_RESPONSE_REQUEST_INVALID; eANTFSRequest = ANTFS_REQUEST_UPLOAD_RESPONSE; DSIThread_CondSignal(&stCondRequest); } DSIThread_MutexUnlock(&stMutexCriticalSection); } } else { if (ucControlByte_ & SEQUENCE_LAST_MESSAGE) { // Reject if uploads are not supported DSIThread_MutexLock(&stMutexCriticalSection); ucRequestResponse = UPLOAD_RESPONSE_REQUEST_INVALID; eANTFSRequest = ANTFS_REQUEST_UPLOAD_RESPONSE; DSIThread_CondSignal(&stCondRequest); DSIThread_MutexUnlock(&stMutexCriticalSection); } } } // ANTFS_UPLOAD_ID break; case ANTFS_UPLOAD_DATA_ID: { if(stInitParams.bUploadEnabled && eANTFSState == ANTFS_CLIENT_STATE_UPLOADING_WAIT_FOR_RESPONSE) // Only process if we support uploads { if((ucControlByte_ & SEQUENCE_NUMBER_ROLLOVER) == 0) // first packet { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeTransportCommand(): Received UPLOAD DATA."); #endif stHostRequestParams.usCRCSeed = Convert_Bytes_To_USHORT( pucTransCommand_[UPLOAD_DATA_CRC_SEED_OFFSET + 1], pucTransCommand_[UPLOAD_DATA_CRC_SEED_OFFSET]); stHostRequestParams.ulOffset = Convert_Bytes_To_ULONG( pucTransCommand_[UPLOAD_DATA_DATA_OFFSET_OFFSET + 3], pucTransCommand_[UPLOAD_DATA_DATA_OFFSET_OFFSET + 2], pucTransCommand_[UPLOAD_DATA_DATA_OFFSET_OFFSET + 1], pucTransCommand_[UPLOAD_DATA_DATA_OFFSET_OFFSET]); } if(ucControlByte_ & SEQUENCE_LAST_MESSAGE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::DecodeTransportCommand(): Upload contains no data."); #endif } } } // ANTFS_UPLOAD_DATA_ID: break; default: { #if defined(DEBUG_FILE) UCHAR aucString[256]; SNPRINTF((char *) aucString, 256, "ANTFSClientChannel::DecodeTransportCommand(): Received invalid request: %u", ucLinkCommandInProgress); DSIDebug::ThreadWrite((char*) aucString); #endif ucLinkCommandInProgress = ANTFS_CMD_NONE; } // DEFAULT break; } } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::UploadInputData(UCHAR ucControlByte_, UCHAR* pucMesg_) { // TODO: Implement upload } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::SwitchToLink(void) { if(eANTFSState < ANTFS_CLIENT_STATE_IDLE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToLink(): Device is not in correct state."); #endif return RETURN_FAIL; } if(eANTFSState > ANTFS_CLIENT_STATE_IDLE) { // Reload beacon link configuration ucActiveBeaconStatus1 = 0; ucActiveBeaconStatus1 |= ((stInitParams.ucLinkPeriod & BEACON_PERIOD_MASK) << BEACON_PERIOD_SHIFT); ucActiveBeaconStatus1 |= stInitParams.bPairingEnabled * PAIRING_AVAILABLE_FLAG_MASK; ucActiveBeaconStatus1 |= stInitParams.bUploadEnabled * UPLOAD_ENABLED_FLAG_MASK; ucActiveBeaconStatus1 |= stInitParams.bDataAvailable * DATA_AVAILABLE_FLAG_MASK; ucActiveBeaconFrequency = stInitParams.ucBeaconFrequency; if(pclANT->SetChannelRFFrequency(ucChannelNumber, ucActiveBeaconFrequency, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToLink(): Failed ANT_SetChannelRFFreq()."); #endif return RETURN_SERIAL_ERROR; } SetANTChannelPeriod(stInitParams.ucLinkPeriod); if (pclANT->SetChannelPeriod(ucChannelNumber, usTheMessagePeriod, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToLink(): Failed ANT_SetChannelPeriod()."); #endif return RETURN_SERIAL_ERROR; } if(bCustomTxPower) { if(pclANT->SetChannelTransmitPower(ucChannelNumber, ucLinkTxPower, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToLink(): Failed ANT_SetChannelTransmitPower(), setting power level for all channels."); #endif if(pclANT->SetAllChannelsTransmitPower(ucLinkTxPower, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToLink(): Failed ANT_SetAllChannelsTransmitPower()."); #endif return RETURN_SERIAL_ERROR; } } } if(bReturnToBroadcast) // No need to reload beacon if going back to broadcast { ucLinkCommandInProgress = ANTFS_CMD_NONE; return RETURN_PASS; } } eANTFSState = ANTFS_CLIENT_STATE_BEACONING; ucLinkCommandInProgress = ANTFS_CMD_NONE; bReceivedCommand = FALSE; bReceivedBurst = FALSE; bRxError = FALSE; LoadBeacon(); if(pclANT->SendBroadcastData(ucChannelNumber, aucBeacon) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToLink(): Failed to load beacon."); #endif return RETURN_SERIAL_ERROR; } return RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::SwitchToAuthenticate(void) { if(eANTFSState < ANTFS_CLIENT_STATE_BEACONING) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToAuthenticate(): Device is not in correct state."); #endif return RETURN_FAIL; } if(eANTFSState < ANTFS_CLIENT_STATE_CONNECTED) { if(pclANT->SetChannelRFFrequency(ucChannelNumber, ucActiveBeaconFrequency, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToAuthenticate(): Failed ANT_SetChannelRFFreq()."); #endif return RETURN_SERIAL_ERROR; } if (pclANT->SetChannelPeriod(ucChannelNumber, usTheMessagePeriod, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToAuthenticate(): Failed ANT_SetChannelPeriod()."); #endif return RETURN_SERIAL_ERROR; } if(bCustomTxPower) { if(pclANT->SetChannelTransmitPower(ucChannelNumber, ucSessionTxPower, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToAuthenticate(): Failed ANT_SetChannelTransmittPower(), setting power level for all channels."); #endif if(pclANT->SetAllChannelsTransmitPower(ucSessionTxPower, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToAuthenticate(): Failed ANT_SetAllChannelsTransmittPower()."); #endif return RETURN_SERIAL_ERROR; } } } } ucPairingTimeout = MAX_UCHAR; eANTFSState = ANTFS_CLIENT_STATE_CONNECTED; ucLinkCommandInProgress = ANTFS_CMD_NONE; bReceivedCommand = FALSE; bReceivedBurst = FALSE; bRxError = FALSE; LoadBeacon(); if(pclANT->SendBroadcastData(ucChannelNumber, aucBeacon) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToAuthenticate(): Failed to load beacon."); #endif return RETURN_SERIAL_ERROR; } return RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::SwitchToTransport(void) { if(eANTFSState < ANTFS_CLIENT_STATE_CONNECTED) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToTransport(): Device is not in correct state."); #endif return RETURN_FAIL; } eANTFSState = ANTFS_CLIENT_STATE_TRANSPORT; ucLinkCommandInProgress = ANTFS_CMD_NONE; bReceivedCommand = FALSE; bReceivedBurst = FALSE; bRxError = FALSE; LoadBeacon(); if(pclANT->SendBroadcastData(ucChannelNumber, aucBeacon) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchToTransport(): Failed to load beacon."); #endif return RETURN_SERIAL_ERROR; } return RETURN_PASS; } /////////////////////////////////////////////////////////////////////// ANTFSClientChannel::RETURN_STATUS ANTFSClientChannel::SwitchLinkParameters(void) { if(eANTFSState < ANTFS_CLIENT_STATE_TRANSPORT) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchLinkParameters(): Device is not in correct state."); #endif return RETURN_FAIL; } if(pclANT->SetChannelRFFrequency(ucChannelNumber, ucActiveBeaconFrequency, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchLinkParameters(): Failed ANT_SetChannelRFFreq()."); #endif return RETURN_SERIAL_ERROR; } if (pclANT->SetChannelPeriod(ucChannelNumber, usTheMessagePeriod, MESSAGE_TIMEOUT) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchLinkParameters(): Failed ANT_SetChannelPeriod()."); #endif return RETURN_SERIAL_ERROR; } ucLinkCommandInProgress = ANTFS_CMD_NONE; LoadBeacon(); if(pclANT->SendBroadcastData(ucChannelNumber, aucBeacon) == FALSE) { #if defined(DEBUG_FILE) DSIDebug::ThreadWrite("ANTFSClientChannel::SwitchLinkParameters(): Failed to load beacon."); #endif return RETURN_SERIAL_ERROR; } return RETURN_PASS; } /////////////////////////////////////////////////////////////////////// void ANTFSClientChannel::SetANTChannelPeriod(UCHAR ucLinkPeriod_) { switch (ucLinkPeriod_) { default: // Shouldn't happen. case BEACON_PERIOD_0_5_HZ: usTheMessagePeriod = 65535; break; case BEACON_PERIOD_1_HZ: usTheMessagePeriod = 32768; break; case BEACON_PERIOD_2_HZ: usTheMessagePeriod = 16384; break; case BEACON_PERIOD_4_HZ: usTheMessagePeriod = 8192; break; case BEACON_PERIOD_8_HZ: usTheMessagePeriod = 4096; break; case BEACON_PERIOD_KEEP: usTheMessagePeriod = usBeaconChannelPeriod; break; } ucActiveBeaconStatus1 &= ~BEACON_PERIOD_MASK; ucActiveBeaconStatus1 |= ((ucLinkPeriod_ & BEACON_PERIOD_MASK) << BEACON_PERIOD_SHIFT); }