Ldalvik / ForzaTelemetryAPI

Forza Horizon 4/5 DATA OUT structure and wrapper for android
12 stars 4 forks source link

speed returns 0 on Forza Motorsport #1

Open ilker-aktuna opened 11 months ago

ilker-aktuna commented 11 months ago

Hi,

I am trying this API with the new Forza Motorsport game Unfortunately getSpeedKph and getSpeedMph returns 0

RPM values are returned correctly also getVelocity works fine

but getSpeed does not

Ldalvik commented 10 months ago

This API only works for Forza Horizon 5 because of the difference in telemetry schemas. I may or may not update it to support FM8. The new telemetry schema is not all that different.

https://support.forzamotorsport.net/hc/en-us/articles/21742934024211-Forza-Motorsport-Data-Out-Documentation

ilker-aktuna commented 10 months ago

thank you. maybe if you update , you can inform via this issue.

Ldalvik commented 10 months ago

Someone contacted me and wanted to add merge their code for FM8 to this repo, so if they do I will let you know!

ilker-aktuna commented 10 months ago

Someone contacted me and wanted to add merge their code for FM8 to this repo, so if they do I will let you know!

great ! thanks

dusanders commented 10 months ago

I have forked this repo and added some initial FM7/8 logic. I have not tested it completely as I was only looking to get some specific values from FM7. However, you can check out my changes here: https://github.com/dusanders/ForzaTelemetryAPI/commit/737c47f25801f234da5487a1bef7e387195593aa

I have 2 branches on my repo:

ilker-aktuna commented 10 months ago

great , thanks ! I see that the implementation does not require to select which game is in use. It detects the game from packet size. Can you confirm ?

ilker-aktuna commented 10 months ago

I have forked this repo and added some initial FM7/8 logic. I have not tested it completely as I was only looking to get some specific values from FM7. However, you can check out my changes here: dusanders@737c47f

I have 2 branches on my repo:

  • motorsport adds FM7/8
  • kotlin contains kotlin files that were produced by Android Studio's built-in conversion utility. Completely untested at the moment. Based on motorsport branch.

I tried getSpeedKph, getSpeedMph and getSpeedMps they did not work I tried to understand the packet structure but failed. Maybe you can...

dusanders commented 10 months ago

Not 100% as I only own FM7.

This seems logical as the Forza games output different data in different byte lengths, so we can probably assume the game based on byte length. If the games output the same byte length but different ordering, then I would agree a selection would be required; but since we get different byte lengths from the different games I think the assumption is safe enough.

This also leads to the additions I implemented, namely the byte[] allocation of FM8 and the passing of the DatagramPacket getLength(). These were required for:

  1. We need to allocate the largest expected array (FM8)
  2. We need to know the actual size of the UDP packet, which Java only exposes via 'getLength()' - the length of the array returned from 'getData()' would equal the allocation size passed during packet initialization.

I can do some more testing - originally, I was only looking for torque, hp, and RPMs (dyno graphs for different cars to set gearing)

When I was looking for a solution I found a couple things; a reddit post (https://www.reddit.com/r/forza/comments/16vnrr8/forza_telemetry_data_out/) leads to this C# repo and specifically this file (https://github.com/austinbaccus/forza-telemetry/blob/main/ForzaCore/PacketParse.cs) which is doing the same logic.

Forza (unofficial docs?) https://support.forzamotorsport.net/hc/en-us/articles/21742934024211-Forza-Motorsport-Data-Out-Documentation

Lastly, I should specify that I am using DASH output format - i have done nothing to support SLED.

EDIT: It looks like maybe the parse is getting offset due to Horizon timestamp using long instead of int? Forza says FM7 is a U32... so, maybe update API parse to consider that? I wont have time to test until tomorrow.

        //Set data by going through the bytebuffer
        isRaceOn = getFromBuffer(bb, int.class) == 1;
        if(isFHPacket()) {
            timeStampMS = getFromBuffer(bb, long.class);
        } else {
            timeStampMS = (long)getFromBuffer(bb, int.class);
        }
ilker-aktuna commented 10 months ago

isRaceOn = getFromBuffer(bb, int.class) == 1; if(isFHPacket()) { timeStampMS = getFromBuffer(bb, long.class); } else { timeStampMS = (long)getFromBuffer(bb, int.class); }

ok I tried this with :

    if(bytes.length==324) {
        timeStampMS = getFromBuffer(bb, long.class);
    } else {
        timeStampMS = (long)getFromBuffer(bb, int.class);
    }

it did not help me get any speed values. But this is weird , because with or without this modification, I get the same values for "velocity" if this mode was effective, I assume I should get different values for anything after timeStampMS

Btw, velocity values are working , speed is not working. There are many other values between velocity and speed.

ilker-aktuna commented 10 months ago

also, I could not find a way to check if the thread (ForzaInterface) is running or not. Sometimes my app is started and then run twice while in background. Then of course it crashes because the udp port is already in use. To prevent that, I want to check the state of the thread. How can we implement this ?

dusanders commented 10 months ago

For threading, there are 2 things we could do.

  1. use isAlive() - https://developer.android.com/reference/java/lang/Thread#isAlive()
  2. The logic for starting the thread should be in 'onResume()' override of your main class and we should interrupt and release the handle to the thread inside the 'onPause()' override.
    @Override
    protected void onPause() {
        super.onPause();
        builder.getThread()
                .interrupt();
        builder = null;
    }

    @Override
    protected void onResume() {
        super.onResume();
        builder = new ForzaTelemetryBuilder();
        builder.addListener(this)
                .getThread()
                .start();
}

If we don't want to kill the thread, we should be able to use isAlive() in the onResume() to check if the thread is running or not and either start thread or just return if already alive.

Edit: Finally got some time to really look at this Thread. The issue is because the builder is returning the 'startConnection()' function when calling 'getThread()' - this forces a new thread for every call to 'getThread()'

The builder should have a handle on the Thread from 'startConnection()' and return that handle instead.

ilker-aktuna commented 10 months ago

Well, I had tried both and they both did not succeed.

  1. isAlive() did not return "true" but the port was in use
  2. I used following in onPause and still when resumed activity address was in use.

if(udpThread != null) udpThread.interrupt();

dusanders commented 10 months ago

Yes, the issue really stems from the Builder... see here:

https://github.com/dusanders/ForzaTelemetryAPI/commit/a316570dcabe2d84e3b5e7d74c514f6879594fad

once we have those changes - we can do this:

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(builder == null) {
            builder = new ForzaTelemetryBuilder(port);
            builder.addListener(this);
        }
        if(!builder.getThread().isAlive()) {
            Log.w(TAG, "Thread not alive..");
            builder.getThread().start();
        }
    }

