Skip to content

Commit

Permalink
Initial upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Koseng authored May 26, 2021
1 parent 8318080 commit d025bab
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/mobiflightVarAccess.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<mxfile host="Electron" modified="2021-05-26T11:32:32.590Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/14.1.8 Chrome/87.0.4280.88 Electron/11.1.1 Safari/537.36" etag="bnXJMvJ6PpK9BHE153Qq" version="14.1.8" type="device"><diagram id="8LHJcELrov1qkNwrF_JH" name="Seite-1">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</diagram></mxfile>
Binary file added doc/mobiflightVarAccess.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 30 additions & 0 deletions src/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import logging, logging.handlers
from simconnect_mobiflight import SimConnectMobiFlight
from mobiflight_variable_requests import MobiFlightVariableRequests
from time import sleep

def setupLogging(logFileName):
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s")
rootLogger = logging.getLogger()
rootLogger.setLevel(logging.DEBUG)
fileHandler = logging.handlers.RotatingFileHandler(logFileName, maxBytes=500000, backupCount=7)
fileHandler.setFormatter(logFormatter)
rootLogger.addHandler(fileHandler)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)

# MAIN
setupLogging("SimConnectMobiFlight.log")
sm = SimConnectMobiFlight()
vr = MobiFlightVariableRequests(sm)
vr.clear_sim_variables()

while True:
alt_ground = vr.get("(A:GROUND ALTITUDE,Meters)")
alt_plane = vr.get("(A:PLANE ALTITUDE,Feet)")
# FlyByWire A320
ap1 = vr.get("(L:A32NX_AUTOPILOT_1_ACTIVE)")
hdg = vr.get("(L:A32NX_AUTOPILOT_HEADING_SELECTED)")
mode = vr.get("(L:A32NX_FMA_LATERAL_MODE)")
sleep(1)
132 changes: 132 additions & 0 deletions src/mobiflight_variable_requests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import logging
import struct
from ctypes import sizeof
from ctypes.wintypes import FLOAT
from SimConnect.Enum import SIMCONNECT_CLIENT_DATA_PERIOD, SIMCONNECT_UNUSED


class SimVariable:
def __init__(self, id, name, float_value = 0):
self.id = id
self.name = name
self.float_value = float_value
def __str__(self):
return f"Id={self.id}, value={self.float_value}, name={self.name}"


class MobiFlightVariableRequests:

def __init__(self, simConnect):
logging.info("MobiFlightVariableRequests __init__")
self.sm = simConnect
self.sim_vars = {}
self.sim_var_name_to_id = {}
self.CLIENT_DATA_AREA_LVARS = 0
self.CLIENT_DATA_AREA_CMD = 1
self.CLIENT_DATA_AREA_RESPONSE = 2
self.FLAG_DEFAULT = 0
self.FLAG_CHANGED = 1
self.DATA_STRING_SIZE = 256
self.DATA_STRING_OFFSET = 0
self.DATA_STRING_DEFINITION_ID = 0
self.sm.register_client_data_handler(self.client_data_callback_handler)
self.initialize_client_data_areas()


def add_to_client_data_definition(self, definition_id, offset, size):
logging.info("add_to_client_data_definition definition_id=%s, offset=%s, size=%s", definition_id, offset, size)
self.sm.dll.AddToClientDataDefinition(
self.sm.hSimConnect,
definition_id,
offset,
size,
0, # fEpsilon
SIMCONNECT_UNUSED) # DatumId


def subscribe_to_data_change(self, data_area_id, request_id, definition_id):
logging.info("subscribe_to_data_change data_area_id=%s, request_id=%s, definition_id=%s", data_area_id, request_id, definition_id)
self.sm.dll.RequestClientData(
self.sm.hSimConnect,
data_area_id,
request_id,
definition_id,
SIMCONNECT_CLIENT_DATA_PERIOD.SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET,
self.FLAG_CHANGED,
0, # origin
0, # interval
0) # limit


def send_data(self, data_area_id, definition_id, size, dataBytes):
logging.info("send_data data_area_id=%s, definition_id=%s, size=%s, dataBytes=%s", data_area_id, definition_id, size, dataBytes)
self.sm.dll.SetClientData(
self.sm.hSimConnect,
data_area_id,
definition_id,
self.FLAG_DEFAULT,
0, # dwReserved
size,
dataBytes)


def send_command(self, command):
logging.info("send_command command=%s", command)
data_byte_array = bytearray(command, "ascii")
data_byte_array.extend(bytearray(self.DATA_STRING_SIZE - len(data_byte_array))) # extend to fix DATA_STRING_SIZE
self.send_data(self.CLIENT_DATA_AREA_CMD, self.DATA_STRING_DEFINITION_ID, self.DATA_STRING_SIZE, bytes(data_byte_array))


