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,51 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <everest/io/event/event_fd.hpp>
#include <optional>
#include <stdexcept>
#include <sys/eventfd.h>
namespace everest::lib::io::event {
event_fd_base::event_fd_base(unsigned int initval, int flags) : m_fd(::eventfd(initval, flags)) {
if (m_fd == -1) {
throw std::runtime_error("failed to create an eventfd");
}
}
event_fd_base::operator int() const {
return get_raw_fd();
}
int event_fd_base::get_raw_fd() const {
return m_fd;
}
bool event_fd_base::valid() const {
return m_fd != unique_fd::NO_DESCRIPTOR_SENTINEL;
}
std::optional<uint64_t> event_fd_base::read() {
eventfd_t eventfd_buffer{0};
if (eventfd_read(m_fd, &eventfd_buffer) == 0) {
return eventfd_buffer;
}
return std::nullopt;
}
bool event_fd_base::write(std::uint64_t data) {
return eventfd_write(m_fd, data) == 0;
}
bool event_fd_base::notify() {
return write(1);
}
event_fd::event_fd() : event_fd_base(0, 0) {
}
semaphore_fd::semaphore_fd() : event_fd_base(0, EFD_SEMAPHORE) {
}
} // namespace everest::lib::io::event

View File

@@ -0,0 +1,164 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <everest/io/event/fd_event_client.hpp>
#include <everest/io/event/fd_event_handler.hpp>
namespace everest::lib::io::event {
generic_fd_event_client_impl::generic_fd_event_client_impl(action const& send_one, action const& receive_one,
action const& reset_client, error_status const& get_error) :
m_send_one(send_one), m_receive_one(receive_one), m_reset_client(reset_client), m_get_error(get_error) {
m_event_handler = std::make_unique<event::fd_event_handler>();
}
generic_fd_event_client_impl::~generic_fd_event_client_impl() = default;
int generic_fd_event_client_impl::get_poll_fd() {
return m_event_handler->get_poll_fd();
}
sync_status generic_fd_event_client_impl::sync() {
return sync_impl(-1);
}
sync_status generic_fd_event_client_impl::sync_impl(int timeout_ms) {
auto result = m_event_handler->poll(std::chrono::milliseconds(timeout_ms));
m_event_handler->run_actions();
// The error handler must be called after all event handlers have run.
// Removing handlers during error processing is likely to result in
// inconsistent state and and segmentations fault.
return result ? sync_status::ok : sync_status::timeout;
}
bool generic_fd_event_client_impl::setup_error_event_handler() {
return m_event_handler->register_event_handler(&m_error_status_event_fd, [this](auto) {
if (on_error()) {
error_handler();
call_error_handler(m_error);
return sync_status::error;
} else if (clear_error_pending()) {
clear_error_handler(m_error);
}
return sync_status::ok;
});
}
void generic_fd_event_client_impl::setup_io_event_handler(int fd) {
using namespace everest::lib::io::event;
m_event_handler->register_event_handler(
fd,
[this, fd](auto events) {
auto success = true;
if (events.count(poll_events::error)) {
auto error = m_get_error();
if (error) {
set_error_status_and_notify(error);
}
success = false;
}
if (events.count(poll_events::hungup)) {
success = false;
}
if (success && events.count(poll_events::read)) {
success = rx_handler();
}
if (success && events.count(poll_events::write)) {
success = tx_handler(fd);
}
},
poll_events::read);
m_event_handler->register_event_handler(&m_io_event_fd, [this, fd](auto) {
m_event_handler->modify_event_handler(fd, poll_events::write, event_modification::add);
});
}
void generic_fd_event_client_impl::set_error_handler(cb_error const& handler) {
add_action([this, handler]() { m_error = handler; });
}
bool generic_fd_event_client_impl::unregister_source(int fd) {
return m_event_handler->remove_event_handler(fd);
}
bool generic_fd_event_client_impl::set_error_status_and_notify(int error_code) {
auto result = set_error_status(error_code);
m_error_status_event_fd.notify();
return result;
}
bool generic_fd_event_client_impl::rx_handler() {
auto status = m_receive_one();
auto error_code = status == action_status::success ? 0 : m_get_error();
auto result = set_error_status_and_notify(error_code);
return result;
}
bool generic_fd_event_client_impl::tx_handler(int fd) {
// We send one message only, even if more data is queued.
// This prevents the kernel buffer from filling up
auto status = m_send_one();
switch (status) {
case action_status::empty: {
// if there are no more message we no longer listen to writeable events
// otherwise we wait for the socket to become writeable again.
m_event_handler->modify_event_handler(fd, event::poll_events::write, event::event_modification::remove);
return true;
}
case action_status::fail: {
auto error_code = m_get_error();
set_error_status_and_notify(error_code);
return false;
}
case action_status::success: {
set_error_status_and_notify(0);
return true;
}
}
return true;
}
void generic_fd_event_client_impl::error_handler() {
add_action([this]() { m_reset_client(); });
}
void generic_fd_event_client_impl::prepare_io_event_handler() {
m_event_handler->register_event_handler(&m_connected_event_fd, [this](auto) {
auto client_status = m_client_status.handle();
if (client_status->ok) {
auto error_code = m_get_error();
set_error_status_and_notify(error_code);
setup_io_event_handler(client_status->fd);
if (m_on_ready_action) {
m_event_handler->add_action(m_on_ready_action);
}
} else {
auto error_code = m_get_error();
set_error_status_and_notify(error_code);
}
return sync_status::ok;
});
}
void generic_fd_event_client_impl::on_client_ready(bool ok, int fd) {
auto client_status = m_client_status.handle();
client_status->ok = ok;
client_status->fd = fd;
m_connected_event_fd.notify();
}
void generic_fd_event_client_impl::add_action(fd_event_handler::task&& item) {
m_event_handler->add_action(std::forward<fd_event_handler::task>(item));
}
void generic_fd_event_client_impl::set_on_ready_action(ready_action&& item) {
m_on_ready_action = std::move(item);
auto client_status = m_client_status.handle();
if (client_status->ok) {
m_event_handler->add_action(m_on_ready_action);
}
}
} // namespace everest::lib::io::event

