PDA

View Full Version : [HowTo] Shared Memory (API) App



Lars Rosenquist
12-06-2015, 09:21
Introduction
With the APP & API forum slowly filling up with apps developed by WMD members, it's time to expand the knowledge on how to actually interface with Project CARS to the general public. The info in this post comes mostly from posts by SMS developers inside the WMD forum (I C/P most of it, so credits must go mostly to SMS for this) and I'll start with a fairly short introductory post, but will keep expanding it and adding on to it as we go along. I suppose this thread is also good to ask questions regarding the SharedMemory itself, but also to ask for tips in case you want to use it in a development environment/language that differs from Visual Studio/C/C++.

Shared Memory - concept
The way to interface with Project CARS is by the concept of shared memory. Shared memory (in Project CARS) is basically an in-memory file which contains lots of various real-time information about the game, e.g. physics state, car speed, best lap time, wind direction, contestants info, etc. It's currently updated every render frame. The purpose for this 'in memory file' is to share this real-time data with your external software and hardware. So using the shared memory your app has direct access to the information that is exposed by the game. This is by far the fastest way of getting data into your own app. What you can build is limited only by what you can come up with, e.g. it could range from cockpit simulators, telemetry calculations, to additional info displays. So this is: literally "Created by you". :)

Shared Memory vs UDP streaming
Instead of using Shared Memory, there's also UDP streaming available, please see this topic (http://forum.projectcarsgame.com/showthread.php?40113-COMPLETE-Companion-app-UDP-streaming) for more info on how to set this up. Note that Shared Memory only works on PC, but UDP is available on all platforms (PC, Xbox One, PS4).

Shared memory - implementation
The shared memory is implemented using a Memory-Mapped file (easier understood as an in-memory file). In memory file is named "$pcars$". It's updated every render frame, so this really depends on your user settings; ie; Resolution: 'Hz'. It's turned off by default, and switched on via the Main Menu options screen, under 'Help & Options' -> 'Visuals' -> 'Hardware' -> 'Use Shared Memory' -> 'Yes'.

The data structure is defined in "SharedMemory.h" (see the attached files below). You should be able to simply drop it into a C/C++ project with little difficulty. Or instead you could refer to it as a guideline/map/template if you're using other languages. I'll add a more detailed description of what does what at a later moment.

To make your lives a bit easier please find a small sample project attached below (made by SMS BTW, not me) which just keeps printing a value from the data until you press ESC. Also be sure to check out the threads from the other app developers, as some of them have provided open source implementations (including myself), so that should be good to give you guys a kick start. :)

Below is the latest SharedMemory.h


/*************************************************************************************************
Description:
Storage structure for storing and updating shared memory

Copyright (c) MWL. All rights reserved.
*************************************************************************************************/

#ifndef _SHARED_MEMORY_HPP_
#define _SHARED_MEMORY_HPP_

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTES:
//
// -The shared memory variables will be updated once per graphics frame.
//
// -Each variable comes with a UNIT, RANGE, and UNSET description where applicable.
// UNITS - Is the numeric form which a variable is stored in (e.g. KPH, Celsius)
// RANGE - Is the min-max ranges for a variable
// UNSET - Is the initialised/default/invalid value, depending on the variables usage
//
// -Constant/unchanging values are included in the data, such as 'maxRPM', 'fuelCapacity' - this is done to allow percentage calculations.
//
// -Also included are 12 unique enumerated types, to be used against the mentioned flag/state variables
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


// *** Types ***

// Header version number to test against
enum
{
SHARED_MEMORY_VERSION = 5
};

// Maximum allowed length of string
enum
{
STRING_LENGTH_MAX = 64
};

// Maximum number of general participant information allowed to be stored in memory-mapped file
enum
{
STORED_PARTICIPANTS_MAX = 64
};

// Tyres
enum
{
TYRE_FRONT_LEFT = 0,
TYRE_FRONT_RIGHT,
TYRE_REAR_LEFT,
TYRE_REAR_RIGHT,
//--------------
TYRE_MAX
};

// Vector
enum
{
VEC_X = 0,
VEC_Y,
VEC_Z,
//-------------
VEC_MAX
};

// (Type#1) GameState (to be used with 'mGameState')
enum
{
GAME_EXITED = 0,
GAME_FRONT_END,
GAME_INGAME_PLAYING,
GAME_INGAME_PAUSED,
//-------------
GAME_MAX
};

// (Type#2) Session state (to be used with 'mSessionState')
enum
{
SESSION_INVALID = 0,
SESSION_PRACTICE,
SESSION_TEST,
SESSION_QUALIFY,
SESSION_FORMATION_LAP,
SESSION_RACE,
SESSION_TIME_ATTACK,
//-------------
SESSION_MAX
};

// (Type#3) RaceState (to be used with 'mRaceState')
enum
{
RACESTATE_INVALID,
RACESTATE_NOT_STARTED,
RACESTATE_RACING,
RACESTATE_FINISHED,
RACESTATE_DISQUALIFIED,
RACESTATE_RETIRED,
RACESTATE_DNF,
//-------------
RACESTATE_MAX
};

// (Type#4) Current Sector (to be used with 'mCurrentSector')
enum
{
SECTOR_INVALID = 0,
SECTOR_START,
SECTOR_SECTOR1,
SECTOR_SECTOR2,
SECTOR_FINISH,
SECTOR_STOP,
//-------------
SECTOR_MAX
};

// (Type#5) Flag Colours (to be used with 'mHighestFlagColour')
enum
{
FLAG_COLOUR_NONE = 0, // Not used for actual flags, only for some query functions
FLAG_COLOUR_GREEN, // End of danger zone, or race started
FLAG_COLOUR_BLUE, // Faster car wants to overtake the participant
FLAG_COLOUR_WHITE, // Approaching a slow car
FLAG_COLOUR_YELLOW, // Danger on the racing surface itself
FLAG_COLOUR_DOUBLE_YELLOW, // Danger that wholly or partly blocks the racing surface
FLAG_COLOUR_BLACK, // Participant disqualified
FLAG_COLOUR_CHEQUERED, // Chequered flag
//-------------
FLAG_COLOUR_MAX
};

