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); }
public static pCars2APIStruct MergeWithExistingState(pCars2APIStruct existingState, sRaceData raceData) { Boolean isTimedSession = (raceData.sLapsTimeInEvent >> 15) == 1; int sessionLength = raceData.sLapsTimeInEvent / 2; // need the bottom bits of this short here - is it valid to just halve it? if (isTimedSession) { existingState.mLapsInEvent = (uint)sessionLength; existingState.mSessionLengthTimeFromGame = 0; } else { existingState.mSessionLengthTimeFromGame = 300 * (uint)sessionLength; // *300 because this is in 5 minutes blocks existingState.mLapsInEvent = 0; } existingState.mTrackLength = raceData.sTrackLength; existingState.mWorldFastestLapTime = raceData.sWorldFastestLapTime; existingState.mWorldFastestSector1Time = raceData.sWorldFastestSector1Time; existingState.mWorldFastestSector2Time = raceData.sWorldFastestSector2Time; existingState.mWorldFastestSector3Time = raceData.sWorldFastestSector3Time; existingState.mPersonalFastestLapTime = raceData.sPersonalFastestLapTime; existingState.mPersonalFastestSector1Time = raceData.sPersonalFastestSector1Time; existingState.mPersonalFastestSector2Time = raceData.sPersonalFastestSector2Time; existingState.mPersonalFastestSector3Time = raceData.sPersonalFastestSector3Time; existingState.mTrackLocation = raceData.sTrackLocation; existingState.mTrackVariation = raceData.sTrackVariation; existingState.mTranslatedTrackLocation = raceData.sTranslatedTrackLocation; existingState.mTranslatedTrackVariation = raceData.sTranslatedTrackVariation; existingState.mEnforcedPitStopLap = raceData.sEnforcedPitStopLap; return(existingState); }