How to read panel.xml

How to read for ex. the PC-24 configuration files? We need some Epic example planes.- Thanks

PC 24 is encrypted… use pc 12

Thanks I’ll try.

I started off posting just these notes but decided to cut-paste the code from my gauge as well… Not sure how much code is appropriate in this forum but if it helps, here it is (cut down for clarity). BTW I think the panel.xml support for html/js gauges is awesome. All my gauge work is RPN/HTML/JS so apologies if your interest is WASM.

Pls note inside my html/js ‘BaseInstrument’ class I consistently assign const instrument = this; mainly to propagate instrument through the calls, so the local instrument var is an alias for the BaseInstrument object. Not essential but with async code in JS there are various reasons why you need to be wary of the this variable, especially in callbacks.

General points:

  • Your parseXMLConfig() function is called asynchronously by the html/js gauge framework, much like connectedCallback(). When these async calls are made has no guarantees but your later code in the gauge will certainly have dependencies on these completing, so you’ll see I have instrument.config_complete = true; at the end of my parseXMLConfig(). I can use that e.g. to mask things in the Update() loop until things are ready.
  • The ‘spec’ for the panel.xml is to repeat elements called <Instrument> with an internal element called <Name> for each of your instruments which is a bit awkward, and I noted Working Title have side-stepped that for their instruments, instead using a unique tag for each of them. Makes it a lot easier to pull out the pertinent entry from the panel.xml file, especially if you have multiple instruments of the same type on the panel. In my example I’ve written that ‘id’ as MY_GAUGE but it’s whatever you think will be unique. The whole panel config is available to all gauges in instrument.xmlConfig so you can use getElementsByTagName("MY_GAUGE") from there.
  • FWIW I created a JS Class B21Config to hold the values from the config XML. Not really necessary but it’s super-simple and I included the code below.
  • It can be an important consideration how to differ the config across multiple instances of the same gauge on the same panel. This can be done by appending an ‘INDEX’ value to your instrument ‘BASENAME’ and that value can be picked up from the gauge URL in panel.cfg.

Your requirements may differ so a different approach could easily be better, but those hints might help. You could rightly be wary of going off-piste with panel XML element names, but I think I’m in good company. I actually have way of sharing the html/js between variants of a plane (different wingspans) and automatically pick up different config values for those (so they can share the same panel.xml file) but omitted that dimension here.

panel.xml

<PlaneHTMLConfig>
    <MY_GAUGE>
        <Name>MY_GAUGE</Name>
        <SettingsId>JS3</SettingsId>
        <Pages>["map","task","settings","grid"]</Pages>
        <Circuit>30</Circuit>
    </MY_GAUGE>
    ...
</PlaneHTMLConfig>

gauge js

I created a simple B21Config class for JS to hold the config values loaded from the XML, and instantiate that as instrument.config in the BaseInstrument constructor. As mentioned, not essential.

const instrument = this;
instrument.BASENAME = "MY_GAUGE";
instrument.INDEX = null;
...
instrument.config = new B21Config(
            {
                SETTINGS_ID: "",
                PAGES: ["map","task","settings","grid"],
                CIRCUIT: null,
            }

parseXMLConfig()

    // parseXMLConfig will load panel.xml and set instrument.config_complete = true
    parseXMLConfig() {
        const instrument = this;
        console.log("parseXMLConfig()");
        super.parseXMLConfig();
        if (instrument.xmlConfig) {
            try {
                let xml = instrument.xmlConfig.getElementsByTagName(instrument.BASENAME)[0];
                // All MY_GAUGE gauges load these common values
                instrument.load_panel_config(xml);
                // If this particular gauge has an INDEX, it can load more XML e.g. MY_GAUGE_1
                // which can add additional values or override the BASENAME gauge values.
                if (instrument.INDEX != null) {
                    let index_name = instrument.BASENAME+"_"+instrument.INDEX;
                    console.log("parseXMLConfig() loading indexed config from "+index_name);
                    let index_xml = instrument.xmlConfig.getElementsByTagName(index_name)[0];
                    if (index_xml != null) {
                        instrument.load_panel_config(index_xml);
                    }
                }
            } catch (e) {
                console.error("parseXMLConfig() fail",e);
            }
        } else {
            console.warn("No XML Config");
        }
        instrument.config_complete = true
    }

    load_panel_config(xml) {
        const instrument = this;
        console.log("instrument.load_panel_config() with index "+instrument.INDEX);

        let settings_id = instrument.config.get_string(xml, "SettingsId","");
        if (settings_id != null) {
            instrument.config.SETTINGS_ID = settings_id;
        }

        let pages = instrument.config.get_array(xml, "Pages");
        if (pages != null) {
            instrument.config.PAGES = pages;
        }

        let circuit = instrument.config.get_number(xml, "Circuit", -1);
        if (circuit >= 0) {
            instrument.config.CIRCUIT = circuit;
        }
    }

B21Config class

This is my optional class used to hold the panel.xml values. In the instrument it’s instantiated as instrument.config.

class B21Config {
    constructor(init_obj) {
        Object.assign(this, init_obj);
    }

    get_string(xml, tag_name, default_value) {
        let el = xml.getElementsByTagName(tag_name)[0];
        if (el) {
            try {
                let js_value = el.textContent;
                console.log(`B21Config.get_string for ${tag_name} found "${js_value}"`);
                return js_value;
            } catch (e) {
                console.warn(`B21Config.get_string failed for ${tag_name}`);
            }
        }
        console.warn(`B21Config.get_string using default for ${tag_name}`);
        return default_value;
    }

    get_number(xml, tag_name, default_value) {
        let el = xml.getElementsByTagName(tag_name)[0];
        if (el) {
            try {
                let js_value = JSON.parse(el.textContent);
                if (typeof js_value == "number") {
                    console.log(`B21Config.get_number for ${tag_name} found a number ${JSON.stringify(js_value)}`);
                    return js_value;
                } else {
                  console.warn(`B21Config.get_number not number for ${tag_name}`);
                }
            } catch (e) {
                console.warn(`B21Config.get_number failed for ${tag_name}`);
            }
        }
        console.warn(`B21Config.get_number using default for ${tag_name}`);
        return default_value;
    }

    get_array(xml, tag_name) {
        let el = xml.getElementsByTagName(tag_name)[0];
        if (el) {
            try {
                let js_value = JSON.parse(el.textContent);
                if (js_value instanceof Array) {
                    console.log(`B21Config.get_array for ${tag_name} found an array ${JSON.stringify(js_value)}`);
                    return js_value;
                } else {
                    console.log(`B21Config.get_array for ${tag_name} not an array`);
                }
            } catch (e) {
                console.warn(`B21Config.get_array failed for ${tag_name}`);
            }
        }
        return null;
    }

} // end class B21Config