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,62 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <ieee2030/charger/session/callback.hpp>
|
||||
#include <ieee2030/charger/session/session.hpp>
|
||||
#include <ieee2030/charger/v20/control_event.hpp>
|
||||
#include <ieee2030/common/v20/event_queue.hpp>
|
||||
|
||||
namespace ieee2030::charger {
|
||||
|
||||
enum class HwSignal {
|
||||
CS1,
|
||||
CS2,
|
||||
CHARGE_PERMISSION,
|
||||
PROX,
|
||||
};
|
||||
|
||||
class Controller {
|
||||
public:
|
||||
Controller(std::string, callback::Callbacks);
|
||||
~Controller(); // Todo: Adding destructor
|
||||
|
||||
// Collection of api ideas
|
||||
|
||||
// Call only if the charging session is authorized and the ev is connected
|
||||
void start_session(bool, float, float, float, defs::ProtocolNumber);
|
||||
|
||||
// HW Signals
|
||||
void update_hw_signal(HwSignal, bool);
|
||||
|
||||
// Update physical values
|
||||
void update_present_voltage_current(float, float);
|
||||
void update_available_voltage_current(float, float);
|
||||
void update_isolation_status(events::IsolationStatus);
|
||||
|
||||
// Events
|
||||
void cable_check_finished();
|
||||
void stop();
|
||||
|
||||
// Error handling
|
||||
void send_error(); // Todo: define error enums
|
||||
void reset_errors();
|
||||
|
||||
private:
|
||||
std::string can_interface;
|
||||
|
||||
ieee2030::events::EventQueue<events::Event> event_queue;
|
||||
|
||||
// HW Signals: Enable/disable CS1 & CS2 done
|
||||
// EV Target voltage & current done
|
||||
// EV min & max battery voltage
|
||||
// Debug infos (protocol, soc)
|
||||
// Fault
|
||||
// Lock enable/disable?
|
||||
//
|
||||
const callback::Callbacks callbacks;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <ieee2030/common/messages/messages.hpp>
|
||||
|
||||
namespace ieee2030::charger::v20::state {
|
||||
|
||||
bool state_c_1(const messages::EV100&, const messages::EV101&, const messages::EV102&);
|
||||
bool state_c_2(const messages::EV102&);
|
||||
|
||||
} // namespace ieee2030::charger::v20::state
|
||||
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <ieee2030/common/messages/messages.hpp>
|
||||
|
||||
namespace ieee2030::charger::io {
|
||||
|
||||
enum class CanEvent {
|
||||
ACTIVE,
|
||||
NEW_DATA,
|
||||
INACTIVE,
|
||||
};
|
||||
|
||||
using CanEventCallback = std::function<void(CanEvent)>;
|
||||
|
||||
class CanBrokerCharger {
|
||||
|
||||
enum class SendState {
|
||||
ID_108,
|
||||
ID_109,
|
||||
};
|
||||
|
||||
public:
|
||||
CanBrokerCharger();
|
||||
CanBrokerCharger(const std::string&);
|
||||
~CanBrokerCharger();
|
||||
|
||||
void set_event_callback(const CanEventCallback&);
|
||||
|
||||
void enable_tx_can() {
|
||||
tx_active = true;
|
||||
};
|
||||
void disable_tx_can() {
|
||||
tx_active = false;
|
||||
};
|
||||
|
||||
bool rx_can_enabled() {
|
||||
return rx_active;
|
||||
}
|
||||
|
||||
const messages::EV100& get_can_100_message() const {
|
||||
return message_100;
|
||||
}
|
||||
|
||||
const messages::EV101& get_can_101_message() const {
|
||||
return message_101;
|
||||
}
|
||||
|
||||
const messages::EV102& get_can_102_message() const {
|
||||
return message_102;
|
||||
}
|
||||
|
||||
void init_charger_messages(bool welding_detection, float available_voltage, float available_current,
|
||||
float threshold_voltage, defs::ProtocolNumber protocol) {
|
||||
message_108 = messages::Charger108(welding_detection, available_voltage, available_current, threshold_voltage);
|
||||
message_109 = messages::Charger109(protocol);
|
||||
};
|
||||
|
||||
void update_present_voltage(float voltage) {
|
||||
message_109.present_voltage = voltage;
|
||||
}
|
||||
|
||||
void update_present_current(float current) {
|
||||
message_109.present_current = current;
|
||||
}
|
||||
|
||||
void update_available_voltage(float voltage) {
|
||||
message_108.available_voltage = voltage;
|
||||
}
|
||||
|
||||
void update_available_current(float current) {
|
||||
message_108.available_current = current;
|
||||
}
|
||||
|
||||
void update_threshold_voltage(float voltage) {
|
||||
message_108.threshold_voltage = voltage;
|
||||
}
|
||||
|
||||
void update_status_error_flag(defs::ChargerStatusError, bool);
|
||||
void update_reamining_time_10s(uint16_t);
|
||||
|
||||
private:
|
||||
std::atomic_bool exit_rx_loop{false};
|
||||
std::atomic_bool rx_active{false};
|
||||
void rx_loop();
|
||||
std::thread rx_loop_thread;
|
||||
void handle_can_input(uint32_t, const std::vector<uint8_t>&);
|
||||
|
||||
std::atomic_bool exit_tx_loop{false};
|
||||
std::atomic_bool tx_active{false};
|
||||
void tx_loop();
|
||||
std::thread tx_loop_thread;
|
||||
void send(uint32_t, const std::vector<uint8_t>&);
|
||||
|
||||
int can_fd{-1};
|
||||
|
||||
CanEventCallback event_callback{nullptr};
|
||||
|
||||
void publish_event(CanEvent event) {
|
||||
if (!event_callback) {
|
||||
return;
|
||||
}
|
||||
event_callback(event);
|
||||
}
|
||||
|
||||
messages::EV100 message_100;
|
||||
messages::EV101 message_101;
|
||||
messages::EV102 message_102;
|
||||
|
||||
messages::Charger108 message_108;
|
||||
messages::Charger109 message_109;
|
||||
|
||||
SendState tx_state{SendState::ID_108};
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger::io
|
||||
@@ -0,0 +1,50 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace ieee2030::charger {
|
||||
|
||||
namespace callback {
|
||||
|
||||
enum class Signal {
|
||||
START_CABLE_CHECK,
|
||||
CHARGE_LOOP_STARTED,
|
||||
CHARGE_LOOP_FINISHED,
|
||||
};
|
||||
|
||||
enum class ChargerSequence {
|
||||
CS1,
|
||||
CS2,
|
||||
};
|
||||
|
||||
enum class Status : bool {
|
||||
OFF = false,
|
||||
ON = true
|
||||
};
|
||||
|
||||
struct HwSignal {
|
||||
ChargerSequence signal;
|
||||
Status status;
|
||||
};
|
||||
|
||||
struct Callbacks {
|
||||
std::function<void(Signal)> signal;
|
||||
std::function<void(const HwSignal&)> hw_signal;
|
||||
};
|
||||
|
||||
} // namespace callback
|
||||
|
||||
class Callback {
|
||||
public:
|
||||
Callback(callback::Callbacks);
|
||||
|
||||
void signal(callback::Signal) const;
|
||||
void hw_signal(const callback::HwSignal&) const;
|
||||
|
||||
private:
|
||||
callback::Callbacks callbacks;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <ieee2030/charger/io/can_broker_charger.hpp>
|
||||
#include <ieee2030/common/messages/messages.hpp>
|
||||
|
||||
#include <everest/util/fsm/fsm.hpp>
|
||||
#include <ieee2030/charger/v20/context.hpp>
|
||||
#include <ieee2030/charger/v20/control_event.hpp>
|
||||
#include <ieee2030/charger/v20/states.hpp>
|
||||
|
||||
namespace ieee2030::charger {
|
||||
|
||||
struct SessionState {
|
||||
bool can_active{false};
|
||||
bool new_data{false};
|
||||
};
|
||||
|
||||
class Session {
|
||||
public:
|
||||
Session(std::unique_ptr<io::CanBrokerCharger>, const callback::Callbacks&);
|
||||
~Session();
|
||||
|
||||
void update(const std::vector<events::Event>&);
|
||||
|
||||
bool is_session_active() const {
|
||||
return session_is_active;
|
||||
}
|
||||
|
||||
// void end_session() {
|
||||
// session_is_active = false;
|
||||
// }
|
||||
|
||||
private:
|
||||
std::unique_ptr<io::CanBrokerCharger> can_broker;
|
||||
|
||||
std::optional<events::Event> active_event{std::nullopt};
|
||||
|
||||
SessionState state;
|
||||
|
||||
v20::Context ctx;
|
||||
|
||||
fsm::v2::FSM<ieee2030::charger::v20::StateBase> fsm;
|
||||
|
||||
bool session_is_active;
|
||||
|
||||
void handle_can_event(io::CanEvent);
|
||||
|
||||
messages::EV100 message_100;
|
||||
messages::EV101 message_101;
|
||||
messages::EV102 message_102;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger
|
||||
@@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <ieee2030/charger/session/callback.hpp>
|
||||
#include <ieee2030/charger/v20/control_event.hpp>
|
||||
#include <ieee2030/common/io/time.hpp>
|
||||
#include <ieee2030/common/messages/messages.hpp>
|
||||
|
||||
namespace ieee2030::charger::v20 {
|
||||
|
||||
struct CanBrokerContext {
|
||||
std::function<void()> enable_can;
|
||||
std::function<void()> disable_can;
|
||||
std::function<void(defs::ChargerStatusError, bool)> update_status_error;
|
||||
std::function<void(uint16_t)> update_reamining_time;
|
||||
};
|
||||
|
||||
class StateBase;
|
||||
using BasePointerType = std::unique_ptr<StateBase>;
|
||||
|
||||
class Context {
|
||||
public:
|
||||
Context(const std::optional<events::Event>&, callback::Callbacks, const messages::EV100&, const messages::EV101&,
|
||||
const messages::EV102&);
|
||||
|
||||
template <typename StateType, typename... Args> BasePointerType create_state(Args&&... args) {
|
||||
return std::make_unique<StateType>(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
const auto& get_event() {
|
||||
return current_event;
|
||||
}
|
||||
|
||||
template <typename T> T const* get_event() {
|
||||
if (not current_event.has_value()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (not std::holds_alternative<T>(*current_event)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &std::get<T>(*current_event);
|
||||
}
|
||||
|
||||
const messages::EV100& message_100;
|
||||
const messages::EV101& message_101;
|
||||
const messages::EV102& message_102;
|
||||
|
||||
void set_can_broker_callback(const CanBrokerContext& callbacks_) {
|
||||
can_broker_callbacks = callbacks_;
|
||||
}
|
||||
|
||||
void enable_can() {
|
||||
can_broker_callbacks.enable_can();
|
||||
}
|
||||
void disable_can() {
|
||||
can_broker_callbacks.disable_can();
|
||||
}
|
||||
|
||||
void update_status_error(defs::ChargerStatusError status, bool active) {
|
||||
can_broker_callbacks.update_status_error(status, active);
|
||||
}
|
||||
void update_reaminig_time_s(uint16_t seconds) {
|
||||
can_broker_callbacks.update_reamining_time(seconds);
|
||||
}
|
||||
|
||||
const Callback callbacks;
|
||||
|
||||
// bool& log; // Todo: Adding log file logic and write to log file
|
||||
|
||||
ieee2030::io::Timeout timeout;
|
||||
|
||||
private:
|
||||
const std::optional<events::Event>& current_event;
|
||||
|
||||
CanBrokerContext can_broker_callbacks;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger::v20
|
||||
@@ -0,0 +1,109 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
namespace ieee2030::charger::events {
|
||||
|
||||
class CS1 {
|
||||
public:
|
||||
explicit CS1(bool status_) : status(status_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
bool status;
|
||||
};
|
||||
|
||||
class CS2 {
|
||||
public:
|
||||
explicit CS2(bool status_) : status(status_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
bool status;
|
||||
};
|
||||
|
||||
class ProximityDetection {
|
||||
public:
|
||||
explicit ProximityDetection(bool status_) : status(status_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
bool status;
|
||||
};
|
||||
|
||||
class ChargePermission {
|
||||
public:
|
||||
explicit ChargePermission(bool status_) : status(status_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return status;
|
||||
}
|
||||
|
||||
private:
|
||||
bool status;
|
||||
};
|
||||
|
||||
class CableCheckFinished {
|
||||
public:
|
||||
explicit CableCheckFinished(bool success_) : success(success_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return success;
|
||||
}
|
||||
|
||||
private:
|
||||
bool success;
|
||||
};
|
||||
|
||||
class StopCharging {
|
||||
public:
|
||||
explicit StopCharging(bool stop_) : stop(stop_) {
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return stop;
|
||||
}
|
||||
|
||||
private:
|
||||
bool stop;
|
||||
};
|
||||
|
||||
struct PresentVoltageCurrent {
|
||||
float voltage;
|
||||
float current;
|
||||
};
|
||||
|
||||
struct AvailableVoltageCurrent {
|
||||
float voltage;
|
||||
float current;
|
||||
};
|
||||
|
||||
enum class IsolationStatus {
|
||||
Invalid,
|
||||
Valid,
|
||||
Fault,
|
||||
};
|
||||
|
||||
enum class Error {
|
||||
Test,
|
||||
};
|
||||
|
||||
using Event = std::variant<CS1, CS2, ProximityDetection, ChargePermission, CableCheckFinished, StopCharging,
|
||||
PresentVoltageCurrent, AvailableVoltageCurrent, IsolationStatus, Error>;
|
||||
} // namespace ieee2030::charger::events
|
||||
@@ -0,0 +1,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
namespace ieee2030::charger::v20::state {
|
||||
|
||||
struct StateB : public StateBase {
|
||||
public:
|
||||
StateB(Context& ctx) : StateBase(ctx, StateID::StateB) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
bool stop{false};
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger::v20::state
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "../states.hpp"
|
||||
|
||||
#include <ieee2030/common/messages/messages.hpp>
|
||||
|
||||
namespace ieee2030::charger::v20::state {
|
||||
|
||||
namespace state_c {
|
||||
enum class InternalStates {
|
||||
C_1,
|
||||
C_2,
|
||||
};
|
||||
|
||||
} // namespace state_c
|
||||
struct StateC : public StateBase {
|
||||
public:
|
||||
StateC(Context& ctx) : StateBase(ctx, StateID::StateC) {
|
||||
}
|
||||
|
||||
void enter() final;
|
||||
|
||||
Result feed(Event) final;
|
||||
|
||||
private:
|
||||
bool stop{false};
|
||||
|
||||
state_c::InternalStates states{state_c::InternalStates::C_1};
|
||||
|
||||
messages::EV100 ev_100;
|
||||
messages::EV101 ev_101;
|
||||
messages::EV102 ev_102;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger::v20::state
|
||||
@@ -0,0 +1,55 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include "context.hpp"
|
||||
|
||||
namespace ieee2030::charger::v20 {
|
||||
|
||||
class Context;
|
||||
|
||||
enum class Event {
|
||||
CAN_MESSAGE,
|
||||
HW_SIGNAL,
|
||||
EVENT,
|
||||
TIMEOUT,
|
||||
};
|
||||
|
||||
enum class StateID {
|
||||
StateB,
|
||||
StateC
|
||||
};
|
||||
|
||||
struct Result {
|
||||
constexpr Result() = default;
|
||||
Result(BasePointerType result_state) : unhandled(false), new_state(std::move(result_state)) {
|
||||
}
|
||||
|
||||
bool unhandled{true};
|
||||
BasePointerType new_state{nullptr};
|
||||
};
|
||||
|
||||
struct StateBase {
|
||||
using ContainerType = BasePointerType;
|
||||
using EventType = Event;
|
||||
|
||||
StateBase(Context& ctx, StateID id) : m_ctx(ctx), m_id(id){};
|
||||
|
||||
virtual ~StateBase() = default;
|
||||
|
||||
StateID get_id() const {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
virtual void enter(){};
|
||||
virtual Result feed(Event) = 0;
|
||||
virtual void leave(){};
|
||||
|
||||
protected:
|
||||
Context& m_ctx;
|
||||
|
||||
private:
|
||||
StateID m_id;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::charger::v20
|
||||
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2022 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 1, T> from_raw(const std::vector<uint8_t>& raw, int idx) {
|
||||
T ret = raw[idx];
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 2, T> from_raw(const std::vector<uint8_t>& raw, int idx) {
|
||||
if (idx + sizeof(T) > raw.size()) {
|
||||
throw std::out_of_range("from_raw: buffer access out of bounds");
|
||||
}
|
||||
uint16_t tmp{};
|
||||
memcpy(&tmp, raw.data() + idx, sizeof(uint16_t)); // Safe copy from buffer
|
||||
tmp = be16toh(tmp); // Convert endianness
|
||||
|
||||
T ret;
|
||||
memcpy(&ret, &tmp, 2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 4, T> from_raw(const std::vector<uint8_t>& raw, int idx) {
|
||||
if (idx + sizeof(T) > raw.size()) {
|
||||
throw std::out_of_range("from_raw: buffer access out of bounds");
|
||||
}
|
||||
uint32_t tmp{};
|
||||
memcpy(&tmp, raw.data() + idx, sizeof(uint32_t)); // Safe copy from buffer
|
||||
tmp = be32toh(tmp); // Convert endianness
|
||||
|
||||
T ret;
|
||||
memcpy(&ret, &tmp, 4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 8, T> from_raw(const std::vector<uint8_t>& raw, int idx) {
|
||||
if (idx + sizeof(T) > raw.size()) {
|
||||
throw std::out_of_range("from_raw: buffer access out of bounds");
|
||||
}
|
||||
uint64_t tmp{};
|
||||
memcpy(&tmp, raw.data() + idx, sizeof(uint64_t)); // Safe copy from buffer
|
||||
tmp = be64toh(tmp); // Convert endianness
|
||||
T ret;
|
||||
memcpy(&ret, &tmp, 8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 1> to_raw(T src, std::vector<uint8_t>& dest) {
|
||||
uint8_t tmp{};
|
||||
memcpy(&tmp, &src, 1);
|
||||
dest.push_back(tmp);
|
||||
}
|
||||
|
||||
// FIXME (aw): these conversions should be optimized!
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 2> to_raw(T src, std::vector<uint8_t>& dest) {
|
||||
uint16_t tmp{};
|
||||
memcpy(&tmp, &src, 2);
|
||||
tmp = htobe16(tmp);
|
||||
uint8_t ret[2];
|
||||
memcpy(ret, &tmp, 2);
|
||||
dest.insert(dest.end(), {ret[0], ret[1]});
|
||||
}
|
||||
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 4> to_raw(T src, std::vector<uint8_t>& dest) {
|
||||
uint32_t tmp{};
|
||||
memcpy(&tmp, &src, 4);
|
||||
tmp = htobe32(tmp);
|
||||
uint8_t ret[4];
|
||||
memcpy(ret, &tmp, 4);
|
||||
dest.insert(dest.end(), {ret[0], ret[1], ret[2], ret[3]});
|
||||
}
|
||||
|
||||
template <class T> typename std::enable_if_t<sizeof(T) == 8> to_raw(T src, std::vector<uint8_t>& dest) {
|
||||
uint64_t tmp{};
|
||||
memcpy(&tmp, &src, 8);
|
||||
tmp = htobe64(tmp);
|
||||
uint8_t ret[8];
|
||||
memcpy(ret, &tmp, 8);
|
||||
dest.insert(dest.end(), {ret[0], ret[1], ret[2], ret[3], ret[4], ret[5], ret[6], ret[7]});
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
|
||||
namespace ieee2030 {
|
||||
|
||||
void logf(const char* fmt, ...);
|
||||
|
||||
void vlogf(const char* fmt, va_list ap);
|
||||
|
||||
void log(const std::string&);
|
||||
|
||||
template <typename CallbackType, typename... Args> bool call_if_available(const CallbackType& callback, Args... args) {
|
||||
if (not callback) {
|
||||
false;
|
||||
}
|
||||
|
||||
callback(std::forward<Args>(args)...);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ieee2030
|
||||
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace ieee2030::io {
|
||||
void set_logging_callback(const std::function<void(std::string)>&);
|
||||
|
||||
} // namespace ieee2030::io
|
||||
@@ -0,0 +1,34 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <optional>
|
||||
|
||||
namespace ieee2030::io {
|
||||
|
||||
using TimePoint = std::chrono::steady_clock::time_point;
|
||||
|
||||
inline TimePoint get_current_time_point() {
|
||||
return std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
inline TimePoint offset_time_point_by_ms(const TimePoint& time_point, int32_t offset) {
|
||||
return time_point + std::chrono::milliseconds(offset);
|
||||
}
|
||||
|
||||
// Todo: How to handle parallel timeouts?
|
||||
class Timeout {
|
||||
public:
|
||||
Timeout(){};
|
||||
|
||||
void start(float timeout_s); // Todo: Perhaps change that chrono::seconds
|
||||
void reset();
|
||||
|
||||
std::optional<bool> timeout_reached();
|
||||
|
||||
private:
|
||||
std::optional<TimePoint> timeout_point;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::io
|
||||
@@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2022 - 2026 Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
// #include <linux/can.h>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
namespace ieee2030 {
|
||||
|
||||
namespace defs {
|
||||
|
||||
static constexpr auto CHARGED_RATE_REFERENCE = 100;
|
||||
|
||||
enum class ProtocolNumber : uint8_t {
|
||||
VERSION_0_9_1 = 0,
|
||||
VERSION_1_X_X = 1,
|
||||
VERSION_2_0 = 2,
|
||||
};
|
||||
|
||||
enum class EVStatusFault : uint8_t {
|
||||
FAULT_BATTERY_OVER_VOLTAGE,
|
||||
FAULT_BATTERY_UNDER_VOTLAGE,
|
||||
FAULT_BATTER_CURRENT_DEVIATION_ERROR,
|
||||
FAULT_HIGH_BATTERY_TEMPERATURE,
|
||||
FAULT_BATTERY_VOLTAGE_DEVIATION_ERROR,
|
||||
STATUS_CHARGING_ENABLED,
|
||||
STATUS_SHIFT_POSITION,
|
||||
STATUS_SYSTEM_FAULT,
|
||||
STATUS_VEHICLE_STATUS,
|
||||
STATUS_STOP_REQUEST,
|
||||
};
|
||||
enum class ChargerStatusError : uint8_t {
|
||||
CHARGER_STATUS,
|
||||
CHARGER_MALFUNCTION,
|
||||
CONNECTOR_LOCK,
|
||||
BATTERY_INCOMPATIBILITY,
|
||||
SYSTEM_MALFUNCTION,
|
||||
STOP_CONTROL,
|
||||
};
|
||||
} // namespace defs
|
||||
|
||||
namespace messages {
|
||||
|
||||
static constexpr auto EV_ID_100 = 0x100;
|
||||
static constexpr auto EV_ID_101 = 0x101;
|
||||
static constexpr auto EV_ID_102 = 0x102;
|
||||
|
||||
struct EV100 {
|
||||
EV100(){};
|
||||
EV100(const std::vector<uint8_t> raw);
|
||||
friend std::ostream& operator<<(std::ostream&, const EV100&);
|
||||
operator std::vector<uint8_t>();
|
||||
|
||||
float max_battery_voltage;
|
||||
uint8_t charged_rate{defs::CHARGED_RATE_REFERENCE};
|
||||
};
|
||||
|
||||
struct EV101 {
|
||||
EV101(){};
|
||||
EV101(const std::vector<uint8_t> raw);
|
||||
friend std::ostream& operator<<(std::ostream&, const EV101&);
|
||||
operator std::vector<uint8_t>();
|
||||
|
||||
uint8_t max_charging_time_10s; // 0xFF -> use of time_1min
|
||||
uint8_t max_charging_time_1min;
|
||||
uint8_t estimated_charging_time_1min;
|
||||
std::optional<float> total_capacity; // 0.1kWh/bit
|
||||
};
|
||||
|
||||
struct EV102 {
|
||||
EV102(){};
|
||||
EV102(const std::vector<uint8_t> raw);
|
||||
friend std::ostream& operator<<(std::ostream&, const EV102&);
|
||||
operator std::vector<uint8_t>();
|
||||
|
||||
defs::ProtocolNumber protocol;
|
||||
float target_voltage;
|
||||
float target_current;
|
||||
|
||||
bool fault_battery_over_voltage;
|
||||
bool fault_battery_under_voltage;
|
||||
bool fault_battery_current_deviation_error;
|
||||
bool fault_high_battery_temperature;
|
||||
bool fault_battery_voltage_deviation_error;
|
||||
|
||||
bool status_charging_enabled;
|
||||
bool status_shift_position;
|
||||
bool status_system_fault;
|
||||
bool status_vehicle_status;
|
||||
bool status_stop_request;
|
||||
|
||||
uint8_t soc; // 0% - 100%
|
||||
};
|
||||
|
||||
namespace v1_2 {} // namespace v1_2
|
||||
|
||||
namespace v2_0 {} // namespace v2_0
|
||||
|
||||
static constexpr auto CHARGER_ID_108 = 0x108;
|
||||
static constexpr auto CHARGER_ID_109 = 0x109;
|
||||
|
||||
struct Charger108 {
|
||||
Charger108(){};
|
||||
Charger108(const std::vector<uint8_t> raw);
|
||||
Charger108(bool welding_detection_, float voltage_, float current_, float threshold_voltage_) :
|
||||
identifier_welding_detection(welding_detection_),
|
||||
available_voltage(voltage_),
|
||||
available_current(current_),
|
||||
threshold_voltage(threshold_voltage_){};
|
||||
friend std::ostream& operator<<(std::ostream&, const Charger108&);
|
||||
operator std::vector<uint8_t>();
|
||||
|
||||
uint8_t identifier_welding_detection; // 0: not supported, 1-255: supported
|
||||
float available_voltage;
|
||||
float available_current;
|
||||
float threshold_voltage;
|
||||
};
|
||||
|
||||
struct Charger109 {
|
||||
Charger109(){};
|
||||
Charger109(const std::vector<uint8_t> raw);
|
||||
Charger109(defs::ProtocolNumber protocol_) : protocol(protocol_){};
|
||||
friend std::ostream& operator<<(std::ostream&, const Charger109&);
|
||||
operator std::vector<uint8_t>();
|
||||
|
||||
defs::ProtocolNumber protocol;
|
||||
float present_voltage;
|
||||
float present_current;
|
||||
|
||||
bool charger_status;
|
||||
bool charger_malfunction;
|
||||
bool connector_lock;
|
||||
bool battery_incompatibility;
|
||||
bool system_malfunction;
|
||||
bool stop_control{true};
|
||||
|
||||
uint8_t reamining_time_10s; // 0xFF -> use of time_1min
|
||||
uint8_t reamining_time_1min;
|
||||
};
|
||||
|
||||
namespace v1_2 {} // namespace v1_2
|
||||
|
||||
namespace v2_0 {} // namespace v2_0
|
||||
|
||||
} // namespace messages
|
||||
|
||||
} // namespace ieee2030
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
namespace ieee2030::events {
|
||||
|
||||
template <class T> class EventQueue {
|
||||
public:
|
||||
std::optional<T> pop() {
|
||||
std::lock_guard<std::mutex> lck(mutex);
|
||||
|
||||
if (queue.empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto event = std::make_optional<T>(std::move(queue.front()));
|
||||
queue.pop();
|
||||
|
||||
return event;
|
||||
};
|
||||
|
||||
void push(T event) {
|
||||
std::lock_guard<std::mutex> lck(mutex);
|
||||
|
||||
queue.push(std::move(event));
|
||||
};
|
||||
|
||||
private:
|
||||
std::queue<T> queue;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
} // namespace ieee2030::events
|
||||
@@ -0,0 +1,92 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <ieee2030/common/messages/messages.hpp>
|
||||
|
||||
namespace ieee2030::ev::io {
|
||||
|
||||
enum class CanEvent {
|
||||
ACTIVE,
|
||||
NEW_DATA,
|
||||
INACTIVE,
|
||||
};
|
||||
|
||||
using CanEventCallback = std::function<void(CanEvent)>;
|
||||
|
||||
// Todo(sl): Check if refactoring with CanBrokerCharger is possible
|
||||
class CanBrokerEv {
|
||||
|
||||
enum class SendState {
|
||||
ID_100,
|
||||
ID_101,
|
||||
ID_102,
|
||||
};
|
||||
|
||||
public:
|
||||
CanBrokerEv(){}; // Todo(sl): Check if needed
|
||||
CanBrokerEv(const std::string&);
|
||||
~CanBrokerEv();
|
||||
|
||||
void set_event_callback(const CanEventCallback&);
|
||||
|
||||
void enable_tx_can() {
|
||||
tx_active = true;
|
||||
};
|
||||
void disable_tx_can() {
|
||||
tx_active = false;
|
||||
};
|
||||
|
||||
const messages::Charger108& get_can_108_message() const {
|
||||
return message_108;
|
||||
};
|
||||
const messages::Charger109& get_can_109_message() const {
|
||||
return message_109;
|
||||
}
|
||||
|
||||
void init_messages(); // Todo(sl): Define init arguments
|
||||
|
||||
// Todo(sl): define update functions
|
||||
|
||||
private:
|
||||
std::atomic_bool exit_rx_loop{false};
|
||||
std::atomic_bool rx_active{false};
|
||||
void rx_loop();
|
||||
std::thread rx_loop_thread;
|
||||
void handle_can_input(uint32_t, const std::vector<uint8_t>&);
|
||||
|
||||
std::atomic_bool exit_tx_loop{false};
|
||||
std::atomic_bool tx_active{false};
|
||||
void tx_loop();
|
||||
std::thread tx_loop_thread;
|
||||
void send(uint32_t, const std::vector<uint8_t>&);
|
||||
|
||||
int can_fd{-1};
|
||||
|
||||
CanEventCallback event_callback{nullptr};
|
||||
|
||||
void publish_event(CanEvent event) {
|
||||
if (!event_callback) {
|
||||
return;
|
||||
}
|
||||
event_callback(event);
|
||||
}
|
||||
|
||||
messages::EV100 message_100;
|
||||
messages::EV101 message_101;
|
||||
messages::EV102 message_102;
|
||||
|
||||
messages::Charger108 message_108;
|
||||
messages::Charger109 message_109;
|
||||
|
||||
SendState tx_state{SendState::ID_100};
|
||||
};
|
||||
|
||||
} // namespace ieee2030::ev::io
|
||||
Reference in New Issue
Block a user