- 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
142 lines
4.5 KiB
C++
142 lines
4.5 KiB
C++
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright Pionix GmbH and Contributors to EVerest
|
|
#include "session_logger.hpp"
|
|
|
|
#include <chrono>
|
|
#include <ctime>
|
|
#include <fstream>
|
|
#include <iomanip>
|
|
#include <stdexcept>
|
|
|
|
#include <date/date.h>
|
|
|
|
#include <iso15118/session/logger.hpp>
|
|
|
|
#include <everest/logging.hpp>
|
|
|
|
using LogEvent = iso15118::session::logging::Event;
|
|
|
|
std::string get_filename_for_current_time() {
|
|
const auto now = std::chrono::system_clock::now();
|
|
const auto now_t = std::chrono::system_clock::to_time_t(now);
|
|
|
|
std::tm now_tm;
|
|
gmtime_r(&now_t, &now_tm);
|
|
|
|
char buffer[64];
|
|
strftime(buffer, sizeof(buffer), "%y%m%d_%H-%M-%S.yaml", &now_tm);
|
|
return buffer;
|
|
}
|
|
|
|
// static auto timepoint_to_string(const iso15118::session::logging::TimePoint& timepoint) {
|
|
// using namespace date;
|
|
// return static_cast<std::string>(timepoint);
|
|
// }
|
|
|
|
std::ostream& operator<<(std::ostream& os, const iso15118::session::logging::ExiMessageDirection& direction) {
|
|
using Direction = iso15118::session::logging::ExiMessageDirection;
|
|
switch (direction) {
|
|
case Direction::FROM_EV:
|
|
return os << "FROM_EV";
|
|
case Direction::TO_EV:
|
|
return os << "TO_EV";
|
|
}
|
|
|
|
return os;
|
|
}
|
|
|
|
class SessionLog {
|
|
public:
|
|
SessionLog(const std::string& file_name) : file(file_name.c_str(), std::ios::out) {
|
|
if (not file.good()) {
|
|
throw std::runtime_error("Failed to open file " + file_name + " for writing iso15118 session log");
|
|
}
|
|
|
|
EVLOG_info << "Created logfile at: " << file_name;
|
|
}
|
|
void operator()(const iso15118::session::logging::SimpleEvent& event) {
|
|
file << "- type: INFO\n";
|
|
add_timestamp(event.time_point);
|
|
file << " info: \"" << event.info << "\"\n";
|
|
}
|
|
|
|
void operator()(const iso15118::session::logging::ExiMessageEvent& event) {
|
|
file << "- type: EXI\n";
|
|
add_timestamp(event.time_point);
|
|
file << " direction: " << event.direction << "\n";
|
|
file << " sdp_payload_type: " << event.payload_type << "\n";
|
|
add_hex_encoded_data(event.data, event.len);
|
|
}
|
|
|
|
void flush() {
|
|
file.flush();
|
|
}
|
|
|
|
private:
|
|
std::fstream file;
|
|
|
|
void add_timestamp(const iso15118::session::logging::TimePoint& timestamp) {
|
|
if (not timestamp_initialized) {
|
|
last_timestamp = timestamp;
|
|
timestamp_initialized = true;
|
|
}
|
|
|
|
const auto offset_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp - last_timestamp);
|
|
file << " timestamp_offset: " << offset_ms.count() << "\n";
|
|
|
|
const auto dp = date::floor<date::days>(timestamp);
|
|
const auto time = date::make_time(timestamp - dp);
|
|
const auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(time.subseconds());
|
|
file << " timestamp: \"";
|
|
file << std::setfill('0') << std::setw(2) << time.hours().count() << ":";
|
|
file << std::setfill('0') << std::setw(2) << time.minutes().count() << ":";
|
|
file << std::setfill('0') << std::setw(2) << time.seconds().count() << ".";
|
|
file << std::setfill('0') << std::setw(4) << milliseconds.count();
|
|
file << "\"\n";
|
|
|
|
last_timestamp = timestamp;
|
|
}
|
|
|
|
void add_hex_encoded_data(const uint8_t* data, size_t len) {
|
|
file << " data: \"";
|
|
|
|
const auto flags = file.flags();
|
|
|
|
file << std::hex;
|
|
|
|
for (int i = 0; i < len; ++i) {
|
|
file << std::setfill('0') << std::setw(2) << static_cast<int>(data[i]);
|
|
}
|
|
|
|
file.flags(flags);
|
|
file << "\"\n";
|
|
}
|
|
|
|
iso15118::session::logging::TimePoint last_timestamp;
|
|
bool timestamp_initialized{false};
|
|
};
|
|
|
|
SessionLogger::SessionLogger(std::filesystem::path output_dir_) : output_dir(std::filesystem::absolute(output_dir_)) {
|
|
// FIXME (aw): this is quite brute force ...
|
|
if (not std::filesystem::exists(output_dir)) {
|
|
std::filesystem::create_directory(output_dir);
|
|
}
|
|
|
|
iso15118::session::logging::set_session_log_callback([this](std::uintptr_t id, const LogEvent& event) {
|
|
auto log_it = logs.find(id);
|
|
if (log_it == logs.end()) {
|
|
const auto log_file_name = output_dir / get_filename_for_current_time();
|
|
const auto emplaced = logs.emplace(id, std::make_unique<SessionLog>(log_file_name.string()));
|
|
|
|
log_it = emplaced.first;
|
|
}
|
|
|
|
auto& log = *log_it->second;
|
|
|
|
std::visit(log, event);
|
|
log.flush();
|
|
});
|
|
}
|
|
|
|
SessionLogger::~SessionLogger() = default;
|