PDA

View Full Version : SimConnect GetPlaneHeading



MechDave
07-11-2009, 01:17 AM
Here is my source code for the SimConnect GetPlaneHeading program for MS FSX.
When launched with FSX it displays the heading in degrees of the plane on the console. This is the first step in getting data for input into the gyro compass to make it work.



//------------------------------------------------------------------------------
//
// GetPlaneHeading V1.02 Beta
//
// Description:
// Open a connection to the server and get the users aircraft
// heading and write it to the console.
//
// Written by Mechdave using FSX SDK code sample "RequestData" as a code base
//
//------------------------------------------------------------------------------

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>

#include "SimConnect.h"

int quit = 0;
HANDLE hSimConnect = NULL;

struct Struct1
{
double radians;
};

static enum EVENT_ID{
EVENT_SIM_START,
};

static enum DATA_DEFINE_ID {
DEFINITION_1,
};

static enum DATA_REQUEST_ID {
REQUEST_1,
};


void CALLBACK MyDispatchProcRD(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{
HRESULT hr;
static double conversion = 57.2957795; //Conversion for radians --> degrees courtesy of Google :)
double degrees=0;

switch(pData->dwID)
{
case SIMCONNECT_RECV_ID_EVENT:
{
SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;
switch(evt->uEventID)
{
case EVENT_SIM_START:
// Now the sim is running, request information on the user aircraft
hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_1, DEFINITION_1, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);

break;

default:
break;
}
break;
}

case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE:
{
SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData;
switch(pObjData->dwRequestID)
{
case REQUEST_1:
{
//Run below again to update the data.
hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_1, DEFINITION_1, 0, SIMCONNECT_SIMOBJECT_TYPE_AIRCRAFT);
DWORD ObjectID = pObjData->dwObjectID;
Struct1 *pS = (Struct1*)&pObjData->dwData;
if (SUCCEEDED(sizeof(pS->radians))) // security check
{
degrees = pS->radians * conversion; //Convert the radians to degrees so a compare can be done with plane
printf("\nHeading in degrees = %f",degrees );
}
break;
}

default:
break;
}
break;
}


case SIMCONNECT_RECV_ID_QUIT:
{
quit = 1;
break;
}

default:
printf("\nReceived:%d",pData->dwID);
break;
}
}

void GetHeading()
{
HRESULT hr;

if (SUCCEEDED(SimConnect_Open(&hSimConnect, "Request Data", NULL, 0, 0, 0)))
{
printf("\nConnected to Flight Simulator!");
// Set up the data definition, but do not yet do anything with it
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "HEADING INDICATOR", "radians");
// Request an event when the simulation starts
hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_SIM_START, "SimStart");
while( quit == 0 )
{
SimConnect_CallDispatch(hSimConnect, MyDispatchProcRD, NULL);
//Sleep(1); //To introduce a delay for a lower resolution.
}

hr = SimConnect_Close(hSimConnect);
}
}

int __cdecl _tmain(int argc, _TCHAR* argv[])
{
GetHeading();

return 0;
}

MechDave
07-13-2009, 12:57 AM
I found that the 1.02 Beta code had some major sim slow down problems to the extent where the sim stopped responding after a few minutes. Here is a much more elegant solution to the problem. The sim now only sends data when the turn angle exceeds roughly 1 step of the stepper motor, (.45 degrees), so we don't waste processing power in the interface software evaluating and ignoring values which don't matter. This may end up in a slightly jerky resolution with the stepper motor yet . If that is the case I shall have to reduce the angle before the sim sends more data to the gauges (console at the moment).

Here is the code, (almost complete... sans some comments)

//------------------------------------------------------------------------------

//

// GetPlaneHeading V1.03 Beta

//

// Description:

// Open a connection to the server and get the users aircraft

// heading and write it to the console. Now data is only recieved

// if aircraft turns more than .45 degrees. This is designed so

// unneccessary cycles are not wasted on sending position data that will

// be discarded by the gyro compass driver software.

//

// Written by Mechdave using FSX SDK Sample RequestData as a code base

//

//------------------------------------------------------------------------------



#include <windows.h>

#include <tchar.h>

#include <stdio.h>

#include <strsafe.h>



#include "SimConnect.h"



int quit = 0;

HANDLE hSimConnect = NULL;



struct Struct1

{

double radians;

};



