Skip to content
Snippets Groups Projects
ErrorHandler.hpp 7.09 KiB
#ifndef PROJECT_ERRORHANDLER_HPP
#define PROJECT_ERRORHANDLER_HPP

#include <type_traits>

// Forward declaration of the class, since its header file depends on the ErrorHandler
class Message;

#include <stdint.h> // for the uint_8t stepID

/**
 * A class that handles unexpected software errors, including internal errors or errors due to
 * invalid & incorrect input data.
 *
 * @todo Add auxiliary data field to errors
 */
class ErrorHandler {
private:
	/**
	 * Log the error to a logging facility. Platform-dependent.
	 */
	template<typename ErrorType>
	static void logError(const Message &message, ErrorType errorType);

	/**
	 * Log an error without a Message to a logging facility. Platform-dependent.
	 */
	template<typename ErrorType>
	static void logError(ErrorType errorType);

public:
	enum InternalErrorType {
		UnknownInternalError = 0,
		/**
		 * While writing (creating) a message, an amount of bytes was tried to be added but
		 * resulted in failure, since the message storage was not enough.
		 */
			MessageTooLarge = 1,
		/**
		 * Asked to append a number of bits larger than supported
		 */
			TooManyBitsAppend = 2,
		/**
		 * Asked to append a byte, while the previous byte was not complete
		 */
			ByteBetweenBits = 3,
		/**
		 * A string is larger than the largest allowed string
		 */
			StringTooLarge = 4,
		/**
		 * An error in the header of a packet makes it unable to be parsed
		 */
			UnacceptablePacket = 5,

		/**
		 * Asked a Message type that it doesn't exist
		 */
			UnknownMessageType = 6,
	};

	/**
	 * The error code for failed acceptance reports, as specified in ECSS 6.1.4.3d
	 *
	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
	 * changes.
	 */
	enum AcceptanceErrorType {
		UnknownAcceptanceError = 0,
		/**
		 * The received message does not contain enough information as specified
		 */
			MessageTooShort = 1,
		/**
		 * Asked to read a number of bits larger than supported
		 */
			TooManyBitsRead = 2,
		/**
		 * Cannot read a string, because it is larger than the largest allowed string
		 */
			StringTooShort = 4,
		/**
		 * Cannot parse a Message, because there is an error in its secondary header
		 */
			UnacceptableMessage = 5,
	};

	/**
	 * The error code for failed start of execution reports, as specified in ECSS 5.3.5.2.3g
	 *
	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
	 * changes.
	 */
	enum ExecutionStartErrorType {
		UnknownExecutionStartError = 0,
	};

	/**
	 * The error code for failed progress of execution reports, as specified in ECSS 5.3.5.2.3g
	 *
	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
	 * changes.
	 */
	enum ExecutionProgressErrorType {
		UnknownExecutionProgressError = 0,
	};

	/**
	 * The error code for failed completion of execution reports, as specified in ECSS 5.3.5.2.3g
	 *
	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
	 * changes.
	 */
	enum ExecutionCompletionErrorType {
		UnknownExecutionCompletionError = 0,
		/**
		 * Checksum comparison failed
		 */
			ChecksumFailed = 1,
		/**
		 * Address of a memory is out of the defined range for the type of memory
		 */
			AddressOutOfRange = 2,
	};

	/**
	 * The error code for failed routing reports, as specified in ECSS 6.1.3.3d
	 *
	 * Note: Numbers are kept in code explicitly, so that there is no uncertainty when something
	 * changes.
	 */
	enum RoutingErrorType {
		UnknownRoutingError = 0
	};

	/**
	 * The location where the error occurred
	 */
	enum ErrorSource {
		Internal,
		Acceptance,
		ExecutionStart,
		ExecutionProgress,
		ExecutionCompletion,
		Routing
	};

	/**
	 * Report a failure and, if applicable, store a failure report message
	 *
	 * @tparam ErrorType The Type struct of the error; can be AcceptanceErrorType,
	 * StartExecutionErrorType,CompletionExecutionErrorType,  or RoutingErrorType.
	 * @param message The incoming message that prompted the failure
	 * @param errorCode The error's code, as defined in ErrorHandler
	 * @todo See if this needs to include InternalErrorType
	 */
	template<typename ErrorType>
	static void reportError(const Message &message, ErrorType errorCode);

	/**
 	 * Report a failure about the progress of the execution of a request
 	 *
 	 * Note:This function is different from reportError, because we need one more /p(stepID)
 	 * to call the proper function for reporting the progress of the execution of a request
 	 *
 	 * @param message The incoming message that prompted the failure
 	 * @param errorCode The error's code, when a failed progress of the execution of a request
 	 * occurs
 	 * @param stepID If the execution of a request is a long process, then we can divide
	 * the process into steps. Each step goes with its own definition, the stepID. Each value
	 * ,that the stepID is assigned, should be documented.
 	 */
	static void reportProgressError(const Message &message, ExecutionProgressErrorType errorCode,
	                                uint8_t stepID);

	/**
	 * Report a failure that occurred internally, not due to a failure of a received packet.
	 *
	 * Note that these errors correspond to bugs or faults in the software, and should be treated
	 * differently. Such an error may prompt a task or software reset.
	 */
	static void reportInternalError(InternalErrorType errorCode);

	/**
	 * Make an assertion, to ensure that a runtime condition is met.
	 *
	 * Reports a failure that occurred internally, not due to a failure of a received packet.
	 *
	 * Creates an error if \p condition is false. The created error is Internal.
	 */
	static void assertInternal(bool condition, InternalErrorType errorCode) {
		if (not condition) {
			reportInternalError(errorCode);
		}
	}

	/**
	 * Make an assertion, to ensure that a runtime condition is met.
	 *
	 * Reports a failure that occurred while processing a request, in any of the process phases.
	 *
	 * Creates an error if \p condition is false. The created error corresponds to a \p message.
	 */
	template<typename ErrorType>
	static void assertRequest(bool condition, const Message &message, ErrorType errorCode) {
		if (not condition) {
			reportError(message, errorCode);
		}
	}
	/**
	 * Convert a parameter given in C++ to an ErrorSource that can be easily used in comparisons.
	 * @tparam ErrorType One of the enums specified in ErrorHandler.
	 * @param error An error code of a specific type
	 * @return The corresponding ErrorSource
	 */
	template<typename ErrorType>
	inline static ErrorSource findErrorSource(ErrorType error) {
		// While this may seem like a "hacky" way to convert enums to ErrorSource, it should be
		// optimised by the compiler to constant time.

		if (std::is_same<ErrorType, AcceptanceErrorType>()) {
			return Acceptance;
		}
		if (std::is_same<ErrorType, ExecutionStartErrorType>()) {
			return ExecutionStart;
		}
		if (std::is_same<ErrorType, ExecutionProgressErrorType>()) {
			return ExecutionProgress;
		}
		if (std::is_same<ErrorType, ExecutionCompletionErrorType>()) {
			return ExecutionCompletion;
		}
		if (std::is_same<ErrorType, RoutingErrorType>()) {
			return Routing;
		}
		return Internal;
	}
};

#endif //PROJECT_ERRORHANDLER_HPP