private void responsePollFunc() { ushort messageSize = 0; byte channelNum; bool isMsgForChannel; pollingOn = true; //Set to false on shutdown to terminate the thread #if (ANTFS_DEBUGGING) ANT_Common.initDebugLogThread("Device" + USBDeviceNum + "_ANTReceive"); // We still need this for ANT-FS! Will not be created if debug disabled #endif while (initializedUSB && pollingOn) //check continuously; this thread is terminated on destruction of the class { // We only wait in the unmanged code for 100 ms because we want this thread to be responsive on our side. // It does mean that we are running through a lot more cycles than we need to messageSize = ANT_WaitForMessage(unmanagedANTFramerPtr, 100); if (messageSize == (ushort)0xFFFE) //DSI_FRAMER_TIMEDOUT continue; //Expected, just keep looping ANTMessage newMessage = new ANTMessage(); messageSize = ANT_GetMessage(unmanagedANTFramerPtr, ref newMessage); if (messageSize == (ushort)0xFFFF) // DSI_FRAMER_ERROR - in current library could be from CRC error, Write error, Read error, or DeviceGone { serialErrorCode error; bool isCritical = false; switch(newMessage.msgID) { case 0x02: //DSI_FRAMER_ANT_ESERIAL switch(newMessage.ucharBuf[0]) { case 0x04: //ESERIAL -> DSI_FRAMER_ANT_CRC_ERROR error = serialErrorCode.MessageLost_CrcError; break; case 0x02: //ESERIAL -> DSI_SERIAL_EWRITE error = serialErrorCode.SerialWriteError; break; case 0x03: //ESERIAL -> DSI_SERIAL_EREAD error = serialErrorCode.SerialReadError; isCritical = true; break; case 0x01: //ESERIAL -> DSI_SERIAL_DEVICE_GONE error = serialErrorCode.DeviceConnectionLost; isCritical = true; break; default: error = serialErrorCode.Unknown; System.Diagnostics.Debug.Fail("Unknown serial failure, why isn't this known?"); break; } break; case 0x01: //DSI_FRAMER_ANT_EQUEUE_OVERFLOW error = serialErrorCode.MessageLost_QueueOverflow; break; case 0x03: //DSI_FRAMER_ANT_EINVALID_SIZE error = serialErrorCode.MessageLost_TooLarge; break; default: error = serialErrorCode.Unknown; System.Diagnostics.Debug.Fail("Unknown serial failure, why isn't this known?"); break; } if(isCritical) { //System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(x => shutdown())); //Clean up all resources on another thread to allow this one to close cleanly pollingOn = false; //Just stop polling, since we will never get new messages now. Allow the user to dispose of the device. } //If application has subscribed to the event we can inform them if (serialError != null) serialError(this, error, isCritical); else //Debug.Fail is a no-op in release mode, so we will only see this in debugging, in release mode we don't want to do anything intrusive (ie:message box, exception) System.Diagnostics.Debug.Fail("Device Serial Communication Failure, HandleSerialError not handled by application"); if (isCritical) break; //If the device is dead, exit the polling loop else continue; } isMsgForChannel = false; channelNum = Byte.MaxValue; switch (newMessage.msgID) //Check if we send to channel or protocol response func { // Send on Channel event case (byte)ANT_ReferenceLibrary.ANTMessageID.RESPONSE_EVENT_0x40: if (newMessage.ucharBuf[1] == (byte)ANT_ReferenceLibrary.ANTMessageID.EVENT_0x01) isMsgForChannel = true; break; // or any of the transmission events case (byte)ANT_ReferenceLibrary.ANTMessageID.BROADCAST_DATA_0x4E: case (byte)ANT_ReferenceLibrary.ANTMessageID.ACKNOWLEDGED_DATA_0x4F: case (byte)ANT_ReferenceLibrary.ANTMessageID.EXT_BROADCAST_DATA_0x5D: case (byte)ANT_ReferenceLibrary.ANTMessageID.EXT_ACKNOWLEDGED_DATA_0x5E: case (byte)ANT_ReferenceLibrary.ANTMessageID.BURST_DATA_0x50: case (byte)ANT_ReferenceLibrary.ANTMessageID.EXT_BURST_DATA_0x5F: #if (!REFERENCE_DESIGN) case (byte)ANT_ReferenceLibrary.ANTMessageID.ADV_BURST_DATA_0x72: #endif case (byte)ANT_ReferenceLibrary.ANTMessageID.RSSI_BROADCAST_DATA_0xC1: case (byte)ANT_ReferenceLibrary.ANTMessageID.RSSI_ACKNOWLEDGED_DATA_0xC2: case (byte)ANT_ReferenceLibrary.ANTMessageID.RSSI_BURST_DATA_0xC3: isMsgForChannel = true; break; } ANT_Response newResponse; //Now dispatch to appropriate event //The messages are buffered in the ant library so we just dispatch with current thread //then no matter how long the event call takes we still won't miss messages if (isMsgForChannel) { channelNum = (byte)(newMessage.ucharBuf[0] & 0x1F); //Mask out what channel this is for. [We can eventually switch to use the c++ code to determine the channel, but we should do it all together with getMessage to avoid extra marshalling and copying and remove the processing in C# above] if (antChannels != null && channelNum < antChannels.Length) { if (antChannels[channelNum] != null) antChannels[channelNum].MessageReceived(newMessage, messageSize); } else { if (serialError != null) serialError(this, serialErrorCode.MessageLost_InvalidChannel, false); } } else { newResponse = new ANT_Response(this, newMessage.ucharBuf[0], DateTime.Now, newMessage.msgID, newMessage.ucharBuf.Take(messageSize).ToArray()); if (deviceResponse != null) //Ensure events are assigned before we call the event deviceResponse(newResponse); } } }
private static extern int ANT_WriteMessage(IntPtr FramerPtr, ANTMessage pstANTMessage, UInt16 usMessageSize);
private static extern byte ANT_GetChannelNumber(IntPtr FramerPtr, ref ANTMessage pstANTMessage);
private static extern UInt16 ANT_GetMessage(IntPtr FramerPtr, ref ANTMessage ANT_MESSAGE_response);
/// <summary> /// Writes a message to the device, this function allows sending manually formatted messages. /// </summary> /// <param name="msgID">msgID to write</param> /// <param name="msgData">data buffer to write</param> /// <returns>False if writing bytes to device fails</returns> public bool writeRawMessageToDevice(byte msgID, byte[] msgData) { if (!initializedUSB) throw new ObjectDisposedException("ANTDevice object has been disposed"); //Create ANT_MESSAGE ANTMessage aMsg = new ANTMessage(); aMsg.msgID = msgID; //We create an array of max size, because the struct sizing expects a constant size array int padNum = ANT_ReferenceLibrary.MAX_MESG_SIZE - msgData.Length; if(padNum < 0) throw new ANT_Exception("msgData max length is " + ANT_ReferenceLibrary.MAX_MESG_SIZE + " bytes"); aMsg.ucharBuf = msgData.Concat(new byte[padNum]).ToArray(); return ANT_WriteMessage(unmanagedANTFramerPtr, aMsg, (UInt16)msgData.Length) == 1; }