Added proof-of-concept client application

This commit is contained in:
Mark van Renswoude 2017-08-31 23:09:03 +02:00
parent 1c0ecea038
commit f7c199eb56
9 changed files with 4667 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
AssettoCorsa/source/__history
AssettoCorsa/*.dproj.local
AssettoCorsa/bin
AssettoCorsa/lib

View File

@ -0,0 +1,19 @@
program AssettoCorsaSF;
uses
Vcl.Forms,
MainFrm in 'source\MainFrm.pas' {MainForm},
AssettoCorsa.SharedMemory in 'source\AssettoCorsa.SharedMemory.pas',
CPort in 'source\CPort.pas';
{$R *.res}
var
MainForm: TMainForm;
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.

View File

@ -0,0 +1,155 @@
 <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectGuid>{3CBA51E1-33C8-4599-8659-3A1F26AA5E70}</ProjectGuid>
<ProjectVersion>13.4</ProjectVersion>
<FrameworkType>VCL</FrameworkType>
<MainSource>AssettoCorsaSF.dpr</MainSource>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
<Base_Win64>true</Base_Win64>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<Manifest_File>None</Manifest_File>
<VerInfo_Locale>1043</VerInfo_Locale>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<DCC_UsePackage>bindcompfmx;fmx;rtl;dbrtl;IndySystem;DbxClientDriver;bindcomp;inetdb;DBXInterBaseDriver;DataSnapCommon;DataSnapClient;DataSnapServer;DataSnapProviderClient;xmlrtl;DbxCommonDriver;IndyProtocols;DBXMySQLDriver;dbxcds;soaprtl;FMXTee;bindengine;DBXOracleDriver;CustomIPTransport;dsnap;DBXInformixDriver;IndyCore;FmxTeeUI;DBXFirebirdDriver;inet;inetdbxpress;DBXSybaseASADriver;IPIndyImpl;dbexpress;DataSnapIndy10ServerTransport;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_E>false</DCC_E>
<DCC_N>false</DCC_N>
<DCC_S>false</DCC_S>
<DCC_F>false</DCC_F>
<DCC_K>false</DCC_K>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win64)'!=''">
<DCC_UsePackage>DBXOdbcDriver;DBXSybaseASEDriver;vclimg;vclactnband;vcldb;bindcompvcl;vcldsnap;vclie;vcltouch;DBXDb2Driver;websnap;VclSmp;vcl;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;$(DCC_UsePackage)</DCC_UsePackage>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<DCC_ExeOutput>.\bin\x86</DCC_ExeOutput>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<DCC_UsePackage>madBasic_;vcldbx;TeeDB;vclib;inetdbbde;Tee;DBXOdbcDriver;madDisAsm_;svnui;ibxpress;DBXSybaseASEDriver;vclimg;vclactnband;vcldb;TeeUI;bindcompvcl;vcldsnap;vclie;madExcept_;vcltouch;DBXDb2Driver;websnap;VclSmp;vcl;DataSnapConnectors;CloudService;DBXMSSQLDriver;dsnapcon;vclx;webdsnap;svn;bdertl;VirtualTreesR;$(DCC_UsePackage)</DCC_UsePackage>
<DCC_DcuOutput>.\lib\x86</DCC_DcuOutput>
<VerInfo_Locale>1033</VerInfo_Locale>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_Optimize>false</DCC_Optimize>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Locale>1033</VerInfo_Locale>
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
<DCC_DebugInformation>false</DCC_DebugInformation>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="source\MainFrm.pas">
<Form>MainForm</Form>
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="source\AssettoCorsa.SharedMemory.pas"/>
<DCCReference Include="source\CPort.pas"/>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType/>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">AssettoCorsaSF.dpr</Source>
</Source>
<VersionInfo>
<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
<VersionInfo Name="MajorVer">1</VersionInfo>
<VersionInfo Name="MinorVer">0</VersionInfo>
<VersionInfo Name="Release">0</VersionInfo>
<VersionInfo Name="Build">0</VersionInfo>
<VersionInfo Name="Debug">False</VersionInfo>
<VersionInfo Name="PreRelease">False</VersionInfo>
<VersionInfo Name="Special">False</VersionInfo>
<VersionInfo Name="Private">False</VersionInfo>
<VersionInfo Name="DLL">False</VersionInfo>
<VersionInfo Name="Locale">1043</VersionInfo>
<VersionInfo Name="CodePage">1252</VersionInfo>
</VersionInfo>
<VersionInfoKeys>
<VersionInfoKeys Name="CompanyName"/>
<VersionInfoKeys Name="FileDescription"/>
<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="InternalName"/>
<VersionInfoKeys Name="LegalCopyright"/>
<VersionInfoKeys Name="LegalTrademarks"/>
<VersionInfoKeys Name="OriginalFilename"/>
<VersionInfoKeys Name="ProductName"/>
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
<VersionInfoKeys Name="Comments"/>
</VersionInfoKeys>
</Delphi.Personality>
<Deployment/>
<Platforms>
<Platform value="Win64">False</Platform>
<Platform value="Win32">True</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
<Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
</Project>

Binary file not shown.

View File

@ -0,0 +1,333 @@
unit AssettoCorsa.SharedMemory;
interface
type
AC_STATUS = Integer;
TACStatus = AC_STATUS;
const
{ AC_STATUS }
AC_OFF = 0;
AC_REPLAY = 1;
AC_LIVE = 2;
AC_PAUSE = 3;
type
AC_SESSION_TYPE = Integer;
TACSessionType = AC_SESSION_TYPE;
const
{ AC_SESSION_TYPE }
AC_UNKNOWN = -1;
AC_PRACTICE = 0;
AC_QUALIFY = 1;
AC_RACE = 2;
AC_HOTLAP = 3;
AC_TIME_ATTACK = 4;
AC_DRIFT = 5;
AC_DRAG = 6;
type
AC_FLAG_TYPE = Integer;
TACFlagType = AC_FLAG_TYPE;
const
{ AC_FLAG_TYPE }
AC_NO_FLAG = 0;
AC_BLUE_FLAG = 1;
AC_YELLOW_FLAG = 2;
AC_BLACK_FLAG = 3;
AC_WHITE_FLAG = 4;
AC_CHECKERED_FLAG = 5;
AC_PENALTY_FLAG = 6;
type
TACSMPhysics = packed record
packetId: Integer;
gas: Single;
brake: Single;
fuel: Single;
gear: Integer;
rpms: Integer;
steerAngle: Single;
speedKmh: Single;
velocity: array[0..2] of Single;
accG: array[0..2] of Single;
wheelSlip: array[0..3] of Single;
wheelLoad: array[0..3] of Single;
wheelsPressure: array[0..3] of Single;
wheelAngularSpeed: array[0..3] of Single;
tyreWear: array[0..3] of Single;
tyreDirtyLevel: array[0..3] of Single;
tyreCoreTemperature: array[0..3] of Single;
camberRAD: array[0..3] of Single;
suspensionTravel: array[0..3] of Single;
drs: Single;
tc: Single;
heading: Single;
pitch: Single;
roll: Single;
cgHeight: Single;
carDamage: array[0..4] of Single;
umberOfTyresOut: Integer;
pitLimiterOn: Integer;
abs: Single;
kersCharge: Single;
kersInput: Single;
autoShifterOn: Integer;
rideHeigh: Single;
turboBoost: Single;
ballast: Single;
airDensity: Single;
airTemp: Single;
roadTemp: Single;
localAngularVelocity: array[0..2] of Single;
finalFF: Single;
performanceMeter: Single;
engineBrake: Integer;
ersRecoveryLevel: Integer;
ersPowerLevel: Integer;
ersHeatCharging: Integer;
ersIsCharging: Integer;
kersCurrentKJ: Single;
drsAvailable: Integer;
drsEnabled: Integer;
brakeTemp: array[0..3] of Single;
clutch: Single;
tyreTempI: array[0..3] of Single;
tyreTempM: array[0..3] of Single;
tyreTempO: array[0..3] of Single;
isAIControlled: Integer;
tyreContactPoint: array[0..3, 0..2] of Single;
tyreContactNormal: array[0..3, 0..2] of Single;
tyreContactHeading: array[0..3, 0..2] of Single;
brakeBias: Single;
end;
PACSMPhysics = ^TACSMPhysics;
TACSMGraphic = packed record
packetId: Integer;
status: TACStatus;
session: TACSessionType;
currentTime: array[0..14] of WideChar;
lastTime: array[0..14] of WideChar;
bestTime: array[0..14] of WideChar;
split: array[0..14] of WideChar;
completedLaps: Integer;
position: Integer;
iCurrentTime: Integer;
iLastTime: Integer;
iBestTime: Integer;
sessionTimeLeft: Single;
distanceTraveled: Single;
isInPit: Integer;
currentSectorIndex: Integer;
lastSectorTime: Integer;
numberOfLaps: Integer;
tyreCompound: array[0..32] of WideChar;
replayTimeMultiplier: Single;
normalizedCarPosition: Single;
carCoordinates: array[0..2] of Single;
penaltyTime: Single;
flag: TACFlagType;
idealLineOn: Integer;
isInPitLane: Integer;
surfaceGrip: Single;
end;
PACSMGraphic = ^TACSMGraphic;
TACSMStatic = packed record
smVersion: array[0..14] of WideChar;
acVersion: array[0..14] of WideChar;
// Session static info
numberOfSessions: Integer;
numCars: Integer;
carModel: array[0..32] of WideChar;
track: array[0..32] of WideChar;
playerName: array[0..32] of WideChar;
playerSurname: array[0..32] of WideChar;
playerNick: array[0..32] of WideChar;
sectorCount: Integer;
// Car static info
maxTorque: Single;
maxPower: Single;
maxRpm: Integer;
maxFuel: Single;
suspensionMaxTravel: array[0..3] of Single;
tyreRadius: array[0..3] of Single;
maxTurboBoost: Single;
deprecated_1: Single;
deprecated_2: Single;
penaltiesEnabled: Integer;
aidFuelRate: Single;
aidTireRate: Single;
aidMechanicalDamage: Single;
aidAllowTyreBlankets: Integer;
aidStability: Single;
aidAutoClutch: Integer;
aidAutoBlip: Integer;
hasDRS: Integer;
hasERS: Integer;
hasKERS: Integer;
kersMaxJ: Single;
engineBrakeSettingsCount: Integer;
ersPowerControllerCount: Integer;
trackSPlineLength: Single;
trackConfiguration: array[0..32] of WideChar;
ersMaxJ: Single;
end;
PACSMStatic = ^TACSMStatic;
const
ACSM_PHYSICS = 'Local\acpmf_physics';
ACSM_GRAPHICS = 'Local\acpmf_graphics';
ACSM_STATIC = 'Local\acpmf_static';
type
IAssettoCorsaSharedMemory = interface
['{D7C0E678-CB11-4C34-81EB-4AAD5737C44F}']
function GetPhysics(out APhysics: TACSMPhysics): Boolean;
function GetGraphic(out AGraphic: TACSMGraphic): Boolean;
function GetStatic(out AStatic: TACSMStatic): Boolean;
end;
function GetAssettoCorsaSharedMemory(): IAssettoCorsaSharedMemory;
implementation
uses
WinApi.Windows, System.SysUtils, System.Classes;
type
TACSMMapping = record
Handle: THandle;
Buffer: Pointer;
end;
TAssettoCorsaSharedMemory = class(TInterfacedObject, IAssettoCorsaSharedMemory)
private
FPhysicsMapping: TACSMMapping;
FGraphicMapping: TACSMMapping;
FStaticMapping: TACSMMapping;
protected
function OpenMapping(const AName: string; var AMapping: TACSMMapping; ASize: Integer): Boolean;
procedure CloseMapping(var AMapping: TACSMMapping);
public
destructor Destroy; override;
{ IACSM }
function GetPhysics(out APhysics: TACSMPhysics): Boolean;
function GetGraphic(out AGraphic: TACSMGraphic): Boolean;
function GetStatic(out AStatic: TACSMStatic): Boolean;
end;
function GetAssettoCorsaSharedMemory(): IAssettoCorsaSharedMemory;
begin
Result := TAssettoCorsaSharedMemory.Create;
end;
{ TACSM }
destructor TAssettoCorsaSharedMemory.Destroy;
begin
CloseMapping(FPhysicsMapping);
CloseMapping(FGraphicMapping);
CloseMapping(FStaticMapping);
inherited;
end;
function TAssettoCorsaSharedMemory.GetPhysics(out APhysics: TACSMPhysics): Boolean;
begin
Result := OpenMapping(ACSM_PHYSICS, FPhysicsMapping, SizeOf(TACSMPhysics));
if Result then
APhysics := PACSMPhysics(FPhysicsMapping.Buffer)^;
end;
function TAssettoCorsaSharedMemory.GetGraphic(out AGraphic: TACSMGraphic): Boolean;
begin
Result := OpenMapping(ACSM_GRAPHICS, FGraphicMapping, SizeOf(TACSMGraphic));
if Result then
AGraphic := PACSMGraphic(FGraphicMapping.Buffer)^;
end;
function TAssettoCorsaSharedMemory.GetStatic(out AStatic: TACSMStatic): Boolean;
begin
Result := OpenMapping(ACSM_STATIC, FStaticMapping, SizeOf(TACSMStatic));
if Result then
AStatic := PACSMStatic(FStaticMapping.Buffer)^;
end;
function TAssettoCorsaSharedMemory.OpenMapping(const AName: string; var AMapping: TACSMMapping; ASize: Integer): Boolean;
var
handle: THandle;
buffer: Pointer;
begin
if AMapping.Handle <> 0 then
begin
Result := True;
exit;
end;
Result := False;
handle := OpenFileMapping(FILE_MAP_READ, False, PChar(AName));
if handle = 0 then
Exit;
buffer := MapViewOfFile(handle, FILE_MAP_READ, 0, 0, ASize);
if Assigned(buffer) then
begin
AMapping.Handle := handle;
AMapping.Buffer := buffer;
Result := True;
end else
begin
CloseHandle(handle);
RaiseLastOSError;
end;
end;
procedure TAssettoCorsaSharedMemory.CloseMapping(var AMapping: TACSMMapping);
begin
if AMapping.Handle <> 0 then
begin
UnmapViewOfFile(AMapping.Buffer);
CloseHandle(AMapping.Handle);
end;
end;
end.

View File

@ -0,0 +1,227 @@
{ ComPort Library global definitions }
{ Fixed up for Delphi 2009 by W.Postma. }
{$B-}
{$X+}
{$H+}
{$IFDEF VER110} { C++ Builder 3 }
{$ObjExportAll On}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER120} { Delphi 4 }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_4}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER125} { C++ Builder 4 }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_4}
{$ObjExportAll On}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER130} { Delphi 5 and C++ Builder 5 }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_5}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER140} { Delphi 6 and C++ Builder 6}
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_6}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER150} { Delphi 7 }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_7}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER160} { Delphi 8 }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_8}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER170} { Delphi 9 (2005) }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_2005_OR_HIGHER}
{$DEFINE DELPHI_2005}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER180} { Delphi 10 (2006) }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_2005_OR_HIGHER}
{$DEFINE DELPHI_2006_OR_HIGHER}
{$DEFINE DELPHI_2006}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER185} { Delphi 11 - 2007 }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_2005_OR_HIGHER}
{$DEFINE DELPHI_2006_OR_HIGHER}
{$DEFINE DELPHI_2007_OR_HIGHER}
{$DEFINE DELPHI_2007}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$IFDEF BCB}
{$DEFINE BCB11}
{$ObjExportAll On}
{$ENDIF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER190} { Delphi 12 2008 }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_2005_OR_HIGHER}
{$DEFINE DELPHI_2006_OR_HIGHER}
{$DEFINE DELPHI_2007_OR_HIGHER}
{$DEFINE DELPHI_2008_OR_HIGHER}
{$DEFINE DELPHI_2008}
{$DEFINE DELPHI_UNICODE}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER200} { Delphi 14 2009 UNICODE }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_2005_OR_HIGHER}
{$DEFINE DELPHI_2006_OR_HIGHER}
{$DEFINE DELPHI_2007_OR_HIGHER}
{$DEFINE DELPHI_2008_OR_HIGHER}
{$DEFINE DELPHI_2009_OR_HIGHER}
{$DEFINE DELPHI_2009}
{$DEFINE DELPHI_UNICODE}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{$IFDEF VER210} { Delphi 15 XE 2010 UNICODE }
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_2005_OR_HIGHER}
{$DEFINE DELPHI_2006_OR_HIGHER}
{$DEFINE DELPHI_2007_OR_HIGHER}
{$DEFINE DELPHI_2008_OR_HIGHER}
{$DEFINE DELPHI_2009_OR_HIGHER}
{$DEFINE DELPHI_2010_OR_HIGHER}
{$DEFINE DELPHI_2010}
{$DEFINE DELPHI_UNICODE}
{$IFDEF BCBNOTDELPHI}
{$ObjExportAll On}
{$ENDIF}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$DEFINE VER_RECOGNIZED}
{$ENDIF}
{... Lets try to make it work, for Delphi 2011 and later, right now...}
{$IFNDEF VER_RECOGNIZED}
{$DEFINE DELPHI_4_OR_HIGHER}
{$DEFINE DELPHI_5_OR_HIGHER}
{$DEFINE DELPHI_6_OR_HIGHER}
{$DEFINE DELPHI_7_OR_HIGHER}
{$DEFINE DELPHI_8_OR_HIGHER}
{$DEFINE DELPHI_2005_OR_HIGHER}
{$DEFINE DELPHI_2006_OR_HIGHER}
{$DEFINE DELPHI_2007_OR_HIGHER}
{$DEFINE DELPHI_2009_OR_HIGHER}
{$DEFINE DELPHI_2010_OR_HIGHER}
{$DEFINE DELPHI_UNICODE}
{$WARN UNSAFE_TYPE OFF}
{$WARN UNSAFE_CODE OFF}
{$WARN UNSAFE_CAST OFF}
{$ENDIF}
{$UNDEF VER_RECOGNIZED}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
object MainForm: TMainForm
Left = 0
Top = 0
BorderIcons = [biSystemMenu, biMinimize]
BorderStyle = bsSingle
Caption = 'SimulatorFans - Assetto Corsa'
ClientHeight = 309
ClientWidth = 645
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object PortComboBox: TComboBox
Left = 24
Top = 24
Width = 201
Height = 21
Style = csDropDownList
TabOrder = 0
end
object RefreshPortsButton: TButton
Left = 231
Top = 23
Width = 75
Height = 23
Caption = 'Refresh'
TabOrder = 1
OnClick = RefreshPortsButtonClick
end
object Button1: TButton
Left = 192
Top = 176
Width = 75
Height = 25
Caption = 'Connect'
TabOrder = 2
OnClick = Button1Click
end
object Button2: TButton
Left = 288
Top = 176
Width = 75
Height = 25
Caption = 'Fan 1 full'
TabOrder = 3
OnClick = Button2Click
end
object Button3: TButton
Left = 384
Top = 176
Width = 75
Height = 25
Caption = 'Fan 2 full'
TabOrder = 4
OnClick = Button3Click
end
object Button4: TButton
Left = 480
Top = 176
Width = 75
Height = 25
Caption = 'Off'
TabOrder = 5
OnClick = Button4Click
end
object Button5: TButton
Left = 288
Top = 207
Width = 75
Height = 25
Caption = 'Fan 1 half'
TabOrder = 6
OnClick = Button5Click
end
object Button6: TButton
Left = 384
Top = 207
Width = 75
Height = 25
Caption = 'Fan 2 half'
TabOrder = 7
OnClick = Button6Click
end
end

View File

@ -0,0 +1,187 @@
unit MainFrm;
interface
uses
System.Classes,
System.SysUtils,
Vcl.Controls,
Vcl.ExtCtrls,
Vcl.Forms,
Vcl.StdCtrls,
CPort;
type
TMainForm = class(TForm)
PortComboBox: TComboBox;
RefreshPortsButton: TButton;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
procedure FormCreate(Sender: TObject);
procedure RefreshPortsButtonClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
private
FComPort: TComPort;
FReceived: string;
FOnResponse: TProc<string>;
procedure OnReceiveChar(Sender: TObject; Count: Integer);
procedure RefreshPorts;
procedure SendCommand(const ACommand: string; AOnResponse: TProc<string>);
property ComPort: TComPort read FComPort;
end;
implementation
uses
System.RegularExpressions, Vcl.Dialogs;
{$R *.dfm}
procedure TMainForm.Button1Click(Sender: TObject);
begin
SendCommand('>Info',
procedure(Response: string)
var
match: TMatch;
begin
match := TRegEx.Match(Response, '<Info:Fans=(\d+)', [roSingleLine]);
if match.Success then
ShowMessage('Connected, got ' + match.Groups[1].Value + ' fan(s)')
else
ShowMessage('Invalid response: ' + Response);
end);
end;
procedure TMainForm.Button2Click(Sender: TObject);
begin
SendCommand('>SetFans:255,0',
procedure(Response: string)
begin
if Response <> '<SetFans' then
ShowMessage('Invalid response: ' + Response);
end);
end;
procedure TMainForm.Button3Click(Sender: TObject);
begin
SendCommand('>SetFans:0,255',
procedure(Response: string)
begin
if Response <> '<SetFans' then
ShowMessage('Invalid response: ' + Response);
end);
end;
procedure TMainForm.Button4Click(Sender: TObject);
begin
SendCommand('>SetFans:0,0',
procedure(Response: string)
begin
if Response <> '<SetFans' then
ShowMessage('Invalid response: ' + Response);
end);
end;
procedure TMainForm.Button5Click(Sender: TObject);
begin
SendCommand('>SetFans:128,0',
procedure(Response: string)
begin
if Response <> '<SetFans' then
ShowMessage('Invalid response: ' + Response);
end);
end;
procedure TMainForm.Button6Click(Sender: TObject);
begin
SendCommand('>SetFans:0,128',
procedure(Response: string)
begin
if Response <> '<SetFans' then
ShowMessage('Invalid response: ' + Response);
end);
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
RefreshPorts;
end;
procedure TMainForm.RefreshPortsButtonClick(Sender: TObject);
begin
RefreshPorts;
end;
procedure TMainForm.RefreshPorts;
var
currentPort: string;
begin
currentPort := '';
if PortComboBox.ItemIndex > -1 then
currentPort := PortComboBox.Items[PortComboBox.ItemIndex];
EnumComPorts(PortComboBox.Items);
if Length(currentPort) > 0 then
PortComboBox.ItemIndex := PortComboBox.Items.IndexOf(currentPort);
end;
procedure TMainForm.OnReceiveChar(Sender: TObject; Count: Integer);
var
data: string;
terminatorPos: Integer;
begin
(Sender as TComPort).ReadStr(data, Count);
FReceived := FReceived + data;
terminatorPos := AnsiPos(#10, FReceived);
if terminatorPos > 0 then
begin
// Since the protocol is quite synchronous, this is good enough for now
SetLength(FReceived, terminatorPos - 1);
if Assigned(FOnResponse) then
FOnResponse(FReceived);
FReceived := '';
FOnResponse := nil;
end;
end;
procedure TMainForm.SendCommand(const ACommand: string; AOnResponse: TProc<string>);
begin
if not Assigned(FComPort) then
begin
FComPort := TComPort.Create(Self);
FComPort.Port := PortComboBox.Items[PortComboBox.ItemIndex];
FComPort.BaudRate := br19200;
FComPort.OnRxChar := OnReceiveChar;
FComPort.Open;
end;
FOnResponse := AOnResponse;
ComPort.WriteStr(ACommand + #10);
end;
end.