Skip to content

Commit

Permalink
[TC]: Add options for falling back to other language data sources whe…
Browse files Browse the repository at this point in the history
…n TC doesn't respond

Allow the TC client to fall back to other language sources as needed.
Fixed a condition where the TC client would become stuck while waiting for a language response if a response never arrived.
Added a getter to the language command interface to allow retrieving the assigned partner CF.
Prevent a crash in the language command interface which could occur if you send the command with some fields left unconfigured.
  • Loading branch information
ad3154 committed Mar 13, 2024
1 parent 6edc33d commit a4c3571
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ namespace isobus
/// @param[in] filteredControlFunction The new partner to communicate with
void set_partner(std::shared_ptr<PartneredControlFunction> filteredControlFunction);

/// @brief Returns the current partner being used by the interface
/// @return The current partner being used by the interface, or nullptr if none
std::shared_ptr<PartneredControlFunction> get_partner() const;

/// @brief Returns if initialize has been called yet
/// @return `true` if initialize has been called, otherwise false
bool get_initialized() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ namespace isobus
std::uint32_t statusMessageTimestamp_ms = 0; ///< Timestamp corresponding to the last time we sent a status message to the TC
std::uint32_t serverStatusMessageTimestamp_ms = 0; ///< Timestamp corresponding to the last time we received a status message from the TC
std::uint32_t userSuppliedBinaryDDOPSize_bytes = 0; ///< The number of bytes in the user provided binary DDOP (if one was provided)
std::uint32_t languageCommandWaitingTimestamp_ms = 0; ///< Timestamp used to determine when to give up on waiting for a language command response
std::uint8_t numberOfWorkingSetMembers = 1; ///< The number of working set members that will be reported in the working set master message
std::uint8_t tcStatusBitfield = 0; ///< The last received TC/DL status from the status message
std::uint8_t sourceAddressOfCommandBeingExecuted = 0; ///< Source address of client for which the current command is being executed
Expand Down
10 changes: 10 additions & 0 deletions isobus/src/isobus_language_command_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ namespace isobus
myPartner = filteredControlFunction;
}

std::shared_ptr<PartneredControlFunction> LanguageCommandInterface::get_partner() const
{
return myPartner;
}

