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:
311
tools/EVerest-main/lib/everest/slac/test/evse_slac_test.cpp
Normal file
311
tools/EVerest-main/lib/everest/slac/test/evse_slac_test.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2023 - 2023 Pionix GmbH and Contributors to EVerest
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <thread>
|
||||
|
||||
#include <everest/slac/fsm/evse/fsm.hpp>
|
||||
#include <everest/slac/fsm/evse/states/others.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
static auto create_cm_set_key_cnf() {
|
||||
// FIXME (aw): needs to be fully implemented!
|
||||
slac::messages::cm_set_key_cnf set_key_cnf;
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_payload(&set_key_cnf, sizeof(set_key_cnf),
|
||||
(slac::defs::MMTYPE_CM_SET_KEY | slac::defs::MMTYPE_MODE_CNF), slac::defs::MMV::AV_1_1);
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
static auto create_cm_validate_req() {
|
||||
slac::messages::cm_validate_req validate_req;
|
||||
validate_req.signal_type = slac::defs::CM_VALIDATE_REQ_SIGNAL_TYPE;
|
||||
validate_req.timer = 0;
|
||||
validate_req.result = slac::defs::CM_VALIDATE_REQ_RESULT_READY;
|
||||
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_payload(&validate_req, sizeof(validate_req),
|
||||
(slac::defs::MMTYPE_CM_VALIDATE | slac::defs::MMTYPE_MODE_REQ), slac::defs::MMV::AV_1_1);
|
||||
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
struct EVSession {
|
||||
EVSession(const std::array<uint8_t, 8>& run_id_, const std::array<uint8_t, 6>& mac_) : run_id(run_id_), mac(mac_){};
|
||||
|
||||
// FIXME (aw): all these create_cm_* need to be fully implemented!
|
||||
auto create_cm_slac_parm_req() {
|
||||
slac::messages::cm_slac_parm_req parm_req;
|
||||
std::copy(run_id.begin(), run_id.end(), parm_req.run_id);
|
||||
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_ethernet_header(mac.data(), mac.data());
|
||||
hp_message.setup_payload(&parm_req, sizeof(parm_req),
|
||||
(slac::defs::MMTYPE_CM_SLAC_PARAM | slac::defs::MMTYPE_MODE_REQ),
|
||||
slac::defs::MMV::AV_1_1);
|
||||
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
auto create_cm_start_atten_char_ind() {
|
||||
slac::messages::cm_start_atten_char_ind atten_char_ind;
|
||||
std::copy(run_id.begin(), run_id.end(), atten_char_ind.run_id);
|
||||
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_ethernet_header(mac.data(), mac.data());
|
||||
hp_message.setup_payload(&atten_char_ind, sizeof(atten_char_ind),
|
||||
(slac::defs::MMTYPE_CM_START_ATTEN_CHAR | slac::defs::MMTYPE_MODE_IND),
|
||||
slac::defs::MMV::AV_1_1);
|
||||
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
auto create_cm_mnbc_sound_ind() {
|
||||
slac::messages::cm_mnbc_sound_ind sound_ind;
|
||||
std::copy(run_id.begin(), run_id.end(), sound_ind.run_id);
|
||||
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_ethernet_header(mac.data(), mac.data());
|
||||
hp_message.setup_payload(&sound_ind, sizeof(sound_ind),
|
||||
(slac::defs::MMTYPE_CM_MNBC_SOUND | slac::defs::MMTYPE_MODE_IND),
|
||||
slac::defs::MMV::AV_1_1);
|
||||
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
auto create_cm_atten_profile_ind() {
|
||||
slac::messages::cm_atten_profile_ind profile_ind;
|
||||
std::copy(mac.begin(), mac.end(), profile_ind.pev_mac);
|
||||
profile_ind.num_groups = slac::defs::AAG_LIST_LEN;
|
||||
|
||||
for (int i = 0; i < slac::defs::AAG_LIST_LEN; ++i) {
|
||||
profile_ind.aag[i] = i;
|
||||
}
|
||||
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_ethernet_header(mac.data(), mac.data());
|
||||
hp_message.setup_payload(&profile_ind, sizeof(profile_ind),
|
||||
(slac::defs::MMTYPE_CM_ATTEN_PROFILE | slac::defs::MMTYPE_MODE_IND),
|
||||
slac::defs::MMV::AV_1_1);
|
||||
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
auto create_cm_atten_char_rsp() {
|
||||
slac::messages::cm_atten_char_rsp atten_char;
|
||||
std::copy(run_id.begin(), run_id.end(), atten_char.run_id);
|
||||
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_ethernet_header(mac.data(), mac.data());
|
||||
hp_message.setup_payload(&atten_char, sizeof(atten_char),
|
||||
(slac::defs::MMTYPE_CM_ATTEN_CHAR | slac::defs::MMTYPE_MODE_RSP),
|
||||
slac::defs::MMV::AV_1_1);
|
||||
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
auto create_cm_slac_match_req() {
|
||||
slac::messages::cm_slac_match_req match_req;
|
||||
std::copy(run_id.begin(), run_id.end(), match_req.run_id);
|
||||
|
||||
slac::messages::HomeplugMessage hp_message;
|
||||
hp_message.setup_ethernet_header(mac.data(), mac.data());
|
||||
hp_message.setup_payload(&match_req, sizeof(match_req),
|
||||
(slac::defs::MMTYPE_CM_SLAC_MATCH | slac::defs::MMTYPE_MODE_REQ),
|
||||
slac::defs::MMV::AV_1_1);
|
||||
|
||||
return hp_message;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<uint8_t, 8> run_id;
|
||||
const std::array<uint8_t, ETH_ALEN>& mac;
|
||||
};
|
||||
|
||||
void feed_machine_for(slac::fsm::evse::FSM& machine, int period_ms,
|
||||
fsm::FeedResult<slac::fsm::evse::FSMReturnType> feed_result) {
|
||||
using namespace std::chrono;
|
||||
|
||||
auto end_tp = steady_clock::now() + milliseconds(period_ms);
|
||||
|
||||
while (true) {
|
||||
if (feed_result.transition()) {
|
||||
// need to call feed
|
||||
} else if (feed_result.unhandled_event()) {
|
||||
printf("DEBUG: got an unhandled event\n");
|
||||
break;
|
||||
} else if (feed_result.internal_error()) {
|
||||
printf("ERROR: internal FSM error\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (feed_result.has_value() == false) {
|
||||
// nothing to do
|
||||
break;
|
||||
} else if (feed_result.has_value() == true) {
|
||||
const auto timeout = *feed_result;
|
||||
if (timeout == 0) {
|
||||
// need to call feed directly
|
||||
} else {
|
||||
auto next_tp = steady_clock::now() + milliseconds(timeout);
|
||||
if (next_tp > end_tp) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_until(next_tp);
|
||||
}
|
||||
} else {
|
||||
printf("ERROR: unknown feed result case\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
feed_result = machine.feed();
|
||||
}
|
||||
|
||||
std::this_thread::sleep_until(end_tp);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
const auto ATTENUATION_ADJUSTMENT = 10;
|
||||
printf("Hi from SLAC!\n");
|
||||
|
||||
std::optional<slac::messages::HomeplugMessage> msg_in;
|
||||
|
||||
slac::fsm::evse::ContextCallbacks callbacks;
|
||||
callbacks.log = [](const std::string& text) { fmt::print("SLAC LOG: {}\n", text); };
|
||||
|
||||
callbacks.send_raw_slac = [&msg_in](slac::messages::HomeplugMessage& hp_message) { msg_in = hp_message; };
|
||||
|
||||
auto ctx = slac::fsm::evse::Context(callbacks);
|
||||
ctx.slac_config.sounding_atten_adjustment = ATTENUATION_ADJUSTMENT;
|
||||
ctx.slac_config.chip_reset.enabled = false;
|
||||
|
||||
auto machine = slac::fsm::evse::FSM();
|
||||
|
||||
//
|
||||
// reset machine
|
||||
//
|
||||
machine.reset<slac::fsm::evse::ResetState>(ctx);
|
||||
auto fr = machine.feed();
|
||||
|
||||
// assert that CM_SET_KEY_REQ gets set!
|
||||
if (!msg_in.has_value() || msg_in->get_mmtype() != (slac::defs::MMTYPE_CM_SET_KEY | slac::defs::MMTYPE_MODE_REQ)) {
|
||||
printf("Expected CM_SET_KEY_REQ!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
msg_in.reset();
|
||||
}
|
||||
|
||||
feed_machine_for(machine, 230, fr);
|
||||
|
||||
// feed in CM_SET_KEY_CNF
|
||||
ctx.slac_message_payload = create_cm_set_key_cnf();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
// should be idle state now, send ENTER_BCD, to enter MATCHING
|
||||
machine.handle_event(slac::fsm::evse::Event::ENTER_BCD);
|
||||
fr = machine.feed();
|
||||
|
||||
feed_machine_for(machine, 300, fr);
|
||||
|
||||
// create session 1 and inject CM_SLAC_PARM_REQ
|
||||
auto session_1 = EVSession({0, 1, 2, 3, 4, 5, 6, 7}, {0xca, 0xfe, 0xca, 0xfe, 0xca, 0xfe});
|
||||
ctx.slac_message_payload = session_1.create_cm_slac_parm_req();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
// assert that CM_SLAC_PARM_CNF gets set!
|
||||
if (!msg_in.has_value() ||
|
||||
msg_in->get_mmtype() != (slac::defs::MMTYPE_CM_SLAC_PARAM | slac::defs::MMTYPE_MODE_CNF)) {
|
||||
printf("Expected CM_SLAC_PARM_CNF!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
msg_in.reset();
|
||||
}
|
||||
|
||||
feed_machine_for(machine, 233, fr);
|
||||
|
||||
// inject CM_START_ATTEN_CHAR_IND
|
||||
ctx.slac_message_payload = session_1.create_cm_start_atten_char_ind();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
// inject all the soundings ...
|
||||
for (int i = 0; i < slac::defs::CM_SLAC_PARM_CNF_NUM_SOUNDS - 1; i++) {
|
||||
ctx.slac_message_payload = session_1.create_cm_mnbc_sound_ind();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
ctx.slac_message_payload = session_1.create_cm_atten_profile_ind();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
}
|
||||
|
||||
feed_machine_for(machine, 700 + 1 * 45, fr);
|
||||
|
||||
// assert that CM_ATTEN_CHAR_IND gets set!
|
||||
if (!msg_in.has_value() ||
|
||||
msg_in->get_mmtype() != (slac::defs::MMTYPE_CM_ATTEN_CHAR | slac::defs::MMTYPE_MODE_IND)) {
|
||||
printf("Expected CM_ATTEN_CHAR_IND!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
auto atten_char_ind = msg_in->get_payload<slac::messages::cm_atten_char_ind>();
|
||||
for (int i = 0; i < slac::defs::AAG_LIST_LEN; ++i) {
|
||||
if (atten_char_ind.attenuation_profile.aag[i] != i + ATTENUATION_ADJUSTMENT) {
|
||||
printf("Averaging not correct in ATTEN_CHAR_IND\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
msg_in.reset();
|
||||
}
|
||||
|
||||
// "async" insert an CM_VALIDATE.REQ
|
||||
ctx.slac_message_payload = create_cm_validate_req();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
// assert that CM_VALIDATE.CNF gets set!
|
||||
if (!msg_in.has_value() || msg_in->get_mmtype() != (slac::defs::MMTYPE_CM_VALIDATE | slac::defs::MMTYPE_MODE_CNF)) {
|
||||
printf("Expected CM_VALIDATE.CNF!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
// check for correct "failure" result
|
||||
auto validate_cnf = msg_in->get_payload<slac::messages::cm_validate_cnf>();
|
||||
if (validate_cnf.result != slac::defs::CM_VALIDATE_REQ_RESULT_FAILURE) {
|
||||
printf("Expected result field of CM_VALIDATE.CNF to be set to failure\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
// inject CM_ATTEN_CHAR_RSP
|
||||
ctx.slac_message_payload = session_1.create_cm_atten_char_rsp();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
feed_machine_for(machine, 1000, fr);
|
||||
|
||||
// inject messages from a second session
|
||||
auto session_2 = EVSession({9, 1, 2, 3, 4, 5, 6, 7}, {0xbe, 0xaf, 0xbe, 0xaf, 0xbe, 0xaf});
|
||||
ctx.slac_message_payload = session_2.create_cm_slac_parm_req();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
feed_machine_for(machine, 1000, fr);
|
||||
|
||||
// inject CM_SLAC_MATCH_REQ
|
||||
ctx.slac_message_payload = session_1.create_cm_slac_match_req();
|
||||
machine.handle_event(slac::fsm::evse::Event::SLAC_MESSAGE);
|
||||
fr = machine.feed();
|
||||
|
||||
// assert that CM_SLAC_MATCH_CNF gets set!
|
||||
if (!msg_in.has_value() ||
|
||||
msg_in->get_mmtype() != (slac::defs::MMTYPE_CM_SLAC_MATCH | slac::defs::MMTYPE_MODE_CNF)) {
|
||||
printf("Expected CM_ATTEN_CHAR_IND!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
msg_in.reset();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user