View File

@@ -0,0 +1,379 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include "everest/io/event/fd_event_sync_interface.hpp"
#include <everest/io/event/event_fd.hpp>
#include <everest/io/event/fd_event_client.hpp>
#include <everest/io/event/fd_event_handler.hpp>
#include <everest/io/event/timer_fd.hpp>
#include <everest/io/event/unique_fd.hpp>
#include <cstdio>
#include <fcntl.h>
#include <map>
#include <vector>
#include <poll.h>
#include <sys/epoll.h>
namespace everest::lib::io::event {
namespace {
uint32_t poll_event_to_bitmask(poll_events e) {
switch (e) {
case poll_events::read:
return EPOLLIN;
case poll_events::priority:
return EPOLLPRI;
case poll_events::write:
return EPOLLOUT;
case poll_events::error:
return EPOLLERR;
case poll_events::hungup:
return EPOLLHUP;
}
return 0;
}
std::set<poll_events> bitmask_to_poll_events(uint32_t bitmask) {
std::set<poll_events> result;
if (bitmask & EPOLLIN) {
result.insert(poll_events::read);
}
if (bitmask & EPOLLPRI) {
result.insert(poll_events::priority);
}
if (bitmask & EPOLLOUT) {
result.insert(poll_events::write);
}
if (bitmask & EPOLLERR) {
result.insert(poll_events::error);
}
if (bitmask & EPOLLHUP) {
result.insert(poll_events::hungup);
}
return result;
}
uint32_t sum_events(std::set<poll_events> const& events) {
uint32_t result = 0;
for (auto e : events) {
result = result | poll_event_to_bitmask(e);
}
return result;
}
} // namespace
std::set<poll_events> operator|(poll_events lhs, poll_events rhs) {
return {lhs, rhs};
}
std::set<poll_events>& operator|(std::set<poll_events>& lhs, poll_events rhs) {
lhs.insert(rhs);
return lhs;
}
bool operator&(std::set<poll_events> const& lhs, poll_events rhs) {
return lhs.count(rhs) == 1;
}
class EventHandlerMap {
public:
EventHandlerMap() : m_epoll_fd(epoll_create1(0)) {
if (not m_epoll_fd.is_fd()) {
::perror("epoll_create");
}
}
bool add(int fd, fd_event_handler::event_handler_type handler, fd_event_handler::event_list const& events) {
epoll_event event;
event.events = sum_events(events);
event.data.fd = fd;
auto result = epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, fd, &event) == 0;
if (result) {
m_event_map[fd] = {std::move(handler), event};
m_pollfds.resize(m_pollfds.size() + 1);
}
return result;
}
bool remove(int fd) {
auto epoll_result = epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
auto handler_result = m_event_map.count(fd);
if (handler_result) {
m_event_map.erase(fd);
m_pollfds.resize(m_pollfds.size() - 1);
}
return epoll_result or handler_result;
}
bool modify_remove(int fd, fd_event_handler::event_list const& events) {
auto action = [](uint32_t current, fd_event_handler::event_list const& change) {
auto raw_change = sum_events(change);
auto result = current & (~raw_change);
return result;
};
return modify(fd, events, action);
}
bool modify_add(int fd, fd_event_handler::event_list const& events) {
auto action = [](uint32_t current, fd_event_handler::event_list const& change) {
auto raw_change = sum_events(change);
auto result = current | raw_change;
return result;
};
return modify(fd, events, action);
}
bool modify_replace(int fd, fd_event_handler::event_list const& events) {
auto action = [](uint32_t, fd_event_handler::event_list const& change) {
auto raw_change = sum_events(change);
auto result = raw_change;
return result;
};
return modify(fd, events, action);
}
const auto& get(int fd) const {
return std::get<fd_event_handler::event_handler_type>(m_event_map.at(fd));
}
bool exists(int fd) const {
return m_event_map.count(fd);
}
auto& get_pollfds() {
return m_pollfds;
}
int get_epoll_fd() {
return static_cast<int>(m_epoll_fd);
}
private:
using event_state = std::tuple<fd_event_handler::event_handler_type, epoll_event>;
bool modify(int fd, fd_event_handler::event_list const& events,
std::function<uint32_t(uint32_t, fd_event_handler::event_list const&)> const& event_action) {
auto result = false;
if (m_event_map.count(fd)) {
auto& event = std::get<epoll_event>(m_event_map.at(fd));
auto backup = event.events;
event.events = event_action(backup, events);
result = epoll_ctl(m_epoll_fd, EPOLL_CTL_MOD, fd, &event) == 0;
if (not result) {
event.events = backup;
}
}
return result;
}
std::vector<epoll_event> m_pollfds;
std::map<int, event_state> m_event_map;
unique_fd m_epoll_fd;
};
fd_event_handler::~fd_event_handler() = default;
fd_event_handler::fd_event_handler() {
m_handlers = std::make_unique<EventHandlerMap>();
register_event_handler(&m_action_event, [](auto&&) {});
}
bool fd_event_handler::register_event_handler(int fd, event_handler_type const& handler, event_list const& events) {
if (fd == -1 or not handler or m_handlers->exists(fd)) {
return false;
}
m_handlers->add(fd, handler, events);
return true;
}
bool fd_event_handler::register_event_handler(int fd, event_handler_type const& handler, poll_events event) {
return register_event_handler(fd, handler, event_list{event});
}
bool fd_event_handler::register_event_handler(event_fd* fd, event_handler_type const& handler) {
if (not fd) {
return false;
}
auto raw = fd->get_raw_fd();
return register_event_handler(
raw,
[handler, fd](event_list const& e) {
fd->read();
handler(e);
},
poll_events::read);
}
bool fd_event_handler::register_event_handler(event_fd* fd, event_handler_simple_type const& handler) {
return register_event_handler(fd, [handler](event_list const&) { handler(); });
}
bool fd_event_handler::register_event_handler(timer_fd* fd, event_handler_type const& handler) {
if (not fd) {
return false;
}
auto raw = fd->get_raw_fd();
return register_event_handler(
raw,
[handler, fd](event_list const& e) {
fd->read();
handler(e);
},
poll_events::read);
}
bool fd_event_handler::register_event_handler(timer_fd* fd, event_handler_simple_type const& handler) {
return register_event_handler(fd, [handler](event_list const&) { handler(); });
}
bool fd_event_handler::register_event_handler(fd_event_sync_interface* obj) {
if (not obj) {
return false;
}
auto raw = obj->get_poll_fd();
return register_event_handler(
raw, [obj](event_list const&) { obj->sync(); }, poll_events::read);
}
bool fd_event_handler::register_event_handler(fd_event_register_interface* obj) {
if (not obj) {
return false;
}
return obj->register_events(*this);
}
bool fd_event_handler::register_event_handler(fd_event_handler* obj) {
if (not obj or obj == this) {
return false;
}
auto raw = obj->get_poll_fd();
return register_event_handler(
raw,
[obj](event_list const&) {
obj->poll();
obj->run_actions();
},
poll_events::read);
}
bool fd_event_handler::unregister_event_handler(fd_event_register_interface* obj) {
if (not obj) {
return false;
}
return obj->unregister_events(*this);
}
bool fd_event_handler::unregister_event_handler(fd_event_sync_interface* obj) {
if (not obj) {
return false;
}
return remove_event_handler(obj->get_poll_fd());
}
bool fd_event_handler::unregister_event_handler(timer_fd* obj) {
if (not obj) {
return false;
}
return remove_event_handler(obj->get_raw_fd());
}
bool fd_event_handler::unregister_event_handler(event_fd* obj) {
if (not obj) {
return false;
}
return remove_event_handler(obj->get_raw_fd());
}
bool fd_event_handler::unregister_event_handler(int fd) {
if (fd == -1) {
return false;
}
return remove_event_handler(fd);
}
bool fd_event_handler::modify_event_handler(int fd, event_list const& events, event_modification change) {
if (fd == -1) {
return false;
}
switch (change) {
case event_modification::add:
return m_handlers->modify_add(fd, events);
case event_modification::remove:
return m_handlers->modify_remove(fd, events);
case event_modification::replace:
return m_handlers->modify_replace(fd, events);
default:
return false;
}
}
bool fd_event_handler::modify_event_handler(int fd, poll_events event, event_modification change) {
return modify_event_handler(fd, event_list{event}, change);
}
bool fd_event_handler::remove_event_handler(int fd) {
if (fd == -1) {
return false;
}
return m_handlers->remove(fd);
}
void fd_event_handler::poll() {
poll_impl(-1);
}
bool fd_event_handler::poll_impl(int timeout_ms) {
auto& pollfds = m_handlers->get_pollfds();
auto status = ::epoll_wait(m_handlers->get_epoll_fd(), pollfds.data(), pollfds.size(), timeout_ms);
if (status > 0) {
for (int i = 0; i < status; ++i) {
auto& item = pollfds[i];
m_handlers->get(item.data.fd)(bitmask_to_poll_events(item.events));
}
return true;
}
return false;
}
int fd_event_handler::get_poll_fd() {
return m_handlers->get_epoll_fd();
}
void fd_event_handler::add_action(task&& item) {
task_pool.push(std::forward<task>(item));
m_action_event.notify();
}
void fd_event_handler::add_action(task const& item) {
task_pool.push(std::move(item));
m_action_event.notify();
}
void fd_event_handler::run_actions() {
while (true) {
auto item = task_pool.try_pop();
if (item.has_value()) {
try {
item.value()();
} catch (...) {
}
} else {
break;
}
}
}
void fd_event_handler::run_once() {
poll();
run_actions();
}
void fd_event_handler::run(std::atomic_bool& online) {
while (online.load()) {
poll();
run_actions();
}
}
} // namespace everest::lib::io::event