static enum EVENT_ID{

EVENT_SIM_START,

};



static enum DATA_DEFINE_ID {

DEFINITION_1,

};



static enum DATA_REQUEST_ID {

REQUEST_1,

};





void CALLBACK MyDispatchProcRD(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)

{

HRESULT hr;

static double conversion = 57.295778; //Conversion for radians --> degrees courtesy of Google :)

double degrees=0;

switch (pData->dwID)

{

case SIMCONNECT_RECV_ID_EVENT:

{

SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*) pData;

switch (evt->uEventID)

{

case EVENT_SIM_START:

{

//Now the Sim is running, request information on the user aircraft and get it to send data when plane exceeds turn
//angle (last) argument in function SimConnect_AddToDataDefinition()

hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, SIMCONNECT_OBJECT_ID_USER,SIMCONNECT_PERIOD_VISUAL_FRAME,SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);

//printf("\nSim successfully started"); //Debug output

break;

}

default:

{

//printf("Error1"); //Debug output

break;

}

}

break;

}

case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:

{

SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;

switch(pObjData->dwRequestID)

{

case REQUEST_1:

{

Struct1 *pS = (Struct1*)&pObjData->dwData;

degrees = pS->radians * conversion; //Used to provide a user interface

printf("\nDegrees =%f", degrees ); //to show program is actually doing something :) Eventually the code to
//send the data to the gyro compass will live here

break;

}

default:

{

//printf("Error"); //Debug output

break;

}

}

break;

}

case SIMCONNECT_RECV_ID_QUIT:

{

quit = 1;

break;

}

default:

{

//printf("\nRecieved: %d",pData->dwID); //Debug output

break;

}

}

}



void GetHeading()

{

HRESULT hr;



if (SUCCEEDED(SimConnect_Open(&hSimConnect, "Request Heading", NULL, 0, 0,0)))

{

//printf("\nConnected to Flight Simulator!"); //Debug output

// Set up the data definition, but do not yet do anything with it. The last argument is the angle the plane must turn in radians
//before the sim sends another angle position

hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "HEADING INDICATOR", "Radians",SIMCONNECT_DATATYPE_FLOAT64,0.0078539);

//Request an event when simulation starts

hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_SIM_START,"SimStart");

while( quit == 0 )

{

SimConnect_CallDispatch(hSimConnect,MyDispatchProcRD,NULL);

Sleep (1); //Sleep for 1 mSec

}

hr = SimConnect_Close(hSimConnect);

}

}



int __cdecl _tmain(int argc, _TCHAR* argv[])

{

GetHeading();

return 0;

}

Peter Dowson
07-13-2009, 03:50 AM
Here is the code, (almost complete... sans some comments)


while( quit == 0 )

{

SimConnect_CallDispatch(hSimConnect,MyDispatchProcRD,NULL);

Sleep (1); //Sleep for 1 mSec

}</pre><windows.h><tchar.h><stdio.h><strsafe.h>

You don't need to keep calling "CallDispatch" in a tight loop -- it is better (more efficient) to supply SimConnect with a Window handle and a User Message number (i.e. WM_USER+1 etc.), and it will then send you that message when there's something for you. THAT's when you call "CallDispatch".

Check out the </strsafe.h></stdio.h></tchar.h></windows.h>hWnd and UserEventWin32 parameters to the SimConnect Open call.

Regards

Pete

MechDave
07-13-2009, 06:37 AM
Pete,
Having a little trouble handling the windows message, how should I catch the message so I can make it work, could you please explain a little more in depth?
[EDIT]
Had a crack at it, is this sort of right? Where am I going wrong, it all works but I have a funny feeling there are more than just 1 message windows on the desktop!

void GetHeading()
{
HRESULT hr;
HWND wo = 0;
DWORD HC_VEH = 110011;

if (SUCCEEDED(SimConnect_Open(&hSimConnect, "Request Heading", wo, HC_VEH, 0,0)))
{
//printf("\nConnected to Flight Simulator!"); //Debug output
// Set up the data definition, but do not yet do anything with it. The last argument is the angle the plane must turn in radians
//before the sim sends another angle position
hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "HEADING INDICATOR", "Radians",SIMCONNECT_DATATYPE_FLOAT64,0.0078539);
//Request an event when simulation starts
hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_SIM_START,"SimStart");
while( quit == 0 )
{
if(FindWindowEx(NULL,NULL,NULL,NULL)!= NULL)
{
SimConnect_CallDispatch(hSimConnect,MyDispatchProcRD,NULL);
//Sleep (1); //Sleep for 1 mSec
}
}
hr = SimConnect_Close(hSimConnect);
}
}
Cheers,
Dave

