The CRJ 1.4.5 update is uploading to the publishers now, and you will see it on your machines this week.
The biggest advance is what I call the no-more-pretzels-technology. The CRJ was notorious for doing awkward things when trying to enter a holding pattern. Entering a holding in what was supposed to be a parallel entry looked more like flying a pretzel.
If you are not interested in software development, you can stop reading here. Just believe me it works great now. If you want to know why, read on.
How does no-more-pretzels work?
It is all about treating object-oriented design as type-design. Just like Scott Meyers says in Effective C++ (i take it for granted you all have a copy of this book besides your bed. If not, buy it now!) you're not doing object-oriented design right unless you treat class design as type design.
The key to get the holdings right was to solve the confusion I was having about the four types of "course" there are:
- True Track
- Magnetic Track
- True Heading
- Magnetic Heading
If you are passing around courses as numbers (floats), you are in the constant state of wondering "wait, is this magnetic? And what about wind here anyway? Is the wind direction magnetic or true? Can I add a correction with regard to magnetic wind on this true course?".
Believe me, you will screw that big times. My git log shows I touched the holding and holding entry code a gazillion times correcting such problems.
Now types to the rescue: A true track is not a float! A true track is a type! And a true course is a different type!
So here's how it works: You can't compare a true track to a magnetic heading. Because there is no operator for that. You can't add a magnetic wind correction on a true heading. No operator for that.
Compare this code:
float crs = 315.f; // is this 315 true or magnetic ??? crs += mag_var; // did we just correct from true to mag or the other way? crs += wca; // did we just convert track to heading or heading to track???
with this code:
// MagenticTrack holding_inbd = 315._degm; /* You can do this if your compiler supports C++11 user-defined literals, which for now only a gcc 4.7 pre-release does */ MagenticTrack holding_inbd = MagneticTrack::fromDegrees(315); WindCorrection wca = WindCorrection::fromTrackAndWind(holding_inbd, wind, groundspeed); // operator+ overloading ftw! MagneticHeading crs_to_steer = holding_inbd + wca;
More verbose, certainly, but compile-time checked to make sense.
Compile-time checked to not fly pretzels.
Yesterday we shipped the 1.3 update for the CRJ. It included the much-awaited remote CDU functionality, which is basically a web server running in the plugin, serving the CDU screen in HTML format via Ajax.
The webserver in the plugin is a very basic HTTP server built with boost.asio, an incredibly powerful cross-platform asynchronous network library.
Thinking progressive as I always do, I of course built the webserver with IPv6 support, and configured it to always start in dual-stack mode, that means it serves the CDU both via IPv4 and IPv6.
I thought I could relax on that basis, and not touch this code again until the IPv6 address space is full.
I was so wrong!
Reports from customers kept coming in, that they couldn't start the CRJ any more. A very helpful customer showed me a gdb stacktrace of what was wrong. Guess what: it couldn't open a listening socket on 0::0, the "any" IP address in IPv6.
No, this guy was not using Windows 98. He was using the latest and greatest Ubuntu Linux. SRSLY, WTF?! It is 2011 and Ubuntu 11.10 has IPv6 support disabled by default?
Next customer with this problem was using Windows XP. Still the most popular MS OS these days. Guess what, no IPv6 enabled by default!
After instructing those guys how to enable IPv6 on their machines, I coded a patch for the server, to fallback to IPv4 only when dual-stack is unavailable. This is released as the 1.3.1 hotfix now.
I wonder how this planet is going to make the transition to IPv6 any time soon, when about 25% of my customers just can't use it without browsing through cryptic knowledgebase articles...