From b33937c8245939043f1e1684c6de4d85c7f8cd64 Mon Sep 17 00:00:00 2001 From: Adrian Del Grosso <10929341+ad3154@users.noreply.github.com> Date: Sat, 11 May 2024 13:11:56 -0600 Subject: [PATCH] [Tutorials]: Add TC client documentation to tutorials --- .../isobus/can_transport_protocol_base.hpp | 2 +- sphinx/source/Tutorials.rst | 3 +- .../Tutorials/Task Controller Basics.rst | 9 +- .../Tutorials/Task Controller Client.rst | 118 ++++++++++++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100644 sphinx/source/Tutorials/Task Controller Client.rst diff --git a/isobus/include/isobus/isobus/can_transport_protocol_base.hpp b/isobus/include/isobus/isobus/can_transport_protocol_base.hpp index a74f92523..d66a95431 100644 --- a/isobus/include/isobus/isobus/can_transport_protocol_base.hpp +++ b/isobus/include/isobus/isobus/can_transport_protocol_base.hpp @@ -1,5 +1,5 @@ //================================================================================================ -/// @file can_transport_protocol_base.cpp +/// @file can_transport_protocol_base.hpp /// /// @brief Abstract base class for CAN transport protocols. /// @author Daan Steenbergen diff --git a/sphinx/source/Tutorials.rst b/sphinx/source/Tutorials.rst index b94d89458..d7e69f512 100644 --- a/sphinx/source/Tutorials.rst +++ b/sphinx/source/Tutorials.rst @@ -13,5 +13,6 @@ Tutorials Tutorials/PGN Requests Tutorials/Debug Logging Tutorials/ISOBUS Shortcut Button - Tutorials/ESP32 PlatformIO Tutorials/Task Controller Basics + Tutorials/Task Controller Client + Tutorials/ESP32 PlatformIO diff --git a/sphinx/source/Tutorials/Task Controller Basics.rst b/sphinx/source/Tutorials/Task Controller Basics.rst index 2ad6ee254..e6b5c0b92 100644 --- a/sphinx/source/Tutorials/Task Controller Basics.rst +++ b/sphinx/source/Tutorials/Task Controller Basics.rst @@ -38,7 +38,7 @@ The DDOP is uploaded to the TC during the connection process of the implement to In other words, the Device Descriptor Object Pool (DDOP) is a collection of objects that describe the capabilities of the implement, such as the number of sections, the width of each section, and the type of product being applied. It is the authoritative source of implement geometry on the machine. -In AgIsoStack, if you use our TC client, you will have to create a DDOP that tells the TC abour your implement. +In AgIsoStack, if you use our TC client, you will have to create a DDOP that tells the TC about your implement. Likewise, if you use the AgIsoStack TC Server, you will receive DDOPs from client implements, and you'll have to know what they mean. Before we jump into some examples of well constructed DDOPs, let's go over some terminology first. Once you have some understanding of the things you can put in a DDOP, we'll show you how you can use AgIsoStack to easily create one. @@ -179,3 +179,10 @@ Here's an example of what a DDOP might look like for a more complex implement, l The more complex an implement is, the more objects will be in the DDOP to accurately provide the TC with the information it needs to control and monitor the implement. For DDOPs this complex, a good resource to refer to is `our seeder example `_, which contains the code to create a more complex DDOP for a seeder. + +AgIsoDDOPGenerator +^^^^^^^^^^^^^^^^^^ + +Open-Agriculture has created a tool called `AgIsoDDOPGenerator `_, which can help create, view, and edit binary DDOPs for your implements. Using this tool to view the heierarchies of DDOP objects can be very helpful in understanding how they are structured. + +DDOPs created with AgIsoDDOPGenerator can be used with AgIsoStack, and can be uploaded to a TC using the AgIsoStack TC client. diff --git a/sphinx/source/Tutorials/Task Controller Client.rst b/sphinx/source/Tutorials/Task Controller Client.rst new file mode 100644 index 000000000..8c6831e52 --- /dev/null +++ b/sphinx/source/Tutorials/Task Controller Client.rst @@ -0,0 +1,118 @@ +.. _TaskControllerClient: + +Task Controller Client +======================= + +.. toctree:: + :hidden: + :glob: + +.. contents:: Contents + :depth: 2 + :local: + +This tutorial will walk you through basic use of the Task Controller client in AgIsoStack. The Task Controller client is used to connect an implement to a Task Controller. + +It's suggested that you read the Task Controller Basics tutorial before starting this one, as it will give you an understanding of what a Task Controller is, and what a DDOP is. + +Creating the Task Controller Client +------------------------------------ + +In order to communicate with a task controller, first you should identify the capabilities of your implement. How many sections can it control? How many simultaneous VRA rates can it handle? Can it function correctly without TC provided position based (GNSS) control? + +Next, you'll have to create a DDOP that describes your implement to the TC. This DDOP will be uploaded to the TC when AgIsoStack connects to it, and will tell the TC what your implement is capable of doing. + +Check out `our seeder example `_ to see how a DDOP can be created, or review the :doc:`task controller basics tutorial <./Task Controller Basics>`. + +Once you know the answer to these questions and you have a DDOP, you can create a :code:`TaskControllerClient`, and configure it to match your implement's capabilities. + +Here's an example of how you can create a :code:`TaskControllerClient` in AgIsoStack: + +.. code-block:: c++ + + #include "isobus/isobus/isobus_task_controller_client.hpp" + + // Create a TaskControllerClient + // The parameters are, in order: + // The control function for the TC + // The control function used to send messages to the TC + // The control function for a virtual terminal you're connected to with the VT client (optional - helps synchronize language and units in some cases) + isobus::TaskControllerClient OurTaskControllerClient(PartnerTC, InternalECU, nullptr); + + // Configure the TaskControllerClient with our DDOP. + // The parameters are, in order: + // Includes support for 1 boom, 10 sections, 1 rate + // Supports documentation, not supporting TC-GEO without position based control + // Supports TC-GEO with position based control, not supporting peer control + // Supports TC-SC section control + OurTaskControllerClient.configure(myDDOP, 1, 10, 1, true, false, true, false, true); + +Now that we have our TC client, we need to define some functions to handle what we do when the TC requests information from us, and when it commands us to do something. + +First, we define a function to handle requests: + +.. code-block:: c++ + + bool request_value_command_callback(std::uint16_t elementNumber, + std::uint16_t DDI, + std::int32_t &value, + void *parentPointer) + { + + } + +This function will be called by the TC client when the TC requests a value from the implement. You should fill in the function to return the requested value. Generally this means that you'll want to `switch` on the DDI and/or element number, and return the appropriate value based on what your implement is doing. + +You'll want to return true if the TC provided a valid DDI and element number, and you gave it a value in return. +Returning false will cause the TC client to send an error message to the TC, indicating that the requested value was not available. A TC expects all DPD values in your DDOP to be available, so you should basically never return false. + +See the `seeder example `_ or the `TC client example `_ for an example of how this function can be implemented. + +Next, we define a function to handle commands: + +.. code-block:: c++ + + bool command_value_command_callback(std::uint16_t elementNumber, + std::uint16_t DDI, + std::int32_t processVariableValue, + void *parentPointer) + { + + } + +This function will be called by the TC client when the TC sends a command to the implement. You should fill in the function to handle the command. Generally this means that you'll want to `switch` on the DDI and/or element number, and set the appropriate value based on what your implement is doing. + +You'll want to return true if the TC provided a valid DDI and element number, and you executed the command successfully. If you return false, the TC client will send an error message to the TC, indicating that the command was not executed. A TC expects all "settable" DPD values in your DDOP to be writable, so you should basically never return false. + +You may also then need to trigger sending a value back to the TC, to confirm that the command was received and executed. For example, if the TC sends a command to turn on a section, you probably set the section to on. +Then, if your section's "Actual Condensed Work State" has an on-change trigger, you need to send the new value of that information to the TC. + +To accomplish this, and in fact, to send any value to the TC, you can call the function :code:`on_value_changed_trigger` on the :code:`TaskControllerClient` object. Which will cause the interface to call your previously defined :code:`request_value_command_callback` function with the appropriate DDI and element number and send a message to the TC. + +Lastly, we need to tell the TC client to start running. We do this by calling :code:`initialize`. + +.. code-block:: c++ + + OurTaskControllerClient.initialize(true); // The "true" parameter tells the TC client to start running in a separate thread. If you pass "false", the TC client will run in the same thread as your main program and you'll have to call `update` on it periodically. + +This starts the TC client running. It will now handle messages from the TC, and call your :code:`request_value_command_callback` and :code:`command_value_command_callback` functions as needed. All CAN messaging is handled for you, so you don't need to worry about manually sending any process data messages. + +Once you are done with your TC client, you should call :code:`terminate` on it to stop it from running. + +.. code-block:: c++ + + OurTaskControllerClient.terminate(); + +Other Useful Features +--------------------- + +There are many other functions on the `TaskControllerClient` object that you can use to interact with the TC. You should review the `TaskControllerClient` class in the `AgIsoStack documentation `_ to see what functions are available. + +Some highlights include: + +- :code:`reupload_device_descriptor_object_pool` Which will re-upload the DDOP to the TC. This can be useful if you need to change the DDOP after the TC client has already started running. +- :code:`request_task_controller_identification` Which will request the TC to display its TC "number" on its screen, if applicable. This can be useful if you need to know visually what TC you're connected to. +- :code:`get_is_connected` Which will return true if the TC client is connected to a TC, and false otherwise. Useful to know if you're connected to a TC or not. +- :code:`get_is_task_active` Which will return true if the TC indicates it is currently running a task, and false otherwise. Not all TCs use this value properly, so it may not be useful in all cases. + +Be sure to check out our examples for more information on how to use the `TaskControllerClient` object.