books for embedded software development

I have been having some private email discussions about this thread and an example that first focused me about the impact of standard reliability math on software was brought home in a early software project that I had a contract for.

This project involved fixing daisy wheel printer software that some one had written that was implemented as a strange state machine that was losing characters both on paper and part of the serial protocol. The printer had evolved over time to have more features and support faster serial speeds. It had what appeared to be random failures resulting in increasing customer complaints. Among other things the printer was being used to print banking check masters.

A total of maybe a 100 lines of code (out of about 20k lines) that changed the scheduler from truly round robin with about 75 items in the loop many of them duplicated because of there need to be serviced in less time than the loop time. Most items most of the time didn't execute but sometimes many did all contributing to the series communication irregularities and timing problems for everybody.

The serial communication was separated from the printer parts and two co_routine loops were created. The implementation had no interrupts. Instead of executing all the possible printer functions each time I executed one printer function dropping the 75 count back to about

30 eliminating some boolean flags and duplicate and split functions. The printer would actually run faster than previously and about 30% of the processor (F8 it does go back) still available.

Most of the code was unchanged (about 0.5% of the code was changed) The primary failure was timing and in a few cases random combinations of the order of execution of events. The two conflicting timing parts serial data and actual print functions were isolated so they would not interfere with each other.

The fix actually took less than a week and rigorous testing on the site of a particular critical (and knowledgeable) customer confirmed the approach.

Walter Banks Byte Craft Limited

Reply to
Walter Banks
Loading thread data ...

First I like Samek's book , it is well written and has a lot of good material in it.

This issue is the problem that has been found in most large state machines. Every state is combination of all of the possible state combinations that can reach that point. As the state count increases the number of reliability series terms grows and the system reliability decreases. Reliable but not perfect code can tolerate some failure and the system will continue to function. At some point as the the code grows it becomes fragile where bug arrival rate and death rate are about equal because the application cannot tolerate the little but non fatal failures. Reducing the number of series terms in the reliability calculation does a lot for extending the system reliability as the system gets more complex.

One test that we have used in applications is to assign some arbitrary reliability for each piece of straight line code (say 1) and then solve the system reliability. It is not a shining example objective reliability prediction but it does help identify the parts of an application that has potential reliability issues that should be focused on.

Walter Banks Byte Craft Limited

Reply to
Walter Banks

There are two common situations when signed/unsigned can cause trouble - when doing any multiplies or divides, or dealing with wrapparound or overflow. Unsigned arithmetic in C has clearly defined overflow semantics - it operates as mod 2^n arithmetic. But signed arithmetic has no such specifications, and the compiler can assume that it never overflows (since overflow is undefined, the compiler can do what it wants in that case).

My preference these days is to be entirely explicit - I enable warnings on signed conversions, and explicitly cast as needed. I too use more unsigned types - but since everything is specified there is no "default" in my code.

That raises a good question - should you write code to handle undefined bad states, or should you write code that never gets into a bad state?

Reply to
David Brown

That's why we have typedef.

typedef uint8_t small_counter;

or even

typedef uint_fast8_t small_counter;

Then everyone is happy.

Reply to
David Brown

would you kindly have a look at the link I included instead of assuming the ar code *is included* in the binutils?

Your confidence is good on one hand but it maybe read as arrogance on another. I suggest you download the package from the link I posted and have a look yourself to the content. If you don't have time to do that I can understand, but if I were you I would not assume what can and cannot be in such a strong way.

Reply to
Alessandro Basili

by

ones.

According to FOLDOC (which is usually right): Block Started by Symbol (BSS) The uninitialised data segment produced by Unix linkers. Objects in the bss segment have only a name and a size but no value.

Executable code is located in the code segment and initialised data in the data segment.

formatting link

Of course, that is Unix, not C.

--------------------------------------- Posted through

formatting link

Reply to
RCIngham

I think you should try to do both.

I try to write my code to the latter standard, but I assume I will not always succeed. Therefore, I try to structure my code in such a way as to try and force a internal consistancy check failure when I do make a mistake.

Simon.

--
Simon Clubley, clubley@remove_me.eisner.decus.org-Earth.UFP
Microsoft: Bringing you 1980s technology to a 21st century world
Reply to
Simon Clubley

The problem with such a tactic is testing. You should not write code that you cannot, or have not, tested accurately - even if it is unlikely that it will run, it is still something else that could go wrong. And such error code will not run in a real system, unless you have made a mistake - so in the process of testing you should find and fix that mistake.

But sometimes a simple, general "Stop the system, program error" mode can be appropriate. It can certainly be a help during development and debugging.

In the case of uninitialised variables, of course, it is totally unnecessary. Static variables are always initialised - either explicitly, or implicitly zeroed by the C startup code. Automatic variables are either properly initialised, or your compiler's warning messages tell you of the problem (and if your compiler won't do that, use a different compiler).

Reply to
David Brown

That's true, but the *nix (and Windows) program loaders clear the BSS area to zeros, which, on most architectures, satisfies the requirements for non-explicitly initialized static variables in C (pointers to NULL, other values to unsigned zero or positive zero as appropriate).

That's not true on all platforms, and on those the CRT* will require explicit code to clear the BSS area. IIRC, MS-DOS used to a specified amount of extra area when loading a MZ executable, which was often used for BSS storage, but it did not clear the area, so there was code in the CRT startup to do it.

*In practice we usually consider the CRT and OS separately, but that's not true from the perspective of the standard, where there's just some amount of magic that must happen before the first line of main() is executed.
Reply to
Robert Wessel

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.