bool LanguageCommandInterface::get_initialized() const
{
return initialized;
Expand All @@ -100,6 +105,11 @@ namespace isobus

bool LanguageCommandInterface::send_language_command() const
{
if ((languageCode.length() < 2) || (countryCode.length() < 2))
{
LOG_ERROR("[VT/TC]: Language command interface is missing language or country code, and will not send a language command.");
return false;
}
std::array<std::uint8_t, CAN_DATA_LENGTH> buffer{
static_cast<std::uint8_t>(languageCode[0]),
static_cast<std::uint8_t>(languageCode[1]),
Expand Down
38 changes: 30 additions & 8 deletions isobus/src/isobus_task_controller_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,15 +511,13 @@ namespace isobus
LOG_WARNING("[TC]: The TC is < version 4 but no VT was provided. Language data will be requested globally, which might not be ideal.");
}

if ((serverVersion < static_cast<std::uint8_t>(Version::SecondPublishedEdition)) &&
(nullptr != primaryVirtualTerminal) &&
(primaryVirtualTerminal->languageCommandInterface.send_request_language_command()))
{
set_state(StateMachineState::WaitForLanguageResponse);
}
else if (languageCommandInterface.send_request_language_command())
if (((serverVersion < static_cast<std::uint8_t>(Version::SecondPublishedEdition)) &&
(nullptr != primaryVirtualTerminal) &&
(primaryVirtualTerminal->languageCommandInterface.send_request_language_command())) ||
(languageCommandInterface.send_request_language_command()))
{
set_state(StateMachineState::WaitForLanguageResponse);
languageCommandWaitingTimestamp_ms = SystemTiming::get_timestamp_ms();
}
else if (SystemTiming::time_expired_ms(stateMachineTimestamp_ms, SIX_SECOND_TIMEOUT_MS))
{
Expand All @@ -531,11 +529,35 @@ namespace isobus

case StateMachineState::WaitForLanguageResponse:
{
if ((SystemTiming::get_time_elapsed_ms(languageCommandInterface.get_language_command_timestamp()) < SIX_SECOND_TIMEOUT_MS) &&
if ((SystemTiming::get_time_elapsed_ms(languageCommandInterface.get_language_command_timestamp()) < TWO_SECOND_TIMEOUT_MS) &&
("" != languageCommandInterface.get_language_code()))
{
set_state(StateMachineState::ProcessDDOP);
}
else if ((SystemTiming::time_expired_ms(stateMachineTimestamp_ms, TWO_SECOND_TIMEOUT_MS)) &&
(nullptr != languageCommandInterface.get_partner()))
{
LOG_WARNING("[TC]: No response to our request for the language command data, which is unusual.");

if (nullptr != primaryVirtualTerminal)
{
LOG_WARNING("[TC]: Falling back to VT for language data.");
primaryVirtualTerminal->languageCommandInterface.send_request_language_command();
stateMachineTimestamp_ms = SystemTiming::get_timestamp_ms();
}
else
{
LOG_WARNING("[TC]: Since no VT was specified, falling back to a global request for language data.");
languageCommandInterface.set_partner(nullptr);
languageCommandInterface.send_request_language_command();
stateMachineTimestamp_ms = SystemTiming::get_timestamp_ms();
}
}
else if (SystemTiming::time_expired_ms(languageCommandWaitingTimestamp_ms, SIX_SECOND_TIMEOUT_MS))
{
LOG_WARNING("[TC]: Timeout waiting for language response. Moving on to processing the DDOP anyways.");
set_state(StateMachineState::ProcessDDOP);
}
}
break;

Expand Down
3 changes: 3 additions & 0 deletions test/language_command_interface_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ TEST(LANGUAGE_COMMAND_INTERFACE_TESTS, SettersAndTransmitting)

interfaceUnderTest.initialize();

// Sending a request without setting the various string parameters should not emit a message
EXPECT_FALSE(interfaceUnderTest.send_language_command());

interfaceUnderTest.set_language_code("en");
interfaceUnderTest.set_commanded_decimal_symbol(LanguageCommandInterface::DecimalSymbols::Comma);
interfaceUnderTest.set_commanded_time_format(LanguageCommandInterface::TimeFormats::TwentyFourHour);
Expand Down
4 changes: 2 additions & 2 deletions test/tc_client_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1309,11 +1309,11 @@ TEST(TASK_CONTROLLER_CLIENT_TESTS, TimeoutTests)
interfaceUnderTest.update();
EXPECT_EQ(interfaceUnderTest.test_wrapper_get_state(), TaskControllerClient::StateMachineState::RequestLanguage);

// Test lack of timeout waiting for language (hold state)
// Test that we can't get stuck in the request language state
interfaceUnderTest.test_wrapper_set_state(TaskControllerClient::StateMachineState::WaitForLanguageResponse);
EXPECT_EQ(interfaceUnderTest.test_wrapper_get_state(), TaskControllerClient::StateMachineState::WaitForLanguageResponse);
interfaceUnderTest.update();
EXPECT_EQ(interfaceUnderTest.test_wrapper_get_state(), TaskControllerClient::StateMachineState::WaitForLanguageResponse);
EXPECT_EQ(interfaceUnderTest.test_wrapper_get_state(), TaskControllerClient::StateMachineState::ProcessDDOP);

// Test timeout waiting for object pool transfer response
interfaceUnderTest.test_wrapper_set_state(TaskControllerClient::StateMachineState::WaitForObjectPoolTransferResponse, 0);
Expand Down

0 comments on commit a4c3571

Please sign in to comment.