The online racing simulator
G27 LEDs mod [renamed]
After much experimenting I finally present a working mod for G27 LEDs. For the sake of simplicity I will always edit this post when(if) I upload a newer version.

For instructions how to use this mod read the attached README file.

V 1.99D TEST
- Experimental support for Logitech G29
- Improved InSim and OutGauge error handling
(VS 2015 redistributable is required. 32bit version (x86) is needed)

V 1.99C TEST
- Added rev limiter indicator

V 1.99B TEST
- Immediate crash fixed
- Autolaunch feature to start LFS along with the application

V 1.99A TEST
- Substantially rewritten from the grounds up.
- Uses OutGauge exclusively, no weird accessing of LFS' memory anymore.
- Compatible with any version of LFS that uses the "new" OutGauge packet format.

V 1.05E TEST
- Built with MSVS 2012 (info)
- Minor tweaks to G27LEDsHelper and debugging output.

V 1.05
- Fixed 1.04, G27 detection should work fine now

V 1.04 TEST
- Hopefully finally sorts out G27 detection
(Note that this is a testing version which has not been tested at all. If 1.03 works for you, I suggest you stick to it for the time being)

V 1.03
- Ignores all devices except G27

V 1.02
- Switches the LEDs off when LFS looses focus or exits (untested).
- Optional capability to read data from OutGauge. Useful if you want to use the mod with modified or older versions of LFS.
(OutGauge has to be enabled in LFS even if you're _not_ using this feature)

V 1.01
- First fully working version
Attached files
G27LEDS_199D.zip - 233.2 KB - 3088 views
You get major points for sharing the source code! Thanks!
Now to port it for rotation
EXE removed - not working. See follow up posts for the working one
I've been toying with this a little more and I think I have the basic concepts right. I attached updated EXE and g27led.cpp as the rest of the source hasn't changed. As for the wheel range adjustment, check out the source, it can be done pretty easily


// g27led.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <winsock2.h>

#define BUFFER_SIZE 512 // Receive buffer size (basically maximum packet size in UDP).
#define HOST "127.0.0.1" // Host to connect to.
#define PORT 30000 // Port to connect to the host through.

#define FIRST_LEDS_ON 4000.00f
#define REDLINE_LEDS 8000.00f

// Include Logitech headers
#include "LogiWheel.h"
#include "LogiControllerInput.h"

// Define types used by InSim.
typedef unsigned char byte;
typedef unsigned short word;
typedef struct
{
int X, Y, Z;
} Vec;

typedef struct
{
float X, Y, Z;
} Vector;

// Include InSim header.
#include "InSim.h"

using namespace LogitechSteeringWheel;
using namespace LogitechControllerInput;

// Declare variables for the Logitech Wheel
Wheel* g_wheel;
ControllerInput* g_controllerInput;

// Declare RPM variable too
float inRpm = 0;

// Level of debbuging, passed by external argument
// 0 = Default, no verbosity
// 1 = Print what RPM are we getting from OutGauge
// 2 = Confirm that LED data is being sent to wheel
// 3 = Only output RPM info from OutGauge, don't send anything to wheel
int debugLevel = 0;

// More than one Logitech wheel can be connected. We have to take care of all of them.
int wheelIdx = 0;

int initInSimConnection();
void processOutGaugePacket(const OutGaugePack packet);

int _tmain(int argc, char** argv)
{
if(argc > 1)
{
int debugArg = atoi(argv[1]);
if((debugArg >= 0) && (debugArg < 4))
{
debugLevel = debugArg;
}
}

//Bit of a hack, we need the HWND of LFS's window
CString winTitle = "Live for Speed";
HWND hLfsWin = FindWindow(NULL, winTitle);

if(hLfsWin == NULL)
{
CString errMsg = "Cannot find active LFS instance.\nMake sure LFS is running.";
MessageBox(NULL, errMsg, NULL, NULL);
return EXIT_FAILURE;
}

//Initialize the wheel input
g_controllerInput = new ControllerInput(hLfsWin, TRUE);
g_wheel = new Wheel(g_controllerInput);

//Get some wheel settings

//This is an example of controlling wheel settings
//in the same way Logitech Profiler does. Particularly
//"propsData.wheelRange" can be very useful.
ControllerPropertiesData propsData;
ZeroMemory(&propsData, sizeof(propsData));
g_controllerInput->Update();
g_wheel->Update();
for(wheelIdx = 0; wheelIdx < LogitechSteeringWheel::LG_MAX_CONTROLLERS; wheelIdx++)
{
g_wheel->GetCurrentControllerProperties(wheelIdx, propsData);
}

//Some adjustments, I will comment them out as we don't
//want to adjust anything right now.
/*propsData.wheelRange = 720;
propsData.overallGain = 10;
propsData.forceEnable = 0;
g_wheel->SetPreferredControllerProperties(propsData);*/

std::cout << "Init completeted, connecting to LFS" << std::endl;

//Connect to InSim
int retState = initInSimConnection();

return retState;
}

int initInSimConnection()
{

// Initialise WinSock version 2.2.
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
WSACleanup();
std::cerr << "Error: Failed to init WinSock" << std::endl;
return EXIT_FAILURE;
}

// Create UDP socket.
SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Error: Could not create socket." << std::endl;
return EXIT_FAILURE;
}

