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,157 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
#ifndef MODULE_ADAPTER_HPP
#define MODULE_ADAPTER_HPP
#include "everest.hpp"
#include <everest/logging.hpp>
#include <utils/conversions.hpp>
#include <utils/date.hpp>
#include <utils/error.hpp>
#include <iomanip>
#include <iostream>
#include <memory>
namespace Everest {
// FIXME (aw): does the standard library already has something like this?
template <typename T> class PtrContainer {
public:
PtrContainer(){};
// disable copy constructor, because in general it should be used as a reference
PtrContainer(const PtrContainer& obj) = delete;
T* operator->() const {
return ptr;
}
operator bool() const {
return ptr != nullptr;
}
void set(T* ptr) {
this->ptr = ptr;
}
private:
T* ptr{nullptr};
};
struct ModuleAdapter;
struct ModuleBase;
class ImplementationBase {
public:
friend class ModuleAdapter; // for accessing gather_cmds
friend class ModuleBase; // for accessing init & ready
virtual ~ImplementationBase() = default;
private:
virtual void _gather_cmds(std::vector<cmd>&) = 0;
virtual void init() = 0;
virtual void ready() = 0;
};
class ModuleBase {
public:
ModuleBase(const ModuleInfo& info);
virtual ~ModuleBase() = default;
const ModuleInfo& info;
protected:
void invoke_init(ImplementationBase& impl);
void invoke_ready(ImplementationBase& impl);
};
namespace error {
struct ErrorManagerImpl;
struct ErrorManagerReq;
struct ErrorManagerReqGlobal;
struct ErrorStateMonitor;
struct ErrorFactory;
} // namespace error
struct ModuleAdapter {
using CallFunc = std::function<Result(const Requirement&, const std::string&, const Parameters&)>;
using PublishFunc = std::function<void(const std::string&, const std::string&, const Value&)>;
using SubscribeFunc = std::function<void(const Requirement&, const std::string&, const ValueCallback&)>;
using GetErrorManagerImplFunc = std::function<std::shared_ptr<error::ErrorManagerImpl>(const std::string&)>;
using GetErrorStateMonitorImplFunc = std::function<std::shared_ptr<error::ErrorStateMonitor>(const std::string&)>;
using GetErrorFactoryFunc = std::function<std::shared_ptr<error::ErrorFactory>(const std::string&)>;
using GetErrorManagerReqFunc = std::function<std::shared_ptr<error::ErrorManagerReq>(const Requirement&)>;
using GetGlobalErrorManagerFunc = std::function<std::shared_ptr<error::ErrorManagerReqGlobal>()>;
using GetGlobalErrorStateMonitorFunc = std::function<std::shared_ptr<error::ErrorStateMonitor>()>;
using GetErrorStateMonitorReqFunc = std::function<std::shared_ptr<error::ErrorStateMonitor>(const Requirement&)>;
using ExtMqttPublishFunc = std::function<void(const std::string&, const std::string&, bool)>;
using ExtMqttSubscribeFunc = std::function<UnsubscribeToken(const std::string&, StringHandler)>;
using ExtMqttSubscribePairFunc = std::function<UnsubscribeToken(const std::string&, StringPairHandler)>;
using TelemetryPublishFunc =
std::function<void(const std::string&, const std::string&, const std::string&, const TelemetryMap&)>;
using GetMappingFunc = std::function<std::optional<ModuleTierMappings>()>;
using GetConfigServiceClientFunc = std::function<std::shared_ptr<config::ConfigServiceClient>()>;
CallFunc call;
PublishFunc publish;
SubscribeFunc subscribe;
GetErrorManagerImplFunc get_error_manager_impl;
GetErrorStateMonitorImplFunc get_error_state_monitor_impl;
GetErrorFactoryFunc get_error_factory;
GetErrorManagerReqFunc get_error_manager_req;
GetErrorStateMonitorReqFunc get_error_state_monitor_req;
GetGlobalErrorManagerFunc get_global_error_manager;
GetGlobalErrorStateMonitorFunc get_global_error_state_monitor;
ExtMqttPublishFunc ext_mqtt_publish;
ExtMqttSubscribeFunc ext_mqtt_subscribe;
ExtMqttSubscribePairFunc ext_mqtt_subscribe_pair;
std::vector<cmd> registered_commands;
TelemetryPublishFunc telemetry_publish;
GetMappingFunc get_mapping;
GetConfigServiceClientFunc get_config_service_client;
void check_complete();
void gather_cmds(ImplementationBase& impl);
};
class MqttProvider {
public:
MqttProvider(ModuleAdapter& ev);
void publish(const std::string& topic, const std::string& data, bool retain = false);
void publish(const std::string& topic, const char* data, bool retain = false);
void publish(const std::string& topic, bool data, bool retain = false);
void publish(const std::string& topic, int data, bool retain = false);
void publish(const std::string& topic, double data, int precision, bool retain = false);
void publish(const std::string& topic, double data, bool retain = false);
UnsubscribeToken subscribe(const std::string& topic, StringHandler handler) const;
UnsubscribeToken subscribe(const std::string& topic, StringPairHandler handler) const;
private:
ModuleAdapter& ev;
};
class TelemetryProvider {
public:
TelemetryProvider(ModuleAdapter& ev);
void publish(const std::string& category, const std::string& subcategory, const std::string& type,
const TelemetryMap& telemetry);
void publish(const std::string& category, const std::string& subcategory, const TelemetryMap& telemetry);
private:
ModuleAdapter& ev;
};
} // namespace Everest
#endif // MODULE_ADAPTER_HPP

