Skip to content

Commit

Permalink
DCSupplySimulator: Add C++ simulation module
Browse files Browse the repository at this point in the history
This C++ module emulates the behavior of the existing JsDCSupplySimulator.

Unlike JsDCSupplySimulator, it does not provide the powermeter simulation
interface though. This should be implemented in a separate C++ module.

Co-authored-by: Cornelius Claussen <[email protected]>
Co-authored-by: Fabian Hartung <[email protected]>
Co-authored-by: Mohannad Oraby <[email protected]>
Co-authored-by: Moritz Barsnick <[email protected]>

Signed-off-by: Fabian Hartung <[email protected]>
Signed-off-by: Moritz Barsnick <[email protected]>
  • Loading branch information
FaHaGit authored and barsnick committed Jan 24, 2024
1 parent e2077b7 commit 3b6a044
Show file tree
Hide file tree
Showing 7 changed files with 344 additions and 0 deletions.
1 change: 1 addition & 0 deletions modules/simulation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
ev_add_module(DCSupplySimulator)
ev_add_module(JsCarSimulator)
ev_add_module(JsDCSupplySimulator)
ev_add_module(JsIMDSimulator)
Expand Down
23 changes: 23 additions & 0 deletions modules/simulation/DCSupplySimulator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
# template version 3
#

# module setup:
# - ${MODULE_NAME}: module name
ev_setup_cpp_module()

# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
# insert your custom targets and additional config variables here
# needed for std::scoped_lock
target_compile_features(${MODULE_NAME} PUBLIC cxx_std_17)
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1

target_sources(${MODULE_NAME}
PRIVATE
"main/power_supply_DCImpl.cpp"
)

# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
# insert other things like install cmds etc here
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
17 changes: 17 additions & 0 deletions modules/simulation/DCSupplySimulator/DCSupplySimulator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2023 chargebyte GmbH
// Copyright (C) 2023 Contributors to EVerest

#include "DCSupplySimulator.hpp"

namespace module {

void DCSupplySimulator::init() {
invoke_init(*p_main);
}

void DCSupplySimulator::ready() {
invoke_ready(*p_main);
}

} // namespace module
58 changes: 58 additions & 0 deletions modules/simulation/DCSupplySimulator/DCSupplySimulator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright chargebyte GmbH and Contributors to EVerest
#ifndef DCSUPPLY_SIMULATOR_HPP
#define DCSUPPLY_SIMULATOR_HPP

//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 2
//

#include "ld-ev.hpp"

// headers for provided interface implementations
#include <generated/interfaces/power_supply_DC/Implementation.hpp>

// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1

namespace module {

struct Conf {};

class DCSupplySimulator : public Everest::ModuleBase {
public:
DCSupplySimulator() = delete;
DCSupplySimulator(const ModuleInfo& info, std::unique_ptr<power_supply_DCImplBase> p_main, Conf& config) :
ModuleBase(info), p_main(std::move(p_main)), config(config){};

const std::unique_ptr<power_supply_DCImplBase> p_main;
const Conf& config;

// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
// insert your public definitions here
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1

protected:
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
// insert your protected definitions here
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1

private:
friend class LdEverest;
void init();
void ready();

// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
// insert your private definitions here
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
};

// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
// insert other definitions here
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1

} // namespace module

#endif // DCSUPPLY_SIMULATOR_HPP
123 changes: 123 additions & 0 deletions modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2023 chargebyte GmbH
// Copyright (C) 2023 Contributors to EVerest

#include <chrono>
#include <mutex>

#include "power_supply_DCImpl.hpp"

