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:
44
tools/EVerest-main/lib/everest/slac/fsm/ev/src/context.cpp
Normal file
44
tools/EVerest-main/lib/everest/slac/fsm/ev/src/context.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 - 2023 Pionix GmbH and Contributors to EVerest
|
||||
#include <everest/slac/fsm/ev/context.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace slac::fsm::ev {
|
||||
|
||||
void Context::signal_state(const std::string& state) {
|
||||
if (callbacks.signal_state) {
|
||||
callbacks.signal_state(state);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::log_debug(const std::string& text) {
|
||||
if (callbacks.log_debug) {
|
||||
callbacks.log_debug(text);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::log_info(const std::string& text) {
|
||||
if (callbacks.log_info) {
|
||||
callbacks.log_info(text);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::log_warn(const std::string& text) {
|
||||
if (callbacks.log_warn) {
|
||||
callbacks.log_warn(text);
|
||||
}
|
||||
}
|
||||
|
||||
void Context::log_error(const std::string& text) {
|
||||
if (callbacks.log_error) {
|
||||
callbacks.log_error(text);
|
||||
}
|
||||
}
|
||||
|
||||
SessionParamaters::SessionParamaters(const uint8_t* run_id_, const uint8_t* evse_mac_) {
|
||||
memcpy(run_id, run_id_, sizeof(run_id));
|
||||
memcpy(evse_mac, evse_mac_, sizeof(evse_mac));
|
||||
}
|
||||
|
||||
} // namespace slac::fsm::ev
|
||||
303
tools/EVerest-main/lib/everest/slac/fsm/ev/src/states/others.cpp
Normal file
303
tools/EVerest-main/lib/everest/slac/fsm/ev/src/states/others.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 - 2023 Pionix GmbH and Contributors to EVerest
|
||||
#include <everest/slac/fsm/ev/states/others.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <random>
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
#include "timing_helper.hpp"
|
||||
|
||||
#include <everest/slac/fsm/ev/states/sounding.hpp>
|
||||
|
||||
namespace slac::fsm::ev {
|
||||
|
||||
void ResetState::enter() {
|
||||
ctx.signal_state("UNMATCHED");
|
||||
ctx.log_info("Entered Reset state");
|
||||
}
|
||||
|
||||
FSMSimpleState::HandleEventReturnType ResetState::handle_event(AllocatorType& sa, Event ev) {
|
||||
if (ev == Event::TRIGGER_MATCHING) {
|
||||
return sa.create_simple<InitSlacState>(ctx);
|
||||
} else {
|
||||
return sa.PASS_ON;
|
||||
}
|
||||
}
|
||||
|
||||
FSMSimpleState::CallbackReturnType ResetState::callback() {
|
||||
ctx.log_info("Called callback of ResetState");
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
FSMSimpleState::HandleEventReturnType InitSlacState::handle_event(AllocatorType& sa, Event ev) {
|
||||
if (ev == Event::SLAC_MESSAGE) {
|
||||
if (check_for_valid_parm_conf()) {
|
||||
ctx.signal_state("MATCHING");
|
||||
return sa.create_simple<SoundingState>(ctx, SessionParamaters{run_id, ctx.slac_message.get_src_mac()});
|
||||
}
|
||||
|
||||
return sa.HANDLED_INTERNALLY;
|
||||
} else if (ev == Event::FAILED) {
|
||||
return sa.create_simple<FailedState>(ctx);
|
||||
} else if (ev == Event::RESET) {
|
||||
return sa.create_simple<ResetState>(ctx);
|
||||
} else {
|
||||
return sa.PASS_ON;
|
||||
}
|
||||
}
|
||||
|
||||
void InitSlacState::enter() {
|
||||
ctx.log_info("Entered init state");
|
||||
|
||||
// generate random run_id
|
||||
std::random_device rnd_dev;
|
||||
std::mt19937 rng(rnd_dev());
|
||||
std::uniform_int_distribution<std::mt19937::result_type> dist256(0, 255);
|
||||
|
||||
for (auto& id : this->run_id) {
|
||||
id = dist256(rng);
|
||||
}
|
||||
}
|
||||
|
||||
FSMSimpleState::CallbackReturnType InitSlacState::callback() {
|
||||
if (num_of_tries == 0) {
|
||||
return send_parm_req();
|
||||
}
|
||||
|
||||
// did already send a parm req, check for timeout
|
||||
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto time_left = milliseconds_left(now, next_timeout);
|
||||
|
||||
if (time_left > 0) {
|
||||
// still have time
|
||||
return time_left;
|
||||
}
|
||||
|
||||
// timeout, check if we still have retries
|
||||
if (num_of_tries < 100) {
|
||||
// FIXME (aw): the norm says num_of_tries < slac::defs::C_EV_MATCH_RETRY
|
||||
// but doesn't seem to work in 'real life'
|
||||
return send_parm_req();
|
||||
}
|
||||
|
||||
// no retries left fail
|
||||
return Event::FAILED;
|
||||
}
|
||||
|
||||
int InitSlacState::send_parm_req() {
|
||||
slac::messages::cm_slac_parm_req msg;
|
||||
msg.application_type = 0x0;
|
||||
msg.security_type = 0x0;
|
||||
memcpy(msg.run_id, run_id, sizeof(msg.run_id));
|
||||
|
||||
ctx.send_slac_message(ctx.BROADCAST_MAC.data(), msg);
|
||||
|
||||
num_of_tries++;
|
||||
|
||||
next_timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(slac::defs::TT_MATCH_RESPONSE_MS);
|
||||
|
||||
return slac::defs::TT_MATCH_RESPONSE_MS;
|
||||
}
|
||||
|
||||
bool InitSlacState::check_for_valid_parm_conf() {
|
||||
const auto mmtype = ctx.slac_message.get_mmtype();
|
||||
if (mmtype != (slac::defs::MMTYPE_CM_SLAC_PARAM | slac::defs::MMTYPE_MODE_CNF)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// correct message type
|
||||
const auto& parm_cnf = ctx.slac_message.get_payload<slac::messages::cm_slac_parm_cnf>();
|
||||
|
||||
// it is not clear, whether we should use the m-sound target anyhow ... or if we should really validate any of the
|
||||
// fields except the run id
|
||||
const auto same_run_id = (memcmp(parm_cnf.run_id, run_id, sizeof(run_id)) == 0);
|
||||
|
||||
return same_run_id;
|
||||
}
|
||||
|
||||
MatchRequestState::MatchRequestState(Context& ctx, SessionParamaters session_parameters_) :
|
||||
FSMSimpleState(ctx), session_parameters(std::move(session_parameters_)) {
|
||||
}
|
||||
|
||||
FSMSimpleState::HandleEventReturnType MatchRequestState::handle_event(AllocatorType& sa, Event ev) {
|
||||
if (ev == Event::SLAC_MESSAGE) {
|
||||
const auto nmk = check_for_valid_match_req_conf();
|
||||
if (nmk) {
|
||||
return sa.create_simple<JoinNetworkState>(ctx, nmk);
|
||||
}
|
||||
|
||||
return sa.HANDLED_INTERNALLY;
|
||||
} else if (ev == Event::FAILED) {
|
||||
return sa.create_simple<FailedState>(ctx);
|
||||
} else if (ev == Event::RESET) {
|
||||
return sa.create_simple<ResetState>(ctx);
|
||||
} else {
|
||||
return sa.PASS_ON;
|
||||
}
|
||||
}
|
||||
|
||||
void MatchRequestState::enter() {
|
||||
ctx.log_info("Entered MatchRequestState state");
|
||||
}
|
||||
|
||||
FSMSimpleState::CallbackReturnType MatchRequestState::callback() {
|
||||
if (num_of_tries == 0) {
|
||||
return send_match_req();
|
||||
}
|
||||
|
||||
// did already send a parm req, check for timeout
|
||||
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto time_left = milliseconds_left(now, next_timeout);
|
||||
|
||||
if (time_left > 0) {
|
||||
// still have time
|
||||
return time_left;
|
||||
}
|
||||
|
||||
// timeout, check if we still have retries
|
||||
if (num_of_tries < slac::defs::C_EV_MATCH_RETRY) {
|
||||
return send_match_req();
|
||||
}
|
||||
|
||||
// no retries left fail
|
||||
return Event::FAILED;
|
||||
}
|
||||
|
||||
const uint8_t* MatchRequestState::check_for_valid_match_req_conf() {
|
||||
if (num_of_tries == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto mmtype = ctx.slac_message.get_mmtype();
|
||||
if (mmtype != (slac::defs::MMTYPE_CM_SLAC_MATCH | slac::defs::MMTYPE_MODE_CNF)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// correct message type
|
||||
const auto& match_cnf = ctx.slac_message.get_payload<slac::messages::cm_slac_match_cnf>();
|
||||
|
||||
const auto run_id_match =
|
||||
(memcmp(session_parameters.run_id, match_cnf.run_id, sizeof(session_parameters.run_id)) == 0);
|
||||
|
||||
if (run_id_match) {
|
||||
return match_cnf.nmk;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int MatchRequestState::send_match_req() {
|
||||
slac::messages::cm_slac_match_req msg;
|
||||
msg.application_type = 0x0;
|
||||
msg.security_type = 0x0;
|
||||
msg.mvf_length = htole16(0x3e); // FIXME (aw) fixed constant
|
||||
memset(msg.pev_id, 0, sizeof(msg.pev_id));
|
||||
memcpy(msg.pev_mac, ctx.ev_host_mac.data(), sizeof(msg.pev_mac));
|
||||
memset(msg.evse_id, 0, sizeof(msg.evse_id));
|
||||
memcpy(msg.evse_mac, session_parameters.evse_mac, sizeof(msg.evse_mac));
|
||||
memcpy(msg.run_id, session_parameters.run_id, sizeof(msg.run_id));
|
||||
memset(msg._reserved, 0, sizeof(msg._reserved));
|
||||
|
||||
ctx.send_slac_message(session_parameters.evse_mac, msg);
|
||||
|
||||
num_of_tries++;
|
||||
|
||||
next_timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(slac::defs::TT_MATCH_RESPONSE_MS);
|
||||
|
||||
return slac::defs::TT_MATCH_RESPONSE_MS;
|
||||
}
|
||||
|
||||
JoinNetworkState::JoinNetworkState(Context& ctx, const uint8_t* nmk_) : FSMSimpleState(ctx) {
|
||||
memcpy(nmk, nmk_, sizeof(nmk));
|
||||
}
|
||||
|
||||
FSMSimpleState::HandleEventReturnType JoinNetworkState::handle_event(AllocatorType& sa, Event ev) {
|
||||
if (ev == Event::SLAC_MESSAGE) {
|
||||
if (check_for_valid_set_key_conf()) {
|
||||
// FIXME (aw): later on, we also need to distinguish between set_key failed
|
||||
return sa.create_simple<MatchedState>(ctx);
|
||||
}
|
||||
|
||||
return sa.HANDLED_INTERNALLY;
|
||||
} else if (ev == Event::FAILED) {
|
||||
return sa.create_simple<FailedState>(ctx);
|
||||
} else if (ev == Event::RESET) {
|
||||
return sa.create_simple<ResetState>(ctx);
|
||||
} else {
|
||||
return sa.PASS_ON;
|
||||
}
|
||||
}
|
||||
|
||||
void JoinNetworkState::enter() {
|
||||
ctx.log_info("Entered JoinNetwork state");
|
||||
|
||||
slac::messages::cm_set_key_req msg;
|
||||
msg.key_type = slac::defs::CM_SET_KEY_REQ_KEY_TYPE_NMK;
|
||||
msg.my_nonce = 0xAAAAAAAA;
|
||||
msg.your_nonce = 0x00000000;
|
||||
msg.pid = slac::defs::CM_SET_KEY_REQ_PID_HLE;
|
||||
msg.prn = htole16(slac::defs::CM_SET_KEY_REQ_PRN_UNUSED);
|
||||
msg.pmn = slac::defs::CM_SET_KEY_REQ_PMN_UNUSED;
|
||||
msg.cco_capability = slac::defs::CM_SET_KEY_REQ_CCO_CAP_NONE;
|
||||
slac::utils::generate_nid_from_nmk(msg.nid, nmk);
|
||||
msg.new_eks = slac::defs::CM_SET_KEY_REQ_PEKS_NMK_KNOWN_TO_STA;
|
||||
memcpy(msg.new_key, nmk, sizeof(msg.new_key));
|
||||
|
||||
ctx.send_slac_message(ctx.EV_PLC_MAC.data(), msg);
|
||||
|
||||
timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(SET_KEY_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
FSMSimpleState::CallbackReturnType JoinNetworkState::callback() {
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto time_left = milliseconds_left(now, timeout);
|
||||
|
||||
if (time_left > 0) {
|
||||
// still have time
|
||||
return time_left;
|
||||
}
|
||||
|
||||
// we reached the set key timeout
|
||||
return Event::FAILED;
|
||||
}
|
||||
|
||||
bool JoinNetworkState::check_for_valid_set_key_conf() {
|
||||
const auto mmtype = ctx.slac_message.get_mmtype();
|
||||
if (mmtype != (slac::defs::MMTYPE_CM_SET_KEY | slac::defs::MMTYPE_MODE_CNF)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// correct message type
|
||||
const auto& set_key_cnf = ctx.slac_message.get_payload<slac::messages::cm_set_key_cnf>();
|
||||
|
||||
// FIXME (aw): validation of the message?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FSMSimpleState::HandleEventReturnType MatchedState::handle_event(AllocatorType& sa, Event ev) {
|
||||
if (ev == Event::RESET) {
|
||||
return sa.create_simple<ResetState>(ctx);
|
||||
} else if (ev == Event::SLAC_MESSAGE) {
|
||||
return sa.HANDLED_INTERNALLY;
|
||||
} else {
|
||||
return sa.PASS_ON;
|
||||
}
|
||||
}
|
||||
|
||||
FSMSimpleState::HandleEventReturnType FailedState::handle_event(AllocatorType& sa, Event ev) {
|
||||
if (ev == Event::RESET) {
|
||||
return sa.create_simple<ResetState>(ctx);
|
||||
} else if (ev == Event::SLAC_MESSAGE) {
|
||||
return sa.HANDLED_INTERNALLY;
|
||||
} else {
|
||||
return sa.PASS_ON;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace slac::fsm::ev
|
||||
@@ -0,0 +1,154 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 - 2023 Pionix GmbH and Contributors to EVerest
|
||||
#include <everest/slac/fsm/ev/states/sounding.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <random>
|
||||
|
||||
#include "timing_helper.hpp"
|
||||
|
||||
#include <everest/slac/fsm/ev/states/others.hpp>
|
||||
|
||||
namespace slac::fsm::ev {
|
||||
|
||||
SoundingState::SoundingState(Context& ctx, SessionParamaters session_parameters_) :
|
||||
FSMSimpleState(ctx), session_parameters(std::move(session_parameters_)) {
|
||||
}
|
||||
|
||||
void SoundingState::enter() {
|
||||
sounding_timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(slac::defs::TT_EV_ATTEN_RESULTS_MS);
|
||||
}
|
||||
|
||||
FSMSimpleState::CallbackReturnType SoundingState::callback() {
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto sounding_time_left = milliseconds_left(now, sounding_timeout);
|
||||
|
||||
if (sounding_time_left <= 0) {
|
||||
return Event::FAILED;
|
||||
}
|
||||
|
||||
if (count_mnbc_sound_sent == 10) {
|
||||
// we're already done, return time left until sounding timeout
|
||||
return sounding_time_left;
|
||||
}
|
||||
|
||||
if (count_start_atten_char_sent == 0) {
|
||||
// no sounding messages have been send yet
|
||||
next_timeout = now;
|
||||
}
|
||||
|
||||
const auto next_step_time_left = milliseconds_left(now, next_timeout);
|
||||
|
||||
if (next_step_time_left > 0) {
|
||||
// just idle a bit
|
||||
return std::min(next_step_time_left, sounding_time_left);
|
||||
}
|
||||
|
||||
// need to issue the next step
|
||||
if (do_sounding()) {
|
||||
// FIXME (aw): how to setup the next timeout, we could send the everything right away, but waiting at least a
|
||||
// bit seems to be a good practice
|
||||
const auto next_step_delay_ms = 20; // FIXME (aw): which value to use? TP_EV_BATCH_MSG_INTERVAL_MS
|
||||
next_timeout = now + std::chrono::milliseconds(next_step_delay_ms);
|
||||
return std::min(next_step_delay_ms, static_cast<int>(sounding_time_left));
|
||||
}
|
||||
|
||||
return sounding_time_left;
|
||||
}
|
||||
|
||||
FSMSimpleState::HandleEventReturnType SoundingState::handle_event(AllocatorType& sa, Event ev) {
|
||||
if (ev == Event::SLAC_MESSAGE) {
|
||||
if (handle_valid_atten_char_ind()) {
|
||||
return sa.create_simple<MatchRequestState>(ctx, session_parameters);
|
||||
}
|
||||
return sa.HANDLED_INTERNALLY;
|
||||
} else if (ev == Event::RESET) {
|
||||
return sa.create_simple<ResetState>(ctx);
|
||||
}
|
||||
|
||||
return sa.PASS_ON;
|
||||
}
|
||||
|
||||
bool SoundingState::do_sounding() {
|
||||
if (count_start_atten_char_sent < slac::defs::C_EV_START_ATTEN_CHAR_INDS) {
|
||||
|
||||
slac::messages::cm_start_atten_char_ind msg;
|
||||
msg.application_type = 0x0;
|
||||
msg.security_type = 0x0;
|
||||
msg.num_sounds = slac::defs::C_EV_MATCH_MNBC;
|
||||
msg.timeout = (slac::defs::TT_EVSE_MATCH_MNBC_MS + 99) / 100; // in multiples of 100ms!
|
||||
msg.resp_type = 0x01; // fixed value indicating 'other Green Phy station'
|
||||
memcpy(msg.forwarding_sta, ctx.ev_host_mac.data(), sizeof(msg.forwarding_sta));
|
||||
memcpy(msg.run_id, session_parameters.run_id, sizeof(msg.run_id));
|
||||
|
||||
ctx.send_slac_message(ctx.BROADCAST_MAC.data(), msg);
|
||||
|
||||
count_start_atten_char_sent++;
|
||||
|
||||
} else if (count_mnbc_sound_sent < slac::defs::C_EV_MATCH_MNBC) {
|
||||
count_mnbc_sound_sent++;
|
||||
|
||||
slac::messages::cm_mnbc_sound_ind msg;
|
||||
msg.application_type = 0x0;
|
||||
msg.security_type = 0x0;
|
||||
memset(msg.sender_id, 0, sizeof(msg.sender_id));
|
||||
msg.remaining_sound_count = slac::defs::C_EV_MATCH_MNBC - count_mnbc_sound_sent;
|
||||
memcpy(msg.run_id, session_parameters.run_id, sizeof(msg.run_id));
|
||||
memset(msg._reserved, 0, sizeof(msg._reserved));
|
||||
|
||||
// FIXME (aw): does this have any performance penalties?
|
||||
std::random_device rnd_dev;
|
||||
std::mt19937 rng(rnd_dev());
|
||||
std::uniform_int_distribution<std::mt19937::result_type> dist256(0, 255);
|
||||
|
||||
for (auto& random : msg.random) {
|
||||
random = dist256(rng);
|
||||
}
|
||||
|
||||
ctx.send_slac_message(ctx.BROADCAST_MAC.data(), msg);
|
||||
}
|
||||
|
||||
return (count_mnbc_sound_sent < slac::defs::C_EV_MATCH_MNBC);
|
||||
}
|
||||
|
||||
bool SoundingState::handle_valid_atten_char_ind() {
|
||||
if (count_mnbc_sound_sent < slac::defs::C_EV_MATCH_MNBC) {
|
||||
ctx.log_info("Received unexpected message while SOUNDING");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto mmtype = ctx.slac_message.get_mmtype();
|
||||
|
||||
if (mmtype != (slac::defs::MMTYPE_CM_ATTEN_CHAR | slac::defs::MMTYPE_MODE_IND)) {
|
||||
ctx.log_info("Received unexpected message after SOUNDING");
|
||||
return false;
|
||||
}
|
||||
|
||||
// correct message type
|
||||
const auto& atten_char = ctx.slac_message.get_payload<slac::messages::cm_atten_char_ind>();
|
||||
|
||||
const auto run_id_match =
|
||||
(memcmp(session_parameters.run_id, atten_char.run_id, sizeof(session_parameters.run_id)) == 0);
|
||||
|
||||
if (run_id_match == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// reply
|
||||
slac::messages::cm_atten_char_rsp response;
|
||||
response.application_type = 0x0;
|
||||
response.security_type = 0x0;
|
||||
memcpy(response.source_address, ctx.ev_host_mac.data(), sizeof(response.source_address));
|
||||
memcpy(response.run_id, atten_char.run_id, sizeof(response.run_id));
|
||||
memset(response.source_id, 0, sizeof(response.source_id));
|
||||
memset(response.resp_id, 0, sizeof(response.resp_id));
|
||||
response.result = 0x0;
|
||||
|
||||
ctx.send_slac_message(session_parameters.evse_mac, response);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace slac::fsm::ev
|
||||
@@ -0,0 +1,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 - 2023 Pionix GmbH and Contributors to EVerest
|
||||
#ifndef EV_SLAC_STATES_TIMING_HELPER_HPP
|
||||
#define EV_SLAC_STATES_TIMING_HELPER_HPP
|
||||
|
||||
#include <chrono>
|
||||
|
||||
template <typename TimepointType> auto milliseconds_left(const TimepointType& from, const TimepointType& to) {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(to - from).count();
|
||||
}
|
||||
|
||||
#endif // EV_SLAC_STATES_TIMING_HELPER_HPP
|
||||
Reference in New Issue
Block a user