Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DCSupplySimulator: Add C++ simulation module #499

Merged
merged 1 commit into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could remove JsDCSupplySimulator probably with this PR and update the configs in core to use the C++ version

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not yet, as the car sides of the SIL configs use JsDCSupplySimulator's powermeter interface implementation. That is not covered in this PR. (Should it be?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, not neccesarily now, but I'd like to drop the JS module at some point

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,
.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
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;

Check notice on line 25 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L25

struct member 'Conf::bidirectional' is never used.
double max_power;

Check notice on line 26 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L26

struct member 'Conf::max_power' is never used.
double min_voltage;

Check notice on line 27 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L27

struct member 'Conf::min_voltage' is never used.
double max_voltage;

Check notice on line 28 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L28

struct member 'Conf::max_voltage' is never used.
double min_current;

Check notice on line 29 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L29

struct member 'Conf::min_current' is never used.
double max_current;

Check notice on line 30 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L30

struct member 'Conf::max_current' is never used.
};

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) :

Check warning on line 36 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L36

Member variable 'power_supply_DCImpl::settings_connector_export_voltage' is not initialized in the constructor.
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;

Check notice on line 63 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L63

class member 'power_supply_DCImpl::settings_connector_export_voltage' is never used.
double settings_connector_import_voltage;

Check notice on line 64 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L64

class member 'power_supply_DCImpl::settings_connector_import_voltage' is never used.
double settings_connector_max_export_current;

Check notice on line 65 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L65

class member 'power_supply_DCImpl::settings_connector_max_export_current' is never used.
double settings_connector_max_import_current;

Check notice on line 66 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L66

class member 'power_supply_DCImpl::settings_connector_max_import_current' is never used.
types::power_supply_DC::Mode mode;
double connector_voltage;

Check notice on line 68 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L68

class member 'power_supply_DCImpl::connector_voltage' is never used.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can see connector_voltage and connector_current are used in the worker thread without locking the mutex. Also the set mode command handler does not use the mutex. Please review all access and add locks or use std::atomic here if it is ok that voltage/current do not both need to be locked at the same time.

double connector_current;

Check notice on line 69 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L69

class member 'power_supply_DCImpl::connector_current' is never used.
std::mutex power_supply_values_mutex;
Everest::Thread power_supply_thread_handle;
void power_supply_worker(void);

static constexpr int LOOP_SLEEP_MS{500};

Check notice on line 74 in modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/simulation/DCSupplySimulator/main/power_supply_DCImpl.hpp#L74

class member 'power_supply_DCImpl::LOOP_SLEEP_MS' is never used.
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)