// (Type#6) Flag Reason (to be used with 'mHighestFlagReason')
enum
{
FLAG_REASON_NONE = 0,
FLAG_REASON_SOLO_CRASH,
FLAG_REASON_VEHICLE_CRASH,
FLAG_REASON_VEHICLE_OBSTRUCTION,
//-------------
FLAG_REASON_MAX
};

// (Type#7) Pit Mode (to be used with 'mPitMode')
enum
{
PIT_MODE_NONE = 0,
PIT_MODE_DRIVING_INTO_PITS,
PIT_MODE_IN_PIT,
PIT_MODE_DRIVING_OUT_OF_PITS,
PIT_MODE_IN_GARAGE,
//-------------
PIT_MODE_MAX
};

// (Type#8) Pit Stop Schedule (to be used with 'mPitSchedule')
enum
{
PIT_SCHEDULE_NONE = 0, // Nothing scheduled
PIT_SCHEDULE_STANDARD, // Used for standard pit sequence
PIT_SCHEDULE_DRIVE_THROUGH, // Used for drive-through penalty
PIT_SCHEDULE_STOP_GO, // Used for stop-go penalty
//-------------
PIT_SCHEDULE_MAX
};

// (Type#9) Car Flags (to be used with 'mCarFlags')
enum
{
CAR_HEADLIGHT = (1<<0),
CAR_ENGINE_ACTIVE = (1<<1),
CAR_ENGINE_WARNING = (1<<2),
CAR_SPEED_LIMITER = (1<<3),
CAR_ABS = (1<<4),
CAR_HANDBRAKE = (1<<5),
};

// (Type#10) Tyre Flags (to be used with 'mTyreFlags')
enum
{
TYRE_ATTACHED = (1<<0),
TYRE_INFLATED = (1<<1),
TYRE_IS_ON_GROUND = (1<<2),
};

// (Type#11) Terrain Materials (to be used with 'mTerrain')
enum
{
TERRAIN_ROAD = 0,
TERRAIN_LOW_GRIP_ROAD,
TERRAIN_BUMPY_ROAD1,
TERRAIN_BUMPY_ROAD2,
TERRAIN_BUMPY_ROAD3,
TERRAIN_MARBLES,
TERRAIN_GRASSY_BERMS,
TERRAIN_GRASS,
TERRAIN_GRAVEL,
TERRAIN_BUMPY_GRAVEL,
TERRAIN_RUMBLE_STRIPS,
TERRAIN_DRAINS,
TERRAIN_TYREWALLS,
TERRAIN_CEMENTWALLS,
TERRAIN_GUARDRAILS,
TERRAIN_SAND,
TERRAIN_BUMPY_SAND,
TERRAIN_DIRT,
TERRAIN_BUMPY_DIRT,
TERRAIN_DIRT_ROAD,
TERRAIN_BUMPY_DIRT_ROAD,
TERRAIN_PAVEMENT,
TERRAIN_DIRT_BANK,
TERRAIN_WOOD,
TERRAIN_DRY_VERGE,
TERRAIN_EXIT_RUMBLE_STRIPS,
TERRAIN_GRASSCRETE,
TERRAIN_LONG_GRASS,
TERRAIN_SLOPE_GRASS,
TERRAIN_COBBLES,
TERRAIN_SAND_ROAD,
TERRAIN_BAKED_CLAY,
TERRAIN_ASTROTURF,
TERRAIN_SNOWHALF,
TERRAIN_SNOWFULL,
//-------------
TERRAIN_MAX
};

// (Type#12) Crash Damage State (to be used with 'mCrashState')
enum
{
CRASH_DAMAGE_NONE = 0,
CRASH_DAMAGE_OFFTRACK,
CRASH_DAMAGE_LARGE_PROP,
CRASH_DAMAGE_SPINNING,
CRASH_DAMAGE_ROLLING,
//-------------
CRASH_MAX
};

// (Type#13) ParticipantInfo struct (to be used with 'mParticipantInfo')
typedef struct
{
bool mIsActive;
char mName[STRING_LENGTH_MAX]; // [ string ]
float mWorldPosition[VEC_MAX]; // [ UNITS = World Space X Y Z ]
float mCurrentLapDistance; // [ UNITS = Metres ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
unsigned int mRacePosition; // [ RANGE = 1->... ] [ UNSET = 0 ]
unsigned int mLapsCompleted; // [ RANGE = 0->... ] [ UNSET = 0 ]
unsigned int mCurrentLap; // [ RANGE = 0->... ] [ UNSET = 0 ]
unsigned int mCurrentSector; // [ enum (Type#4) Current Sector ]
} ParticipantInfo;


// *** Shared Memory ***

