Skip to content

Introduction of CbCPXDriver for upcoming new product "Charge Point eXtender"#47

Open
Erik827 wants to merge 13 commits intomainfrom
feature/CbCpxDriver
Open

Introduction of CbCPXDriver for upcoming new product "Charge Point eXtender"#47
Erik827 wants to merge 13 commits intomainfrom
feature/CbCpxDriver

Conversation

@Erik827
Copy link

@Erik827 Erik827 commented Jan 13, 2026

No description provided.

@Erik827 Erik827 requested review from FaHaGit and barsnick January 13, 2026 14:34
Copy link
Contributor

@barsnick barsnick left a comment

Choose a reason for hiding this comment

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

Great job, and what a big effort!

I don't think any of my comments are functional. Just one big compile problem with the dependency of CbCpx to CbCpxDriver.

The rest is cosmetic.

After fixing everything, be sure to run clang-format -i to fix indentation, header order, and stuff.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think if you name this file config/config-cpx-can-sil.yaml, and add generate_config_run_script(CONFIG cpx-can-sil) to config/CMakeLists.txt, it will create a run script for you. Or perhaps not in external repositories - not quite sure. 😉

Comment on lines 3 to 12
active_modules:
api:
connections:
evse_manager:
- implementation_id: evse
module_id: connector_1
error_history:
- module_id: error_history
implementation_id: error_history
module: API
Copy link
Contributor

Choose a reason for hiding this comment

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

For readability, we try to keep the module: entries at the top, i.e.:

Suggested change
active_modules:
api:
connections:
evse_manager:
- implementation_id: evse
module_id: connector_1
error_history:
- module_id: error_history
implementation_id: error_history
module: API
active_modules:
api:
module: API
connections:
evse_manager:
- implementation_id: evse
module_id: connector_1
error_history:
- module_id: error_history
implementation_id: error_history

(Also for the other entries below.)

ac_hlc_enabled: true
ac_hlc_use_5percent: false
ac_nominal_voltage: 230
charge_mode: AC
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't our major use case DC?

config_module:
device: auto
supported_ISO15118_2: true
connections: {}
Copy link
Contributor

Choose a reason for hiding this comment

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

An empty connections object is meaningless and can be omitted. (Yes it's also used in the upstream configs.)

Suggested change
connections: {}

Also in the other modules in this config.

Comment on lines 300 to 305
if (state_change)
EVLOG_info << "handle_allow_power_on: request to " << (value.allow_power_on ? "CLOSE" : "OPEN")
<< " the contactor";
else
EVLOG_debug << "handle_allow_power_on: request to " << (value.allow_power_on ? "CLOSE" : "OPEN")
<< " the contactor";
Copy link
Contributor

Choose a reason for hiding this comment

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

Try not to create the same string twice.

Suggested change
if (state_change)
EVLOG_info << "handle_allow_power_on: request to " << (value.allow_power_on ? "CLOSE" : "OPEN")
<< " the contactor";
else
EVLOG_debug << "handle_allow_power_on: request to " << (value.allow_power_on ? "CLOSE" : "OPEN")
<< " the contactor";
std::ostringstream ss;
ss << "handle_allow_power_on: request to " << (value.allow_power_on ? "CLOSE" : "OPEN")
<< " the contactor";
if (state_change)
EVLOG_info << ss.str();
else
EVLOG_debug << ss.str();

return;
}

int code_switch_state = this->mod->controller->switch_state(value.allow_power_on);
Copy link
Contributor

Choose a reason for hiding this comment

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

const

Suggested change
int code_switch_state = this->mod->controller->switch_state(value.allow_power_on);
const int code_switch_state = this->mod->controller->switch_state(value.allow_power_on);

EVLOG_info << "Current state: " << (this->mod->controller->get_contactor_state() ? "CLOSED" : "OPEN");

// publish PowerOn or PowerOff event
types::board_support_common::Event tmp_event = value.allow_power_on
Copy link
Contributor

Choose a reason for hiding this comment

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

const