// Bind to receive UDP packets.
sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr(HOST);
saddr.sin_port = htons(PORT);
if (bind(sock, (sockaddr *)&saddr, sizeof(sockaddr)) == SOCKET_ERROR)
{
closesocket(sock);
WSACleanup();
std::cerr << "Error: Could not connect to LFS" << std::endl;
return EXIT_FAILURE;
}


std::cout << "Connection established, recieving data" << std::endl;

// Packet receive loop.
char recvbuf[BUFFER_SIZE];
memset(recvbuf, 0, sizeof(recvbuf)); // Set recvbuf to zero.
int bytes = 0;
do
{
bytes = recv(sock, recvbuf, BUFFER_SIZE, 0);
if (bytes > 0)
{
processOutGaugePacket((OutGaugePack &)recvbuf);
}
else if (bytes == 0)
std::cerr << "Error: Lost connection with LFS" << std::endl;
else
std::cerr << "Error: " << WSAGetLastError() << std::endl;
} while (bytes > 0);

// Cleanup and exit.
closesocket(sock);
WSACleanup();
delete g_wheel;
delete g_controllerInput;
return EXIT_SUCCESS;
}

void processOutGaugePacket(const OutGaugePack packet)
{
inRpm = packet.RPM;

if (debugLevel > 0)
{
std::cout << "Current RPM is: " << inRpm << std::endl;
}

//We are confident enough to send LED data to the wheel
if(debugLevel < 3)
{
g_controllerInput->Update();
g_wheel->Update();

for(wheelIdx = 0; wheelIdx < LogitechSteeringWheel::LG_MAX_CONTROLLERS; wheelIdx++)
{
if(g_wheel->IsConnected(wheelIdx))
{
g_wheel->PlayLeds(wheelIdx, inRpm, FIRST_LEDS_ON, REDLINE_LEDS);

//Print whether the data has been sent
if (debugLevel == 2)
{
std::cout << "RPM data sent to device ID = " << wheelIdx << std::endl;
}
}
}
}

}
Attached files
readme.txt - 1.3 KB - 952 views
When im trying to run the .exe im getting an error something about parameters.

What will happen if you change the
"int _tmain(int argc, char** argv)"
to
"int main(int argc, char *argv[])"
or just
"int main()"
Can you be more specific about the error or post a screenshot? "char** argv" and "char* argv[]" should be equal. Can you run the program from console with command like "g27led.exe 0"? Do you have VS 2005 libraries installed?
It says
"Software didnt start because settings of parameters are invalid. Reinstalling the software may fix the problem." (translated from greek)

Yes i have already installed the libraries and also i tried to run it like that by creating a bat file and adding "start g27led.exe 0"
also i tried creating a shortcut with this destination
["C:\Documents and Settings\Dark_Kostas\Επιφάνεια εργασίας\g27led.exe" 0]
without the []
I'm pretty sure I've seem this error before but I don't recall what caused it. Anyway, I did few modifications to the EXE, so you might try this one out. Do you have the latest Logitech software and drivers installed? What Windows version do you have? Also try running the program from folder whose name doesn't contain Greek charakters and make sure you've read the readme
Still doesnt work. Same error. Im having the latest Logitech software(thats why G27 works, this is the last version including the G27).

