Skip to content

Commit

Permalink
Fix YetiDriver and include binary firmware image. (#595)
Browse files Browse the repository at this point in the history
* Fix YetiDriver and include binary firmware image.

Manually update Yeti with:

yeti_fwupdate /dev/serial0 /usr/share/everest/modules/YetiDriver/firmware/yetiR1_2.0-1_firmware.bin

Make sure that EVerest is NOT running before updating!

---------

Signed-off-by: Cornelius Claussen <[email protected]>
Signed-off-by: Kai-Uwe Hermann <[email protected]>
Co-authored-by: Kai-Uwe Hermann <[email protected]>
  • Loading branch information
corneliusclaussen and hikinggrass authored Mar 21, 2024
1 parent 3b0ea32 commit 1ab671e
Show file tree
Hide file tree
Showing 8 changed files with 175 additions and 23 deletions.
2 changes: 2 additions & 0 deletions modules/YetiDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
46 changes: 32 additions & 14 deletions modules/YetiDriver/board_support/evse_board_supportImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,39 @@ void evse_board_supportImpl::init() {
std::lock_guard<std::mutex> 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<std::mutex> lock(capsMutex);
last_pp = cast_pp_type(pp_state);
publish_ac_pp_ampacity(last_pp);
});
Expand All @@ -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<std::mutex> lock(capsMutex);
if (caps_received)
break;
}

if (caps_received)
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
if (i == 49) {
Expand All @@ -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<std::mutex> lock(capsMutex);
return caps;
}
Expand Down
7 changes: 5 additions & 2 deletions modules/YetiDriver/board_support/evse_board_supportImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down
Binary file added modules/YetiDriver/yetiR1_2.0-1_firmware.bin
Binary file not shown.
4 changes: 4 additions & 0 deletions modules/YetiDriver/yeti_comms/evSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
111 changes: 111 additions & 0 deletions modules/YetiDriver/yeti_comms/firmware_version.hpp
Original file line number Diff line number Diff line change
@@ -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 <regex>
#include <string>

/*
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<std::string> 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
3 changes: 1 addition & 2 deletions modules/YetiDriver/yeti_fwupdate/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)


25 changes: 20 additions & 5 deletions modules/YetiDriver/yeti_fwupdate/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@
#include <string.h>

#include "evSerial.h"
#include <filesystem>
#include <unistd.h>

#include "firmware_version.hpp"
#include "yeti.pb.h"
#include <sigslot/signal.hpp>

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;
}

Expand All @@ -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();

Expand All @@ -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();
Expand All @@ -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);
Expand Down

0 comments on commit 1ab671e

Please sign in to comment.