Teste semf
Kontakt

Error Handling

General

In the deep-embedded field, isolating and understanding errors can be a big pain – less breakpoints and komplex hardware drivers can lead to frustration.
For helping 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 Error is unique 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 listes in each specific class, for example in the Logger class. There classes have a generic error signal.

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

In the implementation for every error case a 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;
    }
	// ...
} 

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 <Core/Signals/signal.h>
#include <Core/error.h>
#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, implement the ErrorCodes use the 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)));
		}
	}

	semf::Signal<1, semf::Error> error;
private:        
	static constexpr ClassId kClassId = Component0_Class0;
};

Connect the error signals to an onError slot in the application, where the error signals will arrive and can be post 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....
	}
	Component0_Class0 m_obj;
};

zurück zur Dokumentation