Peter Dowson
07-13-2009, 07:33 AM
Having a little trouble handling the windows message, how should I catch the message so I can make it work, could you please explain a little more in depth?

Sorry, what part needs explanation?

If it is a Windows program, it must have a Windows Procedure, a "wndproc". That's where all windows messages are processed. It simply isn't possible to call a program a Windows program unless it processes Windows messages.

Windows messages are used to draw the window, to get mouse and key events, etc etc. Just about everything Windows does with a windows program is done via its wndproc.

In the WndProc, having switched on the message number, you have a "case WM_USER+1:" (say, depending what value you gave to the SimConnect_Open call), and there you do your CallDispatch. That's it.

Pete

Peter Dowson
07-13-2009, 07:39 AM
Had a crack at it, is this sort of right?
No, totally different to what I said.

{ HWND wo = 0;

A window handle of zero is not right. You need the handle to YOUR window.

DWORD HC_VEH = 110011;

Why not use "WM_USER + 1"?

if (SUCCEEDED(SimConnect_Open(&hSimConnect, "Request Heading", wo, HC_VEH, 0,0)))

You are providing SimConnect with a zero Window handle. How can it call that Window? That makes no sense. You must provide it with a valid Window handle.

while( quit == 0 )
{
if(FindWindowEx(NULL,NULL,NULL,NULL)!= NULL)
{
SimConnect_CallDispatch(hSimConnect,MyDispatchProcRD,NULL);
//Sleep (1); //Sleep for 1 mSec
}
}

You are still Calling your dispatcher in the same loop. Obviously you must because you failed to provide the Window handle for SimConnect to send you your message!

What is the FindWindowEx for? What is it you think that is doing?

Regards

Pete

MechDave
07-14-2009, 12:18 AM
Pete,
Am I correct in thinking that to obtain a valid window handle (HWND), I first need to create a message only window?

Do I need to use CreateWindow(), or is there an simpler function to call, or can I just use a current window handle?

I have searched the internet with what I can think of, do you know of a good reference/tutorial for these message only windows?

Please excuse my ignorance of Win32 programming as I have come from UNIX based programming, and I didn't do much of that, just basic console stuff.

Peter Dowson
07-14-2009, 04:55 AM
Am I correct in thinking that to obtain a valid window handle (HWND), I first need to create a message only window?

That would do. Any window would do, but if you really don't want or need anything on screen, then a message-only window would do.


Do I need to use CreateWindow(), or is there an simpler function to call, or can I just use a current window handle?

CreateWindow is simple enough. But if you already have a window, as you are implying here, why not use that? As long as you are processing messages!


I have searched the internet with what I can think of, do you know of a good reference/tutorial for these message only windows?

They are the same as any other, but don't receive Paint, Mouse or Keyboard messages because they have no user interface.


Please excuse my ignorance of Win32 programming as I have come from UNIX based programming, and I didn't do much of that, just basic console stuff.

Sorry, I didn't realise that when I was advising on efficient use of SimConnect. I find it quite difficult to imagine how one could write an efficient console program -- they are mostly used for short tasks, ones that come and go quickly. For anything persistent in Windows you normally design something which is message-driven, not something which is assumed to retain control of a processor al the time and which therefore has to deliberately relinquish it on occasion to get any cooperation from other processes.

Maybe, if you don't really want to venture into Windows programming you are better off staying with the methods you were using before I interfered. However, if you do want to try, then almost any elementary book on Windows will start you off with a "Hello World" type of application, which makes a trivial Window to display that message. There realy are only a few parts:

1. Register a "class" for your Window, usually using your application name. This Registration call provides the name of the windows message processing procedure (WndProc).

2. Create the window using, usually, CreateWindow. It doesn't need to be a visible window -- a Message window certainly would not be visible.

3. Loop getting messages and dispatching them (no sleep needed -- that's taken care of by GetMessage not returning till there is a message.). The loop is exited on a Quit message from Windows.

4. The WndProc, processing any messages you want, on a Switch statement with Cases for each, ending with a call to the default window message processing for all those messages you aren't interested in.

Regards

Pete

MechDave
07-14-2009, 06:16 AM
Thanks Pete,
Im off to digest a book on Win32 API programming :)
Cheers for the pointers on SimConnect, without them I would have been well stuck. I shall report back when I have managed to get an "invisible" window going and managed to feed it to SimConnect ;)

