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,337 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include "evse_board_supportIntfStub.hpp"
#include <EventQueue.hpp>
#include <IECStateMachine.hpp>
#include <backtrace.hpp>
#include <chrono>
#include <gtest/gtest.h>
#include <memory>
#include <string>
#include <thread>
namespace {
using BspEvent = types::board_support_common::BspEvent;
using Event = types::board_support_common::Event;
using Reason = types::evse_board_support::Reason;
using namespace std::chrono_literals;
struct BspStub : public module::stub::ModuleAdapterStub {
typedef Result (BspStub::*bsp_fn)(Parameters p);
ValueCallback event_cb;
std::map<std::string, bsp_fn> _bsp;
BspStub() : module::stub::ModuleAdapterStub() {
_bsp["allow_power_on"] = &BspStub::call_allow_power_on;
_bsp["enable"] = &BspStub::call_enable;
_bsp["cp_state_X1"] = &BspStub::call_cp_state_X1;
_bsp["pwm_on"] = &BspStub::call_pwm_on;
}
// ------------------------------------------------------------------------
// test interface (calls from BSP)
void raise_event(Event event) {
if (event_cb != nullptr) {
BspEvent bsp_event;
bsp_event.event = event;
event_cb(bsp_event);
}
};
// ------------------------------------------------------------------------
// BSP calls
virtual Result call_allow_power_on(Parameters p) {
std::cout << "call_allow_power_on(" << p << ")" << std::endl;
return std::nullopt;
}
virtual Result call_enable(Parameters p) {
std::cout << "call_enable(" << p << ")" << std::endl;
return std::nullopt;
}
virtual Result call_cp_state_X1(Parameters p) {
std::cout << "call_cp_state_X1(" << p << ")" << std::endl;
return std::nullopt;
}
virtual Result call_pwm_on(Parameters p) {
std::cout << "call_pwm_on(" << p << ")" << std::endl;
return std::nullopt;
}
// ------------------------------------------------------------------------
// internal interface
virtual void subscribe_fn(const Requirement&, const std::string& fn, ValueCallback cb) override {
std::printf("subscribe_fn(%s)\n", fn.c_str());
event_cb = cb;
}
virtual Result call_fn(const Requirement& req, const std::string& fn, Parameters p) override {
if (auto itt = _bsp.find(fn); itt == _bsp.end()) {
std::cout << "<missing> call_fn(" << fn << "," << p << ")" << std::endl;
return std::nullopt;
} else {
return std::invoke(itt->second, this, p);
}
}
};
TEST(IECStateMachine, init) {
module::stub::ModuleAdapterStub module_adapter = module::stub::ModuleAdapterStub();
std::unique_ptr<evse_board_supportIntf> bsp_if =
std::make_unique<module::stub::evse_board_supportIntfStub>(module_adapter);
module::IECStateMachine state_machine(std::move(bsp_if), true);
}
#if 0
// test to demonstrate the output from backtrace
struct BspStubTimeout : public BspStub {
Result call_allow_power_on(Parameters p) {
std::cout << "call_allow_power_on(" << p << ")" << std::endl;
std::cout << "call_allow_power_on: sleep (" << std::this_thread::get_id() << ")" << std::endl;
std::this_thread::sleep_for(200s);
std::cout << "call_allow_power_on: finished" << std::endl;
return std::nullopt;
}
};
TEST(IECStateMachine, init_subscribe) {
#ifdef EVEREST_USE_BACKTRACES
Everest::install_backtrace_handler();
#endif
BspStubTimeout bsp;
std::unique_ptr<evse_board_supportIntf> bsp_if = std::make_unique<module::stub::evse_board_supportIntfStub>(bsp);
module::IECStateMachine state_machine(std::move(bsp_if), true);
state_machine.enable(true);
state_machine.allow_power_on(true, Reason::FullPowerCharging);
bsp.raise_event(Event::A);
bsp.raise_event(Event::B);
bsp.raise_event(Event::PowerOn);
bsp.raise_event(Event::C);
std::cout << "main: sleep (" << std::this_thread::get_id() << ")" << std::endl;
std::this_thread::sleep_for(300s);
}
#endif
struct BspStubDeadlock : public BspStub {
std::vector<std::chrono::time_point<std::chrono::steady_clock>> call_cp_state_X1_times;
std::vector<std::chrono::time_point<std::chrono::steady_clock>> call_allow_power_on_times;
int count = 0;
enum class events_t : std::uint8_t {
call_allow_power_on,
call_enable,
call_cp_state_X1,
call_pwm_on,
signal_lock,
sleeping,
};
module::EventQueue<events_t> events;
std::string to_string(module::EventQueue<events_t>::events_t e) {
std::string result;
for (const auto& i : e) {
result += std::to_string(static_cast<std::uint8_t>(i));
result += " ";
}
return result;
}
bool contains(module::EventQueue<events_t>::events_t e, events_t event) {
for (const auto& i : e) {
if (i == event) {
return true;
}
}
return false;
}
auto wait() {
return events.wait();
}
virtual Result call_allow_power_on(Parameters p) {
std::cout << "call_allow_power_on(" << p << ")" << std::endl;
call_allow_power_on_times.push_back(std::chrono::steady_clock::now());
events.push(events_t::call_allow_power_on);
return std::nullopt;
}
virtual Result call_enable(Parameters p) {
std::cout << "call_enable(" << p << ")" << std::endl;
events.push(events_t::call_enable);
return std::nullopt;
}
virtual Result call_cp_state_X1(Parameters p) {
std::cout << "call_cp_state_X1(" << p << ")" << std::endl;
call_cp_state_X1_times.push_back(std::chrono::steady_clock::now());
if (count == 2) {
std::cout << "sleeping ..." << std::endl;
events.push(events_t::sleeping);
std::this_thread::sleep_for(7s);
}
count++;
events.push(events_t::call_cp_state_X1);
return std::nullopt;
}
virtual Result call_pwm_on(Parameters p) {
std::cout << "call_pwm_on(" << p << ")" << std::endl;
events.push(events_t::call_pwm_on);
return std::nullopt;
}
auto elapsed() const {
auto last_call_cp_state_X1_time = call_cp_state_X1_times.back();
auto last_call_allow_power_on_time = call_allow_power_on_times.back();
return std::chrono::duration_cast<std::chrono::milliseconds>(last_call_allow_power_on_time -
last_call_cp_state_X1_time)
.count();
}
};
TEST(IECStateMachine, deadlock_test) {
GTEST_SKIP() << "relies on thread timing so occasionally fails";
/*
* a deadlock was caused by timeout_state_c1 timing out and
* trying to raise an event while state_machine() was running
* and wanting to stop the timer
* 61851-1 state C starts the timer (from x2)
*
* check the timer runs for 6 seconds
*/
#ifdef EVEREST_USE_BACKTRACES
Everest::install_backtrace_handler();
#endif
BspStubDeadlock bsp;
std::unique_ptr<evse_board_supportIntf> bsp_if = std::make_unique<module::stub::evse_board_supportIntfStub>(bsp);
module::IECStateMachine state_machine(std::move(bsp_if), true);
std::uint8_t signal_lock_count = 0;
state_machine.signal_lock.connect([&signal_lock_count, &bsp]() {
signal_lock_count++;
std::cout << "signal_lock" << std::endl;
// bsp.events.push(BspStubDeadlock::events_t::signal_lock);
});
state_machine.enable(true);
auto actions = bsp.wait();
ASSERT_EQ(actions.size(), 1);
ASSERT_EQ(actions[0], BspStubDeadlock::events_t::call_enable);
bsp.raise_event(Event::A);
actions = bsp.wait();
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_cp_state_X1));
bsp.raise_event(Event::B);
actions = bsp.wait();
// std::cout << bsp.to_string(actions) << std::endl;
// call_allow_power_on and/or signal_lock
// ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_allow_power_on));
state_machine.set_pwm(0.5);
actions = bsp.wait();
// std::cout << bsp.to_string(actions) << std::endl;
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_pwm_on));
state_machine.allow_power_on(true, types::evse_board_support::Reason::FullPowerCharging);
std::this_thread::sleep_for(1s);
// actions = bsp.wait();
// ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::signal_lock));
bsp.raise_event(Event::C);
actions = bsp.wait();
// std::cout << bsp.to_string(actions) << std::endl;
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_allow_power_on));
state_machine.set_cp_state_X1();
// expect state_machine to run once and then again when the
// timer expires
std::this_thread::sleep_for(8s);
auto elapsed = bsp.elapsed();
std::cout << "Elapsed: " << elapsed << std::endl;
EXPECT_GT(elapsed, 6000);
EXPECT_LT(elapsed, 6500);
}
TEST(IECStateMachine, deadlock_fix) {
GTEST_SKIP() << "relies on thread timing so occasionally fails";
/*
* a deadlock was caused by timeout_state_c1 timing out and
* trying to raise an event while state_machine() was running
* and wanting to stop the timer
* 61851-1 state C starts the timer (from X2)
*/
#ifdef EVEREST_USE_BACKTRACES
Everest::install_backtrace_handler();
#endif
BspStubDeadlock bsp;
std::unique_ptr<evse_board_supportIntf> bsp_if = std::make_unique<module::stub::evse_board_supportIntfStub>(bsp);
module::IECStateMachine state_machine(std::move(bsp_if), true);
std::uint8_t signal_lock_count = 0;
state_machine.signal_lock.connect([&signal_lock_count, &bsp]() {
signal_lock_count++;
std::cout << "signal_lock" << std::endl;
// bsp.events.push(BspStubDeadlock::events_t::signal_lock);
});
state_machine.enable(true);
auto actions = bsp.wait();
ASSERT_EQ(actions.size(), 1);
ASSERT_EQ(actions[0], BspStubDeadlock::events_t::call_enable);
bsp.raise_event(Event::A);
actions = bsp.wait();
// std::cout << bsp.to_string(actions) << std::endl;
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_cp_state_X1));
bsp.raise_event(Event::B);
actions = bsp.wait();
// call_allow_power_on and/or signal_lock
// ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_allow_power_on));
state_machine.set_pwm(0.5);
actions = bsp.wait();
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_pwm_on));
state_machine.allow_power_on(true, types::evse_board_support::Reason::FullPowerCharging);
std::this_thread::sleep_for(1s);
bsp.raise_event(Event::C);
actions = bsp.wait();
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_allow_power_on));
state_machine.set_cp_state_X1();
// expect state_machine to run once and then again when the
// timer expires
actions = bsp.wait();
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::call_cp_state_X1));
// this would previously trigger the deadlock
bsp.raise_event(Event::A);
actions = bsp.wait();
// std::cout << bsp.to_string(actions) << std::endl;
ASSERT_TRUE(bsp.contains(actions, BspStubDeadlock::events_t::sleeping));
std::this_thread::sleep_for(10s);
// if there is a deadlock the test won't finish
}
} // namespace