def initialize_client_data_areas(self):
logging.info("initialize_client_data_areas")
# register client data area for receiving simvars
self.sm.dll.MapClientDataNameToID(self.sm.hSimConnect, "MobiFlight.LVars".encode("ascii"), self.CLIENT_DATA_AREA_LVARS)
self.sm.dll.CreateClientData(self.sm.hSimConnect, self.CLIENT_DATA_AREA_LVARS, 4096, self.FLAG_DEFAULT)
# register client data area for sending commands
self.sm.dll.MapClientDataNameToID(self.sm.hSimConnect, "MobiFlight.Command".encode("ascii"), self.CLIENT_DATA_AREA_CMD)
self.sm.dll.CreateClientData(self.sm.hSimConnect, self.CLIENT_DATA_AREA_CMD, self.DATA_STRING_SIZE, self.FLAG_DEFAULT)
# register client data area for receiving responses
self.sm.dll.MapClientDataNameToID(self.sm.hSimConnect, "MobiFlight.Response".encode("ascii"), self.CLIENT_DATA_AREA_RESPONSE)
self.sm.dll.CreateClientData(self.sm.hSimConnect, self.CLIENT_DATA_AREA_RESPONSE, self.DATA_STRING_SIZE, self.FLAG_DEFAULT)
# subscribe to WASM Module responses
self.add_to_client_data_definition(self.DATA_STRING_DEFINITION_ID, self.DATA_STRING_OFFSET, self.DATA_STRING_SIZE)
self.subscribe_to_data_change(self.CLIENT_DATA_AREA_RESPONSE, self.DATA_STRING_DEFINITION_ID, self.DATA_STRING_DEFINITION_ID)


# simconnect library callback
def client_data_callback_handler(self, client_data):
if client_data.dwDefineID in self.sim_vars:
data_bytes = struct.pack("i", client_data.dwData[0])
float_data = struct.unpack('<f', data_bytes)[0] # unpack delivers a tuple -> [0]
self.sim_vars[client_data.dwDefineID].float_value = round(float_data, 5)
logging.debug("client_data_callback_handler %s", self.sim_vars[client_data.dwDefineID])
else:
logging.warning("client_data_callback_handler DefinitionID %s not found!", client_data.dwDefineID)


def get(self, variableString):
if variableString not in self.sim_var_name_to_id:
# add new variable
id = len(self.sim_vars) + 1
self.sim_vars[id] = SimVariable(id, variableString)
self.sim_var_name_to_id[variableString] = id
# subscribe to variable data change
offset = (id-1)*sizeof(FLOAT)
self.add_to_client_data_definition(id, offset, sizeof(FLOAT))
self.subscribe_to_data_change(self.CLIENT_DATA_AREA_LVARS, id, id)
self.send_command("MF.SimVars.Add." + variableString)
# determine id and return value
variable_id = self.sim_var_name_to_id[variableString]
float_value = self.sim_vars[variable_id].float_value
logging.debug("get %s. Return=%s", variableString, float_value)
return float_value


def clear_sim_variables(self):
logging.info("clear_sim_variables")
self.sim_vars.clear()
self.sim_var_name_to_id.clear()
self.send_command("MF.SimVars.Clear")



39 changes: 39 additions & 0 deletions src/simconnect_mobiflight.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import logging, logging.handlers
import ctypes
from ctypes import wintypes
from SimConnect import SimConnect
from SimConnect.Enum import SIMCONNECT_CLIENT_DATA_ID, SIMCONNECT_RECV_ID, SIMCONNECT_RECV_CLIENT_DATA


class SimConnectMobiFlight(SimConnect):

def __init__(self, auto_connect=True, library_path=None):
self.client_data_handlers = []
if library_path:
super().__init__(auto_connect, library_path)
else:
super().__init__(auto_connect)
# Fix missing types
self.dll.MapClientDataNameToID.argtypes = [wintypes.HANDLE, ctypes.c_char_p, SIMCONNECT_CLIENT_DATA_ID]


def register_client_data_handler(self, handler):
if not handler in self.client_data_handlers:
logging.info("Register new client data handler")
self.client_data_handlers.append(handler)


def unregister_client_data_handler(self, handler):
if handler in self.client_data_handlers:
logging.info("Unregister client data handler")
self.client_data_handlers.remove(handler)


def my_dispatch_proc(self, pData, cbData, pContext):
dwID = pData.contents.dwID
if dwID == SIMCONNECT_RECV_ID.SIMCONNECT_RECV_ID_CLIENT_DATA:
client_data = ctypes.cast(pData, ctypes.POINTER(SIMCONNECT_RECV_CLIENT_DATA)).contents
for handler in self.client_data_handlers:
handler(client_data)
else:
super().my_dispatch_proc(pData, cbData, pContext)

0 comments on commit d025bab

Please sign in to comment.