search the lab

Embedded Testing with Unity & CMock (by Mark)

Embedded Testing with Unity & CMock

James Grenning's book (features Unity)

Test Driven Development for Embedded C

Topics

« CMock Intro | Main | Unity Intro »
Wednesday
Feb162011

CException Intro

What is CException?

CException is simple exception handling in C. It is significantly faster than full-blown C++ exception handling but loses some flexibility. It is portable to any platform supporting setjmp/longjmp.

The main library is only two small files (CException.h and CException.c), plus maybe a config file where you stick 4 defines if you want to customize its behavior. When you download the package, you also get some docs and some tests that we have used to verify that everything is working peachy.

There is also a stub where you can define a function for CException to call when there is no master Try ... Catch... a fallback mechanism so that the application doesn't just take a blind leap into random memory.

There are about a gabillion exception frameworks using a similar setjmp/longjmp method out there... and there will probably be more in the future. Unfortunately, when we started our last embedded project, all those that existed either (a) did not support multiple tasks (therefore multiple stacks) or (b) were way more complex than we really wanted.

Why use CException?

  1. It's ANSI C, and it beats passing error codes around.
  2. You want something simple... CException throws a single id. You can define those ID's to be whatever you like. You might even choose which type that number is for your project. But that's as far as it goes. We weren't interested in passing objects or structs or strings... just simple error codes.
  3. Performance... CException can be configured for single tasking or multitasking. In single tasking, there is very little overhead past the setjmp/longjmp calls (which are already fast). In multitasking, your only overhead is the speed with which you can determine a unique task id.

Is it Reliable?

CException has been tested on a number of platforms (IAR ARM 4, IAR ARM 5, gcc, clang). We're using Unity for a test framework. Also, there are a couple of rules that you need to follow... as long as you stick to the rules, it's very reliable and robust.

Alternatives

Here are a couple of the 'gabillion' exception handling frameworks:

Adam M. Costello's cexcept - Nicely done. Feels a bit more like C++ and allows custom types. If it had existed before I started this project, mine might not exist. Still, it's a bit more complex to use and multitasking is rockier.

Doug Jone's Exception Handling - Small. Different syntax. No multitasking.

Examples

Old surly error handling

BOOL ProductionLine_DoWholeBunchOfStuff( int a )
{
   BOOL retVal = FALSE;

   if (Worker_DoStepA(a) == SUCCESS)
   {
      if (Worker_DoStepB(a+1) == SUCCESS)
      {
         if (Worker_DoStepC(a+2) == SUCCESS)
         {
            retVal = TRUE;
         }
      }
   }

   return retVal;
}

Way better mad scientist error handling

void ProductionLine_DoWholeBunchOfStuff( int a )
{
   CEXCEPTION_T e;

   Try
   {
      Worker_DoStepA(a);
      Worker_DoStepB(a+1);
      Worker_DoStepC(a+2);
   }
   Catch(e)
   {
      SystemLogger_Error(e);
   }
}

void Worker_DoStepA( int a )
{
   if (a < 100)
   {
      Throw( BOOM_GOES_THE_DYNAMITE );
   }

   // do something useful
}

// --- Tests ---

void test_ProductionLine_DoWholeBunchOfStuff( void )
{
   Worker_DoStepA_Expect( 50 );
   Worker_DoStepB_ExpectAndThrow( 51, BOOM_GOES_THE_DYNAMITE );
   SystemLogger_Error_Expect( BOOM_GOES_THE_DYNAMITE );

   ProductionLine_DoWholeBunchOfStuff( 50 );
}

void test_Worker_DoStepA( void )
{
   CEXCEPTION_T e;

   Worker_DoStepA( 101 );
   Worker_DoStepA( 100 );

   Try
   {
      Worker_DoStepA( 99 );
      TEST_FAIL_MESSAGE( "Should have thrown!" );
   }
   Catch(e)
   {
      TEST_ASSERT_EQUAL( BOOM_GOES_THE_DYNAMITE, e );
   }
}