View File

@@ -0,0 +1,300 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef FRAMEWORK_EVEREST_HPP
#define FRAMEWORK_EVEREST_HPP
#include <atomic>
#include <chrono>
#include <functional>
#include <future>
#include <map>
#include <set>
#include <thread>
#include <variant>
#include <everest/exceptions.hpp>
#include <utils/config.hpp>
#include <utils/config_service.hpp>
#include <utils/error.hpp>
#include <utils/exceptions.hpp>
#include <utils/mqtt_abstraction.hpp>
#include <utils/types.hpp>
namespace Everest {
///
/// \brief A structure that contains a command definition for a cmd of a module
///
struct cmd {
std::string impl_id; ///< The implementation id of the command
std::string cmd_name; ///< The name of the command
Command cmd; ///< The callback function
Arguments arg_types; ///< The argument types
ReturnType return_type; ///< The return type
};
using TelemetryEntry = std::variant<std::string, const char*, bool, int32_t, uint32_t, int64_t, uint64_t, double>;
using TelemetryMap = std::map<std::string, TelemetryEntry>;
using UnsubscribeToken = std::function<void()>;
enum class CmdErrorType;
struct CmdResultError;
struct CmdResult;
namespace error {
struct ErrorDatabaseMap;
struct ErrorManagerImpl;
struct ErrorManagerReq;
struct ErrorManagerReqGlobal;
struct ErrorStateMonitor;
struct ErrorFactory;
} // namespace error
///
/// \brief Contains the EVerest framework that provides convenience functionality for implementing EVerest modules
///
class Everest {
public:
Everest(std::string module_id, const Config& config, bool validate_data_with_schema,
std::shared_ptr<MQTTAbstraction> mqtt_abstraction, const std::string& telemetry_prefix,
bool telemetry_enabled, bool forward_exceptions = false);
// forbid copy assignment and copy construction
// NOTE (aw): move assignment and construction are also not supported because we're creating explicit references to
// our instance due to callback registration
Everest(Everest const&) = delete;
void operator=(Everest const&) = delete;
nlohmann::json get_cmd_definition(const std::string& module_id, const std::string& impl_id,
const std::string& cmd_name, bool is_call);
nlohmann::json get_cmd_definition(const std::string& module_id, const std::string& impl_id,
const std::string& cmd_name);
///
/// \brief Allows a module to indicate that it provides the given command \p cmd
///
void provide_cmd(const std::string& impl_id, const std::string& cmd_name, const JsonCommand& handler);
void provide_cmd(const cmd& cmd);
///
/// \brief Provides functionality for calling commands of other modules. The module is identified by the given \p
/// req, the command by the given command name \p cmd_name and the needed arguments by \p args
///
nlohmann::json call_cmd(const Requirement& req, const std::string& cmd_name, const nlohmann::json& args);
///
/// \brief Publishes a variable of the given \p impl_id, names \p var_name with the given \p value
///
void publish_var(const std::string& impl_id, const std::string& var_name, const nlohmann::json& value);
///
/// \brief Subscribes to a variable of another module identified by the given \p req and variable name \p
/// var_name. The given \p callback is called when a new value becomes available
///
void subscribe_var(const Requirement& req, const std::string& var_name, const JsonCallback& callback);
///
/// \brief Return the error manager for the given \p impl_id
///
std::shared_ptr<error::ErrorManagerImpl> get_error_manager_impl(const std::string& impl_id);
///
/// \brief Return the error state monitor for the given \p impl_id
///
std::shared_ptr<error::ErrorStateMonitor> get_error_state_monitor_impl(const std::string& impl_id);
///
/// \brief Return the error factory for the given \p impl_id
///
std::shared_ptr<error::ErrorFactory> get_error_factory(const std::string& impl_id);
///
/// \brief Return the error manager for the given \p req
///
std::shared_ptr<error::ErrorManagerReq> get_error_manager_req(const Requirement& req);
///
/// \brief Return the error state monitor for the given \p req
std::shared_ptr<error::ErrorStateMonitor> get_error_state_monitor_req(const Requirement& req);
///
/// \brief Return the global error manager, if not enabled nullptr
std::shared_ptr<error::ErrorManagerReqGlobal> get_global_error_manager() const;
///
/// \brief Return the global state monitor, if not enabled nullptr
std::shared_ptr<error::ErrorStateMonitor> get_global_error_state_monitor() const;
///
/// \brief Return the config service client
std::shared_ptr<config::ConfigServiceClient> get_config_service_client() const;
///
/// \brief publishes the given \p data on the given \p topic with the given \p retain
///
void external_mqtt_publish(const std::string& topic, const std::string& data, bool retain);
///
/// \brief Allows a module to indicate that it provides a external mqtt \p handler at the given \p topic
///
UnsubscribeToken provide_external_mqtt_handler(const std::string& topic, const StringHandler& handler);
///
/// \brief Allows a module to indicate that it provides a external mqtt \p handler at the given \p topic
///
UnsubscribeToken provide_external_mqtt_handler(const std::string& topic, const StringPairHandler& handler);
///
/// \brief publishes the given telemetry \p data on the given \p topic
///
void telemetry_publish(const std::string& topic, const std::string& data);
///
/// \brief publishes the given telemetry \p telemetry on a topic constructed from \p category \p subcategory and \p
/// type
///
void telemetry_publish(const std::string& category, const std::string& subcategory, const std::string& type,
const TelemetryMap& telemetry);
/// \returns true if telemetry is enabled
bool is_telemetry_enabled();
///
/// \returns the 3 tier model mappings for this module
///
std::optional<ModuleTierMappings> get_3_tier_model_mapping();
///
/// \brief Chccks if all commands of a module that are listed in its manifest are available
///
void check_code();
///
/// \brief Calls the connect method of the MQTTAbstraction to connect to the MQTT broker
///
bool connect();
///
/// \brief Calls the disconnect method of the MQTTAbstraction to disconnect from the MQTT broker
///
void disconnect();
///
/// \brief Initiates spawning the MQTT main loop thread
///
void spawn_main_loop_thread();
///
/// \brief Wait for main loop thread to end
///
void wait_for_main_loop_end();
///
/// \brief Ready Handler for local readyness (e.g. this module is now ready)
///
void signal_ready();
///
/// \brief registers a callback \p handler that is called when the global ready signal is received via mqtt
///
void register_on_ready_handler(const std::function<void()>& handler);
///
/// \brief Blocks until ready is processed;
///
void ensure_ready() const;
private:
std::shared_ptr<MQTTAbstraction> mqtt_abstraction;
Config config;
std::string module_id;
std::map<std::string, std::shared_ptr<error::ErrorManagerImpl>> impl_error_managers; // one per implementation
std::map<std::string, std::shared_ptr<error::ErrorStateMonitor>>
impl_error_state_monitors; // one per implementation
std::map<std::string, std::shared_ptr<error::ErrorFactory>> error_factories; // one per implementation
std::map<Requirement, std::shared_ptr<error::ErrorManagerReq>> req_error_managers; // one per requirement
std::map<Requirement, std::shared_ptr<error::ErrorStateMonitor>> req_error_state_monitors; // one per requirement
std::shared_ptr<error::ErrorManagerReqGlobal> global_error_manager; // nullptr if not enabled in manifest
std::shared_ptr<error::ErrorStateMonitor> global_error_state_monitor; // nullptr if not enabled in manifest
std::shared_ptr<config::ConfigServiceClient> config_service_client;
std::map<std::string, std::set<std::string>> registered_cmds;
std::atomic<bool> ready_received;
std::atomic<bool> ready_processed;
std::chrono::seconds remote_cmd_res_timeout;
bool validate_data_with_schema;
std::unique_ptr<std::function<void()>> on_ready;
std::thread heartbeat_thread;
std::string module_name;
std::shared_future<void> main_loop_end{};
nlohmann::json module_manifest;
nlohmann::json module_classes;
std::string mqtt_everest_prefix;
std::string mqtt_external_prefix;
std::string telemetry_prefix;
std::optional<TelemetryConfig> telemetry_config;
bool telemetry_enabled;
std::optional<ModuleTierMappings> module_tier_mappings;
bool forward_exceptions;
void handle_ready(const nlohmann::json& data);
void heartbeat();
void publish_metadata();
static std::string check_args(const Arguments& func_args, nlohmann::json manifest_args);
static bool check_arg(ArgumentType arg_types, nlohmann::json manifest_arg);
///
/// \brief Publishes the given \p error as a cleared error
///
void publish_cleared_error(const std::string& impl_id, const error::Error& error);
///
/// \brief Publishes the given \p error as a raised error
///
void publish_raised_error(const std::string& impl_id, const error::Error& error);
///
/// \brief Subscribes to an error of another module indentified by the given \p req and error type
/// \p error_type. The given \p raise_callback is called when a new error is raised and \p clear_callback is called
/// when an error is cleared
///
void subscribe_error(const Requirement& req, const error::ErrorType& error_type,
const error::ErrorCallback& raise_callback, const error::ErrorCallback& clear_callback);
///
/// \brief Subscribes globally to all errors of all modules. The given \p raise_callback is called when a new error
/// is raised. The given \p clear_callback is called when an error is cleared
///
void subscribe_global_all_errors(const error::ErrorCallback& raise_callback,
const error::ErrorCallback& clear_callback);
///
/// \brief Check that external MQTT is configured - raises exception on error
///
void check_external_mqtt();
///
/// \brief Check that external MQTT is configured - raises exception on error
/// \returns the full external MQTT topic
///
std::string check_external_mqtt(const std::string& topic);
///
/// \brief Create external MQTT with an unsubscribe token
/// \returns the unsubscribe token
///
UnsubscribeToken create_external_handler(const std::string& topic, const std::string& external_topic,
const StringPairHandler& handler);
};
///
/// \returns the 3 tier model mapping from a \p module_tier_mapping for the given \p impl_id
///
std::optional<Mapping> get_impl_mapping(std::optional<ModuleTierMappings> module_tier_mappings,
const std::string& impl_id);
} // namespace Everest
#endif // FRAMEWORK_EVEREST_HPP

