semf
ErrorHandling

General

In the deep-embedded field isolating and understanding errors can be a big pain – less breakpoints and complex hardware drivers can lead to frustration. To help developers out in this field semf delivers a staightforward solution for error tracking which is optimized for low ROM and RAM.

Features

  • Fast error isolation
  • Functional safety compatible
  • Easy expandability
  • Advanced error tracking in combination with the FlashLogger

Functionality

To isolate an error fast an semf::Error is uniquely defined by a class ID and a class specific ErrorCode. The unique class ID can be found in the error.h file.

enum ClassID : uint32_t
{
// ...
SectionHardwareBegin = 0x08000000,
SectionAnaloginBegin,
Stm32AnalogIn,
// ...
SectionHardwareEnd = 0x0FFFFFFF,
SectionUserBegin = 0x10000000,
// User section can be used in the application
SectionUserEnd = 0xFFFFFFFF
}

The class spesific ErrorCodes are listed in each specific class. For example in the Logger class where classes have a generic error signal.

class Logger
{
// ...
enum class ErrorCode : uint8_t
{
AddEntry_IsBusy = 0,
AddEntry_PayloadIsNullptr,
AddEntry_NotInitialized,
// ...
};
// ...
Signal<Error> error;
// ...

In the implementation for every error case an Error object will be emitted by the error signal.

bool Logger::addEntry(Entry& entry)
{
if (m_busy)
{
SEMF_ERROR("is busy");
onError(Error(kSemfClassId, static_cast(ErrorCode::AddEntry_IsBusy)));
return false;
}
// ...
}
#define SEMF_ERROR(...)
Definition: debug.h:39

To catch all error signals it is recomended to have an onError slot in the application and connect the error signals as shown in the user code example below.

User Application Example

To use the semf error handling functionality in an user application the following steps are recommended.

Add a file where all application components / classes are listed. semf has a predefined begin and end value for the unique class IDs.

#include <cstdio>
enum class UserClasses : uint32_t
{
Begin = static_cast(semf::Error::ClassID::SectionUserBegin),
Component0_Begin,
Component0_Class0,
Component0_Class1,
Component0_Class2,
Component0_End,
End = semf::Error::ClassID::SectionUserEnd
};

Create components which have their own ErrorCodes, classId and error signal

class Class0
{
public:
enum class ErrorCode : uint8_t
{
Foo_InvalidParameter = 0
};
void foo(void* param)
{
if (param == nullptr)
{
error(semf::Error(static_cast<uint32_t>(kClassId), static_cast<uint8_t>(ErrorCode::Foo_InvalidParameter)));
}
}
private:
static constexpr ClassId kClassId = Component0_Class0;
};
Class for representing errors. Every error should have a unique source code. As a user feel encourage...
Definition: error.h:22

Connect the error signals to an onError slot in the application where the error signals will be processed.

class Application
{
public:
void init()
{
// connect the error signal
m_obj.error.clear()
m_obj.error.connect(this, &Application::onError);
// invalid operation
m_obj.foo(nullptr);
}
private:
void onError(semf::Error thrown)
{
printf("Error %u from %u\n", thrown.classId(), thrown.errorCode());
// maybe add some more specific error handling....
}
SEMF_SLOT(m_onErrorSlot, Application, *this, onError, semf::Error);
Component0_Class0 m_obj;
};
uint8_t errorCode() const
Returns the error code from the error.
Definition: error.cpp:30
uint32_t classId() const
Returns the class id from the error.
Definition: error.cpp:25
#define SEMF_SLOT(name, className, object, function,...)
Creates a semf slot.
Definition: slot.h:30