AgIsoStack++
A control-function-focused implementation of the major ISOBUS and J1939 protocols
Loading...
Searching...
No Matches
isobus_language_command_interface.cpp
Go to the documentation of this file.
1//================================================================================================
9//================================================================================================
11
17#include "isobus/utility/system_timing.hpp"
18#include "isobus/utility/to_string.hpp"
19
20#include <string>
21
22namespace isobus
23{
24 LanguageCommandInterface::LanguageCommandInterface(std::shared_ptr<InternalControlFunction> sourceControlFunction, bool shouldRespondToRequests) :
25 myControlFunction(sourceControlFunction),
26 myPartner(nullptr),
27 respondToRequests(shouldRespondToRequests)
28 {
29 }
30
31 LanguageCommandInterface::LanguageCommandInterface(std::shared_ptr<InternalControlFunction> sourceControlFunction, std::shared_ptr<PartneredControlFunction> filteredControlFunction) :
32 myControlFunction(sourceControlFunction),
33 myPartner(filteredControlFunction)
34 {
35 }
36
37 LanguageCommandInterface ::~LanguageCommandInterface()
38 {
39 if (initialized)
40 {
41 CANNetworkManager::CANNetwork.remove_global_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand), process_rx_message, this);
42
43 if (respondToRequests && (!myControlFunction->get_pgn_request_protocol().expired()))
44 {
45 myControlFunction->get_pgn_request_protocol().lock()->remove_pgn_request_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand), on_language_request, this);
46 }
47 }
48 }
49
51 {
52 if (!initialized)
53 {
54 if (nullptr != myControlFunction)
55 {
56 CANNetworkManager::CANNetwork.add_global_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand), process_rx_message, this);
57
58 if (respondToRequests && (!myControlFunction->get_pgn_request_protocol().expired()))
59 {
60 myControlFunction->get_pgn_request_protocol().lock()->register_pgn_request_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand), on_language_request, this);
61 }
62 initialized = true;
63 }
64 else
65 {
66 LOG_ERROR("[VT/TC]: Language command interface is missing an internal control function, and will not be functional.");
67 }
68 }
69 else
70 {
71 LOG_WARNING("[VT/TC]: Language command interface has been initialized, but is being initialized again.");
72 }
73 }
74
75 void LanguageCommandInterface::set_partner(std::shared_ptr<PartneredControlFunction> filteredControlFunction)
76 {
77 myPartner = filteredControlFunction;
78 }
79
80 std::shared_ptr<PartneredControlFunction> LanguageCommandInterface::get_partner() const
81 {
82 return myPartner;
83 }
84
86 {
87 return initialized;
88 }
89
91 {
92 bool retVal = false;
93
94 if (initialized)
95 {
96 retVal = ParameterGroupNumberRequestProtocol::request_parameter_group_number(static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand), myControlFunction, myPartner);
97 }
98 else
99 {
100 // Make sure you call initialize first!
101 LOG_ERROR("[VT/TC]: Language command interface is being used without being initialized!");
102 }
103 return retVal;
104 }
105
107 {
108 if ((languageCode.length() < 2) || (countryCode.length() < 2))
109 {
110 LOG_ERROR("[VT/TC]: Language command interface is missing language or country code, and will not send a language command.");
111 return false;
112 }
113 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer{
114 static_cast<std::uint8_t>(languageCode[0]),
115 static_cast<std::uint8_t>(languageCode[1]),
116 static_cast<std::uint8_t>((static_cast<std::uint8_t>(timeFormat) << 4) |
117 (static_cast<std::uint8_t>(decimalSymbol) << 6)),
118 static_cast<std::uint8_t>(dateFormat),
119 static_cast<std::uint8_t>(static_cast<std::uint8_t>(massUnitSystem) |
120 (static_cast<std::uint8_t>(volumeUnitSystem) << 2) |
121 (static_cast<std::uint8_t>(areaUnitSystem) << 4) |
122 (static_cast<std::uint8_t>(distanceUnitSystem) << 6)),
123 static_cast<std::uint8_t>(static_cast<std::uint8_t>(genericUnitSystem) |
124 (static_cast<std::uint8_t>(forceUnitSystem) << 2) |
125 (static_cast<std::uint8_t>(pressureUnitSystem) << 4) |
126 (static_cast<std::uint8_t>(temperatureUnitSystem) << 6)),
127 static_cast<std::uint8_t>(countryCode[0]),
128 static_cast<std::uint8_t>(countryCode[1])
129 };
130 return CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand),
131 buffer.data(),
132 buffer.size(),
134 nullptr);
135 }
136
138 {
139 return countryCode;
140 }
141
143 {
144 if (country.length() > 2)
145 {
146 LOG_WARNING("[VT/TC]: Language command country code should not be more than 2 characters! It will be truncated.");
147 }
148 else if (country.length() < 2)
149 {
150 LOG_WARNING("[VT/TC]: Language command country code should not be less than 2 characters! It will be padded.");
151 }
152
153 while (country.length() < 2)
154 {
155 country.push_back(' ');
156 }
157 countryCode = country;
158 }
159
161 {
162 return languageCode;
163 }
164
166 {
167 if (language.length() > 2)
168 {
169 LOG_WARNING("[VT/TC]: Language command language code should not be more than 2 characters! It will be truncated.");
170 }
171 else if (language.length() < 2)
172 {
173 LOG_WARNING("[VT/TC]: Language command language code should not be less than 2 characters! It will be padded.");
174 }
175
176 while (language.length() < 2)
177 {
178 language.push_back(' ');
179 }
180 languageCode = language;
181 }
182
187
192
197
202
207
212
217
222
227
232
237
242
247
252
257
262
267
272
277
282
287
292
297
298 const std::array<std::uint8_t, 7> LanguageCommandInterface::get_localization_raw_data() const
299 {
300 std::array<std::uint8_t, 7> retVal = { 0 };
301
302 if (languageCode.size() >= 2)
303 {
304 retVal[0] = languageCode[0];
305 retVal[1] = languageCode[1];
306 }
307 else
308 {
309 retVal[0] = ' ';
310 retVal[1] = ' ';
311 }
312 retVal[2] = ((static_cast<std::uint8_t>(timeFormat) << 4) |
313 (static_cast<std::uint8_t>(decimalSymbol) << 6));
314 retVal[3] = static_cast<std::uint8_t>(dateFormat);
315 retVal[4] = (static_cast<std::uint8_t>(massUnitSystem) |
316 (static_cast<std::uint8_t>(volumeUnitSystem) << 2) |
317 (static_cast<std::uint8_t>(areaUnitSystem) << 4) |
318 (static_cast<std::uint8_t>(distanceUnitSystem) << 6));
319 retVal[5] = (static_cast<std::uint8_t>(genericUnitSystem) |
320 (static_cast<std::uint8_t>(forceUnitSystem) << 2) |
321 (static_cast<std::uint8_t>(pressureUnitSystem) << 4) |
322 (static_cast<std::uint8_t>(temperatureUnitSystem) << 6));
323 retVal[6] = 0xFF;
324 return retVal;
325 }
326
327 void LanguageCommandInterface::process_rx_message(const CANMessage &message, void *parentPointer)
328 {
329 auto *parentInterface = reinterpret_cast<LanguageCommandInterface *>(parentPointer);
330
331 if ((nullptr != parentInterface) &&
332 (CAN_DATA_LENGTH <= message.get_data_length()) &&
333 (static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand) == message.get_identifier().get_parameter_group_number()) &&
334 ((nullptr == parentInterface->myPartner) ||
335 (message.get_source_control_function()->get_NAME() == parentInterface->myPartner->get_NAME())))
336 {
337 const auto &data = message.get_data();
338 parentInterface->languageCommandTimestamp_ms = SystemTiming::get_timestamp_ms();
339 parentInterface->languageCode.clear();
340 parentInterface->languageCode.push_back(static_cast<char>(data.at(0)));
341 parentInterface->languageCode.push_back(static_cast<char>(data.at(1)));
342 parentInterface->timeFormat = static_cast<TimeFormats>((data.at(2) >> 4) & 0x03);
343 parentInterface->decimalSymbol = static_cast<DecimalSymbols>((data.at(2) >> 6) & 0x03);
344 parentInterface->dateFormat = static_cast<DateFormats>(data.at(3));
345 parentInterface->massUnitSystem = static_cast<MassUnits>(data.at(4) & 0x03);
346 parentInterface->volumeUnitSystem = static_cast<VolumeUnits>((data.at(4) >> 2) & 0x03);
347 parentInterface->areaUnitSystem = static_cast<AreaUnits>((data.at(4) >> 4) & 0x03);
348 parentInterface->distanceUnitSystem = static_cast<DistanceUnits>((data.at(4) >> 6) & 0x03);
349 parentInterface->genericUnitSystem = static_cast<UnitSystem>(data.at(5) & 0x03);
350 parentInterface->forceUnitSystem = static_cast<ForceUnits>((data.at(5) >> 2) & 0x03);
351 parentInterface->pressureUnitSystem = static_cast<PressureUnits>((data.at(5) >> 4) & 0x03);
352 parentInterface->temperatureUnitSystem = static_cast<TemperatureUnits>((data.at(5) >> 6) & 0x03);
353 parentInterface->countryCode.clear();
354
355 if ((0xFF != data.at(6)) || (0xFF != data.at(7)))
356 {
357 parentInterface->countryCode.push_back(static_cast<char>(data.at(6)));
358 parentInterface->countryCode.push_back(static_cast<char>(data.at(7)));
359 }
360
361 LOG_DEBUG("[VT/TC]: Language and unit data received from control function " +
362 isobus::to_string(static_cast<int>(message.get_identifier().get_source_address())) +
363 " language is: " +
364 parentInterface->languageCode.c_str(),
365 " and country code is ",
366 parentInterface->countryCode.empty() ? "unknown." : parentInterface->countryCode.c_str());
367 }
368 }
369
370 bool LanguageCommandInterface::on_language_request(std::uint32_t parameterGroupNumber,
371 std::shared_ptr<ControlFunction>,
372 bool &acknowledge,
373 AcknowledgementType &acknowledgeType,
374 void *parentPointer)
375 {
376 bool retVal = false;
377
378 if ((nullptr != parentPointer) && (static_cast<std::uint32_t>(CANLibParameterGroupNumber::LanguageCommand) == parameterGroupNumber))
379 {
380 auto targetInterface = static_cast<LanguageCommandInterface *>(parentPointer);
381 acknowledge = false;
382 acknowledgeType = AcknowledgementType::Positive;
383 retVal = true;
384 targetInterface->send_language_command();
385 }
386 return retVal;
387 }
388}
General constants used throughout this library.
Defines some PGNs that are used in the library or are very common.
A protocol that handles PGN requests.
A class that describes a control function on the bus that the stack should communicate with....
A class that acts as a logging sink. The intent is that someone could make their own derived class of...
std::uint8_t get_source_address() const
Returns the source address of the frame encoded in the identifier.
std::uint32_t get_parameter_group_number() const
Returns the PGN encoded in the identifier.
A class that represents a generic CAN message of arbitrary length.
const std::vector< std::uint8_t > & get_data() const
Gets a reference to the data in the CAN message.
std::uint32_t get_data_length() const
Returns the length of the data in the CAN message.
std::shared_ptr< ControlFunction > get_source_control_function() const
Gets the source control function that the message is from.
CANIdentifier get_identifier() const
Returns the identifier of the message.
void add_global_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parent)
This is how you register a callback for any PGN destined for the global address (0xFF)
static CANNetworkManager CANNetwork
Static singleton of the one network manager. Use this to access stack functionality.
void remove_global_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parent)
This is how you remove a callback for any PGN destined for the global address (0xFF)
bool send_can_message(std::uint32_t parameterGroupNumber, const std::uint8_t *dataBuffer, std::uint32_t dataLength, std::shared_ptr< InternalControlFunction > sourceControlFunction, std::shared_ptr< ControlFunction > destinationControlFunction=nullptr, CANIdentifier::CANPriority priority=CANIdentifier::CANPriority::PriorityDefault6, TransmitCompleteCallback txCompleteCallback=nullptr, void *parentPointer=nullptr, DataChunkCallback frameChunkCallback=nullptr)
This is the main way to send a CAN message of any length.
An interface for requesting and parsing the ISO11783 language command PGN, 0xFE0F.
static bool on_language_request(std::uint32_t parameterGroupNumber, std::shared_ptr< ControlFunction > requestingControlFunction, bool &acknowledge, AcknowledgementType &acknowledgeType, void *parentPointer)
This is a callback to handle clients requesting the content of our language data for things like VT/T...
ForceUnits forceUnitSystem
The force units that were commanded by the last language command message.
DecimalSymbols get_commanded_decimal_symbol() const
Returns the commanded decimal symbol parsed from the last language command.
PressureUnits get_commanded_pressure_units() const
Returns the commanded pressure units parsed from the last received language command.
ForceUnits get_commanded_force_units() const
Returns the commanded force units parsed from the last received language command.
UnitSystem genericUnitSystem
The "unit system" that was commanded by the last language command message.
void set_commanded_generic_units(UnitSystem units)
Sets the commanded generic unit system.
MassUnits
Command specifying a mass unit. (SPN 2417)
void set_commanded_date_format(DateFormats format)
Sets the commanded date format.
std::string get_language_code() const
Returns the commanded language code parsed from the last language command.
bool respondToRequests
Stores if the class should respond to PGN requests for the language command.
TemperatureUnits get_commanded_temperature_units() const
Returns the commanded temperature units parsed from the last received language command.
void set_commanded_force_units(ForceUnits units)
Sets the commanded force units.
bool initialized
Tracks if initialize has been called yet for this interface.
std::shared_ptr< InternalControlFunction > myControlFunction
The control function to send messages as.
bool send_request_language_command() const
Sends a PGN request for the language command PGN to the interface's partner, or the global address de...
VolumeUnits
Command specifying a volume unit. (SPN 2416)
void set_country_code(std::string country)
Sets the country code specifying the operator's desired language dialect.
DistanceUnits get_commanded_distance_units() const
Returns the commanded distance units parsed from the last language command.
void set_commanded_decimal_symbol(DecimalSymbols decimals)
Sets the decimal symbol to be used.
TemperatureUnits temperatureUnitSystem
The temperature units that were commanded by the last language command message.
LanguageCommandInterface(std::shared_ptr< InternalControlFunction > sourceControlFunction, bool shouldRespondToRequests=false)
Constructor for a LanguageCommandInterface.
TimeFormats
Command sent to all CFs specifying the displayed format of the time. (SPN 2413)
AreaUnits
Command specifying an area unit. (SPN 2415)
std::string get_country_code() const
Returns the commanded country code parsed from the last language command specifying the operator's de...
MassUnits get_commanded_mass_units() const
Returns the commanded mass units parsed from the last received language command.
ForceUnits
Command specifying a force unit (SPN 5196)
MassUnits massUnitSystem
The mass units that were commanded by the last language command message.
DateFormats dateFormat
The date format that was commanded by the last language command message.
std::shared_ptr< PartneredControlFunction > get_partner() const
Returns the current partner being used by the interface.
DateFormats
Command sent to all CFs specifying the displayed format of the date. (SPN 2412)
void set_commanded_mass_units(MassUnits units)
Sets the commanded mass units.
void set_partner(std::shared_ptr< PartneredControlFunction > filteredControlFunction)
Changes the partner being used by the interface to a new partner.
void set_commanded_pressure_units(PressureUnits units)
Sets the commanded pressure units.
bool get_initialized() const
Returns if initialize has been called yet.
UnitSystem get_commanded_generic_units() const
Returns the commanded "unit system" generic value that was parsed from the last received language com...
std::uint32_t get_language_command_timestamp() const
Returns a timestamp (in ms) corresponding to when the interface last received a language command.
AreaUnits get_commanded_area_units() const
Returns the commanded area units parsed from the last received language command.
const std::array< std::uint8_t, 7 > get_localization_raw_data() const
Returns The raw bytes that comprise the current localization data as defined in ISO11783-7.
bool send_language_command()
Sends a language command based on the current content of this class as a broadcast.
UnitSystem
May be used for the display of any unit, or a unit other than those explicitly specified (SPN 5197)
DistanceUnits distanceUnitSystem
The distance units that were commanded by the last language command message.
void set_language_code(std::string language)
Sets the language.
AreaUnits areaUnitSystem
The area units that were commanded by the last language command message.
void set_commanded_volume_units(VolumeUnits units)
Sets the commanded volume units.
DistanceUnits
Command specifying a distance unit. (SPN 2414)
DecimalSymbols decimalSymbol
The decimal symbol that was commanded by the last language command message.
VolumeUnits volumeUnitSystem
The volume units that were commanded by the last language command message.
PressureUnits
Command specifying a pressure unit (SPN 5195)
TimeFormats timeFormat
The time format that was commanded by the last language command message.
TemperatureUnits
Command specifying a temperature unit. (SPN 5194)
void set_commanded_temperature_units(TemperatureUnits units)
Sets the commanded temperature units.
static void process_rx_message(const CANMessage &message, void *parentPointer)
Parses incoming CAN messages into usable unit and language settings.
void set_commanded_area_units(AreaUnits units)
Sets the commanded area units.
std::shared_ptr< PartneredControlFunction > myPartner
The partner to talk to, or nullptr to listen to all CFs.
TimeFormats get_commanded_time_format() const
Returns the commanded time format parsed from the last language command.
DecimalSymbols
Command sent to all CFs that determines whether a point or a comma will be displayed as the decimal s...
std::string languageCode
The last received language code, such as "en", "es", "de", etc.
DateFormats get_commanded_date_format() const
Returns the commanded date format parsed from the last language command.
std::uint32_t languageCommandTimestamp_ms
A millisecond timestamp correlated to the last received language command message.
std::string countryCode
The last received alpha-2 country code as specified by ISO 3166-1, such as "NL, FR,...
void set_commanded_distance_units(DistanceUnits units)
Sets the commanded distance units.
VolumeUnits get_commanded_volume_units() const
Returns the commanded volume units parsed from the last received language command.
void set_commanded_time_format(TimeFormats format)
Sets the commanded time format.
PressureUnits pressureUnitSystem
The pressure units that were commanded by the last language command message.
static bool request_parameter_group_number(std::uint32_t pgn, std::shared_ptr< InternalControlFunction > source, std::shared_ptr< ControlFunction > destination)
Sends a PGN request to the specified control function.
Defines a set of values found in the isobus language command message from ISO11783-7 commonly used in...
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...
constexpr std::uint8_t CAN_DATA_LENGTH
The length of a classical CAN frame.
AcknowledgementType
The types of acknowledgement that can be sent in the Ack PGN.
@ Positive
"ACK" Indicates that the request was completed