typedef struct
{
// Version Number
unsigned int mVersion; // [ RANGE = 0->... ]
unsigned int mBuildVersionNumber; // [ RANGE = 0->... ] [ UNSET = 0 ]

// Game States
unsigned int mGameState; // [ enum (Type#1) Game state ]
unsigned int mSessionState; // [ enum (Type#2) Session state ]
unsigned int mRaceState; // [ enum (Type#3) Race State ]

// Participant Info
int mViewedParticipantIndex; // [ RANGE = 0->STORED_PARTICIPANTS_MAX ] [ UNSET = -1 ]
int mNumParticipants; // [ RANGE = 0->STORED_PARTICIPANTS_MAX ] [ UNSET = -1 ]
ParticipantInfo mParticipantInfo[STORED_PARTICIPANTS_MAX]; // [ struct (Type#13) ParticipantInfo struct ]

// Unfiltered Input
float mUnfilteredThrottle; // [ RANGE = 0.0f->1.0f ]
float mUnfilteredBrake; // [ RANGE = 0.0f->1.0f ]
float mUnfilteredSteering; // [ RANGE = -1.0f->1.0f ]
float mUnfilteredClutch; // [ RANGE = 0.0f->1.0f ]

// Vehicle information
char mCarName[STRING_LENGTH_MAX]; // [ string ]
char mCarClassName[STRING_LENGTH_MAX]; // [ string ]

// Event information
unsigned int mLapsInEvent; // [ RANGE = 0->... ] [ UNSET = 0 ]
char mTrackLocation[STRING_LENGTH_MAX]; // [ string ]
char mTrackVariation[STRING_LENGTH_MAX]; // [ string ]
float mTrackLength; // [ UNITS = Metres ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]

// Timings
bool mLapInvalidated; // [ UNITS = boolean ] [ RANGE = false->true ] [ UNSET = false ]
float mBestLapTime; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mLastLapTime; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mCurrentTime; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mSplitTimeAhead; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mSplitTimeBehind; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mSplitTime; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mEventTimeRemaining; // [ UNITS = milli-seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mPersonalFastestLapTime; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mWorldFastestLapTime; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mCurrentSector1Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mCurrentSector2Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mCurrentSector3Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mFastestSector1Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mFastestSector2Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mFastestSector3Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mPersonalFastestSector1Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mPersonalFastestSector2Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mPersonalFastestSector3Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mWorldFastestSector1Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mWorldFastestSector2Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
float mWorldFastestSector3Time; // [ UNITS = seconds ] [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]

// Flags
unsigned int mHighestFlagColour; // [ enum (Type#5) Flag Colour ]
unsigned int mHighestFlagReason; // [ enum (Type#6) Flag Reason ]

// Pit Info
unsigned int mPitMode; // [ enum (Type#7) Pit Mode ]
unsigned int mPitSchedule; // [ enum (Type#8) Pit Stop Schedule ]

// Car State
unsigned int mCarFlags; // [ enum (Type#9) Car Flags ]
float mOilTempCelsius; // [ UNITS = Celsius ] [ UNSET = 0.0f ]
float mOilPressureKPa; // [ UNITS = Kilopascal ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mWaterTempCelsius; // [ UNITS = Celsius ] [ UNSET = 0.0f ]
float mWaterPressureKPa; // [ UNITS = Kilopascal ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mFuelPressureKPa; // [ UNITS = Kilopascal ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mFuelLevel; // [ RANGE = 0.0f->1.0f ]
float mFuelCapacity; // [ UNITS = Liters ] [ RANGE = 0.0f->1.0f ] [ UNSET = 0.0f ]
float mSpeed; // [ UNITS = Metres per-second ] [ RANGE = 0.0f->... ]
float mRpm; // [ UNITS = Revolutions per minute ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mMaxRPM; // [ UNITS = Revolutions per minute ] [ RANGE = 0.0f->... ] [ UNSET = 0.0f ]
float mBrake; // [ RANGE = 0.0f->1.0f ]
float mThrottle; // [ RANGE = 0.0f->1.0f ]
float mClutch; // [ RANGE = 0.0f->1.0f ]
float mSteering; // [ RANGE = -1.0f->1.0f ]
int mGear; // [ RANGE = -1 (Reverse) 0 (Neutral) 1 (Gear 1) 2 (Gear 2) etc... ] [ UNSET = 0 (Neutral) ]
int mNumGears; // [ RANGE = 0->... ] [ UNSET = -1 ]
float mOdometerKM; // [ RANGE = 0.0f->... ] [ UNSET = -1.0f ]
bool mAntiLockActive; // [ UNITS = boolean ] [ RANGE = false->true ] [ UNSET = false ]
int mLastOpponentCollisionIndex; // [ RANGE = 0->STORED_PARTICIPANTS_MAX ] [ UNSET = -1 ]
float mLastOpponentCollisionMagnitude; // [ RANGE = 0.0f->... ]
bool mBoostActive; // [ UNITS = boolean ] [ RANGE = false->true ] [ UNSET = false ]
float mBoostAmount; // [ RANGE = 0.0f->100.0f ]

// Motion & Device Related
float mOrientation[VEC_MAX]; // [ UNITS = Euler Angles ]
float mLocalVelocity[VEC_MAX]; // [ UNITS = Metres per-second ]
float mWorldVelocity[VEC_MAX]; // [ UNITS = Metres per-second ]
float mAngularVelocity[VEC_MAX]; // [ UNITS = Radians per-second ]
float mLocalAcceleration[VEC_MAX]; // [ UNITS = Metres per-second ]
float mWorldAcceleration[VEC_MAX]; // [ UNITS = Metres per-second ]
float mExtentsCentre[VEC_MAX]; // [ UNITS = Local Space X Y Z ]

// Wheels / Tyres
unsigned int mTyreFlags[TYRE_MAX]; // [ enum (Type#10) Tyre Flags ]
unsigned int mTerrain[TYRE_MAX]; // [ enum (Type#11) Terrain Materials ]
float mTyreY[TYRE_MAX]; // [ UNITS = Local Space Y ]
float mTyreRPS[TYRE_MAX]; // [ UNITS = Revolutions per second ]
float mTyreSlipSpeed[TYRE_MAX]; // [ UNITS = Metres per-second ]
float mTyreTemp[TYRE_MAX]; // [ UNITS = Celsius ] [ UNSET = 0.0f ]
float mTyreGrip[TYRE_MAX]; // [ RANGE = 0.0f->1.0f ]
float mTyreHeightAboveGround[TYRE_MAX]; // [ UNITS = Local Space Y ]
float mTyreLateralStiffness[TYRE_MAX]; // [ UNITS = Lateral stiffness coefficient used in tyre deformation ]
float mTyreWear[TYRE_MAX]; // [ RANGE = 0.0f->1.0f ]
float mBrakeDamage[TYRE_MAX]; // [ RANGE = 0.0f->1.0f ]
float mSuspensionDamage[TYRE_MAX]; // [ RANGE = 0.0f->1.0f ]
float mBrakeTempCelsius[TYRE_MAX]; // [ UNITS = Celsius ]
float mTyreTreadTemp[TYRE_MAX]; // [ UNITS = Kelvin ]
float mTyreLayerTemp[TYRE_MAX]; // [ UNITS = Kelvin ]
float mTyreCarcassTemp[TYRE_MAX]; // [ UNITS = Kelvin ]
float mTyreRimTemp[TYRE_MAX]; // [ UNITS = Kelvin ]
float mTyreInternalAirTemp[TYRE_MAX]; // [ UNITS = Kelvin ]

// Car Damage
unsigned int mCrashState; // [ enum (Type#12) Crash Damage State ]
float mAeroDamage; // [ RANGE = 0.0f->1.0f ]
float mEngineDamage; // [ RANGE = 0.0f->1.0f ]

// Weather
float mAmbientTemperature; // [ UNITS = Celsius ] [ UNSET = 25.0f ]
float mTrackTemperature; // [ UNITS = Celsius ] [ UNSET = 30.0f ]
float mRainDensity; // [ UNITS = How much rain will fall ] [ RANGE = 0.0f->1.0f ]
float mWindSpeed; // [ RANGE = 0.0f->100.0f ] [ UNSET = 2.0f ]
float mWindDirectionX; // [ UNITS = Normalised Vector X ]
float mWindDirectionY; // [ UNITS = Normalised Vector Y ]
float mCloudBrightness; // [ RANGE = 0.0f->... ]
} SharedMemory;


