Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions include/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ class Settings
*/
bool set_vt_enabled(bool enabled, bool save = true);

/// @brief Check whether every implement section follows AOG's section 1.
/// @details For implements that declare several sections (or booms) that really are one, such as
/// several dispensers on one working width. AOG then sees the implement as a single section.
bool is_all_sections_follow_first() const;

/// @brief Set whether every implement section follows AOG's section 1.
bool set_all_sections_follow_first(bool enabled, bool save = true);

/**
* @brief Get the configured TC version
* @return The configured version (0-4, default 3)
Expand Down Expand Up @@ -161,6 +169,7 @@ class Settings
constexpr static bool DEFAULT_NMEA_SEND_ENABLED = true;
constexpr static bool DEFAULT_AOG_HEARTBEAT_ENABLED = true;
constexpr static bool DEFAULT_VT_ENABLED = true;
constexpr static bool DEFAULT_ALL_SECTIONS_FOLLOW_FIRST = false;
constexpr static std::uint8_t DEFAULT_TC_VERSION = 3; ///< SecondEditionDraft (V3 default for maximum implement compatibility)
static const std::string DEFAULT_LANGUAGE_CODE;
static const std::string DEFAULT_COUNTRY_CODE;
Expand All @@ -169,6 +178,7 @@ class Settings
bool nmeaSendEnabled = DEFAULT_NMEA_SEND_ENABLED;
bool aogHeartbeatEnabled = DEFAULT_AOG_HEARTBEAT_ENABLED;
bool vtEnabled = DEFAULT_VT_ENABLED;
bool allSectionsFollowFirst = DEFAULT_ALL_SECTIONS_FOLLOW_FIRST;
std::uint8_t tcVersion = DEFAULT_TC_VERSION;
std::string languageCode = DEFAULT_LANGUAGE_CODE;
std::string countryCode = DEFAULT_COUNTRY_CODE;
Expand Down
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ AOG-TaskController reads its configuration from a `settings.json` file located i
| `nmeaSendEnabled` | `bool` | `true` | Enables cyclic NMEA2000 COG/SOG transmission. Requires `tecuEnabled`. |
| `aogHeartbeatEnabled` | `bool` | `true` | Sends the 100 ms zero-section heartbeat when no implement is connected. Disable for AgOpenGPS versions before v6.8.2 beta 5. |
| `vtEnabled` | `bool` | `true` | Enables the ISOBUS Virtual Terminal UI. |
| `allSectionsFollowFirst` | `bool` | `false` | Every implement section follows AOG's section 1, and AOG sees the implement as one section (on while any section is on). For implements that declare several sections or booms that really are one, such as several dispensers on one working width. Set AOG to 1 section. Applies to every connected implement: with two section-controlled implements, both follow section 1 and AOG gets one combined report. |
| `tcVersion` | `integer` | `3` | Task Controller version code, from `0` through `4`; `3` is Second Edition Draft. |
| `languageCode` | `string` | `"en"` | Two-character language code advertised on ISOBUS. |
| `countryCode` | `string` | `"US"` | Two-character country code advertised on ISOBUS. |
Expand Down
32 changes: 31 additions & 1 deletion src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,12 @@ void Application::setup_udp_connections()
sectionDemand = sectionStates;
sectionDemandChangesSinceLog++;
}
if (settings->is_all_sections_follow_first())
{
// The implement's sections are really one: all follow AOG's section 1 (sectionDemand above stays as AOG sent it).
// PGN 229 carries 64 bits; cover every section a DDOP can declare (up to 255), not just the first 64.
sectionStates.assign(256, sectionStates.front());
}
tcServer->update_section_states(sectionStates);
}
else if (pgn == 0xF1 && !data.empty()) // 241 - Section Control
Expand Down Expand Up @@ -728,6 +734,9 @@ bool Application::update()
if (isobus::SystemTiming::time_expired_ms(lastHeartbeatTransmit, 100))
{
bool anyClientWithSections = false;
const bool followFirst = settings->is_all_sections_follow_first();
bool followFirstEnabled = false;
bool followFirstOn = false;
for (auto &client : tcServer->get_clients())
{
auto &state = client.second;
Expand All @@ -739,6 +748,19 @@ bool Application::update()
}

anyClientWithSections = true;

if (followFirst)
{
// AOG is set up with one section, and section 1 drives every connected implement:
// collect them all into one report, on while any implement section is on
followFirstEnabled = followFirstEnabled || state.is_section_control_enabled();
for (std::uint8_t i = 0; i < state.get_number_of_sections(); i++)
{
followFirstOn = followFirstOn || (state.get_section_actual_state(i) == SectionState::ON);
}
continue;
}

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

std::uint8_t sectionIndex = 0;
Expand All @@ -758,6 +780,12 @@ bool Application::update()
udpConnections->send(0x80, 0xF0, data);
}

if (followFirst && anyClientWithSections)
{
std::vector<uint8_t> oneSection = { followFirstEnabled, 1, static_cast<std::uint8_t>(followFirstOn ? 1 : 0) };
udpConnections->send(0x80, 0xF0, oneSection);
}

// If no clients with sections, send heartbeat with 0 sections
if (settings->is_aog_heartbeat_enabled() && !anyClientWithSections)
{
Expand Down Expand Up @@ -1029,7 +1057,9 @@ void Application::check_section_demand()
for (std::uint8_t i = 0; i < state.get_number_of_sections(); i++)
{
actual.push_back(SectionState::ON == state.get_section_actual_state(i));
demanded = demanded || (arriving && (i < sectionDemand.size()) && sectionDemand[i]);
// With allSectionsFollowFirst, AOG has one section: only its bit is demand, any others are padding
const std::uint8_t demandIndex = settings->is_all_sections_follow_first() ? 0 : i;
demanded = demanded || (arriving && (demandIndex < sectionDemand.size()) && sectionDemand[demandIndex]);
}
const bool working = (actual.end() != std::find(actual.begin(), actual.end(), true));

Expand Down
13 changes: 13 additions & 0 deletions src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ bool Settings::load()
nmeaSendEnabled = loadBoolean("nmeaSendEnabled", DEFAULT_NMEA_SEND_ENABLED);
aogHeartbeatEnabled = loadBoolean("aogHeartbeatEnabled", DEFAULT_AOG_HEARTBEAT_ENABLED);
vtEnabled = loadBoolean("vtEnabled", DEFAULT_VT_ENABLED);
allSectionsFollowFirst = loadBoolean("allSectionsFollowFirst", DEFAULT_ALL_SECTIONS_FOLLOW_FIRST);

if (data.contains("tcVersion"))
{
Expand Down Expand Up @@ -143,6 +144,7 @@ bool Settings::save() const
data["nmeaSendEnabled"] = nmeaSendEnabled;
data["aogHeartbeatEnabled"] = aogHeartbeatEnabled;
data["vtEnabled"] = vtEnabled;
data["allSectionsFollowFirst"] = allSectionsFollowFirst;
data["tcVersion"] = tcVersion;
data["languageCode"] = languageCode;
data["countryCode"] = countryCode;
Expand Down Expand Up @@ -261,6 +263,17 @@ bool Settings::set_vt_enabled(bool enabled, bool save)
return set_boolean(vtEnabled, enabled, save);
}

bool Settings::is_all_sections_follow_first() const
{
std::scoped_lock lock(settingsMutex);
return allSectionsFollowFirst;
}

bool Settings::set_all_sections_follow_first(bool enabled, bool save)
{
return set_boolean(allSectionsFollowFirst, enabled, save);
}

bool Settings::is_aog_heartbeat_enabled() const
{
std::scoped_lock lock(settingsMutex);
Expand Down
Loading