View File

@@ -0,0 +1,75 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <ctime>
#include <everest/io/event/timer_fd.hpp>
#include <stdexcept>
#include <sys/timerfd.h>
#include <unistd.h>
namespace everest::lib::io::event {
timer_fd::timer_fd() : m_fd(::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) {
if (m_fd == -1) {
throw std::runtime_error("failed to create an timerfd");
}
}
timer_fd::operator int() const {
return get_raw_fd();
}
int timer_fd::get_raw_fd() const {
return m_fd;
}
bool timer_fd::valid() const {
return m_fd != unique_fd::NO_DESCRIPTOR_SENTINEL;
}
int timer_fd::read() {
uint64_t buffer;
return ::read(m_fd, &buffer, sizeof(buffer));
}
bool timer_fd::reset() {
return set_timeout_ns(m_to_ns);
}
void timer_fd::set_single_shot(bool on) {
m_single_shot = on;
}
bool timer_fd::disarm() {
struct itimerspec timer {};
return ::timerfd_settime(m_fd, 0, &timer, nullptr) == 0;
}
bool timer_fd::set_timeout_ms(long long to) {
return set_timeout_ns(1000 * 1000 * to);
}
bool timer_fd::set_timeout_us(long long to) {
return set_timeout_ns(1000 * to);
}
bool timer_fd::set_timeout_ns(long long to) {
m_to_ns = to;
struct itimerspec timer {};
auto const sec = to / 1000000000LL;
auto const nano = to % 1000000000LL;
timer.it_value.tv_sec = sec;
timer.it_value.tv_nsec = nano;
if (m_single_shot) {
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_nsec = 0;
} else {
timer.it_interval.tv_sec = sec;
timer.it_interval.tv_nsec = nano;
}
return ::timerfd_settime(m_fd, 0, &timer, nullptr) == 0;
}
} // namespace everest::lib::io::event

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include <everest/io/event/unique_fd.hpp>
#include <unistd.h>
#include <utility>
namespace everest::lib::io::event {
namespace {
void close_descriptor_if_valid(int fd) {
if (fd != unique_fd::NO_DESCRIPTOR_SENTINEL) {
// NOTE (aw): according to the close(2) man page, close might return an error but it should not be retried
::close(fd);
}
}
} // namespace
unique_fd::unique_fd(int fd) : m_fd(fd){};
unique_fd::operator int() const {
return m_fd;
}
bool unique_fd::is_fd() const {
return m_fd != NO_DESCRIPTOR_SENTINEL;
}
int unique_fd::release() {
return std::exchange(m_fd, NO_DESCRIPTOR_SENTINEL);
}
void unique_fd::close() {
close_descriptor_if_valid(m_fd);
std::exchange(m_fd, NO_DESCRIPTOR_SENTINEL);
}
unique_fd::unique_fd(unique_fd&& other) : m_fd(std::exchange(other.m_fd, NO_DESCRIPTOR_SENTINEL)) {
}
unique_fd& unique_fd::operator=(unique_fd&& other) {
if (this != &other) {
close_descriptor_if_valid(m_fd);
m_fd = std::exchange(other.m_fd, NO_DESCRIPTOR_SENTINEL);
}
return *this;
}
unique_fd::~unique_fd() {
close_descriptor_if_valid(m_fd);
}
} // namespace everest::lib::io::event