#endif // _SHARED_MEMORY_HPP_

SharedMemory header file: 207342

Sample implementations
207343
C#/WPF demo app by MikeyTT (https://bitbucket.org/MikeyTT/pcars-api-demo/overview).
C/C++ implementation by NLxAROSA (https://github.com/NLxAROSA/CREST).
Java/JNI howto/tutorial (http://forum.projectcarsgame.com/showthread.php?30903-Project-CARS-Shared-Memory-or-how-do-I-make-my-own-app&p=1025973&viewfull=1#post1025973).

EDIT: Update:


This field has been recently updated for the UDP streamer, it is also present in the shared memory API:



// (Type#9) Car Flags (to be used with 'mCarFlags')
enum
{
CAR_HEADLIGHT = (1<<0),
CAR_ENGINE_ACTIVE = (1<<1),
CAR_ENGINE_WARNING = (1<<2),
CAR_SPEED_LIMITER = (1<<3),
CAR_ABS = (1<<4),
CAR_HANDBRAKE = (1<<5),
CAR_STABILITY = (1<<6),
CAR_TRACTION_CONTROL = (1<<7),
};

Lars Rosenquist
12-06-2015, 09:55
reserved.

AfterAll14
18-06-2015, 12:31
We desperately need more data. Ride height, suspension load - at least. Downforce and drag of the cars would be nice to have to study physics of the game.

DauRacer
18-06-2015, 21:05
Seems the in game option has moved to Visuals->Hardware!

flynny75
18-06-2015, 22:40
We desperately need more data. Ride height, suspension load - at least. Downforce and drag of the cars would be nice to have to study physics of the game.

We have been asking for much more information for a while now... I think the API has been buried by post-release patches. Hopefully work will pick up on it again soon.

Lars Rosenquist
19-06-2015, 05:57
Seems the in game option has moved to Visuals->Hardware!
Updated. :)

Blackvault
29-06-2015, 14:10
I'm going to sticky this post.

Lars could you include any links to sample implementations in your first post?

Pete

AndyA
29-06-2015, 16:43
Is it safe to assume that ints, bools and enums will be 32 bits each?
In theory they could be 16 or 64 bits depending on the compiler settings used.

Also packing isn't specified but assuming 32bit ints it looks like everything will be dword aligned anyway.

Blackvault
29-06-2015, 18:20
Is it safe to assume that ints, bools and enums will be 32 bits each?
In theory they could be 16 or 64 bits depending on the compiler settings used.

Also packing isn't specified but assuming 32bit ints it looks like everything will be dword aligned anyway.

I think I've got my app set to 32bits for ints.

Pete

Lars Rosenquist
01-07-2015, 05:29
I'm going to sticky this post.

Lars could you include any links to sample implementations in your first post?

Pete

Done for the ones that have source code public. :)

flynny75
01-07-2015, 17:39
READING THE SHARED MEMORY WITH JAVA - AN EXAMPLE WITH VDASH
To start with, you're going to need a few things. I'm not going to assume anything, so lets start at the top. Here are the things you'll need:

Java
Eclipse
Eclipse CDT
MinGW-W64
VDash server repository


Installing Java

Download the Java installer from HERE (http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html). If you have a 64-bit OS, download the x64 version, as you're going to be building x86 and x64 DLLs later.
Run the installer, accept defaults (apart from if it asks to install adware.. I cant remember if it does)
Verify it works by opening a command window and running:

java -version
If it works, you should see something like:


C:\Users\Alex>java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

If you don't, you need to add the path to your java installation to your environment variables (https://docs.oracle.com/javase/tutorial/essential/environment/paths.html).
Hurray, you have Java installed!

Even if you already have Java installed, I recommend keeping it up to date, and making sure you don't have millions of versions installed.

Installing Eclipse
Eclipse is a development environment that does a lot for you, but not everything. It is the tool used to build the VDash server, and up until recently, the VDash apps (which have no made the transition to Android Studio)

Download Eclipse from their website (http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/marsr). Its just an archive, so extract it somewhere memorable.
Run it. It will ask you to pick a workspace location. Make a new folder. Put it somewhere memorable.
Yay, Eclipse is installed! You can now go crazy with Java.


Installing Eclipse CDT
CDT are the tools that allow the Eclipse Java environment to use C/C++ build tools, which are needed to create JNI DLLs to access the shared memory.

In Eclipse, go to 'Help > Install New Software'. Click 'Add' in the top right. Use 'Eclipse CDT' as the name, and 'http://download.eclipse.org/tools/cdt/releases/8.7' as the address, then click OK. Only the bare minimum CDT installation is required, so tick the top box and click next a few times. Accept a license, install it, and restart Eclipse
Wooooo CDT installed!


Almost there...
Installing MinGW-W64
MinGW-W64 is the toolchain that will build and link the x86 and x64 DLLs for us.