namespace module {
namespace main {

void power_supply_DCImpl::init() {
this->connector_voltage = 0.0;
this->connector_current = 0.0;

this->power_supply_thread_handle = std::thread(&power_supply_DCImpl::power_supply_worker, this);
}

void power_supply_DCImpl::ready() {
}

types::power_supply_DC::Capabilities power_supply_DCImpl::handle_getCapabilities() {
types::power_supply_DC::Capabilities Capabilities = {
.bidirectional = this->config.bidirectional,
.current_regulation_tolerance_A = 2.0,
.peak_current_ripple_A = 2.0,

This comment has been minimized.

Copy link
@a-w50

a-w50 Jan 24, 2024

Contributor

@barsnick @FaHaGit:
designated initializers for structs is not supported by c++17 (only c++20), gcc seems to support them anyway, but for compatibility I wouldn't use it right now

This comment has been minimized.

Copy link
@barsnick

barsnick Jan 24, 2024

Contributor

Thanks for the observation! (Does clang support them with -std=cxx17? Too lazy to check right now.)

What do we do? Do we assume g++ or clang anyway? We can fix this to some less compact, but more correct syntax.

This comment has been minimized.

Copy link
@a-w50

a-w50 Jan 25, 2024

Contributor

I wouldn't consider this good practice to rely on gcc/clang supporting a c++20 feature when using c++17 (it could be even removed in future). I would just create a helper function which takes the config as an argument and just creates the cap struct, sets each field, and returns it. That would look like as it is right now.

This comment has been minimized.

Copy link
@barsnick

barsnick Jan 25, 2024

Contributor

Okay, I opened PR #509, let me know whether that's okay.

I found some other instances of designated initializers in the code 😎. Let's fix those later, but make sure that this is a clean module.

.max_export_voltage_V = static_cast<float>(this->config.max_voltage),
.min_export_voltage_V = static_cast<float>(this->config.min_voltage),
.max_export_current_A = static_cast<float>(this->config.max_current),
.min_export_current_A = static_cast<float>(this->config.min_current),
.max_export_power_W = static_cast<float>(this->config.max_power),
.max_import_voltage_V = static_cast<float>(this->config.max_voltage),
.min_import_voltage_V = static_cast<float>(this->config.min_voltage),
.max_import_current_A = static_cast<float>(this->config.max_current),
.min_import_current_A = static_cast<float>(this->config.min_current),
.max_import_power_W = static_cast<float>(this->config.max_power),
.conversion_efficiency_import = 0.85,
.conversion_efficiency_export = 0.9,
};
return Capabilities;
}

void power_supply_DCImpl::handle_setMode(types::power_supply_DC::Mode& value) {
this->mode = value;

std::scoped_lock access_lock(this->power_supply_values_mutex);
if ((value == types::power_supply_DC::Mode::Off) || (value == types::power_supply_DC::Mode::Fault)) {
this->connector_voltage = 0.0;
this->connector_current = 0.0;
} else if (value == types::power_supply_DC::Mode::Export) {
this->connector_voltage = this->settings_connector_export_voltage;
this->connector_current = this->settings_connector_max_export_current;
} else if (value == types::power_supply_DC::Mode::Import) {
this->connector_voltage = this->settings_connector_import_voltage;
this->connector_current = this->settings_connector_max_import_current;
}

mod->p_main->publish_mode(value);
}

void power_supply_DCImpl::clampVoltageCurrent(double& voltage, double& current) {
voltage = voltage < this->config.min_voltage ? this->config.min_voltage
: voltage > this->config.max_voltage ? this->config.max_voltage
: voltage;

current = current < this->config.min_current ? this->config.min_current
: current > this->config.max_current ? this->config.max_current
: current;
}

void power_supply_DCImpl::handle_setExportVoltageCurrent(double& voltage, double& current) {
double temp_voltage = voltage;
double temp_current = current;

clampVoltageCurrent(temp_voltage, temp_current);

std::scoped_lock access_lock(this->power_supply_values_mutex);
this->settings_connector_export_voltage = temp_voltage;
this->settings_connector_max_export_current = temp_current;

if (this->mode == types::power_supply_DC::Mode::Export) {
this->connector_voltage = this->settings_connector_export_voltage;
this->connector_current = this->settings_connector_max_export_current;
}
}

void power_supply_DCImpl::handle_setImportVoltageCurrent(double& voltage, double& current) {
double temp_voltage = voltage;
double temp_current = current;

clampVoltageCurrent(temp_voltage, temp_current);

std::scoped_lock access_lock(this->power_supply_values_mutex);
this->settings_connector_import_voltage = temp_voltage;
this->settings_connector_max_import_current = temp_current;

if (this->mode == types::power_supply_DC::Mode::Import) {
this->connector_voltage = this->settings_connector_import_voltage;
this->connector_current = -this->settings_connector_max_import_current;
}
}

void power_supply_DCImpl::power_supply_worker(void) {
types::power_supply_DC::VoltageCurrent voltage_current;

while (true) {
if (this->power_supply_thread_handle.shouldExit()) {
break;
}

// set interval for publishing
std::this_thread::sleep_for(std::chrono::milliseconds(LOOP_SLEEP_MS));

std::scoped_lock access_lock(this->power_supply_values_mutex);
voltage_current.voltage_V = static_cast<float>(this->connector_voltage);
voltage_current.current_A = static_cast<float>(this->connector_current);

this->mod->p_main->publish_voltage_current(voltage_current);
}
}
} // namespace main
} // namespace module
86 changes: 86 additions & 0 deletions modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright chargebyte GmbH and Contributors to EVerest
#ifndef MAIN_POWER_SUPPLY_DC_IMPL_HPP
#define MAIN_POWER_SUPPLY_DC_IMPL_HPP