I tried putting it on C:/ and run it but still same(tried also with parameter)
It looks like some nasty linking error, unfortunately I have only one windows machine available so I cannot do some extensive testing. Can you download the source and try to compile it yourself? In the meantime I will try to come up with some solution...
I forgot to say that im on Windows XP SP3. I tried to compile it, but im having the same problem as i had when i tried to make this program by myself. Missing dininput.h(i know that i have to download the DirectX libraries). Also what is ATL? (im totally new to programming and everything i learn was from the example of C# insim)

EDIT: Do you need all these .cpp files? About FB and other things?
You can get DirectX SDK here. Unless you have Express editions of Visual Studio, you shouldn't be worried about ATL. I don't know if all of those .cpp files of Logitech API are needed, but compiling them all will make your life a bit easier because you are less likely to run into linking errors hell. I think that the source I uploaded contains everything you need.
I think I finally managed to link statically everything this app needs. Give it a try...

EDIT: EXE removed, see the thread to get a working one
Ok now program is working. I get the
Connection Established, receiving data, but i dont see any leds working...

EDIT: Enable debug, so i can tell you what is going on.
EDIT2: I forgot that parameter works for debug. I enabled it and i prints correctly the RPM and also
"RPM data sent to Device ID = 0"
If you run the program like "g27led_v2.exe 2", you should see a lot of debugging info. See the source for other debug options.
I cant get this to work. I have all the cfg set correctly and have the port set right. i cant work our what isnt working right... any help would be appreciated. i am running w7 64bit

EDIT

Just put the app in diag mode and it is picking up the rpm fine. but it is trying to send it to device id 0... is that correct?

EDIT

Looked at logitech profiler and it has the id of the wheel set to 1... any chance u can change the script to reflect that?
Have you got any other controllers connected to your PC??

I maybe wrong, but working with controllers in VB/C++ etc it selects by default the first ID (in this case being 0)

If you only have your wheel connected then obv there is another problem somewhere
This application is written in a way that should ensure that only Logitech Wheels are probed and supplied with data. If you have only one Logitech wheel connected, it's ID should be 0. The real problem here is the damn DirectInput which won't allow LFS and this app to work simultaneously.
I think I've finally managed to acquire a lock to the wheel though the Logitech API, but if I do it, LFS looses it's lock so you cannot steer
Unless anybody knows a workaround for this, I'm afraid we'll have to wait until this feature is implemented in LFS itself...
Well, all the functions the SDK provides, are realized through Logitech profiler.
I guess profiler itself uses the window handle to distinguish between games/application cause it is used to init the profiler classes.

So what need to be done is, get the window handle of LFS and init the controller classes using the Lfs window handle.

I made application myself but for the reason to set the steering range in game.
Here is a part of the code the class that handles the communication with the wheel.
I hope it helps.


// get handle of LFS window
HWND WheelHandler::GetLFSWindow(void)
{
HWND hwnd = FindWindow(L"LFS", NULL);
if(hwnd == NULL)
{
throw std::exception("LFS window not found");
}
return hwnd;
}

// initialise wheel member
void WheelHandler::InitWheel(void)
{
HWND hLFSWindow = this->GetLFSWindow();
this->m_pControllerInput = new LogitechControllerInput::ControllerInput(hLFSWindow, TRUE);
this->m_pWheel = new LogitechSteeringWheel::Wheel(this->m_pControllerInput);
}


this is precisely what I tried to do, but when I attempt to send data to the wheel, I get E_ACCESSDENIED error (PlayLeds method returns HRESULT, that's how I get the error). I guess it's because LFS already has a lock of the wheel and DirectInput doesn't allow this kind of fooling around with the device locks.
I don't know if the leds are special thing,
but I have an application running in the background, that sets the wheel range via Wheel::SetPreferredControllerProperties, while I play LFS and it works.
I was toying with that too and I got the wheel turn adjustment working too (sort of ).
If you're interested in trying it out with the leds, could you add something like this to your app?

for(wheelIdx = 0; wheelIdx < LogitechSteeringWheel::LG_MAX_CONTROLLERS; wheelIdx++)
{
if(g_wheel->IsConnected(wheelIdx))
{
HRESULT hRes = g_wheel->PlayLeds(wheelIdx, 2000f, 1000f, 2000f);
printHResult(hRes);
}
}

void printHResult(HERSULT hRes)
{
switch(hRes)
{
case 0x80070005:
MessageBox(NULL, NULL, L"E_ACCESSDENIED", NULL);
break;
case 0x80004001:
MessageBox(NULL, NULL, L"E_NOTIMPL", NULL);
break;
default:
MessageBox(NULL, NULL, L"Something else has happened", NULL);
}
}

This should light all the leds up. If you don't have a G27 wheel, you should get E_NOTIMPL error. If you run into the same issue as I did, you should get E_ACCESSDENIED error.

I haven't actually tested this code, but I think it's OK...
I called PlayLeds via SetTimer every 5 seconds and put LFS in foreground.
The hres is E_NOTIMPL (guess I own a G25) but no E_ACCESSDENIED.

Are you 100% sure you supply the LFS window handle when creating the ControllerInput class ?
very interesting and promising work, please keep working on that guyz
Thanks for the tip yankman, calling FindWindow like FindWindow(L"LFS", NULL) instead of FindWindow(NULL, L"Live for Speed") probably did the trick (tough I dunno why, I certainly was getting a handle of something...). I attached updated version of this app, so feel free to try it out...

G27 LEDs mod [renamed]
(329 posts, started )
FGED GREDG RDFGDR GSFDG