Confirming this works on Android 12 - app does not crash

ilker-aktuna commented 10 months ago

ok. now isAlive() works. did you see my post above about the speed/velocity fields ?

dusanders commented 10 months ago

I did - haven't gotten to that quite yet. But, when you say velocity do you mean the velocity x/y/z values? or the base speed? it seems the MPH / KPH is returned from a calculation. Perhaps something there is getting dropped?

dusanders commented 10 months ago

I also pushed out this repo: https://github.com/dusanders/android_forza_telemetry

If you clone that - you will have to update some directory structures so the import works correctly in Android Studio. Namely, the core API files need to be moved into 'src/forza/telemetry' (for namespacing in Android Studio)

And, update (or follow README) the gradle file to point your 'srcDirs' to the API library files...

ilker-aktuna commented 10 months ago

I am using getAverageVelocity which is calculated from velocity x/y/z that works.

But I prefer to use speedKph or speedMph These are both calculated from speedMps (simple calculation)

in summary velocity values are working , speed values are not. And changing timestamp to int (from long) does not change anything. Isn't that weird ? I had assumed, if that causes a shift then after that change , velocity should not report same.

dusanders commented 10 months ago

After looking at the 'getFromBuffer()' - it makes sense that nothing is changed via parse because we don't actually read a long. We read an int and cast it to a long:

            case "long":
                return (T) (checkBuffer(buffer, 4) ? (Object) Integer.toUnsignedLong(buffer.getInt()) : 0L);
dusanders commented 10 months ago

Finally got around to testing - i am getting speeds and average velocity (FM7 DASH out) logcat:

2023-12-08 14:58:57.167 10599-10627/com.dusanders.forzatelemetry D/MainViewModel: 
     speed: 17
     mph: 38
     kph: 61
     time: 508814031
    avg vel: 1727
    gear: 1
     rpm: 5253

The other thing that might be causing issues is the expected byte count for FH? In my changes, I changed the packet size of Horizon from 323 -> 324. Can you verify if that length change affected anything? If using my changes, your logcat should be displaying an error message about invalid packet length... But it will still continue to parse the packet. Perhaps we need to change that back to 323?

ilker-aktuna commented 10 months ago

ok, then there is a difference in FM7 and FM8 I am using FM8 and I don't get "invalid packet length" log. I get that if I change to "Sled" format. In "dashboard" format , there is no invalid packet length log.

dusanders commented 10 months ago

Sorry, for some reason I thought you were having issues with Horizon. Either way - I don't have FM8 so I am unable to help further.... There seems to be many people having issues: https://forums.forza.net/t/udp-telemetry-packet-details/629111 The linked document from that post showing the output format is the same document I used when I added my changes; so I have no idea what the developers are outputting in FM8 that would change from FM7?

Maybe more info here : https://forums.forza.net/t/data-out-feature-in-forza-motorsport/651333/11

Unless @Ldalvik has any ideas...?

ilker-aktuna commented 10 months ago

linked document from that post showing

Do you mean this document : https://support.forzamotorsport.net/hc/en-us/articles/21742934024211-Forza-Motorsport-Data-Out-Documentation ?

Can we compare 2 packets from FM7 and FM8 ? If you can get a packet from FM7 and tell me how you get it (bytebuffer to string ?), then I get the same from FM8 and compoare ? we could get 2 packets , 1 with zero speed and 1 with speed around 50km/h

dusanders commented 10 months ago

Yes, that is the document I used.

Here is 2 logs: 1st is @ 50kph, 2nd @ 0kph

