User Interfaces and Usability for Embedded Systems

Feedback to "A Version Therapy"- Murphy's Law, July 2001

return to Murphy's Law

Dear Mr. Murphy,

I enjoyed your ESP article on firmware versioning. I wrote a module to read/write configuration data for a pressure gauge. I wish your article had come out before then as I discovered a lot of what you point out. Since I wrote this code I have been thinking about this problem and wondering how others have successfully solve it. Every solution I had to opportunity to review seemed insufficient. I wish I had thought of writing an article on this given the amount of time I've spent researching it.

I agree that storing C++ objects is not worth the effort. This is what I originally set out to do. In the end, I simply created accessors to read and write NVRAM.

I ran across another option when I was getting my cell phone upgraded. It assumes that you are using a PC-like computer to flash a firmware upgrade. Simply write a routine to upload the configuration data to the PC prior to the upgrade then download the data back. This has it's other potential problems like what to do if the connection fails during upload and download.

Also, I feel I must comment on your approach to the layout changing because of compiler flag changes and the like. I feel your suggestions are too reactive. I believe a developer should be more proactive in their design and implementation. I believe most developers will use a structure to store the layout as you show. Would it not be better to surround the structure definition with a '#pragma pack' to ensure the size right from the beginning? This way there will be no surprises later on - after much time spent debugging. Even if the compiler's pack statement is not portable to the next compiler or compiler version, the developer will find it at compile time, not run time. What are your thoughts?

Thanks again,
Mark Clayton
NetPlane Systems Inc
Dedham MA

Niall Murphy's reply to Mark Clayton

Your comment about using the #pragma pack is well considered, but you do not have any guarantee that 2 compilers will treat that progma the same way. Some compilers simply ignore pragma's that can not handle, so you have to watch for warnings. Compilers may have debug flags that supercede the #pragma. The bottom line is that if anything changes then you can not be certain that the layout will not change. If you generate some assembler and check it to be sure the layout has not changed, then you can happily change compilers, flags etc., but do not assume that something like this #pragma means that this problem goes away.

Andy Gryc makes some good points about needless complexity, and I wholeheartedly agree with him on all counts.

Hi Niall,

I enjoyed your article article that appeared in the July 2001 ESP. It in, you asked if users have had experience with placing C++ objects in persistent store. I've got some experience in this, and I can't recommend it.

I worked with another consultant on a project a couple of years back. He was an OO evangelist, whereas I'm more of a moderate. We had constant "battles" about the correct way to approach things: he would always recommend the "pure" way, where I would recommend a simple one. One example was that although the staff that would inherit the code once we were finished implementing was trained in C (not C++) he would insist that the "proper" way to do something in his part was to use templates. Where they certainly have their place, I feel that templates (and other non-obvious features of the language) can inappropriately limit the skill level of future maintainers of the software.

Unfortunately, he was also a little green in embedded systems, and designed a C++ class hierarchy that lived in persistent store (NVRAM). Of course, even though he applied discipline in maintaining the class *data*, the virtual table entries on the objects would change after every new link, which would cause old objects to crash once invoked. He didn't really know how the objects were layed out in memory (i.e. vtable pointers), and so didn't account for this eventuality. Without having to rewrite a large amount of his code, I ended up fixing the problem with a real kludge. The base objects kept an enum that identified the type of object, and each class derivation had to register itself with it's enum value and a static pointer to a "factory" that provided the correct vtable entry. On startup, the object list was walked, and the vtable pointer was reset to the correct value based on the value of the enum.

In contrast, the code that I wrote had a structure much like what you suggested: the NVRAM contained C structs, and a C++ wrapper was used to access them. Since it was very simple, it worked pretty much the first time, without encountering any fundamental design flaws.

In my opinion, the complexity required to manage C++ objects that required virtual methods in a persistent store was not worth the incremental benefit. Furthermore, the understandability of the code, especially given the skill level of the successors of the code, was severly compromised. I have yet to see a compelling case for putting C++ objects in persistent store, *except* when those objects are non-deriveable (i.e. "final" classes, like Date, Currency, etc.).

--Andy Gryc

[PanelSoft Home | Training Courses ]