I think it is going to be a sizeable jump for me from procedural to event based programming, considering the last two days have been nearly a vertical learning curve for me... Just the way I like it.

Cheers,
Dave...

Tripacer
07-16-2009, 10:07 PM
Thanks to you both, Dave and Pete. I am just about to start, I have been building hardware for about a year and finished my cockpit upholstery (see attachment). Now I moving to instruments based on Mike Powells designs. I am anxiously awaiting the next book. My first batch of PIC chip hardware is inbound and a stepping motor instrument (directional gyro compass) is next for me.

Dave, please keep posting as you solve you problems. We probably need a tutorial section somewhere.

William, Tripacer Builder

MechDave
08-22-2009, 03:38 AM
I have now successfuly got a window working with FSX to output the heading in degrees. The exe can be downloaded here (http://users.on.net/~dtjoyce/GetPlaneHeading.exe). The next step is to get the data to the serial port. I soon will be calling for beta testers to try the extension out on their own gyrocompass gauge. :)

Tripacer
08-22-2009, 11:43 AM
MechDave,
Do you have your gryo compass circuit working? I am almost finished with the mechanical fabrication. I am building a 1960 version of a gyro compass. I have been breadboarding 3315 rotary encoders learning how to decode the output pulses. I am about ready to start experimenting with the LW293 driver and the ste pping motor. I really want to develop a circuit board in 3.24" format to attach to the back of the mechanical stack.

William, Tripacer Builder


http://www.mycockpit.org/photopost/data/532/thumbs/DirectionalGyro3Small.JPG (http://www.mycockpit.org/photopost/data/532/DirectionalGyro3Small.JPG)http://www.mycockpit.org/photopost/data/532/thumbs/DirectionalGyro4Small.JPG (http://www.mycockpit.org/photopost/data/532/DirectionalGyro4Small.JPG)

MechDave
08-23-2009, 02:19 AM
If you use a stepper motor, you can graft Mike's electronics and firmware onto it and then run it using my translation code from FSX it should all work. You don't even need to use a 0.9 degree step motor either, whatever step motor you get just change the number of steps in the firmware adn all should be good :)

MechDave
10-04-2009, 04:04 AM
I have got all the data out to the visible window to show the number of steps along with the basic serial port stuff going. Here is the code to make the window and serial port open up. I haven't got the data to work for the serial port yet. There are several notification windows in the code to tell me what is going on... -->


#include <windows.h>

#include "SimConnect.h"

#include <stdio.h> //Needed for sprintf()remove for production code



const char g_szClassName[] = "myWindowClass";

HANDLE hSerial,hSimConnect = NULL;

HWND hwnd = NULL;



double degrees=0; //Remove for production



struct CMD //ADT for Commands. No frame transfer function added yet

{

char* ID;

int Byte5;

int MotorPos;

}QueryName = {"ZZZ99",8}, Reset = {"ZZZ99",0}, SetMotorPos = {"ZZZ99",1,0};





struct Struct1

{

double radians; //More members of Struct1 to come

};



static enum EVENT_ID{

EVENT_SIM_START,

};



static enum DATA_DEFINE_ID {

DEFINITION_1,

};



static enum DATA_REQUEST_ID {

REQUEST_1,

};





void ReadQuery (HANDLE hSerial)