2023-12-10 20:11:49.582 18639-18663/com.dusanders.forzatelemetry W/ForzaTelemetryApi: { isRaceOn='true', timeStampMS='700388562', engineMaxRpm='8000', engineIdleRpm='800', currentEngineRpm='1951', accelerationX='4', accelerationY='-4', accelerationZ='502', velocityX='0', velocityY='-8', velocityZ='1353', averageVelocityZ='1353', angularVelocityX='3', angularVelocityY='0', angularVelocityZ='0', yaw='-289', pitch='-2', roll='1', normalizedSuspensionTravelFrontLeft='28', normalizedSuspensionTravelFrontRight='29', normalizedSuspensionTravelRearLeft='45', normalizedSuspensionTravelRearRight='44', tireSlipRatioFrontLeft='-1', tireSlipRatioFrontRight='-1', tireSlipRatioRearLeft='4', tireSlipRatioRearRight='10', wheelRotationSpeedFrontLeft='4152', wheelRotationSpeedFrontRight='4145', wheelRotationSpeedRearLeft='4218', wheelRotationSpeedRearRight='4176', wheelOnRumbleStripFrontLeft='0', wheelOnRumbleStripFrontRight='0', wheelOnRumbleStripRearLeft='0', wheelOnRumbleStripRearRight='0', wheelInPuddleDepthFrontLeft='0.0', wheelInPuddleDepthFrontRight='0.0', wheelInPuddleDepthRearLeft='0.0', wheelInPuddleDepthRearRight='0.0', surfaceRumbleFrontLeft='0.0', surfaceRumbleFrontRight='0.0', surfaceRumbleRearLeft='0.0', surfaceRumbleRearRight='0.0', tireSlipAngleFrontLeft='0', tireSlipAngleFrontRight='0', tireSlipAngleRearLeft='0', tireSlipAngleRearRight='0', tireCombinedSlipFrontLeft='1', tireCombinedSlipFrontRight='1', tireCombinedSlipRearLeft='4', tireCombinedSlipRearRight='10', suspensionTravelMetersFrontLeft='0', suspensionTravelMetersFrontRight='0', suspensionTravelMetersRearLeft='1', suspensionTravelMetersRearRight='1', carClass='S1', carPerformanceIndex='700', drivetrainType='RWD', numCylinders='8', carType='Unknown (0)', objectHit1='0', carOrdinal='287', positionX='-80598', positionY='90', positionZ='-238840', speedMps='14', speedMph='31', speedKph='50', power='92793', horsepower='124', torque='456', tireTempFrontLeft='182', tireTempFrontRight='181', tireTempRearLeft='214', tireTempRearRight='214', boost='0', fuel='100.0', distanceTraveled='995.6243', bestLap='0.0', lastLap='0.0', currentLap='79.68422', currentRaceTime='82.20106', lapNumber='0', racePosition='24', accel='100', brake='0', clutch='0', handbrake='0', gear='3', steer='0', normalizedDrivingLine='37', normalizedAIBrakeDifference='0', tireWearFrontLeft='0', tireWearFrontRight='0', tireWearRearLeft='0', tireWearRearRight='0', trackID='0'}
2023-12-10 20:11:51.930 18639-18663/com.dusanders.forzatelemetry W/ForzaTelemetryApi: { isRaceOn='true', timeStampMS='700390906', engineMaxRpm='8000', engineIdleRpm='800', currentEngineRpm='775', accelerationX='-13', accelerationY='16', accelerationZ='-629', velocityX='0', velocityY='1', velocityZ='48', averageVelocityZ='48', angularVelocityX='-3', angularVelocityY='0', angularVelocityZ='1', yaw='-312', pitch='-1', roll='2', normalizedSuspensionTravelFrontLeft='42', normalizedSuspensionTravelFrontRight='43', normalizedSuspensionTravelRearLeft='30', normalizedSuspensionTravelRearRight='30', tireSlipRatioFrontLeft='2', tireSlipRatioFrontRight='2', tireSlipRatioRearLeft='2', tireSlipRatioRearRight='2', wheelRotationSpeedFrontLeft='156', wheelRotationSpeedFrontRight='155', wheelRotationSpeedRearLeft='156', wheelRotationSpeedRearRight='156', wheelOnRumbleStripFrontLeft='0', wheelOnRumbleStripFrontRight='0', wheelOnRumbleStripRearLeft='0', wheelOnRumbleStripRearRight='0', wheelInPuddleDepthFrontLeft='0.0', wheelInPuddleDepthFrontRight='0.0', wheelInPuddleDepthRearLeft='0.0', wheelInPuddleDepthRearRight='0.0', surfaceRumbleFrontLeft='0.0', surfaceRumbleFrontRight='0.0', surfaceRumbleRearLeft='0.0', surfaceRumbleRearRight='0.0', tireSlipAngleFrontLeft='0', tireSlipAngleFrontRight='0', tireSlipAngleRearLeft='0', tireSlipAngleRearRight='0', tireCombinedSlipFrontLeft='2', tireCombinedSlipFrontRight='2', tireCombinedSlipRearLeft='2', tireCombinedSlipRearRight='2', suspensionTravelMetersFrontLeft='1', suspensionTravelMetersFrontRight='1', suspensionTravelMetersRearLeft='0', suspensionTravelMetersRearRight='0', carClass='S1', carPerformanceIndex='700', drivetrainType='RWD', numCylinders='8', carType='Unknown (0)', objectHit1='0', carOrdinal='287', positionX='-86504', positionY='497', positionZ='-265028', speedMps='0', speedMph='0', speedKph='0', power='425', horsepower='1', torque='5', tireTempFrontLeft='224', tireTempFrontRight='225', tireTempRearLeft='234', tireTempRearRight='234', boost='0', fuel='100.0', distanceTraveled='1022.5375', bestLap='0.0', lastLap='0.0', currentLap='82.03419', currentRaceTime='84.551025', lapNumber='0', racePosition='24', accel='0', brake='100', clutch='0', handbrake='0', gear='3', steer='0', normalizedDrivingLine='3', normalizedAIBrakeDifference='101', tireWearFrontLeft='0', tireWearFrontRight='0', tireWearRearLeft='0', tireWearRearRight='0', trackID='0'}