//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//

#include <generated/interfaces/power_supply_DC/Implementation.hpp>

#include "../DCSupplySimulator.hpp"

// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
#include <mutex>
#include <utils/thread.hpp>
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1

namespace module {
namespace main {

struct Conf {
bool bidirectional;
double max_power;
double min_voltage;
double max_voltage;
double min_current;
double max_current;
};

class power_supply_DCImpl : public power_supply_DCImplBase {
public:
power_supply_DCImpl() = delete;
power_supply_DCImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<DCSupplySimulator>& mod, Conf& config) :
power_supply_DCImplBase(ev, "main"), mod(mod), config(config){};

// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
// insert your public definitions here
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1

protected:
// command handler functions (virtual)
virtual types::power_supply_DC::Capabilities handle_getCapabilities() override;
virtual void handle_setMode(types::power_supply_DC::Mode& value) override;
virtual void handle_setExportVoltageCurrent(double& voltage, double& current) override;
virtual void handle_setImportVoltageCurrent(double& voltage, double& current) override;

// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1

private:
const Everest::PtrContainer<DCSupplySimulator>& mod;
const Conf& config;

virtual void init() override;
virtual void ready() override;

// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
double settings_connector_export_voltage;
double settings_connector_import_voltage;
double settings_connector_max_export_current;
double settings_connector_max_import_current;
types::power_supply_DC::Mode mode;
double connector_voltage;
double connector_current;
std::mutex power_supply_values_mutex;
Everest::Thread power_supply_thread_handle;
void power_supply_worker(void);

static constexpr int LOOP_SLEEP_MS{500};
void clampVoltageCurrent(double& voltage, double& current);
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};

// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
// insert other definitions here
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1

} // namespace main
} // namespace module

#endif // MAIN_POWER_SUPPLY_DC_IMPL_HPP
36 changes: 36 additions & 0 deletions modules/simulation/DCSupplySimulator/manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
description: Implementation of a programmable power supply for DC charging
provides:
main:
interface: power_supply_DC
description: Main interface for the power supply
config:
bidirectional:
description: Set to true to for bidirectional supply
type: boolean
default: true
max_power:
description: Max supported power in watt
type: number
default: 150000
min_voltage:
description: Min supported voltage
type: number
default: 200.0
max_voltage:
description: Max supported voltage
type: number
default: 900.0
min_current:
description: Min supported current
type: number
default: 1.0
max_current:
description: Max supported current
type: number
default: 200.0
metadata:
license: https://opensource.org/licenses/Apache-2.0
authors:
- Cornelius Claussen (Pionix GmbH)
- Fabian Hartung (chargebyte GmbH)
- Mohannad Oraby (chargebyte GmbH)

0 comments on commit 3b6a044

Please sign in to comment.