EvenAR / node-simconnect

A cross platform SimConnect client library for Node.JS

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is it possible to read pmdg CDU screen data?

alptugidin opened this issue · comments

by doing this, i can get swicth values in pmdg 737

.then(({ recvOpen, handle }) => {
    console.log('Connected:', recvOpen);
    handle.addToDataDefinition(
      DefinitionID.LIVE_DATA,
      'L:switch_573_73X', // A key in CDU
      'bool',
      SimConnectDataType.STRING32,
      0,
      Tag.CDU_KEY 
    );

so how can i get the screen data? or is it possible? (example c++ code block from pmdg sdk document)

HRESULT hr;
if (SUCCEEDED(SimConnect_Open(&hSimConnect, "PMDG NG3 CDU Test", NULL, 0,0, 0)))
// Associate an ID with the PMDG data area name
hr = SimConnect_MapClientDataNameToID (hSimConnect,PMDG_NG3_CDU_0_NAME, PMDG_NG3_CDU_0_ID);
// Define the data area structure - this is a required step
hr = SimConnect_AddToClientDataDefinition (hSimConnect,PMDG_NG3_CDU_0_DEFINITION, 0,sizeof(PMDG_NG3_CDU_Screen), 0, 0);
// Sign up for notification of data change.
// SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_CHANGED flag asks for the data
// to be sent only when some of the data is changed.
hr = SimConnect_RequestClientData(
  hSimConnect, 
  PMDG_NG3_CDU_0_ID,
  CDU_DATA_REQUEST, PMDG_NG3_CDU_0_DEFINITION,
  SIMCONNECT_CLIENT_DATA_PERIOD_ON_SET,
  SIMCONNECT_CLIENT_DATA_REQUEST_FLAG_CHANGED, 0, 0, 0
);

Great question! I couldn't resist giving this a try myself - and yes it's possible!

First you need to look up the PMDG_NG3_CDU_Screen struct in the C header file from PMDG. Here's what I found in PMDG_NG3_SDK.h:

struct PMDG_NG3_CDU_Cell
{
    unsigned char	Symbol;			
    unsigned char	Color;     // any of PMDG_NG3_CDU_COLOR_ defines
    unsigned char	Flags;     // a combination of PMDG_NG3_CDU_FLAG_ bits
};

// NG3 CDU Screen Data Structure

#define CDU_COLUMNS	24
#define CDU_ROWS	14

struct PMDG_NG3_CDU_Screen
{
    PMDG_NG3_CDU_Cell Cells[CDU_COLUMNS][CDU_ROWS];	
    bool Powered;     // true if the CDU is powered
};

Once you have the struct definition you can calculate its size, which will replace sizeof(PMDG_NG3_CDU_Screen):
24 * 14 * (1+1+1) + 1 = 1009

The tricky part is extracting all the bytes from the received raw data correctly. You must read each part from the blob in the exact same order they are defined in the C-struct, with the correct size.

This is the code I ended up with:

// These consts were found in PMDG_NG3_SDK.h;
const PMDG_NG3_CDU_0_NAME = "PMDG_NG3_CDU_0";
const PMDG_NG3_CDU_0_ID = 0x4E473335;
const PMDG_NG3_CDU_0_DEFINITION = 0x4E473338;
const CDU_COLUMNS = 24;
const CDU_ROWS = 14;

// Based on the PMDG_NG3_CDU_Screen struct found in PMDG_NG3_SDK.h
const SCREEN_STATE_SIZE = CDU_COLUMNS * CDU_ROWS * (1+1+1) + 1;

const CDU_DATA_REQUEST = 0;

(async function readFmcScreen() {
    const { handle, recvOpen } = await open('My app', Protocol.KittyHawk)
    console.log('Connected:', recvOpen)

    handle.mapClientDataNameToID(PMDG_NG3_CDU_0_NAME, PMDG_NG3_CDU_0_ID)
    handle.addToClientDataDefinition(PMDG_NG3_CDU_0_DEFINITION, 0, SCREEN_STATE_SIZE)
    handle.requestClientData(
        PMDG_NG3_CDU_0_ID,
        CDU_DATA_REQUEST,
        PMDG_NG3_CDU_0_DEFINITION,
        ClientDataPeriod.ON_SET,
        ClientDataRequestFlag.CLIENT_DATA_REQUEST_FLAG_CHANGED
    )

    handle.on("exception", (ex) => console.log(ex))

    handle.on("clientData", recvSimObjectData => {
        const screenText: string[] = Array(CDU_ROWS).fill("")

        if (recvSimObjectData.requestID === CDU_DATA_REQUEST) {
            for (let col = 0; col < CDU_COLUMNS; col++) {
                for (let row = 0; row < CDU_ROWS; row++) {
                    const symbol = recvSimObjectData.data.readBytes(1).toString("utf-8") // I tried readString(1) but that only works with zero-terminated strings, which doesn't seem to be used here
                    const color = recvSimObjectData.data.readBytes(1)[0]
                    const flags = recvSimObjectData.data.readBytes(1)[0]
                    screenText[row] += symbol
                }
            }
            const cduPowered = recvSimObjectData.data.readBytes(1)[0] === 1

            if (cduPowered) {
                console.log(screenText.join("\r\n"))
            } else {
                console.log("Not powered")
            }
        }
    })
})()

Example output:

  ACT RTE           1/2 
 ORIGIN             DEST
ENGM                ENVA
 CO ROUTE        FLT NO.
-----           --------
 RUNWAY        FLT PLAN
-----           REQUEST>
------------------------
<SAVE



<ALTN DEST    PERF INIT>

EDIT: I added a complete example here