Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 97 additions & 8 deletions modules/HardwareDrivers/EVSE/PhyVersoBSP/PhyVersoBSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,76 @@ void PhyVersoBSP::init() {
return;
}

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);
serial.flush_buffers();

serial.signal_config_request.connect([&]() {
serial.send_config();
EVLOG_info << "Sent config packet to MCU";
});
}

void PhyVersoBSP::ready() {
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);
Expand All @@ -58,6 +111,36 @@ void PhyVersoBSP::ready() {

// 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;
Expand All @@ -72,6 +155,12 @@ void PhyVersoBSP::everest_config_to_verso_config() {
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
8 changes: 8 additions & 0 deletions modules/HardwareDrivers/EVSE/PhyVersoBSP/PhyVersoBSP.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ struct Conf {
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 {
Expand Down Expand Up @@ -110,6 +116,8 @@ class PhyVersoBSP : public Everest::ModuleBase {
// 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
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"conn1_motor_lock_type": 2,
"conn1_motor_lock_type": 1,
"conn2_motor_lock_type": 1,
"reset_gpio_bank": 2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"conn1_motor_lock_type": 2,
"conn2_motor_lock_type": 2,
"reset_gpio_bank": 2
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ void evse_board_supportImpl::init() {

mod->serial.signal_pp_state.connect([this](int connector, PpState s) {
if (connector == 1) {
EVLOG_info << "[1] PpState " << s;
if (last_pp_state != s) {
EVLOG_info << "[1] PpState " << s;
publish_ac_pp_ampacity(to_pp_ampacity(s));
}
last_pp_state = s;
Expand All @@ -67,6 +67,47 @@ void evse_board_supportImpl::init() {
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() {
Expand Down Expand Up @@ -101,14 +142,13 @@ void evse_board_supportImpl::handle_pwm_F() {
}

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);
// FIXME: implement in MCU with feedback
if (value.allow_power_on) {
publish_event({types::board_support_common::Event::PowerOn});
} else {
publish_event({types::board_support_common::Event::PowerOff});
}
} else {
mod->serial.set_coil_state_request(1, CoilType_COIL_AC, value.allow_power_on);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class evse_board_supportImpl : public evse_board_supportImplBase {
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;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ void evse_board_supportImpl::init() {

mod->serial.signal_pp_state.connect([this](int connector, PpState s) {
if (connector == 2) {
EVLOG_info << "[2] PpState " << s;
if (last_pp_state != s) {
EVLOG_info << "[2] PpState " << s;
publish_ac_pp_ampacity(to_pp_ampacity(s));
}
last_pp_state = s;
Expand All @@ -67,6 +67,47 @@ void evse_board_supportImpl::init() {
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() {
Expand Down Expand Up @@ -101,14 +142,13 @@ void evse_board_supportImpl::handle_pwm_F() {
}

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);
// FIXME: implement in MCU with feedback
if (value.allow_power_on) {
publish_event({types::board_support_common::Event::PowerOn});
} else {
publish_event({types::board_support_common::Event::PowerOff});
}
} else {
mod->serial.set_coil_state_request(2, CoilType_COIL_AC, value.allow_power_on);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class evse_board_supportImpl : public evse_board_supportImplBase {
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;
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
};

Expand Down

This file was deleted.

This file was deleted.

Loading