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