And JSON

{ "isRaceOn":"true","timeStampMS":"701373375","engineMaxRpm":"8000","engineIdleRpm":"800","currentEngineRpm":"4281","accelerationX":"-2","accelerationY":"-5","accelerationZ":"491","velocityX":"-1","velocityY":"-5","velocityZ":"1356","averageVelocityZ":"1356","angularVelocityX":"1","angularVelocityY":"0","angularVelocityZ":"2","yaw":"-223","pitch":"-2","roll":"0","normalizedSuspensionTravelFrontLeft":"28","normalizedSuspensionTravelFrontRight":"32","normalizedSuspensionTravelRearLeft":"42","normalizedSuspensionTravelRearRight":"42","tireSlipRatioFrontLeft":"-1","tireSlipRatioFrontRight":"-1","tireSlipRatioRearLeft":"19","tireSlipRatioRearRight":"22","wheelRotationSpeedFrontLeft":"4151","wheelRotationSpeedFrontRight":"4152","wheelRotationSpeedRearLeft":"4264","wheelRotationSpeedRearRight":"4283","wheelOnRumbleStripFrontLeft":"0","wheelOnRumbleStripFrontRight":"0","wheelOnRumbleStripRearLeft":"0","wheelOnRumbleStripRearRight":"0","wheelInPuddleDepthFrontLeft":"0.0","wheelInPuddleDepthFrontRight":"0.0","wheelInPuddleDepthRearLeft":"0.0","wheelInPuddleDepthRearRight":"0.0","surfaceRumbleFrontLeft":"0.0","surfaceRumbleFrontRight":"0.0","surfaceRumbleRearLeft":"0.0","surfaceRumbleRearRight":"0.0","tireSlipAngleFrontLeft":"0","tireSlipAngleFrontRight":"0","tireSlipAngleRearLeft":"0","tireSlipAngleRearRight":"0","tireCombinedSlipFrontLeft":"1","tireCombinedSlipFrontRight":"1","tireCombinedSlipRearLeft":"19","tireCombinedSlipRearRight":"22","suspensionTravelMetersFrontLeft":"0","suspensionTravelMetersFrontRight":"0","suspensionTravelMetersRearLeft":"1","suspensionTravelMetersRearRight":"1","carClass":"S1","carPerformanceIndex":"700","drivetrainType":"RWD","numCylinders":"8","carType":"Unknown (0)","objectHit1":"0","carOrdinal":"287","positionX":"-30803","positionY":"-835","positionZ":"-463375","speedMps":"14","speedMph":"31","speedKph":"50","power":"157074","horsepower":"211","torque":"351","tireTempFrontLeft":"133","tireTempFrontRight":"135","tireTempRearLeft":"162","tireTempRearRight":"162","boost":"0","fuel":"100.0","distanceTraveled":"1288.0413","bestLap":"0.0","lastLap":"0.0","currentLap":"774.9918","currentRaceTime":"777.50867","lapNumber":"0","racePosition":"24","accel":"70","brake":"0","clutch":"0","handbrake":"0","gear":"1","steer":"0","normalizedDrivingLine":"150","normalizedAIBrakeDifference":"0","tireWearFrontLeft":"0","tireWearFrontRight":"0","tireWearRearLeft":"0","tireWearRearRight":"0","trackID":"0"}

{ "isRaceOn":"true","timeStampMS":"701375640","engineMaxRpm":"8000","engineIdleRpm":"800","currentEngineRpm":"762","accelerationX":"-1","accelerationY":"21","accelerationZ":"-618","velocityX":"0","velocityY":"0","velocityZ":"46","averageVelocityZ":"46","angularVelocityX":"0","angularVelocityY":"0","angularVelocityZ":"-1","yaw":"-224","pitch":"-1","roll":"3","normalizedSuspensionTravelFrontLeft":"39","normalizedSuspensionTravelFrontRight":"40","normalizedSuspensionTravelRearLeft":"32","normalizedSuspensionTravelRearRight":"29","tireSlipRatioFrontLeft":"2","tireSlipRatioFrontRight":"2","tireSlipRatioRearLeft":"2","tireSlipRatioRearRight":"2","wheelRotationSpeedFrontLeft":"147","wheelRotationSpeedFrontRight":"147","wheelRotationSpeedRearLeft":"147","wheelRotationSpeedRearRight":"147","wheelOnRumbleStripFrontLeft":"0","wheelOnRumbleStripFrontRight":"0","wheelOnRumbleStripRearLeft":"0","wheelOnRumbleStripRearRight":"0","wheelInPuddleDepthFrontLeft":"0.0","wheelInPuddleDepthFrontRight":"0.0","wheelInPuddleDepthRearLeft":"0.0","wheelInPuddleDepthRearRight":"0.0","surfaceRumbleFrontLeft":"0.0","surfaceRumbleFrontRight":"0.0","surfaceRumbleRearLeft":"0.0","surfaceRumbleRearRight":"0.0","tireSlipAngleFrontLeft":"0","tireSlipAngleFrontRight":"0","tireSlipAngleRearLeft":"0","tireSlipAngleRearRight":"0","tireCombinedSlipFrontLeft":"2","tireCombinedSlipFrontRight":"2","tireCombinedSlipRearLeft":"2","tireCombinedSlipRearRight":"2","suspensionTravelMetersFrontLeft":"0","suspensionTravelMetersFrontRight":"0","suspensionTravelMetersRearLeft":"0","suspensionTravelMetersRearRight":"0","carClass":"S1","carPerformanceIndex":"700","drivetrainType":"RWD","numCylinders":"8","carType":"Unknown (0)","objectHit1":"0","carOrdinal":"287","positionX":"-51130","positionY":"-331","positionZ":"-479159","speedMps":"0","speedMph":"0","speedKph":"0","power":"418","horsepower":"1","torque":"5","tireTempFrontLeft":"177","tireTempFrontRight":"180","tireTempRearLeft":"182","tireTempRearRight":"182","boost":"0","fuel":"100.0","distanceTraveled":"1313.5898","bestLap":"0.0","lastLap":"0.0","currentLap":"777.25854","currentRaceTime":"779.7754","lapNumber":"0","racePosition":"24","accel":"0","brake":"100","clutch":"0","handbrake":"0","gear":"1","steer":"0","normalizedDrivingLine":"197","normalizedAIBrakeDifference":"101","tireWearFrontLeft":"0","tireWearFrontRight":"0","tireWearRearLeft":"0","tireWearRearRight":"0","trackID":"0"}
Ldalvik commented 10 months ago