Download the online installer. (http://mingw-w64.org/doku.php/download/mingw-builds) Save it somewhere, you wont need it again
Run it, click next, and let it download the repository information. Once it has, it will show a list of options
Pick from the options:

x86_x64 as architecture
'sjlj' as the Exception
Leave the others as default

Click next, and pick somewhere for it to install. It wants to go in the Program Files folder, but I chose to move it to the root, with the full path being:


C:\mingw-w64\x86_64-5.1.0-posix-seh-rt_v4-rev0

Dont bother with start menu shortcuts...
Click next, let it download and unpack
Done!


Not long now...
Clone VDash-server repository

Using your favourite Git client (TortoiseGIT FTW), clone the VDash-server repository. Its available at: 'https://Flynny75@bitbucket.org/Flynny75/vdash-server.git'. Clone the repository into your Eclipse Workspace folder.
Open Eclipse, click 'File > Import > General > Existing projects into workspace'. Then browse to your Eclipse workspace folder, and click ok. Select all the projects. Make sure 'Copy projects into workspace' is NOT ticked.


One last thing...
Configuring Eclipse to use MinGW-W64
Eclipse comes with its own compiler, but we are going to use MinGW. So to do that, we need to tell Eclipse the right 'make' command, and where the MinGW installation is.

In Eclipse, right-click on the server project and click 'C/C++ Build' on the left. Enter a custom build command of 'mingw32-make'
Beneath that, select 'Environment Variables'. Edit the value for 'MINGW_HOME' to point to the directory of the MinGW installation. Mine is:


C:\mingw-w64\x86_64-5.1.0-posix-sjlj-rt_v4-rev0\mingw64

Edit the PATH variable to include the MINGW_PATH variable like so:


${MINGW_HOME}\bin;${Path}




Building
Using the green play button at the top of the Eclipse window, run the project. It will fail to run (it will complain about being unable to find libraries, but that's ok). Once its build, the .class should be available for the makefile. So now you should be able to right-click on the makefile in the JNI folder, and click 'Make Targets > Build'. This will display a list of make targets. Build 'all'. This should build all the required DLLs for accessing shared memory for a bunch of different games.

Then there's just the matter of explaining how it works...

Lars Rosenquist
02-07-2015, 05:36
http://media.giphy.com/media/wi8Ez1mwRcKGI/giphy.gif

flynny75
02-07-2015, 23:09
BOOM!

Really hope people actually contribute (aside from those who already have). Having someone else implement more game support would be pretty awesome

Lars Rosenquist
03-07-2015, 06:39
Awesome! Link added to first post.

flynny75
07-07-2015, 15:55
There is not an official SMS Project Cars companion app. Just go through the features of each and use whichever one sounds the best for you

flynny75
07-07-2015, 22:50
Cheers Flynny, I'm down to 2 now, Pcars dash and dash meter pro. The dash meter one doesn't show tire wear for pcars only ac from what I can gather so it's looking like my 2.99 will go to Pcars dash.

I have not used either for long enough so couldn't possibly comment :P

Out of interest... what was it about VDash that put you off?

flynny75
07-07-2015, 23:08
Importing my own stuff, I'm not into all that, I just want to set it up and go.

I see... well I'm sure you wont be disappointed with either.

/offtopic

I wonder if the PCars 1 API will see any love now with work started on PCars 2... we are still waiting on a lot of data to be added...

Lars Rosenquist
08-07-2015, 05:08
I'm pretty sure it will, but I guess it's not too high on the priority list yet, so best be patient. :)

R74NN
10-08-2015, 19:34
Hey Lars, the structure in the OP is not the latest I think. There are some GameStates missing. Unfortunately I can't find neither here or on the WMD forum original SMS posts with the structure.

Lars Rosenquist
11-08-2015, 05:38
Thanks for the headsup, updated it with the contents of the V5 header file. :)

jimmyb_84
25-08-2015, 08:51
Very interesting thread, however I'm a complete newbie to programming but would love to create an app that incorporates my pit strategy calculator, this could update with live data as the race develops for example if it rains the fuel consumption will and pit stop lap will change along with fuel needed in pits for longer races.

Also with the las test developments regarding the possibility of PS4 apps I'd love to use it myself. I'd be more than happy for a current developer to add the feature to any current app, I don't want anything in return apart from the use of the app.

info here
http://forum.projectcarsgame.com/showthread.php?35604-GT3-Strategy-Testing-and-info-(NOW-INCLUDES-DOWNLOAD)

R74NN
25-08-2015, 10:16
What real-time data would be needed from the API?

jimmyb_84
25-08-2015, 11:24
What real-time data would be needed from the API?

fuel consumption is the main one needed, current lap, average lap time help work out time gained/lost.

If race distance (laps) fuel tank size needs to be pre entered or the info could be pulled from the game that would be better. Not a lot is needed, I can do a more detailed response including formulas later

R74NN
25-08-2015, 11:30
I could put together a simple desktop app, that could run on the second monitor or in the background. But I need complete info how it should work.

jimmyb_84
25-08-2015, 11:44
I could put together a simple desktop app, that could run on the second monitor or in the background. But I need complete info how it should work.

see my spreadsheet for everything (see sig for download Open Office) , where there is input if they could be from the game it would make it more accurate. Could this be compatible with PS4 as that's the platform I'm on, I know early discussions have happened?

thank you

R74NN
25-08-2015, 11:51
Nope, PS4 can't take advantage of the API or broadcast any information from the game. It will have to be run on the PC the game runs on. Another possibility would be make it a mobile application (I'm only doing Windows Phone 8.1/10 apps though) - but it would be completely offline, no information taken from the game, you would have to enter all data manually, just like your spreadsheet.

jimmyb_84
25-08-2015, 12:03
Nope, PS4 can't take advantage of the API or broadcast any information from the game. It will have to be run on the PC the game runs on. Another possibility would be make it a mobile application (I'm only doing Windows Phone 8.1/10 apps though) - but it would be completely offline, no information taken from the game, you would have to enter all data manually, just like your spreadsheet.

you may find this interesting

http://forum.projectcarsgame.com/showthread.php?24031-Unlikely-Second-Screen-amp-Apps-on-PS4&p=1094407&viewfull=1#post1094407

