Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,388 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#include "protocol/cb_config.h"
#include <charge_bridge/charge_bridge.hpp>
#include <charge_bridge/discovery.hpp>
#include <charge_bridge/firmware_update/sync_fw_updater.hpp>
#include <charge_bridge/gpio_bridge.hpp>
#include <charge_bridge/heartbeat_service.hpp>
#include <charge_bridge/utilities/logging.hpp>
#include <charge_bridge/utilities/print_config.hpp>
#include <charge_bridge/utilities/string.hpp>
#include <charge_bridge/utilities/sync_udp_client.hpp>
#include <everest/io/event/fd_event_sync_interface.hpp>
#include <everest/io/netlink/vcan_netlink_manager.hpp>
#include <everest/util/misc/bind.hpp>
#include <iostream>
#include <memory>
#include <thread>
namespace charge_bridge {
namespace {
std::pair<bool, std::set<std::string>> make_interface_list(std::string const& str, std::string const& pattern) {
if (str == pattern) {
return {false, {}};
};
auto raw = utilities::string_after_pattern(str, pattern).substr(1);
if (raw.size() <= 2) {
return {false, {}};
}
auto exclude = raw.substr(0, 1) == "!";
auto items = utilities::csv_to_set(raw.substr(exclude ? 1 : 0));
for (auto const& elem : items) {
std::cout << elem << ", ";
}
std::cout << std::endl;
return {exclude, items};
}
} // namespace
charge_bridge::charge_bridge(charge_bridge_config const& config) : m_config(config) {
if (utilities::string_starts_with(config.cb_remote, "ANY_EVSE")) {
auto params = make_interface_list(config.cb_remote, "ANY_EVSE");
init_discovery(discovery_device_type::CB_EVSE, params.second, params.first);
} else if (utilities::string_starts_with(config.cb_remote, "ANY_EV")) {
auto params = make_interface_list(config.cb_remote, "ANY_EV");
init_discovery(discovery_device_type::CB_EV, params.second, params.first);
} else {
init();
}
}
void charge_bridge::init_discovery(discovery_device_type type, std::set<std::string> const& interfaces,
bool excluding) {
using namespace everest::lib::util;
utilities::print_error(m_config.cb_name, "DISCOVERY", -1) << "Discovery pending" << std::endl;
m_discovery = std::make_unique<discovery>(type, interfaces, excluding);
m_discovery->set_discovery_callback(bind_obj(&charge_bridge::handle_discovery, this));
{
auto handle = m_cb_status.handle();
handle->discovery_pending = true;
}
m_cb_status.notify_one();
}
void charge_bridge::handle_discovery(std::string const& ip) {
utilities::print_error(m_config.cb_name, "DISCOVERY", 0) << "Discovered at: " + ip << std::endl;
m_config.cb_remote = ip;
if (m_config.can0) {
m_config.can0->cb_remote = ip;
}
if (m_config.serial1) {
m_config.serial1->cb_remote = ip;
}
if (m_config.serial2) {
m_config.serial2->cb_remote = ip;
}
if (m_config.serial3) {
m_config.serial3->cb_remote = ip;
}
if (m_config.plc) {
m_config.plc->cb_remote = ip;
}
if (m_config.bsp) {
m_config.bsp->cb_remote = ip;
}
if (m_config.heartbeat) {
m_config.heartbeat->cb_remote = ip;
}
if (m_config.gpio) {
m_config.gpio->cb_remote = ip;
}
m_config.firmware.cb_remote = ip;
m_event_handler->add_action([this]() {
std::unique_ptr<discovery> tmp;
std::swap(m_discovery, tmp);
init();
{
auto handle = m_cb_status.handle();
handle->discovery_pending = false;
}
m_cb_status.notify_one();
});
}
void charge_bridge::init() {
if (m_config.can0.has_value()) {
m_can_0_client = std::make_unique<can_bridge>(m_config.can0.value());
}
if (m_config.serial1.has_value()) {
m_pty_1 = std::make_unique<serial_bridge>(m_config.serial1.value());
}
if (m_config.serial2.has_value()) {
m_pty_2 = std::make_unique<serial_bridge>(m_config.serial2.value());
}
if (m_config.serial3.has_value()) {
m_pty_3 = std::make_unique<serial_bridge>(m_config.serial3.value());
}
if (m_config.plc.has_value()) {
m_plc = std::make_unique<plc_bridge>(m_config.plc.value());
}
if (m_config.bsp.has_value()) {
m_bsp = std::make_unique<bsp_bridge>(m_config.bsp.value());
}
if (m_config.heartbeat.has_value()) {
m_heartbeat = std::make_unique<heartbeat_service>(m_config.heartbeat.value(), [this](bool connected) {
{
auto handle = m_cb_status.handle();
handle->is_connected = connected;
}
m_cb_status.notify_one();
});
}
if (m_config.gpio.has_value()) {
m_gpio = std::make_unique<gpio_bridge>(m_config.gpio.value());
}
}
charge_bridge::~charge_bridge() {
m_cb_status.notify_one();
}
void charge_bridge::manage(everest::lib::io::event::fd_event_handler& handler, std::atomic_bool const& run,
bool force_update) {
using namespace std::chrono_literals;
m_event_handler = &handler;
m_force_firmware_update = force_update;
auto action = [this](bool is_connected, bool discovery_pending, int& error_count) {
if (discovery_pending) {
if (m_discovery_active) {
return;
}
m_discovery_active = true;
m_event_handler->add_action([this]() { register_events(*m_event_handler); });
return;
}
if (m_was_connected and not is_connected) {
if (error_count > 1) {
m_event_handler->add_action([this]() { unregister_events(*m_event_handler); });
m_was_connected = false;
} else {
error_count++;
}
}
if (not m_was_connected) {
if (update_firmware(m_force_firmware_update)) {
m_event_handler->add_action([this]() { register_events(*m_event_handler); });
m_was_connected = true;
error_count = 0;
}
}
};
std::thread manager([&run, action, this]() {
auto handle = m_cb_status.handle();
bool last_is_connected = handle->is_connected;
bool last_discovery_pending = handle->discovery_pending;
int error_count = 0;
auto condition = [&] {
if (handle->is_connected not_eq last_is_connected) {
return true;
}
if (handle->discovery_pending not_eq last_discovery_pending) {
return true;
}
if (not run.load()) {
return true;
}
return false;
};
while (run.load()) {
action(handle->is_connected, handle->discovery_pending, error_count);
handle.wait_for(condition, 10s);
last_is_connected = handle->is_connected;
last_discovery_pending = handle->discovery_pending;
}
});
manager.detach();
}
bool charge_bridge::update_firmware(bool force) {
firmware_update::sync_fw_updater updater(m_config.firmware);
auto is_connected = updater.quick_check_connection();
if (not is_connected) {
return false;
}
updater.print_fw_version();
auto do_update = force or (m_config.firmware.fw_update_on_start and not updater.check_if_correct_fw_installed());
if (not do_update) {
return true;
}
auto result = updater.upload_fw() && updater.check_connection();
if (not result) {
std::cout << "Error: could not install correct firmware version" << std::endl;
}
return result;
}
std::string charge_bridge::get_pty_1_slave_path() {
if (m_pty_1) {
return m_pty_1->get_slave_path();
}
return "";
}
std::string charge_bridge::get_pty_2_slave_path() {
if (m_pty_2) {
return m_pty_2->get_slave_path();
}
return "";
}
std::string charge_bridge::get_pty_3_slave_path() {
if (m_pty_3) {
return m_pty_3->get_slave_path();
}
return "";
}
bool charge_bridge::register_events(everest::lib::io::event::fd_event_handler& handler) {
auto result = true;
if (m_can_0_client) {
result = handler.register_event_handler(m_can_0_client.get()) && result;
}
if (m_pty_1) {
result = handler.register_event_handler(m_pty_1.get()) && result;
}
if (m_pty_2) {
result = handler.register_event_handler(m_pty_2.get()) && result;
}
if (m_pty_3) {
result = handler.register_event_handler(m_pty_3.get()) && result;
}
if (m_bsp) {
result = handler.register_event_handler(m_bsp.get()) && result;
}
if (m_plc) {
result = handler.register_event_handler(m_plc.get()) && result;
}
if (m_heartbeat) {
result = handler.register_event_handler(m_heartbeat.get()) && result;
}
if (m_gpio) {
result = handler.register_event_handler(m_gpio.get()) && result;
}
if (m_discovery) {
result = handler.register_event_handler(m_discovery.get()) && result;
}
return result;
}
bool charge_bridge::unregister_events(everest::lib::io::event::fd_event_handler& handler) {
auto result = true;
if (m_can_0_client) {
result = handler.unregister_event_handler(m_can_0_client.get()) && result;
}
if (m_pty_1) {
result = handler.unregister_event_handler(m_pty_1.get()) && result;
}
if (m_pty_2) {
result = handler.unregister_event_handler(m_pty_2.get()) && result;
}
if (m_pty_3) {
result = handler.unregister_event_handler(m_pty_3.get()) && result;
}
if (m_bsp) {
result = handler.unregister_event_handler(m_bsp.get()) && result;
}
if (m_plc) {
result = handler.unregister_event_handler(m_plc.get()) && result;
}
if (m_heartbeat) {
result = handler.unregister_event_handler(m_heartbeat.get()) && result;
}
if (m_gpio) {
result = handler.unregister_event_handler(m_gpio.get()) && result;
}
if (m_discovery) {
result = handler.unregister_event_handler(m_discovery.get()) && result;
}
return result;
}
void charge_bridge::print_config() {
print_charge_bridge_config(m_config);
}
void print_charge_bridge_config(charge_bridge_config const& c) {
using namespace utilities;
std::cout << "ChargeBridge: " << c.cb_name << std::endl;
std::cout << " * remote: " << c.cb_remote << std::endl;
if (c.serial1) {
std::cout << " * serial 1: " << c.serial1->serial_device;
if (c.heartbeat.has_value() && CB_NUMBER_OF_UARTS >= 1) {
std::cout << " " << to_string(c.heartbeat->cb_config.uarts[0]);
}
std::cout << std::endl;
}
if (c.serial2) {
std::cout << " * serial 2: " << c.serial2->serial_device;
if (c.heartbeat.has_value() && CB_NUMBER_OF_UARTS >= 2) {
std::cout << " " << to_string(c.heartbeat->cb_config.uarts[1]);
}
std::cout << std::endl;
}
if (c.serial3) {
std::cout << " * serial 3: " << c.serial3->serial_device;
if (c.heartbeat.has_value() && CB_NUMBER_OF_UARTS >= 3) {
std::cout << " " << to_string(c.heartbeat->cb_config.uarts[2]);
}
std::cout << std::endl;
}
if (c.can0) {
std::cout << " * can 0: " << c.can0->can_device;
if (c.heartbeat.has_value()) {
std::cout << " " << to_string(c.heartbeat->cb_config.can.baudrate) << "bps" << std::endl;
}
}
if (c.plc) {
std::cout << " * plc: " << c.plc->plc_tap << std::flush;
std::cout << " " << c.cb_remote << ":" << c.plc->cb_port;
std::cout << " adress " << c.plc->plc_ip;
std::cout << " netmask " << c.plc->plc_netmaks;
std::cout << " MTU " << c.plc->plc_mtu << std::endl;
}
if (c.bsp) {
if (c.bsp->api.evse.enabled) {
std::cout << " * evse_bsp: ";
} else if (c.bsp->api.ev.enabled) {
std::cout << " * ev_bsp: ";
}
std::cout << c.bsp->cb_remote << ":" << c.bsp->cb_port;
std::cout << " module " << c.bsp->api.evse.module_id;
std::cout << " MQTT " << c.bsp->api.mqtt_remote << ":" << c.bsp->api.mqtt_port;
if (not c.bsp->api.mqtt_bind.empty()) {
std::cout << " on " << c.bsp->api.mqtt_bind;
}
std::cout << " ping " << c.bsp->api.mqtt_ping_interval_ms << "ms";
if (c.bsp->api.ovm.enabled) {
std::cout << " OVM module " << c.bsp->api.ovm.module_id;
}
std::cout << std::endl;
}
if (c.heartbeat) {
std::cout << " * heartbeat: " << c.cb_remote << ":" << c.cb_port;
std::cout << " heartbeat interval " << c.heartbeat->interval_s << "s" << std::endl;
}
if (c.gpio) {
std::cout << " * gpio: " << c.cb_remote << ":" << c.cb_port;
std::cout << " MQTT " << c.gpio->mqtt_remote << ":" << c.gpio->mqtt_port;
if (not c.gpio->mqtt_bind.empty()) {
std::cout << " on " << c.gpio->mqtt_bind;
}
std::cout << " send interval " << c.gpio->interval_s << "s" << std::endl;
}
std::cout << "\n" << std::endl;
}
} // namespace charge_bridge