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);
 }
Example #3
0
        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);
        }