R74NN
25-08-2015, 13:56
Well,

1. it is not confirmed Sony would officially allow something like that, even if it would work in the end and
2. I don't have a PS4 and
3. I'm a Microsoft platform developer and
4. taking all above in consideration, I probably won't be the right person for the job :)

jimmyb_84
26-08-2015, 09:08
Well,

1. it is not confirmed Sony would officially allow something like that, even if it would work in the end and
2. I don't have a PS4 and
3. I'm a Microsoft platform developer and
4. taking all above in consideration, I probably won't be the right person for the job :)

I appreciate the responds, thank you

artao
22-09-2015, 16:31
hmm ... I just tried using MoTec i2, and it didn't seem to work. Is this software compatible with pCars? It's my preferred post-race telemetry analysis app. Always used it with Race 07 and GTR2.
otherwise I guess I'll use pCars Profiler

redo
31-10-2015, 09:46
I want make a app to share the info to comport,Im make arduino interface on a spi display.
https://db.tt/etoRs2rb

Tim Mann
21-11-2015, 19:44
This field has been recently updated for the UDP streamer, it is also present in the shared memory API:



// (Type#9) Car Flags (to be used with 'mCarFlags')
enum
{
CAR_HEADLIGHT = (1<<0),
CAR_ENGINE_ACTIVE = (1<<1),
CAR_ENGINE_WARNING = (1<<2),
CAR_SPEED_LIMITER = (1<<3),
CAR_ABS = (1<<4),
CAR_HANDBRAKE = (1<<5),
CAR_STABILITY = (1<<6),
CAR_TRACTION_CONTROL = (1<<7),
};

jimmyb_84
23-11-2015, 10:33
Hi all, seeing as API has now changed UDP I'm wondering if anyone knows of any basic how to videos, just had a quick search but only found what and how it works, not how to create a receiver. I'm after something really basic but want to have a play.

I'm a complete programming novice, I don't even know what software I need to start with. All helped welcomed

tonaz
23-11-2015, 11:41
Hello!
Is there a way to "read" the ideal racing line color and transmit it to an external application i am programming?
The idea is to make a circle that changes color indicating the braking point for training, without having that ugly line on the track.

Lars Rosenquist
26-11-2015, 10:34
This field has been recently updated for the UDP streamer, it is also present in the shared memory API:



// (Type#9) Car Flags (to be used with 'mCarFlags')
enum
{
CAR_HEADLIGHT = (1<<0),
CAR_ENGINE_ACTIVE = (1<<1),
CAR_ENGINE_WARNING = (1<<2),
CAR_SPEED_LIMITER = (1<<3),
CAR_ABS = (1<<4),
CAR_HANDBRAKE = (1<<5),
CAR_STABILITY = (1<<6),
CAR_TRACTION_CONTROL = (1<<7),
};
Added to the first post. For sake of completeness, can we get a complete updated SharedMemory.h? Also, if you guys are not maintaining the example, is it ok to slap an open-source license (e.g. Apache2 or MIT) on it and put it on GitHub?


Hi all, seeing as API has now changed UDP I'm wondering if anyone knows of any basic how to videos, just had a quick search but only found what and how it works, not how to create a receiver. I'm after something really basic but want to have a play.I'm up for creating a UDP example, but time is not my friend these days. ;)

bradleyland
15-12-2015, 05:12
Is there any documentation on the UDP stream? I captured some of the data using a simple Ruby script (below), but I'm not clear on how we're supposed to work with this. I see the sequence \x74\x04 repeated frequently after a long series of null data, but I'm not sure I can rely on this as the marker for beginning to parse data. Can anyone shed some light?

For some background, I'm a Ruby programmer who is interested in toying with the data stream. I'm not sure I'll ever release a product, but I think it would be kind of cool to mess around with the data building my own data logger.


#!/usr/bin/env ruby

require 'socket'

BasicSocket.do_not_reverse_lookup = true

client = UDPSocket.new
client.bind('0.0.0.0', 5606)

bucket = ""

begin
loop do
data, addr = client.recvfrom(1024) # if this number is too low it will drop the larger packets and never give them to you
bucket << data
end
rescue Interrupt
File.open 'pcars.dump', 'wb' do |file|
file.write bucket
end
end

client.close

Excerpt of captured data:


0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
7404 1c12 0001 0000 00fc 0900 0000 80bf
0000 80bf 0000 80bf 0000 80bf 0000 80bf
0000 0000 0000 80bf 0000 80bf da9e b943
0000 80bf 0000 80bf 0000 80bf 0000 80bf
0000 80bf 0000 80bf 0000 80bf 0000 80bf
0000 80bf 71fd 1843 b1f2 0643 249b a642
0000 0000 2500 4000 2500 2400 3a00 0a64
ff00 ff00 9a99 193f 0000 0000 8404 3a20
6000 ff00 feda e244 7836 78bd 725b 8f3d

memoric77
15-12-2015, 15:24
I want make a app to share the info to comport,Im make arduino interface on a spi display.
https://db.tt/etoRs2rb

Hi Redo,

can you tell me how you are reading the input from the UDP with arduino? I build a Buttonbox by myselfe but are completely new to arduino and reading informations from wifi. My first wifi modul is still on the way from china to germay right now :). How i will connect the shell so the leonardo or pro micro I will find out, but how is the sketch to read?

Would like to hear from you. I would like to use the input to let a LED turn on if a car is beside of me etc. .

Thx
Memo

BannockMille
15-12-2015, 18:47
n/m

BannockMille
16-12-2015, 01:45
Can someone help me understand the UDP data? It doesn't seem to match what I'm expected, and I'm hoping a little nudge will get me in the right direction (for the PC version, since there's no XBONE UDP right now).

For example, the first data in the UDP datagram (after the header and checksum information) is 7404 xxxx. I put "xxxx" there because that changes every packet, which according to the struct, shouldn't be happening (I'm idling at the menu screen for these packets). The first unsigned int (4 bytes) should be "mVersion"; however, 7404 hex unpacks to 875574327, which is slightly larger than the current version of 5. The second unsigned int (4 bytes) should be "mBuildVersionNumber"; however, unless my game is patching in rapid succession, that's wrong, too.

