Given how much time has passed since the early days of the Canvas system and looking back at the lessons learnt during the porting efforts of Gijs' original NavDisplay code, and how we came up with the MapStructure framework subsequently vs. the number of other glass cockpit efforts (including those that actually proved to be successful, e.g. the shuttle via Richard's MFD framework), the best advice we can give to people wanting to implement new avionics using Nasal and the Canvas system can be distilled to be the following:
- Absolutely do all prototyping/development of your MFD/avionics using a standalone Canvas GUI dialog - this won't just be much faster (compared to doing cockpit-centric development), but this is also crucial to actually making sure that you don't end up adding all sorts of hard-coded assumptions about the use-case or the aircraft the instrument is going to be used on. Which sooner or later will translate into more people/aircraft using your work, and contributing to it, or maintaining/updating it - possibly years after you may have moved on to other things.
- If you find that you need custom logic to support a certain use-case/aircraft (think GUI dialog), structure your code to encapsulate such logic using delegates, i.e. function callbacks that can be passed to the underlying code to accomplish IOC (Inversion of Control).
- For the ND/MapStructure, we ended up moving all these assumptions into a configuration hash, so that there are no hard-coded properties in the ND/MapStructure code, which is to say that -with a corresponding "driver hash", the ND/MapStructure code could just as well be driven by an AI/MP node from /ai/models instead of using /properties, /orientation etc in a hard-coded fashion
- If it is foreseeable that you need to switch a set of APIs, encapsulate those, too - we were facing that dilemma, when people wanted to use navigraph data directly instead of the built-in navdb/navcache, by using a driver hash, we can do away with all built-in navcache queries and use a different navdb source.
- Do structure your MFD (and even a PFD) using something like Richard's MFD framework, i.e. using abstraction for pages, page items, menus and public state
- Keep the multi-pilot (dual-control) and multi-instance (multiplayer vs. FSWeekend/LinuxTag) use-cases in mind, which is to say that MFD building blocks like a map should publish element specific public state that can be shared between fgfs instances to selectively propagate/replicate relevant state to other fgfs instances running the same code, which means that even complex avionics like a G1000 could be kept in sync in a multiplayer or multi-instance use case by only replicating a fraction of crucial key state, rather than sync'ing low-level Canvas primitives at the Canvas::Element level.
- For pretty much the same reason, I would strongly suggest to look at Richard's Emesary framework, and maybe get in touch with him in private to see if it's feasible to integrate his MFD/Emesary frameworks in a sane fashion, to actually "have our cake and eat it" - I would not underestimate the power of using this approach, it has taken us quite a bit of effort to accomplish this degree of loose coupling in the NavDisplay code, and had we had access to Richard's groundwork back then, things could have become much simpler and much more efficient.
- Do permanently profile/benchmark (stress-test) your avionics (which is another good reason for supporting N independent instances), so that you are aware of where performance is spent - and if something shows up as a bottleneck, do document/share your findings, so that we can augment/extend the underlying C++ code.
- Encapsulate all uses of timers and listeners that primarily animate MFD stuff, so that a more proper method can be easily adopted once it is made available[1]
Related