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:
@@ -0,0 +1,7 @@
|
||||
add_subdirectory(EV)
|
||||
add_subdirectory(EVSE)
|
||||
add_subdirectory(IsolationMonitors)
|
||||
add_subdirectory(NfcReaders)
|
||||
add_subdirectory(Payment)
|
||||
add_subdirectory(PowerMeters)
|
||||
add_subdirectory(PowerSupplies)
|
||||
@@ -0,0 +1 @@
|
||||
ev_add_module(YetiEvDriver)
|
||||
1
tools/EVerest-main/modules/HardwareDrivers/EV/README.md
Normal file
1
tools/EVerest-main/modules/HardwareDrivers/EV/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Drivers for an AC or DC power path on the EV side
|
||||
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# 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(evyeti_comms)
|
||||
|
||||
target_include_directories(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"common"
|
||||
"evyeti_comms"
|
||||
"evyeti_comms/nanopb"
|
||||
"evyeti_comms/protobuf"
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
Pal::Sigslot
|
||||
evyeti_comms
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"ev_board_support/ev_board_supportImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,84 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "YetiEvDriver.hpp"
|
||||
|
||||
namespace module {
|
||||
|
||||
void YetiEvDriver::init() {
|
||||
|
||||
// initialize serial driver
|
||||
if (!serial.openDevice(config.serial_port.c_str(), config.baud_rate)) {
|
||||
EVLOG_error << "Could not open serial port " << config.serial_port << " with baud rate " << config.baud_rate;
|
||||
p_ev_board_support->raise_error(p_ev_board_support->error_factory->create_error(
|
||||
"generic/CommunicationFault", "", "Could not open serial port"));
|
||||
return;
|
||||
}
|
||||
|
||||
invoke_init(*p_ev_board_support);
|
||||
}
|
||||
|
||||
void YetiEvDriver::ready() {
|
||||
serial.run();
|
||||
|
||||
if (!serial.reset(config.reset_gpio)) {
|
||||
EVLOG_error << "EVYeti reset not successful.";
|
||||
}
|
||||
|
||||
serial.signalSpuriousReset.connect([this]() { EVLOG_error << "EVYeti uC spurious reset!"; });
|
||||
serial.signalConnectionTimeout.connect([this]() { EVLOG_error << "EVYeti UART timeout!"; });
|
||||
|
||||
serial.signalEvent.connect([this](Event e) {
|
||||
types::board_support_common::BspEvent bspe;
|
||||
|
||||
bspe.event = types::board_support_common::Event::Disconnected;
|
||||
switch (e.type) {
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_A:
|
||||
bspe.event = types::board_support_common::Event::A;
|
||||
EVLOG_info << "BspEvent::A";
|
||||
break;
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_B:
|
||||
EVLOG_info << "BspEvent::B";
|
||||
bspe.event = types::board_support_common::Event::B;
|
||||
break;
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_C:
|
||||
EVLOG_info << "BspEvent::C";
|
||||
bspe.event = types::board_support_common::Event::C;
|
||||
break;
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_D:
|
||||
EVLOG_info << "BspEvent::D";
|
||||
bspe.event = types::board_support_common::Event::D;
|
||||
break;
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_DISCONNECTED:
|
||||
EVLOG_info << "BspEvent::Disconnected";
|
||||
bspe.event = types::board_support_common::Event::Disconnected;
|
||||
break;
|
||||
/// explicitly fall through all the Event_InterfaceEvent values we are not handling
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_E:
|
||||
[[fallthrough]];
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_F:
|
||||
[[fallthrough]];
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_EF:
|
||||
[[fallthrough]];
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_ERROR_RELAIS:
|
||||
[[fallthrough]];
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_RELAIS_ON:
|
||||
[[fallthrough]];
|
||||
case Event_InterfaceEvent::Event_InterfaceEvent_RELAIS_OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
p_ev_board_support->publish_bsp_event(bspe);
|
||||
});
|
||||
|
||||
serial.signalMeasurements.connect([this](Measurements m) {
|
||||
types::board_support_common::BspMeasurement bspm;
|
||||
bspm.cp_pwm_duty_cycle = m.pwmDutyCycle * 100.;
|
||||
// FIXME(cc): This is not implemented on MCU side yet
|
||||
bspm.proximity_pilot = {types::board_support_common::Ampacity::None};
|
||||
p_ev_board_support->publish_bsp_measurement(bspm);
|
||||
});
|
||||
|
||||
invoke_ready(*p_ev_board_support);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef YETI_EV_DRIVER_HPP
|
||||
#define YETI_EV_DRIVER_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/ev_board_support/Implementation.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
#include "evyeti_comms/evSerial.h"
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
std::string serial_port;
|
||||
int baud_rate;
|
||||
int reset_gpio;
|
||||
};
|
||||
|
||||
class YetiEvDriver : public Everest::ModuleBase {
|
||||
public:
|
||||
YetiEvDriver() = delete;
|
||||
YetiEvDriver(const ModuleInfo& info, Everest::TelemetryProvider& telemetry,
|
||||
std::unique_ptr<ev_board_supportImplBase> p_ev_board_support, Conf& config) :
|
||||
ModuleBase(info), telemetry(telemetry), p_ev_board_support(std::move(p_ev_board_support)), config(config){};
|
||||
|
||||
Everest::TelemetryProvider& telemetry;
|
||||
const std::unique_ptr<ev_board_supportImplBase> p_ev_board_support;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
evSerial serial;
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // YETI_EV_DRIVER_HPP
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "ev_board_supportImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace ev_board_support {
|
||||
|
||||
void ev_board_supportImpl::init() {
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::ready() {
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::handle_enable(bool& value) {
|
||||
// your code for cmd enable goes here
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::handle_set_cp_state(types::ev_board_support::EvCpState& cp_state) {
|
||||
// your code for cmd set_cp_state goes here
|
||||
switch (cp_state) {
|
||||
case types::ev_board_support::EvCpState::A:
|
||||
mod->serial.setBCDE(0);
|
||||
break;
|
||||
case types::ev_board_support::EvCpState::B:
|
||||
mod->serial.setBCDE(1);
|
||||
break;
|
||||
case types::ev_board_support::EvCpState::C:
|
||||
mod->serial.setBCDE(2);
|
||||
break;
|
||||
case types::ev_board_support::EvCpState::D:
|
||||
mod->serial.setBCDE(3);
|
||||
break;
|
||||
case types::ev_board_support::EvCpState::E:
|
||||
mod->serial.setBCDE(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::handle_allow_power_on(bool& value) {
|
||||
mod->serial.allowPowerOn(value);
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::handle_diode_fail(bool& value) {
|
||||
// your code for cmd diode_fail goes here
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::handle_set_ac_max_current(double& current) {
|
||||
// your code for cmd set_ac_max_current goes here
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::handle_set_three_phases(bool& three_phases) {
|
||||
// your code for cmd set_three_phases goes here
|
||||
}
|
||||
|
||||
void ev_board_supportImpl::handle_set_rcd_error(double& rcd_current_mA) {
|
||||
// your code for cmd set_rcd_error goes here
|
||||
}
|
||||
|
||||
} // namespace ev_board_support
|
||||
} // namespace module
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef EV_BOARD_SUPPORT_EV_BOARD_SUPPORT_IMPL_HPP
|
||||
#define EV_BOARD_SUPPORT_EV_BOARD_SUPPORT_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ev_board_support/Implementation.hpp>
|
||||
|
||||
#include "../YetiEvDriver.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace ev_board_support {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ev_board_supportImpl : public ev_board_supportImplBase {
|
||||
public:
|
||||
ev_board_supportImpl() = delete;
|
||||
ev_board_supportImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<YetiEvDriver>& mod, Conf& config) :
|
||||
ev_board_supportImplBase(ev, "ev_board_support"), 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_set_cp_state(types::ev_board_support::EvCpState& cp_state) override;
|
||||
virtual void handle_allow_power_on(bool& value) override;
|
||||
virtual void handle_diode_fail(bool& value) override;
|
||||
virtual void handle_set_ac_max_current(double& current) override;
|
||||
virtual void handle_set_three_phases(bool& three_phases) override;
|
||||
virtual void handle_set_rcd_error(double& rcd_current_mA) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<YetiEvDriver>& 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 ev_board_support
|
||||
} // namespace module
|
||||
|
||||
#endif // EV_BOARD_SUPPORT_EV_BOARD_SUPPORT_IMPL_HPP
|
||||
@@ -0,0 +1,36 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# set the project name
|
||||
project(evyeti_comms VERSION 0.1)
|
||||
# specify the C++ standard
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
|
||||
configure_file(config.h.in config.h)
|
||||
|
||||
# add the executable
|
||||
add_library(evyeti_comms STATIC)
|
||||
ev_register_library_target(evyeti_comms)
|
||||
|
||||
target_sources(evyeti_comms
|
||||
PRIVATE
|
||||
evSerial.cpp
|
||||
protobuf/hi2lo.pb.c
|
||||
protobuf/lo2hi.pb.c
|
||||
)
|
||||
|
||||
target_include_directories(evyeti_comms
|
||||
PUBLIC
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
protobuf
|
||||
)
|
||||
|
||||
target_link_libraries(evyeti_comms
|
||||
PUBLIC
|
||||
date::date-tz
|
||||
everest::nanopb
|
||||
PRIVATE
|
||||
Pal::Sigslot
|
||||
everest::framework
|
||||
)
|
||||
@@ -0,0 +1,3 @@
|
||||
// the configured options and settings for YetiDriver
|
||||
#define YetiComms_VERSION_MAJOR @YetiComms_VERSION_MAJOR@
|
||||
#define YetiComms_VERSION_MINOR @YetiComms_VERSION_MINOR@
|
||||
@@ -0,0 +1,399 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2023 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 "hi2lo.pb.h"
|
||||
#include "lo2hi.pb.h"
|
||||
|
||||
evSerial::evSerial() {
|
||||
fd = 0;
|
||||
baud = 0;
|
||||
reset_done_flag = false;
|
||||
forced_reset = false;
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
evSerial::~evSerial() {
|
||||
if (fd)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool evSerial::openDevice(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);
|
||||
cobsDecodeReset();
|
||||
|
||||
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 setSerialAttributes();
|
||||
}
|
||||
|
||||
bool evSerial::setSerialAttributes() {
|
||||
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;
|
||||
}
|
||||
// printf ("Success setting tcsetattr\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void evSerial::cobsDecodeReset() {
|
||||
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;
|
||||
}
|
||||
// printf("%X",crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void evSerial::handlePacket(uint8_t* buf, int len) {
|
||||
// printf ("packet received len %u\n", len);
|
||||
|
||||
// Check CRC32 (last 4 bytes)
|
||||
// uint32_t crc = calculateCrc(rx_packet_buf, rx_packet_len);
|
||||
if (crc32(buf, len)) {
|
||||
printf("CRC mismatch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
|
||||
LoToHi msg_in;
|
||||
pb_istream_t istream = pb_istream_from_buffer(buf, len);
|
||||
|
||||
if (pb_decode(&istream, LoToHi_fields, &msg_in))
|
||||
switch (msg_in.which_payload) {
|
||||
|
||||
case LoToHi_keep_alive_tag:
|
||||
// printf("Received keep_alive_lo\n");
|
||||
signalKeepAliveLo(msg_in.payload.keep_alive);
|
||||
// detect connection timeout if keep_alive packets stop coming...
|
||||
last_keep_alive_lo_timestamp = date::utc_clock::now();
|
||||
break;
|
||||
case LoToHi_event_tag:
|
||||
// printf("Received event %i\n",msg_in.payload.event);
|
||||
signalEvent(msg_in.payload.event);
|
||||
break;
|
||||
case LoToHi_measurements_tag:
|
||||
// printf("Received event %i\n",msg_in.payload.event);
|
||||
signalMeasurements(msg_in.payload.measurements);
|
||||
break;
|
||||
case LoToHi_reset_done_tag:
|
||||
// printf("Received reset_done\n");
|
||||
reset_done_flag = true;
|
||||
if (!forced_reset)
|
||||
signalSpuriousReset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void evSerial::cobsDecode(uint8_t* buf, int len) {
|
||||
for (int i = 0; i < len; i++)
|
||||
cobsDecodeByte(buf[i]);
|
||||
}
|
||||
|
||||
void evSerial::cobsDecodeByte(uint8_t byte) {
|
||||
// check max length
|
||||
if ((decode - msg == 2048 - 1) && byte != 0x00) {
|
||||
printf("cobsDecode: Buffer overflow\n");
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
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");
|
||||
cobsDecodeReset();
|
||||
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
|
||||
handlePacket(msg, decode - 1 - msg);
|
||||
}
|
||||
cobsDecodeReset();
|
||||
return; // need to return here, because of block--
|
||||
}
|
||||
}
|
||||
block--;
|
||||
}
|
||||
|
||||
void evSerial::run() {
|
||||
readThreadHandle = std::thread(&evSerial::readThread, this);
|
||||
timeoutDetectionThreadHandle = std::thread(&evSerial::timeoutDetectionThread, this);
|
||||
}
|
||||
|
||||
void evSerial::timeoutDetectionThread() {
|
||||
while (true) {
|
||||
sleep(1);
|
||||
if (timeoutDetectionThreadHandle.shouldExit())
|
||||
break;
|
||||
if (serial_timed_out())
|
||||
signalConnectionTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
void evSerial::readThread() {
|
||||
uint8_t buf[2048];
|
||||
int n;
|
||||
|
||||
cobsDecodeReset();
|
||||
while (true) {
|
||||
if (readThreadHandle.shouldExit())
|
||||
break;
|
||||
if (fd > 0) {
|
||||
n = read(fd, buf, sizeof buf);
|
||||
cobsDecode(buf, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool evSerial::linkWrite(HiToLo* 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, HiToLo_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 = cobsEncode(tx_packet_buf, tx_payload_len, encode_buf);
|
||||
// std::cout << "Write "<<tx_encode_len<<" bytes to serial port." << std::endl;
|
||||
write(fd, encode_buf, tx_encode_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t evSerial::cobsEncode(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 timeSinceLastKeepAlive =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(now - last_keep_alive_lo_timestamp).count();
|
||||
if (timeSinceLastKeepAlive >= 5000)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void evSerial::allowPowerOn(bool p) {
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_allow_power_on_tag;
|
||||
msg_out.payload.allow_power_on.p = p;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::setBCDE(uint32_t mode) {
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_set_bcde_tag;
|
||||
msg_out.payload.set_bcde.mode = mode;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::enable() {
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_enable_tag;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::disable() {
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_disable_tag;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
bool evSerial::reset(const int reset_pin) {
|
||||
|
||||
reset_done_flag = false;
|
||||
forced_reset = true;
|
||||
|
||||
if (reset_pin > 0) {
|
||||
// Try to hardware reset Yeti controller to be in a known state
|
||||
char cmd[100];
|
||||
sprintf(cmd, "echo %i >/sys/class/gpio/export", reset_pin);
|
||||
system(cmd);
|
||||
sprintf(cmd, "echo out > /sys/class/gpio/gpio%i/direction", reset_pin);
|
||||
system(cmd);
|
||||
sprintf(cmd, "echo 0 > /sys/class/gpio/gpio%i/value", reset_pin);
|
||||
system(cmd);
|
||||
sprintf(cmd, "echo 1 > /sys/class/gpio/gpio%i/value", reset_pin);
|
||||
system(cmd);
|
||||
} else {
|
||||
// Try to soft reset Yeti controller to be in a known state
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_reset_tag;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
// Wait for reset done message from uC
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (reset_done_flag) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
// Reset flag to detect run time spurious resets of uC from now on
|
||||
reset_done_flag = false;
|
||||
forced_reset = false;
|
||||
|
||||
// send some dummy packets to resync COBS etc.
|
||||
keepAlive();
|
||||
keepAlive();
|
||||
keepAlive();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void evSerial::firmwareUpdate(bool rom) {
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_firmware_update_tag;
|
||||
msg_out.payload.firmware_update.invoke_rom_bootloader = rom;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::keepAlive() {
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_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;
|
||||
msg_out.payload.keep_alive.protocol_version_major = 0;
|
||||
msg_out.payload.keep_alive.protocol_version_minor = 1;
|
||||
strcpy(msg_out.payload.keep_alive.sw_version_string, "n/a");
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef YETI_SERIAL
|
||||
#define YETI_SERIAL
|
||||
|
||||
#include "hi2lo.pb.h"
|
||||
#include "lo2hi.pb.h"
|
||||
#include <date/date.h>
|
||||
#include <date/tz.h>
|
||||
#include <sigslot/signal.hpp>
|
||||
#include <stdint.h>
|
||||
#include <termios.h>
|
||||
#include <utils/thread.hpp>
|
||||
|
||||
class evSerial {
|
||||
|
||||
public:
|
||||
evSerial();
|
||||
~evSerial();
|
||||
|
||||
bool openDevice(const char* device, int baud);
|
||||
bool is_open() {
|
||||
return fd > 0;
|
||||
};
|
||||
|
||||
void readThread();
|
||||
void run();
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
void firmwareUpdate(bool rom);
|
||||
void keepAlive();
|
||||
|
||||
bool reset(const int reset_pin);
|
||||
|
||||
void setBCDE(uint32_t mode);
|
||||
void allowPowerOn(bool p);
|
||||
|
||||
sigslot::signal<KeepAliveLo> signalKeepAliveLo;
|
||||
sigslot::signal<Event> signalEvent;
|
||||
sigslot::signal<Measurements> signalMeasurements;
|
||||
sigslot::signal<> signalSpuriousReset;
|
||||
sigslot::signal<> signalConnectionTimeout;
|
||||
|
||||
private:
|
||||
// Serial interface
|
||||
bool setSerialAttributes();
|
||||
int fd;
|
||||
int baud;
|
||||
|
||||
// COBS de-/encoder
|
||||
void cobsDecodeReset();
|
||||
void handlePacket(uint8_t* buf, int len);
|
||||
void cobsDecode(uint8_t* buf, int len);
|
||||
void cobsDecodeByte(uint8_t byte);
|
||||
size_t cobsEncode(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 readThreadHandle;
|
||||
Everest::Thread timeoutDetectionThreadHandle;
|
||||
|
||||
bool linkWrite(HiToLo* m);
|
||||
volatile bool reset_done_flag;
|
||||
volatile bool forced_reset;
|
||||
|
||||
bool serial_timed_out();
|
||||
void timeoutDetectionThread();
|
||||
std::chrono::time_point<date::utc_clock> last_keep_alive_lo_timestamp;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
nanopb_generator.py -L "#include <nanopb/%s>" -I . -D . lo2hi.proto hi2lo.proto
|
||||
@@ -0,0 +1 @@
|
||||
KeepAliveHi.sw_version_string max_length:50
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.6 */
|
||||
|
||||
#include "hi2lo.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(HiToLo, HiToLo, AUTO)
|
||||
|
||||
|
||||
PB_BIND(AllowPowerOn, AllowPowerOn, AUTO)
|
||||
|
||||
|
||||
PB_BIND(SetBCDE, SetBCDE, AUTO)
|
||||
|
||||
|
||||
PB_BIND(FirmwareUpdate, FirmwareUpdate, AUTO)
|
||||
|
||||
|
||||
PB_BIND(KeepAliveHi, KeepAliveHi, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Enable, Enable, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Disable, Disable, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Reset, Reset, AUTO)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.6 */
|
||||
|
||||
#ifndef PB_HI2LO_PB_H_INCLUDED
|
||||
#define PB_HI2LO_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
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _Disable {
|
||||
char dummy_field;
|
||||
} Disable;
|
||||
|
||||
typedef struct _Enable {
|
||||
char dummy_field;
|
||||
} Enable;
|
||||
|
||||
typedef struct _Reset {
|
||||
char dummy_field;
|
||||
} Reset;
|
||||
|
||||
typedef struct _AllowPowerOn {
|
||||
bool p;
|
||||
} AllowPowerOn;
|
||||
|
||||
typedef struct _FirmwareUpdate {
|
||||
bool invoke_rom_bootloader;
|
||||
} FirmwareUpdate;
|
||||
|
||||
typedef struct _KeepAliveHi {
|
||||
uint32_t time_stamp;
|
||||
uint32_t hw_type;
|
||||
uint32_t hw_revision;
|
||||
uint32_t protocol_version_major;
|
||||
uint32_t protocol_version_minor;
|
||||
char sw_version_string[51];
|
||||
} KeepAliveHi;
|
||||
|
||||
typedef struct _SetBCDE {
|
||||
int32_t mode; /* 0: A, 1: B, 2: C, 3: D, 4: E */
|
||||
} SetBCDE;
|
||||
|
||||
/* This container message is send from Hi Level to Low level and may contain any allowed message in that direction. */
|
||||
typedef struct _HiToLo {
|
||||
pb_size_t which_payload;
|
||||
union {
|
||||
/* Common/configuration messages */
|
||||
Enable enable;
|
||||
Disable disable;
|
||||
KeepAliveHi keep_alive;
|
||||
FirmwareUpdate firmware_update;
|
||||
AllowPowerOn allow_power_on;
|
||||
/* Commands for HIL simulator */
|
||||
Reset reset;
|
||||
/* Commands only available in control_mode = 2 (direct low level control) */
|
||||
SetBCDE set_bcde;
|
||||
} payload;
|
||||
} HiToLo;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define HiToLo_init_default {0, {Enable_init_default}}
|
||||
#define AllowPowerOn_init_default {0}
|
||||
#define SetBCDE_init_default {0}
|
||||
#define FirmwareUpdate_init_default {0}
|
||||
#define KeepAliveHi_init_default {0, 0, 0, 0, 0, ""}
|
||||
#define Enable_init_default {0}
|
||||
#define Disable_init_default {0}
|
||||
#define Reset_init_default {0}
|
||||
#define HiToLo_init_zero {0, {Enable_init_zero}}
|
||||
#define AllowPowerOn_init_zero {0}
|
||||
#define SetBCDE_init_zero {0}
|
||||
#define FirmwareUpdate_init_zero {0}
|
||||
#define KeepAliveHi_init_zero {0, 0, 0, 0, 0, ""}
|
||||
#define Enable_init_zero {0}
|
||||
#define Disable_init_zero {0}
|
||||
#define Reset_init_zero {0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define AllowPowerOn_p_tag 1
|
||||
#define FirmwareUpdate_invoke_rom_bootloader_tag 1
|
||||
#define KeepAliveHi_time_stamp_tag 1
|
||||
#define KeepAliveHi_hw_type_tag 2
|
||||
#define KeepAliveHi_hw_revision_tag 3
|
||||
#define KeepAliveHi_protocol_version_major_tag 4
|
||||
#define KeepAliveHi_protocol_version_minor_tag 5
|
||||
#define KeepAliveHi_sw_version_string_tag 6
|
||||
#define SetBCDE_mode_tag 1
|
||||
#define HiToLo_enable_tag 6
|
||||
#define HiToLo_disable_tag 7
|
||||
#define HiToLo_keep_alive_tag 13
|
||||
#define HiToLo_firmware_update_tag 16
|
||||
#define HiToLo_allow_power_on_tag 21
|
||||
#define HiToLo_reset_tag 23
|
||||
#define HiToLo_set_bcde_tag 25
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define HiToLo_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,enable,payload.enable), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,disable,payload.disable), 7) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 13) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,firmware_update,payload.firmware_update), 16) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,allow_power_on,payload.allow_power_on), 21) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,reset,payload.reset), 23) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,set_bcde,payload.set_bcde), 25)
|
||||
#define HiToLo_CALLBACK NULL
|
||||
#define HiToLo_DEFAULT NULL
|
||||
#define HiToLo_payload_enable_MSGTYPE Enable
|
||||
#define HiToLo_payload_disable_MSGTYPE Disable
|
||||
#define HiToLo_payload_keep_alive_MSGTYPE KeepAliveHi
|
||||
#define HiToLo_payload_firmware_update_MSGTYPE FirmwareUpdate
|
||||
#define HiToLo_payload_allow_power_on_MSGTYPE AllowPowerOn
|
||||
#define HiToLo_payload_reset_MSGTYPE Reset
|
||||
#define HiToLo_payload_set_bcde_MSGTYPE SetBCDE
|
||||
|
||||
#define AllowPowerOn_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, p, 1)
|
||||
#define AllowPowerOn_CALLBACK NULL
|
||||
#define AllowPowerOn_DEFAULT NULL
|
||||
|
||||
#define SetBCDE_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, INT32, mode, 1)
|
||||
#define SetBCDE_CALLBACK NULL
|
||||
#define SetBCDE_DEFAULT NULL
|
||||
|
||||
#define FirmwareUpdate_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, invoke_rom_bootloader, 1)
|
||||
#define FirmwareUpdate_CALLBACK NULL
|
||||
#define FirmwareUpdate_DEFAULT NULL
|
||||
|
||||
#define KeepAliveHi_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, UINT32, protocol_version_major, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, protocol_version_minor, 5) \
|
||||
X(a, STATIC, SINGULAR, STRING, sw_version_string, 6)
|
||||
#define KeepAliveHi_CALLBACK NULL
|
||||
#define KeepAliveHi_DEFAULT NULL
|
||||
|
||||
#define Enable_FIELDLIST(X, a) \
|
||||
|
||||
#define Enable_CALLBACK NULL
|
||||
#define Enable_DEFAULT NULL
|
||||
|
||||
#define Disable_FIELDLIST(X, a) \
|
||||
|
||||
#define Disable_CALLBACK NULL
|
||||
#define Disable_DEFAULT NULL
|
||||
|
||||
#define Reset_FIELDLIST(X, a) \
|
||||
|
||||
#define Reset_CALLBACK NULL
|
||||
#define Reset_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t HiToLo_msg;
|
||||
extern const pb_msgdesc_t AllowPowerOn_msg;
|
||||
extern const pb_msgdesc_t SetBCDE_msg;
|
||||
extern const pb_msgdesc_t FirmwareUpdate_msg;
|
||||
extern const pb_msgdesc_t KeepAliveHi_msg;
|
||||
extern const pb_msgdesc_t Enable_msg;
|
||||
extern const pb_msgdesc_t Disable_msg;
|
||||
extern const pb_msgdesc_t Reset_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define HiToLo_fields &HiToLo_msg
|
||||
#define AllowPowerOn_fields &AllowPowerOn_msg
|
||||
#define SetBCDE_fields &SetBCDE_msg
|
||||
#define FirmwareUpdate_fields &FirmwareUpdate_msg
|
||||
#define KeepAliveHi_fields &KeepAliveHi_msg
|
||||
#define Enable_fields &Enable_msg
|
||||
#define Disable_fields &Disable_msg
|
||||
#define Reset_fields &Reset_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define AllowPowerOn_size 2
|
||||
#define Disable_size 0
|
||||
#define Enable_size 0
|
||||
#define FirmwareUpdate_size 2
|
||||
#define HiToLo_size 84
|
||||
#define KeepAliveHi_size 82
|
||||
#define Reset_size 0
|
||||
#define SetBCDE_size 11
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
syntax = "proto3";
|
||||
|
||||
/*
|
||||
This container message is send from Hi Level to Low level and may contain any allowed message in that direction.
|
||||
*/
|
||||
message HiToLo {
|
||||
oneof payload {
|
||||
// Common/configuration messages
|
||||
Enable enable = 6;
|
||||
Disable disable = 7;
|
||||
KeepAliveHi keep_alive = 13;
|
||||
FirmwareUpdate firmware_update = 16;
|
||||
// Commands only available in control_mode = 2 (direct low level control)
|
||||
SetBCDE set_bcde = 25;
|
||||
AllowPowerOn allow_power_on = 21;
|
||||
// Commands for HIL simulator
|
||||
Reset reset = 23;
|
||||
}
|
||||
}
|
||||
|
||||
message AllowPowerOn {
|
||||
bool p = 1;
|
||||
}
|
||||
|
||||
message SetBCDE {
|
||||
int32 mode = 1; // 0: A, 1: B, 2: C, 3: D, 4: E
|
||||
}
|
||||
|
||||
message FirmwareUpdate {
|
||||
bool invoke_rom_bootloader = 1;
|
||||
}
|
||||
|
||||
|
||||
message KeepAliveHi {
|
||||
uint32 time_stamp = 1;
|
||||
uint32 hw_type = 2;
|
||||
uint32 hw_revision = 3;
|
||||
uint32 protocol_version_major = 4;
|
||||
uint32 protocol_version_minor = 5;
|
||||
string sw_version_string = 6;
|
||||
|
||||
}
|
||||
|
||||
message Enable { }
|
||||
message Disable { }
|
||||
message Reset { }
|
||||
@@ -0,0 +1 @@
|
||||
KeepAliveLo.sw_version_string max_length:50
|
||||
@@ -0,0 +1,25 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.6 */
|
||||
|
||||
#include "lo2hi.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(LoToHi, LoToHi, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Event, Event, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Measurements, Measurements, AUTO)
|
||||
|
||||
|
||||
PB_BIND(KeepAliveLo, KeepAliveLo, AUTO)
|
||||
|
||||
|
||||
PB_BIND(ResetDone, ResetDone, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.6 */
|
||||
|
||||
#ifndef PB_LO2HI_PB_H_INCLUDED
|
||||
#define PB_LO2HI_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 _Event_InterfaceEvent {
|
||||
Event_InterfaceEvent_A = 0,
|
||||
Event_InterfaceEvent_B = 1,
|
||||
Event_InterfaceEvent_C = 2,
|
||||
Event_InterfaceEvent_D = 3,
|
||||
Event_InterfaceEvent_E = 4,
|
||||
Event_InterfaceEvent_F = 5,
|
||||
Event_InterfaceEvent_EF = 6,
|
||||
Event_InterfaceEvent_DISCONNECTED = 8,
|
||||
Event_InterfaceEvent_ERROR_RELAIS = 9,
|
||||
Event_InterfaceEvent_RELAIS_ON = 10,
|
||||
Event_InterfaceEvent_RELAIS_OFF = 11
|
||||
} Event_InterfaceEvent;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _ResetDone {
|
||||
char dummy_field;
|
||||
} ResetDone;
|
||||
|
||||
typedef struct _Event {
|
||||
Event_InterfaceEvent type;
|
||||
} Event;
|
||||
|
||||
typedef struct _KeepAliveLo {
|
||||
uint32_t time_stamp;
|
||||
uint32_t hw_type;
|
||||
uint32_t hw_revision;
|
||||
uint32_t protocol_version_major;
|
||||
uint32_t protocol_version_minor;
|
||||
char sw_version_string[51];
|
||||
float hwcap_max_current;
|
||||
float hwcap_min_current;
|
||||
uint32_t hwcap_max_phase_count;
|
||||
uint32_t hwcap_min_phase_count;
|
||||
bool supports_changing_phases_during_charging;
|
||||
} KeepAliveLo;
|
||||
|
||||
typedef struct _Measurements {
|
||||
float pwmDutyCycle;
|
||||
float evse_pwm_voltage_hi;
|
||||
float evse_pwm_voltage_lo;
|
||||
bool evse_pwm_running;
|
||||
uint32_t relais_on;
|
||||
} Measurements;
|
||||
|
||||
/* This container message is send from Lo Level to Hi level and may contain any allowed message in that direction. */
|
||||
typedef struct _LoToHi {
|
||||
pb_size_t which_payload;
|
||||
union {
|
||||
/* Common Packets */
|
||||
KeepAliveLo keep_alive;
|
||||
/* HIL packets */
|
||||
Measurements measurements;
|
||||
/* Packets only available in control_mode = 2 (low level control) */
|
||||
Event event;
|
||||
ResetDone reset_done;
|
||||
} payload;
|
||||
} LoToHi;
|
||||
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _Event_InterfaceEvent_MIN Event_InterfaceEvent_A
|
||||
#define _Event_InterfaceEvent_MAX Event_InterfaceEvent_RELAIS_OFF
|
||||
#define _Event_InterfaceEvent_ARRAYSIZE ((Event_InterfaceEvent)(Event_InterfaceEvent_RELAIS_OFF+1))
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define LoToHi_init_default {0, {KeepAliveLo_init_default}}
|
||||
#define Event_init_default {_Event_InterfaceEvent_MIN}
|
||||
#define Measurements_init_default {0, 0, 0, 0, 0}
|
||||
#define KeepAliveLo_init_default {0, 0, 0, 0, 0, "", 0, 0, 0, 0, 0}
|
||||
#define ResetDone_init_default {0}
|
||||
#define LoToHi_init_zero {0, {KeepAliveLo_init_zero}}
|
||||
#define Event_init_zero {_Event_InterfaceEvent_MIN}
|
||||
#define Measurements_init_zero {0, 0, 0, 0, 0}
|
||||
#define KeepAliveLo_init_zero {0, 0, 0, 0, 0, "", 0, 0, 0, 0, 0}
|
||||
#define ResetDone_init_zero {0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define Event_type_tag 1
|
||||
#define KeepAliveLo_time_stamp_tag 1
|
||||
#define KeepAliveLo_hw_type_tag 2
|
||||
#define KeepAliveLo_hw_revision_tag 3
|
||||
#define KeepAliveLo_protocol_version_major_tag 4
|
||||
#define KeepAliveLo_protocol_version_minor_tag 5
|
||||
#define KeepAliveLo_sw_version_string_tag 6
|
||||
#define KeepAliveLo_hwcap_max_current_tag 7
|
||||
#define KeepAliveLo_hwcap_min_current_tag 8
|
||||
#define KeepAliveLo_hwcap_max_phase_count_tag 9
|
||||
#define KeepAliveLo_hwcap_min_phase_count_tag 10
|
||||
#define KeepAliveLo_supports_changing_phases_during_charging_tag 11
|
||||
#define Measurements_pwmDutyCycle_tag 1
|
||||
#define Measurements_evse_pwm_voltage_hi_tag 2
|
||||
#define Measurements_evse_pwm_voltage_lo_tag 3
|
||||
#define Measurements_evse_pwm_running_tag 4
|
||||
#define Measurements_relais_on_tag 5
|
||||
#define LoToHi_keep_alive_tag 3
|
||||
#define LoToHi_measurements_tag 5
|
||||
#define LoToHi_event_tag 6
|
||||
#define LoToHi_reset_done_tag 7
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define LoToHi_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 3) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,measurements,payload.measurements), 5) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,event,payload.event), 6) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,reset_done,payload.reset_done), 7)
|
||||
#define LoToHi_CALLBACK NULL
|
||||
#define LoToHi_DEFAULT NULL
|
||||
#define LoToHi_payload_keep_alive_MSGTYPE KeepAliveLo
|
||||
#define LoToHi_payload_measurements_MSGTYPE Measurements
|
||||
#define LoToHi_payload_event_MSGTYPE Event
|
||||
#define LoToHi_payload_reset_done_MSGTYPE ResetDone
|
||||
|
||||
#define Event_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UENUM, type, 1)
|
||||
#define Event_CALLBACK NULL
|
||||
#define Event_DEFAULT NULL
|
||||
|
||||
#define Measurements_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, pwmDutyCycle, 1) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, evse_pwm_voltage_hi, 2) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, evse_pwm_voltage_lo, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, evse_pwm_running, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, relais_on, 5)
|
||||
#define Measurements_CALLBACK NULL
|
||||
#define Measurements_DEFAULT NULL
|
||||
|
||||
#define KeepAliveLo_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, UINT32, protocol_version_major, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, protocol_version_minor, 5) \
|
||||
X(a, STATIC, SINGULAR, STRING, sw_version_string, 6) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, hwcap_max_current, 7) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, hwcap_min_current, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hwcap_max_phase_count, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hwcap_min_phase_count, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, supports_changing_phases_during_charging, 11)
|
||||
#define KeepAliveLo_CALLBACK NULL
|
||||
#define KeepAliveLo_DEFAULT NULL
|
||||
|
||||
#define ResetDone_FIELDLIST(X, a) \
|
||||
|
||||
#define ResetDone_CALLBACK NULL
|
||||
#define ResetDone_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t LoToHi_msg;
|
||||
extern const pb_msgdesc_t Event_msg;
|
||||
extern const pb_msgdesc_t Measurements_msg;
|
||||
extern const pb_msgdesc_t KeepAliveLo_msg;
|
||||
extern const pb_msgdesc_t ResetDone_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define LoToHi_fields &LoToHi_msg
|
||||
#define Event_fields &Event_msg
|
||||
#define Measurements_fields &Measurements_msg
|
||||
#define KeepAliveLo_fields &KeepAliveLo_msg
|
||||
#define ResetDone_fields &ResetDone_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define Event_size 2
|
||||
#define KeepAliveLo_size 106
|
||||
#define LoToHi_size 108
|
||||
#define Measurements_size 23
|
||||
#define ResetDone_size 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
syntax = "proto3";
|
||||
|
||||
/*
|
||||
This container message is send from Lo Level to Hi level and may contain any allowed message in that direction.
|
||||
*/
|
||||
message LoToHi {
|
||||
oneof payload {
|
||||
// Common Packets
|
||||
KeepAliveLo keep_alive = 3;
|
||||
ResetDone reset_done = 7;
|
||||
// Packets only available in control_mode = 2 (low level control)
|
||||
Event event = 6;
|
||||
// HIL packets
|
||||
Measurements measurements = 5;
|
||||
}
|
||||
}
|
||||
|
||||
message Event {
|
||||
enum InterfaceEvent {
|
||||
A = 0;
|
||||
B = 1;
|
||||
C = 2;
|
||||
D = 3;
|
||||
E = 4;
|
||||
F = 5;
|
||||
EF = 6;
|
||||
DISCONNECTED = 8;
|
||||
ERROR_RELAIS = 9;
|
||||
RELAIS_ON = 10;
|
||||
RELAIS_OFF = 11;
|
||||
}
|
||||
InterfaceEvent type = 1;
|
||||
}
|
||||
|
||||
message Measurements {
|
||||
float pwmDutyCycle = 1;
|
||||
float evse_pwm_voltage_hi = 2;
|
||||
float evse_pwm_voltage_lo = 3;
|
||||
bool evse_pwm_running = 4;
|
||||
uint32 relais_on = 5;
|
||||
}
|
||||
|
||||
message KeepAliveLo {
|
||||
uint32 time_stamp = 1;
|
||||
uint32 hw_type = 2;
|
||||
uint32 hw_revision = 3;
|
||||
uint32 protocol_version_major = 4;
|
||||
uint32 protocol_version_minor = 5;
|
||||
string sw_version_string = 6;
|
||||
float hwcap_max_current = 7;
|
||||
float hwcap_min_current = 8;
|
||||
uint32 hwcap_max_phase_count = 9;
|
||||
uint32 hwcap_min_phase_count = 10;
|
||||
bool supports_changing_phases_during_charging = 11;
|
||||
}
|
||||
|
||||
message ResetDone {
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
description: Driver module for EV side for the YETI hardware
|
||||
config:
|
||||
serial_port:
|
||||
description: Serial port the Yeti hardware is connected to
|
||||
type: string
|
||||
default: /dev/ttyUSB0
|
||||
baud_rate:
|
||||
description: Serial baud rate to use when communicating with Yeti hardware
|
||||
type: integer
|
||||
minimum: 9600
|
||||
maximum: 230400
|
||||
default: 115200
|
||||
reset_gpio:
|
||||
description: Reset GPIO number to use to HW reset Yeti. If set <0 it is disabled.
|
||||
type: integer
|
||||
minimum: -1
|
||||
maximum: 1000
|
||||
default: -1
|
||||
provides:
|
||||
ev_board_support:
|
||||
interface: ev_board_support
|
||||
description: provides the board support Interface to low level control control pilot, relais, rcd
|
||||
enable_telemetry: true
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Cornelius Claussen
|
||||
- Sebastian Lukas
|
||||
- Piet Gömpel
|
||||
@@ -0,0 +1,154 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
|
||||
// Portions (c) 2025 Analog Devices Inc.
|
||||
#include "AdAcEvse22KwzKitBSP.hpp"
|
||||
#include <fmt/core.h>
|
||||
#include <utils/date.hpp>
|
||||
|
||||
namespace module {
|
||||
|
||||
void AdAcEvse22KwzKitBSP::init() {
|
||||
|
||||
// initialize serial driver
|
||||
if (!serial.openDevice(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;
|
||||
}
|
||||
|
||||
telemetry_power_path_controller_version = {{"timestamp", ""},
|
||||
{"type", "power_path_controller_version"},
|
||||
{"hardware_version", 1},
|
||||
{"software_version", "1.00"},
|
||||
{"date_manufactured", "N/A"},
|
||||
{"operating_time_h", 5},
|
||||
{"operating_time_h_warning", 5000},
|
||||
{"operating_time_h_error", 6000},
|
||||
{"software_version", "1.00"},
|
||||
{"error", false}};
|
||||
|
||||
telemetry_power_path_controller = {{"timestamp", ""},
|
||||
{"type", "power_path_controller"},
|
||||
{"cp_voltage_high", 0.0},
|
||||
{"cp_voltage_low", 0.0},
|
||||
{"cp_pwm_duty_cycle", 0.0},
|
||||
{"cp_state", "A1"},
|
||||
{"pp_ohm", 0.0},
|
||||
{"supply_voltage_12V", 0.0},
|
||||
{"supply_voltage_minus_12V", 0.0},
|
||||
{"temperature_controller", 0.0},
|
||||
{"temperature_car_connector", 0.0},
|
||||
{"watchdog_reset_count", 0.0},
|
||||
{"error", false}};
|
||||
|
||||
telemetry_power_switch = {{"timestamp", ""},
|
||||
{"type", "power_switch"},
|
||||
{"switching_count", 0},
|
||||
{"switching_count_warning", 30000},
|
||||
{"switching_count_error", 50000},
|
||||
{"is_on", false},
|
||||
{"time_to_switch_on_ms", 100},
|
||||
{"time_to_switch_off_ms", 100},
|
||||
{"temperature_C", 0.0},
|
||||
{"error", false},
|
||||
{"error_over_current", false}};
|
||||
|
||||
telemetry_rcd = {{"timestamp", ""}, //
|
||||
{"type", "rcd"}, //
|
||||
{"enabled", true}, //
|
||||
{"current_mA", 0.0}, //
|
||||
{"triggered", false}, //
|
||||
{"error", false}}; //
|
||||
|
||||
invoke_init(*p_powermeter);
|
||||
invoke_init(*p_board_support);
|
||||
}
|
||||
|
||||
void AdAcEvse22KwzKitBSP::ready() {
|
||||
serial.run();
|
||||
|
||||
if (!serial.reset(config.reset_gpio_chip, config.reset_gpio)) {
|
||||
EVLOG_error << "AD-ACEVSE22KWZ-KIT reset not successful.";
|
||||
}
|
||||
|
||||
serial.signalSpuriousReset.connect([this]() { EVLOG_error << "AD-ACEVSE22KWZ-KIT spurious reset!"; });
|
||||
serial.signalConnectionTimeout.connect([this]() { EVLOG_error << "AD-ACEVSE22KWZ-KIT UART timeout!"; });
|
||||
|
||||
invoke_ready(*p_powermeter);
|
||||
invoke_ready(*p_board_support);
|
||||
|
||||
telemetryThreadHandle = std::thread([this]() {
|
||||
while (!telemetryThreadHandle.shouldExit()) {
|
||||
sleep(10);
|
||||
{
|
||||
std::scoped_lock lock(telemetry_mutex);
|
||||
publish_external_telemetry_livedata("power_path_controller", telemetry_power_path_controller);
|
||||
publish_external_telemetry_livedata("rcd", telemetry_rcd);
|
||||
publish_external_telemetry_livedata("power_path_controller_version",
|
||||
telemetry_power_path_controller_version);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
serial.signalErrorFlags.connect([this](ErrorFlags e) { error_handling(e); });
|
||||
|
||||
if (not serial.is_open()) {
|
||||
auto err = p_board_support->error_factory->create_error("evse_board_support/CommunicationFault", "",
|
||||
"Could not open serial port.");
|
||||
p_board_support->raise_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
void AdAcEvse22KwzKitBSP::publish_external_telemetry_livedata(const std::string& topic,
|
||||
const Everest::TelemetryMap& data) {
|
||||
if (info.telemetry_enabled) {
|
||||
telemetry.publish("livedata", topic, data);
|
||||
}
|
||||
}
|
||||
|
||||
bool cp_signal_fault;
|
||||
|
||||
void AdAcEvse22KwzKitBSP::clear_errors_on_unplug() {
|
||||
if (error_MREC2GroundFailure) {
|
||||
p_board_support->clear_error("evse_board_support/MREC2GroundFailure");
|
||||
}
|
||||
error_MREC2GroundFailure = false;
|
||||
}
|
||||
|
||||
void AdAcEvse22KwzKitBSP::error_handling(ErrorFlags e) {
|
||||
|
||||
if (e.diode_fault and not last_error_flags.diode_fault) {
|
||||
Everest::error::Error error_object = p_board_support->error_factory->create_error(
|
||||
"evse_board_support/DiodeFault", "", "Diode Fault", Everest::error::Severity::High);
|
||||
p_board_support->raise_error(error_object);
|
||||
} else if (not e.diode_fault and last_error_flags.diode_fault) {
|
||||
p_board_support->clear_error("evse_board_support/DiodeFault");
|
||||
}
|
||||
|
||||
if (e.rcd_triggered and not last_error_flags.rcd_triggered) {
|
||||
Everest::error::Error error_object = p_board_support->error_factory->create_error(
|
||||
"evse_board_support/MREC2GroundFailure", "", "Onboard RCD triggered", Everest::error::Severity::High);
|
||||
p_board_support->raise_error(error_object);
|
||||
error_MREC2GroundFailure = true;
|
||||
}
|
||||
|
||||
if (e.ventilation_not_available and not last_error_flags.ventilation_not_available) {
|
||||
Everest::error::Error error_object =
|
||||
p_board_support->error_factory->create_error("evse_board_support/VentilationNotAvailable", "",
|
||||
"State D is not supported", Everest::error::Severity::High);
|
||||
p_board_support->raise_error(error_object);
|
||||
} else if (not e.ventilation_not_available and last_error_flags.ventilation_not_available) {
|
||||
p_board_support->clear_error("evse_board_support/VentilationNotAvailable");
|
||||
}
|
||||
|
||||
if (e.cp_signal_fault and not last_error_flags.cp_signal_fault) {
|
||||
Everest::error::Error error_object = p_board_support->error_factory->create_error(
|
||||
"evse_board_support/MREC14PilotFault", "", "CP error", Everest::error::Severity::High);
|
||||
p_board_support->raise_error(error_object);
|
||||
} else if (not e.cp_signal_fault and last_error_flags.cp_signal_fault) {
|
||||
p_board_support->clear_error("evse_board_support/MREC14PilotFault");
|
||||
}
|
||||
|
||||
last_error_flags = e;
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef AD_AC_EVSE22KWZ_KIT_BSP_HPP
|
||||
#define AD_AC_EVSE22KWZ_KIT_BSP_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/evse_board_support/Implementation.hpp>
|
||||
#include <generated/interfaces/powermeter/Implementation.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
#include "adkit_comms/evSerial.hpp"
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
std::string serial_port;
|
||||
int baud_rate;
|
||||
std::string reset_gpio_chip;
|
||||
int reset_gpio;
|
||||
int caps_min_current_A;
|
||||
int caps_max_current_A;
|
||||
};
|
||||
|
||||
class AdAcEvse22KwzKitBSP : public Everest::ModuleBase {
|
||||
public:
|
||||
AdAcEvse22KwzKitBSP() = delete;
|
||||
AdAcEvse22KwzKitBSP(const ModuleInfo& info, Everest::TelemetryProvider& telemetry,
|
||||
std::unique_ptr<powermeterImplBase> p_powermeter,
|
||||
std::unique_ptr<evse_board_supportImplBase> p_board_support, Conf& config) :
|
||||
ModuleBase(info),
|
||||
telemetry(telemetry),
|
||||
p_powermeter(std::move(p_powermeter)),
|
||||
p_board_support(std::move(p_board_support)),
|
||||
config(config){};
|
||||
|
||||
Everest::TelemetryProvider& telemetry;
|
||||
const std::unique_ptr<powermeterImplBase> p_powermeter;
|
||||
const std::unique_ptr<evse_board_supportImplBase> p_board_support;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
void publish_external_telemetry_livedata(const std::string& topic, const Everest::TelemetryMap& data);
|
||||
evSerial serial;
|
||||
void clear_errors_on_unplug();
|
||||
// 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
|
||||
Everest::TelemetryMap telemetry_power_path_controller_version;
|
||||
Everest::TelemetryMap telemetry_power_path_controller;
|
||||
Everest::TelemetryMap telemetry_power_switch;
|
||||
Everest::TelemetryMap telemetry_rcd;
|
||||
std::mutex telemetry_mutex;
|
||||
Everest::Thread telemetryThreadHandle;
|
||||
void error_handling(ErrorFlags e);
|
||||
ErrorFlags last_error_flags;
|
||||
|
||||
std::atomic_bool error_MREC2GroundFailure{false};
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
Everest::json power_meter_data_to_json(const PowerMeter& p);
|
||||
Everest::json keep_alive_lo_to_json(const KeepAliveLo& k);
|
||||
std::string error_type_to_string(ErrorFlags s);
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // AD_AC_EVSE22KWZ_KIT_BSP_HPP
|
||||
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# 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
|
||||
add_subdirectory(adkit_comms)
|
||||
|
||||
target_include_directories(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"common"
|
||||
"adkit_comms"
|
||||
"adkit_comms/nanopb"
|
||||
"adkit_comms/protobuf"
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
Pal::Sigslot
|
||||
adkit_comms
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"powermeter/powermeterImpl.cpp"
|
||||
"board_support/evse_board_supportImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,33 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# set the project name
|
||||
project(adkit_comms VERSION 0.1)
|
||||
# specify the C++ standard
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
# add the executable
|
||||
add_library(adkit_comms STATIC)
|
||||
ev_register_library_target(adkit_comms)
|
||||
|
||||
target_sources(adkit_comms
|
||||
PRIVATE
|
||||
evSerial.cpp
|
||||
protobuf/adkit.pb.c
|
||||
)
|
||||
|
||||
target_include_directories(adkit_comms
|
||||
PUBLIC
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
protobuf
|
||||
)
|
||||
|
||||
target_link_libraries(adkit_comms
|
||||
PUBLIC
|
||||
date::date-tz
|
||||
everest::nanopb
|
||||
PRIVATE
|
||||
Pal::Sigslot
|
||||
everest::framework
|
||||
everest::gpio
|
||||
)
|
||||
@@ -0,0 +1,387 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
|
||||
// Portions (c) 2025 Analog Devices Inc.
|
||||
#include "evSerial.hpp"
|
||||
|
||||
#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/gpio/gpio.hpp>
|
||||
|
||||
#include "adkit.pb.h"
|
||||
|
||||
evSerial::evSerial() {
|
||||
fd = 0;
|
||||
baud = 0;
|
||||
reset_done_flag = false;
|
||||
forced_reset = false;
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
evSerial::~evSerial() {
|
||||
if (fd)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool evSerial::openDevice(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);
|
||||
cobsDecodeReset();
|
||||
|
||||
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 setSerialAttributes();
|
||||
}
|
||||
|
||||
bool evSerial::setSerialAttributes() {
|
||||
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;
|
||||
}
|
||||
// printf ("Success setting tcsetattr\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void evSerial::cobsDecodeReset() {
|
||||
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;
|
||||
}
|
||||
// printf("%X",crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void evSerial::handlePacket(uint8_t* buf, int len) {
|
||||
// printf ("packet received len %u\n", len);
|
||||
|
||||
// Check CRC32 (last 4 bytes)
|
||||
// uint32_t crc = calculateCrc(rx_packet_buf, rx_packet_len);
|
||||
if (crc32(buf, len)) {
|
||||
printf("CRC mismatch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
|
||||
McuToEverest msg_in;
|
||||
pb_istream_t istream = pb_istream_from_buffer(buf, len);
|
||||
|
||||
if (pb_decode(&istream, McuToEverest_fields, &msg_in))
|
||||
switch (msg_in.which_payload) {
|
||||
|
||||
case McuToEverest_keep_alive_tag:
|
||||
// detect connection timeout if keep_alive packets stop coming...
|
||||
last_timeout_detection_timestamp = date::utc_clock::now();
|
||||
signalKeepAliveLo(msg_in.payload.keep_alive);
|
||||
break;
|
||||
case McuToEverest_power_meter_tag: {
|
||||
auto unix_timestamp = std::chrono::seconds(std::time(NULL));
|
||||
msg_in.payload.power_meter.time_stamp = unix_timestamp.count();
|
||||
signalPowerMeter(msg_in.payload.power_meter);
|
||||
} break;
|
||||
case McuToEverest_cp_state_tag:
|
||||
signalCPState(msg_in.payload.cp_state);
|
||||
break;
|
||||
case McuToEverest_pp_state_tag:
|
||||
signalPPState(msg_in.payload.pp_state);
|
||||
break;
|
||||
case McuToEverest_relais_state_tag:
|
||||
signalRelaisState(msg_in.payload.relais_state);
|
||||
break;
|
||||
case McuToEverest_error_flags_tag:
|
||||
signalErrorFlags(msg_in.payload.error_flags);
|
||||
break;
|
||||
case McuToEverest_reset_tag:
|
||||
// reset keep alive so that timeouts don't occur upon reset during initial start up
|
||||
last_timeout_detection_timestamp = date::utc_clock::now();
|
||||
reset_done_flag = true;
|
||||
if (!forced_reset)
|
||||
signalSpuriousReset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void evSerial::cobsDecode(uint8_t* buf, int len) {
|
||||
for (int i = 0; i < len; i++)
|
||||
cobsDecodeByte(buf[i]);
|
||||
}
|
||||
|
||||
void evSerial::cobsDecodeByte(uint8_t byte) {
|
||||
// check max length
|
||||
if ((decode - msg == 2048 - 1) && byte != 0x00) {
|
||||
printf("cobsDecode: Buffer overflow\n");
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
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");
|
||||
cobsDecodeReset();
|
||||
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
|
||||
handlePacket(msg, decode - 1 - msg);
|
||||
}
|
||||
cobsDecodeReset();
|
||||
return; // need to return here, because of block--
|
||||
}
|
||||
}
|
||||
block--;
|
||||
}
|
||||
|
||||
void evSerial::run() {
|
||||
readThreadHandle = std::thread(&evSerial::readThread, this);
|
||||
timeoutDetectionThreadHandle = std::thread(&evSerial::timeoutDetectionThread, this);
|
||||
}
|
||||
|
||||
void evSerial::timeoutDetectionThread() {
|
||||
while (true) {
|
||||
sleep(1);
|
||||
if (timeoutDetectionThreadHandle.shouldExit())
|
||||
break;
|
||||
if (serial_timed_out())
|
||||
signalConnectionTimeout();
|
||||
}
|
||||
}
|
||||
|
||||
void evSerial::readThread() {
|
||||
uint8_t buf[2048];
|
||||
int n;
|
||||
|
||||
cobsDecodeReset();
|
||||
while (true) {
|
||||
if (readThreadHandle.shouldExit())
|
||||
break;
|
||||
if (fd > 0) {
|
||||
n = read(fd, buf, sizeof buf);
|
||||
cobsDecode(buf, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool evSerial::linkWrite(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 = cobsEncode(tx_packet_buf, tx_payload_len, encode_buf);
|
||||
// std::cout << "Write "<<tx_encode_len<<" bytes to serial port." << std::endl;
|
||||
write(fd, encode_buf, tx_encode_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t evSerial::cobsEncode(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 timeSinceLastKeepAlive =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(now - last_timeout_detection_timestamp).count();
|
||||
if (timeSinceLastKeepAlive >= 5000)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void evSerial::setPWM(uint32_t dc) {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_pwm_duty_cycle_tag;
|
||||
msg_out.payload.pwm_duty_cycle = dc;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::allowPowerOn(bool p) {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_allow_power_on_tag;
|
||||
msg_out.payload.allow_power_on = p;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
bool evSerial::reset(const std::string& reset_chip, const int reset_line) {
|
||||
|
||||
reset_done_flag = false;
|
||||
forced_reset = true;
|
||||
|
||||
if (not reset_chip.empty()) {
|
||||
// Try to hardware reset AD-ACEVSE22KWZ-KIT controller to be in a known state
|
||||
Everest::Gpio reset_gpio;
|
||||
reset_gpio.open(reset_chip, reset_line);
|
||||
reset_gpio.set_output(true);
|
||||
reset_gpio.set(true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
reset_gpio.set(false);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
reset_gpio.set(true);
|
||||
} else {
|
||||
// Try to soft reset AD-ACEVSE22KWZ-KIT controller to be in a known state
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_reset_tag;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
// Wait for reset done message from uC
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (reset_done_flag) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
// Reset flag to detect run time spurious resets of uC from now on
|
||||
reset_done_flag = false;
|
||||
forced_reset = false;
|
||||
|
||||
// send some dummy packets to resync COBS etc.
|
||||
keepAlive();
|
||||
keepAlive();
|
||||
keepAlive();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void evSerial::keepAlive() {
|
||||
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");
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
|
||||
// Portions (c) 2025 Analog Devices Inc.
|
||||
#ifndef AD_ACEVSE22KWZ_KIT_SERIAL_HPP
|
||||
#define AD_ACEVSE22KWZ_KIT_SERIAL_HPP
|
||||
|
||||
#include "adkit.pb.h"
|
||||
#include <date/date.h>
|
||||
#include <date/tz.h>
|
||||
#include <sigslot/signal.hpp>
|
||||
#include <stdint.h>
|
||||
#include <termios.h>
|
||||
#include <utils/thread.hpp>
|
||||
|
||||
class evSerial {
|
||||
|
||||
public:
|
||||
evSerial();
|
||||
~evSerial();
|
||||
|
||||
bool openDevice(const char* device, int baud);
|
||||
bool is_open() {
|
||||
return fd > 0;
|
||||
};
|
||||
|
||||
void readThread();
|
||||
void run();
|
||||
|
||||
bool reset(const std::string& reset_chip, const int reset_line);
|
||||
void keepAlive();
|
||||
|
||||
void setPWM(uint32_t dc);
|
||||
void allowPowerOn(bool p);
|
||||
|
||||
sigslot::signal<KeepAliveLo> signalKeepAliveLo;
|
||||
sigslot::signal<PowerMeter> signalPowerMeter;
|
||||
sigslot::signal<CpState> signalCPState;
|
||||
sigslot::signal<PpState> signalPPState;
|
||||
sigslot::signal<ErrorFlags> signalErrorFlags;
|
||||
sigslot::signal<bool> signalRelaisState;
|
||||
|
||||
sigslot::signal<> signalSpuriousReset;
|
||||
sigslot::signal<> signalConnectionTimeout;
|
||||
|
||||
private:
|
||||
// Serial interface
|
||||
bool setSerialAttributes();
|
||||
int fd;
|
||||
int baud;
|
||||
|
||||
// COBS de-/encoder
|
||||
void cobsDecodeReset();
|
||||
void handlePacket(uint8_t* buf, int len);
|
||||
void cobsDecode(uint8_t* buf, int len);
|
||||
void cobsDecodeByte(uint8_t byte);
|
||||
size_t cobsEncode(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 readThreadHandle;
|
||||
Everest::Thread timeoutDetectionThreadHandle;
|
||||
|
||||
bool linkWrite(EverestToMcu* m);
|
||||
volatile bool reset_done_flag;
|
||||
volatile bool forced_reset;
|
||||
|
||||
bool serial_timed_out();
|
||||
void timeoutDetectionThread();
|
||||
std::chrono::time_point<date::utc_clock> last_timeout_detection_timestamp;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
KeepAlive.sw_version_string max_length:50
|
||||
KeepAliveLo.sw_version_string max_length:50
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.8 */
|
||||
|
||||
#include "adkit.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(EverestToMcu, EverestToMcu, 2)
|
||||
|
||||
|
||||
PB_BIND(McuToEverest, McuToEverest, 2)
|
||||
|
||||
|
||||
PB_BIND(ErrorFlags, ErrorFlags, AUTO)
|
||||
|
||||
|
||||
PB_BIND(KeepAliveLo, KeepAliveLo, AUTO)
|
||||
|
||||
|
||||
PB_BIND(KeepAlive, KeepAlive, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Telemetry, Telemetry, AUTO)
|
||||
|
||||
|
||||
PB_BIND(PowerMeter, PowerMeter, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.8 */
|
||||
|
||||
#ifndef PB_ADKIT_PB_H_INCLUDED
|
||||
#define PB_ADKIT_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;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _ErrorFlags {
|
||||
bool diode_fault;
|
||||
bool rcd_selftest_failed;
|
||||
bool rcd_triggered;
|
||||
bool ventilation_not_available;
|
||||
bool cp_signal_fault;
|
||||
bool over_current;
|
||||
} ErrorFlags;
|
||||
|
||||
typedef struct _KeepAliveLo {
|
||||
uint32_t time_stamp;
|
||||
uint32_t hw_type;
|
||||
uint32_t hw_revision;
|
||||
uint32_t protocol_version_major;
|
||||
uint32_t protocol_version_minor;
|
||||
char sw_version_string[51];
|
||||
float hwcap_max_current;
|
||||
float hwcap_min_current;
|
||||
uint32_t hwcap_max_phase_count;
|
||||
uint32_t hwcap_min_phase_count;
|
||||
bool supports_changing_phases_during_charging;
|
||||
} KeepAliveLo;
|
||||
|
||||
typedef struct _KeepAlive {
|
||||
uint32_t time_stamp;
|
||||
uint32_t hw_type;
|
||||
uint32_t hw_revision;
|
||||
char sw_version_string[51];
|
||||
} KeepAlive;
|
||||
|
||||
/* 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;
|
||||
uint32_t pwm_duty_cycle; /* in 0.01 %, 0 = State F, 10000 = X1 */
|
||||
bool allow_power_on;
|
||||
bool reset;
|
||||
} payload;
|
||||
} EverestToMcu;
|
||||
|
||||
typedef struct _Telemetry {
|
||||
uint32_t cp_voltage_hi;
|
||||
uint32_t cp_voltage_lo;
|
||||
} Telemetry;
|
||||
|
||||
typedef struct _PowerMeter {
|
||||
uint32_t time_stamp;
|
||||
float vrmsL1;
|
||||
float vrmsL2;
|
||||
float vrmsL3;
|
||||
float irmsL1;
|
||||
float irmsL2;
|
||||
float irmsL3;
|
||||
float irmsN;
|
||||
float wattHrL1;
|
||||
float wattHrL2;
|
||||
float wattHrL3;
|
||||
float totalWattHr;
|
||||
float tempL1;
|
||||
float tempL2;
|
||||
float tempL3;
|
||||
float tempN;
|
||||
float wattL1;
|
||||
float wattL2;
|
||||
float wattL3;
|
||||
float freqL1;
|
||||
float freqL2;
|
||||
float freqL3;
|
||||
bool phaseSeqError;
|
||||
} PowerMeter;
|
||||
|
||||
/* 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 {
|
||||
KeepAliveLo keep_alive;
|
||||
ResetReason reset;
|
||||
CpState cp_state;
|
||||
bool relais_state; /* false: relais are off, true: relais are on */
|
||||
ErrorFlags error_flags;
|
||||
Telemetry telemetry;
|
||||
PpState pp_state;
|
||||
PowerMeter power_meter;
|
||||
} payload;
|
||||
} McuToEverest;
|
||||
|
||||
|
||||
#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 McuToEverest_payload_reset_ENUMTYPE ResetReason
|
||||
#define McuToEverest_payload_cp_state_ENUMTYPE CpState
|
||||
#define McuToEverest_payload_pp_state_ENUMTYPE PpState
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define EverestToMcu_init_default {0, {KeepAlive_init_default}}
|
||||
#define McuToEverest_init_default {0, {KeepAliveLo_init_default}}
|
||||
#define ErrorFlags_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define KeepAliveLo_init_default {0, 0, 0, 0, 0, "", 0, 0, 0, 0, 0}
|
||||
#define KeepAlive_init_default {0, 0, 0, ""}
|
||||
#define Telemetry_init_default {0, 0}
|
||||
#define PowerMeter_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define EverestToMcu_init_zero {0, {KeepAlive_init_zero}}
|
||||
#define McuToEverest_init_zero {0, {KeepAliveLo_init_zero}}
|
||||
#define ErrorFlags_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define KeepAliveLo_init_zero {0, 0, 0, 0, 0, "", 0, 0, 0, 0, 0}
|
||||
#define KeepAlive_init_zero {0, 0, 0, ""}
|
||||
#define Telemetry_init_zero {0, 0}
|
||||
#define PowerMeter_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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_cp_signal_fault_tag 6
|
||||
#define ErrorFlags_over_current_tag 7
|
||||
#define KeepAliveLo_time_stamp_tag 1
|
||||
#define KeepAliveLo_hw_type_tag 2
|
||||
#define KeepAliveLo_hw_revision_tag 3
|
||||
#define KeepAliveLo_protocol_version_major_tag 4
|
||||
#define KeepAliveLo_protocol_version_minor_tag 5
|
||||
#define KeepAliveLo_sw_version_string_tag 6
|
||||
#define KeepAliveLo_hwcap_max_current_tag 7
|
||||
#define KeepAliveLo_hwcap_min_current_tag 8
|
||||
#define KeepAliveLo_hwcap_max_phase_count_tag 9
|
||||
#define KeepAliveLo_hwcap_min_phase_count_tag 10
|
||||
#define KeepAliveLo_supports_changing_phases_during_charging_tag 11
|
||||
#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 EverestToMcu_keep_alive_tag 100
|
||||
#define EverestToMcu_pwm_duty_cycle_tag 103
|
||||
#define EverestToMcu_allow_power_on_tag 104
|
||||
#define EverestToMcu_reset_tag 105
|
||||
#define Telemetry_cp_voltage_hi_tag 1
|
||||
#define Telemetry_cp_voltage_lo_tag 2
|
||||
#define PowerMeter_time_stamp_tag 1
|
||||
#define PowerMeter_vrmsL1_tag 2
|
||||
#define PowerMeter_vrmsL2_tag 3
|
||||
#define PowerMeter_vrmsL3_tag 4
|
||||
#define PowerMeter_irmsL1_tag 5
|
||||
#define PowerMeter_irmsL2_tag 6
|
||||
#define PowerMeter_irmsL3_tag 7
|
||||
#define PowerMeter_irmsN_tag 8
|
||||
#define PowerMeter_wattHrL1_tag 9
|
||||
#define PowerMeter_wattHrL2_tag 10
|
||||
#define PowerMeter_wattHrL3_tag 11
|
||||
#define PowerMeter_totalWattHr_tag 12
|
||||
#define PowerMeter_tempL1_tag 13
|
||||
#define PowerMeter_tempL2_tag 14
|
||||
#define PowerMeter_tempL3_tag 15
|
||||
#define PowerMeter_tempN_tag 16
|
||||
#define PowerMeter_wattL1_tag 17
|
||||
#define PowerMeter_wattL2_tag 18
|
||||
#define PowerMeter_wattL3_tag 19
|
||||
#define PowerMeter_freqL1_tag 20
|
||||
#define PowerMeter_freqL2_tag 21
|
||||
#define PowerMeter_freqL3_tag 22
|
||||
#define PowerMeter_phaseSeqError_tag 23
|
||||
#define McuToEverest_keep_alive_tag 3
|
||||
#define McuToEverest_reset_tag 101
|
||||
#define McuToEverest_cp_state_tag 102
|
||||
#define McuToEverest_relais_state_tag 103
|
||||
#define McuToEverest_error_flags_tag 104
|
||||
#define McuToEverest_telemetry_tag 105
|
||||
#define McuToEverest_pp_state_tag 106
|
||||
#define McuToEverest_power_meter_tag 108
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define EverestToMcu_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 100) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,pwm_duty_cycle,payload.pwm_duty_cycle), 103) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,allow_power_on,payload.allow_power_on), 104) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,reset,payload.reset), 105)
|
||||
#define EverestToMcu_CALLBACK NULL
|
||||
#define EverestToMcu_DEFAULT NULL
|
||||
#define EverestToMcu_payload_keep_alive_MSGTYPE KeepAlive
|
||||
|
||||
#define McuToEverest_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 3) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,reset,payload.reset), 101) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,cp_state,payload.cp_state), 102) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,relais_state,payload.relais_state), 103) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,error_flags,payload.error_flags), 104) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,telemetry,payload.telemetry), 105) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,pp_state,payload.pp_state), 106) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,power_meter,payload.power_meter), 108)
|
||||
#define McuToEverest_CALLBACK NULL
|
||||
#define McuToEverest_DEFAULT NULL
|
||||
#define McuToEverest_payload_keep_alive_MSGTYPE KeepAliveLo
|
||||
#define McuToEverest_payload_error_flags_MSGTYPE ErrorFlags
|
||||
#define McuToEverest_payload_telemetry_MSGTYPE Telemetry
|
||||
#define McuToEverest_payload_power_meter_MSGTYPE PowerMeter
|
||||
|
||||
#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, cp_signal_fault, 6) \
|
||||
X(a, STATIC, SINGULAR, BOOL, over_current, 7)
|
||||
#define ErrorFlags_CALLBACK NULL
|
||||
#define ErrorFlags_DEFAULT NULL
|
||||
|
||||
#define KeepAliveLo_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, UINT32, protocol_version_major, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, protocol_version_minor, 5) \
|
||||
X(a, STATIC, SINGULAR, STRING, sw_version_string, 6) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, hwcap_max_current, 7) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, hwcap_min_current, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hwcap_max_phase_count, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hwcap_min_phase_count, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, supports_changing_phases_during_charging, 11)
|
||||
#define KeepAliveLo_CALLBACK NULL
|
||||
#define KeepAliveLo_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)
|
||||
#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 PowerMeter_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, time_stamp, 1) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, vrmsL1, 2) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, vrmsL2, 3) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, vrmsL3, 4) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsL1, 5) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsL2, 6) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsL3, 7) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsN, 8) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattHrL1, 9) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattHrL2, 10) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattHrL3, 11) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, totalWattHr, 12) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempL1, 13) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempL2, 14) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempL3, 15) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempN, 16) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattL1, 17) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattL2, 18) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattL3, 19) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, freqL1, 20) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, freqL2, 21) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, freqL3, 22) \
|
||||
X(a, STATIC, SINGULAR, BOOL, phaseSeqError, 23)
|
||||
#define PowerMeter_CALLBACK NULL
|
||||
#define PowerMeter_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 KeepAliveLo_msg;
|
||||
extern const pb_msgdesc_t KeepAlive_msg;
|
||||
extern const pb_msgdesc_t Telemetry_msg;
|
||||
extern const pb_msgdesc_t PowerMeter_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 KeepAliveLo_fields &KeepAliveLo_msg
|
||||
#define KeepAlive_fields &KeepAlive_msg
|
||||
#define Telemetry_fields &Telemetry_msg
|
||||
#define PowerMeter_fields &PowerMeter_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ADKIT_PB_H_MAX_SIZE McuToEverest_size
|
||||
#define ErrorFlags_size 12
|
||||
#define EverestToMcu_size 73
|
||||
#define KeepAliveLo_size 106
|
||||
#define KeepAlive_size 70
|
||||
#define McuToEverest_size 124
|
||||
#define PowerMeter_size 121
|
||||
#define Telemetry_size 12
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
syntax = "proto3";
|
||||
|
||||
/*
|
||||
This container message is send from EVerest to MCU and may contain any allowed message in that direction.
|
||||
*/
|
||||
message EverestToMcu {
|
||||
// Please keep IDs and don't use reserved IDs to maintain support with older firmware versions
|
||||
reserved 16, 102, 106;
|
||||
|
||||
oneof payload {
|
||||
KeepAlive keep_alive = 100;
|
||||
uint32 pwm_duty_cycle = 103; // in 0.01 %, 0 = State F, 10000 = X1
|
||||
bool allow_power_on = 104;
|
||||
bool reset = 105;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This container message is send from MCU to EVerest and may contain any allowed message in that direction.
|
||||
*/
|
||||
message McuToEverest {
|
||||
// Please keep IDs and don't use reserved IDs to maintain support with older firmware versions
|
||||
reserved 107;
|
||||
|
||||
oneof payload {
|
||||
KeepAliveLo keep_alive = 3;
|
||||
|
||||
ResetReason reset = 101;
|
||||
CpState cp_state = 102;
|
||||
bool relais_state = 103; // false: relais are off, true: relais are on
|
||||
ErrorFlags error_flags = 104;
|
||||
Telemetry telemetry = 105;
|
||||
PpState pp_state = 106;
|
||||
PowerMeter power_meter = 108;
|
||||
}
|
||||
}
|
||||
|
||||
enum CpState {
|
||||
STATE_A = 0;
|
||||
STATE_B = 1;
|
||||
STATE_C = 2;
|
||||
STATE_D = 3;
|
||||
STATE_E = 4;
|
||||
STATE_F = 5;
|
||||
}
|
||||
|
||||
message ErrorFlags {
|
||||
// Please keep IDs and don't use reserved IDs to maintain support with older firmware versions
|
||||
reserved 5;
|
||||
|
||||
bool diode_fault = 1;
|
||||
bool rcd_selftest_failed = 2;
|
||||
bool rcd_triggered = 3;
|
||||
bool ventilation_not_available = 4;
|
||||
bool cp_signal_fault = 6;
|
||||
bool over_current = 7;
|
||||
}
|
||||
|
||||
enum ResetReason {
|
||||
USER = 0;
|
||||
WATCHDOG = 1;
|
||||
}
|
||||
|
||||
message KeepAliveLo {
|
||||
uint32 time_stamp = 1;
|
||||
uint32 hw_type = 2;
|
||||
uint32 hw_revision = 3;
|
||||
uint32 protocol_version_major = 4;
|
||||
uint32 protocol_version_minor = 5;
|
||||
string sw_version_string = 6;
|
||||
float hwcap_max_current = 7;
|
||||
float hwcap_min_current = 8;
|
||||
uint32 hwcap_max_phase_count = 9;
|
||||
uint32 hwcap_min_phase_count = 10;
|
||||
bool supports_changing_phases_during_charging = 11;
|
||||
}
|
||||
|
||||
message KeepAlive {
|
||||
uint32 time_stamp = 1;
|
||||
uint32 hw_type = 2;
|
||||
uint32 hw_revision = 3;
|
||||
string sw_version_string = 6;
|
||||
}
|
||||
|
||||
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 PowerMeter {
|
||||
uint32 time_stamp = 1;
|
||||
float vrmsL1 = 2;
|
||||
float vrmsL2 = 3;
|
||||
float vrmsL3 = 4;
|
||||
float irmsL1 = 5;
|
||||
float irmsL2 = 6;
|
||||
float irmsL3 = 7;
|
||||
float irmsN = 8;
|
||||
float wattHrL1 = 9;
|
||||
float wattHrL2 = 10;
|
||||
float wattHrL3 = 11;
|
||||
float totalWattHr = 12;
|
||||
float tempL1 = 13;
|
||||
float tempL2 = 14;
|
||||
float tempL3 = 15;
|
||||
float tempN = 16;
|
||||
float wattL1 = 17;
|
||||
float wattL2 = 18;
|
||||
float wattL3 = 19;
|
||||
float freqL1 = 20;
|
||||
float freqL2 = 21;
|
||||
float freqL3 = 22;
|
||||
bool phaseSeqError = 23;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
nanopb_generator.py -L "#include <everest/3rd_party/nanopb/%s>" -I . -D . adkit.proto
|
||||
@@ -0,0 +1,200 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
// Portions (c) 2025 Analog Devices Inc.
|
||||
#include "evse_board_supportImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace board_support {
|
||||
|
||||
static types::board_support_common::BspEvent cast_event_type(CpState cp_state) {
|
||||
types::board_support_common::BspEvent event;
|
||||
switch (cp_state) {
|
||||
case CpState_STATE_A:
|
||||
event.event = types::board_support_common::Event::A;
|
||||
break;
|
||||
case CpState_STATE_B:
|
||||
event.event = types::board_support_common::Event::B;
|
||||
break;
|
||||
case CpState_STATE_C:
|
||||
event.event = types::board_support_common::Event::C;
|
||||
break;
|
||||
case CpState_STATE_D:
|
||||
event.event = types::board_support_common::Event::D;
|
||||
break;
|
||||
case CpState_STATE_E:
|
||||
event.event = types::board_support_common::Event::E;
|
||||
break;
|
||||
case CpState_STATE_F:
|
||||
event.event = types::board_support_common::Event::F;
|
||||
break;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
static types::board_support_common::BspEvent cast_event_type(bool relais_state) {
|
||||
types::board_support_common::BspEvent event;
|
||||
if (relais_state) {
|
||||
event.event = types::board_support_common::Event::PowerOn;
|
||||
} else {
|
||||
event.event = types::board_support_common::Event::PowerOff;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
static types::board_support_common::ProximityPilot cast_pp_type(PpState pp_state) {
|
||||
types::board_support_common::ProximityPilot pp;
|
||||
switch (pp_state) {
|
||||
case PpState_STATE_13A:
|
||||
pp.ampacity = types::board_support_common::Ampacity::A_13;
|
||||
break;
|
||||
case PpState_STATE_20A:
|
||||
pp.ampacity = types::board_support_common::Ampacity::A_20;
|
||||
break;
|
||||
case PpState_STATE_32A:
|
||||
pp.ampacity = types::board_support_common::Ampacity::A_32;
|
||||
break;
|
||||
case PpState_STATE_70A:
|
||||
pp.ampacity = types::board_support_common::Ampacity::A_63_3ph_70_1ph;
|
||||
break;
|
||||
case PpState_STATE_FAULT:
|
||||
pp.ampacity = types::board_support_common::Ampacity::None;
|
||||
break;
|
||||
case PpState_STATE_NC:
|
||||
pp.ampacity = types::board_support_common::Ampacity::None;
|
||||
break;
|
||||
}
|
||||
return pp;
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::init() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(capsMutex);
|
||||
|
||||
caps.min_current_A_import = 6;
|
||||
caps.max_current_A_import = 16;
|
||||
caps.min_phase_count_import = 1;
|
||||
caps.max_phase_count_import = 3;
|
||||
caps.supports_changing_phases_during_charging = false;
|
||||
caps.supports_cp_state_E = false;
|
||||
caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable;
|
||||
|
||||
caps.min_current_A_export = 6;
|
||||
caps.max_current_A_export = 16;
|
||||
caps.min_phase_count_export = 1;
|
||||
caps.max_phase_count_export = 3;
|
||||
}
|
||||
|
||||
mod->serial.signalCPState.connect([this](CpState cp_state) {
|
||||
if (cp_state not_eq last_cp_state) {
|
||||
auto event_cp_state = cast_event_type(cp_state);
|
||||
EVLOG_info << "CP state changed: "
|
||||
<< types::board_support_common::event_to_string(cast_event_type(last_cp_state).event) << " -> "
|
||||
<< types::board_support_common::event_to_string(event_cp_state.event);
|
||||
if (enabled) {
|
||||
publish_event(event_cp_state);
|
||||
}
|
||||
|
||||
if (cp_state == CpState_STATE_A) {
|
||||
mod->clear_errors_on_unplug();
|
||||
}
|
||||
last_cp_state = cp_state;
|
||||
}
|
||||
});
|
||||
mod->serial.signalRelaisState.connect([this](bool relais_state) {
|
||||
if (last_relais_state not_eq relais_state) {
|
||||
publish_event(cast_event_type(relais_state));
|
||||
last_relais_state = relais_state;
|
||||
}
|
||||
});
|
||||
|
||||
mod->serial.signalPPState.connect([this](PpState pp_state) {
|
||||
last_pp = cast_pp_type(pp_state);
|
||||
publish_ac_pp_ampacity(last_pp);
|
||||
});
|
||||
|
||||
mod->serial.signalKeepAliveLo.connect([this](KeepAliveLo l) {
|
||||
std::lock_guard<std::mutex> lock(capsMutex);
|
||||
|
||||
caps.min_current_A_import =
|
||||
(mod->config.caps_min_current_A >= 0 ? mod->config.caps_min_current_A : l.hwcap_min_current);
|
||||
caps.max_current_A_import =
|
||||
(mod->config.caps_max_current_A >= 0 ? mod->config.caps_max_current_A : l.hwcap_max_current);
|
||||
caps.min_phase_count_import = l.hwcap_min_phase_count;
|
||||
caps.max_phase_count_import = l.hwcap_max_phase_count;
|
||||
|
||||
caps.min_current_A_export =
|
||||
(mod->config.caps_min_current_A >= 0 ? mod->config.caps_min_current_A : l.hwcap_min_current);
|
||||
caps.max_current_A_export =
|
||||
(mod->config.caps_max_current_A >= 0 ? mod->config.caps_max_current_A : l.hwcap_max_current);
|
||||
caps.min_phase_count_export = l.hwcap_min_phase_count;
|
||||
caps.max_phase_count_export = l.hwcap_max_phase_count;
|
||||
|
||||
caps.supports_changing_phases_during_charging = l.supports_changing_phases_during_charging;
|
||||
if (not caps_received) {
|
||||
EVLOG_info << "AD-ACEVSE22KWZ-KIT Configuration:";
|
||||
EVLOG_info << " Hardware revision: " << l.hw_revision;
|
||||
EVLOG_info << " Firmware version: " << l.sw_version_string;
|
||||
EVLOG_info << " Current Limit: " << l.hwcap_max_current;
|
||||
}
|
||||
caps_received = true;
|
||||
});
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::ready() {
|
||||
wait_for_caps();
|
||||
{
|
||||
// Publish caps once in the beginning
|
||||
std::lock_guard<std::mutex> lock(capsMutex);
|
||||
publish_capabilities(caps);
|
||||
}
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::wait_for_caps() {
|
||||
// Wait for caps to be received at least once
|
||||
int i;
|
||||
for (i = 0; i < 50; i++) {
|
||||
if (caps_received)
|
||||
break;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
if (i == 50) {
|
||||
EVLOG_error << "Did not receive hardware capabilities from AD-ACEVSE22KWZ-KIT hardware, using defaults.";
|
||||
}
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_pwm_on(double& value) {
|
||||
mod->serial.setPWM(value * 100);
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_cp_state_X1() {
|
||||
mod->serial.setPWM(10001);
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_cp_state_F() {
|
||||
mod->serial.setPWM(0);
|
||||
}
|
||||
|
||||
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) {
|
||||
mod->serial.allowPowerOn(value.allow_power_on);
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_ac_set_overcurrent_limit_A(double& value) {
|
||||
// your code for cmd ac_set_overcurrent_limit_A goes here
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_ac_switch_three_phases_while_charging(bool& value) {
|
||||
EVLOG_warning << "AdAdEvse22KwzKitBSP doesn't support ac_switch_three_phases_while_charging, ignoring command.";
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_enable(bool& value) {
|
||||
enabled = true;
|
||||
// Publish CP state once on enable
|
||||
publish_event(cast_event_type(last_cp_state));
|
||||
}
|
||||
|
||||
} // namespace board_support
|
||||
} // namespace module
|
||||
@@ -0,0 +1,77 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BOARD_SUPPORT_EVSE_BOARD_SUPPORT_IMPL_HPP
|
||||
#define BOARD_SUPPORT_EVSE_BOARD_SUPPORT_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/evse_board_support/Implementation.hpp>
|
||||
|
||||
#include "../AdAcEvse22KwzKitBSP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace board_support {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class evse_board_supportImpl : public evse_board_supportImplBase {
|
||||
public:
|
||||
evse_board_supportImpl() = delete;
|
||||
evse_board_supportImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<AdAcEvse22KwzKitBSP>& mod,
|
||||
Conf& config) :
|
||||
evse_board_supportImplBase(ev, "board_support"), 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<AdAcEvse22KwzKitBSP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
types::evse_board_support::HardwareCapabilities caps;
|
||||
std::atomic_bool caps_received{false};
|
||||
std::mutex capsMutex;
|
||||
CpState last_cp_state{CpState::CpState_STATE_F};
|
||||
bool last_relais_state{false};
|
||||
types::board_support_common::ProximityPilot last_pp{types::board_support_common::Ampacity::None};
|
||||
void wait_for_caps();
|
||||
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 board_support
|
||||
} // namespace module
|
||||
|
||||
#endif // BOARD_SUPPORT_EVSE_BOARD_SUPPORT_IMPL_HPP
|
||||
@@ -0,0 +1,222 @@
|
||||
.. _everest_modules_handwritten_AdAcEvse22KwzKitBSP:
|
||||
|
||||
.. ************************
|
||||
.. AdAcEvse22KwzKitBSP
|
||||
.. ************************
|
||||
|
||||
The module ``AdAcEvse22KwzKitBSP`` is a board support driver for the Analog Devices
|
||||
`AD-ACEVSE22KWZ-KIT <https://www.analog.com/en/resources/evaluation-hardware-and-software/evaluation-boards-kits/ad-acevse22kwz-kit.html#eb-overview>`_
|
||||
EVSE reference design.
|
||||
|
||||
AdAcEvse22KwzKitBSP Quickstart
|
||||
==============================
|
||||
|
||||
A typical hardware setup would consist of the AD-ACEVSE22KWZ-KIT and a Raspberry Pi 4 running
|
||||
EVerest with this module. Communication between AD-ACEVSE22KWZ-KIT and the AdAcEvse22KwzKitBSP
|
||||
on the Raspberry Pi 4 is through a 3.3V TTL UART link with a default configuration of 115200 bps 8N1.
|
||||
There is also a GPIO used to reset AD-ACEVSE22KWZ-KIT from EVerest so the firmware is in a known state.
|
||||
|
||||
Hardware Connectivity
|
||||
---------------------
|
||||
|
||||
By default, AD-ACEVSE22KWZ-KIT supports the Pionix Yak board and Raspberry Pi 4 as host boards running
|
||||
EVerest.
|
||||
|
||||
The simplest way to get AD-ACEVSE22KWZ-KIT up and running with EVerest is with a Pionix Yak board. First,
|
||||
you must connect AD-ACEVSE22KWZ-KIT's P3 to Yak's J3 using a 10-wire cable. Note that using the 10-wire
|
||||
cable has Yak powered off AD-ACEVSE22KWZ-KIT's 12V supply.
|
||||
|
||||
Next, we need to add the AdAcEvse22KwzKitBSP as an active module inside the configuration YAML file
|
||||
passed to EVerest:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
active_modules:
|
||||
# ** Other EVerest modules **
|
||||
adacevse22kwz_driver:
|
||||
telemetry:
|
||||
id: 1
|
||||
config_module:
|
||||
baud_rate: 115200 # default baud rate
|
||||
reset_gpio: 27 # Yak reset GPIO pin
|
||||
serial_port: /dev/serial0 # Yak UART0 port
|
||||
connections: {}
|
||||
module: AdAcEvse22KwzKitBSP
|
||||
# ** Other EVerest modules **
|
||||
|
||||
Next, we need to link our active AdAcEvse22KwzKitBSP to EvseManager to facilitate high-level charging
|
||||
logic. This can be done by adding the following to EvseManager inside the EVerest configuration YAML:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
active_modules:
|
||||
# ** Other EVerest modules **
|
||||
evse_manager:
|
||||
config_module:
|
||||
# ** Various EvseManager configurations **
|
||||
connections:
|
||||
bsp:
|
||||
- implementation_id: board_support
|
||||
module_id: adacevse22kwz_driver
|
||||
powermeter_grid_side:
|
||||
- implementation_id: powermeter
|
||||
module_id: adacevse22kwz_driver
|
||||
module: EvseManager
|
||||
telemetry:
|
||||
id: 1
|
||||
# ** Other EVerest modules **
|
||||
|
||||
Finally, we can start EVerest. AD-ACEVSE22KWZ-KIT should now be able to communicate with EVerest
|
||||
on the Yak board using AdAcEvse22KwzKitBSP.
|
||||
|
||||
AD-ACEVSE22KWZ-KIT can also be run off a Raspberry Pi 4 by using various test points on the
|
||||
AD-ACEVSE22KWZ-KIT instead of the 10-wire cable. These test points can then be connected to
|
||||
Raspberry Pi pins which can operate as a UART link and a standard GPIO:
|
||||
|
||||
.. list-table::
|
||||
:header-rows: 1
|
||||
|
||||
* - Purpose
|
||||
- Test Point
|
||||
- RPI Pin
|
||||
* - Reset Pin
|
||||
- TP_18
|
||||
- GPIO27
|
||||
* - Host TX
|
||||
- TP_28
|
||||
- TX_D0
|
||||
* - Host RX
|
||||
- TP_41
|
||||
- RX_D0
|
||||
* - Shared ground
|
||||
- Any GND pin
|
||||
- Any GND pin
|
||||
|
||||
You can now follow the steps used for configuring EVerest on the Yak board to start EVerest
|
||||
on the Raspberry Pi.
|
||||
|
||||
Protocol
|
||||
========
|
||||
|
||||
EVerest can send commands to AD-ACEVSE22KWZ-KIT and AD-ACEVSE22KWZ-KIT publishes
|
||||
data and events back to EVerest. The packets are defined with protobuf to serialize the C structs
|
||||
into a binary representation that is transferred over the serial wire in a
|
||||
stream:
|
||||
|
||||
https://developers.google.com/protocol-buffers
|
||||
|
||||
To be able to split the stream back into packets all data is encoded using COBS
|
||||
before it is transmitted on the UART:
|
||||
|
||||
https://en.wikipedia.org/wiki/Consistent_Overhead_Byte_Stuffing
|
||||
|
||||
COBS
|
||||
----
|
||||
|
||||
COBS is implemented in ``adkit_comms/evSerial.cpp``. Whenever a new packet
|
||||
was extracted from the stream ``handlePacket()`` is called to decode protobuf
|
||||
and generate the corresponding signals.
|
||||
Other parts of the module subscribe to these signals to handle the incoming
|
||||
packets.
|
||||
|
||||
For TX ``linkWrite`` encodes the packet with COBS and outputs it to the UART.
|
||||
|
||||
Protobuf
|
||||
--------
|
||||
|
||||
The actual packet definitions are located under ``adkit_comms/protobuf``.
|
||||
|
||||
``adkit.proto`` contains all messages that can be sent by EVerest and AD-ACEVSE22KWZ-KIT.
|
||||
|
||||
Refer to these files for an up-to-date definition as they may change
|
||||
frequently.
|
||||
|
||||
To generate the C code nanopb is used:
|
||||
|
||||
``nanopb_generator -I . -D . *.proto``
|
||||
|
||||
The output should also be manually copied to AD-ACEVSE22KWZ-KIT Firmware to ensure the same
|
||||
definition is used on both sides when making changes.
|
||||
|
||||
|
||||
Modes of Operation
|
||||
-----------------------------
|
||||
|
||||
AD-ACEVSE22KWZ-KIT board operates in the following two modes:
|
||||
|
||||
``Hostless mode``: AD-ACEVSE22KWZ-KIT acts as a standalone EVSE
|
||||
and will control PWM and relay state without external influence. In this
|
||||
mode, PWM will be enabled immediately upon entering state B1 with the
|
||||
relay closing in state C2 assuming no errors occur. If an error occurs
|
||||
(i.e. RCD trigger, diode short, C1 timeout, etc.), AD-ACEVSE22KWZ-KIT
|
||||
will open the relay and disable PWM until state A1 is reentered where
|
||||
the errors will be cleared.
|
||||
|
||||
``Host-driven mode``: AD-ACEVSE22KWZ-KIT will allow EVerest to influence PWM
|
||||
and relay states. In this mode, PWM will not be enabled until an EVerest
|
||||
``PwmDutyCycle`` command is received. Similarly, the relay will not open in state
|
||||
C2 until an ``AllowPowerOn`` message is received. AD-ACEVSE22KWZ-KIT can
|
||||
override relay and PWM state in the event of an error.
|
||||
|
||||
By default, the AD-ACEVSE22KWZ-KIT operates in hostless mode until a message
|
||||
is received from the host. Additionally, all outbound messages from
|
||||
AD-ACEVSE22KWZ-KIT are sent irrespective of mode of operation. This enables
|
||||
AD-ACEVSE22KWZ-KIT evaluation without using EVerest.
|
||||
|
||||
Message types
|
||||
-------------
|
||||
AD-ACEVSE22KWZ-KIT supports the following set of messages:
|
||||
|
||||
EVerest to AD-ACEVSE22KWZ-KIT:
|
||||
______________________________
|
||||
|
||||
``AllowPowerOn(bool)``: Inform AD-ACEVSE22KWZ-KIT that it is allowed to
|
||||
switch on the power relays/contactors to the car on (true) or must switch
|
||||
off now (false). The final decision remains with AD-ACEVSE22KWZ-KIT in
|
||||
case of power on, it should only power on after all other requirements
|
||||
are met (such as RCD current is below limit, car is in CP state C etc).
|
||||
On power off, AD-ACEVSE22KWZ-KIT will switch off immediately.
|
||||
|
||||
``PwmDutyCycle(uint32)``: Set AD-ACEVSE22KWZ-KIT PWM state and duty
|
||||
cycle. PWM can be enabled at specific duty cycle by passing a value of
|
||||
1-10000, where each value corresponds to 0.0001% duty cycle (i.e. 50%
|
||||
duty cycle = 5000 passed value). AD-ACEVSE22KWZ will ignore any duty cycles
|
||||
greater than 5333 as this corresponds to the maximum duty cycle supported.
|
||||
PWM can be disabled by passing a value greater than 10000. PWM state F can
|
||||
be enabled by passing a PWM value of 0.
|
||||
|
||||
``KeepAlive(Message)``: EVerest sends this packet to AD-ACEVSE22KWZ-KIT at 1Hz.
|
||||
Currently unused by AD-ACEVSE22KWZ-KIT.
|
||||
|
||||
``Reset(bool)``: Reset AD-ACEVSE22KWZ-KIT firmware.
|
||||
|
||||
AD-ACEVSE22KWZ-KIT to EVerest
|
||||
-----------------------------
|
||||
|
||||
``CpState(enum)``: Notify EVerest of current CP state (A/B/C/D/E/F). Sent upon
|
||||
state change. AD-ACEVSE22KWZ-KIT currently doesn't support State D.
|
||||
|
||||
``RelaisState(bool)``: Notify EVerest of current relay state. Sent upon relay
|
||||
closing/opening. True corresponds to relay closed and false is sent when relay
|
||||
is open.
|
||||
|
||||
``PpState(enum)``: Notify EVerest of current PP state (NC/13A/20A/32A/70A/F).
|
||||
AD-ACEVSE22KWZ-KIT currently doesn't support PP for maximum output current
|
||||
so 32A is sent by default.
|
||||
|
||||
``PowerMeter(Message)``: Sent roughly every second when relay is closed.
|
||||
Contains all data from the ADE9178 power measurement.
|
||||
|
||||
``ErrorState(Message)``: Notify EVerest of active errors. Sent when an errors
|
||||
are set/cleared. Each error has an associated boolean value where true
|
||||
corresponds to active error and false corresponds to error not active. Currently,
|
||||
only diode faults, RCD triggered, and overcurrent are supported by
|
||||
AD-ACEVSE22KWZ-KIT.
|
||||
|
||||
``Telemetry(Message)``: Telemetry message with cp pwm high and low voltage
|
||||
values. Not currently supported by AD-ACEVSE22KWZ-KIT firmware.
|
||||
|
||||
``KeepAliveLo(Message)``: AD-ACEVSE22KWZ-KIT sends this every 3 seconds to keep
|
||||
connection online.
|
||||
|
||||
``ResetReason(enum)``: Sent once on boot of the AD-ACEVSE22KWZ-KIT firmware.
|
||||
@@ -0,0 +1,45 @@
|
||||
description: Board support package module for the AD-ACEVSE22KWZ-KIT reference design
|
||||
config:
|
||||
serial_port:
|
||||
description: Serial port the AD-ACEVSE22KWZ-KIT is connected to
|
||||
type: string
|
||||
default: /dev/ttyUSB0
|
||||
baud_rate:
|
||||
description: Serial baud rate to use when communicating with the AD-ACEVSE22KWZ-KIT
|
||||
type: integer
|
||||
minimum: 9600
|
||||
maximum: 230400
|
||||
default: 115200
|
||||
reset_gpio_chip:
|
||||
description: >-
|
||||
Reset GPIO chip to use to HW reset the AD-ACEVSE22KWZ-KIT. If set to empty string, it is disabled.
|
||||
type: string
|
||||
default: 'gpiochip0'
|
||||
reset_gpio:
|
||||
description: GPIO line to use to reset AD-ACEVSE22KWZ-KIT
|
||||
type: integer
|
||||
default: 27
|
||||
caps_min_current_A:
|
||||
description: Minimal current on AC side. For AC this is typically 6, but for HLC this can be less. -1 means use limit reported by HW.
|
||||
type: integer
|
||||
default: -1
|
||||
caps_max_current_A:
|
||||
description: Maximum current on AC side. For AC this is typically 16 or 32, but for HLC this can be less. -1 means use limit reported by HW.
|
||||
type: integer
|
||||
default: -1
|
||||
provides:
|
||||
powermeter:
|
||||
interface: powermeter
|
||||
description: provides the AD-ACEVSE22KWZ-KIT Internal Power Meter
|
||||
board_support:
|
||||
interface: evse_board_support
|
||||
description: provides the board support Interface to low level control control pilot, relais, motor lock
|
||||
enable_telemetry: true
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Cornelius Claussen
|
||||
- Kai-Uwe Hermann
|
||||
- Thilo Molitor
|
||||
- Anton Wöllert
|
||||
- Ryan Wiebe
|
||||
@@ -0,0 +1,73 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
|
||||
// Portions (c) 2025 Analog Devices Inc.
|
||||
#include "powermeterImpl.hpp"
|
||||
#include <utils/date.hpp>
|
||||
|
||||
namespace module {
|
||||
namespace powermeter {
|
||||
|
||||
static types::powermeter::Powermeter adacevse22kwzkit_to_everest(const PowerMeter& p) {
|
||||
types::powermeter::Powermeter j;
|
||||
|
||||
j.timestamp = Everest::Date::to_rfc3339(date::utc_clock::now());
|
||||
j.meter_id = "AD_ACEVSE22KWZ_KIT_POWERMETER";
|
||||
j.phase_seq_error = p.phaseSeqError;
|
||||
|
||||
j.energy_Wh_import.total = p.totalWattHr;
|
||||
j.energy_Wh_import.L1 = p.wattHrL1;
|
||||
j.energy_Wh_import.L2 = p.wattHrL2;
|
||||
j.energy_Wh_import.L3 = p.wattHrL3;
|
||||
|
||||
types::units::Power pwr;
|
||||
pwr.total = p.wattL1 + p.wattL2 + p.wattL3;
|
||||
pwr.L1 = p.wattL1;
|
||||
pwr.L2 = p.wattL2;
|
||||
pwr.L3 = p.wattL3;
|
||||
j.power_W = pwr;
|
||||
|
||||
types::units::Voltage volt;
|
||||
volt.L1 = p.vrmsL1;
|
||||
volt.L2 = p.vrmsL2;
|
||||
volt.L3 = p.vrmsL3;
|
||||
j.voltage_V = volt;
|
||||
|
||||
types::units::Current amp;
|
||||
amp.L1 = p.irmsL1;
|
||||
amp.L2 = p.irmsL2;
|
||||
amp.L3 = p.irmsL3;
|
||||
amp.N = p.irmsN;
|
||||
j.current_A = amp;
|
||||
|
||||
types::units::Frequency freq;
|
||||
freq.L1 = p.freqL1;
|
||||
freq.L2 = p.freqL2;
|
||||
freq.L3 = p.freqL3;
|
||||
j.frequency_Hz = freq;
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
void powermeterImpl::init() {
|
||||
mod->serial.signalPowerMeter.connect(
|
||||
[this](const PowerMeter& p) { publish_powermeter(adacevse22kwzkit_to_everest(p)); });
|
||||
}
|
||||
|
||||
void powermeterImpl::ready() {
|
||||
}
|
||||
|
||||
types::powermeter::TransactionStopResponse powermeterImpl::handle_stop_transaction(std::string& transaction_id) {
|
||||
return {types::powermeter::TransactionRequestStatus::NOT_SUPPORTED,
|
||||
{},
|
||||
{},
|
||||
"AdAcEvse22KwzKitBSP powermeter does not support the stop_transaction command"};
|
||||
};
|
||||
|
||||
types::powermeter::TransactionStartResponse
|
||||
powermeterImpl::handle_start_transaction(types::powermeter::TransactionReq& value) {
|
||||
return {types::powermeter::TransactionRequestStatus::NOT_SUPPORTED,
|
||||
"AdAcEvse22KwzKitBSP powermeter does not support the start_transaction command"};
|
||||
}
|
||||
|
||||
} // namespace powermeter
|
||||
} // namespace module
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef POWERMETER_POWERMETER_IMPL_HPP
|
||||
#define POWERMETER_POWERMETER_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/powermeter/Implementation.hpp>
|
||||
|
||||
#include "../AdAcEvse22KwzKitBSP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace powermeter {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class powermeterImpl : public powermeterImplBase {
|
||||
public:
|
||||
powermeterImpl() = delete;
|
||||
powermeterImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<AdAcEvse22KwzKitBSP>& mod, Conf& config) :
|
||||
powermeterImplBase(ev, "powermeter"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual types::powermeter::TransactionStartResponse
|
||||
handle_start_transaction(types::powermeter::TransactionReq& value) override;
|
||||
virtual types::powermeter::TransactionStopResponse handle_stop_transaction(std::string& transaction_id) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<AdAcEvse22KwzKitBSP>& 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 powermeter
|
||||
} // namespace module
|
||||
|
||||
#endif // POWERMETER_POWERMETER_IMPL_HPP
|
||||
@@ -0,0 +1,5 @@
|
||||
ev_add_module(AdAcEvse22KwzKitBSP)
|
||||
ev_add_module(MicroMegaWattBSP)
|
||||
ev_add_module(PhyVersoBSP)
|
||||
ev_add_module(TIDA010939)
|
||||
ev_add_module(YetiDriver)
|
||||
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# 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
|
||||
add_subdirectory(umwc_comms)
|
||||
add_subdirectory(umwc_fwupdate)
|
||||
|
||||
target_include_directories(${MODULE_NAME}
|
||||
PRIVATE
|
||||
umwc_comms
|
||||
umwc_comms/protobuf
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
Pal::Sigslot
|
||||
umwc_comms
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"dc_supply/power_supply_DCImpl.cpp"
|
||||
"powermeter/powermeterImpl.cpp"
|
||||
"board_support/evse_board_supportImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "MicroMegaWattBSP.hpp"
|
||||
|
||||
namespace module {
|
||||
|
||||
void MicroMegaWattBSP::init() {
|
||||
// initialize serial driver
|
||||
if (!serial.openDevice(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;
|
||||
}
|
||||
|
||||
invoke_init(*p_board_support);
|
||||
invoke_init(*p_dc_supply);
|
||||
invoke_init(*p_powermeter);
|
||||
}
|
||||
|
||||
void MicroMegaWattBSP::ready() {
|
||||
serial.run();
|
||||
|
||||
if (not config.reset_gpio_chip.empty()) {
|
||||
EVLOG_info << "Perform HW reset with gpio chip " << config.reset_gpio_chip << " line " << config.reset_gpio;
|
||||
if (!serial.reset(config.reset_gpio_chip, config.reset_gpio)) {
|
||||
EVLOG_error << "uMWC reset not successful.";
|
||||
}
|
||||
}
|
||||
|
||||
serial.signalSpuriousReset.connect([this]() { EVLOG_warning << "uMWC uC spurious reset!"; });
|
||||
serial.signalConnectionTimeout.connect([this]() { EVLOG_warning << "uMWC UART timeout!"; });
|
||||
|
||||
serial.signalTelemetry.connect([this](Telemetry t) {
|
||||
mqtt.publish("everest_external/umwc/cp_hi", t.cp_hi);
|
||||
mqtt.publish("everest_external/umwc/cp_lo", t.cp_lo);
|
||||
mqtt.publish("everest_external/umwc/pwm_dc", t.pwm_dc);
|
||||
mqtt.publish("everest_external/umwc/relais_on", t.relais_on);
|
||||
mqtt.publish("everest_external/umwc/output_voltage", t.voltage);
|
||||
});
|
||||
|
||||
invoke_ready(*p_board_support);
|
||||
invoke_ready(*p_dc_supply);
|
||||
invoke_ready(*p_powermeter);
|
||||
|
||||
if (not serial.is_open()) {
|
||||
auto err = p_board_support->error_factory->create_error("evse_board_support/CommunicationFault", "",
|
||||
"Could not open serial port.");
|
||||
p_board_support->raise_error(err);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,80 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef MICRO_MEGA_WATT_BSP_HPP
|
||||
#define MICRO_MEGA_WATT_BSP_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/evse_board_support/Implementation.hpp>
|
||||
#include <generated/interfaces/power_supply_DC/Implementation.hpp>
|
||||
#include <generated/interfaces/powermeter/Implementation.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
#include "umwc_comms/evSerial.h"
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
std::string serial_port;
|
||||
int baud_rate;
|
||||
std::string reset_gpio_chip;
|
||||
int reset_gpio;
|
||||
int dc_max_voltage;
|
||||
int connector_id;
|
||||
};
|
||||
|
||||
class MicroMegaWattBSP : public Everest::ModuleBase {
|
||||
public:
|
||||
MicroMegaWattBSP() = delete;
|
||||
MicroMegaWattBSP(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider,
|
||||
std::unique_ptr<power_supply_DCImplBase> p_dc_supply,
|
||||
std::unique_ptr<powermeterImplBase> p_powermeter,
|
||||
std::unique_ptr<evse_board_supportImplBase> p_board_support, Conf& config) :
|
||||
ModuleBase(info),
|
||||
mqtt(mqtt_provider),
|
||||
p_dc_supply(std::move(p_dc_supply)),
|
||||
p_powermeter(std::move(p_powermeter)),
|
||||
p_board_support(std::move(p_board_support)),
|
||||
config(config){};
|
||||
|
||||
Everest::MqttProvider& mqtt;
|
||||
const std::unique_ptr<power_supply_DCImplBase> p_dc_supply;
|
||||
const std::unique_ptr<powermeterImplBase> p_powermeter;
|
||||
const std::unique_ptr<evse_board_supportImplBase> p_board_support;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
evSerial serial;
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // MICRO_MEGA_WATT_BSP_HPP
|
||||
@@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "evse_board_supportImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace board_support {
|
||||
static types::board_support_common::BspEvent cast_event_type(CpState cp_state) {
|
||||
types::board_support_common::BspEvent event;
|
||||
switch (cp_state) {
|
||||
case CpState_STATE_A:
|
||||
event.event = types::board_support_common::Event::A;
|
||||
break;
|
||||
case CpState_STATE_B:
|
||||
event.event = types::board_support_common::Event::B;
|
||||
break;
|
||||
case CpState_STATE_C:
|
||||
event.event = types::board_support_common::Event::C;
|
||||
break;
|
||||
case CpState_STATE_D:
|
||||
event.event = types::board_support_common::Event::D;
|
||||
break;
|
||||
case CpState_STATE_E:
|
||||
event.event = types::board_support_common::Event::E;
|
||||
break;
|
||||
case CpState_STATE_F:
|
||||
event.event = types::board_support_common::Event::F;
|
||||
break;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
static types::board_support_common::BspEvent cast_event_type(bool relais_state) {
|
||||
types::board_support_common::BspEvent event;
|
||||
if (relais_state) {
|
||||
event.event = types::board_support_common::Event::PowerOn;
|
||||
} else {
|
||||
event.event = types::board_support_common::Event::PowerOff;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::init() {
|
||||
{
|
||||
std::scoped_lock lock(capsMutex);
|
||||
|
||||
caps.min_current_A_import = 0;
|
||||
caps.max_current_A_import = 100;
|
||||
caps.min_phase_count_import = 1;
|
||||
caps.max_phase_count_import = 3;
|
||||
caps.supports_changing_phases_during_charging = false;
|
||||
caps.supports_cp_state_E = false;
|
||||
caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable;
|
||||
|
||||
caps.min_current_A_export = 0;
|
||||
caps.max_current_A_export = 100;
|
||||
caps.min_phase_count_export = 1;
|
||||
caps.max_phase_count_export = 3;
|
||||
}
|
||||
|
||||
mod->serial.signalKeepAliveLo.connect([this](KeepAliveLo l) {
|
||||
if (not keep_alive_printed) {
|
||||
EVLOG_info << "uMWC Controller Configuration:";
|
||||
EVLOG_info << " Hardware revision: " << l.hw_revision;
|
||||
EVLOG_info << " Firmware version: " << l.sw_version_string;
|
||||
}
|
||||
keep_alive_printed = true;
|
||||
});
|
||||
|
||||
mod->serial.signalCPState.connect([this](CpState cp_state) {
|
||||
if (cp_state not_eq last_cp_state) {
|
||||
auto event_cp_state = cast_event_type(cp_state);
|
||||
EVLOG_info << "CP state changed: " << types::board_support_common::event_to_string(event_cp_state.event);
|
||||
publish_event(event_cp_state);
|
||||
last_cp_state = cp_state;
|
||||
|
||||
if (cp_state == CpState::CpState_STATE_A) {
|
||||
if (error_state_monitor->is_error_active("evse_board_support/MREC8EmergencyStop", "")) {
|
||||
clear_error("evse_board_support/MREC8EmergencyStop");
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mod->serial.signalRelaisState.connect([this](bool relais_state) {
|
||||
if (last_relais_state not_eq relais_state) {
|
||||
publish_event(cast_event_type(relais_state));
|
||||
last_relais_state = relais_state;
|
||||
}
|
||||
});
|
||||
|
||||
mod->mqtt.subscribe(fmt::format("everest_external/nodered/{}/cmd/emergency_stop", mod->config.connector_id),
|
||||
[this](const std::string& data) {
|
||||
types::evse_manager::StopTransactionRequest request;
|
||||
request.reason = types::evse_manager::StopTransactionReason::EmergencyStop;
|
||||
mod->p_board_support->publish_request_stop_transaction(request);
|
||||
Everest::error::Error error_object = error_factory->create_error(
|
||||
"evse_board_support/MREC8EmergencyStop", "", "Emergency stop button pushed by user",
|
||||
Everest::error::Severity::High);
|
||||
raise_error(error_object);
|
||||
});
|
||||
|
||||
mod->mqtt.subscribe(fmt::format("everest_external/nodered/{}/cmd/evse_utility_int", mod->config.connector_id),
|
||||
[this](const std::string& data) {
|
||||
types::evse_manager::StopTransactionRequest request;
|
||||
request.reason = types::evse_manager::StopTransactionReason::PowerLoss;
|
||||
mod->p_board_support->publish_request_stop_transaction(request);
|
||||
});
|
||||
|
||||
mod->mqtt.subscribe(fmt::format("everest_external/nodered/{}/cmd/stop_transaction", mod->config.connector_id),
|
||||
[this](const std::string& data) {
|
||||
types::evse_manager::StopTransactionRequest request;
|
||||
request.reason = types::evse_manager::StopTransactionReason::Local;
|
||||
mod->p_board_support->publish_request_stop_transaction(request);
|
||||
});
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::ready() {
|
||||
{
|
||||
// Publish caps once in the beginning
|
||||
std::scoped_lock lock(capsMutex);
|
||||
publish_capabilities(caps);
|
||||
}
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_enable(bool& value) {
|
||||
mod->serial.enable(value);
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_pwm_on(double& value) {
|
||||
mod->serial.setPWM(value * 100);
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_cp_state_X1() {
|
||||
mod->serial.setPWM(10001.);
|
||||
}
|
||||
|
||||
void evse_board_supportImpl::handle_cp_state_F() {
|
||||
mod->serial.setPWM(0);
|
||||
}
|
||||
|
||||
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) {
|
||||
mod->serial.allowPowerOn(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 board_support
|
||||
} // namespace module
|
||||
@@ -0,0 +1,74 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef BOARD_SUPPORT_EVSE_BOARD_SUPPORT_IMPL_HPP
|
||||
#define BOARD_SUPPORT_EVSE_BOARD_SUPPORT_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/evse_board_support/Implementation.hpp>
|
||||
|
||||
#include "../MicroMegaWattBSP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace board_support {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class evse_board_supportImpl : public evse_board_supportImplBase {
|
||||
public:
|
||||
evse_board_supportImpl() = delete;
|
||||
evse_board_supportImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<MicroMegaWattBSP>& mod,
|
||||
Conf& config) :
|
||||
evse_board_supportImplBase(ev, "board_support"), 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<MicroMegaWattBSP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
types::evse_board_support::HardwareCapabilities caps;
|
||||
std::mutex capsMutex;
|
||||
std::atomic_bool keep_alive_printed{false};
|
||||
CpState last_cp_state{CpState::CpState_STATE_E};
|
||||
bool last_relais_state{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 board_support
|
||||
} // namespace module
|
||||
|
||||
#endif // BOARD_SUPPORT_EVSE_BOARD_SUPPORT_IMPL_HPP
|
||||
@@ -0,0 +1,103 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "power_supply_DCImpl.hpp"
|
||||
#include <fmt/core.h>
|
||||
|
||||
namespace module {
|
||||
namespace dc_supply {
|
||||
|
||||
void power_supply_DCImpl::init() {
|
||||
mod->serial.signalTelemetry.connect([this](Telemetry t) {
|
||||
types::power_supply_DC::VoltageCurrent vc;
|
||||
vc.current_A = 0;
|
||||
vc.voltage_V = t.voltage;
|
||||
publish_voltage_current(vc);
|
||||
|
||||
types::powermeter::Powermeter p;
|
||||
p.timestamp = Everest::Date::to_rfc3339(date::utc_clock::now());
|
||||
p.meter_id = "UMWC";
|
||||
types::units::Energy e;
|
||||
e.total = 0.;
|
||||
p.energy_Wh_import = e;
|
||||
types::units::Voltage v;
|
||||
v.DC = t.voltage;
|
||||
p.voltage_V = v;
|
||||
mod->p_powermeter->publish_powermeter(p);
|
||||
});
|
||||
|
||||
std::thread([this]() {
|
||||
float low_pass_voltage = 0.;
|
||||
|
||||
float last_low_pass_voltage = -1;
|
||||
|
||||
while (true) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
// prevent overshoot
|
||||
if (low_pass_voltage > req_voltage) {
|
||||
// step down immediately
|
||||
low_pass_voltage = req_voltage;
|
||||
} else {
|
||||
float delta = req_voltage - low_pass_voltage;
|
||||
if (delta > 500) {
|
||||
low_pass_voltage += 100;
|
||||
} else {
|
||||
if (delta > 50) {
|
||||
low_pass_voltage += 25;
|
||||
} else {
|
||||
low_pass_voltage = req_voltage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (not is_on) {
|
||||
low_pass_voltage = 0.;
|
||||
}
|
||||
|
||||
if (last_low_pass_voltage not_eq low_pass_voltage) {
|
||||
mod->serial.setOutputVoltageCurrent(low_pass_voltage, 0.);
|
||||
}
|
||||
|
||||
last_low_pass_voltage = low_pass_voltage;
|
||||
}
|
||||
}).detach();
|
||||
}
|
||||
|
||||
void power_supply_DCImpl::ready() {
|
||||
types::power_supply_DC::Capabilities caps;
|
||||
caps.bidirectional = false;
|
||||
caps.conversion_efficiency_export = 0.9;
|
||||
caps.max_export_current_A = 25;
|
||||
caps.max_export_voltage_V = mod->config.dc_max_voltage;
|
||||
caps.min_export_current_A = 0;
|
||||
caps.min_export_voltage_V = 50;
|
||||
caps.max_export_power_W = 10000;
|
||||
caps.current_regulation_tolerance_A = 1;
|
||||
caps.peak_current_ripple_A = 0;
|
||||
|
||||
publish_capabilities(caps);
|
||||
}
|
||||
|
||||
void power_supply_DCImpl::handle_setMode(types::power_supply_DC::Mode& mode,
|
||||
types::power_supply_DC::ChargingPhase& phase) {
|
||||
// your code for cmd setMode goes here
|
||||
if (mode == types::power_supply_DC::Mode::Export) {
|
||||
mod->serial.setOutputVoltageCurrent(req_voltage, req_current);
|
||||
is_on = true;
|
||||
} else {
|
||||
mod->serial.setOutputVoltageCurrent(0, 0);
|
||||
is_on = false;
|
||||
}
|
||||
};
|
||||
|
||||
void power_supply_DCImpl::handle_setExportVoltageCurrent(double& voltage, double& current) {
|
||||
req_voltage = voltage;
|
||||
req_current = current;
|
||||
};
|
||||
|
||||
void power_supply_DCImpl::handle_setImportVoltageCurrent(double& voltage, double& current){
|
||||
// not supported here
|
||||
};
|
||||
|
||||
} // namespace dc_supply
|
||||
} // namespace module
|
||||
@@ -0,0 +1,67 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef DC_SUPPLY_POWER_SUPPLY_DC_IMPL_HPP
|
||||
#define DC_SUPPLY_POWER_SUPPLY_DC_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/power_supply_DC/Implementation.hpp>
|
||||
|
||||
#include "../MicroMegaWattBSP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace dc_supply {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class power_supply_DCImpl : public power_supply_DCImplBase {
|
||||
public:
|
||||
power_supply_DCImpl() = delete;
|
||||
power_supply_DCImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<MicroMegaWattBSP>& mod, Conf& config) :
|
||||
power_supply_DCImplBase(ev, "dc_supply"), 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_setMode(types::power_supply_DC::Mode& mode,
|
||||
types::power_supply_DC::ChargingPhase& phase) override;
|
||||
virtual void handle_setExportVoltageCurrent(double& voltage, double& current) override;
|
||||
virtual void handle_setImportVoltageCurrent(double& voltage, double& current) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<MicroMegaWattBSP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
std::atomic<float> req_voltage{0};
|
||||
std::atomic<float> req_current{0};
|
||||
std::atomic_bool is_on{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 dc_supply
|
||||
} // namespace module
|
||||
|
||||
#endif // DC_SUPPLY_POWER_SUPPLY_DC_IMPL_HPP
|
||||
@@ -0,0 +1,46 @@
|
||||
description: Driver module for the Micro Mega Watt DC Charging Tester v1.0
|
||||
config:
|
||||
serial_port:
|
||||
description: Serial port the uMWC hardware is connected to
|
||||
type: string
|
||||
default: /dev/ttyUSB0
|
||||
baud_rate:
|
||||
description: Serial baud rate to use when communicating with uMWC hardware
|
||||
type: integer
|
||||
minimum: 9600
|
||||
maximum: 230400
|
||||
default: 115200
|
||||
reset_gpio_chip:
|
||||
description: >-
|
||||
Reset GPIO chip to use to HW reset uMWC. If set to empty string, it is disabled.
|
||||
type: string
|
||||
default: 'gpiochip0'
|
||||
reset_gpio:
|
||||
description: GPIO line to use to reset uMWC
|
||||
type: integer
|
||||
default: 27
|
||||
dc_max_voltage:
|
||||
description: Maximum voltage to support
|
||||
type: integer
|
||||
minimum: 50
|
||||
maximum: 1000
|
||||
default: 1000
|
||||
connector_id:
|
||||
description: Connector id
|
||||
type: integer
|
||||
default: 1
|
||||
provides:
|
||||
dc_supply:
|
||||
interface: power_supply_DC
|
||||
description: Interface for the DC/DC output supply
|
||||
powermeter:
|
||||
interface: powermeter
|
||||
description: Interface for the powermeter
|
||||
board_support:
|
||||
interface: evse_board_support
|
||||
description: provides the board support Interface to low level control control pilot, relais, rcd, motor lock
|
||||
enable_external_mqtt: true
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Cornelius Claussen
|
||||
@@ -0,0 +1,30 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "powermeterImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace powermeter {
|
||||
|
||||
void powermeterImpl::init() {
|
||||
}
|
||||
|
||||
void powermeterImpl::ready() {
|
||||
}
|
||||
|
||||
types::powermeter::TransactionStartResponse
|
||||
powermeterImpl::handle_start_transaction(types::powermeter::TransactionReq& value) {
|
||||
// your code for cmd start_transaction goes here
|
||||
return {types::powermeter::TransactionRequestStatus::NOT_SUPPORTED,
|
||||
"MicroMegaWattBSP powermeter does not support the start_transaction command"};
|
||||
}
|
||||
|
||||
types::powermeter::TransactionStopResponse powermeterImpl::handle_stop_transaction(std::string& transaction_id) {
|
||||
return {types::powermeter::TransactionRequestStatus::NOT_SUPPORTED,
|
||||
{},
|
||||
{},
|
||||
"MicroMegaWattBSP powermeter does not support the stop_transaction command"};
|
||||
}
|
||||
|
||||
} // namespace powermeter
|
||||
} // namespace module
|
||||
@@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef POWERMETER_POWERMETER_IMPL_HPP
|
||||
#define POWERMETER_POWERMETER_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/powermeter/Implementation.hpp>
|
||||
|
||||
#include "../MicroMegaWattBSP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace powermeter {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class powermeterImpl : public powermeterImplBase {
|
||||
public:
|
||||
powermeterImpl() = delete;
|
||||
powermeterImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<MicroMegaWattBSP>& mod, Conf& config) :
|
||||
powermeterImplBase(ev, "powermeter"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual types::powermeter::TransactionStartResponse
|
||||
handle_start_transaction(types::powermeter::TransactionReq& value) override;
|
||||
virtual types::powermeter::TransactionStopResponse handle_stop_transaction(std::string& transaction_id) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<MicroMegaWattBSP>& 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 powermeter
|
||||
} // namespace module
|
||||
|
||||
#endif // POWERMETER_POWERMETER_IMPL_HPP
|
||||
@@ -0,0 +1,36 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# set the project name
|
||||
project(umwc_comms VERSION 0.1)
|
||||
# specify the C++ standard
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# add the executable
|
||||
add_library(umwc_comms STATIC)
|
||||
ev_register_library_target(umwc_comms)
|
||||
|
||||
target_sources(umwc_comms
|
||||
PRIVATE
|
||||
evSerial.cpp
|
||||
protobuf/umwc.pb.c
|
||||
)
|
||||
|
||||
target_include_directories(umwc_comms
|
||||
PUBLIC
|
||||
"${PROJECT_BINARY_DIR}"
|
||||
protobuf
|
||||
)
|
||||
|
||||
target_link_libraries(umwc_comms
|
||||
PUBLIC
|
||||
date::date-tz
|
||||
everest::nanopb
|
||||
PRIVATE
|
||||
Pal::Sigslot
|
||||
everest::framework
|
||||
everest::gpio
|
||||
)
|
||||
@@ -0,0 +1,413 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2023 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/gpio/gpio.hpp>
|
||||
|
||||
#include "umwc.pb.h"
|
||||
|
||||
evSerial::evSerial() {
|
||||
fd = 0;
|
||||
baud = 0;
|
||||
reset_done_flag = false;
|
||||
forced_reset = false;
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
evSerial::~evSerial() {
|
||||
if (fd)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
bool evSerial::openDevice(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);
|
||||
cobsDecodeReset();
|
||||
|
||||
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 setSerialAttributes();
|
||||
}
|
||||
|
||||
bool evSerial::setSerialAttributes() {
|
||||
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;
|
||||
}
|
||||
// printf ("Success setting tcsetattr\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
void evSerial::cobsDecodeReset() {
|
||||
code = 0xff;
|
||||
block = 0;
|
||||
decode = msg;
|
||||
}
|
||||
|
||||
uint32_t evSerial::crc32(uint8_t* buf, int len) {
|
||||
int i, j;
|
||||
uint32_t crc, msk;
|
||||
|
||||
i = 0;
|
||||
crc = 0xFFFFFFFF;
|
||||
while (i < len) {
|
||||
uint32_t b = buf[i];
|
||||
crc = crc ^ b;
|
||||
for (j = 7; j >= 0; j--) {
|
||||
msk = -(crc & 1);
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & msk);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
// printf("%X",crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void evSerial::handlePacket(uint8_t* buf, int len) {
|
||||
// printf ("packet received len %u\n", len);
|
||||
|
||||
// Check CRC32 (last 4 bytes)
|
||||
if (crc32(buf, len)) {
|
||||
printf("CRC mismatch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
|
||||
McuToEverest msg_in;
|
||||
pb_istream_t istream = pb_istream_from_buffer(buf, len);
|
||||
|
||||
if (pb_decode(&istream, McuToEverest_fields, &msg_in))
|
||||
switch (msg_in.which_payload) {
|
||||
|
||||
case McuToEverest_keep_alive_tag:
|
||||
// printf("Received keep_alive_lo\n");
|
||||
signalKeepAliveLo(msg_in.payload.keep_alive);
|
||||
// detect connection timeout if keep_alive packets stop coming...
|
||||
last_keep_alive_lo_timestamp = date::utc_clock::now();
|
||||
break;
|
||||
case McuToEverest_telemetry_tag:
|
||||
/*printf("Received telemetry cp_hi %f cp_lo %f relais_on %i pwm_dc %f\n", msg_in.payload.telemetry.cp_hi,
|
||||
msg_in.payload.telemetry.cp_lo, (int)msg_in.payload.telemetry.relais_on,
|
||||
msg_in.payload.telemetry.pwm_dc);*/
|
||||
signalTelemetry(msg_in.payload.telemetry);
|
||||
break;
|
||||
case McuToEverest_cp_state_tag:
|
||||
signalCPState(msg_in.payload.cp_state);
|
||||
break;
|
||||
case McuToEverest_relais_state_tag:
|
||||
signalRelaisState(msg_in.payload.relais_state);
|
||||
break;
|
||||
case McuToEverest_error_flags_tag:
|
||||
signalErrorFlags(msg_in.payload.error_flags);
|
||||
break;
|
||||
case McuToEverest_reset_tag:
|
||||
// printf("Received reset_done\n");
|
||||
reset_done_flag = true;
|
||||
if (!forced_reset)
|
||||
signalSpuriousReset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void evSerial::cobsDecode(uint8_t* buf, int len) {
|
||||
for (int i = 0; i < len; i++)
|
||||
cobsDecodeByte(buf[i]);
|
||||
}
|
||||
|
||||
void evSerial::cobsDecodeByte(uint8_t byte) {
|
||||
// check max length
|
||||
if ((decode - msg == 2048 - 1) && byte != 0x00) {
|
||||
printf("cobsDecode: Buffer overflow\n");
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
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");
|
||||
cobsDecodeReset();
|
||||
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
|
||||
handlePacket(msg, decode - 1 - msg);
|
||||
}
|
||||
cobsDecodeReset();
|
||||
return; // need to return here, because of block--
|
||||
}
|
||||
}
|
||||
block--;
|
||||
}
|
||||
|
||||
void evSerial::run() {
|
||||
readThreadHandle = std::thread(&evSerial::readThread, this);
|
||||
timeoutDetectionThreadHandle = std::thread(&evSerial::timeoutDetectionThread, this);
|
||||
}
|
||||
|
||||
void evSerial::timeoutDetectionThread() {
|
||||
while (true) {
|
||||
sleep(1);
|
||||
if (timeoutDetectionThreadHandle.shouldExit())
|
||||
break;
|
||||
if (serial_timed_out())
|
||||
signalConnectionTimeout();
|
||||
// send keep alive to LO
|
||||
keepAlive();
|
||||
}
|
||||
}
|
||||
|
||||
void evSerial::readThread() {
|
||||
uint8_t buf[2048];
|
||||
|
||||
cobsDecodeReset();
|
||||
while (true) {
|
||||
if (readThreadHandle.shouldExit())
|
||||
break;
|
||||
if (fd > 0) {
|
||||
int n = read(fd, buf, sizeof buf);
|
||||
cobsDecode(buf, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool evSerial::linkWrite(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 = cobsEncode(tx_packet_buf, tx_payload_len, encode_buf);
|
||||
// std::cout << "Write "<<tx_encode_len<<" bytes to serial port." << std::endl;
|
||||
write(fd, encode_buf, tx_encode_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t evSerial::cobsEncode(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 timeSinceLastKeepAlive =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(now - last_keep_alive_lo_timestamp).count();
|
||||
if (timeSinceLastKeepAlive >= 5000)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void evSerial::setPWM(uint32_t dc) {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_pwm_duty_cycle_tag;
|
||||
msg_out.payload.pwm_duty_cycle = dc;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::allowPowerOn(bool p) {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_allow_power_on_tag;
|
||||
msg_out.payload.allow_power_on = p;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::enable(bool en) {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_enable_tag;
|
||||
msg_out.payload.enable = en;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::replug() {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_replug_tag;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::firmwareUpdate(bool rom) {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_firmware_update_tag;
|
||||
msg_out.payload.firmware_update.invoke_rom_bootloader = rom;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void evSerial::setOutputVoltageCurrent(float v, float c) {
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_set_output_voltage_current_tag;
|
||||
msg_out.payload.set_output_voltage_current.voltage = v;
|
||||
msg_out.payload.set_output_voltage_current.current = c;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
bool evSerial::reset(const std::string& reset_chip, const int reset_line) {
|
||||
|
||||
reset_done_flag = false;
|
||||
forced_reset = true;
|
||||
|
||||
if (not reset_chip.empty()) {
|
||||
// Try to hardware reset Yeti controller to be in a known state
|
||||
Everest::Gpio reset_gpio;
|
||||
reset_gpio.open(reset_chip, reset_line);
|
||||
reset_gpio.set_output(true);
|
||||
reset_gpio.set(true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
reset_gpio.set(false);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
reset_gpio.set(true);
|
||||
} else {
|
||||
// Try to soft reset Yeti controller to be in a known state
|
||||
EverestToMcu msg_out = EverestToMcu_init_default;
|
||||
msg_out.which_payload = EverestToMcu_reset_tag;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
// Wait for reset done message from uC
|
||||
for (int i = 0; i < 20; i++) {
|
||||
if (reset_done_flag) {
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
// Reset flag to detect run time spurious resets of uC from now on
|
||||
reset_done_flag = false;
|
||||
forced_reset = false;
|
||||
|
||||
// send some dummy packets to resync COBS etc.
|
||||
keepAlive();
|
||||
keepAlive();
|
||||
keepAlive();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void evSerial::keepAlive() {
|
||||
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");
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef YETI_SERIAL
|
||||
#define YETI_SERIAL
|
||||
|
||||
#include "umwc.pb.h"
|
||||
#include <date/date.h>
|
||||
#include <date/tz.h>
|
||||
#include <sigslot/signal.hpp>
|
||||
#include <stdint.h>
|
||||
#include <termios.h>
|
||||
#include <utils/thread.hpp>
|
||||
|
||||
class evSerial {
|
||||
|
||||
public:
|
||||
evSerial();
|
||||
~evSerial();
|
||||
|
||||
bool openDevice(const char* device, int baud);
|
||||
bool is_open() {
|
||||
return fd > 0;
|
||||
};
|
||||
|
||||
void readThread();
|
||||
void run();
|
||||
|
||||
void enable(bool en);
|
||||
void disable();
|
||||
void replug();
|
||||
bool reset(const std::string& reset_chip, const int reset_line);
|
||||
void firmwareUpdate(bool rom);
|
||||
void keepAlive();
|
||||
|
||||
void setPWM(uint32_t dc);
|
||||
void allowPowerOn(bool p);
|
||||
|
||||
void setOutputVoltageCurrent(float v, float c);
|
||||
|
||||
sigslot::signal<KeepAliveLo> signalKeepAliveLo;
|
||||
sigslot::signal<Telemetry> signalTelemetry;
|
||||
|
||||
sigslot::signal<CpState> signalCPState;
|
||||
sigslot::signal<ErrorFlags> signalErrorFlags;
|
||||
sigslot::signal<bool> signalRelaisState;
|
||||
|
||||
sigslot::signal<> signalSpuriousReset;
|
||||
sigslot::signal<> signalConnectionTimeout;
|
||||
|
||||
private:
|
||||
// Serial interface
|
||||
bool setSerialAttributes();
|
||||
int fd;
|
||||
int baud;
|
||||
|
||||
// COBS de-/encoder
|
||||
void cobsDecodeReset();
|
||||
void handlePacket(uint8_t* buf, int len);
|
||||
void cobsDecode(uint8_t* buf, int len);
|
||||
void cobsDecodeByte(uint8_t byte);
|
||||
size_t cobsEncode(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 readThreadHandle;
|
||||
Everest::Thread timeoutDetectionThreadHandle;
|
||||
|
||||
bool linkWrite(EverestToMcu* m);
|
||||
volatile bool reset_done_flag;
|
||||
volatile bool forced_reset;
|
||||
|
||||
bool serial_timed_out();
|
||||
void timeoutDetectionThread();
|
||||
std::chrono::time_point<date::utc_clock> last_keep_alive_lo_timestamp;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
nanopb_generator.py -L "#include <everest/3rd_party/nanopb/%s>" -I . -D . umwc.proto
|
||||
@@ -0,0 +1,2 @@
|
||||
KeepAlive.sw_version_string max_length:50
|
||||
KeepAliveLo.sw_version_string max_length:50
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.8 */
|
||||
|
||||
#include "umwc.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(EverestToMcu, EverestToMcu, 2)
|
||||
|
||||
|
||||
PB_BIND(McuToEverest, McuToEverest, 2)
|
||||
|
||||
|
||||
PB_BIND(SetOutputVoltageCurrent, SetOutputVoltageCurrent, AUTO)
|
||||
|
||||
|
||||
PB_BIND(ErrorFlags, ErrorFlags, AUTO)
|
||||
|
||||
|
||||
PB_BIND(KeepAliveLo, KeepAliveLo, AUTO)
|
||||
|
||||
|
||||
PB_BIND(KeepAlive, KeepAlive, AUTO)
|
||||
|
||||
|
||||
PB_BIND(Telemetry, Telemetry, AUTO)
|
||||
|
||||
|
||||
PB_BIND(FirmwareUpdate, FirmwareUpdate, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.8 */
|
||||
|
||||
#ifndef PB_UMWC_PB_H_INCLUDED
|
||||
#define PB_UMWC_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;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _SetOutputVoltageCurrent {
|
||||
float voltage;
|
||||
float current;
|
||||
} SetOutputVoltageCurrent;
|
||||
|
||||
typedef struct _ErrorFlags {
|
||||
bool diode_fault;
|
||||
bool cp_signal_fault;
|
||||
} ErrorFlags;
|
||||
|
||||
typedef struct _KeepAliveLo {
|
||||
uint32_t time_stamp;
|
||||
uint32_t hw_type;
|
||||
uint32_t hw_revision;
|
||||
uint32_t protocol_version_major;
|
||||
uint32_t protocol_version_minor;
|
||||
char sw_version_string[51];
|
||||
float hwcap_max_current;
|
||||
float hwcap_min_current;
|
||||
uint32_t hwcap_max_phase_count;
|
||||
uint32_t hwcap_min_phase_count;
|
||||
bool supports_changing_phases_during_charging;
|
||||
} KeepAliveLo;
|
||||
|
||||
typedef struct _KeepAlive {
|
||||
uint32_t time_stamp;
|
||||
uint32_t hw_type;
|
||||
uint32_t hw_revision;
|
||||
char sw_version_string[51];
|
||||
} KeepAlive;
|
||||
|
||||
typedef struct _Telemetry {
|
||||
float cp_hi;
|
||||
float cp_lo;
|
||||
float pwm_dc;
|
||||
float relais_on;
|
||||
float voltage;
|
||||
} Telemetry;
|
||||
|
||||
/* 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 {
|
||||
/* Needs to remain the same to allow firmware updates of older versions */
|
||||
KeepAliveLo keep_alive;
|
||||
/* Other IDs are 100+ to avoid compatibility issues with older firmware versions */
|
||||
ResetReason reset;
|
||||
CpState cp_state;
|
||||
bool relais_state; /* false: relais are off, true: relais are on */
|
||||
ErrorFlags error_flags;
|
||||
Telemetry telemetry;
|
||||
} payload;
|
||||
} McuToEverest;
|
||||
|
||||
typedef struct _FirmwareUpdate {
|
||||
bool invoke_rom_bootloader;
|
||||
} FirmwareUpdate;
|
||||
|
||||
/* 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 {
|
||||
/* Needs to remain the same to allow firmware updates of older versions */
|
||||
FirmwareUpdate firmware_update;
|
||||
SetOutputVoltageCurrent set_output_voltage_current;
|
||||
/* Other IDs are 100+ to avoid compatibility issues with older firmware versions */
|
||||
KeepAlive keep_alive;
|
||||
uint32_t pwm_duty_cycle; /* in 0.01 %, 0 = State F, 10000 = X1 */
|
||||
bool allow_power_on;
|
||||
bool reset;
|
||||
bool enable;
|
||||
bool replug;
|
||||
} payload;
|
||||
} 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 McuToEverest_payload_reset_ENUMTYPE ResetReason
|
||||
#define McuToEverest_payload_cp_state_ENUMTYPE CpState
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define EverestToMcu_init_default {0, {FirmwareUpdate_init_default}}
|
||||
#define McuToEverest_init_default {0, {KeepAliveLo_init_default}}
|
||||
#define SetOutputVoltageCurrent_init_default {0, 0}
|
||||
#define ErrorFlags_init_default {0, 0}
|
||||
#define KeepAliveLo_init_default {0, 0, 0, 0, 0, "", 0, 0, 0, 0, 0}
|
||||
#define KeepAlive_init_default {0, 0, 0, ""}
|
||||
#define Telemetry_init_default {0, 0, 0, 0, 0}
|
||||
#define FirmwareUpdate_init_default {0}
|
||||
#define EverestToMcu_init_zero {0, {FirmwareUpdate_init_zero}}
|
||||
#define McuToEverest_init_zero {0, {KeepAliveLo_init_zero}}
|
||||
#define SetOutputVoltageCurrent_init_zero {0, 0}
|
||||
#define ErrorFlags_init_zero {0, 0}
|
||||
#define KeepAliveLo_init_zero {0, 0, 0, 0, 0, "", 0, 0, 0, 0, 0}
|
||||
#define KeepAlive_init_zero {0, 0, 0, ""}
|
||||
#define Telemetry_init_zero {0, 0, 0, 0, 0}
|
||||
#define FirmwareUpdate_init_zero {0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define SetOutputVoltageCurrent_voltage_tag 1
|
||||
#define SetOutputVoltageCurrent_current_tag 2
|
||||
#define ErrorFlags_diode_fault_tag 1
|
||||
#define ErrorFlags_cp_signal_fault_tag 6
|
||||
#define KeepAliveLo_time_stamp_tag 1
|
||||
#define KeepAliveLo_hw_type_tag 2
|
||||
#define KeepAliveLo_hw_revision_tag 3
|
||||
#define KeepAliveLo_protocol_version_major_tag 4
|
||||
#define KeepAliveLo_protocol_version_minor_tag 5
|
||||
#define KeepAliveLo_sw_version_string_tag 6
|
||||
#define KeepAliveLo_hwcap_max_current_tag 7
|
||||
#define KeepAliveLo_hwcap_min_current_tag 8
|
||||
#define KeepAliveLo_hwcap_max_phase_count_tag 9
|
||||
#define KeepAliveLo_hwcap_min_phase_count_tag 10
|
||||
#define KeepAliveLo_supports_changing_phases_during_charging_tag 11
|
||||
#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 Telemetry_cp_hi_tag 1
|
||||
#define Telemetry_cp_lo_tag 2
|
||||
#define Telemetry_pwm_dc_tag 3
|
||||
#define Telemetry_relais_on_tag 4
|
||||
#define Telemetry_voltage_tag 5
|
||||
#define McuToEverest_keep_alive_tag 3
|
||||
#define McuToEverest_reset_tag 101
|
||||
#define McuToEverest_cp_state_tag 102
|
||||
#define McuToEverest_relais_state_tag 103
|
||||
#define McuToEverest_error_flags_tag 104
|
||||
#define McuToEverest_telemetry_tag 105
|
||||
#define FirmwareUpdate_invoke_rom_bootloader_tag 1
|
||||
#define EverestToMcu_firmware_update_tag 16
|
||||
#define EverestToMcu_set_output_voltage_current_tag 50
|
||||
#define EverestToMcu_keep_alive_tag 100
|
||||
#define EverestToMcu_pwm_duty_cycle_tag 103
|
||||
#define EverestToMcu_allow_power_on_tag 104
|
||||
#define EverestToMcu_reset_tag 105
|
||||
#define EverestToMcu_enable_tag 106
|
||||
#define EverestToMcu_replug_tag 107
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define EverestToMcu_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,firmware_update,payload.firmware_update), 16) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,set_output_voltage_current,payload.set_output_voltage_current), 50) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 100) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,pwm_duty_cycle,payload.pwm_duty_cycle), 103) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,allow_power_on,payload.allow_power_on), 104) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,reset,payload.reset), 105) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,enable,payload.enable), 106) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,replug,payload.replug), 107)
|
||||
#define EverestToMcu_CALLBACK NULL
|
||||
#define EverestToMcu_DEFAULT NULL
|
||||
#define EverestToMcu_payload_firmware_update_MSGTYPE FirmwareUpdate
|
||||
#define EverestToMcu_payload_set_output_voltage_current_MSGTYPE SetOutputVoltageCurrent
|
||||
#define EverestToMcu_payload_keep_alive_MSGTYPE KeepAlive
|
||||
|
||||
#define McuToEverest_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,keep_alive,payload.keep_alive), 3) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,reset,payload.reset), 101) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,cp_state,payload.cp_state), 102) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,relais_state,payload.relais_state), 103) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,error_flags,payload.error_flags), 104) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,telemetry,payload.telemetry), 105)
|
||||
#define McuToEverest_CALLBACK NULL
|
||||
#define McuToEverest_DEFAULT NULL
|
||||
#define McuToEverest_payload_keep_alive_MSGTYPE KeepAliveLo
|
||||
#define McuToEverest_payload_error_flags_MSGTYPE ErrorFlags
|
||||
#define McuToEverest_payload_telemetry_MSGTYPE Telemetry
|
||||
|
||||
#define SetOutputVoltageCurrent_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, voltage, 1) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, current, 2)
|
||||
#define SetOutputVoltageCurrent_CALLBACK NULL
|
||||
#define SetOutputVoltageCurrent_DEFAULT NULL
|
||||
|
||||
#define ErrorFlags_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, diode_fault, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, cp_signal_fault, 6)
|
||||
#define ErrorFlags_CALLBACK NULL
|
||||
#define ErrorFlags_DEFAULT NULL
|
||||
|
||||
#define KeepAliveLo_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, UINT32, protocol_version_major, 4) \
|
||||
X(a, STATIC, SINGULAR, UINT32, protocol_version_minor, 5) \
|
||||
X(a, STATIC, SINGULAR, STRING, sw_version_string, 6) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, hwcap_max_current, 7) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, hwcap_min_current, 8) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hwcap_max_phase_count, 9) \
|
||||
X(a, STATIC, SINGULAR, UINT32, hwcap_min_phase_count, 10) \
|
||||
X(a, STATIC, SINGULAR, BOOL, supports_changing_phases_during_charging, 11)
|
||||
#define KeepAliveLo_CALLBACK NULL
|
||||
#define KeepAliveLo_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)
|
||||
#define KeepAlive_CALLBACK NULL
|
||||
#define KeepAlive_DEFAULT NULL
|
||||
|
||||
#define Telemetry_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, cp_hi, 1) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, cp_lo, 2) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, pwm_dc, 3) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, relais_on, 4) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, voltage, 5)
|
||||
#define Telemetry_CALLBACK NULL
|
||||
#define Telemetry_DEFAULT NULL
|
||||
|
||||
#define FirmwareUpdate_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, invoke_rom_bootloader, 1)
|
||||
#define FirmwareUpdate_CALLBACK NULL
|
||||
#define FirmwareUpdate_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t EverestToMcu_msg;
|
||||
extern const pb_msgdesc_t McuToEverest_msg;
|
||||
extern const pb_msgdesc_t SetOutputVoltageCurrent_msg;
|
||||
extern const pb_msgdesc_t ErrorFlags_msg;
|
||||
extern const pb_msgdesc_t KeepAliveLo_msg;
|
||||
extern const pb_msgdesc_t KeepAlive_msg;
|
||||
extern const pb_msgdesc_t Telemetry_msg;
|
||||
extern const pb_msgdesc_t FirmwareUpdate_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define EverestToMcu_fields &EverestToMcu_msg
|
||||
#define McuToEverest_fields &McuToEverest_msg
|
||||
#define SetOutputVoltageCurrent_fields &SetOutputVoltageCurrent_msg
|
||||
#define ErrorFlags_fields &ErrorFlags_msg
|
||||
#define KeepAliveLo_fields &KeepAliveLo_msg
|
||||
#define KeepAlive_fields &KeepAlive_msg
|
||||
#define Telemetry_fields &Telemetry_msg
|
||||
#define FirmwareUpdate_fields &FirmwareUpdate_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ErrorFlags_size 4
|
||||
#define EverestToMcu_size 73
|
||||
#define FirmwareUpdate_size 2
|
||||
#define KeepAliveLo_size 106
|
||||
#define KeepAlive_size 70
|
||||
#define McuToEverest_size 108
|
||||
#define SetOutputVoltageCurrent_size 10
|
||||
#define Telemetry_size 25
|
||||
#define UMWC_PB_H_MAX_SIZE McuToEverest_size
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,95 @@
|
||||
syntax = "proto3";
|
||||
|
||||
/*
|
||||
This container message is send from EVerest to MCU and may contain any allowed message in that direction.
|
||||
*/
|
||||
message EverestToMcu {
|
||||
oneof payload {
|
||||
// Needs to remain the same to allow firmware updates of older versions
|
||||
FirmwareUpdate firmware_update = 16;
|
||||
|
||||
SetOutputVoltageCurrent set_output_voltage_current = 50;
|
||||
|
||||
// Other IDs are 100+ to avoid compatibility issues with older firmware versions
|
||||
KeepAlive keep_alive = 100;
|
||||
uint32 pwm_duty_cycle = 103; // in 0.01 %, 0 = State F, 10000 = X1
|
||||
bool allow_power_on = 104;
|
||||
bool reset = 105;
|
||||
bool enable = 106;
|
||||
bool replug = 107;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This container message is send from MCU to EVerest and may contain any allowed message in that direction.
|
||||
*/
|
||||
message McuToEverest {
|
||||
oneof payload {
|
||||
// Needs to remain the same to allow firmware updates of older versions
|
||||
KeepAliveLo keep_alive = 3;
|
||||
|
||||
// Other IDs are 100+ to avoid compatibility issues with older firmware versions
|
||||
ResetReason reset = 101;
|
||||
CpState cp_state = 102;
|
||||
bool relais_state = 103; // false: relais are off, true: relais are on
|
||||
ErrorFlags error_flags = 104;
|
||||
Telemetry telemetry = 105;
|
||||
}
|
||||
}
|
||||
|
||||
enum CpState {
|
||||
STATE_A = 0;
|
||||
STATE_B = 1;
|
||||
STATE_C = 2;
|
||||
STATE_D = 3;
|
||||
STATE_E = 4;
|
||||
STATE_F = 5;
|
||||
}
|
||||
|
||||
message SetOutputVoltageCurrent {
|
||||
float voltage = 1;
|
||||
float current = 2;
|
||||
}
|
||||
|
||||
message ErrorFlags {
|
||||
bool diode_fault = 1;
|
||||
bool cp_signal_fault = 6;
|
||||
}
|
||||
|
||||
enum ResetReason {
|
||||
USER = 0;
|
||||
WATCHDOG = 1;
|
||||
}
|
||||
|
||||
message KeepAliveLo {
|
||||
uint32 time_stamp = 1;
|
||||
uint32 hw_type = 2;
|
||||
uint32 hw_revision = 3;
|
||||
uint32 protocol_version_major = 4;
|
||||
uint32 protocol_version_minor = 5;
|
||||
string sw_version_string = 6;
|
||||
float hwcap_max_current = 7;
|
||||
float hwcap_min_current = 8;
|
||||
uint32 hwcap_max_phase_count = 9;
|
||||
uint32 hwcap_min_phase_count = 10;
|
||||
bool supports_changing_phases_during_charging = 11;
|
||||
}
|
||||
|
||||
message KeepAlive {
|
||||
uint32 time_stamp = 1;
|
||||
uint32 hw_type = 2;
|
||||
uint32 hw_revision = 3;
|
||||
string sw_version_string = 6;
|
||||
}
|
||||
|
||||
message Telemetry {
|
||||
float cp_hi = 1;
|
||||
float cp_lo = 2;
|
||||
float pwm_dc = 3;
|
||||
float relais_on = 4;
|
||||
float voltage = 5;
|
||||
}
|
||||
|
||||
message FirmwareUpdate {
|
||||
bool invoke_rom_bootloader = 1;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# set the project name
|
||||
project(umwc_fwupdate VERSION 0.1)
|
||||
# specify the C++ standard
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
# add the executable
|
||||
add_executable(umwc_fwupdate main.cpp)
|
||||
target_include_directories(umwc_fwupdate PUBLIC "${PROJECT_BINARY_DIR}" PUBLIC "../umwc_comms/nanopb" PUBLIC "../umwc_comms/protobuf" PUBLIC "../umwc_comms")
|
||||
target_link_libraries(umwc_fwupdate PRIVATE Pal::Sigslot Threads::Threads umwc_comms everest::framework everest::gpio)
|
||||
|
||||
install(TARGETS umwc_fwupdate
|
||||
DESTINATION ${EVEREST_MOD_YETIDRIVER_DESTINATION})
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2021 Pionix GmbH and Contributors to EVerest
|
||||
#include "evSerial.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sigslot/signal.hpp>
|
||||
|
||||
#include "umwc.pb.h"
|
||||
#include <everest/gpio/gpio.hpp>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
volatile bool sw_version_received = false;
|
||||
|
||||
void recvKeepAliveLo(KeepAliveLo s) {
|
||||
printf("Current uMWC SW Version: %s (Protocol %i.%i)\n", s.sw_version_string, s.protocol_version_major,
|
||||
s.protocol_version_minor);
|
||||
sw_version_received = true;
|
||||
}
|
||||
|
||||
void help() {
|
||||
printf("\nUsage: ./umwc_fwupdate /dev/ttyXXX firmware.bin\n\n");
|
||||
printf("This tool uses stm32flash (version 0.6 and above) which needs to be installed.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
printf("uMWC ROM Bootloader Firmware Updater\n");
|
||||
if (argc != 3) {
|
||||
help();
|
||||
exit(0);
|
||||
}
|
||||
const char* device = argv[1];
|
||||
const char* filename = argv[2];
|
||||
|
||||
evSerial* p = new evSerial();
|
||||
|
||||
if (p->openDevice(device, 115200)) {
|
||||
// printf("Running\n");
|
||||
p->run();
|
||||
p->signalKeepAliveLo.connect(recvKeepAliveLo);
|
||||
while (true) {
|
||||
if (sw_version_received)
|
||||
break;
|
||||
std::this_thread::sleep_for(100us);
|
||||
}
|
||||
printf("\nRebooting uMWC in ROM Bootloader mode...\n");
|
||||
// send some dummy commands to make sure protocol is in sync
|
||||
p->enable(false);
|
||||
p->enable(false);
|
||||
// now reboot uC in boot loader mode
|
||||
p->firmwareUpdate(true);
|
||||
sleep(1);
|
||||
delete p;
|
||||
|
||||
sleep(1);
|
||||
// Try to hardware reset Yeti controller to be in a known state
|
||||
Everest::Gpio reset_gpio;
|
||||
reset_gpio.open("gpiochip0", 27);
|
||||
reset_gpio.set_output(true);
|
||||
reset_gpio.set(true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
reset_gpio.set(false);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
reset_gpio.set(true);
|
||||
char cmd[1000];
|
||||
sprintf(cmd, "stm32flash -b 115200 %.100s -v -w %.100s -R", device, filename);
|
||||
// sprintf(cmd, "stm32flash -b115200 %.100s", device);
|
||||
printf("Executing %s ...\n", cmd);
|
||||
system(cmd);
|
||||
|
||||
// printf ("Joining\n");
|
||||
} else {
|
||||
printf("Cannot open device \"%s\"\n", device);
|
||||
delete p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -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"],
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"conn1_motor_lock_type": 1,
|
||||
"conn2_motor_lock_type": 1,
|
||||
"reset_gpio_bank": 2
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"conn1_motor_lock_type": 2,
|
||||
"conn2_motor_lock_type": 2,
|
||||
"reset_gpio_bank": 2
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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})
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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"],
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
@@ -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 : {}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"],
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
nanopb_generator -L "#include <everest/3rd_party/nanopb/%s>" -I . -D . phyverso.proto
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user