Can we get some decent documentation? Or an explanation of how the UDP data is actually structured? Some of us didn't get into the secret WMD club.

bradleyland
17-12-2015, 00:45
Can someone help me understand the UDP data? It doesn't seem to match what I'm expected, and I'm hoping a little nudge will get me in the right direction (for the PC version, since there's no XBONE UDP right now).

For example, the first data in the UDP datagram (after the header and checksum information) is 7404 xxxx. I put "xxxx" there because that changes every packet, which according to the struct, shouldn't be happening (I'm idling at the menu screen for these packets). The first unsigned int (4 bytes) should be "mVersion"; however, 7404 hex unpacks to 875574327, which is slightly larger than the current version of 5. The second unsigned int (4 bytes) should be "mBuildVersionNumber"; however, unless my game is patching in rapid succession, that's wrong, too.

Can we get some decent documentation? Or an explanation of how the UDP data is actually structured? Some of us didn't get into the secret WMD club.

I'm running in to a lot of the same questions. However, you should have a closer look at your interpretation. In hex, "\x74\x04" is only 2 bytes. Also, the value depends upon whether you're using big/little endian interpretation.

Big-endian (which is typical network byte order): 29700
Little-endian: 1140

That's all just academic though, because...

In the standard Windows C world, the 'unsigned int' type is 4 bytes, so (just like you) I'm assuming that's the width we should be looking at. As you noted, that doesn't make any sense when you look at the data we're getting, because the 3rd and 4th bytes are constantly changing. Out of curiosity, I set my game's UDP streaming rate to "9", which causes the game to transmit once per second. Then, using Wireshark, I captured four transmissions of data. I then compared the values using big-endian and little-endian interpretation to see if either made more sense:


Sample Hex Type Dec Delta
1 \x74\x04\xEC\x01 uint32be 1946479617
2 \x74\x04\xF0\x01 uint32be 1946480641 -1024
3 \x74\x04\xF4\x01 uint32be 1946481665 -1024
4 \x74\x04\xF8\x01 uint32be 1946482689 -1024

Sample Hex Type Dec Delta
1 \x74\x04\xEC\x01 uint32le 32244852
2 \x74\x04\xF0\x01 uint32le 32506996 -262144
3 \x74\x04\xF4\x01 uint32le 32769140 -262144
4 \x74\x04\xF8\x01 uint32le 33031284 -262144


Big-endian is making a lot of sense. I'm thinking that the first four bytes are a sequence indicator of some sort. I've adjusted my UDP rate to 8 and am going to do some further analysis once I get back from dinner.

I really do wish there were some real documentation for this stuff though. The guys who have already made apps must be much smarter than me.

bradleyland
17-12-2015, 03:11
So, if it's not obvious from the above, the 1st and 2nd bytes don't appear to change from record to record. The third byte increments by 4 with each record that is transmitted. I just did a sampling at settings 8 (200ms interval) and 9 (1000ms interval), and the increment is 4 in both:

Sample at setting 8, 3rd byte
28
2c
30
34

Sample at setting 9, 3rd byte
ec
f0
f4
f8

These samples were taken while sitting in the menus, so there's something more to this than just the SharedMemory.h struct.

Tim Mann
17-12-2015, 11:11
It's fully documented here:

http://forum.projectcarsgame.com/showthread.php?40113-COMPLETE-Companion-app-UDP-streaming

bradleyland
17-12-2015, 13:41
Thanks, Tim!

