Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,119 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utils/error.hpp>
#include <everest/helpers/helpers.hpp>
#include <everest/logging.hpp>
namespace Everest {
namespace error {
UUID::UUID() {
uuid = everest::helpers::get_uuid();
}
UUID::UUID(const std::string& uuid_) : uuid(uuid_) {
}
bool UUID::operator<(const UUID& other) const {
return uuid < other.uuid;
}
bool UUID::operator==(const UUID& other) const {
return this->uuid == other.uuid;
}
bool UUID::operator!=(const UUID& other) const {
return !(*this == other);
}
std::string UUID::to_string() const {
return uuid;
}
Error::Error(const ErrorType& type_, const ErrorSubType& sub_type_, const std::string& message_,
const std::string& description_, const ImplementationIdentifier& origin_, const std::string& vendor_id_,
const Severity& severity_, const time_point& timestamp_, const UUID& uuid_, const State& state_) :
type(type_),
sub_type(sub_type_),
message(message_),
description(description_),
origin(origin_),
vendor_id(vendor_id_),
severity(severity_),
timestamp(timestamp_),
uuid(uuid_),
state(state_) {
}
Error::Error(const ErrorType& type_, const ErrorSubType& sub_type_, const std::string& message_,
const std::string& description_, const ImplementationIdentifier& origin_, const Severity& severity_) :
Error(type_, sub_type_, message_, description_, origin_, UTILS_ERROR_DEFAULTS_VENDOR_ID, severity_,
UTILS_ERROR_DEFAULTS_TIMESTAMP, UTILS_ERROR_DEFAULTS_UUID) {
}
Error::Error(const ErrorType& type_, const ErrorSubType& sub_type_, const std::string& message_,
const std::string& description_, const std::string& origin_module_,
const std::string& origin_implementation_, const Severity& severity_) :
Error(type_, sub_type_, message_, description_,
ImplementationIdentifier(origin_module_, origin_implementation_, std::nullopt), severity_) {
}
Error::Error() :
Error(UTILS_ERROR_DEFAULTS_TYPE, UTILS_ERROR_DEFAULTS_SUB_TYPE, UTILS_ERROR_DEFAULTS_MESSAGE,
UTILS_ERROR_DEFAULTS_DESCRIPTION, UTILS_ERROR_DEFAULTS_ORIGIN, UTILS_ERROR_DEFAULTS_SEVERITY) {
}
std::string severity_to_string(const Severity& s) {
switch (s) {
case Severity::Low:
return "Low";
case Severity::Medium:
return "Medium";
case Severity::High:
return "High";
}
EVLOG_error << "No known string conversion for provided enum of type Severity. Defaulting to High.";
return "High";
}
Severity string_to_severity(const std::string& s) {
if (s == "Low") {
return Severity::Low;
} else if (s == "Medium") {
return Severity::Medium;
} else if (s == "High") {
return Severity::High;
}
EVLOG_error << "Provided string " << s << " could not be converted to enum of type Severity. Defaulting to High.";
return Severity::High;
}
std::string state_to_string(const State& s) {
switch (s) {
case State::Active:
return "Active";
case State::ClearedByModule:
return "ClearedByModule";
case State::ClearedByReboot:
return "ClearedByReboot";
}
EVLOG_error << "No known string conversion for provided enum of type State. Defaulting to Active.";
return "Active";
}
State string_to_state(const std::string& s) {
if (s == "Active") {
return State::Active;
} else if (s == "ClearedByModule") {
return State::ClearedByModule;
} else if (s == "ClearedByReboot") {
return State::ClearedByReboot;
}
EVLOG_error << "Provided string " << s << " could not be converted to enum of type State. Defaulting to Active.";
return State::Active;
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,110 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utils/error/error_database_map.hpp>
#include <everest/logging.hpp>
#include <utils/error.hpp>
#include <utils/error/error_json.hpp>
#include <algorithm>
namespace Everest {
namespace error {
void ErrorDatabaseMap::add_error(ErrorPtr error) {
const std::lock_guard<std::mutex> lock(this->errors_mutex);
if (this->errors.find(error->uuid) != this->errors.end()) {
std::stringstream ss;
ss << "Error with handle " << error->uuid.to_string() << " already exists in ErrorDatabaseMap." << std::endl;
ss << "Error object: " << nlohmann::json(*error).dump(2);
EVLOG_error << ss.str();
return;
}
this->errors[error->uuid] = error;
}
std::list<ErrorPtr> ErrorDatabaseMap::get_errors(const std::list<ErrorFilter>& filters) const {
const std::lock_guard<std::mutex> lock(this->errors_mutex);
return this->get_errors_no_mutex(filters);
}
std::list<ErrorPtr> ErrorDatabaseMap::get_errors_no_mutex(const std::list<ErrorFilter>& filters) const {
BOOST_LOG_FUNCTION();
std::list<ErrorPtr> result;
std::transform(this->errors.begin(), this->errors.end(), std::back_inserter(result),
[](const std::pair<ErrorHandle, ErrorPtr>& entry) { return entry.second; });
for (const ErrorFilter& filter : filters) {
std::function<bool(const ErrorPtr&)> pred;
switch (filter.get_filter_type()) {
case FilterType::State: {
pred = []([[maybe_unused]] const ErrorPtr& error) { return false; };
EVLOG_error << "ErrorDatabaseMap does not support StateFilter. Ignoring.";
} break;
case FilterType::Origin: {
pred = [&filter](const ErrorPtr& error) { return error->origin != filter.get_origin_filter(); };
} break;
case FilterType::Type: {
pred = [&filter](const ErrorPtr& error) { return error->type != filter.get_type_filter().value; };
} break;
case FilterType::Severity: {
pred = [&filter](const ErrorPtr& error) {
switch (filter.get_severity_filter()) {
case SeverityFilter::LOW_GE: {
return error->severity < Severity::Low;
} break;
case SeverityFilter::MEDIUM_GE: {
return error->severity < Severity::Medium;
} break;
case SeverityFilter::HIGH_GE: {
return error->severity < Severity::High;
} break;
}
EVLOG_error << "No known condition for provided enum of type SeverityFilter.";
return false;
};
} break;
case FilterType::TimePeriod: {
pred = [&filter](const ErrorPtr& error) {
return error->timestamp < filter.get_time_period_filter().from ||
error->timestamp > filter.get_time_period_filter().to;
};
} break;
case FilterType::Handle: {
pred = [&filter](const ErrorPtr& error) { return error->uuid != filter.get_handle_filter(); };
} break;
case FilterType::SubType: {
pred = [&filter](const ErrorPtr& error) { return error->sub_type != filter.get_sub_type_filter().value; };
} break;
case FilterType::VendorId: {
pred = [&filter](const ErrorPtr& error) { return error->vendor_id != filter.get_vendor_id_filter().value; };
} break;
default:
EVLOG_error << "No known pred for provided enum of type FilterType. Ignoring.";
return result;
}
result.remove_if(pred);
}
return result;
}
std::list<ErrorPtr> ErrorDatabaseMap::edit_errors(const std::list<ErrorFilter>& filters, EditErrorFunc edit_func) {
const std::lock_guard<std::mutex> lock(this->errors_mutex);
std::list<ErrorPtr> result = this->get_errors_no_mutex(filters);
for (const ErrorPtr& error : result) {
edit_func(error);
}
return result;
}
std::list<ErrorPtr> ErrorDatabaseMap::remove_errors(const std::list<ErrorFilter>& filters) {
BOOST_LOG_FUNCTION();
const EditErrorFunc remove_func = [this](const ErrorPtr& error) { this->errors.erase(error->uuid); };
return this->edit_errors(filters, remove_func);
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,185 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utility>
#include <utils/error/error_factory.hpp>
#include <utils/error/error_type_map.hpp>
namespace Everest {
namespace error {
ErrorFactory::ErrorFactory(std::shared_ptr<ErrorTypeMap> error_type_map_) :
ErrorFactory(error_type_map_, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt,
std::nullopt) {
}
ErrorFactory::ErrorFactory(std::shared_ptr<ErrorTypeMap> error_type_map_, ImplementationIdentifier default_origin_) :
ErrorFactory(error_type_map_, default_origin_, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt,
std::nullopt) {
}
ErrorFactory::ErrorFactory(std::shared_ptr<ErrorTypeMap> error_type_map_, ImplementationIdentifier default_origin_,
Severity default_severity_) :
ErrorFactory(error_type_map_, default_origin_, default_severity_, std::nullopt, std::nullopt, std::nullopt,
std::nullopt, std::nullopt) {
}
ErrorFactory::ErrorFactory(std::shared_ptr<ErrorTypeMap> error_type_map_,
std::optional<ImplementationIdentifier> default_origin_,
std::optional<Severity> default_severity_, std::optional<State> default_state_,
std::optional<ErrorType> default_type_, std::optional<ErrorSubType> default_sub_type_,
std::optional<std::string> default_message_, std::optional<std::string> default_vendor_id_) :
error_type_map(error_type_map_),
default_origin(std::move(default_origin_)),
default_severity(default_severity_),
default_state(default_state_),
default_type(std::move(default_type_)),
default_sub_type(std::move(default_sub_type_)),
default_message(std::move(default_message_)),
default_vendor_id(std::move(default_vendor_id_)) {
}
Error ErrorFactory::create_error() const {
Error error;
if (default_origin.has_value()) {
error.origin = default_origin.value();
}
if (default_severity.has_value()) {
error.severity = default_severity.value();
}
if (default_state.has_value()) {
error.state = default_state.value();
}
if (default_type.has_value()) {
error.type = default_type.value();
}
if (default_sub_type.has_value()) {
error.sub_type = default_sub_type.value();
}
if (default_message.has_value()) {
error.message = default_message.value();
}
if (default_vendor_id.has_value()) {
error.vendor_id = default_vendor_id.value();
}
set_description(error);
return error;
}
Error ErrorFactory::create_error(const ErrorType& type, const ErrorSubType& sub_type,
const std::string& message) const {
Error error;
error.type = type;
error.sub_type = sub_type;
error.message = message;
if (default_origin.has_value()) {
error.origin = default_origin.value();
}
if (default_severity.has_value()) {
error.severity = default_severity.value();
}
if (default_state.has_value()) {
error.state = default_state.value();
}
if (default_vendor_id.has_value()) {
error.vendor_id = default_vendor_id.value();
}
set_description(error);
return error;
}
Error ErrorFactory::create_error(const ErrorType& type, const ErrorSubType& sub_type, const std::string& message,
const Severity severity) const {
Error error;
error.type = type;
error.sub_type = sub_type;
error.message = message;
error.severity = severity;
if (default_origin.has_value()) {
error.origin = default_origin.value();
}
if (default_state.has_value()) {
error.state = default_state.value();
}
if (default_vendor_id.has_value()) {
error.vendor_id = default_vendor_id.value();
}
set_description(error);
return error;
}
Error ErrorFactory::create_error(const ErrorType& type, const ErrorSubType& sub_type, const std::string& message,
const State state) const {
Error error;
error.type = type;
error.sub_type = sub_type;
error.message = message;
error.state = state;
if (default_origin.has_value()) {
error.origin = default_origin.value();
}
if (default_severity.has_value()) {
error.severity = default_severity.value();
}
if (default_vendor_id.has_value()) {
error.vendor_id = default_vendor_id.value();
}
set_description(error);
return error;
}
Error ErrorFactory::create_error(const ErrorType& type, const ErrorSubType& sub_type, const std::string& message,
const Severity severity, const State state) const {
Error error;
error.type = type;
error.sub_type = sub_type;
error.message = message;
error.severity = severity;
error.state = state;
if (default_origin.has_value()) {
error.origin = default_origin.value();
}
if (default_vendor_id.has_value()) {
error.vendor_id = default_vendor_id.value();
}
set_description(error);
return error;
}
void ErrorFactory::set_default_origin(const ImplementationIdentifier& origin) {
default_origin = origin;
}
void ErrorFactory::set_default_severity(Severity severity) {
default_severity = severity;
}
void ErrorFactory::set_default_state(State state) {
default_state = state;
}
void ErrorFactory::set_default_type(const ErrorType& type) {
default_type = type;
}
void ErrorFactory::set_default_sub_type(const ErrorSubType& sub_type) {
default_sub_type = sub_type;
}
void ErrorFactory::set_default_message(const std::string& message) {
default_message = message;
}
void ErrorFactory::set_default_vendor_id(const std::string& vendor_id) {
default_vendor_id = vendor_id;
}
void ErrorFactory::set_description(Error& error) const {
if (error.type == "") {
return;
}
error.description = error_type_map->get_description(error.type);
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,181 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utils/error/error_filter.hpp>
#include <everest/exceptions.hpp>
#include <everest/logging.hpp>
namespace Everest {
namespace error {
std::string state_filter_to_string(const StateFilter& f) {
return state_to_string(f);
}
StateFilter string_to_state_filter(const std::string& s) {
return string_to_state(s);
}
std::string severity_filter_to_string(const SeverityFilter& f) {
switch (f) {
case SeverityFilter::LOW_GE:
return "LOW_GE";
case SeverityFilter::MEDIUM_GE:
return "MEDIUM_GE";
case SeverityFilter::HIGH_GE:
return "HIGH_GE";
}
EVLOG_error << "No known string conversion for provided enum of type SeverityFilter. Defaulting to HIGH_GE";
return "HIGH_GE";
}
SeverityFilter string_to_severity_filter(const std::string& s) {
if (s == "LOW_GE") {
return SeverityFilter::LOW_GE;
} else if (s == "MEDIUM_GE") {
return SeverityFilter::MEDIUM_GE;
} else if (s == "HIGH_GE") {
return SeverityFilter::HIGH_GE;
}
EVLOG_error << "Provided string " << s
<< " could not be converted to enum of type SeverityFilter. Defaulting to HIGH_GE";
return SeverityFilter::HIGH_GE;
}
TypeFilter::TypeFilter(const ErrorType& value_) : value(value_) {
}
SubTypeFilter::SubTypeFilter(const ErrorSubType& value_) : value(value_) {
}
VendorIdFilter::VendorIdFilter(const std::string& value_) : value(value_) {
}
std::string filter_type_to_string(const FilterType& f) {
switch (f) {
case FilterType::State:
return "State";
case FilterType::Origin:
return "Origin";
case FilterType::Type:
return "Type";
case FilterType::Severity:
return "Severity";
case FilterType::TimePeriod:
return "TimePeriod";
case FilterType::Handle:
return "Handle";
case FilterType::SubType:
return "SubType";
case FilterType::VendorId:
return "VendorId";
}
EVLOG_error << "No known string conversion for provided enum of type FilterType. Defaulting to Type";
return "Type";
}
FilterType string_to_filter_type(const std::string& s) {
if (s == "State") {
return FilterType::State;
} else if (s == "Origin") {
return FilterType::Origin;
} else if (s == "Type") {
return FilterType::Type;
} else if (s == "Severity") {
return FilterType::Severity;
} else if (s == "TimePeriod") {
return FilterType::TimePeriod;
} else if (s == "Handle") {
return FilterType::Handle;
} else if (s == "SubType") {
return FilterType::SubType;
} else if (s == "VendorId") {
return FilterType::VendorId;
}
EVLOG_error << "Provided string " << s << " could not be converted to enum of type FilterType. Deafulting to Type.";
return FilterType::Type;
}
ErrorFilter::ErrorFilter() = default;
ErrorFilter::ErrorFilter(const FilterVariant& filter_) : filter(filter_) {
}
FilterType ErrorFilter::get_filter_type() const {
if (filter.index() == 0) {
EVLOG_error << "Filter type is not set. Defaulting to 'FilterType::State'.";
return FilterType::State;
}
return static_cast<FilterType>(filter.index());
}
StateFilter ErrorFilter::get_state_filter() const {
if (this->get_filter_type() != FilterType::State) {
EVLOG_error << "Filter type is not StateFilter. Defaulting to 'StateFilter::Active'.";
return StateFilter::Active;
}
return std::get<StateFilter>(filter);
}
OriginFilter ErrorFilter::get_origin_filter() const {
if (this->get_filter_type() != FilterType::Origin) {
EVLOG_error << "Filter type is not OriginFilter. Defaulting to "
"'OriginFilter::ImplementationIdentifier(\"no-module-id-provided\", "
"\"no-implementation-id-provided\")'.";
return OriginFilter(
ImplementationIdentifier("no-module-id-provided", "no-implementation-id-provided", std::nullopt));
}
return std::get<OriginFilter>(filter);
}
TypeFilter ErrorFilter::get_type_filter() const {
if (this->get_filter_type() != FilterType::Type) {
EVLOG_error << "Filter type is not TypeFilter. Defaulting to 'TypeFilter(\"no-type-provided\")'.";
return TypeFilter("no-type-provided");
}
return std::get<TypeFilter>(filter);
}
SeverityFilter ErrorFilter::get_severity_filter() const {
if (this->get_filter_type() != FilterType::Severity) {
EVLOG_error << "Filter type is not SeverityFilter. Defaulting to 'SeverityFilter::HIGH_GE'.";
return SeverityFilter::HIGH_GE;
}
return std::get<SeverityFilter>(filter);
}
TimePeriodFilter ErrorFilter::get_time_period_filter() const {
if (this->get_filter_type() != FilterType::TimePeriod) {
EVLOG_error << "Filter type is not TimePeriodFilter. Defaulting to 'TimePeriodFilter{Error::time_point(), "
"Error::time_point()}'.";
return TimePeriodFilter{Error::time_point(), Error::time_point()};
}
return std::get<TimePeriodFilter>(filter);
}
HandleFilter ErrorFilter::get_handle_filter() const {
if (this->get_filter_type() != FilterType::Handle) {
EVLOG_error << "Filter type is not HandleFilter. Defaulting to 'HandleFilter()'.";
return HandleFilter();
}
return std::get<HandleFilter>(filter);
}
SubTypeFilter ErrorFilter::get_sub_type_filter() const {
if (this->get_filter_type() != FilterType::SubType) {
EVLOG_error << "Filter type is not SubTypeFilter. Defaulting to 'SubTypeFilter(\"no-sub-type-provided\")'.";
return SubTypeFilter("no-sub-type-provided");
}
return std::get<SubTypeFilter>(filter);
}
VendorIdFilter ErrorFilter::get_vendor_id_filter() const {
if (this->get_filter_type() != FilterType::VendorId) {
throw EverestBaseLogicError("Filter type is not VendorIdFilter.");
}
return std::get<VendorIdFilter>(filter);
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,151 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utility>
#include <utils/error/error_manager_impl.hpp>
#include <utils/error.hpp>
#include <utils/error/error_database.hpp>
#include <utils/error/error_json.hpp>
#include <utils/error/error_type_map.hpp>
#include <everest/logging.hpp>
#include <list>
#include <memory>
namespace Everest {
namespace error {
ErrorManagerImpl::ErrorManagerImpl(std::shared_ptr<ErrorTypeMap> error_type_map_,
std::shared_ptr<ErrorDatabase> error_database_,
std::list<ErrorType> allowed_error_types_,
ErrorManagerImpl::PublishErrorFunc publish_raised_error_,
ErrorManagerImpl::PublishErrorFunc publish_cleared_error_,
const bool validate_error_types_) :
error_type_map(error_type_map_),
database(error_database_),
allowed_error_types(std::move(allowed_error_types_)),
publish_raised_error(std::move(publish_raised_error_)),
publish_cleared_error(std::move(publish_cleared_error_)),
validate_error_types(validate_error_types_) {
if (validate_error_types) {
for (const ErrorType& type : allowed_error_types) {
if (!error_type_map->has(type)) {
EVLOG_error << "Error type '" << type << "' in allowed_error_types is not defined, ignored.";
}
}
}
}
void ErrorManagerImpl::raise_error(const Error& error) {
if (validate_error_types) {
if (std::find(allowed_error_types.begin(), allowed_error_types.end(), error.type) ==
allowed_error_types.end()) {
std::stringstream ss;
ss << "Error type " << error.type << " is not allowed to be raised. Ignoring.";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
}
const std::lock_guard<std::mutex> lock(mutex);
if (!can_be_raised(error.type, error.sub_type)) {
std::stringstream ss;
ss << "Error can't be raised, because type " << error.type << ", sub_type " << error.sub_type
<< " is already active.";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_debug << ss.str();
return;
}
database->add_error(std::make_shared<Error>(error));
this->publish_raised_error(error);
EVLOG_error << "Error raised, type: " << error.type << ", sub_type: " << error.sub_type
<< ", message: " << error.message;
}
std::list<ErrorPtr> ErrorManagerImpl::clear_error(const ErrorType& type) {
const ErrorSubType sub_type("");
return clear_error(type, sub_type);
}
std::list<ErrorPtr> ErrorManagerImpl::clear_error(const ErrorType& type, const ErrorSubType& sub_type) {
const std::lock_guard<std::mutex> lock(mutex);
if (!can_be_cleared(type, sub_type)) {
EVLOG_debug << "Error can't be cleared, because type " << type << ", sub_type " << sub_type
<< " is not active.";
return {};
}
const std::list<ErrorFilter> filters = {ErrorFilter(TypeFilter(type)), ErrorFilter(SubTypeFilter(sub_type))};
std::list<ErrorPtr> res = database->remove_errors(filters);
if (res.size() > 1) {
std::stringstream ss;
ss << "There are more than one matching error, this is not valid:" << std::endl;
for (const ErrorPtr& error : res) {
ss << nlohmann::json(*error).dump(2) << std::endl;
}
EVLOG_error << ss.str();
return {};
}
const ErrorPtr error = res.front();
error->state = State::ClearedByModule;
this->publish_cleared_error(*error);
EVLOG_info << "Cleared error of type " << type << " with sub_type " << sub_type;
return res;
}
std::list<ErrorPtr> ErrorManagerImpl::clear_all_errors() {
const std::lock_guard<std::mutex> lock(mutex);
const std::list<ErrorFilter> filters = {};
std::list<ErrorPtr> res = database->remove_errors(filters);
if (res.empty()) {
EVLOG_debug << "No errors can be cleared, because no errors are active";
return res;
}
std::stringstream ss;
ss << "Cleared " << res.size() << " errors:" << std::endl;
for (const ErrorPtr& error : res) {
error->state = State::ClearedByModule;
this->publish_cleared_error(*error);
ss << " - type: " << error->type << ", sub_type: " << error->sub_type << std::endl;
}
EVLOG_info << ss.str();
return res;
}
std::list<ErrorPtr> ErrorManagerImpl::clear_all_errors(const ErrorType& error_type) {
const std::lock_guard<std::mutex> lock(mutex);
if (!can_be_cleared(error_type)) {
EVLOG_debug << "Errors can't be cleared, because type " << error_type << " is not active.";
return {};
}
const std::list<ErrorFilter> filters = {ErrorFilter(TypeFilter(error_type))};
std::list<ErrorPtr> res = database->remove_errors(filters);
std::stringstream ss;
ss << "Cleared " << res.size() << " errors of type " << error_type << " with sub_types:" << std::endl;
for (const ErrorPtr& error : res) {
error->state = State::ClearedByModule;
this->publish_cleared_error(*error);
ss << " - " << error->sub_type << std::endl;
}
EVLOG_info << ss.str();
return res;
}
bool ErrorManagerImpl::can_be_raised(const ErrorType& type, const ErrorSubType& sub_type) const {
const std::list<ErrorFilter> filters = {ErrorFilter(TypeFilter(type)), ErrorFilter(SubTypeFilter(sub_type))};
return database->get_errors(filters).empty();
}
bool ErrorManagerImpl::can_be_cleared(const ErrorType& type, const ErrorSubType& sub_type) const {
const std::list<ErrorFilter> filters = {ErrorFilter(TypeFilter(type)), ErrorFilter(SubTypeFilter(sub_type))};
return !database->get_errors(filters).empty();
}
bool ErrorManagerImpl::can_be_cleared(const ErrorType& type) const {
const std::list<ErrorFilter> filters = {ErrorFilter(TypeFilter(type))};
return !database->get_errors(filters).empty();
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,125 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utility>
#include <utils/error/error_manager_req.hpp>
#include <utils/error.hpp>
#include <utils/error/error_database.hpp>
#include <utils/error/error_filter.hpp>
#include <utils/error/error_json.hpp>
#include <utils/error/error_type_map.hpp>
#include <everest/logging.hpp>
namespace Everest {
namespace error {
ErrorManagerReq::ErrorManagerReq(std::shared_ptr<ErrorTypeMap> error_type_map_,
std::shared_ptr<ErrorDatabase> error_database_,
std::list<ErrorType> allowed_error_types_, SubscribeErrorFunc subscribe_error_func_) :
error_type_map(error_type_map_),
database(error_database_),
allowed_error_types(std::move(allowed_error_types_)),
subscribe_error_func(std::move(subscribe_error_func_)) {
for (const ErrorType& type : allowed_error_types) {
if (!error_type_map->has(type)) {
EVLOG_error << "Error type '" << type << "' in allowed_error_types is not defined, ignored.";
}
}
const ErrorCallback on_raise = [this](const Error& error) { this->on_error_raised(error); };
const ErrorCallback on_clear = [this](const Error& error) { this->on_error_cleared(error); };
for (const ErrorType& type : allowed_error_types) {
subscribe_error_func(type, on_raise, on_clear);
error_subscriptions[type] = {};
}
}
ErrorManagerReq::Subscription::Subscription(const ErrorType& type_, const ErrorCallback& callback_,
const ErrorCallback& clear_callback_) :
type(type_), callback(callback_), clear_callback(clear_callback_) {
}
void ErrorManagerReq::subscribe_error(const ErrorType& type, const ErrorCallback& callback,
const ErrorCallback& clear_callback) {
if (error_subscriptions.count(type) != 1) {
EVLOG_error << "Tpye " << type << " is not known, ignore subscription";
return;
}
const Subscription sub(type, callback, clear_callback);
error_subscriptions.at(type).push_back(sub);
}
void ErrorManagerReq::subscribe_all_errors(const ErrorCallback& callback, const ErrorCallback& clear_callback) {
for (const ErrorType& type : allowed_error_types) {
const Subscription sub(type, callback, clear_callback);
error_subscriptions.at(type).push_back(sub);
}
}
void ErrorManagerReq::on_error_raised(const Error& error) {
if (std::find(allowed_error_types.begin(), allowed_error_types.end(), error.type) == allowed_error_types.end()) {
std::stringstream ss;
ss << "Error can't be raised by module_id " << error.origin.module_id << " and implemenetation_id "
<< error.origin.implementation_id << ", ignored.";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
if (!error_type_map->has(error.type)) {
std::stringstream ss;
ss << "Error type '" << error.type << "' is not defined, ignored.";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
std::list<ErrorPtr> errors =
database->get_errors({ErrorFilter(TypeFilter(error.type)), ErrorFilter(SubTypeFilter(error.sub_type)),
ErrorFilter(OriginFilter(error.origin))});
if (!errors.empty()) {
// Error is already raised, ignoring identical new error
// FIXME: can we prevent this from happening in the first place?
return;
}
database->add_error(std::make_shared<Error>(error));
on_error(error, true);
}
void ErrorManagerReq::on_error_cleared(const Error& error) {
const std::list<ErrorFilter> filters = {ErrorFilter(TypeFilter(error.type)),
ErrorFilter(SubTypeFilter(error.sub_type))};
const std::list<ErrorPtr> res = database->remove_errors(filters);
if (res.size() < 1) {
std::stringstream ss;
ss << "Error wasn't raised, type: " << error.type << ", sub_type: " << error.sub_type << ", ignored.";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
if (res.size() > 1) {
std::stringstream ss;
ss << "More than one error is cleared, type: " << error.type << ", sub_type: " << error.sub_type
<< ", ignored.";
for (const ErrorPtr& error : res) {
ss << std::endl << "Error object: " << nlohmann::json(*error).dump(2);
}
EVLOG_error << ss.str();
return;
}
on_error(error, false);
}
void ErrorManagerReq::on_error(const Error& error, const bool raised) const {
for (const Subscription& sub : error_subscriptions.at(error.type)) {
if (raised) {
sub.callback(error);
} else {
sub.clear_callback(error);
}
}
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,112 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utility>
#include <utils/error/error_manager_req_global.hpp>
#include <everest/logging.hpp>
#include <utils/error/error_database.hpp>
#include <utils/error/error_json.hpp>
#include <utils/error/error_type_map.hpp>
namespace Everest {
namespace error {
ErrorManagerReqGlobal::ErrorManagerReqGlobal(std::shared_ptr<ErrorTypeMap> error_type_map_,
std::shared_ptr<ErrorDatabase> error_database_,
SubscribeGlobalAllErrorsFunc subscribe_global_all_errors_func_) :
error_type_map(error_type_map_),
database(error_database_),
subscribe_global_all_errors_func(std::move(subscribe_global_all_errors_func_)),
subscriptions({}) {
this->subscribe_global_all_errors_func([this](const Error& error) { this->on_error_raised(error); },
[this](const Error& error) { this->on_error_cleared(error); });
}
void ErrorManagerReqGlobal::subscribe_global_all_errors(const ErrorCallback& callback,
const ErrorCallback& clear_callback) {
const Subscription sub(callback, clear_callback);
subscriptions.push_back(sub);
}
ErrorManagerReqGlobal::Subscription::Subscription(const ErrorCallback& callback_,
const ErrorCallback& clear_callback_) :
callback(callback_), clear_callback(clear_callback_) {
}
void ErrorManagerReqGlobal::on_error_raised(const Error& error) {
if (!error_type_map->has(error.type)) {
std::stringstream ss;
ss << "Error type '" << error.type << "' is not defined, ignoring error";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
std::list<ErrorPtr> errors =
database->get_errors({ErrorFilter(TypeFilter(error.type)), ErrorFilter(SubTypeFilter(error.sub_type)),
ErrorFilter(OriginFilter(error.origin))});
if (!errors.empty()) {
std::stringstream ss;
ss << "Error of type '" << error.type << "' and sub type '" << error.sub_type
<< "' is already raised, ignoring new error";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
database->add_error(std::make_shared<Error>(error));
errors = database->get_errors({ErrorFilter(TypeFilter(error.type)), ErrorFilter(SubTypeFilter(error.sub_type)),
ErrorFilter(OriginFilter(error.origin))});
if (errors.size() != 1) {
EVLOG_error << "Error wasn't added, type: " << error.type << ", sub type: " << error.sub_type;
return;
}
for (const Subscription& sub : subscriptions) {
sub.callback(error);
}
}
void ErrorManagerReqGlobal::on_error_cleared(const Error& error) {
if (!error_type_map->has(error.type)) {
std::stringstream ss;
ss << "Error type '" << error.type << "' is not defined, ignoring error";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
const std::list<ErrorPtr> errors =
database->get_errors({ErrorFilter(TypeFilter(error.type)), ErrorFilter(SubTypeFilter(error.sub_type)),
ErrorFilter(OriginFilter(error.origin))});
if (errors.empty()) {
std::stringstream ss;
ss << "Error of type '" << error.type << "' and sub type '" << error.sub_type
<< "' is not raised, ignoring clear error";
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
const std::list<ErrorPtr> res =
database->remove_errors({ErrorFilter(TypeFilter(error.type)), ErrorFilter(SubTypeFilter(error.sub_type)),
ErrorFilter(OriginFilter(error.origin))});
if (res.size() > 1) {
std::stringstream ss;
ss << "More than one error is cleared, type: " << error.type << ", sub type: " << error.sub_type;
for (const ErrorPtr& error : res) {
ss << std::endl << "Error object: " << nlohmann::json(*error).dump(2);
}
EVLOG_error << ss.str();
return;
}
if (res.empty()) {
std::stringstream ss;
ss << "Error wasn't removed, type: " << error.type << ", sub type: " << error.sub_type;
ss << std::endl << "Error object: " << nlohmann::json(error).dump(2);
EVLOG_error << ss.str();
return;
}
for (const Subscription& sub : subscriptions) {
sub.clear_callback(error);
}
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,46 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utility>
#include <utils/error/error_state_monitor.hpp>
#include <utils/error/error_database.hpp>
#include <utils/error/error_filter.hpp>
#include <everest/logging.hpp>
namespace Everest {
namespace error {
ErrorStateMonitor::StateCondition::StateCondition(ErrorType type_, ErrorSubType sub_type_, bool active_) :
type(std::move(type_)), sub_type(std::move(sub_type_)), active(active_) {
}
ErrorStateMonitor::ErrorStateMonitor(std::shared_ptr<ErrorDatabase> error_database_) : database(error_database_) {
}
bool ErrorStateMonitor::is_error_active(const ErrorType& type, const ErrorSubType& sub_type) const {
const std::list<ErrorFilter> filters = {ErrorFilter(TypeFilter(type)), ErrorFilter(SubTypeFilter(sub_type))};
return database->get_errors(filters).size() > 0;
}
std::list<ErrorPtr> ErrorStateMonitor::get_active_errors() const {
return database->get_errors({});
}
bool ErrorStateMonitor::is_condition_satisfied(const StateCondition& condition) const {
const bool res = is_error_active(condition.type, condition.sub_type);
return res == condition.active;
}
bool ErrorStateMonitor::is_condition_satisfied(const std::list<StateCondition>& condition) const {
for (const auto& cond : condition) {
if (!is_condition_satisfied(cond)) {
return false;
}
}
return true;
}
} // namespace error
} // namespace Everest

View File

@@ -0,0 +1,94 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <utility>
#include <utils/error/error_type_map.hpp>
#include <utils/error.hpp>
#include <utils/yaml_loader.hpp>
#include <everest/logging.hpp>
namespace Everest {
namespace error {
ErrorTypeMap::ErrorTypeMap(const std::filesystem::path& error_types_dir) {
load_error_types(error_types_dir);
}
void ErrorTypeMap::load_error_types(const std::filesystem::path& error_types_dir) {
BOOST_LOG_FUNCTION();
if (!std::filesystem::is_directory(error_types_dir) || !std::filesystem::exists(error_types_dir)) {
EVLOG_error << "Error types directory '" << error_types_dir.string()
<< "' does not exist, error types not loaded.";
return;
}
for (const auto& entry : std::filesystem::directory_iterator(error_types_dir)) {
if (!entry.is_regular_file()) {
continue;
}
if (entry.path().extension() != ".yaml") {
continue;
}
const std::string prefix = entry.path().stem().string();
json error_type_file = Everest::load_yaml(entry.path());
if (!error_type_file.contains("errors")) {
EVLOG_warning << "Error type file '" << entry.path().string() << "' does not contain 'errors' key.";
continue;
}
if (!error_type_file.at("errors").is_array()) {
EVLOG_error << "Error type file '" << entry.path().string()
<< "' does not contain an array with key 'errors', skipped.";
continue;
}
for (const auto& error : error_type_file["errors"]) {
if (!error.contains("name")) {
EVLOG_error << "Error type file '" << entry.path().string()
<< "' contains an error without a 'name' key, skipped.";
continue;
}
std::string description;
if (!error.contains("description")) {
EVLOG_error << "Error type file '" << entry.path().string()
<< "' contains an error without a 'description' key, using default description";
description = "No description found";
} else {
description = error.at("description").get<std::string>();
}
ErrorType complete_name = prefix + "/" + error.at("name").get<std::string>();
if (this->has(complete_name)) {
EVLOG_error << "Error type file '" << entry.path().string() << "' contains an error with the name '"
<< complete_name << "' which is already defined, skipped.";
continue;
}
error_types[complete_name] = description;
}
}
}
void ErrorTypeMap::load_error_types_map(std::map<ErrorType, std::string> error_types_map) {
this->error_types = std::move(error_types_map);
}
std::string ErrorTypeMap::get_description(const ErrorType& error_type) const {
std::string description;
try {
description = error_types.at(error_type);
} catch (...) {
EVLOG_error << "Error type '" << error_type << "' is not defined, returning default description.";
description = "No description found";
}
return description;
}
bool ErrorTypeMap::has(const ErrorType& error_type) const {
return error_types.find(error_type) != error_types.end();
}
const ErrorTypes& ErrorTypeMap::get_error_types() const {
return error_types;
}
} // namespace error
} // namespace Everest