Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7d05e40
Send GNSS quality (DDI 514) to implements
gunicsba Sep 19, 2026
46fe425
Announce guidance track data (DDI 507-513) to implements
gunicsba Sep 19, 2026
679b293
Add track control level negotiation (DDI 505/506) and track control s…
gunicsba Sep 19, 2026
e63db02
Add Tractor Facilities (PGN 65033) for the TECU
gunicsba Sep 19, 2026
3389908
Merge origin/develop into feature/gnss-quality-announcement
gunicsba Sep 27, 2026
c563c62
Merge feature/gnss-quality-announcement into feature/guidance-track-a…
gunicsba Sep 27, 2026
3e6e0e0
Merge feature/guidance-track-announcement into feature/track-control-…
gunicsba Sep 27, 2026
bd7ff2a
Link async_log into test_guidance_track
gunicsba Sep 27, 2026
44aa5b8
Merge feature/guidance-track-announcement into feature/track-control-…
gunicsba Sep 27, 2026
f3d0998
Cut log noise from bad UDP packets and global-destination RTS frames
gunicsba Sep 28, 2026
a11fdad
Log DDOPs without sections as a non-section client instead of a warning
gunicsba Sep 28, 2026
99abf3d
Switch section control on automatically when an implement connects
gunicsba Oct 12, 2026
18a6bb5
Parse each AOG UDP datagram on its own so short packets do not drop t…
gunicsba Oct 14, 2026
a3652a2
Reconnect implements that missed a TC restart
gunicsba Oct 14, 2026
a0463b6
Switch section control on when AOG opens a field
gunicsba Oct 14, 2026
cbf1e59
Log the sender and bytes of datagrams that are not AOG packets
gunicsba Oct 14, 2026
a1174e9
Merge remote-tracking branch 'origin/develop'
gunicsba Nov 6, 2026
e7753a7
Merge remote-tracking branch 'origin/develop'
gunicsba Nov 6, 2026
e196d78
Merge remote-tracking branch 'origin/develop'
gunicsba Nov 6, 2026
ccad3d6
Merge remote-tracking branch 'origin/develop'
gunicsba Nov 6, 2026
072dc86
Merge remote-tracking branch 'origin/develop'
gunicsba Nov 8, 2026
6e1f83e
Run the TECU as a secondary Tractor ECU when the tractor has one
gunicsba Nov 8, 2026
0b25d97
Fill the tractor's gaps when tecuEnabled is off
gunicsba Nov 8, 2026
ae37e99
Bump AgIsoStack++ to upstream main 02f3fe9
gunicsba Nov 8, 2026
1b04497
Add the candleLight/gs_usb adapter option on Windows
gunicsba Nov 8, 2026
f5ed405
Make the TC number configurable (tcNumber setting)
gunicsba Nov 8, 2026
317824f
Send nothing as a secondary TECU until the plan has settled
gunicsba Nov 8, 2026
00a05a9
Answer requests for Time/Date (PGN 65254) from the TECU
gunicsba Nov 8, 2026
15dfbe6
Merge origin/fix/udp-parser-index into test/upcoming-integration
gunicsba Nov 8, 2026
52dd77b
Merge origin/fix/tc-restart-recovery into test/upcoming-integration
gunicsba Nov 8, 2026
70cf602
Merge origin/feature/section-control-on-connect into test/upcoming-in…
gunicsba Nov 8, 2026
24a0da7
Merge origin/fix/log-noise-and-non-section-clients into test/upcoming…
gunicsba Nov 8, 2026
f33a208
Merge origin/feature/candlelight-gs-usb into test/upcoming-integration
gunicsba Nov 8, 2026
8c56798
Merge origin/feature/tecu-tractor-facilities into test/upcoming-integ…
gunicsba Nov 8, 2026
21c99e5
Merge feature/tc-number into test/upcoming-integration
gunicsba Nov 8, 2026
09e8e63
Merge origin/feature/track-control-levels into test/upcoming-integration
gunicsba Nov 8, 2026
b066073
Fix what the integration merges left doubled
gunicsba Nov 8, 2026
1e31bde
Keep the field name branch where the guidance track code adds its own
gunicsba Nov 8, 2026
6fb0266
Merge origin/feature/section-control-on-connect (branch move only, al…
gunicsba Nov 8, 2026
50de93f
Merge origin/feature/tecu-time-date-on-request into test/upcoming-int…
gunicsba Nov 8, 2026
cda4137
Let tcNumber 0 pick a free TC number at startup
gunicsba Nov 9, 2026
a66f9fd
Merge remote-tracking branch 'origin/feature/tc-number' into test/upc…
gunicsba Nov 9, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/validate-iop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
-Wno-dev

- name: Build
run: cmake --build build --config Release --target iop_validator
run: cmake --build build --config Release --target iop_validator test_tractor_facilities

- name: Validate object pool
run: ctest --test-dir build --output-on-failure
60 changes: 59 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ if(NOT DEFINED CAN_DRIVER)
list(APPEND CAN_DRIVER "WindowsInnoMakerUSB2CAN")
list(APPEND CAN_DRIVER "TouCAN")
list(APPEND CAN_DRIVER "SYS_TEC")
list(APPEND CAN_DRIVER "WindowsCandleLight")
elseif(APPLE)
set(CAN_DRIVER "MacCANPCAN")
else()
Expand All @@ -62,7 +63,7 @@ FetchContent_MakeAvailable(Boost)
FetchContent_Declare(
isobus
GIT_REPOSITORY https://github.com/Open-Agriculture/AgIsoStack-plus-plus.git
GIT_TAG 1d081d9a9df61e256015efda3683d15c8fa3d580
GIT_TAG 02f3fe910de5fdc73e2014394c2e80900490b9cc
DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
FetchContent_MakeAvailable(isobus)

Expand Down Expand Up @@ -159,6 +160,22 @@ if(AOG_TC_VALIDATE_IOP)
add_test(NAME object_pool_attributes_in_range COMMAND iop_validator
"${AOG_TC_IOP_SOURCE}")

# GuidanceTrackProvider (AOG PGN 0xF4 parsing) unit tests. Made a dependency
# of iop_validator so the validation workflow, which builds only that target,
# also builds this test.
add_executable(
test_guidance_track
${CMAKE_CURRENT_LIST_DIR}/tools/test_guidance_track.cpp
${CMAKE_CURRENT_LIST_DIR}/src/guidance_track_context.cpp
${CMAKE_CURRENT_LIST_DIR}/src/async_log.cpp)
target_compile_features(test_guidance_track PRIVATE cxx_std_20)
set_target_properties(test_guidance_track PROPERTIES CXX_EXTENSIONS OFF)
target_include_directories(test_guidance_track
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(test_guidance_track PRIVATE Threads::Threads)
add_dependencies(iop_validator test_guidance_track)
add_test(NAME guidance_track_parsing COMMAND test_guidance_track)

# A deliberately broken pool, so the suite asserts more than "today's pool
# passes". One case per message, since a shared exit code stays green as long
# as any one check still fires.
Expand Down Expand Up @@ -194,6 +211,16 @@ if(AOG_TC_VALIDATE_IOP)
add_dependencies(iop_validator test_async_log)
add_test(NAME async_log COMMAND test_async_log)

# AOG UDP datagram parsing; the parser is header-only.
add_executable(test_aog_packet_parser
${CMAKE_CURRENT_LIST_DIR}/tools/test_aog_packet_parser.cpp)
target_compile_features(test_aog_packet_parser PRIVATE cxx_std_20)
set_target_properties(test_aog_packet_parser PROPERTIES CXX_EXTENSIONS OFF)
target_include_directories(test_aog_packet_parser
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
add_dependencies(iop_validator test_aog_packet_parser)
add_test(NAME aog_packet_parser COMMAND test_aog_packet_parser)

# element_hierarchy (cached element parents for the section state lookup) unit
# tests, built with the validation workflow for the same reason.
add_executable(test_element_hierarchy
Expand All @@ -212,6 +239,37 @@ if(AOG_TC_VALIDATE_IOP)
add_test(NAME malformed_pool_exit_status COMMAND iop_validator
"${AOG_TC_MALFORMED_IOP}")
set_tests_properties(malformed_pool_exit_status PROPERTIES WILL_FAIL TRUE)

# Tractor Facilities (PGN 65033) encode/decode unit tests
add_executable(
test_tractor_facilities
${CMAKE_CURRENT_LIST_DIR}/tools/test_tractor_facilities.cpp
${CMAKE_CURRENT_LIST_DIR}/src/tractor_facilities.cpp)
target_compile_features(test_tractor_facilities PRIVATE cxx_std_20)
set_target_properties(test_tractor_facilities PROPERTIES CXX_EXTENSIONS OFF)
target_include_directories(test_tractor_facilities
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(
test_tractor_facilities PRIVATE isobus::Isobus isobus::HardwareIntegration
isobus::Utility)
add_test(NAME tractor_facilities_encode_decode
COMMAND test_tractor_facilities)

# Sharing the bus with other Tractor ECUs (ISO 11783-9 4.4.2.1)
add_executable(
test_tecu_coexistence
${CMAKE_CURRENT_LIST_DIR}/tools/test_tecu_coexistence.cpp
${CMAKE_CURRENT_LIST_DIR}/src/tecu_coexistence.cpp
${CMAKE_CURRENT_LIST_DIR}/src/tractor_facilities.cpp)
target_compile_features(test_tecu_coexistence PRIVATE cxx_std_20)
set_target_properties(test_tecu_coexistence PROPERTIES CXX_EXTENSIONS OFF)
target_include_directories(test_tecu_coexistence
PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(
test_tecu_coexistence PRIVATE isobus::Isobus isobus::HardwareIntegration
isobus::Utility)
add_dependencies(iop_validator test_tecu_coexistence)
add_test(NAME tecu_coexistence COMMAND test_tecu_coexistence)
endif()

if(WIN32)
Expand Down
20 changes: 18 additions & 2 deletions docs/CONCURRENCY.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ registered:
`softKeyEventDispatcher`/`buttonEventDispatcher`/`changeNumericValueEventDispatcher`/etc.
synchronously). Any raw
`add_global_parameter_group_number_callback`/`add_any_control_function_parameter_group_number_callback`
registered directly in `app.cpp` is in this category too, unless proven otherwise the same way:
read the registration call, not the surrounding comments.
registered directly in `app.cpp`/`tractor_facilities.cpp` (PGN-request handlers, diagnostic
loggers) is in this category too, unless proven otherwise the same way: read the registration
call, not the surrounding comments.

If you're not sure which category a new callback falls into, trace it the way this file's history
did: find where it's registered with `CANNetworkManager`/`ControlFunction` and check whether that
Expand All @@ -58,6 +59,21 @@ registration point itself defers to an `update()` call, or invokes the listener/
overrides may turn out to already be main-thread-only — the lock is cheap insurance and keeps
every entry point consistent regardless of how the library's internals might change.

- **`OtherTecuMonitor`** (`tecu_coexistence.hpp`/`.cpp`) — `on_frame()` (frame-received event) and its
PGN 65033 callback run on the background thread, `refresh()` and the queries on the main thread. The
per-address and per-message flags are atomics; the facility map is under its own mutex. It lives as long
as `Application` because the stack calls global PGN callbacks from a copy of the list, so one can still run
once after `remove_global_parameter_group_number_callback()` returns.
- **Rebuilding the TECU at runtime** (`Application::teardown_tecu()`, when stepping down to a secondary Tractor
ECU) destroys `TractorFacilities`, `SpeedMessagesInterface`, `NMEA2000MessageInterface` and the functionalities
object before `deactivate_control_function()`. The PGN request protocol and the "any control function"
callbacks are invoked under the same locks their removal takes, so they cannot run against a destroyed
object. `TractorFacilities`' PGN 65032 callback may still run once after removal, which is harmless: it only
logs and never touches the object. `TractorFacilities::providedFacilities` is under its own mutex
(set on the main thread, read when answering a PGN 65033 request).
- **`TractorFacilities::timeDateActive`** — atomic: set on the main thread from the TECU plan, read on the
background thread when answering a request for PGN 65033 or PGN 65254.

## What's *not* protected yet — known gap

Calls into `vtClient` (`isobus::VirtualTerminalClient`) happen from both the main thread
Expand Down
2 changes: 2 additions & 0 deletions docs/LINUX_DAEMON.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ The TC reads `settings.json` from `$XDG_CONFIG_HOME/AOG-TaskController/` (typica
"aogHeartbeatEnabled": true,
"vtEnabled": true,
"tcVersion": 3,
"tcNumber": 1,
"languageCode": "en",
"countryCode": "US"
}
Expand All @@ -138,6 +139,7 @@ The TC reads `settings.json` from `$XDG_CONFIG_HOME/AOG-TaskController/` (typica
| `aogHeartbeatEnabled` | `bool` | `true` | Whether the TC sends a 100 ms heartbeat UDP packet to AgIO/AgValonia even when no implement is connected. **Set to `false` if pairing with AgOpenGPS pre-v6.8.2 beta 5** — older AOG versions choke on the heartbeat. |
| `vtEnabled` | `bool` | `true` | Whether the TC registers its Virtual Terminal UI. |
| `tcVersion` | `integer` | `3` | Task Controller version code (`0`–`4`); `3` selects Second Edition Draft. |
| `tcNumber` | `integer` | `1` | Task Controller number, `1`–`32` (ISO 11783-10: the TC NAME's function instance + 1). Set `2` or higher when the tractor already has a TC, so implements can tell the two apart. `0` picks the first number no other TC on the bus has, which adds about 1.4 s to startup. Takes effect after restart. |
| `languageCode` | `string` | `"en"` | Two-character ISOBUS language code. |
| `countryCode` | `string` | `"US"` | Two-character ISOBUS country code. |

Expand Down
Loading
Loading