diff --git a/CMakeLists.txt b/CMakeLists.txt index 0763f95..e3ffc41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,8 @@ cmake_minimum_required(VERSION 3.16) project("AOG-TaskController") set(PROJECT_VERSION_MAJOR 1) -set(PROJECT_VERSION_MINOR 3) -set(PROJECT_VERSION_PATCH 3) +set(PROJECT_VERSION_MINOR 5) +set(PROJECT_VERSION_PATCH 0) set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}" ) @@ -61,8 +61,8 @@ FetchContent_MakeAvailable(Boost) FetchContent_Declare( isobus - GIT_REPOSITORY https://github.com/Open-Agriculture/AgIsoStack-plus-plus.git - GIT_TAG 869430f0347188e0f8dc0740d6c6a1cfcce37706 + GIT_REPOSITORY https://github.com/gunicsba/AgIsoStack-plus-plus.git + GIT_TAG d4d36dd6f15af6c6f6218317572025a1ffec6883 DOWNLOAD_EXTRACT_TIMESTAMP TRUE) FetchContent_MakeAvailable(isobus) @@ -73,11 +73,13 @@ FetchContent_Declare( FetchContent_MakeAvailable(json) include(FetchContent) +set(CMAKE_POLICY_VERSION_MINIMUM 3.5) FetchContent_Declare( git_version GIT_REPOSITORY https://github.com/andrew-hardin/cmake-git-version-tracking.git GIT_TAG 904dbda1336ba4b9a1415a68d5f203f576b696bb) FetchContent_MakeAvailable(git_version) +unset(CMAKE_POLICY_VERSION_MINIMUM) find_package(Threads REQUIRED) diff --git a/include/task_controller.hpp b/include/task_controller.hpp index d1ca919..490e3c9 100644 --- a/include/task_controller.hpp +++ b/include/task_controller.hpp @@ -87,6 +87,7 @@ class MyTCServer : public isobus::TaskControllerServer bool get_is_enough_memory_available(std::uint32_t) override; void identify_task_controller(std::uint8_t) override; void on_client_timeout(std::shared_ptr partner) override; + void on_client_version_received(std::shared_ptr clientControlFunction, std::uint8_t version) override; void on_process_data_acknowledge(std::shared_ptr partner, std::uint16_t dataDescriptionIndex, std::uint16_t elementNumber, std::uint8_t errorCodesFromClient, ProcessDataCommands processDataCommand) override; bool on_value_command(std::shared_ptr partner, std::uint16_t dataDescriptionIndex, diff --git a/src/task_controller.cpp b/src/task_controller.cpp index ce6a2b0..169374a 100644 --- a/src/task_controller.cpp +++ b/src/task_controller.cpp @@ -17,6 +17,22 @@ #include #include +// Sanitize a string for use as a filename by replacing invalid characters with underscores +static std::string sanitize_filename(const std::string &input) +{ + std::string result = input; + // Characters invalid on Windows (and / is invalid on POSIX too) + const std::string invalid_chars = "\\/*:?\"<>|"; + for (char &c : result) + { + if (invalid_chars.find(c) != std::string::npos) + { + c = '_'; + } + } + return result; +} + void ClientState::set_number_of_sections(std::uint8_t number) { numberOfSections = number; @@ -295,11 +311,11 @@ bool MyTCServer::activate_object_pool(std::shared_ptr p auto labelBytes = deviceObject->get_localization_label(); std::string label(reinterpret_cast(labelBytes.data()), labelBytes.size()); - // trim at first occurrence of null or ETX (0x03) - auto it = std::find_if(label.begin(), label.end(), [](char c) { return c == '\0' || static_cast(c) == 0x03; }); + // trim at first non-printable character (control chars, DEL, etc.) + auto it = std::find_if(label.begin(), label.end(), [](unsigned char c) { return c < 0x20 || c >= 0x7F; }); label.erase(it, label.end()); - auto fileName = std::to_string(partnerCF->get_NAME().get_full_name()) + "\\" + label + ".ddop"; + auto fileName = std::to_string(partnerCF->get_NAME().get_full_name()) + "/" + sanitize_filename(label) + ".ddop"; std::vector binaryPool; if (state.get_pool().generate_binary_object_pool(binaryPool)) { @@ -420,6 +436,12 @@ void MyTCServer::on_client_timeout(std::shared_ptr part clients.erase(partner); } +void MyTCServer::on_client_version_received(std::shared_ptr clientControlFunction, std::uint8_t version) +{ + std::cout << "[" << get_timestamp() << "] [TC Server] Client " << clientControlFunction->get_NAME().get_full_name() + << " reported TC version " << static_cast(version) << std::endl; +} + void MyTCServer::on_process_data_acknowledge(std::shared_ptr partner, std::uint16_t dataDescriptionIndex, std::uint16_t elementNumber, @@ -502,7 +524,8 @@ void MyTCServer::request_measurement_commands() { for (auto &client : clients) { - if (!client.second.are_measurement_commands_sent()) + // Skip clients with 0 sections (e.g. tractors) - sending measurement commands to a tractor ECU can cause unexpected behavior + if (!client.second.are_measurement_commands_sent() && client.second.get_number_of_sections() > 0) { // Find all actual (condensed) work state DDIs and request them to trigger "On Change" and "Time Interval" for (std::uint32_t i = 0; i < client.second.get_pool().size(); i++)