Skip to content

Commit

Permalink
[VT]: add a numeric value tracker and updater for working sets of a V…
Browse files Browse the repository at this point in the history
…T client (#405)

* feat(vt-client): add numeric value state tracker and updater for working sets

* feat(vt-client): add callback to validate numeric value change in tracker

* fix(vt-client): prevent crashes in multiple places
Also changed place of switch-case break points to align with rest of repo

* refactor(vt-client): remove shadowing of field "client"
  • Loading branch information
GwnDaan authored Jan 23, 2024
1 parent 706ffb1 commit 63bdc46
Show file tree
Hide file tree
Showing 9 changed files with 490 additions and 92 deletions.
32 changes: 18 additions & 14 deletions examples/virtual_terminal/version3_object_pool/main.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#include "isobus/hardware_integration/available_can_drivers.hpp"
#include "isobus/hardware_integration/can_hardware_interface.hpp"
#include "isobus/isobus/can_general_parameter_group_numbers.hpp"
#include "isobus/isobus/can_network_manager.hpp"
#include "isobus/isobus/can_partnered_control_function.hpp"
#include "isobus/isobus/can_stack_logger.hpp"
#include "isobus/isobus/isobus_virtual_terminal_client.hpp"
#include "isobus/isobus/isobus_virtual_terminal_client_update_helper.hpp"
#include "isobus/utility/iop_file_interface.hpp"

#include "console_logger.cpp"
Expand All @@ -17,7 +17,8 @@
#include <memory>

//! It is discouraged to use global variables, but it is done here for simplicity.
static std::shared_ptr<isobus::VirtualTerminalClient> TestVirtualTerminalClient = nullptr;
static std::shared_ptr<isobus::VirtualTerminalClient> virtualTerminalClient = nullptr;
static std::shared_ptr<isobus::VirtualTerminalClientUpdateHelper> virtualTerminalUpdateHelper = nullptr;
static std::atomic_bool running = { true };

void signal_handler(int)
Expand All @@ -28,35 +29,34 @@ void signal_handler(int)
// This callback will provide us with event driven notifications of button presses from the stack
void handleVTKeyEvents(const isobus::VirtualTerminalClient::VTKeyEvent &event)
{
static std::uint32_t exampleNumberOutput = 214748364; // In the object pool the output number has an offset of -214748364 so we use this to represent 0.

switch (event.keyEvent)
{
case isobus::VirtualTerminalClient::KeyActivationCode::ButtonUnlatchedOrReleased:
case isobus::VirtualTerminalClient::KeyActivationCode::ButtonStillHeld:
{
switch (event.objectID)
{
case Plus_Button:
{
TestVirtualTerminalClient->send_change_numeric_value(ButtonExampleNumber_VarNum, ++exampleNumberOutput);
virtualTerminalUpdateHelper->increase_numeric_value(ButtonExampleNumber_VarNum);
}
break;

case Minus_Button:
{
TestVirtualTerminalClient->send_change_numeric_value(ButtonExampleNumber_VarNum, --exampleNumberOutput);
virtualTerminalUpdateHelper->decrease_numeric_value(ButtonExampleNumber_VarNum);
}
break;

case alarm_SoftKey:
{
TestVirtualTerminalClient->send_change_active_mask(example_WorkingSet, example_AlarmMask);
virtualTerminalClient->send_change_active_mask(example_WorkingSet, example_AlarmMask);
}
break;

case acknowledgeAlarm_SoftKey:
{
TestVirtualTerminalClient->send_change_active_mask(example_WorkingSet, mainRunscreen_DataMask);
virtualTerminalClient->send_change_active_mask(example_WorkingSet, mainRunscreen_DataMask);
}
break;

Expand Down Expand Up @@ -138,19 +138,23 @@ int main()
auto TestInternalECU = isobus::InternalControlFunction::create(TestDeviceNAME, 0x1C, 0);
auto TestPartnerVT = isobus::PartneredControlFunction::create(0, vtNameFilters);

TestVirtualTerminalClient = std::make_shared<isobus::VirtualTerminalClient>(TestPartnerVT, TestInternalECU);
TestVirtualTerminalClient->set_object_pool(0, testPool.data(), testPool.size(), objectPoolHash);
auto softKeyListener = TestVirtualTerminalClient->add_vt_soft_key_event_listener(handleVTKeyEvents);
auto buttonListener = TestVirtualTerminalClient->add_vt_button_event_listener(handleVTKeyEvents);
TestVirtualTerminalClient->initialize(true);
virtualTerminalClient = std::make_shared<isobus::VirtualTerminalClient>(TestPartnerVT, TestInternalECU);
virtualTerminalClient->set_object_pool(0, testPool.data(), testPool.size(), objectPoolHash);
auto softKeyListener = virtualTerminalClient->add_vt_soft_key_event_listener(handleVTKeyEvents);
auto buttonListener = virtualTerminalClient->add_vt_button_event_listener(handleVTKeyEvents);
virtualTerminalClient->initialize(true);

virtualTerminalUpdateHelper = std::make_shared<isobus::VirtualTerminalClientUpdateHelper>(virtualTerminalClient);
virtualTerminalUpdateHelper->add_tracked_numeric_value(ButtonExampleNumber_VarNum, 214748364); // In the object pool the output number has an offset of -214748364 so we use this to represent 0.
virtualTerminalUpdateHelper->initialize();

while (running)
{
// CAN stack runs in other threads. Do nothing forever.
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

TestVirtualTerminalClient->terminate();
virtualTerminalClient->terminate();
isobus::CANHardwareInterface::stop();
return 0;
}
4 changes: 4 additions & 0 deletions isobus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ set(ISOBUS_SRC
"isobus_speed_distance_messages.cpp"
"isobus_maintain_power_interface.cpp"
"isobus_virtual_terminal_objects.cpp"
"isobus_virtual_terminal_client_state_tracker.cpp"
"isobus_virtual_terminal_client_update_helper.cpp"
"nmea2000_message_definitions.cpp"
"nmea2000_message_interface.cpp"
"can_message_data.cpp")
Expand Down Expand Up @@ -84,6 +86,8 @@ set(ISOBUS_INCLUDE
"isobus_speed_distance_messages.hpp"
"isobus_maintain_power_interface.hpp"
"isobus_virtual_terminal_objects.hpp"
"isobus_virtual_terminal_client_state_tracker.hpp"
"isobus_virtual_terminal_client_update_helper.hpp"
"nmea2000_message_definitions.hpp"
"nmea2000_message_interface.hpp"
"can_message_data.hpp")
Expand Down
6 changes: 6 additions & 0 deletions isobus/include/isobus/isobus/can_message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#define CAN_MESSAGE_HPP

#include "isobus/isobus/can_control_function.hpp"
#include "isobus/isobus/can_general_parameter_group_numbers.hpp"
#include "isobus/isobus/can_identifier.hpp"
#include "isobus/utility/data_span.hpp"

Expand Down Expand Up @@ -103,6 +104,11 @@ namespace isobus
/// @returns The identifier of the message
CANIdentifier get_identifier() const;

/// @brief Compares the identifier of the message to the parameter group number (PGN) supplied
/// @param[in] parameterGroupNumber The parameter group number to compare to
/// @returns True if the message identifier matches the parameter group number, false otherwise
bool is_parameter_group_number(CANLibParameterGroupNumber parameterGroupNumber) const;

/// @brief Returns the CAN channel index associated with the message
/// @returns The CAN channel index associated with the message
std::uint8_t get_can_port_index() const;
Expand Down
156 changes: 78 additions & 78 deletions isobus/include/isobus/isobus/isobus_virtual_terminal_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,84 @@ namespace isobus
class VirtualTerminalClient
{
public:
/// @brief Enumerates the multiplexor byte values for VT commands
enum class Function : std::uint8_t
{
SoftKeyActivationMessage = 0x00,
ButtonActivationMessage = 0x01,
PointingEventMessage = 0x02,
VTSelectInputObjectMessage = 0x03,
VTESCMessage = 0x04,
VTChangeNumericValueMessage = 0x05,
VTChangeActiveMaskMessage = 0x06,
VTChangeSoftKeyMaskMessage = 0x07,
VTChangeStringValueMessage = 0x08,
VTOnUserLayoutHideShowMessage = 0x09,
VTControlAudioSignalTerminationMessage = 0x0A,
ObjectPoolTransferMessage = 0x11,
EndOfObjectPoolMessage = 0x12,
AuxiliaryAssignmentTypeOneCommand = 0x20,
AuxiliaryInputTypeOneStatus = 0x21,
PreferredAssignmentCommand = 0x22,
AuxiliaryInputTypeTwoMaintenanceMessage = 0x23,
AuxiliaryAssignmentTypeTwoCommand = 0x24,
AuxiliaryInputStatusTypeTwoEnableCommand = 0x25,
AuxiliaryInputTypeTwoStatusMessage = 0x26,
AuxiliaryCapabilitiesRequest = 0x27,
SelectActiveWorkingSet = 0x90,
ESCCommand = 0x92,
HideShowObjectCommand = 0xA0,
EnableDisableObjectCommand = 0xA1,
SelectInputObjectCommand = 0xA2,
ControlAudioSignalCommand = 0xA3,
SetAudioVolumeCommand = 0xA4,
ChangeChildLocationCommand = 0xA5,
ChangeSizeCommand = 0xA6,
ChangeBackgroundColourCommand = 0xA7,
ChangeNumericValueCommand = 0xA8,
ChangeEndPointCommand = 0xA9,
ChangeFontAttributesCommand = 0xAA,
ChangeLineAttributesCommand = 0xAB,
ChangeFillAttributesCommand = 0xAC,
ChangeActiveMaskCommand = 0xAD,
ChangeSoftKeyMaskCommand = 0xAE,
ChangeAttributeCommand = 0xAF,
ChangePriorityCommand = 0xB0,
ChangeListItemCommand = 0xB1,
DeleteObjectPoolCommand = 0xB2,
ChangeStringValueCommand = 0xB3,
ChangeChildPositionCommand = 0xB4,
ChangeObjectLabelCommand = 0xB5,
ChangePolygonPointCommand = 0xB6,
ChangePolygonScaleCommand = 0xB7,
GraphicsContextCommand = 0xB8,
GetAttributeValueMessage = 0xB9,
SelectColourMapCommand = 0xBA,
IdentifyVTMessage = 0xBB,
ExecuteExtendedMacroCommand = 0xBC,
LockUnlockMaskCommand = 0xBD,
ExecuteMacroCommand = 0xBE,
GetMemoryMessage = 0xC0,
GetSupportedWidecharsMessage = 0xC1,
GetNumberOfSoftKeysMessage = 0xC2,
GetTextFontDataMessage = 0xC3,
GetWindowMaskDataMessage = 0xC4,
GetSupportedObjectsMessage = 0xC5,
GetHardwareMessage = 0xC7,
StoreVersionCommand = 0xD0,
LoadVersionCommand = 0xD1,
DeleteVersionCommand = 0xD2,
ExtendedGetVersionsMessage = 0xD3,
ExtendedStoreVersionCommand = 0xD4,
ExtendedLoadVersionCommand = 0xD5,
ExtendedDeleteVersionCommand = 0xD6,
GetVersionsMessage = 0xDF,
GetVersionsResponse = 0xE0,
UnsupportedVTFunctionMessage = 0xFD,
VTStatusMessage = 0xFE,
WorkingSetMaintenanceMessage = 0xFF
};

/// @brief Enumerates the states that can be sent with a hide/show object command
enum class HideShowObjectCommand : std::uint8_t
{
Expand Down Expand Up @@ -1197,84 +1275,6 @@ namespace isobus
LanguageCommandInterface languageCommandInterface;

protected:
/// @brief Enumerates the multiplexor byte values for VT commands
enum class Function : std::uint8_t
{
SoftKeyActivationMessage = 0x00,
ButtonActivationMessage = 0x01,
PointingEventMessage = 0x02,
VTSelectInputObjectMessage = 0x03,
VTESCMessage = 0x04,
VTChangeNumericValueMessage = 0x05,
VTChangeActiveMaskMessage = 0x06,
VTChangeSoftKeyMaskMessage = 0x07,
VTChangeStringValueMessage = 0x08,
VTOnUserLayoutHideShowMessage = 0x09,
VTControlAudioSignalTerminationMessage = 0x0A,
ObjectPoolTransferMessage = 0x11,
EndOfObjectPoolMessage = 0x12,
AuxiliaryAssignmentTypeOneCommand = 0x20,
AuxiliaryInputTypeOneStatus = 0x21,
PreferredAssignmentCommand = 0x22,
AuxiliaryInputTypeTwoMaintenanceMessage = 0x23,
AuxiliaryAssignmentTypeTwoCommand = 0x24,
AuxiliaryInputStatusTypeTwoEnableCommand = 0x25,
AuxiliaryInputTypeTwoStatusMessage = 0x26,
AuxiliaryCapabilitiesRequest = 0x27,
SelectActiveWorkingSet = 0x90,
ESCCommand = 0x92,
HideShowObjectCommand = 0xA0,
EnableDisableObjectCommand = 0xA1,
SelectInputObjectCommand = 0xA2,
ControlAudioSignalCommand = 0xA3,
SetAudioVolumeCommand = 0xA4,
ChangeChildLocationCommand = 0xA5,
ChangeSizeCommand = 0xA6,
ChangeBackgroundColourCommand = 0xA7,
ChangeNumericValueCommand = 0xA8,
ChangeEndPointCommand = 0xA9,
ChangeFontAttributesCommand = 0xAA,
ChangeLineAttributesCommand = 0xAB,
ChangeFillAttributesCommand = 0xAC,
ChangeActiveMaskCommand = 0xAD,
ChangeSoftKeyMaskCommand = 0xAE,
ChangeAttributeCommand = 0xAF,
ChangePriorityCommand = 0xB0,
ChangeListItemCommand = 0xB1,
DeleteObjectPoolCommand = 0xB2,
ChangeStringValueCommand = 0xB3,
ChangeChildPositionCommand = 0xB4,
ChangeObjectLabelCommand = 0xB5,
ChangePolygonPointCommand = 0xB6,
ChangePolygonScaleCommand = 0xB7,
GraphicsContextCommand = 0xB8,
GetAttributeValueMessage = 0xB9,
SelectColourMapCommand = 0xBA,
IdentifyVTMessage = 0xBB,
ExecuteExtendedMacroCommand = 0xBC,
LockUnlockMaskCommand = 0xBD,
ExecuteMacroCommand = 0xBE,
GetMemoryMessage = 0xC0,
GetSupportedWidecharsMessage = 0xC1,
GetNumberOfSoftKeysMessage = 0xC2,
GetTextFontDataMessage = 0xC3,
GetWindowMaskDataMessage = 0xC4,
GetSupportedObjectsMessage = 0xC5,
GetHardwareMessage = 0xC7,
StoreVersionCommand = 0xD0,
LoadVersionCommand = 0xD1,
DeleteVersionCommand = 0xD2,
ExtendedGetVersionsMessage = 0xD3,
ExtendedStoreVersionCommand = 0xD4,
ExtendedLoadVersionCommand = 0xD5,
ExtendedDeleteVersionCommand = 0xD6,
GetVersionsMessage = 0xDF,
GetVersionsResponse = 0xE0,
UnsupportedVTFunctionMessage = 0xFD,
VTStatusMessage = 0xFE,
WorkingSetMaintenanceMessage = 0xFF
};

/// @brief Enumerates the command types for graphics context objects
enum class GraphicsContextSubCommandID : std::uint8_t
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//================================================================================================
/// @file isobus_virtual_terminal_client_state_tracker.hpp
///
/// @brief A helper class to track the state of an active working set.
/// @author Daan Steenbergen
///
/// @copyright 2023 The Open-Agriculture Developers
//================================================================================================

#ifndef ISOBUS_VIRTUAL_TERMINAL_CLIENT_STATE_TRACKER_HPP
#define ISOBUS_VIRTUAL_TERMINAL_CLIENT_STATE_TRACKER_HPP

#include "isobus/isobus/can_control_function.hpp"
#include "isobus/isobus/can_message.hpp"

#include <map>
#include <vector>

namespace isobus
{
/// @brief A helper class to update and track the state of an active working set.
/// @details The state is from the client's perspective. It might not be the same
/// as the state of the server, but tries to be as close as possible.
class VirtualTerminalClientStateTracker
{
public:
/// @brief The constructor to track the state of an active working set provided by a client.
/// @param[in] client The control function of the client. May be external.
explicit VirtualTerminalClientStateTracker(std::shared_ptr<ControlFunction> client);

/// @brief The destructor.
~VirtualTerminalClientStateTracker();

/// @brief Initializes the state tracker.
void initialize();

/// @brief Terminate the state tracker.
void terminate();

//! TODO: void initialize_with_defaults(ObjectPool &objectPool);

/// @brief Adds a numeric value to track.
/// @param[in] objectId The object id of the numeric value to track.
/// @param[in] initialValue The initial value of the numeric value to track.
void add_tracked_numeric_value(std::uint16_t objectId, std::uint32_t initialValue = 0);

/// @brief Removes a numeric value from tracking.
/// @param[in] objectId The object id of the numeric value to remove from tracking.
void remove_tracked_numeric_value(std::uint16_t objectId);

/// @brief Gets the current numeric value of a tracked object.
/// @param[in] objectId The object id of the numeric value to get.
/// @return The current numeric value of the tracked object.
std::uint32_t get_numeric_value(std::uint16_t objectId) const;

protected:
std::shared_ptr<ControlFunction> client; ///< The control function of the virtual terminal client to track.

//! TODO: std::map<std::uint16_t, bool> shownStates; ///< Holds the 'hide/show' state of tracked objects.
//! TODO: std::map<std::uint16_t, bool> enabledStates; ///< Holds the 'enable/disable' state of tracked objects.
//! TODO: std::map<std::uint16_t, bool> selectedStates; ///< Holds the 'selected for input' state of tracked objects.
//! TODO: add current audio signal state
//! TODO: std::uint8_t audioVolumeState; ///< Holds the current audio volume.
//! TODO: std::map<std::uint16_t, std::pair<std::uint16_t, std::uint16_t>> positionStates; ///< Holds the 'position (x,y)' state of tracked objects.
//! TODO: std::map<std::uint16_t, std::pair<std::uint16_t, std::uint16_t>> sizeStates; ///< Holds the 'size (width,height)' state of tracked objects.
//! TODO: std::map<std::uint16_t, std::uint8_t> backgroundColourStates; ///< Holds the 'background colour' state of tracked objects.
std::map<std::uint16_t, std::uint32_t> numericValueStates; ///< Holds the 'numeric value' state of tracked objects.
//! TODO: std::map<std::uint16_t, std::string> stringValueStates; ///< Holds the 'string value' state of tracked objects.
//! TODO: std::map<std::uint16_t, std::uint8_t> endPointStates; ///< Holds the 'end point' state of tracked objects.
//! TODO: add font attribute state
//! TODO: add line attribute state
//! TODO: add fill attribute state
std::uint16_t currentActiveMask; ///< Holds the currently active mask.
//! TODO: std::uint16_t currentWorkingSet; ///< Holds the working set of the current active mask.
//! TODO: std::map<std::uint16_t, std::uint16_t> softKeyMasks; ///< Holds the data/alarms masks with their associated soft keys masks for tracked objects.
//! TODO: std::map<std::uint16_t, std::pair<std::uint8_t, std::uint32_t>> attributeStates; ///< Holds the 'attribute' state of tracked objects.
//! TODO: std::map<std::uint16_t, std::uint8_t> alarmMaskPrioritiesStates; ///< Holds the 'alarm mask priority' state of tracked objects.
//! TODO: std::map<std::uint16_t, std::pair<std::uint8_t, std::uint16_t>> listItemStates; ///< Holds the 'list item' state of tracked objects.
//! TODO: add lock/unlock mask state
//! TODO: add object label state
//! TODO: add polygon point state
//! TODO: add polygon scale state
//! TODO: add graphics context state
//! TODO: std::uint16_t currentColourMap; ///< Holds the current colour map/palette object.

private:
/// @brief Processes a received message.
/// @param[in] message The received message.
/// @param[in] parentPointer The pointer to the parent object, which should be the VirtualTerminalClientStateTracker.
static void process_rx_message(const CANMessage &message, void *parentPointer);

/// @brief Processes a received message.
/// @param[in] message The received message.
void process_rx_message(const CANMessage &message);
};
} // namespace isobus

#endif // ISOBUS_VIRTUAL_TERMINAL_CLIENT_STATE_TRACKER_HPP
Loading

0 comments on commit 63bdc46

Please sign in to comment.