@ilker-aktuna @dusanders I am open to working with you guys on getting a finished merge here-- but I'd prefer talking in discord as it's a little easier. If you'd like, you can @ me (heyroot) and I'll get you added to our development channel. We spent a while working on the FH5 telemetry, and wouldn't mind getting this tested and verified for you guys as well.

https://discord.gg/optn-915290676600647690

Also, you are free to change my code as you like. I don't really know much about android development anymore, and I only made this library for Ldalvik/ForzaTelemetryAndroidApp. It's safe to say some of my code may be outdated or just straight up bad.

ilker-aktuna commented 10 months ago

Here is 2 logs: 1st is @ 50kph, 2nd @ 0kph

can you provide the code which you got this with ? I was assuming to compare unparsed packets. If we'll compare parsed, let's do with the same code.

dusanders commented 10 months ago

@Ldalvik I glanced at the Discord - quite the community over there! I do think there is value in continuing the discussion on this github issue. It might be helpful for the community to have this information available to others who may get here looking for the same issue instead of blocking it behind Discord channels. If you prefer, we could move discussion to my fork?

Here is another sample with raw byte[] - not sure how helpful it will be as its not formatted the same as when we extract... (just dumped array)

The code is the same parse as on my branch - I added some conditionals to only print at 50 kph and then at 0 kph to limit the output in logcat. Printing was done at the bottom of the constructor right after we parse. see: https://github.com/dusanders/ForzaTelemetryAPI/commit/8055c764545d209e4aa2754c2a494ec6f3eace50

