Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
cmake_minimum_required(VERSION 3.16)
project("AOG-TaskController")
set(PROJECT_VERSION_MAJOR 1)
set(PROJECT_VERSION_MINOR 2)
set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION_MINOR 3)
set(PROJECT_VERSION_PATCH 1)
set(PROJECT_VERSION
"${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}"
)
Expand Down
16 changes: 16 additions & 0 deletions include/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,20 @@ class Settings
*/
bool set_subnet(std::array<std::uint8_t, 3> subnet, bool save = true);

/**
* @brief Check if Tractor ECU is enabled
* @return True if TECU is enabled, false otherwise
*/
bool is_tecu_enabled() const;

/**
* @brief Set the Tractor ECU enabled state
* @param enabled Whether to enable the Tractor ECU
* @param save Whether or not to save the settings to file
* @return True if the setting was set successfully, false otherwise
*/
bool set_tecu_enabled(bool enabled, bool save = true);

/**
* @brief Get the absolute path to the settings file
* @param filename The filename to get the path for
Expand All @@ -57,5 +71,7 @@ class Settings

private:
constexpr static std::array<std::uint8_t, 3> DEFAULT_SUBNET = { 192, 168, 5 };
constexpr static bool DEFAULT_TECU_ENABLED = true;
std::array<std::uint8_t, 3> configuredSubnet = DEFAULT_SUBNET;
bool tecuEnabled = DEFAULT_TECU_ENABLED;
};
15 changes: 14 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,21 @@ Then, you can run the following commands:

```bash
mkdir build
cmake -S . -B build -DBUILD_EXAMPLES=OFF -DBUILD_TESTING=OFF -Wno-dev
cmake -S . -B build -DBUILD_EXAMPLES=OFF -DCMAKE_POLICY_VERSION_MINIMUM="3.16" -DBUILD_TESTING=OFF -Wno-dev
cmake --build build --config Release --target package
```

The installer will be generated in the `build` directory.

Before committing it's better to run these commands: (requires the LLVM project to be installed)
Comment thread
gunicsba marked this conversation as resolved.
git ls-files | Select-String '\.(c|cc|cpp|cxx|h|hh|hpp|hxx|proto)$' | ForEach-Object {
clang-format -i $_.ToString()
}

(Install cmake-format with:
python -m pip install --upgrade pip
pip install cmake-format pyyaml
)
Get-ChildItem -Recurse -Filter CMakeLists.txt | ForEach-Object {
python -m cmakelang.format -i $_.FullName
}
Comment thread
gunicsba marked this conversation as resolved.
20 changes: 17 additions & 3 deletions src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ bool Application::initialize()
// Create TECU control function
// TODO: Should we wait between this and TC?
// TODO: If there's already a TECU on the bus we should not create ours
if (tcCF)
{ // Only create TECU if TC was created
if (tcCF && settings->is_tecu_enabled())
{ // Only create TECU if TC was created and ECU is enabled
std::cout << "[Init] Creating Tractor ECU control function..." << std::endl;
tecuCF = isobus::CANNetworkManager::CANNetwork.create_internal_control_function(tecuNAME, 0, isobus::preferred_addresses::IndustryGroup2::TractorECU);
std::cout << "[Init] Tractor ECU control function created, waiting 1.5 seconds..." << std::endl;
Expand Down Expand Up @@ -125,7 +125,14 @@ bool Application::initialize()
}
else
{
std::cout << "[Warning] TECU Control Function not available, Speed/NMEA interfaces not created" << std::endl;
if (!settings->is_tecu_enabled())
{
std::cout << "[Info] Tractor ECU disabled in settings, skipping ECU initialization." << std::endl;
}
else
{
std::cout << "[Warning] TECU Control Function not available, Speed/NMEA interfaces not created" << std::endl;
}
}

std::cout << "Task controller server started." << std::endl;
Expand Down Expand Up @@ -248,6 +255,13 @@ bool Application::update()
for (auto &client : tcServer->get_clients())
{
auto &state = client.second;

// Skip clients with no sections (e.g., tractors or non-implement devices)
if (state.get_number_of_sections() == 0)
{
continue;
}

std::vector<uint8_t> data = { state.is_section_control_enabled(), state.get_number_of_sections() };

std::uint8_t sectionIndex = 0;
Expand Down
33 changes: 33 additions & 0 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,31 @@ bool Settings::load()
configuredSubnet = DEFAULT_SUBNET; // Key not found, use default
}

if (data.contains("tecuEnabled"))
{
try
{
tecuEnabled = data["tecuEnabled"].get<bool>();
}
catch (const nlohmann::json::exception &e)
{
std::cout << "Error parsing 'tecuEnabled': " << e.what() << std::endl;
tecuEnabled = DEFAULT_TECU_ENABLED; // Fallback to default
}
}
else
{
tecuEnabled = DEFAULT_TECU_ENABLED; // Key not found, use default
}

return true;
}

bool Settings::save() const
{
json data;
data["subnet"] = configuredSubnet;
data["tecuEnabled"] = tecuEnabled;

std::ofstream file(get_filename_path("settings.json"));
if (!file.is_open())
Expand Down Expand Up @@ -82,6 +100,21 @@ bool Settings::set_subnet(std::array<std::uint8_t, 3> subnet, bool save)
return true;
}

bool Settings::is_tecu_enabled() const
{
return tecuEnabled;
}

bool Settings::set_tecu_enabled(bool enabled, bool save)
{
tecuEnabled = enabled;
if (save)
{
return this->save();
}
return true;
}

std::string Settings::get_filename_path(std::string fileName)
{
char path[MAX_PATH];
Expand Down
17 changes: 17 additions & 0 deletions src/task_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ MyTCServer::MyTCServer(std::shared_ptr<isobus::InternalControlFunction> internal

bool MyTCServer::activate_object_pool(std::shared_ptr<isobus::ControlFunction> partnerCF, ObjectPoolActivationError &, ObjectPoolErrorCodes &, std::uint16_t &, std::uint16_t &)
{
std::cout << "[TC Server] Client " << partnerCF->get_NAME().get_full_name() << " requesting object pool activation" << std::endl;
// Safety check to make sure partnerCF has uploaded a DDOP
if (uploadedPools.find(partnerCF) == uploadedPools.end())
{
Expand Down Expand Up @@ -339,6 +340,8 @@ bool MyTCServer::activate_object_pool(std::shared_ptr<isobus::ControlFunction> p
}

clients[partnerCF] = state;
std::cout << "[TC Server] Client " << partnerCF->get_NAME().get_full_name() << " registered successfully with "
<< static_cast<int>(state.get_number_of_sections()) << " sections." << std::endl;
return true;
}

Expand Down Expand Up @@ -385,6 +388,7 @@ void MyTCServer::identify_task_controller(std::uint8_t)
void MyTCServer::on_client_timeout(std::shared_ptr<isobus::ControlFunction> partner)
{
// Cleanup the client state
std::cout << "[TC Server] Client " << partner->get_NAME().get_full_name() << " has timed out!" << std::endl;
clients.erase(partner);
}

Expand Down Expand Up @@ -452,6 +456,7 @@ bool MyTCServer::on_value_command(std::shared_ptr<isobus::ControlFunction> partn

bool MyTCServer::store_device_descriptor_object_pool(std::shared_ptr<isobus::ControlFunction> partnerCF, const std::vector<std::uint8_t> &binaryPool, bool appendToPool)
{
std::cout << "[TC Server] Client " << partnerCF->get_NAME().get_full_name() << " requesting object pool transfer of " << binaryPool.size() << " bytes" << std::endl;
if (uploadedPools.find(partnerCF) == uploadedPools.end())
{
uploadedPools[partnerCF] = std::queue<std::vector<std::uint8_t>>();
Expand Down Expand Up @@ -582,6 +587,12 @@ void MyTCServer::update_section_states(std::vector<bool> &sectionStates)
return;
}

// Skip clients that don't support section control (e.g., tractors or other non-implement devices)
if (!state.has_element_number_for_ddi(isobus::DataDescriptionIndex::SectionControlState))
Comment thread
gunicsba marked this conversation as resolved.
Outdated
{
Comment thread
gunicsba marked this conversation as resolved.
continue;
}

bool requiresUpdate = false;
for (std::uint8_t i = 0; i < state.get_number_of_sections(); i++)
{
Expand Down Expand Up @@ -614,6 +625,12 @@ void MyTCServer::update_section_control_enabled(bool enabled)
{
for (auto &client : clients)
{
// Skip clients that don't support section control (e.g., tractors or other non-implement devices)
if (!client.second.has_element_number_for_ddi(isobus::DataDescriptionIndex::SectionControlState))
{
continue;
}

Comment thread
gunicsba marked this conversation as resolved.
Outdated
if (client.second.is_section_control_enabled() != enabled)
{
client.second.set_section_control_enabled(enabled);
Expand Down
Loading