mr_belowski
17-12-2015, 14:56
My PC (C#) code is open source, you're welcome to have a rummage around in here https://github.com/mrbelowski/r3e_crewchief_v3. This cheats a little though and just dumps the byte array straight into a C# struct so it only has to get into fiddling with the bytes when 2 or more values are packed into the same single byte.

The closed source Android port gets the byte array from the datagram then does



// rawData[0] and [1] are version information
int frameTypeAndSequence = rawData[2] & 0xFF;
int frameType = frameTypeAndSequence & 3;// 0, 1, or 2
int sequence = frameTypeAndSequence >> 2; // the sequence number in the type 0 packets



it then has to manually unpack the byte array into an object, iterating over the byte array and keeping an offset value each time it gets another value from the array - stuff like




private int getNextUInt8() {
int i = this.data[this.offset] & 0xFF;
this.offset++;
return i;
}
private int getNextInt8() {
int i = this.data[this.offset];
this.offset++;
return i;
}

private float getNextFloat() {
float f = ByteBuffer.wrap(this.data, this.offset, 4).order(ByteOrder.LITTLE_ENDIAN).getFloat();
this.offset = this.offset + 4;
return f;
}


There are a few more of these helper methods that retrieve a Java type from one or more bytes and increment the counters as they go along. It's all quite fiddly and error-prone :(

The calling code can then do stuff like this:



public void processRawData(byte[] rawData) {
// start at 3 as we don't care about the build / version number (0 & 1) and the sequence and packet type (2)
this.offset = 3;
this.data = rawData;
int gameAndSessionState = getNextUInt8();
mGameState = gameAndSessionState & 7;
mSessionState = gameAndSessionState >> 4;
mViewedParticipantIndex = getNextInt8();
mNumParticipants = getNextInt8();

bradleyland
17-12-2015, 17:03
It seems odd that the shared memory API and the UDP stream API are documented in separate forums. I searched quite a bit in the 'PC - Technical Help & Support' section for UDP stream information to no avail. When Tim posted the link above, I was initially puzzled as to why I didn't find the UDP documentation in my searches. Then I noticed that the UDP thread is in the 'General Discussion' forum.

Given the importance of both the shared memory and UDP stream documentation to application developers, would it be possible to get the UDP stream sticky'd to 'PC - Technical Help & Support' forum as well? If not, maybe Lars add a link to the UDP thread at the bottom of the first post?

Lars Rosenquist
18-12-2015, 07:56
I added a small section about UDP with a link to the thread Tim mentioned.

bradleyland
20-12-2015, 21:24
My PC (C#) code is open source, you're welcome to have a rummage around in here https://github.com/mrbelowski/r3e_crewchief_v3. This cheats a little though and just dumps the byte array straight into a C# struct so it only has to get into fiddling with the bytes when 2 or more values are packed into the same single byte.

The closed source Android port gets the byte array from the datagram then does



// rawData[0] and [1] are version information
int frameTypeAndSequence = rawData[2] & 0xFF;
int frameType = frameTypeAndSequence & 3;// 0, 1, or 2
int sequence = frameTypeAndSequence >> 2; // the sequence number in the type 0 packets



it then has to manually unpack the byte array into an object, iterating over the byte array and keeping an offset value each time it gets another value from the array - stuff like




private int getNextUInt8() {
int i = this.data[this.offset] & 0xFF;
this.offset++;
return i;
}
private int getNextInt8() {
int i = this.data[this.offset];
this.offset++;
return i;
}

private float getNextFloat() {
float f = ByteBuffer.wrap(this.data, this.offset, 4).order(ByteOrder.LITTLE_ENDIAN).getFloat();
this.offset = this.offset + 4;
return f;
}


There are a few more of these helper methods that retrieve a Java type from one or more bytes and increment the counters as they go along. It's all quite fiddly and error-prone :(

The calling code can then do stuff like this:



public void processRawData(byte[] rawData) {
// start at 3 as we don't care about the build / version number (0 & 1) and the sequence and packet type (2)
this.offset = 3;
this.data = rawData;
int gameAndSessionState = getNextUInt8();
mGameState = gameAndSessionState & 7;
mSessionState = gameAndSessionState >> 4;
mViewedParticipantIndex = getNextInt8();
mNumParticipants = getNextInt8();


Wow! I can't tell you how much I appreciate you open-sourcing your code. I'm a Ruby programmer, so all the C stuff is pretty deep for me, but I have uncovered some interesting things about the way TelemetryData is packed in the UDP stream. I'm using a Ruby library called BinData (https://github.com/dmendel/bindata) to parse the stream (example Gist below). I quickly stumbled upon the fiddly bits you're referring to. What's interesting is that it's really only fiddly if you treat the values as the types specified in the TelemetryData examples. If your library supports additional types (outside of the standard int[I]N, uintN, etc), you can actually unpack much of the data directly.

For example the sGameSessionState field is specified as uint8 in the sTelemetryData struct.


u8 sGameSessionState; // 3

However, in we can see that this is actually a packed set of bytes (composed of two 4-bit values) when we look at how sGameSessionState is created from the SharedMemory struct:


// Game state
mTelemetryData.sGameSessionState=((u8)pMemory->mGameState)|(((u8)pMemory->mSessionState)<<4); // (enum 3 bits/enum 3 bits)->u8

Initially, I was specifying sGameSessionState as a uint8 using the BinData library, then unpacking the bits, but after I started dissecting this code, I shifted strategies. Instead, I used BinData's bit4 data type to extract 4 bytes at a time.

I'm not sure if anything like BinData exists for C#, but it's made working with this UDP payload much easier for me.

https://gist.github.com/bradland/91046d8cb770e201daec#file-pcars_net-rb

I_am_Andre
07-06-2016, 15:29
Hi guys,
would you please tell me what is the main difference between mLocalAcceleration and mWorldAcceleration in the game data?

Scott Mullin
09-08-2016, 15:33
I'm not sure if anyone is monitoring this particular section in the forum but I am going to post anyway. Has anyone noticed that sometimes other real drivers are not in the data stream? With the assistance of some very talented people here, I have put a little visual studio app together that reads the data stream and writes it into a text file as a log that I later load into a database and use for scoring. We have run 7 races with no issues and all of a sudden, last night none of the other real drivers were ever reported in the telemetry at all for any of the sessions. I have not made any changes to my app that reads the data since the first event. Just curious if anyone else has ever seen this activity.

Chawabax
09-08-2016, 21:00
I'm not sure if anyone is monitoring this particular section in the forum but I am going to post anyway. Has anyone noticed that sometimes other real drivers are not in the data stream? With the assistance of some very talented people here, I have put a little visual studio app together that reads the data stream and writes it into a text file as a log that I later load into a database and use for scoring. We have run 7 races with no issues and all of a sudden, last night none of the other real drivers were ever reported in the telemetry at all for any of the sessions. I have not made any changes to my app that reads the data since the first event. Just curious if anyone else has ever seen this activity.

What do you mean with "OTHER real drivers" ?
Your data were correct in the telemetry but no other driver data on it?
or no data at all ?

UDP or shared memory?

Scott Mullin
11-08-2016, 12:33
I am reading the shared memory model. We typically add in some AI cars to the mix just to bring the field higher. My other real world non-ai drivers were not reported in the telemetry for some odd reason, just myself as the host and all the AI cars. This is the first time this has happened in probably 20 races.

bigj_pcars
12-12-2016, 08:56
hi guys

im working on some opengl overlays for pcars in windowed mode
got everything running so far
and i wanted to display the antilock, stability and tractioncontrol status
though the sharedmemory api is updated (v5) with access to stability and tractioncontrol sharedmemory.h (v5, latest?) is not
there is sharedData->mAntiLockActive but it doesnt work (?)
(maybe im doing something wrong)
every other data i can display without problems

is there an even more updated ( :) ) sharedmemory.h

thx ;)

Edit: got it working now: ABS SC and TC show up only when triggered

thx again :))

naldin
27-01-2017, 13:29
Hi, I'm working on motion cockpit prototype with Arduino, but when I looked the "SharedMemory.h" I didn't find g-force parameter. There will be this option in the future? In the meantime, what can I use for side and longitude roll? I tested "mAngularVelocity[1]" and it worked well for Y axis (side roll), but for longitude roll I didn't find anything. If I can make everything work well I will post here for everyone, my idea is just learning and I want shared it.

Thank you,
Ronaldo

naldin
09-03-2017, 13:56
Hi, my project is in github as naldin/SimArduino I can't post link here. :)