Suggested change
types::board_support_common::Event tmp_event = value.allow_power_on
const types::board_support_common::Event tmp_event = value.allow_power_on

types::board_support_common::BspEvent tmp {tmp_event};
this->publish_event(tmp);
} else {
types::cb_board_support::ContactorState actual_state = !(value.allow_power_on)
Copy link
Contributor

Choose a reason for hiding this comment

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

const

Suggested change
types::cb_board_support::ContactorState actual_state = !(value.allow_power_on)
const types::cb_board_support::ContactorState actual_state = !(value.allow_power_on)

} // namespace temperatures
} // namespace module

#endif // TEMPERATURES_CB_CHARGESOM_TEMPERATURES_IMPL_HPP
Copy link
Contributor

Choose a reason for hiding this comment

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

Incorrect comment. This will fix itself if you re-run ev-cli.

Suggested change
#endif // TEMPERATURES_CB_CHARGESOM_TEMPERATURES_IMPL_HPP
#endif // TEMPERATURES_CB_CPX_TEMPERATURES_IMPL_HPP

this->cp_current_state = types::cb_board_support::CPState::PilotFault;
}
});

this->mod->controller->on_contactor_error.connect(
[&](const std::string& source, bool desired_state, types::cb_board_support::ContactorState actual_state) {
[this](const std::string& source, bool desired_state, types::cb_board_support::ContactorState actual_state) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you use two different types for desired_state and actual_state?

Copy link
Author

Choose a reason for hiding this comment

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

desired_state is used as bool because the contactors can either be open or closed. I thought it would be enough to use this binary type instead of enum which I use to make the semantics clearer for the log output.

Copy link
Member

Choose a reason for hiding this comment

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

We have similar constructs in the other drivers; let's leave it as is for now and rework it later for all platforms.

}

// we should see the changes take effect after 1s (FIXME)
std::this_thread::sleep_for(std::chrono::seconds(1));
Copy link
Contributor

Choose a reason for hiding this comment

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

What does “fixme” stand for? I would also appreciate not having to wait here for a fixed amount of time, especially because, as I see it, handle_power_on is blocked (mqtt receive thread).

@barsnick barsnick self-requested a review January 28, 2026 14:04
@Erik827 Erik827 requested review from FaHaGit and mhei January 28, 2026 14:15
Copy link
Contributor

@barsnick barsnick left a comment

Choose a reason for hiding this comment

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

Thanks for the changes! Looking good. I only found some (further) minor stuff.

Also, as a last step, maybe still worth running clang-formatover it.

Pal::Sigslot
nlohmann_json::nlohmann_json
everest::log
everest::sqlite

This comment was marked as resolved.

/// @brief Default constructor.
/// @param device_id Offset in CAN-ID used to identify hardware plattform
/// @param can_interface Name of the CAN-interface used for communication
CbCPX(int device_id, std::string can_interface, int can_bitrate);

This comment was marked as resolved.

bool is_emergency();

/// @brief Set a new duty cycle.
/// @param duty_cycle The desired duty cycle in percent [0.1 %].
Copy link
Contributor

Choose a reason for hiding this comment

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

in tenths of percent?

Copy link
Member

Choose a reason for hiding this comment

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

yes, this should be correct and is in sync with other safety chip based products

void set_duty_cycle(unsigned int duty_cycle);

/// @brief Set contactor state.
/// @param on Desired contactor state.

This comment was marked as resolved.

/// @param data Received CAN data
void read_git_hash(uint8_t* data);

/// @brief Return the current contactor state (even when no contactor is configured)

This comment was marked as resolved.

Comment on lines 196 to 197
int bytes_sent = write(this->can_raw_fd, &frame, static_cast<size_t>(sizeof(frame)));
if (bytes_sent != static_cast<int>(sizeof(frame))) {

This comment was marked as resolved.

gh_lock.unlock();

bytes_sent = write(this->can_raw_fd, &frame, static_cast<size_t>(sizeof(frame)));
if (bytes_sent != static_cast<int>(sizeof(frame))) {

This comment was marked as resolved.

@mhei mhei changed the title Feature/cb cpx driver Introduction of CbCPXDriver for upcoming new product "Charge Point eXtender" Jan 29, 2026
Copy link
Member

@mhei mhei left a comment

Choose a reason for hiding this comment

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

Now that #49 was merged, please rebase your branch on top of main branch and I recommend to squash your commits for the next review round.

default: 80
can_interface:
description: >-
Device name of the can interface to use for communication with CPX
Copy link
Member

Choose a reason for hiding this comment

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

I think we should use throughout the spelling "CAN" (all upper-case) since this is a well-known abbreviation.

Copy link
Author

Choose a reason for hiding this comment

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

I have changed the naming throughout except for included and generated libraries.

default: can0
can_bitrate:
description: >-
Bitrate of CAN bus used by CPX can controller.

This comment was marked as resolved.

description: >-
Bitrate of CAN bus used by CPX can controller.
type: integer
default: 500000

This comment was marked as resolved.

description: Enables or disables monitoring of an external Residual Current Device.
type: boolean
default: false
device_id:

This comment was marked as resolved.

description: Identification string used when this temperature channel is published
type: string
default: "PT1000-4"
rcm_enable:

This comment was marked as resolved.

This comment was marked as resolved.

Erik Herrmann added 12 commits January 30, 2026 08:26
This adds support for CPX hardware platform.

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
…lean

up config, fix bug in reacting to PP changes

- the id parameter was renamed to device_id to make it more intuitive
- now the default can-interface is can0
- before a complete config-object was handed down from CbCpxDriver to
CbCpx which is now done by handing over only the necessary values which
are then saved into a config-object of CbCpx
- a bug did not allow publishing the first PP-state change which is now
fixed

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
- remove unnecessary while-loop from CbCpxDriver
- improve comment meaningfulness
- use 1s instead of std::chrono::seconds(1)
- remove double string-formatting
- remove multiple identical function calls within same scope
- remove unnecessary breaking condition
- correct bug where contactor state was displayed wrong in log Output

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
- qualify member access with this-> and use const locals
- add safe casts for CAN frame sizes/IDs
- fix lambda captures and minor logic/style cleanups
- allow default args for temperature/contactor helpers

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
- replace notify flag struct with bitset + helpers
- simplify contactor/estop/pt1000 accessors with switch
- remove unused includes and stale comments
- drop unused Boost deps from cpx CMakeLists
- update manifest wording to CPX platform

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
Before the CAN-interface had to be configured on the operating system.
Now the usage of libsocketcan allows to do this setup from EVerest-configs.

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
Before a static one second wait was used to check if contactors switched
correctly. Now a condition variable is used to notify immediately if a
change is noticed.

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
@Erik827 Erik827 force-pushed the feature/CbCpxDriver branch from 0a71afa to 6e2d8a7 Compare January 30, 2026 07:36
- Rename CAN interface/bitrate config keys and propagate through driver
- Rename CAN interface source/header paths and includes
- Update CAN socket/member naming and helper functions for clarity
- Tighten type handling with explicit bool/size casts
- Tidy manifest (move device_id, add CAN bitrate bounds, drop rcm_enable)

Signed-off-by: Erik Herrmann <erik.herrmann@chargebyte.com>
@Erik827
Copy link
Author

Erik827 commented Jan 30, 2026

@mhei and @barsnick I have made the changes according to your comments. Everything compiles and works in the SiL. Once I have tested it with the HiL on Tuesday and confirmed that the changes are working I will request another review.

@Erik827 Erik827 requested review from barsnick and mhei February 3, 2026 07:42
Copy link
Member

@mhei mhei left a comment

Choose a reason for hiding this comment

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

I did not want you to change the variables in the manifest to be mixed-case, nor I wanted to change file names to upper case. I only wanted that you use "CAN" in comments and text.

And as mentioned before, please squash your commit, rebase on latest main branch and force-push to this branch to update this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants