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,20 @@
load("//modules:module.bzl", "cc_everest_module")
IMPLS = [
"connector_2",
"connector_1",
"rcd_1",
"rcd_2",
"connector_lock_1",
"connector_lock_2",
]
cc_everest_module(
name = "PhyVersoBSP",
deps = [
"//modules/HardwareDrivers/EVSE/PhyVersoBSP/phyverso_gpio",
"//modules/HardwareDrivers/EVSE/PhyVersoBSP/phyverso_mcu_comms",
],
impls = IMPLS,
srcs = ["board_support_common.cpp", "board_support_common.hpp"],
)

View File

@@ -0,0 +1,61 @@
#
# 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
add_subdirectory(phyverso_mcu_comms)
add_subdirectory(phyverso_cli)
add_subdirectory(phyverso_gpio)
target_include_directories(${MODULE_NAME}
PRIVATE
"common"
"phyverso_mcu_comms"
"phyverso_mcu_comms/nanopb"
"phyverso_mcu_comms/protobuf"
"phyverso_config"
"phyverso_gpio"
)
target_link_libraries(${MODULE_NAME}
PRIVATE
Pal::Sigslot
everest::gpio
phyverso_mcu_comms
phyverso_config
phyverso_gpio
)
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
target_sources(${MODULE_NAME}
PRIVATE
"connector_1/evse_board_supportImpl.cpp"
"connector_2/evse_board_supportImpl.cpp"
"rcd_1/ac_rcdImpl.cpp"
"rcd_2/ac_rcdImpl.cpp"
"connector_lock_1/connector_lockImpl.cpp"
"connector_lock_2/connector_lockImpl.cpp"
)
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
target_sources(${MODULE_NAME}
PRIVATE
"board_support_common.cpp"
)
# install MCU configs
# List all JSON files in the current directory and subdirectories
file(GLOB_RECURSE JSON_FILES "*.json")
# Check if the list is not empty
if(JSON_FILES)
# Install JSON files
install(FILES ${JSON_FILES} DESTINATION "${CMAKE_INSTALL_SYSCONFDIR}/everest")
endif()
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1

View File

@@ -0,0 +1,166 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "PhyVersoBSP.hpp"
#include <filesystem>
namespace module {
void PhyVersoBSP::init() {
// transform everest config into evConfig accessible to evSerial
everest_config_to_verso_config();
// initialize serial driver
if (!serial.open_device(config.serial_port.c_str(), config.baud_rate)) {
EVLOG_error << "Could not open serial port " << config.serial_port << " with baud rate " << config.baud_rate;
return;
}
// init user gpios
if (not gpio.init_gpios()) {
EVLOG_error << "Could not initialize user GPIOs. Terminating.";
return;
}
serial.flush_buffers();
serial.signal_config_request.connect([&]() {
serial.send_config();
EVLOG_info << "Sent config packet to MCU";
});
serial.signal_connection_timeout.connect([this]() {
auto err = p_connector_1->error_factory->create_error("evse_board_support/CommunicationFault", "McuToEverest",
"Serial connection to MCU timed out");
p_connector_1->raise_error(err);
err = p_connector_2->error_factory->create_error("evse_board_support/CommunicationFault", "McuToEverest",
"Serial connection to MCU timed out");
p_connector_2->raise_error(err);
});
serial.signal_error_flags.connect([this](int connector, ErrorFlags error_flags) {
// heartbeat failure from Mcu side (not receiving packets) will be visible in both connector errors
if (error_flags.heartbeat_timeout != last_heartbeat_error) {
if (error_flags.heartbeat_timeout) {
auto err = p_connector_1->error_factory->create_error(
"evse_board_support/CommunicationFault", "EverestToMcu", "MCU did not receive Everest heartbeat");
p_connector_1->raise_error(err);
err = p_connector_2->error_factory->create_error(
"evse_board_support/CommunicationFault", "EverestToMcu", "MCU did not receive Everest heartbeat");
p_connector_2->raise_error(err);
} else {
p_connector_1->clear_error("evse_board_support/CommunicationFault", "EverestToMcu");
p_connector_2->clear_error("evse_board_support/CommunicationFault", "EverestToMcu");
}
}
last_heartbeat_error = error_flags.heartbeat_timeout;
});
serial.signal_keep_alive.connect([this](KeepAlive d) {
mcu_config_done = d.configuration_done;
p_connector_1->clear_error("evse_board_support/CommunicationFault", "McuToEverest");
p_connector_2->clear_error("evse_board_support/CommunicationFault", "McuToEverest");
});
serial.reset(1);
serial.run();
gpio.run();
// very sporadically multiple resets needed for MCU to respond -> retrying until we get MCU response in a
// configured, ready and running state
mcu_config_done = false;
uint16_t n_tries = 0;
while (!mcu_config_done) {
serial.keep_alive();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
n_tries++;
if (n_tries > 20) {
EVLOG_info << "Trying reset again";
serial.flush_buffers();
serial.reset(1);
n_tries = 0;
}
}
invoke_init(*p_connector_1);
invoke_init(*p_connector_2);
invoke_init(*p_rcd_1);
invoke_init(*p_rcd_2);
invoke_init(*p_connector_lock_1);
invoke_init(*p_connector_lock_2);
}
void PhyVersoBSP::ready() {
invoke_ready(*p_connector_1);
invoke_ready(*p_connector_2);
invoke_ready(*p_rcd_1);
invoke_ready(*p_rcd_2);
invoke_ready(*p_connector_lock_1);
invoke_ready(*p_connector_lock_2);
if (not serial.is_open()) {
auto err = p_connector_1->error_factory->create_error("evse_board_support/CommunicationFault", "",
"Could not open serial port.");
p_connector_1->raise_error(err);
err = p_connector_2->error_factory->create_error("evse_board_support/CommunicationFault", "",
"Could not open serial port.");
p_connector_2->raise_error(err);
}
}
// fills evConfig bridge with config values from manifest/everest config
void PhyVersoBSP::everest_config_to_verso_config() {
// if a port is configured to be AC and has a socket, a motor lock type specification/usage is mandatory
if ((this->config.conn1_disable_port == false) && (this->config.conn1_dc == false) &&
(this->config.conn1_has_socket == true) && (this->config.conn1_motor_lock_type < 1)) {
EVLOG_critical << "Motor lock type for connector 1 has to be specified when using connector 1 as AC charging "
"port with a socket/detachable charging cable!";
throw std::runtime_error("Motor lock type for connector 1 has to be specified when using connector 1 as AC "
"charging port with a socket/detachable charging cable!");
}
if ((this->config.conn2_disable_port == false) && (this->config.conn2_dc == false) &&
(this->config.conn2_has_socket == true) && (this->config.conn2_motor_lock_type < 1)) {
EVLOG_critical << "Motor lock type for connector 2 has to be specified when using connector 2 as AC charging "
"port with a socket/detachable charging cable!";
throw std::runtime_error("Motor lock type for connector 2 has to be specified when using connector 2 as AC "
"charging port with a socket/detachable charging cable!");
}
if ((this->config.conn1_feedback_pull < 0) || (this->config.conn1_feedback_pull > 2)) {
EVLOG_error << "conn1_feedback_pull out of range! Falling back to default: 2";
verso_config.conf.conn1_feedback_pull = 2;
} else {
verso_config.conf.conn1_feedback_pull = this->config.conn1_feedback_pull;
}
if ((this->config.conn2_feedback_pull < 0) || (this->config.conn2_feedback_pull > 2)) {
EVLOG_error << "conn2_feedback_pull out of range! Falling back to default: 2";
verso_config.conf.conn2_feedback_pull = 2;
} else {
verso_config.conf.conn2_feedback_pull = this->config.conn2_feedback_pull;
}
verso_config.conf.serial_port = this->config.serial_port;
verso_config.conf.baud_rate = this->config.baud_rate;
verso_config.conf.reset_gpio_bank = this->config.reset_gpio_bank;
verso_config.conf.reset_gpio_pin = this->config.reset_gpio_pin;
verso_config.conf.conn1_motor_lock_type = this->config.conn1_motor_lock_type;
verso_config.conf.conn2_motor_lock_type = this->config.conn2_motor_lock_type;
verso_config.conf.conn1_gpio_stop_button_enabled = this->config.conn1_gpio_stop_button_enabled;
verso_config.conf.conn1_gpio_stop_button_bank = this->config.conn1_gpio_stop_button_bank;
verso_config.conf.conn1_gpio_stop_button_pin = this->config.conn1_gpio_stop_button_pin;
verso_config.conf.conn1_gpio_stop_button_invert = this->config.conn1_gpio_stop_button_invert;
verso_config.conf.conn2_gpio_stop_button_enabled = this->config.conn2_gpio_stop_button_enabled;
verso_config.conf.conn2_gpio_stop_button_bank = this->config.conn2_gpio_stop_button_bank;
verso_config.conf.conn2_gpio_stop_button_pin = this->config.conn2_gpio_stop_button_pin;
verso_config.conf.conn2_gpio_stop_button_invert = this->config.conn2_gpio_stop_button_invert;
verso_config.conf.conn1_disable_port = this->config.conn1_disable_port;
verso_config.conf.conn2_disable_port = this->config.conn2_disable_port;
verso_config.conf.conn1_feedback_active_low = this->config.conn1_feedback_active_low;
verso_config.conf.conn2_feedback_active_low = this->config.conn2_feedback_active_low;
verso_config.conf.conn1_dc = this->config.conn1_dc;
verso_config.conf.conn2_dc = this->config.conn2_dc;
}
} // namespace module

View File

@@ -0,0 +1,128 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PHY_VERSO_BSP_HPP
#define PHY_VERSO_BSP_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 2
//
#include "ld-ev.hpp"
// headers for provided interface implementations
#include <generated/interfaces/ac_rcd/Implementation.hpp>
#include <generated/interfaces/connector_lock/Implementation.hpp>
#include <generated/interfaces/evse_board_support/Implementation.hpp>
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
#include "phyverso_gpio/evGpio.h"
#include "phyverso_mcu_comms/evSerial.h"
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
namespace module {
struct Conf {
std::string serial_port;
int baud_rate;
int reset_gpio;
int conn1_max_current_A_import;
int conn1_min_current_A_import;
int conn1_min_phase_count_import;
int conn1_max_phase_count_import;
int conn1_min_current_A_export;
int conn1_max_current_A_export;
int conn1_min_phase_count_export;
int conn1_max_phase_count_export;
bool conn1_has_socket;
bool conn1_dc;
int conn2_max_current_A_import;
int conn2_min_current_A_import;
int conn2_min_phase_count_import;
int conn2_max_phase_count_import;
int conn2_min_current_A_export;
int conn2_max_current_A_export;
int conn2_min_phase_count_export;
int conn2_max_phase_count_export;
bool conn2_has_socket;
bool conn2_dc;
int reset_gpio_bank;
int reset_gpio_pin;
int conn1_motor_lock_type;
int conn2_motor_lock_type;
bool conn1_gpio_stop_button_enabled;
std::string conn1_gpio_stop_button_bank;
int conn1_gpio_stop_button_pin;
bool conn1_gpio_stop_button_invert;
bool conn2_gpio_stop_button_enabled;
std::string conn2_gpio_stop_button_bank;
int conn2_gpio_stop_button_pin;
bool conn2_gpio_stop_button_invert;
bool conn1_disable_port;
bool conn2_disable_port;
bool conn1_feedback_active_low;
bool conn2_feedback_active_low;
int conn1_feedback_pull;
int conn2_feedback_pull;
};
class PhyVersoBSP : public Everest::ModuleBase {
public:
PhyVersoBSP() = delete;
PhyVersoBSP(const ModuleInfo& info, Everest::TelemetryProvider& telemetry,
std::unique_ptr<evse_board_supportImplBase> p_connector_1,
std::unique_ptr<evse_board_supportImplBase> p_connector_2, std::unique_ptr<ac_rcdImplBase> p_rcd_1,
std::unique_ptr<ac_rcdImplBase> p_rcd_2, std::unique_ptr<connector_lockImplBase> p_connector_lock_1,
std::unique_ptr<connector_lockImplBase> p_connector_lock_2, Conf& config) :
ModuleBase(info),
telemetry(telemetry),
p_connector_1(std::move(p_connector_1)),
p_connector_2(std::move(p_connector_2)),
p_rcd_1(std::move(p_rcd_1)),
p_rcd_2(std::move(p_rcd_2)),
p_connector_lock_1(std::move(p_connector_lock_1)),
p_connector_lock_2(std::move(p_connector_lock_2)),
config(config){};
Everest::TelemetryProvider& telemetry;
const std::unique_ptr<evse_board_supportImplBase> p_connector_1;
const std::unique_ptr<evse_board_supportImplBase> p_connector_2;
const std::unique_ptr<ac_rcdImplBase> p_rcd_1;
const std::unique_ptr<ac_rcdImplBase> p_rcd_2;
const std::unique_ptr<connector_lockImplBase> p_connector_lock_1;
const std::unique_ptr<connector_lockImplBase> p_connector_lock_2;
const Conf& config;
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
// insert your public definitions here
evSerial serial{verso_config};
evConfig verso_config;
evGpio gpio{verso_config};
// 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
void everest_config_to_verso_config();
bool last_heartbeat_error;
bool mcu_config_done = false;
// 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 // PHY_VERSO_BSP_HPP

View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "board_support_common.hpp"
namespace module {
types::board_support_common::BspEvent to_bsp_event(CpState s) {
switch (s) {
case CpState_STATE_A:
return {types::board_support_common::Event::A};
case CpState_STATE_B:
return {types::board_support_common::Event::B};
case CpState_STATE_C:
return {types::board_support_common::Event::C};
case CpState_STATE_D:
return {types::board_support_common::Event::D};
case CpState_STATE_E:
return {types::board_support_common::Event::E};
case CpState_STATE_F:
return {types::board_support_common::Event::F};
// This should never happen
default:
return {types::board_support_common::Event::F};
}
}
types::board_support_common::BspEvent to_bsp_event(CoilState s) {
// TODO: implement coil type handling
if (s.coil_state) {
return {types::board_support_common::Event::PowerOn};
} else {
return {types::board_support_common::Event::PowerOff};
}
}
types::board_support_common::ProximityPilot to_pp_ampacity(PpState s) {
switch (s) {
case PpState_STATE_NC: {
return {types::board_support_common::Ampacity::None};
}
case PpState_STATE_13A: {
return {types::board_support_common::Ampacity::A_13};
}
case PpState_STATE_20A: {
return {types::board_support_common::Ampacity::A_20};
}
case PpState_STATE_32A: {
return {types::board_support_common::Ampacity::A_32};
}
case PpState_STATE_70A: {
return {types::board_support_common::Ampacity::A_63_3ph_70_1ph};
}
default: {
return {types::board_support_common::Ampacity::None};
}
}
}
} // namespace module

View File

@@ -0,0 +1,16 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef EVSE_BOARD_SUPPORT_COMMON_HPP
#define EVSE_BOARD_SUPPORT_COMMON_HPP
#include "phyverso.pb.h"
#include <generated/interfaces/evse_board_support/Implementation.hpp>
namespace module {
types::board_support_common::BspEvent to_bsp_event(CpState s);
types::board_support_common::BspEvent to_bsp_event(CoilState s);
types::board_support_common::ProximityPilot to_pp_ampacity(PpState s);
} // namespace module
#endif // EVSE_BOARD_SUPPORT_COMMON_HPP

View File

@@ -0,0 +1,5 @@
{
"conn1_motor_lock_type": 1,
"conn2_motor_lock_type": 1,
"reset_gpio_bank": 2
}

View File

@@ -0,0 +1,5 @@
{
"conn1_motor_lock_type": 2,
"conn2_motor_lock_type": 2,
"reset_gpio_bank": 2
}

View File

@@ -0,0 +1,181 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "evse_board_supportImpl.hpp"
namespace module {
namespace connector_1 {
void evse_board_supportImpl::init() {
{
std::scoped_lock lock(caps_mutex);
caps.min_current_A_import = mod->config.conn1_min_current_A_import;
caps.max_current_A_import = mod->config.conn1_max_current_A_import;
caps.min_phase_count_import = mod->config.conn1_min_phase_count_import;
caps.max_phase_count_import = mod->config.conn1_max_phase_count_import;
caps.supports_changing_phases_during_charging = false;
caps.supports_cp_state_E = false;
caps.min_current_A_export = mod->config.conn1_min_current_A_export;
caps.max_current_A_export = mod->config.conn1_max_current_A_export;
caps.min_phase_count_export = mod->config.conn1_min_phase_count_export;
caps.max_phase_count_export = mod->config.conn1_max_phase_count_export;
if (mod->config.conn1_has_socket) {
caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Socket;
} else {
caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable;
}
}
mod->serial.signal_cp_state.connect([this](int connector, CpState s) {
if (connector == 1 && s != last_cp_state) {
publish_event(to_bsp_event(s));
EVLOG_info << "[1] CP State changed: " << to_bsp_event(s);
last_cp_state = s;
}
});
mod->serial.signal_set_coil_state_response.connect([this](int connector, CoilState s) {
if (connector == 1) {
EVLOG_info << "[1] Relais: " << (s.coil_state ? "ON" : "OFF");
publish_event(to_bsp_event(s));
}
});
mod->serial.signal_telemetry.connect([this](int connector, Telemetry t) {
if (connector == 1) {
EVLOG_info << "[1] CP Voltage: " << t.cp_voltage_hi << " " << t.cp_voltage_lo;
}
});
mod->serial.signal_pp_state.connect([this](int connector, PpState s) {
if (connector == 1) {
if (last_pp_state != s) {
EVLOG_info << "[1] PpState " << s;
publish_ac_pp_ampacity(to_pp_ampacity(s));
}
last_pp_state = s;
}
});
mod->gpio.signal_stop_button_state.connect([this](int connector, bool state) {
if (connector == 1 && (state != last_stop_button_state)) {
types::evse_manager::StopTransactionRequest request;
request.reason = types::evse_manager::StopTransactionReason::Local;
this->publish_request_stop_transaction(request);
EVLOG_info << "[1] Request stop button state: " << (state ? "PUSHED" : "RELEASED");
last_stop_button_state = state;
}
});
mod->serial.signal_error_flags.connect([this](int connector, ErrorFlags error_flags) {
if (connector == 1) {
// Contactor feedback divergence
if (error_flags.coil_feedback_diverges != last_error_flags.coil_feedback_diverges) {
if (error_flags.coil_feedback_diverges) {
Everest::error::Error error_object = this->error_factory->create_error(
"evse_board_support/MREC17EVSEContactorFault", "",
"Port 1 contactor feedback diverges from target state", Everest::error::Severity::High);
this->raise_error(error_object);
} else {
this->clear_error("evse_board_support/MREC17EVSEContactorFault");
}
}
// Diode fault
if (error_flags.diode_fault != last_error_flags.diode_fault) {
if (error_flags.diode_fault) {
Everest::error::Error error_object = this->error_factory->create_error(
"evse_board_support/DiodeFault", "", "Port 1 diode fault", Everest::error::Severity::High);
this->raise_error(error_object);
} else {
this->clear_error("evse_board_support/DiodeFault");
}
}
// PP fault
if (error_flags.pp_signal_fault != last_error_flags.pp_signal_fault) {
if (error_flags.pp_signal_fault) {
Everest::error::Error error_object =
this->error_factory->create_error("evse_board_support/MREC23ProximityFault", "",
"Port 1 PP signal fault", Everest::error::Severity::High);
this->raise_error(error_object);
} else {
this->clear_error("evse_board_support/MREC23ProximityFault");
}
}
last_error_flags = error_flags;
}
});
}
void evse_board_supportImpl::ready() {
{
std::scoped_lock lock(caps_mutex);
publish_capabilities(caps);
}
}
void evse_board_supportImpl::handle_enable(bool& value) {
enabled = value;
if (enabled) {
mod->serial.set_pwm(1, last_pwm_raw);
} else {
mod->serial.set_pwm(1, 0);
}
}
void evse_board_supportImpl::handle_pwm_on(double& value) {
if (value >= 0 && value <= 100.) {
last_pwm_raw = value * 100;
if (enabled) {
mod->serial.set_pwm(1, last_pwm_raw);
}
} else {
EVLOG_warning << "Invalid pwm value " << value;
}
}
void evse_board_supportImpl::handle_cp_state_X1() {
last_pwm_raw = 10000;
if (enabled) {
mod->serial.set_pwm(1, last_pwm_raw);
}
}
void evse_board_supportImpl::handle_cp_state_F() {
last_pwm_raw = 0;
if (enabled) {
mod->serial.set_pwm(1, last_pwm_raw);
}
}
void evse_board_supportImpl::handle_cp_state_E() {
EVLOG_warning << "Command cp_state_E is not supported. Ignoring command.";
}
void evse_board_supportImpl::handle_allow_power_on(types::evse_board_support::PowerOnOff& value) {
if (mod->config.conn1_disable_port) {
EVLOG_error << "[1] Port disabled; Cannot set power_on!";
return;
}
if (mod->config.conn1_dc) {
mod->serial.set_coil_state_request(1, CoilType_COIL_DC1, value.allow_power_on);
} else {
mod->serial.set_coil_state_request(1, CoilType_COIL_AC, value.allow_power_on);
}
}
void evse_board_supportImpl::handle_ac_switch_three_phases_while_charging(bool& value) {
// your code for cmd ac_switch_three_phases_while_charging goes here
}
void evse_board_supportImpl::handle_ac_set_overcurrent_limit_A(double& value) {
// your code for cmd ac_set_overcurrent_limit_A goes here
}
} // namespace connector_1
} // namespace module

View File

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef CONNECTOR_1_EVSE_BOARD_SUPPORT_IMPL_HPP
#define CONNECTOR_1_EVSE_BOARD_SUPPORT_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/evse_board_support/Implementation.hpp>
#include "../PhyVersoBSP.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
#include "board_support_common.hpp"
#include "evGpio.h"
#include <atomic>
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace connector_1 {
struct Conf {};
class evse_board_supportImpl : public evse_board_supportImplBase {
public:
evse_board_supportImpl() = delete;
evse_board_supportImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PhyVersoBSP>& mod, Conf& config) :
evse_board_supportImplBase(ev, "connector_1"), 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 void handle_enable(bool& value) override;
virtual void handle_pwm_on(double& value) override;
virtual void handle_cp_state_X1() override;
virtual void handle_cp_state_F() override;
virtual void handle_cp_state_E() override;
virtual void handle_allow_power_on(types::evse_board_support::PowerOnOff& value) override;
virtual void handle_ac_switch_three_phases_while_charging(bool& value) override;
virtual void handle_ac_set_overcurrent_limit_A(double& value) override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PhyVersoBSP>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
types::evse_board_support::HardwareCapabilities caps;
std::mutex caps_mutex;
CpState last_cp_state;
PpState last_pp_state; ///< The last pp state received from the MCU.
bool last_stop_button_state;
ErrorFlags last_error_flags;
int last_pwm_raw{10000};
std::atomic_bool enabled{false};
// 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 connector_1
} // namespace module
#endif // CONNECTOR_1_EVSE_BOARD_SUPPORT_IMPL_HPP

View File

@@ -0,0 +1,181 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "evse_board_supportImpl.hpp"
namespace module {
namespace connector_2 {
void evse_board_supportImpl::init() {
{
std::scoped_lock lock(caps_mutex);
caps.min_current_A_import = mod->config.conn2_min_current_A_import;
caps.max_current_A_import = mod->config.conn2_max_current_A_import;
caps.min_phase_count_import = mod->config.conn2_min_phase_count_import;
caps.max_phase_count_import = mod->config.conn2_max_phase_count_import;
caps.supports_changing_phases_during_charging = false;
caps.supports_cp_state_E = false;
caps.min_current_A_export = mod->config.conn2_min_current_A_export;
caps.max_current_A_export = mod->config.conn2_max_current_A_export;
caps.min_phase_count_export = mod->config.conn2_min_phase_count_export;
caps.max_phase_count_export = mod->config.conn2_max_phase_count_export;
if (mod->config.conn2_has_socket) {
caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Socket;
} else {
caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable;
}
}
mod->serial.signal_cp_state.connect([this](int connector, CpState s) {
if (connector == 2 && s != last_cp_state) {
publish_event(to_bsp_event(s));
EVLOG_info << "[2] CP State changed: " << to_bsp_event(s);
last_cp_state = s;
}
});
mod->serial.signal_set_coil_state_response.connect([this](int connector, CoilState s) {
if (connector == 2) {
EVLOG_info << "[2] Relais: " << (s.coil_state ? "ON" : "OFF");
publish_event(to_bsp_event(s));
}
});
mod->serial.signal_telemetry.connect([this](int connector, Telemetry t) {
if (connector == 2) {
EVLOG_info << "[2] CP Voltage: " << t.cp_voltage_hi << " " << t.cp_voltage_lo;
}
});
mod->serial.signal_pp_state.connect([this](int connector, PpState s) {
if (connector == 2) {
if (last_pp_state != s) {
EVLOG_info << "[2] PpState " << s;
publish_ac_pp_ampacity(to_pp_ampacity(s));
}
last_pp_state = s;
}
});
mod->gpio.signal_stop_button_state.connect([this](int connector, bool state) {
if (connector == 2 && (state != last_stop_button_state)) {
types::evse_manager::StopTransactionRequest request;
request.reason = types::evse_manager::StopTransactionReason::Local;
this->publish_request_stop_transaction(request);
EVLOG_info << "[2] Request stop button state: " << (state ? "PUSHED" : "RELEASED");
last_stop_button_state = state;
}
});
mod->serial.signal_error_flags.connect([this](int connector, ErrorFlags error_flags) {
if (connector == 2) {
// Contactor feedback divergence
if (error_flags.coil_feedback_diverges != last_error_flags.coil_feedback_diverges) {
if (error_flags.coil_feedback_diverges) {
Everest::error::Error error_object = this->error_factory->create_error(
"evse_board_support/MREC17EVSEContactorFault", "",
"Port 2 contactor feedback diverges from target state", Everest::error::Severity::High);
this->raise_error(error_object);
} else {
this->clear_error("evse_board_support/MREC17EVSEContactorFault");
}
}
// Diode fault
if (error_flags.diode_fault != last_error_flags.diode_fault) {
if (error_flags.diode_fault) {
Everest::error::Error error_object = this->error_factory->create_error(
"evse_board_support/DiodeFault", "", "Port 2 diode fault", Everest::error::Severity::High);
this->raise_error(error_object);
} else {
this->clear_error("evse_board_support/DiodeFault");
}
}
// PP fault
if (error_flags.pp_signal_fault != last_error_flags.pp_signal_fault) {
if (error_flags.pp_signal_fault) {
Everest::error::Error error_object =
this->error_factory->create_error("evse_board_support/MREC23ProximityFault", "",
"Port 2 PP signal fault", Everest::error::Severity::High);
this->raise_error(error_object);
} else {
this->clear_error("evse_board_support/MREC23ProximityFault");
}
}
last_error_flags = error_flags;
}
});
}
void evse_board_supportImpl::ready() {
{
std::scoped_lock lock(caps_mutex);
publish_capabilities(caps);
}
}
void evse_board_supportImpl::handle_enable(bool& value) {
enabled = value;
if (enabled) {
mod->serial.set_pwm(2, last_pwm_raw);
} else {
mod->serial.set_pwm(2, 0);
}
}
void evse_board_supportImpl::handle_pwm_on(double& value) {
if (value >= 0 && value <= 100.) {
last_pwm_raw = value * 100;
if (enabled) {
mod->serial.set_pwm(2, last_pwm_raw);
}
} else {
EVLOG_warning << "Invalid pwm value " << value;
}
}
void evse_board_supportImpl::handle_cp_state_X1() {
last_pwm_raw = 10000;
if (enabled) {
mod->serial.set_pwm(2, last_pwm_raw);
}
}
void evse_board_supportImpl::handle_cp_state_F() {
last_pwm_raw = 0;
if (enabled) {
mod->serial.set_pwm(2, last_pwm_raw);
}
}
void evse_board_supportImpl::handle_cp_state_E() {
EVLOG_warning << "Command cp_state_E is not supported. Ignoring command.";
}
void evse_board_supportImpl::handle_allow_power_on(types::evse_board_support::PowerOnOff& value) {
if (mod->config.conn2_disable_port) {
EVLOG_error << "[2] Port disabled; Cannot set power_on!";
return;
}
if (mod->config.conn2_dc) {
mod->serial.set_coil_state_request(2, CoilType_COIL_DC1, value.allow_power_on);
} else {
mod->serial.set_coil_state_request(2, CoilType_COIL_AC, value.allow_power_on);
}
}
void evse_board_supportImpl::handle_ac_switch_three_phases_while_charging(bool& value) {
// your code for cmd ac_switch_three_phases_while_charging goes here
}
void evse_board_supportImpl::handle_ac_set_overcurrent_limit_A(double& value) {
// your code for cmd ac_set_overcurrent_limit_A goes here
}
} // namespace connector_2
} // namespace module

View File

@@ -0,0 +1,77 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef CONNECTOR_2_EVSE_BOARD_SUPPORT_IMPL_HPP
#define CONNECTOR_2_EVSE_BOARD_SUPPORT_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/evse_board_support/Implementation.hpp>
#include "../PhyVersoBSP.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
#include "board_support_common.hpp"
#include <atomic>
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace connector_2 {
struct Conf {};
class evse_board_supportImpl : public evse_board_supportImplBase {
public:
evse_board_supportImpl() = delete;
evse_board_supportImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PhyVersoBSP>& mod, Conf& config) :
evse_board_supportImplBase(ev, "connector_2"), 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 void handle_enable(bool& value) override;
virtual void handle_pwm_on(double& value) override;
virtual void handle_cp_state_X1() override;
virtual void handle_cp_state_F() override;
virtual void handle_cp_state_E() override;
virtual void handle_allow_power_on(types::evse_board_support::PowerOnOff& value) override;
virtual void handle_ac_switch_three_phases_while_charging(bool& value) override;
virtual void handle_ac_set_overcurrent_limit_A(double& value) override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PhyVersoBSP>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
types::evse_board_support::HardwareCapabilities caps;
std::mutex caps_mutex;
CpState last_cp_state;
PpState last_pp_state; ///< The last pp state received from the MCU.
bool last_stop_button_state;
ErrorFlags last_error_flags;
int last_pwm_raw{10000};
std::atomic_bool enabled{false};
// 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 connector_2
} // namespace module
#endif // CONNECTOR_2_EVSE_BOARD_SUPPORT_IMPL_HPP

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "connector_lockImpl.hpp"
namespace module {
namespace connector_lock_1 {
void connector_lockImpl::init() {
}
void connector_lockImpl::ready() {
}
void connector_lockImpl::handle_lock() {
EVLOG_info << "Locking connector 1";
mod->serial.lock(1, true);
}
void connector_lockImpl::handle_unlock() {
EVLOG_info << "Unlocking connector 1";
mod->serial.lock(1, false);
}
} // namespace connector_lock_1
} // namespace module

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef CONNECTOR_LOCK_1_CONNECTOR_LOCK_IMPL_HPP
#define CONNECTOR_LOCK_1_CONNECTOR_LOCK_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/connector_lock/Implementation.hpp>
#include "../PhyVersoBSP.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace connector_lock_1 {
struct Conf {};
class connector_lockImpl : public connector_lockImplBase {
public:
connector_lockImpl() = delete;
connector_lockImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PhyVersoBSP>& mod, Conf& config) :
connector_lockImplBase(ev, "connector_lock_1"), 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 void handle_lock() override;
virtual void handle_unlock() override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PhyVersoBSP>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
// 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 connector_lock_1
} // namespace module
#endif // CONNECTOR_LOCK_1_CONNECTOR_LOCK_IMPL_HPP

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "connector_lockImpl.hpp"
namespace module {
namespace connector_lock_2 {
void connector_lockImpl::init() {
}
void connector_lockImpl::ready() {
}
void connector_lockImpl::handle_lock() {
EVLOG_info << "Locking connector 2";
mod->serial.lock(2, true);
}
void connector_lockImpl::handle_unlock() {
EVLOG_info << "Unlocking connector 2";
mod->serial.lock(2, false);
}
} // namespace connector_lock_2
} // namespace module

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef CONNECTOR_LOCK_2_CONNECTOR_LOCK_IMPL_HPP
#define CONNECTOR_LOCK_2_CONNECTOR_LOCK_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/connector_lock/Implementation.hpp>
#include "../PhyVersoBSP.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace connector_lock_2 {
struct Conf {};
class connector_lockImpl : public connector_lockImplBase {
public:
connector_lockImpl() = delete;
connector_lockImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PhyVersoBSP>& mod, Conf& config) :
connector_lockImplBase(ev, "connector_lock_2"), 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 void handle_lock() override;
virtual void handle_unlock() override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PhyVersoBSP>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
// 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 connector_lock_2
} // namespace module
#endif // CONNECTOR_LOCK_2_CONNECTOR_LOCK_IMPL_HPP

View File

@@ -0,0 +1,237 @@
description: Driver module for Phytec PhyVerso EV Charging controller with Pionix MCU firmware
config:
serial_port:
description: Serial port the hardware is connected to
type: string
default: /dev/ttyUSB0
baud_rate:
description: Serial baud rate to use when communicating with the hardware
type: integer
minimum: 9600
maximum: 230400
default: 115200
reset_gpio:
description: If set <0 it is disabled. If > 0, configured reset_gpio_bank and reset_gpio_pin configuration is used for hard reset of MCU
type: integer
minimum: -1
maximum: 1000
default: -1
conn1_max_current_A_import:
description: Maximum import current in amps
type: integer
minimum: 0
default: 16
conn1_min_current_A_import:
description: Minimum import current in amps
type: integer
minimum: 0
default: 6
conn1_min_phase_count_import:
description: Minimum phase count for import
type: integer
minimum: 1
maximum: 3
default: 3
conn1_max_phase_count_import:
description: Maximum phase count for import
type: integer
minimum: 1
maximum: 3
default: 3
conn1_min_current_A_export:
description: Minimum export current in amps
type: integer
minimum: 0
maximum: 63
default: 0
conn1_max_current_A_export:
description: Maximum export current in amps
type: integer
minimum: 0
maximum: 63
default: 0
conn1_min_phase_count_export:
description: Minimum phase count for export
type: integer
minimum: 1
maximum: 3
default: 3
conn1_max_phase_count_export:
description: Maximum phase count for export
type: integer
minimum: 1
maximum: 3
default: 3
conn1_has_socket:
description: Set to true if it has a socket, false if it has a permanently attached cable
type: boolean
default: false
conn1_dc:
description: Set to true if it is for DC, false if it is AC
type: boolean
default: false
conn2_max_current_A_import:
description: Maximum import current in amps
type: integer
minimum: 0
default: 16
conn2_min_current_A_import:
description: Minimum import current in amps
type: integer
minimum: 0
default: 6
conn2_min_phase_count_import:
description: Minimum phase count for import
type: integer
minimum: 1
maximum: 3
default: 3
conn2_max_phase_count_import:
description: Maximum phase count for import
type: integer
minimum: 1
maximum: 3
default: 3
conn2_min_current_A_export:
description: Minimum export current in amps
type: integer
minimum: 0
maximum: 63
default: 0
conn2_max_current_A_export:
description: Maximum export current in amps
type: integer
minimum: 0
maximum: 63
default: 0
conn2_min_phase_count_export:
description: Minimum phase count for export
type: integer
minimum: 1
maximum: 3
default: 3
conn2_max_phase_count_export:
description: Maximum phase count for export
type: integer
minimum: 1
maximum: 3
default: 3
conn2_has_socket:
description: Set to true if it has a socket, false if it has a permanently attached cable
type: boolean
default: false
conn2_dc:
description: Set to true if it is for DC, false if it is AC
type: boolean
default: false
reset_gpio_bank:
description: GPIO peripheral bank the nRST pin of the MCU is mapped to
type: integer
default: 1
reset_gpio_pin:
description: GPIO peripheral pin the nRST pin of the MCU is mapped to
type: integer
default: 23
conn1_motor_lock_type:
description: >
Connector 1 motor lock type;
-1 == no Lock
1 == Hella Style time-based lock,
2 == Valeo potentiometer feedback based;
If charging port has a socket and is AC charging, it will need a lock specified
type: integer
default: -1
conn2_motor_lock_type:
description: >
Connector 2 motor lock type;
-1 == no Lock
1 == Hella Style time-based lock,
2 == Valeo potentiometer feedback based;
If charging port has a socket and is AC charging, it will need a lock specified
type: integer
default: -1
conn1_gpio_stop_button_enabled:
description: Set to true to enable external charging stop button for connector 1 on a GPIO connected to the SOM
type: boolean
default: false
conn1_gpio_stop_button_bank:
description: GPIO peripheral bank for connector 1 stop button
type: string
default: gpiochip1
conn1_gpio_stop_button_pin:
description: GPIO peripheral pin for connector 1 stop button
type: integer
default: 36
conn1_gpio_stop_button_invert:
description: Set to true to invert pin logic
type: boolean
default: false
conn2_gpio_stop_button_enabled:
description: Set to true to enable external charging stop button for connector 2 on a GPIO connected to the SOM
type: boolean
default: false
conn2_gpio_stop_button_bank:
description: GPIO peripheral bank for connector 2 stop button
type: string
default: gpiochip1
conn2_gpio_stop_button_pin:
description: GPIO peripheral pin for connector 2 stop button
type: integer
default: 37
conn2_gpio_stop_button_invert:
description: Set to true to invert pin logic
type: boolean
default: false
conn1_disable_port:
description: Set to true if port 1 is neither used for AC nor DC charging (will overwrite conn1_dc parameter)
type: boolean
default: false
conn2_disable_port:
description: Set to true if port 2 is neither used for AC nor DC charging (will overwrite conn2_dc parameter)
type: boolean
default: false
conn1_feedback_active_low:
description: Set to true if relay mirror contact on port 1 feedback is active LOW, false if active HIGH; don't change for AC port config
type: boolean
default: true
conn2_feedback_active_low:
description: Set to true if relay mirror contact on port 2 feedback is active LOW, false if active HIGH; don't change for AC port config
type: boolean
default: true
conn1_feedback_pull:
description: DC port config only - specify which way internal pull resistors will work; 0 -> None, 1 -> PullUp, 2 -> PullDown (default=PD)
type: integer
default: 2
conn2_feedback_pull:
description: DC port config only - specify which way internal pull resistors will work; 0 -> None, 1 -> PullUp, 2 -> PullDown (default=PD)
type: integer
default: 2
provides:
connector_1:
interface: evse_board_support
description: provides the board support interface to low level control the proximity and control pilots, relais and motor lock
connector_2:
interface: evse_board_support
description: provides the board support interface to low level control the proximity and control pilots, relais and motor lock
rcd_1:
interface: ac_rcd
description: RCD interface for an external RDC-MD
rcd_2:
interface: ac_rcd
description: RCD interface of the onboard RDC-MD
connector_lock_1:
interface: connector_lock
description: Lock interface
connector_lock_2:
interface: connector_lock
description: Lock interface
enable_telemetry: true
metadata:
license: https://opensource.org/licenses/Apache-2.0
authors:
- Cornelius Claussen
- Jonas Rockstroh

View File

@@ -0,0 +1,31 @@
cmake_minimum_required(VERSION 3.10)
# set the project name
project(phyverso_cli VERSION 0.1)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
find_package(Threads REQUIRED)
# add the executable
add_executable(phyverso_cli main.cpp)
target_include_directories(phyverso_cli
PUBLIC
"${PROJECT_BINARY_DIR}"
"../phyverso_mcu_comms/protobuf"
"../phyverso_mcu_comms"
"../phyverso_config"
)
target_link_libraries(phyverso_cli
PRIVATE
Pal::Sigslot
Threads::Threads
phyverso_mcu_comms
everest::framework
everest::nanopb
phyverso_config
)
install(TARGETS phyverso_cli
DESTINATION ${EVEREST_MOD_PHYVERSOBSP_DESTINATION})

View File

@@ -0,0 +1,307 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <stdio.h>
#include <string.h>
#include "evSerial.h"
#include <unistd.h>
#include "phyverso.pb.h"
#include <sigslot/signal.hpp>
std::atomic_bool sw_version_received = false;
void help() {
printf("\nUsage: ./phyverso_cli /dev/ttyXXX /path/to/config.json\n\n");
}
int main(int argc, char* argv[]) {
int selected_connector = 1;
printf("-- Phyverso CLI tool --\n");
printf("Use the following keys to send packets:\n");
printf("A or a: set AC coil on or off\n");
printf("D or d: set (monitored) DC coil on or off\n");
printf("O or o: set (unmonitored) AUX1 DC coil on or off\n");
printf("P or p: set (unmonitored) AUX2 DC coil on or off\n");
printf("L or l: motorlock lock or unlock\n");
printf("R or r: hard or soft reset\n");
printf("V: send keep alive/get version\n");
printf("K: trigger RCD TEST on selected connector\n");
printf("k: reset RCD on selected connector\n\n");
printf("1: use connector 1\n");
printf("2: use connector 2\n\n");
printf("0: PWM F (0%% DC, -12V)\n");
printf("5: PWM 5%%\n");
printf("6: PWM 10%%\n");
printf("7: PWM 80%%\n");
printf("8: PWM 97%%\n");
printf("9: PWM X1 (100%%)\n");
printf("9: PWM X1 (100%%)\n");
printf("U or u: Fan1 50%% or OFF (if your fan supports 0%% duty cycle)\n");
printf("I or i: Fan2 ON or 20%%\n");
if (argc != 3) {
help();
exit(0);
}
const char* device = argv[1];
const char* config_path = argv[2];
evConfig verso_config;
// with config rework we still have to go the json route here
if (!verso_config.open_file(config_path)) {
printf("Could not open config file \"%s\"\n", config_path);
return -1;
}
verso_config.json_conf_to_evConfig();
evSerial p(verso_config);
if (!p.open_device(device, 115200)) {
printf("Cannot open device \"%s\"\n", device);
} else {
p.run();
p.signal_config_request.connect([&]() {
printf("Received config request\n");
p.send_config();
printf("Sent config packet\n");
});
p.signal_keep_alive.connect([](KeepAlive s) {
printf(">> KeepAlive: phyverso MCU SW Version: %s, Hardware %i/rev %i, MCU Timestamp %i\n",
s.sw_version_string, s.hw_type, s.hw_revision, s.time_stamp);
sw_version_received = true;
});
p.signal_set_coil_state_response.connect([](int connector, CoilState s) {
if (s.coil_state)
printf(">> Connector %i, Coil %d: Relais CLOSED\n", connector, s.coil_type);
else
printf(">> Connector %i, Coil %d: Relais OPEN\n", connector, s.coil_type);
});
p.signal_telemetry.connect([](int connector, Telemetry t) {
printf(">> Connector %i: CP Voltage %i %i\n", connector, t.cp_voltage_hi, t.cp_voltage_lo);
});
p.signal_cp_state.connect([](int connector, CpState s) {
switch (s) {
case CpState_STATE_A:
printf(">> Connector %i: CP state A\n", connector);
break;
case CpState_STATE_B:
printf(">> Connector %i: CP state B\n", connector);
break;
case CpState_STATE_C:
printf(">> Connector %i: CP state C\n", connector);
break;
case CpState_STATE_D:
printf(">> Connector %i: CP state D\n", connector);
break;
case CpState_STATE_E:
printf(">> Connector %i: CP state E\n", connector);
break;
case CpState_STATE_F:
printf(">> Connector %i: CP state F\n", connector);
break;
}
});
p.signal_pp_state.connect([](int connector, PpState s) {
switch (s) {
case PpState_STATE_NC:
printf(">> Connector %i: PP state NC\n", connector);
break;
case PpState_STATE_13A:
printf(">> Connector %i: PP state 13A\n", connector);
break;
case PpState_STATE_20A:
printf(">> Connector %i: PP state 20A\n", connector);
break;
case PpState_STATE_32A:
printf(">> Connector %i: PP state 32A\n", connector);
break;
case PpState_STATE_70A:
printf(">> Connector %i: PP state 70A\n", connector);
break;
case PpState_STATE_FAULT:
printf(">> Connector %i: PP state FAULT\n", connector);
break;
}
});
p.signal_fan_state.connect([](FanState s) {
printf(">> Fan %i: EN=%s, Duty=%d RPM=%d\n", s.fan_id, (s.enabled ? "ON" : "OFF"), s.duty, s.rpm);
});
p.signal_lock_state.connect([](int connector, LockState s) {
switch (s) {
case LockState_UNDEFINED:
printf(">> Connector %i: Lock State UNDEFINED\n", connector);
break;
case LockState_LOCKED:
printf(">> Connector %i: Lock State Locked\n", connector);
break;
case LockState_UNLOCKED:
printf(">> Connector %i: Lock State Unlocked\n", connector);
break;
case LockState_LOCKING:
printf(">> Connector %i: Lock State Locking\n", connector);
break;
case LockState_UNLOCKING:
printf(">> Connector %i: Lock State Unlocking\n", connector);
break;
}
});
p.signal_error_flags.connect([](int connector, ErrorFlags error_flags) {
printf("------------\nError flags Connector %d:\n", connector);
printf("\tdiode_fault: %d\n", error_flags.diode_fault);
printf("\trcd_selftest_failed: %d\n", error_flags.rcd_selftest_failed);
printf("\trcd_triggered: %d\n", error_flags.rcd_triggered);
printf("\tventilation_not_available: %d\n", error_flags.ventilation_not_available);
printf("\tconnector_lock_failed: %d\n", error_flags.connector_lock_failed);
printf("\tcp_signal_fault: %d\n", error_flags.cp_signal_fault);
printf("\theartbeat_timeout: %d\n", error_flags.heartbeat_timeout);
printf("\tcoil_feedback_diverges_ac: %d\n", error_flags.coil_feedback_diverges);
printf("\tpp_signal_fault: %d\n", error_flags.pp_signal_fault);
printf("------------\n");
});
while (true) {
char c = getc(stdin);
switch (c) {
/* AC coils*/
case 'A':
printf("Setting AC coil to ON\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_AC, true);
break;
case 'a':
printf("Setting AC coil to OFF\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_AC, false);
break;
/* DC coils */
case 'D':
printf("Setting monitored DC coil to ON\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_DC1, true);
break;
case 'd':
printf("Setting monitored DC coil to OFF\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_DC1, false);
break;
case 'O':
printf("Setting AUX1 DC coil to ON\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_DC2, true);
break;
case 'o':
printf("Setting AUX1 DC coil to OFF\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_DC2, false);
break;
case 'P':
printf("Setting AUX2 DC coil to ON\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_DC3, true);
break;
case 'p':
printf("Setting AUX2 DC coil to OFF\n");
p.set_coil_state_request(selected_connector, CoilType_COIL_DC3, false);
break;
/* Motor lock */
case 'L':
printf("Locking connector\n");
p.lock(selected_connector, true);
break;
case 'l':
printf("Unlocking connector\n");
p.lock(selected_connector, false);
break;
/* Resets */
case 'r':
printf("Soft reset\n");
p.reset(-1);
break;
case 'R':
printf("Hard reset\n");
p.reset(1);
break;
/* Versions/timestamp */
case 'V':
printf("Sending keep alive\n");
p.keep_alive();
break;
/* Charging connector selection */
case '1':
printf("Connector 1 selected.\n");
selected_connector = 1;
break;
case '2':
printf("Connector 2 selected.\n");
selected_connector = 2;
break;
/* CP PWM setting */
case '0':
printf("Set 0%% PWM\n");
p.set_pwm(selected_connector, 0);
break;
case '5':
printf("Set 5%% PWM\n");
p.set_pwm(selected_connector, 500);
break;
case '6':
printf("Set 10%% PWM\n");
p.set_pwm(selected_connector, 1000);
break;
case '7':
printf("Set 80%% PWM\n");
p.set_pwm(selected_connector, 8000);
break;
case '8':
printf("Set 97%% PWM\n");
p.set_pwm(selected_connector, 9700);
break;
case '9':
printf("Set 100%% PWM\n");
p.set_pwm(selected_connector, 10000);
break;
/* Fans */
case 'U':
printf("Set fan1 to 50%%\n");
p.set_fan_state(0, true, 500);
break;
case 'u':
printf("Set fan1 to OFF\n");
p.set_fan_state(0, false, 500); // example for setting fan off via enable param
// check if your fan supports full OFF on PWM 0% duty (also check PWM on oscilloscope)
// some PWM fans wont turn fully off without switching 12V supply
break;
case 'I':
printf("Set fan2 to ON\n");
p.set_fan_state(1, true, 1000);
break;
case 'i':
printf("Set fan2 to 20%%\n");
p.set_fan_state(1, true, 200);
break;
/* RCD */
case 'K':
printf("Sending RCD Test on connector %d\n", selected_connector);
p.set_rcd_test(selected_connector, true);
break;
case 'k':
printf("Resetting RCD on connector %d\n", selected_connector);
p.reset_rcd(selected_connector, true);
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
return 0;
}

View File

@@ -0,0 +1,19 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "phyverso_gpio",
deps = [
"//modules/HardwareDrivers/EVSE/PhyVersoBSP/phyverso_mcu_comms",
"//lib/everest/gpio",
"@sigslot//:sigslot",
],
srcs = glob([
"**/*.h",
"**/*.cpp",
]),
visibility = ["//visibility:public"],
includes = [
".",
],
copts = ["-std=c++17"],
)

View File

@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.10)
# set the project name
project(phyverso_gpio VERSION 0.1)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_library(phyverso_gpio STATIC)
ev_register_library_target(phyverso_gpio)
target_sources(phyverso_gpio
PRIVATE
evGpio.cpp
)
target_include_directories(phyverso_gpio
PUBLIC
"${PROJECT_BINARY_DIR}"
"../phyverso_mcu_comms"
)
target_link_libraries(phyverso_gpio
PUBLIC
date::date-tz
everest::nanopb
PRIVATE
Pal::Sigslot
everest::framework
everest::gpio
phyverso_config
fmt::fmt
)

View File

@@ -0,0 +1,89 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "evGpio.h"
#include <everest/logging.hpp>
#include <fmt/format.h>
evGpio::evGpio(evConfig& _verso_config) : verso_config(_verso_config) {
}
evGpio::~evGpio() {
// TODO: deinit gpios?
}
bool evGpio::init_gpios() {
push_buttons[CONN1_PB_STOP].set_enabled(verso_config.conf.conn1_gpio_stop_button_enabled);
push_buttons[CONN2_PB_STOP].set_enabled(verso_config.conf.conn2_gpio_stop_button_enabled);
if (push_buttons[CONN1_PB_STOP].get_enabled()) {
Everest::GpioSettings settings;
settings.chip_name = verso_config.conf.conn1_gpio_stop_button_bank;
settings.line_number = verso_config.conf.conn1_gpio_stop_button_pin;
settings.inverted = verso_config.conf.conn1_gpio_stop_button_invert;
push_buttons[CONN1_PB_STOP].init_gpio(settings);
if (not push_buttons[CONN1_PB_STOP].ready()) {
EVLOG_error << "Could not initialize Connector 1 push button";
return false;
}
}
if (push_buttons[CONN2_PB_STOP].get_enabled()) {
Everest::GpioSettings settings;
settings.chip_name = verso_config.conf.conn2_gpio_stop_button_bank;
settings.line_number = verso_config.conf.conn2_gpio_stop_button_pin;
settings.inverted = verso_config.conf.conn2_gpio_stop_button_invert;
push_buttons[CONN2_PB_STOP].init_gpio(settings);
if (not push_buttons[CONN2_PB_STOP].ready()) {
EVLOG_error << "Could not initialize Connector 2 push button";
return false;
}
}
return true;
}
void evGpio::run() {
poll_thread_handle = std::thread(&evGpio::poll_thread, this);
}
void evGpio::poll_thread() {
while (true) {
if (poll_thread_handle.shouldExit())
break;
// iterate over button list
for (int i = 0; i < NUM_PB_NAMES; i++) {
PushButton& button = push_buttons[i];
if (not button.get_enabled())
continue;
// check if GPIO is still usable
if (not button.ready()) {
EVLOG_error << fmt::format("Push button {} not ready. Stopping thread.", i + 1);
goto cleanup; // break out of polling loop immediatly and terminate thread
}
button.read();
if (button.get_state_changed()) {
// select which signal to send depending on button name
switch (i) {
case CONN1_PB_STOP:
signal_stop_button_state(1, button.get_state());
break;
case CONN2_PB_STOP:
signal_stop_button_state(2, button.get_state());
break;
default:
break;
}
}
}
// sleep the nominal polling interval time
std::this_thread::sleep_for(std::chrono::milliseconds(poll_time_ms));
}
cleanup : {}
}

View File

@@ -0,0 +1,103 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PHYVERSO_GPIO_EV_GPIO_H
#define PHYVERSO_GPIO_EV_GPIO_H
#include "evConfig.h"
#include <atomic>
#include <chrono>
#include <everest/gpio/gpio.hpp>
#include <sigslot/signal.hpp>
#include <stdexcept>
#include <stdint.h>
#include <utility>
#include <utils/thread.hpp>
class evGpio {
public:
evGpio(evConfig& _verso_config);
~evGpio();
void poll_thread();
void run();
bool init_gpios();
// Read thread for serial port
Everest::Thread poll_thread_handle;
// Signals to communicate state changes to other modules
sigslot::signal<int, bool> signal_stop_button_state;
// List of used buttons/gpios
enum PushButtonName {
CONN1_PB_STOP,
CONN2_PB_STOP,
NUM_PB_NAMES,
};
private:
static constexpr uint32_t poll_time_ms = 10; //< time in ms between polled gpio input readings/debouncing
// structure to encapsulate Everest::Gpio and corresponding debounce shift register
// for now we will use 16 consecutive 0's or 1's to correspond to a stable input level (could be 8/32/64 aswell,
// just needs adjusting in bitmasks and bitwidths)
struct PushButton {
void init_gpio(const Everest::GpioSettings& settings) {
gpio.open(settings);
gpio.set_input();
};
bool ready() {
return gpio.is_ready();
};
void read() {
debounce_shift_reg = (debounce_shift_reg << 1) | gpio.read();
switch (debounce_shift_reg) {
case 0xFFFF:
state = true;
break;
case 0x0000:
state = false;
break;
default:
break;
}
state_changed = (last_state != state);
last_state = state;
};
bool get_state() {
return state;
};
bool get_state_changed() {
return state_changed;
};
void set_enabled(bool _enabled) {
enabled = _enabled;
};
bool get_enabled() {
return enabled;
};
private:
Everest::Gpio gpio;
bool state, last_state, state_changed = false;
bool enabled = false;
uint16_t debounce_shift_reg = 0;
};
PushButton push_buttons[NUM_PB_NAMES];
// config bridge (filled by json or everest module config)
evConfig& verso_config;
};
#endif // PHYVERSO_GPIO_EV_GPIO_H

View File

@@ -0,0 +1,48 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
cc_library(
name = "phyverso_config",
deps = [
"//lib/3rd_party/nanopb",
"//lib/everest/framework:framework",
],
srcs = glob([
"protobuf/*.h",
"protobuf/*.c",
]) + [
"evConfig.h",
"evConfig.cpp"
],
visibility = ["//visibility:public"],
includes = [
".",
"protobuf",
],
)
cc_library(
name = "phyverso_mcu_comms",
deps = [
":phyverso_config",
"//lib/3rd_party/nanopb",
"@com_github_HowardHinnant_date//:date",
"//lib/everest/framework:framework",
"@sigslot//:sigslot",
],
srcs = glob([
"**/*.h",
"**/*.c",
"**/*.cpp",
],
exclude = [
"evConfig.h",
"evConfig.cpp",
]),
visibility = ["//visibility:public"],
includes = [
".",
"protobuf",
"bsl",
],
copts = ["-std=c++17"],
)

View File

@@ -0,0 +1,55 @@
cmake_minimum_required(VERSION 3.10)
# set the project name
project(phyverso_mcu_comms VERSION 0.1)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_library(phyverso_config STATIC)
ev_register_library_target(phyverso_config)
target_sources(phyverso_config
PRIVATE
evConfig.cpp
)
target_include_directories(phyverso_config
PUBLIC
"${PROJECT_BINARY_DIR}"
protobuf
)
target_link_libraries(phyverso_config
PRIVATE
everest::nanopb
nlohmann_json::nlohmann_json
fmt::fmt
)
add_library(phyverso_mcu_comms STATIC)
ev_register_library_target(phyverso_mcu_comms)
target_sources(phyverso_mcu_comms
PRIVATE
evSerial.cpp
protobuf/phyverso.pb.c
bsl/bsl_gpio.cpp
)
target_include_directories(phyverso_mcu_comms
PUBLIC
"${PROJECT_BINARY_DIR}"
protobuf
bsl
)
target_link_libraries(phyverso_mcu_comms
PUBLIC
date::date-tz
everest::nanopb
PRIVATE
Pal::Sigslot
everest::framework
phyverso_config
)

View File

@@ -0,0 +1,68 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "bsl_gpio.h"
#include <chrono>
#include <iostream>
#include <thread>
BSL_GPIO::BSL_GPIO(_gpio_def _bsl, _gpio_def _reset) : bsl_out(_bsl), reset_out(_reset) {
}
bool BSL_GPIO::hard_reset(uint16_t ms_reset_time) {
bool status = set_pin(reset_out, true);
if (!status) {
printf("Could set reset active\n");
return status;
}
std::this_thread::sleep_for(std::chrono::milliseconds(ms_reset_time));
status = set_pin(reset_out, false);
if (!status) {
printf("Could set reset inactive\n");
return status;
}
return status;
}
bool BSL_GPIO::enter_bsl() {
bool status = set_pin(bsl_out, true);
if (!status) {
printf("Could not set BSL pin high\n");
return status;
}
std::this_thread::sleep_for(std::chrono::milliseconds(ms_bsl_out_settle));
status = hard_reset();
if (!status) {
printf("Could not reset\n");
return status;
}
std::this_thread::sleep_for(std::chrono::milliseconds(ms_bsl_out_settle));
status = set_pin(bsl_out, false);
if (!status) {
printf("Could not set BSL pin low\n");
return status;
}
return status;
}
bool BSL_GPIO::set_pin(_gpio_def gpio, bool level) {
char* cmd;
int size = asprintf(&cmd, "gpioset %d %d=%d", gpio.bank, gpio.pin, (level ? 1 : 0));
if ((size == -1) || (!cmd)) {
return false;
}
// printf("%s\n", cmd); // debug
int status = system(cmd);
free(cmd);
if (status == 0) {
return true;
} else {
return false;
}
}

View File

@@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PHYVERSO_MCU_COMMS_BSL_BSL_GPIO_H
#define PHYVERSO_MCU_COMMS_BSL_BSL_GPIO_H
#include <cstdint>
class BSL_GPIO {
public:
struct _gpio_def {
uint8_t bank;
uint8_t pin;
};
BSL_GPIO(_gpio_def _bsl = {.bank = 1, .pin = 12}, _gpio_def _reset = {.bank = 1, .pin = 23});
bool hard_reset(uint16_t ms_reset_time = default_ms_reset_time);
bool enter_bsl();
private:
bool set_pin(_gpio_def gpio, bool level);
static constexpr uint16_t default_ms_reset_time = 10;
static constexpr uint16_t ms_bsl_out_settle = 10;
// should be changeable later by loading a conf file
_gpio_def bsl_out;
_gpio_def reset_out;
};
#endif // PHYVERSO_MCU_COMMS_BSL_BSL_GPIO_H

View File

@@ -0,0 +1,108 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "evConfig.h"
#include "phyverso.pb.h"
#include <fmt/core.h>
#include <fstream>
#include <iostream>
// for convenience
using json = nlohmann::json;
evConfig::evConfig() {
}
evConfig::~evConfig() {
}
bool evConfig::open_file(std::string path) {
try {
std::ifstream f(path);
config_file = json::parse(f);
return true;
} catch (const std::exception& e) {
std::cerr << "error: " << e.what() << std::endl;
} catch (...) {
std::cerr << "Exception of unknown type!" << std::endl;
}
return false;
}
// unused for now
bool evConfig::read_hw_eeprom(ConfigHardwareRevision& hw_rev) {
// TODO: read eeprom on new phyVERSO hw revisions,
// for now return hardcoded value
hw_rev = ConfigHardwareRevision_HW_REV_A;
return true;
}
void evConfig::fill_config_packet() {
config_packet.which_payload = EverestToMcu_config_response_tag;
config_packet.connector = 0;
read_hw_eeprom(config_packet.payload.config_response.hw_rev);
/* fill port 1 config */
{
auto& chargeport_config = config_packet.payload.config_response.chargeport_config[0];
chargeport_config.has_lock = true;
chargeport_config.lock.type = static_cast<MotorLockType>(conf.conn1_motor_lock_type);
chargeport_config.feedback_active_low = conf.conn1_feedback_active_low;
chargeport_config.feedback_pull = static_cast<GpioPull>(conf.conn1_feedback_pull);
chargeport_config.has_socket = conf.conn1_has_socket;
if (conf.conn1_disable_port) {
chargeport_config.type = ChargePortType_DISABLED;
} else if (conf.conn1_dc) {
chargeport_config.type = ChargePortType_DC;
} else {
chargeport_config.type = ChargePortType_AC;
}
}
/* fill port 2 config */
{
auto& chargeport_config = config_packet.payload.config_response.chargeport_config[1];
chargeport_config.has_lock = true;
chargeport_config.lock.type = static_cast<MotorLockType>(conf.conn2_motor_lock_type);
chargeport_config.feedback_active_low = conf.conn2_feedback_active_low;
chargeport_config.feedback_pull = static_cast<GpioPull>(conf.conn2_feedback_pull);
chargeport_config.has_socket = conf.conn2_has_socket;
if (conf.conn2_disable_port) {
chargeport_config.type = ChargePortType_DISABLED;
} else if (conf.conn2_dc) {
chargeport_config.type = ChargePortType_DC;
} else {
chargeport_config.type = ChargePortType_AC;
}
}
}
EverestToMcu evConfig::get_config_packet() {
fill_config_packet();
return config_packet;
}
// keep in mind, json config is only used for testing via phyverso_cli
void evConfig::json_conf_to_evConfig() {
// try and get value from json file or keep default values as is
conf.conn1_motor_lock_type = config_file.value("conn1_motor_lock_type", conf.conn1_motor_lock_type);
conf.conn2_motor_lock_type = config_file.value("conn2_motor_lock_type", conf.conn2_motor_lock_type);
conf.reset_gpio_bank = config_file.value("reset_gpio_bank", conf.reset_gpio_bank);
conf.reset_gpio_pin = config_file.value("reset_gpio_pin", conf.reset_gpio_pin);
conf.conn1_disable_port = config_file.value("conn1_disable_port", conf.conn1_disable_port);
conf.conn2_disable_port = config_file.value("conn2_disable_port", conf.conn2_disable_port);
conf.conn1_feedback_active_low = config_file.value("conn1_feedback_active_low", conf.conn1_feedback_active_low);
conf.conn2_feedback_active_low = config_file.value("conn2_feedback_active_low", conf.conn2_feedback_active_low);
conf.conn1_feedback_pull = config_file.value("conn1_feedback_pull", conf.conn1_feedback_pull);
conf.conn2_feedback_pull = config_file.value("conn2_feedback_pull", conf.conn2_feedback_pull);
conf.conn1_dc = config_file.value("conn1_dc", conf.conn1_dc);
conf.conn2_dc = config_file.value("conn2_dc", conf.conn2_dc);
conf.conn1_disable_port = config_file.value("conn1_disable_port", conf.conn1_disable_port);
conf.conn2_disable_port = config_file.value("conn2_disable_port", conf.conn2_disable_port);
conf.conn1_has_socket = config_file.value("conn1_has_socket", conf.conn1_has_socket);
conf.conn2_has_socket = config_file.value("conn2_has_socket", conf.conn2_has_socket);
}

View File

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PHYVERSO_CONFIG_EV_CONFIG_HPP
#define PHYVERSO_CONFIG_EV_CONFIG_HPP
#include "phyverso.pb.h"
#include <nlohmann/json.hpp>
#include <string>
using json = nlohmann::json;
class evConfig {
public:
// same structure as in PhyVersoBSP, gets filled either by json parsing config file for phyverso_cli
// or gets overwritten with PhyVersoBSP everest module config
// changes in manifest have to be fixed here manually
struct Conf {
std::string serial_port = "/dev/ttyUSB0";
int baud_rate = 115200;
int reset_gpio = -1;
int conn1_max_current_A_import = 16;
int conn1_min_current_A_import = 6;
int conn1_min_phase_count_import = 3;
int conn1_max_phase_count_import = 3;
int conn1_min_current_A_export = 0;
int conn1_max_current_A_export = 0;
int conn1_min_phase_count_export = 3;
int conn1_max_phase_count_export = 3;
bool conn1_has_socket = false;
bool conn1_dc = false;
int conn2_max_current_A_import = 16;
int conn2_min_current_A_import = 6;
int conn2_min_phase_count_import = 3;
int conn2_max_phase_count_import = 3;
int conn2_min_current_A_export = 0;
int conn2_max_current_A_export = 0;
int conn2_min_phase_count_export = 3;
int conn2_max_phase_count_export = 3;
bool conn2_has_socket = false;
bool conn2_dc = false;
int reset_gpio_bank = 1;
int reset_gpio_pin = 23;
int conn1_motor_lock_type = -1;
int conn2_motor_lock_type = -1;
bool conn1_gpio_stop_button_enabled = false;
std::string conn1_gpio_stop_button_bank = "gpiochip1";
int conn1_gpio_stop_button_pin = 36;
bool conn1_gpio_stop_button_invert = false;
bool conn2_gpio_stop_button_enabled = false;
std::string conn2_gpio_stop_button_bank = "gpiochip1";
int conn2_gpio_stop_button_pin = 37;
bool conn2_gpio_stop_button_invert = false;
bool conn1_disable_port = false;
bool conn2_disable_port = false;
bool conn1_feedback_active_low = true;
bool conn2_feedback_active_low = true;
int conn1_feedback_pull = 2;
int conn2_feedback_pull = 2;
} conf;
evConfig();
~evConfig();
bool open_file(std::string path);
EverestToMcu get_config_packet();
void json_conf_to_evConfig();
private:
bool check_validity();
bool read_hw_eeprom(ConfigHardwareRevision& hw_rev);
void fill_config_packet();
json config_file;
EverestToMcu config_packet = EverestToMcu_init_default;
};
#endif // PHYVERSO_CONFIG_EV_CONFIG_HPP

View File

@@ -0,0 +1,450 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "evSerial.h"
#include <cerrno>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <thread>
#include <fcntl.h>
#include <unistd.h>
#include <date/date.h>
#include <date/tz.h>
#include <everest/3rd_party/nanopb/pb_decode.h>
#include <everest/3rd_party/nanopb/pb_encode.h>
#include <everest/logging.hpp>
#include "phyverso.pb.h"
#include "bsl_gpio.h"
evSerial::evSerial(evConfig& _verso_config) :
fd(0), baud(0), reset_done_flag(false), forced_reset(false), verso_config(_verso_config) {
cobs_decode_reset();
}
evSerial::~evSerial() {
if (fd) {
close(fd);
}
}
bool evSerial::open_device(const char* device, int _baud) {
fd = open(device, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("Serial: error %d opening %s: %s\n", errno, device, strerror(errno));
return false;
} // else printf ("Serial: opened %s as %i\n", device, fd);
cobs_decode_reset();
switch (_baud) {
case 9600:
baud = B9600;
break;
case 19200:
baud = B19200;
break;
case 38400:
baud = B38400;
break;
case 57600:
baud = B57600;
break;
case 115200:
baud = B115200;
break;
case 230400:
baud = B230400;
break;
default:
baud = 0;
return false;
}
return set_serial_attributes();
}
void evSerial::flush_buffers() {
tcflush(fd, TCIOFLUSH);
}
bool evSerial::set_serial_attributes() {
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
printf("Serial: error %d from tcgetattr\n", errno);
return false;
}
cfsetospeed(&tty, baud);
cfsetispeed(&tty, baud);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read blocks
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Serial: error %d from tcsetattr\n", errno);
return false;
}
return true;
}
void evSerial::cobs_decode_reset() {
code = 0xff;
block = 0;
decode = msg;
}
uint32_t evSerial::crc32(uint8_t* buf, int len) {
int i, j;
uint32_t b, crc, msk;
i = 0;
crc = 0xFFFFFFFF;
while (i < len) {
b = buf[i];
crc = crc ^ b;
for (j = 7; j >= 0; j--) {
msk = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & msk);
}
i = i + 1;
}
return crc;
}
void evSerial::handle_packet(uint8_t* buf, int len) {
if (crc32(buf, len)) {
printf("CRC mismatch\n");
return;
}
len -= 4;
if (handle_McuToEverest_packet(buf, len))
return;
else
printf("Cannot handle a packet");
}
bool evSerial::handle_McuToEverest_packet(uint8_t* buf, int len) {
McuToEverest msg_in;
pb_istream_t istream = pb_istream_from_buffer(buf, len);
if (!pb_decode(&istream, McuToEverest_fields, &msg_in))
return false;
switch (msg_in.which_payload) {
case McuToEverest_keep_alive_tag:
signal_keep_alive(msg_in.payload.keep_alive);
last_keep_alive_lo_timestamp = date::utc_clock::now();
break;
case McuToEverest_cp_state_tag:
signal_cp_state(msg_in.connector, msg_in.payload.cp_state);
break;
case McuToEverest_set_coil_state_response_tag:
signal_set_coil_state_response(msg_in.connector, msg_in.payload.set_coil_state_response);
break;
case McuToEverest_error_flags_tag:
signal_error_flags(msg_in.connector, msg_in.payload.error_flags);
break;
case McuToEverest_telemetry_tag:
signal_telemetry(msg_in.connector, msg_in.payload.telemetry);
break;
case McuToEverest_reset_tag:
reset_done_flag = true;
if (!forced_reset)
signal_spurious_reset(msg_in.payload.reset);
break;
case McuToEverest_pp_state_tag:
signal_pp_state(msg_in.connector, msg_in.payload.pp_state);
break;
case McuToEverest_fan_state_tag:
signal_fan_state(msg_in.payload.fan_state);
break;
case McuToEverest_lock_state_tag:
signal_lock_state(msg_in.connector, msg_in.payload.lock_state);
break;
case McuToEverest_config_request_tag:
signal_config_request();
break;
}
return true;
}
void evSerial::cobs_decode(uint8_t* buf, int len) {
for (int i = 0; i < len; i++)
cobs_decode_byte(buf[i]);
}
void evSerial::cobs_decode_byte(uint8_t byte) {
// check max length
if ((decode - msg == 2048 - 1) && byte != 0x00) {
printf("cobsDecode: Buffer overflow\n");
cobs_decode_reset();
}
if (block) {
// we're currently decoding and should not get a 0
if (byte == 0x00) {
// probably found some garbage -> reset
printf("cobsDecode: Garbage detected\n");
cobs_decode_reset();
return;
}
*decode++ = byte;
} else {
if (code != 0xff) {
*decode++ = 0;
}
block = code = byte;
if (code == 0x00) {
// we're finished, reset everything and commit
if (decode == msg) {
// we received nothing, just a 0x00
printf("cobsDecode: Received nothing\n");
} else {
// set back decode with one, as it gets post-incremented
handle_packet(msg, decode - 1 - msg);
}
cobs_decode_reset();
return; // need to return here, because of block--
}
}
block--;
}
void evSerial::run() {
read_thread_handle = std::thread(&evSerial::read_thread, this);
timeout_detection_thread_handle = std::thread(&evSerial::timeout_detection_thread, this);
last_keep_alive_lo_timestamp = date::utc_clock::now();
}
void evSerial::timeout_detection_thread() {
while (true) {
sleep(1);
if (timeout_detection_thread_handle.shouldExit())
break;
if (serial_timed_out())
signal_connection_timeout();
// send keep alive
keep_alive();
}
}
void evSerial::read_thread() {
uint8_t buf[2048];
int n;
cobs_decode_reset();
while (true) {
if (read_thread_handle.shouldExit())
break;
if (fd > 0) {
n = read(fd, buf, sizeof buf);
cobs_decode(buf, n);
}
}
}
bool evSerial::link_write(EverestToMcu* m) {
if (fd <= 0) {
return false;
}
uint8_t tx_packet_buf[1024];
uint8_t encode_buf[1500];
pb_ostream_t ostream = pb_ostream_from_buffer(tx_packet_buf, sizeof(tx_packet_buf) - 4);
bool status = pb_encode(&ostream, EverestToMcu_fields, m);
if (!status) {
// couldn't encode
return false;
}
size_t tx_payload_len = ostream.bytes_written;
// add crc32 (CRC-32/JAMCRC)
uint32_t crc = crc32(tx_packet_buf, tx_payload_len);
for (int byte_pos = 0; byte_pos < 4; ++byte_pos) {
tx_packet_buf[tx_payload_len] = (uint8_t)crc & 0xFF;
crc = crc >> 8;
tx_payload_len++;
}
size_t tx_encode_len = cobs_encode(tx_packet_buf, tx_payload_len, encode_buf);
write(fd, encode_buf, tx_encode_len);
return true;
}
size_t evSerial::cobs_encode(const void* data, size_t length, uint8_t* buffer) {
uint8_t* encode = buffer; // Encoded byte pointer
uint8_t* codep = encode++; // Output code pointer
uint8_t code = 1; // Code value
for (const uint8_t* byte = (const uint8_t*)data; length--; ++byte) {
if (*byte) // Byte not zero, write it
*encode++ = *byte, ++code;
if (!*byte || code == 0xff) // Input is zero or block completed, restart
{
*codep = code, code = 1, codep = encode;
if (!*byte || length)
++encode;
}
}
*codep = code; // Write final code value
// add final 0
*encode++ = 0x00;
return encode - buffer;
}
bool evSerial::serial_timed_out() {
auto now = date::utc_clock::now();
auto time_since_last_keep_alive =
std::chrono::duration_cast<std::chrono::milliseconds>(now - last_keep_alive_lo_timestamp).count();
if (time_since_last_keep_alive >= 5000)
return true;
return false;
}
void evSerial::set_pwm(int target_connector, uint32_t duty_cycle_e2) {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_pwm_duty_cycle_tag;
msg_out.payload.pwm_duty_cycle = duty_cycle_e2;
msg_out.connector = target_connector;
link_write(&msg_out);
}
void evSerial::set_coil_state_request(int target_connector, CoilType type, bool power_on) {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_set_coil_state_request_tag;
msg_out.payload.set_coil_state_request.coil_type = type;
msg_out.payload.set_coil_state_request.coil_state = power_on;
msg_out.connector = target_connector;
link_write(&msg_out);
}
void evSerial::lock(int target_connector, bool _lock) {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_connector_lock_tag;
msg_out.payload.connector_lock = _lock;
msg_out.connector = target_connector;
link_write(&msg_out);
}
void evSerial::firmware_update() {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_firmware_update_tag;
msg_out.connector = 0;
link_write(&msg_out);
}
bool evSerial::reset(const int reset_pin) {
reset_done_flag = false;
forced_reset = true;
if (reset_pin > 0) {
EVLOG_info << "Hard-resetting PhyVerso";
auto bsl_gpio = BSL_GPIO({.bank = 1, .pin = 12}, // BSL pins are unused here so keep defaults
{.bank = static_cast<uint8_t>(verso_config.conf.reset_gpio_bank),
.pin = static_cast<uint8_t>(verso_config.conf.reset_gpio_pin)});
bsl_gpio.hard_reset(25);
} else {
// Try to soft reset phyVERSO controller to be in a known state
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_reset_tag;
msg_out.connector = 0;
link_write(&msg_out);
}
bool success = true;
// send some dummy packets to resync COBS etc.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
cobs_decode_reset();
keep_alive();
keep_alive();
keep_alive();
return success;
}
void evSerial::keep_alive() {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_keep_alive_tag;
msg_out.payload.keep_alive.time_stamp = 0;
msg_out.payload.keep_alive.hw_type = 0;
msg_out.payload.keep_alive.hw_revision = 0;
strcpy(msg_out.payload.keep_alive.sw_version_string, "n/a");
msg_out.connector = 0;
link_write(&msg_out);
}
void evSerial::send_config() {
EverestToMcu config_packet = verso_config.get_config_packet();
link_write(&config_packet);
}
void evSerial::set_fan_state(uint8_t fan_id, bool enabled, uint32_t duty) {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_set_fan_state_tag;
msg_out.payload.set_fan_state.fan_id = fan_id;
msg_out.payload.set_fan_state.enabled = enabled;
msg_out.payload.set_fan_state.duty = duty;
msg_out.connector = 0;
link_write(&msg_out);
}
void evSerial::set_rcd_test(int target_connector, bool _test) {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_rcd_cmd_tag;
msg_out.payload.rcd_cmd.test = _test;
msg_out.payload.rcd_cmd.reset = false;
msg_out.connector = target_connector;
link_write(&msg_out);
}
void evSerial::reset_rcd(int target_connector, bool _reset) {
EverestToMcu msg_out = EverestToMcu_init_default;
msg_out.which_payload = EverestToMcu_rcd_cmd_tag;
msg_out.payload.rcd_cmd.test = false;
msg_out.payload.rcd_cmd.reset = _reset;
msg_out.connector = target_connector;
link_write(&msg_out);
}

View File

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PHYVERSO_MCU_COMMS_EV_SERIAL_H
#define PHYVERSO_MCU_COMMS_EV_SERIAL_H
#include "evConfig.h"
#include "phyverso.pb.h"
#include <atomic>
#include <chrono>
#include <date/date.h>
#include <date/tz.h>
#include <sigslot/signal.hpp>
#include <stdexcept>
#include <stdint.h>
#include <termios.h>
#include <utility>
#include <utils/thread.hpp>
#include <vector>
class evSerial {
public:
evSerial(evConfig& _verso_config);
~evSerial();
bool open_device(const char* device, int baud);
bool is_open() {
return fd > 0;
};
void flush_buffers();
void read_thread();
void run();
bool reset(const int reset_pin);
void firmware_update();
void keep_alive();
void set_pwm(int target_connector, uint32_t duty_cycle_e2);
void set_coil_state_request(int target_connector, CoilType type, bool power_on);
void lock(int target_connector, bool _lock);
void unlock(int target_connector);
void set_fan_state(uint8_t fan_id, bool enabled, uint32_t duty);
void set_rcd_test(int target_connector, bool _test);
void reset_rcd(int target_connector, bool _reset);
void send_config();
sigslot::signal<KeepAlive> signal_keep_alive;
sigslot::signal<int, CpState> signal_cp_state;
sigslot::signal<int, CoilState> signal_set_coil_state_response;
sigslot::signal<int, ErrorFlags> signal_error_flags;
sigslot::signal<int, Telemetry> signal_telemetry;
sigslot::signal<ResetReason> signal_spurious_reset;
sigslot::signal<> signal_connection_timeout;
sigslot::signal<int, PpState> signal_pp_state;
sigslot::signal<FanState> signal_fan_state;
sigslot::signal<int, LockState> signal_lock_state;
sigslot::signal<> signal_config_request;
private:
// Serial interface
bool set_serial_attributes();
int fd;
int baud;
// COBS de-/encoder
void cobs_decode_reset();
void handle_packet(uint8_t* buf, int len);
bool handle_McuToEverest_packet(uint8_t* buf, int len);
void cobs_decode(uint8_t* buf, int len);
void cobs_decode_byte(uint8_t byte);
size_t cobs_encode(const void* data, size_t length, uint8_t* buffer);
uint8_t msg[2048];
uint8_t code;
uint8_t block;
uint8_t* decode;
uint32_t crc32(uint8_t* buf, int len);
// Read thread for serial port
Everest::Thread read_thread_handle;
Everest::Thread timeout_detection_thread_handle;
bool link_write(EverestToMcu* m);
std::atomic_bool reset_done_flag;
std::atomic_bool forced_reset;
bool serial_timed_out();
void timeout_detection_thread();
std::chrono::time_point<date::utc_clock> last_keep_alive_lo_timestamp;
// config bridge (filled by json or everest module config)
evConfig& verso_config;
};
#endif // PHYVERSO_MCU_COMMS_EV_SERIAL_H

View File

@@ -0,0 +1,2 @@
#!/bin/sh
nanopb_generator -L "#include <everest/3rd_party/nanopb/%s>" -I . -D . phyverso.proto

View File

@@ -0,0 +1,5 @@
KeepAlive.sw_version_string max_length:50
FanState.fan_id int_size:IS_8
FanState.rpm int_size:IS_16
BootConfigResponse.chargeport_config max_count:2
BootConfigResponse.chargeport_config fixed_count:true

View File

@@ -0,0 +1,54 @@
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.8 */
#include "phyverso.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
PB_BIND(EverestToMcu, EverestToMcu, AUTO)
PB_BIND(McuToEverest, McuToEverest, AUTO)
PB_BIND(ErrorFlags, ErrorFlags, AUTO)
PB_BIND(KeepAlive, KeepAlive, AUTO)
PB_BIND(Telemetry, Telemetry, AUTO)
PB_BIND(FanState, FanState, AUTO)
PB_BIND(CoilState, CoilState, AUTO)
PB_BIND(BootConfigRequest, BootConfigRequest, AUTO)
PB_BIND(BootConfigResponse, BootConfigResponse, AUTO)
PB_BIND(ChargePortConfig, ChargePortConfig, AUTO)
PB_BIND(ConfigMotorLockType, ConfigMotorLockType, AUTO)
PB_BIND(RcdCommand, RcdCommand, AUTO)

View File

@@ -0,0 +1,487 @@
/* Automatically generated nanopb header */
/* Generated by nanopb-0.4.8 */
#ifndef PB_PHYVERSO_PB_H_INCLUDED
#define PB_PHYVERSO_PB_H_INCLUDED
#include <everest/3rd_party/nanopb/pb.h>
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
#endif
/* Enum definitions */
typedef enum _CpState {
CpState_STATE_A = 0,
CpState_STATE_B = 1,
CpState_STATE_C = 2,
CpState_STATE_D = 3,
CpState_STATE_E = 4,
CpState_STATE_F = 5
} CpState;
typedef enum _ResetReason {
ResetReason_USER = 0,
ResetReason_WATCHDOG = 1
} ResetReason;
typedef enum _PpState {
PpState_STATE_NC = 0,
PpState_STATE_13A = 1,
PpState_STATE_20A = 2,
PpState_STATE_32A = 3,
PpState_STATE_70A = 4,
PpState_STATE_FAULT = 5
} PpState;
typedef enum _LockState {
LockState_UNDEFINED = 0,
LockState_UNLOCKED = 1,
LockState_LOCKED = 2,
LockState_LOCKING = 3,
LockState_UNLOCKING = 4
} LockState;
typedef enum _CoilType {
CoilType_COIL_UNKNOWN = 0,
CoilType_COIL_AC = 1,
CoilType_COIL_DC1 = 2,
/* add precharge and discharge coils here later */
CoilType_COIL_DC2 = 3,
CoilType_COIL_DC3 = 4
} CoilType;
typedef enum _ChargePortType {
ChargePortType_DISABLED = 0,
ChargePortType_AC = 1,
ChargePortType_DC = 2
} ChargePortType;
typedef enum _GpioPull {
GpioPull_NONE = 0,
GpioPull_UP = 1,
GpioPull_DOWN = 2
} GpioPull;
typedef enum _ConfigHardwareRevision {
ConfigHardwareRevision_HW_REV_UNKNOWN = 0,
ConfigHardwareRevision_HW_REV_A = 1,
ConfigHardwareRevision_HW_REV_B = 2
} ConfigHardwareRevision;
typedef enum _MotorLockType {
MotorLockType_MOTOR_LOCK_UNKNOWN = 0,
MotorLockType_MOTOR_LOCK_HELLA = 1,
MotorLockType_MOTOR_LOCK_DEBUG_VALEO_HVAC = 2,
/* add additional locks here */
MotorLockType_MOTOR_LOCK_NONE = -1
} MotorLockType;
/* Struct definitions */
typedef struct _ErrorFlags {
bool diode_fault;
bool rcd_selftest_failed;
bool rcd_triggered;
bool ventilation_not_available;
bool connector_lock_failed;
bool cp_signal_fault;
bool heartbeat_timeout;
bool coil_feedback_diverges;
bool pp_signal_fault;
} ErrorFlags;
typedef struct _KeepAlive {
uint32_t time_stamp;
uint32_t hw_type;
uint32_t hw_revision;
char sw_version_string[51];
bool configuration_done;
} KeepAlive;
typedef struct _Telemetry {
uint32_t cp_voltage_hi;
uint32_t cp_voltage_lo;
} Telemetry;
typedef struct _FanState {
uint8_t fan_id;
bool enabled;
uint32_t duty; /* in 0.1%, 1000 = 100% */
uint16_t rpm;
} FanState;
typedef struct _CoilState {
CoilType coil_type;
bool coil_state; /* true -> on; false -> off */
} CoilState;
typedef struct _BootConfigRequest { /* TODO */
char dummy_field;
} BootConfigRequest;
/* This container message is send from MCU to EVerest and may contain any allowed message in that direction. */
typedef struct _McuToEverest {
pb_size_t which_payload;
union {
KeepAlive keep_alive;
ResetReason reset;
CpState cp_state;
CoilState set_coil_state_response;
ErrorFlags error_flags;
Telemetry telemetry;
PpState pp_state;
FanState fan_state;
LockState lock_state;
BootConfigRequest config_request;
} payload;
int32_t connector; /* 0: None, 1: Connector 1, 2: Connector 2 */
} McuToEverest;
typedef struct _ConfigMotorLockType {
MotorLockType type; /* additional lock specific options could be added here later
will still keep this in place even if it only holds the type enum at the moment */
} ConfigMotorLockType;
typedef struct _ChargePortConfig {
ChargePortType type;
bool feedback_active_low;
GpioPull feedback_pull;
bool has_lock;
ConfigMotorLockType lock;
bool has_socket;
} ChargePortConfig;
typedef struct _BootConfigResponse {
ConfigHardwareRevision hw_rev;
ChargePortConfig chargeport_config[2];
} BootConfigResponse;
typedef struct _RcdCommand {
bool test; /* true -> set TEST pin high, false -> set TEST pin low */
bool reset; /* reset RCD/emergency off if set to true */
} RcdCommand;
/* This container message is send from EVerest to MCU and may contain any allowed message in that direction. */
typedef struct _EverestToMcu {
pb_size_t which_payload;
union {
KeepAlive keep_alive;
bool firmware_update;
bool connector_lock; /* false: unlock, true: lock */
uint32_t pwm_duty_cycle; /* in 0.01 %, 0 = State F, 10000 = X1 */
CoilState set_coil_state_request;
bool reset;
BootConfigResponse config_response;
FanState set_fan_state;
RcdCommand rcd_cmd;
} payload;
int32_t connector; /* 0: None, 1: Connector 1, 2: Connector 2 */
} EverestToMcu;
#ifdef __cplusplus
extern "C" {
#endif
/* Helper constants for enums */
#define _CpState_MIN CpState_STATE_A
#define _CpState_MAX CpState_STATE_F
#define _CpState_ARRAYSIZE ((CpState)(CpState_STATE_F+1))
#define _ResetReason_MIN ResetReason_USER
#define _ResetReason_MAX ResetReason_WATCHDOG
#define _ResetReason_ARRAYSIZE ((ResetReason)(ResetReason_WATCHDOG+1))
#define _PpState_MIN PpState_STATE_NC
#define _PpState_MAX PpState_STATE_FAULT
#define _PpState_ARRAYSIZE ((PpState)(PpState_STATE_FAULT+1))
#define _LockState_MIN LockState_UNDEFINED
#define _LockState_MAX LockState_UNLOCKING
#define _LockState_ARRAYSIZE ((LockState)(LockState_UNLOCKING+1))
#define _CoilType_MIN CoilType_COIL_UNKNOWN
#define _CoilType_MAX CoilType_COIL_DC3
#define _CoilType_ARRAYSIZE ((CoilType)(CoilType_COIL_DC3+1))
#define _ChargePortType_MIN ChargePortType_DISABLED
#define _ChargePortType_MAX ChargePortType_DC
#define _ChargePortType_ARRAYSIZE ((ChargePortType)(ChargePortType_DC+1))
#define _GpioPull_MIN GpioPull_NONE
#define _GpioPull_MAX GpioPull_DOWN
#define _GpioPull_ARRAYSIZE ((GpioPull)(GpioPull_DOWN+1))
#define _ConfigHardwareRevision_MIN ConfigHardwareRevision_HW_REV_UNKNOWN
#define _ConfigHardwareRevision_MAX ConfigHardwareRevision_HW_REV_B
#define _ConfigHardwareRevision_ARRAYSIZE ((ConfigHardwareRevision)(ConfigHardwareRevision_HW_REV_B+1))
#define _MotorLockType_MIN MotorLockType_MOTOR_LOCK_NONE
#define _MotorLockType_MAX MotorLockType_MOTOR_LOCK_DEBUG_VALEO_HVAC
#define _MotorLockType_ARRAYSIZE ((MotorLockType)(MotorLockType_MOTOR_LOCK_DEBUG_VALEO_HVAC+1))
#define McuToEverest_payload_reset_ENUMTYPE ResetReason
#define McuToEverest_payload_cp_state_ENUMTYPE CpState
#define McuToEverest_payload_pp_state_ENUMTYPE PpState
#define McuToEverest_payload_lock_state_ENUMTYPE LockState
#define CoilState_coil_type_ENUMTYPE CoilType
#define BootConfigResponse_hw_rev_ENUMTYPE ConfigHardwareRevision
#define ChargePortConfig_type_ENUMTYPE ChargePortType
#define ChargePortConfig_feedback_pull_ENUMTYPE GpioPull
#define ConfigMotorLockType_type_ENUMTYPE MotorLockType
/* Initializer values for message structs */
#define EverestToMcu_init_default {0, {KeepAlive_init_default}, 0}
#define McuToEverest_init_default {0, {KeepAlive_init_default}, 0}
#define ErrorFlags_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define KeepAlive_init_default {0, 0, 0, "", 0}
#define Telemetry_init_default {0, 0}
#define FanState_init_default {0, 0, 0, 0}
#define CoilState_init_default {_CoilType_MIN, 0}
#define BootConfigRequest_init_default {0}
#define BootConfigResponse_init_default {_ConfigHardwareRevision_MIN, {ChargePortConfig_init_default, ChargePortConfig_init_default}}
#define ChargePortConfig_init_default {_ChargePortType_MIN, 0, _GpioPull_MIN, false, ConfigMotorLockType_init_default, 0}
#define ConfigMotorLockType_init_default {_MotorLockType_MIN}
#define RcdCommand_init_default {0, 0}
#define EverestToMcu_init_zero {0, {KeepAlive_init_zero}, 0}
#define McuToEverest_init_zero {0, {KeepAlive_init_zero}, 0}
#define ErrorFlags_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define KeepAlive_init_zero {0, 0, 0, "", 0}
#define Telemetry_init_zero {0, 0}
#define FanState_init_zero {0, 0, 0, 0}
#define CoilState_init_zero {_CoilType_MIN, 0}
#define BootConfigRequest_init_zero {0}
#define BootConfigResponse_init_zero {_ConfigHardwareRevision_MIN, {ChargePortConfig_init_zero, ChargePortConfig_init_zero}}
#define ChargePortConfig_init_zero {_ChargePortType_MIN, 0, _GpioPull_MIN, false, ConfigMotorLockType_init_zero, 0}
#define ConfigMotorLockType_init_zero {_MotorLockType_MIN}
#define RcdCommand_init_zero {0, 0}
/* Field tags (for use in manual encoding/decoding) */
#define ErrorFlags_diode_fault_tag 1
#define ErrorFlags_rcd_selftest_failed_tag 2
#define ErrorFlags_rcd_triggered_tag 3
#define ErrorFlags_ventilation_not_available_tag 4
#define ErrorFlags_connector_lock_failed_tag 5
#define ErrorFlags_cp_signal_fault_tag 6
#define ErrorFlags_heartbeat_timeout_tag 7
#define ErrorFlags_coil_feedback_diverges_tag 8
#define ErrorFlags_pp_signal_fault_tag 9
#define KeepAlive_time_stamp_tag 1
#define KeepAlive_hw_type_tag 2
#define KeepAlive_hw_revision_tag 3
#define KeepAlive_sw_version_string_tag 6
#define KeepAlive_configuration_done_tag 7
#define Telemetry_cp_voltage_hi_tag 1
#define Telemetry_cp_voltage_lo_tag 2
#define FanState_fan_id_tag 1
#define FanState_enabled_tag 2
#define FanState_duty_tag 3
#define FanState_rpm_tag 4
#define CoilState_coil_type_tag 1
#define CoilState_coil_state_tag 2
#define McuToEverest_keep_alive_tag 1
#define McuToEverest_reset_tag 2
#define McuToEverest_cp_state_tag 3
#define McuToEverest_set_coil_state_response_tag 4
#define McuToEverest_error_flags_tag 5
#define McuToEverest_telemetry_tag 7
#define McuToEverest_pp_state_tag 8
#define McuToEverest_fan_state_tag 9
#define McuToEverest_lock_state_tag 10
#define McuToEverest_config_request_tag 11
#define McuToEverest_connector_tag 6
#define ConfigMotorLockType_type_tag 1
#define ChargePortConfig_type_tag 1
#define ChargePortConfig_feedback_active_low_tag 2
#define ChargePortConfig_feedback_pull_tag 3
#define ChargePortConfig_lock_tag 4
#define ChargePortConfig_has_socket_tag 5
#define BootConfigResponse_hw_rev_tag 1
#define BootConfigResponse_chargeport_config_tag 6
#define RcdCommand_test_tag 1
#define RcdCommand_reset_tag 2
#define EverestToMcu_keep_alive_tag 1
#define EverestToMcu_firmware_update_tag 2
#define EverestToMcu_connector_lock_tag 3
#define EverestToMcu_pwm_duty_cycle_tag 4
#define EverestToMcu_set_coil_state_request_tag 5
#define EverestToMcu_reset_tag 6
#define EverestToMcu_config_response_tag 8
#define EverestToMcu_set_fan_state_tag 9
#define EverestToMcu_rcd_cmd_tag 10
#define EverestToMcu_connector_tag 7
/* Struct field encoding specification for nanopb */
#define EverestToMcu_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 1) \
X(a, STATIC, ONEOF, BOOL, (payload,firmware_update,payload.firmware_update), 2) \
X(a, STATIC, ONEOF, BOOL, (payload,connector_lock,payload.connector_lock), 3) \
X(a, STATIC, ONEOF, UINT32, (payload,pwm_duty_cycle,payload.pwm_duty_cycle), 4) \
X(a, STATIC, ONEOF, MESSAGE, (payload,set_coil_state_request,payload.set_coil_state_request), 5) \
X(a, STATIC, ONEOF, BOOL, (payload,reset,payload.reset), 6) \
X(a, STATIC, SINGULAR, INT32, connector, 7) \
X(a, STATIC, ONEOF, MESSAGE, (payload,config_response,payload.config_response), 8) \
X(a, STATIC, ONEOF, MESSAGE, (payload,set_fan_state,payload.set_fan_state), 9) \
X(a, STATIC, ONEOF, MESSAGE, (payload,rcd_cmd,payload.rcd_cmd), 10)
#define EverestToMcu_CALLBACK NULL
#define EverestToMcu_DEFAULT NULL
#define EverestToMcu_payload_keep_alive_MSGTYPE KeepAlive
#define EverestToMcu_payload_set_coil_state_request_MSGTYPE CoilState
#define EverestToMcu_payload_config_response_MSGTYPE BootConfigResponse
#define EverestToMcu_payload_set_fan_state_MSGTYPE FanState
#define EverestToMcu_payload_rcd_cmd_MSGTYPE RcdCommand
#define McuToEverest_FIELDLIST(X, a) \
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 1) \
X(a, STATIC, ONEOF, UENUM, (payload,reset,payload.reset), 2) \
X(a, STATIC, ONEOF, UENUM, (payload,cp_state,payload.cp_state), 3) \
X(a, STATIC, ONEOF, MESSAGE, (payload,set_coil_state_response,payload.set_coil_state_response), 4) \
X(a, STATIC, ONEOF, MESSAGE, (payload,error_flags,payload.error_flags), 5) \
X(a, STATIC, SINGULAR, INT32, connector, 6) \
X(a, STATIC, ONEOF, MESSAGE, (payload,telemetry,payload.telemetry), 7) \
X(a, STATIC, ONEOF, UENUM, (payload,pp_state,payload.pp_state), 8) \
X(a, STATIC, ONEOF, MESSAGE, (payload,fan_state,payload.fan_state), 9) \
X(a, STATIC, ONEOF, UENUM, (payload,lock_state,payload.lock_state), 10) \
X(a, STATIC, ONEOF, MESSAGE, (payload,config_request,payload.config_request), 11)
#define McuToEverest_CALLBACK NULL
#define McuToEverest_DEFAULT NULL
#define McuToEverest_payload_keep_alive_MSGTYPE KeepAlive
#define McuToEverest_payload_set_coil_state_response_MSGTYPE CoilState
#define McuToEverest_payload_error_flags_MSGTYPE ErrorFlags
#define McuToEverest_payload_telemetry_MSGTYPE Telemetry
#define McuToEverest_payload_fan_state_MSGTYPE FanState
#define McuToEverest_payload_config_request_MSGTYPE BootConfigRequest
#define ErrorFlags_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, diode_fault, 1) \
X(a, STATIC, SINGULAR, BOOL, rcd_selftest_failed, 2) \
X(a, STATIC, SINGULAR, BOOL, rcd_triggered, 3) \
X(a, STATIC, SINGULAR, BOOL, ventilation_not_available, 4) \
X(a, STATIC, SINGULAR, BOOL, connector_lock_failed, 5) \
X(a, STATIC, SINGULAR, BOOL, cp_signal_fault, 6) \
X(a, STATIC, SINGULAR, BOOL, heartbeat_timeout, 7) \
X(a, STATIC, SINGULAR, BOOL, coil_feedback_diverges, 8) \
X(a, STATIC, SINGULAR, BOOL, pp_signal_fault, 9)
#define ErrorFlags_CALLBACK NULL
#define ErrorFlags_DEFAULT NULL
#define KeepAlive_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, time_stamp, 1) \
X(a, STATIC, SINGULAR, UINT32, hw_type, 2) \
X(a, STATIC, SINGULAR, UINT32, hw_revision, 3) \
X(a, STATIC, SINGULAR, STRING, sw_version_string, 6) \
X(a, STATIC, SINGULAR, BOOL, configuration_done, 7)
#define KeepAlive_CALLBACK NULL
#define KeepAlive_DEFAULT NULL
#define Telemetry_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, cp_voltage_hi, 1) \
X(a, STATIC, SINGULAR, UINT32, cp_voltage_lo, 2)
#define Telemetry_CALLBACK NULL
#define Telemetry_DEFAULT NULL
#define FanState_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, fan_id, 1) \
X(a, STATIC, SINGULAR, BOOL, enabled, 2) \
X(a, STATIC, SINGULAR, UINT32, duty, 3) \
X(a, STATIC, SINGULAR, UINT32, rpm, 4)
#define FanState_CALLBACK NULL
#define FanState_DEFAULT NULL
#define CoilState_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, coil_type, 1) \
X(a, STATIC, SINGULAR, BOOL, coil_state, 2)
#define CoilState_CALLBACK NULL
#define CoilState_DEFAULT NULL
#define BootConfigRequest_FIELDLIST(X, a) \
#define BootConfigRequest_CALLBACK NULL
#define BootConfigRequest_DEFAULT NULL
#define BootConfigResponse_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, hw_rev, 1) \
X(a, STATIC, FIXARRAY, MESSAGE, chargeport_config, 6)
#define BootConfigResponse_CALLBACK NULL
#define BootConfigResponse_DEFAULT NULL
#define BootConfigResponse_chargeport_config_MSGTYPE ChargePortConfig
#define ChargePortConfig_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, type, 1) \
X(a, STATIC, SINGULAR, BOOL, feedback_active_low, 2) \
X(a, STATIC, SINGULAR, UENUM, feedback_pull, 3) \
X(a, STATIC, OPTIONAL, MESSAGE, lock, 4) \
X(a, STATIC, SINGULAR, BOOL, has_socket, 5)
#define ChargePortConfig_CALLBACK NULL
#define ChargePortConfig_DEFAULT NULL
#define ChargePortConfig_lock_MSGTYPE ConfigMotorLockType
#define ConfigMotorLockType_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, ENUM, type, 1)
#define ConfigMotorLockType_CALLBACK NULL
#define ConfigMotorLockType_DEFAULT NULL
#define RcdCommand_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, BOOL, test, 1) \
X(a, STATIC, SINGULAR, BOOL, reset, 2)
#define RcdCommand_CALLBACK NULL
#define RcdCommand_DEFAULT NULL
extern const pb_msgdesc_t EverestToMcu_msg;
extern const pb_msgdesc_t McuToEverest_msg;
extern const pb_msgdesc_t ErrorFlags_msg;
extern const pb_msgdesc_t KeepAlive_msg;
extern const pb_msgdesc_t Telemetry_msg;
extern const pb_msgdesc_t FanState_msg;
extern const pb_msgdesc_t CoilState_msg;
extern const pb_msgdesc_t BootConfigRequest_msg;
extern const pb_msgdesc_t BootConfigResponse_msg;
extern const pb_msgdesc_t ChargePortConfig_msg;
extern const pb_msgdesc_t ConfigMotorLockType_msg;
extern const pb_msgdesc_t RcdCommand_msg;
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
#define EverestToMcu_fields &EverestToMcu_msg
#define McuToEverest_fields &McuToEverest_msg
#define ErrorFlags_fields &ErrorFlags_msg
#define KeepAlive_fields &KeepAlive_msg
#define Telemetry_fields &Telemetry_msg
#define FanState_fields &FanState_msg
#define CoilState_fields &CoilState_msg
#define BootConfigRequest_fields &BootConfigRequest_msg
#define BootConfigResponse_fields &BootConfigResponse_msg
#define ChargePortConfig_fields &ChargePortConfig_msg
#define ConfigMotorLockType_fields &ConfigMotorLockType_msg
#define RcdCommand_fields &RcdCommand_msg
/* Maximum encoded size of messages (where known) */
#define BootConfigRequest_size 0
#define BootConfigResponse_size 48
#define ChargePortConfig_size 21
#define CoilState_size 4
#define ConfigMotorLockType_size 11
#define ErrorFlags_size 18
#define EverestToMcu_size 85
#define FanState_size 15
#define KeepAlive_size 72
#define McuToEverest_size 85
#define PHYVERSO_PB_H_MAX_SIZE EverestToMcu_size
#define RcdCommand_size 4
#define Telemetry_size 12
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@@ -0,0 +1,169 @@
syntax = "proto3";
/*
This container message is send from EVerest to MCU and may contain any allowed message in that direction.
*/
message EverestToMcu {
oneof payload {
KeepAlive keep_alive = 1;
bool firmware_update = 2;
bool connector_lock = 3; // false: unlock, true: lock
uint32 pwm_duty_cycle = 4; // in 0.01 %, 0 = State F, 10000 = X1
CoilState set_coil_state_request = 5;
bool reset = 6;
BootConfigResponse config_response = 8;
FanState set_fan_state = 9;
RcdCommand rcd_cmd = 10;
}
int32 connector = 7; // 0: None, 1: Connector 1, 2: Connector 2
}
/*
This container message is send from MCU to EVerest and may contain any allowed message in that direction.
*/
message McuToEverest {
oneof payload {
KeepAlive keep_alive = 1;
ResetReason reset = 2;
CpState cp_state = 3;
CoilState set_coil_state_response = 4;
ErrorFlags error_flags = 5;
Telemetry telemetry = 7;
PpState pp_state = 8;
FanState fan_state = 9;
LockState lock_state = 10;
BootConfigRequest config_request = 11;
}
int32 connector = 6; // 0: None, 1: Connector 1, 2: Connector 2
}
enum CpState {
STATE_A = 0;
STATE_B = 1;
STATE_C = 2;
STATE_D = 3;
STATE_E = 4;
STATE_F = 5;
}
message ErrorFlags {
bool diode_fault = 1;
bool rcd_selftest_failed = 2;
bool rcd_triggered = 3;
bool ventilation_not_available = 4;
bool connector_lock_failed = 5;
bool cp_signal_fault = 6;
bool heartbeat_timeout = 7;
bool coil_feedback_diverges = 8;
bool pp_signal_fault = 9;
}
enum ResetReason {
USER = 0;
WATCHDOG = 1;
}
message KeepAlive {
uint32 time_stamp = 1;
uint32 hw_type = 2;
uint32 hw_revision = 3;
string sw_version_string = 6;
bool configuration_done = 7;
}
message Telemetry {
uint32 cp_voltage_hi = 1;
uint32 cp_voltage_lo = 2;
}
enum PpState {
STATE_NC = 0;
STATE_13A = 1;
STATE_20A = 2;
STATE_32A = 3;
STATE_70A = 4;
STATE_FAULT = 5;
}
message FanState {
uint32 fan_id = 1;
bool enabled = 2;
uint32 duty = 3; // in 0.1%, 1000 = 100%
uint32 rpm = 4;
}
enum LockState {
UNDEFINED = 0;
UNLOCKED = 1;
LOCKED = 2;
LOCKING = 3;
UNLOCKING = 4;
}
message CoilState {
CoilType coil_type = 1;
bool coil_state = 2; // true -> on; false -> off
}
enum CoilType {
COIL_UNKNOWN = 0;
COIL_AC = 1;
COIL_DC1 = 2;
// add precharge and discharge coils here later
COIL_DC2 = 3;
COIL_DC3 = 4;
}
message BootConfigRequest {
// TODO
}
message BootConfigResponse {
ConfigHardwareRevision hw_rev = 1;
repeated ChargePortConfig chargeport_config = 6;
}
message ChargePortConfig {
ChargePortType type = 1;
bool feedback_active_low = 2;
GpioPull feedback_pull = 3;
ConfigMotorLockType lock = 4;
bool has_socket = 5;
}
enum ChargePortType {
DISABLED = 0;
AC = 1;
DC = 2;
}
enum GpioPull {
NONE = 0;
UP = 1;
DOWN = 2;
}
message ConfigMotorLockType {
MotorLockType type = 1;
// additional lock specific options could be added here later
// will still keep this in place even if it only holds the type enum at the moment
}
enum ConfigHardwareRevision {
HW_REV_UNKNOWN = 0;
HW_REV_A = 1;
HW_REV_B = 2;
}
enum MotorLockType {
MOTOR_LOCK_UNKNOWN = 0;
MOTOR_LOCK_HELLA = 1;
MOTOR_LOCK_DEBUG_VALEO_HVAC = 2;
// add additional locks here
MOTOR_LOCK_NONE = -1;
}
message RcdCommand {
bool test = 1; // true -> set TEST pin high, false -> set TEST pin low
bool reset = 2; // reset RCD/emergency off if set to true
}

View File

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "ac_rcdImpl.hpp"
namespace module {
namespace rcd_1 {
void ac_rcdImpl::init() {
mod->serial.signal_error_flags.connect([this](int connector, ErrorFlags error_flags) {
if (connector == 1) {
if (error_flags.rcd_triggered and not last_error_flags.rcd_triggered) {
Everest::error::Error error_object = this->error_factory->create_error(
"ac_rcd/DC", "", "Port 1 RDC-MD triggered", Everest::error::Severity::High);
this->raise_error(error_object);
} else if (not error_flags.rcd_triggered and last_error_flags.rcd_triggered) {
this->clear_error("ac_rcd/DC");
}
last_error_flags = error_flags;
}
});
}
void ac_rcdImpl::ready() {
}
void ac_rcdImpl::handle_self_test() {
mod->serial.set_rcd_test(1, true);
}
bool ac_rcdImpl::handle_reset() {
mod->serial.reset_rcd(1, true);
return true;
}
} // namespace rcd_1
} // namespace module

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef RCD_1_AC_RCD_IMPL_HPP
#define RCD_1_AC_RCD_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/ac_rcd/Implementation.hpp>
#include "../PhyVersoBSP.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace rcd_1 {
struct Conf {};
class ac_rcdImpl : public ac_rcdImplBase {
public:
ac_rcdImpl() = delete;
ac_rcdImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PhyVersoBSP>& mod, Conf& config) :
ac_rcdImplBase(ev, "rcd_1"), 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 void handle_self_test() override;
virtual bool handle_reset() override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PhyVersoBSP>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
ErrorFlags last_error_flags{false};
// 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 rcd_1
} // namespace module
#endif // RCD_1_AC_RCD_IMPL_HPP

View File

@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "ac_rcdImpl.hpp"
namespace module {
namespace rcd_2 {
void ac_rcdImpl::init() {
mod->serial.signal_error_flags.connect([this](int connector, ErrorFlags error_flags) {
if (connector == 2) {
if (error_flags.rcd_triggered and not last_error_flags.rcd_triggered) {
Everest::error::Error error_object = this->error_factory->create_error(
"ac_rcd/DC", "", "Port 2 RDC-MD triggered", Everest::error::Severity::High);
this->raise_error(error_object);
} else if (not error_flags.rcd_triggered and last_error_flags.rcd_triggered) {
this->clear_error("ac_rcd/DC");
}
last_error_flags = error_flags;
}
});
}
void ac_rcdImpl::ready() {
}
void ac_rcdImpl::handle_self_test() {
mod->serial.set_rcd_test(2, true);
}
bool ac_rcdImpl::handle_reset() {
mod->serial.reset_rcd(2, true);
return true;
}
} // namespace rcd_2
} // namespace module

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef RCD_2_AC_RCD_IMPL_HPP
#define RCD_2_AC_RCD_IMPL_HPP
//
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
// template version 3
//
#include <generated/interfaces/ac_rcd/Implementation.hpp>
#include "../PhyVersoBSP.hpp"
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
// insert your custom include headers here
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
namespace module {
namespace rcd_2 {
struct Conf {};
class ac_rcdImpl : public ac_rcdImplBase {
public:
ac_rcdImpl() = delete;
ac_rcdImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<PhyVersoBSP>& mod, Conf& config) :
ac_rcdImplBase(ev, "rcd_2"), 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 void handle_self_test() override;
virtual bool handle_reset() override;
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
// insert your protected definitions here
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
private:
const Everest::PtrContainer<PhyVersoBSP>& mod;
const Conf& config;
virtual void init() override;
virtual void ready() override;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
// insert your private definitions here
ErrorFlags last_error_flags{false};
// 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 rcd_2
} // namespace module
#endif // RCD_2_AC_RCD_IMPL_HPP