{

char szBuff[18] = {0};

DWORD dwBytesRead = {17};



MessageBox(NULL, "Thread ReadQuery works", "Success!",

MB_ICONINFORMATION | MB_OK);

if(!ReadFile(hSerial,szBuff,18,&dwBytesRead,NULL))

{

//Error occured

MessageBox(NULL, "Failed to read from instrument", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}

}

void WriteQuery(HANDLE hSerial)

{

char szBuff[7] = {"ZZZ998"};

DWORD dwBytesWrite = {0};



MessageBox(NULL, "Thread WriteQuery works", "Success!",

MB_ICONINFORMATION | MB_OK);

if(!WriteFile(hSerial,szBuff,7,&dwBytesWrite,NULL))

{

//Error occured

MessageBox(NULL, "Failed to write to serial port", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}

}

void QueryGaugeName(HANDLE hSerial)

{

//Write to serial port QueryName.ID and QueryName.Byte5

//Recieve from serial port 17 bytes of data from gauge.

//Function runs as a thread.

HANDLE hThreadWrite = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WriteQuery,hSerial,0,NULL);

if(hThreadWrite == NULL)

{

MessageBox(NULL, "Thread for reading instrument type failed", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}

HANDLE hThreadRead = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadQuery,hSerial,0,NULL);

if(hThreadWrite == NULL)

{

MessageBox(NULL, "Thread for reading instrument type failed", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}

}

void SetupSerialPort(DCB &dcbSerialParams, COMMTIMEOUTS &timeouts)

{

//Function call to allow access to serial port. Opens serial port for non overlapped read/write

hSerial = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);



if(hSerial == INVALID_HANDLE_VALUE)

{

if(GetLastError() == ERROR_FILE_NOT_FOUND)

{

MessageBox(NULL, "Serial Port does not exist", "Error!",

MB_ICONEXCLAMATION | MB_OK);

DestroyWindow(hwnd);

}

else //Occurence of unknown error

{

MessageBox(NULL, "Unknown Error - FAILED", "Error!",

MB_ICONEXCLAMATION | MB_OK);

DestroyWindow(hwnd);

}

}

else //Proceed to setting up serial port

{

MessageBox(NULL, "Serial Port does exist", "Success!",

MB_ICONINFORMATION | MB_OK);



dcbSerialParams.DCBlength = sizeof(dcbSerialParams);

if(!GetCommState(hSerial, &dcbSerialParams))

{

//error getting state

MessageBox(NULL, "Error getting state of port", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}



dcbSerialParams.BaudRate = CBR_19200;

dcbSerialParams.ByteSize = 8;

dcbSerialParams.StopBits = ONESTOPBIT;

dcbSerialParams.Parity = NOPARITY;



if(!SetCommState(hSerial, &dcbSerialParams))

{

//error setting serial port state

MessageBox(NULL, "Error setting port", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}

else

{

MessageBox(NULL, "Success setting port", "Success!",

MB_ICONEXCLAMATION | MB_OK);

}



timeouts.ReadIntervalTimeout = 50;

timeouts.ReadTotalTimeoutConstant = 50;

timeouts.ReadTotalTimeoutMultiplier = 10;

timeouts.WriteTotalTimeoutConstant = 50;

timeouts.WriteTotalTimeoutMultiplier = 10;



if(!SetCommTimeouts(hSerial, &timeouts))

{

//timeout set error occurred

MessageBox(NULL, "Timeout set error", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}

else

{

MessageBox(NULL, "Success setting Timeouts", "Success!",

MB_ICONEXCLAMATION | MB_OK);

}

}

} //End of SetupSerialPort()



void CALLBACK MyDispatchProcRD(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)

{

HRESULT hr;

static double conversion = 57.2957780; //Conversion for radians --> degrees

//courtesy of Google :) Remove for production

switch (pData->dwID)

{

case SIMCONNECT_RECV_ID_EVENT:

{

SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*) pData;

switch (evt->uEventID)

{

case EVENT_SIM_START:

{

/*Now the Sim is running, request information on the user aircraft,

get it to send data when plane exceeds turn angle (last) argument

in function SimConnect_AddToDataDefinition()*/

hr = SimConnect_RequestDataOnSimObject(

hSimConnect, REQUEST_1, DEFINITION_1,

SIMCONNECT_OBJECT_ID_USER,SIMCONNECT_PERIOD_VISUAL_FRAME,

SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);

break;

}

default:

{

//printf("Error1"); //Debug output

break;

}

}

break;

}

case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:

{

SIMCONNECT_RECV_SIMOBJECT_DATA *pObjData = (

SIMCONNECT_RECV_SIMOBJECT_DATA*)pData;

switch(pObjData->dwRequestID)

{

case REQUEST_1:

{

Struct1 *pS = (Struct1*)&pObjData->dwData;

SetMotorPos.MotorPos = (int)(pS->radians / 0.0078539);

//degrees = pS->radians * conversion; //Used to provide a user interface

break;

}

default:

{

break;

}

}

break;

}

case SIMCONNECT_RECV_ID_QUIT:

{

DestroyWindow(hwnd);

CloseHandle(hSerial);

break;

}

default:

{

break;

}

}

} //End of MyDispatchProcRD



// Step 4: the Window Procedure

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

{

switch(msg)

{

case WM_CLOSE:

{

DestroyWindow(hwnd);

CloseHandle(hSerial);

return 0;

}

break;

case WM_DESTROY:

{

PostQuitMessage(0);

CloseHandle(hSerial);

return 0;

}

break;

case WM_USER+1:

{

SimConnect_CallDispatch(hSimConnect,MyDispatchProcRD,NULL);

//Place call to serial function to update the instrument here

InvalidateRect(hwnd,NULL,TRUE);

return 0;

}

case WM_PAINT: //Only needed for testing the program... Remove after setting HWND_MESSAGE in final code.

{

PAINTSTRUCT Ps;

HDC hDC;

TCHAR szBuffer[40];

TCHAR szBuffer2[40];

int iLength;

hDC = BeginPaint(hwnd, &Ps);

//Convert the degrees into a string for use with TextOut()

sprintf_s (szBuffer2,"%d",SetMotorPos.MotorPos );

iLength = wsprintf(szBuffer,TEXT("Heading is %s steps"),szBuffer2);

TextOut(hDC,0,0,szBuffer,iLength);

EndPaint(hwnd, &Ps);

return 0;

}

default:

return DefWindowProc(hwnd, msg, wParam, lParam);

}

return 0;

} //End of WndProc



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

LPSTR lpCmdLine, int nCmdShow)

{

WNDCLASSEX wc;

MSG Msg;

HRESULT hr;

DCB dcbSerialParams = {0};

COMMTIMEOUTS timeouts ={0};

HANDLE hThread1 = NULL;

DWORD ThreadID;

//Step 1: Registering the Window Class

wc.cbSize = sizeof(WNDCLASSEX);

wc.style = 0;

wc.lpfnWndProc = WndProc;

wc.cbClsExtra = 0;

wc.cbWndExtra = 0;

wc.hInstance = hInstance;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

wc.lpszMenuName = NULL;

wc.lpszClassName = g_szClassName;

wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);



if(!RegisterClassEx(&wc))

{

MessageBox(NULL, "Window Registration Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}



// Step 2: Creating the Window

hwnd = CreateWindowEx(

WS_EX_CLIENTEDGE,

g_szClassName,

"Heading Window",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,

/*HWND_MESSAGE*/NULL, NULL, hInstance, NULL);



if(hwnd == NULL)

{

MessageBox(NULL, "Window Creation Failed!", "Error!",

MB_ICONEXCLAMATION | MB_OK);

return 0;

}

//Test and open a connection to the SimConnect server

if (SUCCEEDED(

SimConnect_Open(&hSimConnect, "Request Heading",

hwnd, WM_USER+1, 0,SIMCONNECT_OPEN_CONFIGINDEX_LOCAL)))

{

hr = SimConnect_AddToDataDefinition(

hSimConnect, DEFINITION_1, "HEADING INDICATOR",

"Radians",SIMCONNECT_DATATYPE_FLOAT64,0.0078539f);



//Request an event when simulation starts

hr = SimConnect_SubscribeToSystemEvent(hSimConnect, EVENT_SIM_START,"SimStart");



//Now that everything is up and connected we need to set up the serial port!

SetupSerialPort(dcbSerialParams,timeouts);



//Now that the serial port is set up we can start the read thread for reading instrument type.

hThread1 = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)QueryGaugeName,hSerial,0,&ThreadID);

if(hThread1 == NULL)

{

MessageBox(NULL, "Thread for reading instrument type failed", "Error!",

MB_ICONEXCLAMATION | MB_OK);

}





//Now I am happy we can show the window (remove for production)

ShowWindow(hwnd, nCmdShow);

UpdateWindow(hwnd);

while(GetMessage(&Msg, NULL, 0, 0) > 0)

{

DispatchMessage(&Msg);

}

return Msg.wParam;

}

else //Write an error message window to screen if Simconnect fails.

{

MessageBox(NULL, "This program requires Flight Simulator X to be running", "Error!",

MB_ICONEXCLAMATION | MB_OK);

DestroyWindow(hwnd);

return 0;

}

}



I have the project files in a zip archive here (http://users.on.net/~dtjoyce/GetPlaneHeadingWindowed.zip)

Cheers,
Dave