diff --git a/modules/YetiDriver/CMakeLists.txt b/modules/YetiDriver/CMakeLists.txt index f7a826a2f0..3948560755 100644 --- a/modules/YetiDriver/CMakeLists.txt +++ b/modules/YetiDriver/CMakeLists.txt @@ -36,4 +36,6 @@ target_sources(${MODULE_NAME} # ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1 # insert other things like install cmds etc here +install(FILES yetiR1_2.0-1_firmware.bin DESTINATION ${CMAKE_INSTALL_DATADIR}/everest/modules/YetiDriver/firmware) + # ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1 diff --git a/modules/YetiDriver/board_support/evse_board_supportImpl.cpp b/modules/YetiDriver/board_support/evse_board_supportImpl.cpp index bcf12ed44f..0d1dfb4c7f 100644 --- a/modules/YetiDriver/board_support/evse_board_supportImpl.cpp +++ b/modules/YetiDriver/board_support/evse_board_supportImpl.cpp @@ -71,28 +71,39 @@ void evse_board_supportImpl::init() { std::lock_guard lock(capsMutex); caps.min_current_A_import = mod->config.caps_min_current_A; - caps.max_current_A_import = 6; + caps.max_current_A_import = 16; caps.min_phase_count_import = 1; caps.max_phase_count_import = 3; caps.supports_changing_phases_during_charging = false; + caps.connector_type = types::evse_board_support::Connector_type::IEC62196Type2Cable; caps.min_current_A_export = mod->config.caps_min_current_A; - caps.max_current_A_export = 6; + caps.max_current_A_export = 16; caps.min_phase_count_export = 1; caps.max_phase_count_export = 3; caps.supports_changing_phases_during_charging = false; } mod->serial.signalCPState.connect([this](CpState cp_state) { - publish_event(cast_event_type(cp_state)); - - if (cp_state == CpState_STATE_A) { - mod->clear_errors_on_unplug(); + if (cp_state not_eq last_cp_state) { + auto event_cp_state = cast_event_type(cp_state); + EVLOG_info << "CP state changed: " << types::board_support_common::event_to_string(event_cp_state.event); + publish_event(event_cp_state); + + if (cp_state == CpState_STATE_A) { + mod->clear_errors_on_unplug(); + } + last_cp_state = cp_state; + } + }); + mod->serial.signalRelaisState.connect([this](bool relais_state) { + if (last_relais_state not_eq relais_state) { + publish_event(cast_event_type(relais_state)); + last_relais_state = relais_state; } }); - mod->serial.signalRelaisState.connect([this](bool relais_state) { publish_event(cast_event_type(relais_state)); }); + mod->serial.signalPPState.connect([this](PpState pp_state) { - std::lock_guard lock(capsMutex); last_pp = cast_pp_type(pp_state); publish_ac_pp_ampacity(last_pp); }); @@ -113,20 +124,26 @@ void evse_board_supportImpl::init() { caps.max_phase_count_export = l.hwcap_max_phase_count; caps.supports_changing_phases_during_charging = l.supports_changing_phases_during_charging; + if (not caps_received) { + EVLOG_info << "Yeti Controller Configuration:"; + EVLOG_info << " Hardware revision: " << l.hw_revision; + EVLOG_info << " Firmware version: " << l.sw_version_string; + EVLOG_info << " Current Limit: " << l.hwcap_max_current; + } caps_received = true; }); } void evse_board_supportImpl::ready() { + wait_for_caps(); +} + +void evse_board_supportImpl::wait_for_caps() { // Wait for caps to be received at least once int i; for (i = 0; i < 50; i++) { - { - std::lock_guard lock(capsMutex); - if (caps_received) - break; - } - + if (caps_received) + break; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (i == 49) { @@ -136,6 +153,7 @@ void evse_board_supportImpl::ready() { } types::evse_board_support::HardwareCapabilities evse_board_supportImpl::handle_get_hw_capabilities() { + wait_for_caps(); std::lock_guard lock(capsMutex); return caps; } diff --git a/modules/YetiDriver/board_support/evse_board_supportImpl.hpp b/modules/YetiDriver/board_support/evse_board_supportImpl.hpp index 636a4bd1d5..259cbdca12 100644 --- a/modules/YetiDriver/board_support/evse_board_supportImpl.hpp +++ b/modules/YetiDriver/board_support/evse_board_supportImpl.hpp @@ -59,9 +59,12 @@ class evse_board_supportImpl : public evse_board_supportImplBase { // ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1 // insert your private definitions here types::evse_board_support::HardwareCapabilities caps; - bool caps_received{false}; + std::atomic_bool caps_received{false}; std::mutex capsMutex; - types::board_support_common::ProximityPilot last_pp; + CpState last_cp_state{CpState::CpState_STATE_E}; + bool last_relais_state{false}; + types::board_support_common::ProximityPilot last_pp{types::board_support_common::Ampacity::None}; + void wait_for_caps(); // ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1 }; diff --git a/modules/YetiDriver/yetiR1_2.0-1_firmware.bin b/modules/YetiDriver/yetiR1_2.0-1_firmware.bin new file mode 100755 index 0000000000..0a15174efe Binary files /dev/null and b/modules/YetiDriver/yetiR1_2.0-1_firmware.bin differ diff --git a/modules/YetiDriver/yeti_comms/evSerial.cpp b/modules/YetiDriver/yeti_comms/evSerial.cpp index b353405ff0..d9bf59b95a 100644 --- a/modules/YetiDriver/yeti_comms/evSerial.cpp +++ b/modules/YetiDriver/yeti_comms/evSerial.cpp @@ -348,6 +348,10 @@ bool evSerial::reset(const int reset_pin) { system(cmd); sprintf(cmd, "echo 0 > /sys/class/gpio/gpio%i/value", reset_pin); system(cmd); + + // clear uart input and output buffer + //tcflush(fd, TCIOFLUSH); + sprintf(cmd, "echo 1 > /sys/class/gpio/gpio%i/value", reset_pin); system(cmd); } else { diff --git a/modules/YetiDriver/yeti_comms/firmware_version.hpp b/modules/YetiDriver/yeti_comms/firmware_version.hpp new file mode 100644 index 0000000000..c818faa1c2 --- /dev/null +++ b/modules/YetiDriver/yeti_comms/firmware_version.hpp @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Pionix GmbH and Contributors to EVerest +#ifndef YETI_FIRMWARE_VERSION +#define YETI_FIRMWARE_VERSION + +#include +#include + +/* + Helper class to handle yeti Firmware Versions of the following style: + + Reported by MCU: 2.0-1-g2d51638 + Included in file name: yetiR1_2.0-1_firmware.bin + +*/ + +static std::vector split_by_delimeters(const std::string& s, const std::string& delimeters) { + std::regex re("[" + delimeters + "]"); + std::sregex_token_iterator first{s.begin(), s.end(), re, -1}, last; + return {first, last}; +} + +// parse version string from filename +static std::string from_filename(const std::string& v) { + auto tokens = split_by_delimeters(v, "_"); + if (tokens.size() >= 2) { + return tokens[1]; + } + return "0.0-0"; +} + +class YetiFirmwareVersion { + +public: + YetiFirmwareVersion() { + } + + YetiFirmwareVersion(const std::string& _version_string) { + from_string(_version_string); + } + + std::string to_string() { + return std::to_string(major) + "." + std::to_string(minor) + "-" + std::to_string(revision); + } + + void from_string(const std::string& _version_string) { + std::string version_string; + // Is it a full filename or just a version string from the MCU? + if (_version_string.rfind("yetiR", 0) == 0) { + version_string = from_filename(_version_string); + } else { + version_string = _version_string; + } + + auto tokens = split_by_delimeters(version_string, ".-"); + + // parse into major, minor and revision + if (tokens.size() >= 1) { + major = std::stoi(tokens[0]); + } + + if (tokens.size() >= 2) { + minor = std::stoi(tokens[1]); + } + + if (tokens.size() >= 3) { + revision = std::stoi(tokens[2]); + } + } + + YetiFirmwareVersion& operator=(const std::string& s) { + from_string(s); + return *this; + } + + friend bool operator<(const YetiFirmwareVersion& l, const YetiFirmwareVersion& r) { + if (l.major < r.major) { + return true; + } else if (l.major > r.major) { + return false; + } else if (l.minor < r.minor) { + return true; + } else if (l.minor > r.minor) { + return false; + } else if (l.revision < r.revision) { + return true; + } else if (l.revision > r.revision) { + return false; + } + // they are identical + return false; + } + + friend bool operator>(const YetiFirmwareVersion& lhs, const YetiFirmwareVersion& rhs) { + return rhs < lhs; + } + + friend bool operator<=(const YetiFirmwareVersion& lhs, const YetiFirmwareVersion& rhs) { + return not(lhs > rhs); + } + friend bool operator>=(const YetiFirmwareVersion& lhs, const YetiFirmwareVersion& rhs) { + return not(lhs < rhs); + } + +private: + int major{0}; + int minor{0}; + int revision{0}; +}; + +#endif diff --git a/modules/YetiDriver/yeti_fwupdate/CMakeLists.txt b/modules/YetiDriver/yeti_fwupdate/CMakeLists.txt index f9a8276ef1..69e0d93b65 100644 --- a/modules/YetiDriver/yeti_fwupdate/CMakeLists.txt +++ b/modules/YetiDriver/yeti_fwupdate/CMakeLists.txt @@ -11,7 +11,6 @@ add_executable(yeti_fwupdate main.cpp) target_include_directories(yeti_fwupdate PUBLIC "${PROJECT_BINARY_DIR}" PUBLIC "../yeti_comms/nanopb" PUBLIC "../yeti_comms/protobuf" PUBLIC "../yeti_comms") target_link_libraries(yeti_fwupdate PRIVATE Pal::Sigslot Threads::Threads yeti_comms everest::framework) -install(TARGETS yeti_fwupdate - DESTINATION ${EVEREST_MOD_YETIDRIVER_DESTINATION}) +install(TARGETS yeti_fwupdate) diff --git a/modules/YetiDriver/yeti_fwupdate/main.cpp b/modules/YetiDriver/yeti_fwupdate/main.cpp index 2a4b7ccbb9..f3ddf18d86 100644 --- a/modules/YetiDriver/yeti_fwupdate/main.cpp +++ b/modules/YetiDriver/yeti_fwupdate/main.cpp @@ -4,16 +4,20 @@ #include #include "evSerial.h" +#include #include +#include "firmware_version.hpp" #include "yeti.pb.h" #include -volatile bool sw_version_received = false; +std::atomic_bool sw_version_received = false; +YetiFirmwareVersion installed_fw_version; +std::string installed_fw_version_orig; void recvKeepAliveLo(KeepAliveLo s) { - printf("Current Yeti SW Version: %s (Protocol %i.%i)\n", s.sw_version_string, s.protocol_version_major, - s.protocol_version_minor); + installed_fw_version = s.sw_version_string; + installed_fw_version_orig = s.sw_version_string; sw_version_received = true; } @@ -29,7 +33,7 @@ int main(int argc, char* argv[]) { exit(0); } const char* device = argv[1]; - const char* filename = argv[2]; + std::filesystem::path filename = argv[2]; evSerial* p = new evSerial(); @@ -42,6 +46,17 @@ int main(int argc, char* argv[]) { break; usleep(100); } + + YetiFirmwareVersion update_file_fw_version{filename.filename()}; + printf("Installed Yeti Firmware Version: %s (%s)\n", installed_fw_version.to_string().c_str(), + installed_fw_version_orig.c_str()); + printf("Update File Firmware Version: %s\n", update_file_fw_version.to_string().c_str()); + + if (installed_fw_version >= update_file_fw_version) { + printf("Latest version already installed. Exiting.\n"); + exit(1); + } + printf("\nRebooting Yeti in ROM Bootloader mode...\n"); // send some dummy commands to make sure protocol is in sync p->keepAlive(); @@ -54,7 +69,7 @@ int main(int argc, char* argv[]) { sleep(1); char cmd[1000]; - sprintf(cmd, "stm32flash -b 115200 %.100s -v -w %.100s -R", device, filename); + sprintf(cmd, "stm32flash -b 115200 %.100s -v -w %.100s -R", device, filename.string().c_str()); // sprintf(cmd, "stm32flash -b115200 %.100s", device); printf("Executing %s ...\n", cmd); system(cmd);