
ExternalSim.cpp |
|
// ExternalSim.cpp : Test the SimConnect External Sim APIs // #include "stdafx.h" #include "SimConnect.h" #include "ExternalSim.h" HANDLE g_hSimConnect = NULL; VehicleList g_VehicleList; #define EXTERNAL_SIM_CALLBACK_MASK (SIMCONNECT_EXTERNAL_SIM_CALLBACK_FLAG_CREATE | SIMCONNECT_EXTERNAL_SIM_CALLBACK_FLAG_DESTROY | SIMCONNECT_EXTERNAL_SIM_CALLBACK_FLAG_SIMULATE | SIMCONNECT_EXTERNAL_SIM_CALLBACK_FLAG_LOCATION_CHANGED | SIMCONNECT_EXTERNAL_SIM_CALLBACK_FLAG_EVENT) void OnRecvExternalSimCreate(SIMCONNECT_RECV_EXTERNAL_SIM_CREATE *pCreate) { VehicleListIterator iter = g_VehicleList.find(pCreate->dwObjectID); // check that we aren't already tracking this vehicle if (iter == g_VehicleList.end()) { // create new vehicle data structure VehicleData *pVehData = new VehicleData; pVehData->dwObjectID = pCreate->dwObjectID; pVehData->cntSimVars = pCreate->dwExternalSimVarCount; pVehData->idxSimVarsBase = pCreate->dwExternalSimVarBase; float d1, d2, d3; sscanf_s(pCreate->szExternalSimData, "%f, %f, %f", &d1, &d2, &d3); pVehData->fMaxFrontBackVelocity = d1; pVehData->fMaxLeftRightVelocity = d2; pVehData->fMaxUpDownVelocity = d3; pVehData->bReset = true; // add vehicle to list g_VehicleList[pCreate->dwObjectID] = pVehData; } SimConnect_SynchronousUnblock(g_hSimConnect); } void OnRecvExternalSimDestroy(SIMCONNECT_RECV_EXTERNAL_SIM_DESTROY *pDestroy) { VehicleListIterator iter = g_VehicleList.find(pDestroy->dwObjectID); // check that this object ID is being tracked currently if (iter != g_VehicleList.end() && iter->second != NULL) { // delete vehicle and remove from local list delete iter->second; g_VehicleList.erase(iter); } SimConnect_SynchronousUnblock(g_hSimConnect); } void OnRecvExternalSimSimulate(SIMCONNECT_RECV_EXTERNAL_SIM_SIMULATE *pSimulate) { VehicleListIterator iter = g_VehicleList.find(pSimulate->dwObjectID); // check that this object ID is being tracked currently if (iter != g_VehicleList.end() && iter->second != NULL) { // yes, we know this vehicle, simulate it VehicleData *pVehData = iter->second; PerVehicleSimulate *pData = (PerVehicleSimulate*)&pSimulate->dwData; PerVehicleOutput pvo = { // lat, lon, alt pData->Lat, pData->Lon, pData->Alt, // pitch, roll/bank, yaw/heading, pData->Pitch, pData->Bank, pData->Heading, }; if (pSimulate->fDeltaTime > 1.5) { pSimulate->fDeltaTime = 0; } if (pVehData->bReset) { // if reset requested, reset values pVehData->bReset = false; pVehData->fLeftRight = 0; pVehData->fFrontBack = 0; pVehData->fUpDown = 0; pVehData->fLeftRightVelocity = 0; pVehData->fFrontBackVelocity = 0; pVehData->fUpDownVelocity = 0; pvo.Pitch = 0; pvo.Bank = 0; pvo.Heading = 0; SimConnect_SetDataOnSimObject(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, pSimulate->dwObjectID, 0, 0, sizeof(PerVehicleOutput), &pvo); } else if (pSimulate->bShouldSimulate) { // else if should simulate, then simulate this vehicle // process inputs pVehData->fLeftRightVelocity = pVehData->fMaxLeftRightVelocity * pVehData->fLeftRight; pVehData->fFrontBackVelocity = pVehData->fMaxFrontBackVelocity * pVehData->fFrontBack; pVehData->fUpDownVelocity = pVehData->fMaxUpDownVelocity * pVehData->fUpDown; // step time integrate pvo.Lat += LAT_METERS_TO_RADIANS(pVehData->fFrontBackVelocity * pSimulate->fDeltaTime); pvo.Lon += LON_METERS_TO_RADIANS(pVehData->fLeftRightVelocity * pSimulate->fDeltaTime, pvo.Lat); pVehData->GroundAltOffset += pVehData->fUpDownVelocity * pSimulate->fDeltaTime; if (pData->eSurfaceType == 2) { // if SurfaceType == WATER, keep from offseting beyond BathAlt value if (pVehData->GroundAltOffset < pData->BathAlt) { pVehData->GroundAltOffset = pData->BathAlt; } } else { // if SurfaceType != WATER, keep from going below ground if (pVehData->GroundAltOffset < 0) { pVehData->GroundAltOffset = 0; } } pvo.Alt = pData->GroundAlt + pVehData->GroundAltOffset; pvo.Pitch = 0; pvo.Bank = 0; if (pVehData->fFrontBackVelocity != 0 || pVehData->fLeftRightVelocity != 0) { pvo.Heading = atan2(pVehData->fLeftRightVelocity, pVehData->fFrontBackVelocity); while (pvo.Heading >= 2.0 * M_PI) { pvo.Heading -= 2.0 * M_PI; } while (pvo.Heading < -2.0 * M_PI) { pvo.Heading += 2.0 * M_PI; } } pvo.BodyVelX = 0.0; pvo.BodyVelY = pVehData->fUpDownVelocity; pvo.BodyVelZ = sqrt((pVehData->fLeftRightVelocity * pVehData->fLeftRightVelocity) + (pVehData->fFrontBackVelocity * pVehData->fFrontBackVelocity)); pvo.WorldVelX = pVehData->fLeftRightVelocity; pvo.WorldVelY = pVehData->fUpDownVelocity; pvo.WorldVelZ = pVehData->fFrontBackVelocity; pvo.VerticalSpeed = pVehData->fUpDownVelocity; SimConnect_SetDataOnSimObject(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, pSimulate->dwObjectID, 0, 0, sizeof(PerVehicleOutput), &pvo); } } SimConnect_SynchronousUnblock(g_hSimConnect); } void OnRecvExternalSimLocationChanged(SIMCONNECT_RECV_EXTERNAL_SIM_LOCATION_CHANGED *pLocationChanged) { if (pLocationChanged->bZeroSpeed) { VehicleListIterator iter = g_VehicleList.find(pLocationChanged->dwObjectID); if (iter != g_VehicleList.end()) { iter->second->bReset = true; } } SimConnect_SynchronousUnblock(g_hSimConnect); } void OnRecvExternalSimEvent(SIMCONNECT_RECV_EXTERNAL_SIM_EVENT *pEvent) { VehicleListIterator iter = g_VehicleList.find(pEvent->dwObjectID); // check that this object ID is being tracked currently if (iter != g_VehicleList.end() && iter->second != NULL) { VehicleData *pVehData = iter->second; switch (pEvent->uEventID) { case MOVEMENT_CENTER_EVENT: { pVehData->fFrontBack = 0; pVehData->fLeftRight = 0; pVehData->fUpDown = 0; } break; case LEFTRIGHT_INCREMENT_EVENT: { pVehData->fLeftRight += 0.1; if (pVehData->fLeftRight > 1.0) { pVehData->fLeftRight = 1.0; } } break; case LEFTRIGHT_DECREMENT_EVENT: { pVehData->fLeftRight -= 0.1; if (pVehData->fLeftRight < -1.0) { pVehData->fLeftRight = -1.0; } } break; case LEFTRIGHT_SET_EVENT: { pVehData->fLeftRight = ((int)pEvent->dwData) / 100000.0; if (pVehData->fLeftRight > 1.0) { pVehData->fLeftRight = 1.0; } if (pVehData->fLeftRight < -1.0) { pVehData->fLeftRight = -1.0; } } break; case FRONTBACK_INCREMENT_EVENT: { pVehData->fFrontBack += 0.1; if (pVehData->fFrontBack > 1.0) { pVehData->fFrontBack = 1.0; } } break; case FRONTBACK_DECREMENT_EVENT: { pVehData->fFrontBack -= 0.1; if (pVehData->fFrontBack < -1.0) { pVehData->fFrontBack = -1.0; } } break; case FRONTBACK_SET_EVENT: { pVehData->fFrontBack = ((int)pEvent->dwData) / 100000.0; if (pVehData->fFrontBack > 1.0) { pVehData->fFrontBack = 1.0; } if (pVehData->fFrontBack < -1.0) { pVehData->fFrontBack = -1.0; } } break; case UPDOWN_MAX_EVENT: { pVehData->fUpDown = 1.0; } break; case UPDOWN_MIN_EVENT: { pVehData->fUpDown = -1.0; } break; case UPDOWN_INCREMENT_EVENT_1: case UPDOWN_INCREMENT_EVENT_2: case UPDOWN_INCREMENT_EVENT_3: { pVehData->fUpDown += 0.1; if (pVehData->fUpDown > 1.0) { pVehData->fUpDown = 1.0; } } break; case UPDOWN_DECREMENT_EVENT_1: case UPDOWN_DECREMENT_EVENT_2: case UPDOWN_DECREMENT_EVENT_3: { pVehData->fUpDown -= 0.1; if (pVehData->fUpDown < -1.0) { pVehData->fUpDown = -1.0; } } break; case UPDOWN_SET_EVENT: { pVehData->fUpDown = pEvent->dwData / 100000.0; if (pVehData->fUpDown > 1.0) { pVehData->fUpDown = 1.0; } if (pVehData->fUpDown < -1.0) { pVehData->fUpDown = -1.0; } } break; case LEFTRIGHT_AXIS_EVENT: { pVehData->fLeftRight = -(int)pEvent->dwData / 16384.0; } break; case FRONTBACK_AXIS_EVENT: { pVehData->fFrontBack = (int)pEvent->dwData / 16384.0; } break; case UPDOWN_AXIS_EVENT: { pVehData->fUpDown = (int)pEvent->dwData / 16384.0; } break; } } SimConnect_SynchronousUnblock(g_hSimConnect); } void OnRecvException(SIMCONNECT_RECV_EXCEPTION *pExceptionData) { } void OnRecvQuit() { SimConnect_UnregisterExternalSim(g_hSimConnect, g_guidExternalSim); } void OnRecvOpen(SIMCONNECT_RECV_OPEN *pOpenData) { // this struct/request used to get data via the External Sim Simulate callback SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("PLANE LATITUDE"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("PLANE LONGITUDE"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("PLANE ALTITUDE"), ("meters"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("PLANE PITCH DEGREES"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("PLANE BANK DEGREES"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("PLANE HEADING DEGREES TRUE"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("GROUND ALTITUDE"), ("meters"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("BATH ALTITUDE"), ("meters"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_SIMULATE_DEFINITION, ("SURFACE TYPE"), ("enum"), SIMCONNECT_DATATYPE_INT32); // this struct/request used to send data back to the sim from the External Sim Simulate callback SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("PLANE LATITUDE"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("PLANE LONGITUDE"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("PLANE ALTITUDE"), ("meters"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("PLANE PITCH DEGREES"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("PLANE BANK DEGREES"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("PLANE HEADING DEGREES TRUE"), ("radians"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("VELOCITY BODY X"), ("m/s"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("VELOCITY BODY Y"), ("m/s"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("VELOCITY BODY Z"), ("m/s"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("VELOCITY WORLD X"), ("m/s"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("VELOCITY WORLD Y"), ("m/s"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("VELOCITY WORLD Z"), ("m/s"), SIMCONNECT_DATATYPE_FLOAT64); SimConnect_AddToDataDefinition(g_hSimConnect, PER_VEHICLE_OUTPUT_DEFINITION, ("VERTICAL SPEED"), ("m/s"), SIMCONNECT_DATATYPE_FLOAT64); // register as an external sim client SimConnect_RegisterExternalSim(g_hSimConnect, g_guidExternalSim, EXTERNAL_SIM_CALLBACK_MASK, PER_VEHICLE_SIMULATE_DEFINITION); // map some events SimConnect_MapClientEventToSimEvent(g_hSimConnect, MOVEMENT_CENTER_EVENT, ("CENTER_AILER_RUDDER")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, LEFTRIGHT_INCREMENT_EVENT, ("AILERONS_RIGHT")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, LEFTRIGHT_DECREMENT_EVENT, ("AILERONS_LEFT")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, LEFTRIGHT_SET_EVENT, ("AILERON_SET")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, FRONTBACK_INCREMENT_EVENT, ("ELEV_DOWN")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, FRONTBACK_DECREMENT_EVENT, ("ELEV_UP")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, FRONTBACK_SET_EVENT, ("ELEVATOR_SET")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_MAX_EVENT, ("THROTTLE_FULL")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_MIN_EVENT, ("THROTTLE_CUT")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_INCREMENT_EVENT_1, ("THROTTLE_INCR")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_INCREMENT_EVENT_2, ("THROTTLE_INCR_SMALL")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_INCREMENT_EVENT_3, ("INCREASE_THROTTLE")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_DECREMENT_EVENT_1, ("THROTTLE_DECR")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_DECREMENT_EVENT_2, ("THROTTLE_DECR_SMALL")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_DECREMENT_EVENT_3, ("DECREASE_THROTTLE")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_SET_EVENT, ("THROTTLE_SET")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, LEFTRIGHT_AXIS_EVENT, ("AXIS_AILERONS_SET")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, FRONTBACK_AXIS_EVENT, ("AXIS_ELEVATOR_SET")); SimConnect_MapClientEventToSimEvent(g_hSimConnect, UPDOWN_AXIS_EVENT, ("AXIS_THROTTLE_SET")); } void CALLBACK SimConnectProcess(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext) { // process SIMCONNECT_RECV_ID_XXX values here as needed switch(pData->dwID) { case SIMCONNECT_RECV_ID_EXTERNAL_SIM_CREATE: { OnRecvExternalSimCreate((SIMCONNECT_RECV_EXTERNAL_SIM_CREATE*)pData); } break; case SIMCONNECT_RECV_ID_EXTERNAL_SIM_DESTROY: { OnRecvExternalSimDestroy((SIMCONNECT_RECV_EXTERNAL_SIM_DESTROY*)pData); } break; case SIMCONNECT_RECV_ID_EXTERNAL_SIM_SIMULATE: { OnRecvExternalSimSimulate((SIMCONNECT_RECV_EXTERNAL_SIM_SIMULATE*)pData); } break; case SIMCONNECT_RECV_ID_EXTERNAL_SIM_LOCATION_CHANGED: { OnRecvExternalSimLocationChanged((SIMCONNECT_RECV_EXTERNAL_SIM_LOCATION_CHANGED*)pData); } break; case SIMCONNECT_RECV_ID_EXTERNAL_SIM_EVENT: { OnRecvExternalSimEvent((SIMCONNECT_RECV_EXTERNAL_SIM_EVENT*)pData); } break; case SIMCONNECT_RECV_ID_EXCEPTION: { OnRecvException((SIMCONNECT_RECV_EXCEPTION*)pData); } break; case SIMCONNECT_RECV_ID_QUIT: { OnRecvQuit(); } break; case SIMCONNECT_RECV_ID_OPEN: { OnRecvOpen((SIMCONNECT_RECV_OPEN*)pData); } break; } } void __stdcall DLLStart( void ) { // open connection to local SimConnect server if ( SUCCEEDED(SimConnect_Open(&g_hSimConnect, ("ExternalSim"), NULL, 0, NULL, SIMCONNECT_OPEN_CONFIGINDEX_LOCAL)) && g_hSimConnect != NULL) { // register callback routine for message processing SimConnect_CallDispatch(g_hSimConnect, SimConnectProcess, NULL); } } void __stdcall DLLStop( void ) { if (g_hSimConnect != NULL) { SimConnect_Close(g_hSimConnect); g_hSimConnect = NULL; } g_VehicleList.clear(); } |