View File

@@ -0,0 +1,165 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef FRAMEWORK_EVEREST_RUNTIME_HPP
#define FRAMEWORK_EVEREST_RUNTIME_HPP
#include <cstdint>
#include <filesystem>
#include <string>
#include <fmt/color.h>
#include <fmt/core.h>
#include <sys/prctl.h>
#include <framework/ModuleAdapter.hpp>
#include <utils/config/settings.hpp>
#include <utils/module_config.hpp>
#include <utils/yaml_loader.hpp>
#include <everest/compile_time_settings.hpp>
#include <everest/logging.hpp>
namespace boost::program_options {
class variables_map; // forward declaration
} // namespace boost::program_options
namespace Everest {
namespace fs = std::filesystem;
// FIXME (aw): should be everest wide or defined in liblog
const int DUMP_INDENT = 4;
// FIXME (aw): we should also define all other config keys and default
// values here as string literals
inline constexpr auto EV_MODULE = "EV_MODULE";
inline constexpr auto EV_PREFIX = "EV_PREFIX";
inline constexpr auto EV_LOG_CONF_FILE = "EV_LOG_CONF_FILE";
inline constexpr auto EV_MQTT_EVEREST_PREFIX = "EV_MQTT_EVEREST_PREFIX";
inline constexpr auto EV_MQTT_EXTERNAL_PREFIX = "EV_MQTT_EXTERNAL_PREFIX";
inline constexpr auto EV_MQTT_BROKER_SOCKET_PATH = "EV_MQTT_BROKER_SOCKET_PATH";
inline constexpr auto EV_MQTT_BROKER_HOST = "EV_MQTT_BROKER_HOST";
inline constexpr auto EV_MQTT_BROKER_PORT = "EV_MQTT_BROKER_PORT";
inline constexpr auto EV_VALIDATE_SCHEMA = "EV_VALIDATE_SCHEMA";
inline constexpr auto VERSION_INFORMATION_FILE = "version_information.txt";
// FIXME (aw): this needs to be made available by
namespace defaults {
// defaults:
// PREFIX: set by cmake
// EVEREST_NAMESPACE: everest
// EVEREST_INSTALL_LIBDIR: set by cmake
// BIN_DIR: ${PREFIX}/bin
// LIBEXEC_DIR: ${PREFIX}/libexec
// LIB_DIR: ${PREFIX}/${EVEREST_INSTALL_LIBDIR}
// SYSCONF_DIR: /etc, if ${PREFIX}==/usr, otherwise ${PREFIX}/etc
// LOCALSTATE_DIR: /var, if ${PREFIX}==/usr, otherwise ${PREFIX}/var
// DATAROOT_DIR: ${PREFIX}/share
//
// modules_dir: ${LIBEXEC_DIR}${EVEREST_NAMESPACE}
// types_dir: ${DATAROOT_DIR}${EVEREST_NAMESPACE}/types
// interfaces_dir: ${DATAROOT_DIR}${EVEREST_NAMESPACE}/interfaces
// schemas_dir: ${DATAROOT_DIR}${EVEREST_NAMESPACE}/schemas
// configs_dir: ${SYSCONF_DIR}${EVEREST_NAMESPACE}
//
// config_path: ${SYSCONF_DIR}${EVEREST_NAMESPACE}/default.yaml
// logging_config_path: ${SYSCONF_DIR}${EVEREST_NAMESPACE}/default_logging.cfg
inline constexpr auto PREFIX = EVEREST_INSTALL_PREFIX;
inline constexpr auto NAMESPACE = EVEREST_NAMESPACE;
inline constexpr auto BIN_DIR = "bin";
inline constexpr auto LIB_DIR = EVEREST_INSTALL_LIBDIR;
inline constexpr auto LIBEXEC_DIR = "libexec";
inline constexpr auto SYSCONF_DIR = "etc";
inline constexpr auto LOCALSTATE_DIR = "var";
inline constexpr auto DATAROOT_DIR = "share";
inline constexpr auto MODULES_DIR = "modules";
inline constexpr auto TYPES_DIR = "types";
inline constexpr auto ERRORS_DIR = "errors";
inline constexpr auto INTERFACES_DIR = "interfaces";
inline constexpr auto SCHEMAS_DIR = "schemas";
inline constexpr auto CONFIG_NAME = "default.yaml";
inline constexpr auto LOGGING_CONFIG_NAME = "default_logging.cfg";
inline constexpr auto WWW_DIR = "www";
inline constexpr auto CONTROLLER_PORT = 8849;
inline constexpr auto CONTROLLER_RPC_TIMEOUT_MS = 2000;
inline constexpr auto MQTT_BROKER_SOCKET_PATH = "/tmp/mqtt_broker.sock";
inline constexpr auto MQTT_BROKER_HOST = "localhost";
inline constexpr std::uint16_t MQTT_BROKER_PORT = 1883;
inline constexpr auto MQTT_EVEREST_PREFIX = "everest";
inline constexpr auto MQTT_EXTERNAL_PREFIX = "";
inline constexpr auto TELEMETRY_PREFIX = "everest-telemetry";
inline constexpr auto TELEMETRY_ENABLED = false;
inline constexpr auto VALIDATE_SCHEMA = false;
inline constexpr auto FORWARD_EXCEPTIONS = false;
} // namespace defaults
std::string parse_string_option(const boost::program_options::variables_map& vm, const char* option);
inline constexpr auto TERMINAL_STYLE_ERROR = fmt::emphasis::bold | fg(fmt::terminal_color::red);
inline constexpr auto TERMINAL_STYLE_OK = fmt::emphasis::bold | fg(fmt::terminal_color::green);
inline constexpr auto TERMINAL_STYLE_BLUE = fmt::emphasis::bold | fg(fmt::terminal_color::blue);
// NOTE: this function needs the be called with a pre-initialized ModuleInfo struct
void populate_module_info_path_from_runtime_settings(ModuleInfo&, const RuntimeSettings& rs);
/// \brief Callbacks that need to be registered for modules
struct ModuleCallbacks {
std::function<void(ModuleAdapter module_adapter)> register_module_adapter;
std::function<std::vector<cmd>(const RequirementInitialization& requirement_init)> everest_register;
std::function<void(ModuleConfigs module_configs, const ModuleInfo& info)> init;
std::function<void()> ready;
ModuleCallbacks() = default;
ModuleCallbacks(
const std::function<void(ModuleAdapter module_adapter)>& register_module_adapter,
const std::function<std::vector<cmd>(const RequirementInitialization& requirement_init)>& everest_register,
const std::function<void(ModuleConfigs module_configs, const ModuleInfo& info)>& init,
const std::function<void()>& ready);
};
///\brief Version information
struct VersionInformation {
std::string project_name; ///< CMake project name
std::string project_version; ///< Human readable version number
std::string git_version; ///< Git version containing tag and branch information
};
class ModuleLoader {
private:
std::unique_ptr<RuntimeSettings> runtime_settings;
MQTTSettings mqtt_settings;
std::shared_ptr<MQTTAbstraction> mqtt;
std::string module_id;
std::string original_process_name;
std::string application_name;
ModuleCallbacks callbacks;
VersionInformation version_information;
fs::path logging_config_file;
bool should_exit = false;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays): pass-through of argc and argv from main()
bool parse_command_line(int argc, char* argv[]);
public:
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays): pass-through of argc and argv from main()
explicit ModuleLoader(int argc, char* argv[], ModuleCallbacks callbacks) :
ModuleLoader(argc, argv, std::move(callbacks),
{"undefined project", "undefined version", "undefined git version"}){};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays): pass-through of argc and argv from main()
explicit ModuleLoader(int argc, char* argv[], ModuleCallbacks callbacks, VersionInformation version_information);
int initialize();
};
} // namespace Everest
#endif // FRAMEWORK_EVEREST_RUNTIME_HPP