private int readRawData(byte[] rawData) { // unpack the packet header manually before attempting to load into a struct uint packetNumber = BitConverter.ToUInt32(rawData, 0); uint categoryPacketNumber = BitConverter.ToUInt32(rawData, 4); int partialPacketIndexBytes = rawData[8]; int partialPacketNumber = rawData[9]; EUDPStreamerPacketHandlerType packetType = (EUDPStreamerPacketHandlerType)rawData[10]; int packetVersion = rawData[11]; int frameLength = 0; switch (packetType) { case EUDPStreamerPacketHandlerType.eCarPhysics: telemPacketCount++; if (telemPacketCount > packetCountAtStartOfNextRateCheck) { lastPacketRateEstimate = (int)((float)TimeSpan.TicksPerSecond * (float)(telemPacketCount - packetCountAtStartOfCurrentRateCheck) / (float)(DateTime.UtcNow.Ticks - ticksAtStartOfCurrentPacketRateCheck)); Console.WriteLine("Packet rate = " + lastPacketRateEstimate + "Hz, totals:" + "\rtelem = " + telemPacketCount + "\rraceDefinition = " + raceDefinitionPacketCount + "\rparticipants = " + participantsPacketCount + "\rtimings = " + timingsPacketCount + "\rgameState = " + gameStatePacketCount + "\rweather = " + weatherStatePacketCount + "\rvehicleNames = " + vehicleNamesPacketCount + "\rtimeStats = " + timeStatsPacketCount + "\rparticipantVehicleNames = " + participantVehicleNamesPacketCount + "\rin sequence = " + inSequenceTelemCount + " oos accepted = " + acceptedOutOfSequenceTelemCount + " oos rejected = " + discardedTelemCount); packetCountAtStartOfCurrentRateCheck = telemPacketCount; packetCountAtStartOfNextRateCheck = packetCountAtStartOfCurrentRateCheck + packetRateCheckInterval; ticksAtStartOfCurrentPacketRateCheck = DateTime.UtcNow.Ticks; } frameLength = UDPPacketSizes.telemetryPacketSize; Boolean sequenceCheckOK = isNextInSequence(packetNumber); if (sequenceCheckOK) { inSequenceTelemCount++; } if (strictPacketOrdering && !sequenceCheckOK) { discardedTelemCount++; } else { GCHandle telemHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sTelemetryData telem = (sTelemetryData)Marshal.PtrToStructure(telemHandle.AddrOfPinnedObject(), typeof(sTelemetryData)); if (sequenceCheckOK || !telemIsOutOfSequence(telem)) { buttonsState = ConvertBytesToBoolArray(telem.sDPad, telem.sJoyPad1, telem.sJoyPad2); lastSequenceNumberForTelemPacket = (int)packetNumber; workingGameState = StructHelper.MergeWithExistingState(workingGameState, telem); newSpotterData = true; } } finally { telemHandle.Free(); } } break; case EUDPStreamerPacketHandlerType.eRaceDefinition: raceDefinitionPacketCount++; frameLength = UDPPacketSizes.raceDataPacketSize; GCHandle raceDefHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sRaceData raceDefinition = (sRaceData)Marshal.PtrToStructure(raceDefHandle.AddrOfPinnedObject(), typeof(sRaceData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, raceDefinition); } finally { raceDefHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eParticipants: participantsPacketCount++; frameLength = UDPPacketSizes.participantsDataPacketSize; GCHandle participantsHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sParticipantsData participants = (sParticipantsData)Marshal.PtrToStructure(participantsHandle.AddrOfPinnedObject(), typeof(sParticipantsData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, participants); } finally { participantsHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eTimings: timingsPacketCount++; frameLength = UDPPacketSizes.timingsDataPacketSize; GCHandle timingsHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sTimingsData timings = (sTimingsData)Marshal.PtrToStructure(timingsHandle.AddrOfPinnedObject(), typeof(sTimingsData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, timings); } finally { timingsHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eGameState: gameStatePacketCount++; frameLength = UDPPacketSizes.gameStateDataPacketSize; GCHandle gameStateHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sGameStateData gameState = (sGameStateData)Marshal.PtrToStructure(gameStateHandle.AddrOfPinnedObject(), typeof(sGameStateData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, gameState); } finally { gameStateHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eWeatherState: weatherStatePacketCount++; Console.WriteLine("Got an undocumented and unsupported weather packet"); break; case EUDPStreamerPacketHandlerType.eVehicleNames: weatherStatePacketCount++; Console.WriteLine("Got an undocumented and unsupported vehicle names packet"); break; case EUDPStreamerPacketHandlerType.eTimeStats: participantsPacketCount++; frameLength = UDPPacketSizes.timeStatsPacketSize; GCHandle timeStatsHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sTimeStatsData timeStatsData = (sTimeStatsData)Marshal.PtrToStructure(timeStatsHandle.AddrOfPinnedObject(), typeof(sTimeStatsData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, timeStatsData); } finally { timeStatsHandle.Free(); } break; case EUDPStreamerPacketHandlerType.eParticipantVehicleNames: participantsPacketCount++; frameLength = UDPPacketSizes.participantVehicleNamesPacketSize; GCHandle vehNamesHandle = GCHandle.Alloc(rawData.Take(frameLength).ToArray(), GCHandleType.Pinned); try { sParticipantVehicleNamesData participantVehicleNames = (sParticipantVehicleNamesData)Marshal.PtrToStructure(vehNamesHandle.AddrOfPinnedObject(), typeof(sParticipantVehicleNamesData)); workingGameState = StructHelper.MergeWithExistingState(workingGameState, participantVehicleNames); } finally { vehNamesHandle.Free(); } break; } return(frameLength); }
private Boolean telemIsOutOfSequence(sTelemetryData telem) { // TODO: return(false); }
public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sTelemetryData udpTelemetryData) { // Participant Info existingState.mViewedParticipantIndex = udpTelemetryData.sViewedParticipantIndex; // Unfiltered Input existingState.mUnfilteredThrottle = (float)udpTelemetryData.sUnfilteredThrottle / 255f; existingState.mUnfilteredBrake = (float)udpTelemetryData.sUnfilteredBrake / 255f; existingState.mUnfilteredSteering = (float)udpTelemetryData.sUnfilteredSteering / 127f; existingState.mUnfilteredClutch = (float)udpTelemetryData.sUnfilteredClutch / 255f; // Car State existingState.mCarFlags = udpTelemetryData.sCarFlags; existingState.mOilTempCelsius = udpTelemetryData.sOilTempCelsius; existingState.mOilPressureKPa = udpTelemetryData.sOilPressureKPa; existingState.mWaterTempCelsius = udpTelemetryData.sWaterTempCelsius; existingState.mWaterPressureKPa = udpTelemetryData.sWaterPressureKpa; existingState.mFuelPressureKPa = udpTelemetryData.sFuelPressureKpa; existingState.mFuelLevel = udpTelemetryData.sFuelLevel; existingState.mFuelCapacity = udpTelemetryData.sFuelCapacity; existingState.mSpeed = udpTelemetryData.sSpeed; existingState.mMaxRPM = udpTelemetryData.sMaxRpm; existingState.mBrake = (float)udpTelemetryData.sBrake / 255f; existingState.mThrottle = (float)udpTelemetryData.sThrottle / 255f; existingState.mClutch = (float)udpTelemetryData.sClutch / 255f; existingState.mSteering = (float)udpTelemetryData.sSteering / 127f; existingState.mGear = udpTelemetryData.sGearNumGears & 15; existingState.mNumGears = udpTelemetryData.sGearNumGears >> 4; existingState.mOdometerKM = udpTelemetryData.sOdometerKM; existingState.mBoostAmount = udpTelemetryData.sBoostAmount; // Motion & Device Related existingState.mOrientation = udpTelemetryData.sOrientation; existingState.mLocalVelocity = udpTelemetryData.sLocalVelocity; existingState.mWorldVelocity = udpTelemetryData.sWorldVelocity; existingState.mAngularVelocity = udpTelemetryData.sAngularVelocity; existingState.mLocalAcceleration = udpTelemetryData.sLocalAcceleration; existingState.mWorldAcceleration = udpTelemetryData.sWorldAcceleration; existingState.mExtentsCentre = udpTelemetryData.sExtentsCentre; existingState.mTyreFlags = toUIntArray(udpTelemetryData.sTyreFlags); existingState.mTerrain = toUIntArray(udpTelemetryData.sTerrain); existingState.mTyreY = udpTelemetryData.sTyreY; existingState.mTyreRPS = udpTelemetryData.sTyreRPS; existingState.mTyreTemp = toFloatArray(udpTelemetryData.sTyreTemp, 255); existingState.mTyreHeightAboveGround = udpTelemetryData.sTyreHeightAboveGround; existingState.mTyreWear = toFloatArray(udpTelemetryData.sTyreWear, 255); existingState.mBrakeTempCelsius = toFloatArray(udpTelemetryData.sBrakeTempCelsius, 1); existingState.mTyreTreadTemp = toFloatArray(udpTelemetryData.sTyreTreadTemp, 1); existingState.mTyreLayerTemp = toFloatArray(udpTelemetryData.sTyreLayerTemp, 1); existingState.mTyreCarcassTemp = toFloatArray(udpTelemetryData.sTyreCarcassTemp, 1); existingState.mTyreRimTemp = toFloatArray(udpTelemetryData.sTyreRimTemp, 1); existingState.mTyreInternalAirTemp = toFloatArray(udpTelemetryData.sTyreInternalAirTemp, 1); // IMO tyre temps aren't mapped here - they're in UDP but not MMF existingState.mWheelLocalPositionY = udpTelemetryData.sWheelLocalPositionY; existingState.mRideHeight = udpTelemetryData.sRideHeight; existingState.mSuspensionTravel = udpTelemetryData.sSuspensionTravel; existingState.mSuspensionRideHeight = toFloatArray(udpTelemetryData.sSuspensionRideHeight, 1); existingState.mSuspensionVelocity = udpTelemetryData.sSuspensionVelocity; existingState.mAirPressure = toFloatArray(udpTelemetryData.sAirPressure, 1); existingState.mEngineSpeed = udpTelemetryData.sEngineSpeed; existingState.mEngineTorque = udpTelemetryData.sEngineTorque; // Car Damage existingState.mCrashState = udpTelemetryData.sCrashState; existingState.mAeroDamage = (float)udpTelemetryData.sAeroDamage / 255f; existingState.mEngineDamage = (float)udpTelemetryData.sEngineDamage / 255f; existingState.mBrakeDamage = toFloatArray(udpTelemetryData.sBrakeDamage, 255); existingState.mSuspensionDamage = toFloatArray(udpTelemetryData.sSuspensionDamage, 255); existingState.mWings = toFloatArray(udpTelemetryData.sWings, 1); existingState.mJoyPad1 = udpTelemetryData.sJoyPad1; existingState.mJoyPad2 = udpTelemetryData.sJoyPad2; existingState.mDPad = udpTelemetryData.sDPad; // tyres existingState.mLFTyreCompoundName = udpTelemetryData.lfTyreCompound; existingState.mRFTyreCompoundName = udpTelemetryData.rfTyreCompound; existingState.mLRTyreCompoundName = udpTelemetryData.lrTyreCompound; existingState.mRRTyreCompoundName = udpTelemetryData.rrTyreCompound; return(existingState); }