2023-12-11 10:20:32.193 29771-29797/com.dusanders.forzatelemetry W/ForzaTelemetryApi: [1, 0, 0, 0, 87, 27, -56, 44, -5, 63, 28, 70, -8, -1, 71, 68, 17, -112, -112, 69, 0, -30, 99, 60, -83, -102, 55, -66, 86, 56, 1, 65, 0, 0, 59, 59, -121, 81, -116, -67, -5, -85, 88, 65, 39, -18, -96, 59, 98, -85, -62, 59, 106, -104, -36, 58, -101, 6, 8, 64, 95, -115, -56, 59, -37, -113, 97, -68, -74, 57, -126, 62, -56, 7, -125, 62, -47, -28, 4, 63, -61, -104, 5, 63, 127, -15, -50, 61, 127, -34, -53, 61, -84, -97, -70, 62, -20, -67, -89, -67, -61, -87, 37, 66, 12, -74, 37, 66, 57, -95, 35, 66, 86, 116, 36, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 44, -126, -69, 32, 84, -109, 57, 92, 71, -51, -69, 95, -55, -92, -70, 108, 26, -49, 61, -76, -34, -53, 61, -69, -90, -70, 62, -5, -62, -89, 61, -88, 122, 7, -68, -24, -73, 5, -68, 24, -113, -26, 59, 80, 59, -19, 59, 116, 8, 0, 0, 5, 0, 0, 0, 32, 3, 0, 0, 2, 0, 0, 0, 10, 0, 0, 0, -109, 19, 36, 67, 53, -37, -46, -65, 10, 93, -84, -62, -79, -84, 88, 65, -100, -126, 26, 72, 12, -113, -93, 67, 74, -28, 32, 67, 6, 100, 30, 67, -62, -101, 28, 67, -62, -101, 28, 67, 0, 0, 0, 0, 0, 0, -128, 63, 89, -53, 60, 67, 0, 0, 0, 0, 0, 0, 0, 0, 24, -45, 57, 66, 108, -17, 66, 66, 0, 0, 24, -78, 0, 0, 0, 1, 0, -23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2023-12-11 10:20:32.195 29771-29797/com.dusanders.forzatelemetry W/ForzaTelemetryApi: { "isRaceOn":"true","timeStampMS":"751311703","engineMaxRpm":"10000","engineIdleRpm":"800","currentEngineRpm":"4626","accelerationX":"1","accelerationY":"-18","accelerationZ":"808","velocityX":"0","velocityY":"-7","velocityZ":"1354","averageVelocityZ":"1354","angularVelocityX":"0","angularVelocityY":"1","angularVelocityZ":"0","yaw":"213","pitch":"1","roll":"-1","normalizedSuspensionTravelFrontLeft":"25","normalizedSuspensionTravelFrontRight":"26","normalizedSuspensionTravelRearLeft":"52","normalizedSuspensionTravelRearRight":"52","tireSlipRatioFrontLeft":"10","tireSlipRatioFrontRight":"10","tireSlipRatioRearLeft":"36","tireSlipRatioRearRight":"-8","wheelRotationSpeedFrontLeft":"4142","wheelRotationSpeedFrontRight":"4143","wheelRotationSpeedRearLeft":"4091","wheelRotationSpeedRearRight":"4111","wheelOnRumbleStripFrontLeft":"0","wheelOnRumbleStripFrontRight":"0","wheelOnRumbleStripRearLeft":"0","wheelOnRumbleStripRearRight":"0","wheelInPuddleDepthFrontLeft":"0.0","wheelInPuddleDepthFrontRight":"0.0","wheelInPuddleDepthRearLeft":"0.0","wheelInPuddleDepthRearRight":"0.0","surfaceRumbleFrontLeft":"0.0","surfaceRumbleFrontRight":"0.0","surfaceRumbleRearLeft":"0.0","surfaceRumbleRearRight":"0.0","tireSlipAngleFrontLeft":"0","tireSlipAngleFrontRight":"0","tireSlipAngleRearLeft":"0","tireSlipAngleRearRight":"0","tireCombinedSlipFrontLeft":"10","tireCombinedSlipFrontRight":"10","tireCombinedSlipRearLeft":"36","tireCombinedSlipRearRight":"8","suspensionTravelMetersFrontLeft":"-1","suspensionTravelMetersFrontRight":"-1","suspensionTravelMetersRearLeft":"1","suspensionTravelMetersRearRight":"1","carClass":"R","carPerformanceIndex":"800","drivetrainType":"AWD","numCylinders":"10","carType":"Unknown (0)","objectHit1":"0","carOrdinal":"2164","positionX":"164076","positionY":"-1647","positionZ":"-86182","speedMps":"14","speedMph":"31","speedKph":"50","power":"158218","horsepower":"212","torque":"327","tireTempFrontLeft":"161","tireTempFrontRight":"158","tireTempRearLeft":"157","tireTempRearRight":"157","boost":"0","fuel":"100.0","distanceTraveled":"188.79433","bestLap":"0.0","lastLap":"0.0","currentLap":"46.456146","currentRaceTime":"48.73381","lapNumber":"0","racePosition":"24","accel":"69","brake":"0","clutch":"0","handbrake":"0","gear":"1","steer":"0","normalizedDrivingLine":"183","normalizedAIBrakeDifference":"0","tireWearFrontLeft":"0","tireWearFrontRight":"0","tireWearRearLeft":"0","tireWearRearRight":"0","trackID":"0"}
2023-12-11 10:20:34.543 29771-29797/com.dusanders.forzatelemetry W/ForzaTelemetryApi: [1, 0, 0, 0, 126, 36, -56, 44, -5, 63, 28, 70, -8, -1, 71, 68, 113, 19, 68, 68, 0, 100, 125, -69, 38, 35, -120, 62, 24, -49, -75, -64, 0, 8, 12, 57, 16, -54, -111, -69, -58, 57, -9, 62, -74, 109, 127, -69, -122, 32, -102, -72, 122, 68, -20, -70, -102, 11, 9, 64, 94, 95, 125, 60, 93, 57, -114, -68, -69, -23, -29, 62, -68, -33, -28, 62, 31, -22, -64, 62, -60, 63, -61, 62, -54, -51, -78, 60, 110, 126, -77, 60, -125, 85, -90, 60, 46, 27, -89, 60, -77, -28, -62, 63, -13, -16, -62, 63, 96, -60, -72, 63, -116, -49, -72, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -110, -17, -127, 58, -36, -59, -121, 58, 110, 49, 89, 58, 0, -30, 71, 58, -6, -4, -78, 60, -63, -79, -77, 60, -14, 120, -90, 60, 14, 57, -89, 60, 112, 101, -100, 59, -96, -103, -96, 59, -96, -88, 102, -69, 64, 127, 80, -69, 116, 8, 0, 0, 5, 0, 0, 0, 32, 3, 0, 0, 2, 0, 0, 0, 10, 0, 0, 0, -31, 99, 59, 67, -122, -11, -10, -65, -10, 94, -55, -62, 117, 60, -9, 62, 25, 90, -65, 67, -62, 41, -107, 64, -96, -41, 69, 67, 11, -85, 67, 67, 79, -91, 52, 67, 79, -91, 52, 67, 0, 0, 0, 0, 0, 0, -128, 63, 18, 69, 88, 67, 0, 0, 0, 0, 0, 0, 0, 0, -126, 57, 67, 66, -43, 85, 76, 66, 0, 0, 24, 0, -1, 0, 0, 1, 0, -8, -127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
2023-12-11 10:20:34.545 29771-29797/com.dusanders.forzatelemetry W/ForzaTelemetryApi: { "isRaceOn":"true","timeStampMS":"751314046","engineMaxRpm":"10000","engineIdleRpm":"800","currentEngineRpm":"784","accelerationX":"0","accelerationY":"27","accelerationZ":"-568","velocityX":"0","velocityY":"0","velocityZ":"48","averageVelocityZ":"48","angularVelocityX":"0","angularVelocityY":"0","angularVelocityZ":"0","yaw":"214","pitch":"2","roll":"-2","normalizedSuspensionTravelFrontLeft":"45","normalizedSuspensionTravelFrontRight":"45","normalizedSuspensionTravelRearLeft":"38","normalizedSuspensionTravelRearRight":"38","tireSlipRatioFrontLeft":"2","tireSlipRatioFrontRight":"2","tireSlipRatioRearLeft":"2","tireSlipRatioRearRight":"2","wheelRotationSpeedFrontLeft":"152","wheelRotationSpeedFrontRight":"152","wheelRotationSpeedRearLeft":"144","wheelRotationSpeedRearRight":"144","wheelOnRumbleStripFrontLeft":"0","wheelOnRumbleStripFrontRight":"0","wheelOnRumbleStripRearLeft":"0","wheelOnRumbleStripRearRight":"0","wheelInPuddleDepthFrontLeft":"0.0","wheelInPuddleDepthFrontRight":"0.0","wheelInPuddleDepthRearLeft":"0.0","wheelInPuddleDepthRearRight":"0.0","surfaceRumbleFrontLeft":"0.0","surfaceRumbleFrontRight":"0.0","surfaceRumbleRearLeft":"0.0","surfaceRumbleRearRight":"0.0","tireSlipAngleFrontLeft":"0","tireSlipAngleFrontRight":"0","tireSlipAngleRearLeft":"0","tireSlipAngleRearRight":"0","tireCombinedSlipFrontLeft":"2","tireCombinedSlipFrontRight":"2","tireCombinedSlipRearLeft":"2","tireCombinedSlipRearRight":"2","suspensionTravelMetersFrontLeft":"0","suspensionTravelMetersFrontRight":"0","suspensionTravelMetersRearLeft":"0","suspensionTravelMetersRearRight":"0","carClass":"R","carPerformanceIndex":"800","drivetrainType":"AWD","numCylinders":"10","carType":"Unknown (0)","objectHit1":"0","carOrdinal":"2164","positionX":"187390","positionY":"-1929","positionZ":"-100685","speedMps":"0","speedMph":"0","speedKph":"0","power":"383","horsepower":"1","torque":"5","tireTempFrontLeft":"198","tireTempFrontRight":"196","tireTempRearLeft":"181","tireTempRearRight":"181","boost":"0","fuel":"100.0","distanceTraveled":"216.2698","bestLap":"0.0","lastLap":"0.0","currentLap":"48.80616","currentRaceTime":"51.08382","lapNumber":"0","racePosition":"24","accel":"0","brake":"100","clutch":"0","handbrake":"0","gear":"1","steer":"0","normalizedDrivingLine":"195","normalizedAIBrakeDifference":"101","tireWearFrontLeft":"0","tireWearFrontRight":"0","tireWearRearLeft":"0","tireWearRearRight":"0","trackID":"0"}
Ldalvik commented 9 months ago

@dusanders That's a good point, it would definitely be useful for others to see too. I only suggested it for better communication, but this is better to document.

ilker-aktuna commented 9 months ago

The code is the same parse as on my branch

sorry I wasn't here for the last few days. Now I am back on this again. I tried to get the logs as you did. And I am now really puzzled. Because when I put the log statements in ForzaTelemetry class I can see getSpeedKph works:


2023-12-14 13:11:47.419 12501-13226 ForzaTelemetryApi       com.test.test         W  [1, 0, 0, 0, 120, 88, 5, 0, -5, -97, 12, 70, -8, -1, 71, 68, 83, 0, 72, 68, -128, 56, 121, -67, 67, -119, -103, 61, -56, 80, 80, -64, 0, -76, -11, 57, -128, -8, -16, 58, -62, -90, -7, 62, 2, 44, 63, 60, 20, -1, -10, 58, 68, 17, -114, -70, -37, 1, -90, -65, -11, -45, -24, -68, -73, -81, -16, -67, -99, 22, -73, 62, 18, -42, -66, 62, -28, 39, -66, 62, -8, -94, -60, 62, -45, 29, -51, 60, -81, -67, -49, 60, -123, 64, -66, 60, -34, 51, -64, 60, 66, 29, -63, 63, -2, -34, -65, 63, -25, -118, -76, 63, 43, 97, -77, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -36, 45, -124, -69, -55, 17, -117, -69, 119, 67, -99, 59, 37, 124, -123, 58, -31, -62, -49, 60, 84, -95, -46, 60, -100, 69, -62, 60, 51, 98, -64, 60, -128, -75, -78, 58, 96, 67, 30, 59, 0, 119, -31, 57, -64, -93, -80, 58, -88, 12, 0, 0, 6, 0, 0, 0, 51, 3, 0, 0, 1, 0, 0, 0, 6, 0, 0, 0, 68, -10, 61, 68, 94, -94, 18, 68, -101, 35, 19, -60, 62, -89, -7, 62, 2, 25, 35, -68, 125, 49, -7, -72, -92, -93, 11, 67, -12, -49, 13, 67, 13, 102, 15, 67, 13, 102, 15, 67, 100, 102, 48, -63, 0, 0, -128, 63, -123, -93, 22, 68, 0, 0, 0, 0, 0, 0, 0, 0, -52, 120, -74, 66, 99, -14, -44, 66, 0, 0, 2, 0, 0, 0, 0, 1, 0, -41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0]
2023-12-14 13:11:47.423 12501-13226 ForzaTelemetryApi       com.test.test           W  { isRaceOn='true', timeStampMS='350328', engineMaxRpm='9000', engineIdleRpm='800', currentEngineRpm='800', accelerationX='-6', accelerationY='7', accelerationZ='-325', velocityX='0', velocityY='0', velocityZ='49', averageVelocityZ='49', angularVelocityX='1', angularVelocityY='0', angularVelocityZ='0', yaw='-130', pitch='-3', roll='-12', normalizedSuspensionTravelFrontLeft='36', normalizedSuspensionTravelFrontRight='37', normalizedSuspensionTravelRearLeft='37', normalizedSuspensionTravelRearRight='38', tireSlipRatioFrontLeft='3', tireSlipRatioFrontRight='3', tireSlipRatioRearLeft='2', tireSlipRatioRearRight='2', wheelRotationSpeedFrontLeft='151', wheelRotationSpeedFrontRight='150', wheelRotationSpeedRearLeft='141', wheelRotationSpeedRearRight='140', wheelOnRumbleStripFrontLeft='0', wheelOnRumbleStripFrontRight='0', wheelOnRumbleStripRearLeft='0', wheelOnRumbleStripRearRight='0', wheelInPuddleDepthFrontLeft='0.0', wheelInPuddleDepthFrontRight='0.0', wheelInPuddleDepthRearLeft='0.0', wheelInPuddleDepthRearRight='0.0', surfaceRumbleFrontLeft='0.0', surfaceRumbleFrontRight='0.0', surfaceRumbleRearLeft='0.0', surfaceRumbleRearRight='0.0', tireSlipAngleFrontLeft='0', tireSlipAngleFrontRight='0', tireSlipAngleRearLeft='0', tireSlipAngleRearRight='0', tireCombinedSlipFrontLeft='3', tireCombinedSlipFrontRight='3', tireCombinedSlipRearLeft='2', tireCombinedSlipRearRight='2', suspensionTravelMetersFrontLeft='0', suspensionTravelMetersFrontRight='0', suspensionTravelMetersRearLeft='0', suspensionTravelMetersRearRight='0', carClass='X', carPerformanceIndex='819', drivetrainType='RWD', numCylinders='6', carType='Unknown (0)', objectHit1='0', carOrdinal='3240', positionX='759848', positionY='586537', positionZ='-588556', speedMps='0', speedMph='0', speedKph='0', power='0', horsepower='0', torque='0', tireTempFrontLeft='140', tireTempFrontRight='142', tireTempRearLeft='143', tireTempRearRight='143', boost='-11', fuel='100.0', distanceTraveled='602.555', bestLap='0.0', lastLap='0.0', currentLap='91.23593', currentRaceTime='106.47341', lapNumber='0', racePosition='2', accel='0', brake='0', clutch='0', handbrake='0', gear='1', steer='0', normalizedDrivingLine='169', normalizedAIBrakeDifference='0'}

But from my activity class if I call it like below it does not bring anything:

speed=api.getSpeedKph();

instead , if I call velocity as below, it works:

speed=api.getAverageVelocity();

any ideas ?

ilker-aktuna commented 9 months ago

ok; I got it. it is because the values are returned as integer but I need float (because integer divided by integer loses float precision) When I changed the types, it works fine.

I think we can close this issue about speed.

I still have an issue about Thread isAlive returning false though.

dusanders commented 9 months ago

Which types were changed, base speed or all 3 (speed, getMph, getKph)? I thought about that - specifically the use of Math.round() for everything because we lose precision. However, I assumed it was fine as I get the proper speed values in FM7 and I assume FH worked fine. Did you test this fix against FM8?

As for the isAlive() - are you keeping and returning the handle to the thread as I mentioned previously? I know its working with my Pixel 3 XL @ Android 12... https://github.com/dusanders/ForzaTelemetryAPI/commit/a316570dcabe2d84e3b5e7d74c514f6879594fad

lastly, if you want logs in parseable JSON (i use JSONLint.com) https://github.com/dusanders/ForzaTelemetryAPI/commit/c984496a76972a51f83c5b35acf9946bbb58bae6

Ldalvik commented 9 months ago

@ilker-aktuna @dusanders You should remove the rounding for all values in the API, I believe that should be done application side if needed. That was an oversight on my part and was fixed in the C++ version.

Also, not sure how relevant it is now, but I left a tutorial on how to handle Threads in the README (under the android folder) as I had the same issue as you guys. But it seems it could be a version/phone specific thing.

dusanders commented 9 months ago

That makes sense, the the caller can round if they want. I will update my fork based on that. I see what you did in the README; basically the same I did with the builder - I just figured it was simpler (and a bit more OOP) to put that in the builder. I have seen different Thread behavior based on Android levels, so that might also be true for some edge-cases.

ilker-aktuna commented 9 months ago

As for the isAlive() - are you keeping and returning the handle to the thread as I mentioned previously?

Yes I did that change. My onPause method is as below, and I can see both of the logs, but thread continues working. What do you suggest ?


    @Override
    protected void onPause() {
        super.onPause();
        tv8.setText(R.string.st_stop);
        Log.d("00000","PAUSE1");
        if(builder!=null) {
            Log.d("00000","PAUSE2");
            builder.getThread().interrupt();
            builder = null;
        }
    }