AgIsoStack++
A control-function-focused implementation of the major ISOBUS and J1939 protocols
Loading...
Searching...
No Matches
isobus_speed_distance_messages.cpp
Go to the documentation of this file.
1//================================================================================================
20//================================================================================================
25#include "isobus/utility/system_timing.hpp"
26
27#include <cassert>
28
29namespace isobus
30{
31 SpeedMessagesInterface::SpeedMessagesInterface(std::shared_ptr<InternalControlFunction> source,
32 bool enableSendingGroundBasedSpeedPeriodically,
33 bool enableSendingWheelBasedSpeedPeriodically,
34 bool enableSendingMachineSelectedSpeedPeriodically,
35 bool enableSendingMachineSelectedSpeedCommandPeriodically) :
36 machineSelectedSpeedTransmitData(MachineSelectedSpeedData(enableSendingMachineSelectedSpeedPeriodically ? source : nullptr)),
37 wheelBasedSpeedTransmitData(WheelBasedMachineSpeedData(enableSendingWheelBasedSpeedPeriodically ? source : nullptr)),
38 groundBasedSpeedTransmitData(GroundBasedSpeedData(enableSendingGroundBasedSpeedPeriodically ? source : nullptr)),
39 machineSelectedSpeedCommandTransmitData(MachineSelectedSpeedCommandData(enableSendingMachineSelectedSpeedCommandPeriodically ? source : nullptr)),
40 txFlags(static_cast<std::uint32_t>(TransmitFlags::NumberOfFlags), process_flags, this)
41 {
42 }
43
45 {
46 if (initialized)
47 {
48 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeed), process_rx_message, this);
49 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::WheelBasedSpeedAndDistance), process_rx_message, this);
50 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::GroundBasedSpeedAndDistance), process_rx_message, this);
51 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeedCommand), process_rx_message, this);
52 }
53 }
54
56 controlFunction(sender)
57 {
58 }
59
61 {
62 std::uint32_t retVal = wheelBasedMachineDistance_mm;
63
64 // Values above the max are sort of implicitly defined and should be ignored.
65 if (wheelBasedMachineDistance_mm > SAEds05_MAX_VALUE)
66 {
67 retVal = 0;
68 }
69 return retVal;
70 }
71
73 {
74 bool retVal = (distance != wheelBasedMachineDistance_mm);
75 wheelBasedMachineDistance_mm = distance;
76 return retVal;
77 }
78
80 {
81 std::uint16_t retVal = wheelBasedMachineSpeed_mm_per_sec;
82
83 if (wheelBasedMachineSpeed_mm_per_sec > SAEvl01_MAX_VALUE)
84 {
85 retVal = 0;
86 }
87 return retVal;
88 }
89
91 {
92 bool retVal = (speed != wheelBasedMachineSpeed_mm_per_sec);
93 wheelBasedMachineSpeed_mm_per_sec = speed;
94 return retVal;
95 }
96
98 {
99 return maximumTimeOfTractorPower_min;
100 }
101
103 {
104 bool retVal = (maximumTimeOfTractorPower_min != maxTime);
105 maximumTimeOfTractorPower_min = maxTime;
106 return retVal;
107 }
108
113
115 {
116 bool retVal = (machineDirectionState != direction);
117 machineDirectionState = direction;
118 return retVal;
119 }
120
125
127 {
128 bool retVal = (keySwitchState != state);
129 keySwitchState = state;
130 return retVal;
131 }
132
137
139 {
140 bool retVal = (implementStartStopOperationsState != state);
141 implementStartStopOperationsState = state;
142 return retVal;
143 }
144
149
151 {
152 bool retVal = (operatorDirectionReversedState != reverseState);
153 operatorDirectionReversedState = reverseState;
154 return retVal;
155 }
156
158 {
159 return controlFunction;
160 }
161
163 {
164 timestamp_ms = timestamp;
165 }
166
168 {
169 return timestamp_ms;
170 }
171
173 controlFunction(sender)
174 {
175 }
176
178 {
179 std::uint32_t retVal = machineSelectedSpeedDistance_mm;
180
181 // Values above the max are sort of implicitly defined and should be ignored.
182 if (machineSelectedSpeedDistance_mm > SAEds05_MAX_VALUE)
183 {
184 retVal = 0;
185 }
186 return retVal;
187 }
188
190 {
191 bool retVal = (machineSelectedSpeedDistance_mm != distance);
192 machineSelectedSpeedDistance_mm = distance;
193 return retVal;
194 }
195
197 {
198 std::uint16_t retVal = machineSelectedSpeed_mm_per_sec;
199
200 if (machineSelectedSpeed_mm_per_sec > SAEvl01_MAX_VALUE)
201 {
202 retVal = 0;
203 }
204 return retVal;
205 }
206
208 {
209 bool retVal = (speed != machineSelectedSpeed_mm_per_sec);
210 machineSelectedSpeed_mm_per_sec = speed;
211 return retVal;
212 }
213
215 {
216 return exitReasonCode;
217 }
218
220 {
221 bool retVal = (exitCode != exitReasonCode);
222 exitReasonCode = exitCode;
223 return retVal;
224 }
225
230
232 {
233 bool retVal = (source != selectedSource);
234 source = selectedSource;
235 return retVal;
236 }
237
242
244 {
245 bool retVal = (limitStatus != statusToSet);
246 limitStatus = statusToSet;
247 return retVal;
248 }
249
254
256 {
257 bool retVal = (directionOfTravel != machineDirectionState);
258 machineDirectionState = directionOfTravel;
259 return retVal;
260 }
261
263 {
264 return controlFunction;
265 }
266
268 {
269 timestamp_ms = timestamp;
270 }
271
273 {
274 return timestamp_ms;
275 }
276
278 controlFunction(sender)
279 {
280 }
281
283 {
284 std::uint32_t retVal = groundBasedMachineDistance_mm;
285
286 // Values above the max are sort of implicitly defined and should be ignored.
287 if (groundBasedMachineDistance_mm > SAEds05_MAX_VALUE)
288 {
289 retVal = 0;
290 }
291 return retVal;
292 }
293
295 {
296 bool retVal = (distance != groundBasedMachineDistance_mm);
297 groundBasedMachineDistance_mm = distance;
298 return retVal;
299 }
300
302 {
303 std::uint16_t retVal = groundBasedMachineSpeed_mm_per_sec;
304
305 if (groundBasedMachineSpeed_mm_per_sec > SAEvl01_MAX_VALUE)
306 {
307 retVal = 0;
308 }
309 return retVal;
310 }
311
313 {
314 bool retVal = (speed != groundBasedMachineSpeed_mm_per_sec);
315 groundBasedMachineSpeed_mm_per_sec = speed;
316 return retVal;
317 }
318
323
325 {
326 bool retVal = (directionOfTravel != machineDirectionState);
327 machineDirectionState = directionOfTravel;
328 return retVal;
329 }
330
332 {
333 return controlFunction;
334 }
335
337 {
338 timestamp_ms = timestamp;
339 }
340
342 {
343 return timestamp_ms;
344 }
345
347 controlFunction(sender)
348 {
349 }
350
352 {
353 std::uint16_t retVal = speedCommandedSetpoint;
354
355 // Values over the max are implicitly defined, best to treat as zeros.
356 if (speedCommandedSetpoint > SAEvl01_MAX_VALUE)
357 {
358 retVal = 0;
359 }
360 return retVal;
361 }
362
364 {
365 bool retVal = (speed != speedCommandedSetpoint);
366 speedCommandedSetpoint = speed;
367 return retVal;
368 }
369
371 {
372 std::uint16_t retVal = speedSetpointLimit;
373
374 // Values over the max are implicitly defined, best to treat as zeros.
375 if (speedSetpointLimit > SAEvl01_MAX_VALUE)
376 {
377 retVal = 0;
378 }
379 return retVal;
380 }
381
383 {
384 bool retVal = (speedSetpointLimit != speedLimit);
385 speedSetpointLimit = speedLimit;
386 return retVal;
387 }
388
393
395 {
396 bool retVal = (commandedDirection != machineDirectionCommand);
397 machineDirectionCommand = commandedDirection;
398 return retVal;
399 }
400
402 {
403 return controlFunction;
404 }
405
407 {
408 timestamp_ms = timestamp;
409 }
410
412 {
413 return timestamp_ms;
414 }
415
417 {
418 if (!initialized)
419 {
421 {
422 LOG_WARNING("[Speed/Distance]: Use extreme cation! You have configured an interface to command the speed of the machine. The machine may move without warning!");
423 }
424 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeed), process_rx_message, this);
425 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::WheelBasedSpeedAndDistance), process_rx_message, this);
426 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::GroundBasedSpeedAndDistance), process_rx_message, this);
427 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeedCommand), process_rx_message, this);
428 initialized = true;
429 }
430 }
431
433 {
434 return initialized;
435 }
436
441
446
451
456
457 std::shared_ptr<SpeedMessagesInterface::MachineSelectedSpeedData> SpeedMessagesInterface::get_received_machine_selected_speed(std::size_t index)
458 {
459 std::shared_ptr<MachineSelectedSpeedData> retVal = nullptr;
460
461 if (index < receivedMachineSelectedSpeedMessages.size())
462 {
463 retVal = receivedMachineSelectedSpeedMessages.at(index);
464 }
465 return retVal;
466 }
467
468 std::shared_ptr<SpeedMessagesInterface::WheelBasedMachineSpeedData> SpeedMessagesInterface::get_received_wheel_based_speed(std::size_t index)
469 {
470 std::shared_ptr<WheelBasedMachineSpeedData> retVal = nullptr;
471
472 if (index < receivedWheelBasedSpeedMessages.size())
473 {
474 retVal = receivedWheelBasedSpeedMessages.at(index);
475 }
476 return retVal;
477 }
478
479 std::shared_ptr<SpeedMessagesInterface::GroundBasedSpeedData> SpeedMessagesInterface::get_received_ground_based_speed(std::size_t index)
480 {
481 std::shared_ptr<GroundBasedSpeedData> retVal = nullptr;
482
483 if (index < receivedGroundBasedSpeedMessages.size())
484 {
485 retVal = receivedGroundBasedSpeedMessages.at(index);
486 }
487 return retVal;
488 }
489
490 std::shared_ptr<SpeedMessagesInterface::MachineSelectedSpeedCommandData> SpeedMessagesInterface::get_received_machine_selected_speed_command(std::size_t index)
491 {
492 std::shared_ptr<MachineSelectedSpeedCommandData> retVal = nullptr;
493
495 {
497 }
498 return retVal;
499 }
500
501 EventDispatcher<const std::shared_ptr<SpeedMessagesInterface::WheelBasedMachineSpeedData>, bool> &SpeedMessagesInterface::get_wheel_based_machine_speed_data_event_publisher()
502 {
504 }
505
506 EventDispatcher<const std::shared_ptr<SpeedMessagesInterface::MachineSelectedSpeedData>, bool> &SpeedMessagesInterface::get_machine_selected_speed_data_event_publisher()
507 {
509 }
510
511 EventDispatcher<const std::shared_ptr<SpeedMessagesInterface::GroundBasedSpeedData>, bool> &SpeedMessagesInterface::get_ground_based_machine_speed_data_event_publisher()
512 {
514 }
515
516 EventDispatcher<const std::shared_ptr<SpeedMessagesInterface::MachineSelectedSpeedCommandData>, bool> &SpeedMessagesInterface::get_machine_selected_speed_command_data_event_publisher()
517 {
519 }
520
522 {
523 if (initialized)
524 {
527 [](std::shared_ptr<MachineSelectedSpeedData> messageInfo) {
528 return SystemTiming::time_expired_ms(messageInfo->get_timestamp_ms(), SPEED_DISTANCE_MESSAGE_RX_TIMEOUT_MS);
529 }),
533 [](std::shared_ptr<WheelBasedMachineSpeedData> messageInfo) {
534 return SystemTiming::time_expired_ms(messageInfo->get_timestamp_ms(), SPEED_DISTANCE_MESSAGE_RX_TIMEOUT_MS);
535 }),
539 [](std::shared_ptr<GroundBasedSpeedData> messageInfo) {
540 return SystemTiming::time_expired_ms(messageInfo->get_timestamp_ms(), SPEED_DISTANCE_MESSAGE_RX_TIMEOUT_MS);
541 }),
545 [](std::shared_ptr<MachineSelectedSpeedCommandData> messageInfo) {
546 return SystemTiming::time_expired_ms(messageInfo->get_timestamp_ms(), SPEED_DISTANCE_MESSAGE_RX_TIMEOUT_MS);
547 }),
549
552 {
553 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::SendMachineSelectedSpeed));
554 machineSelectedSpeedTransmitTimestamp_ms = SystemTiming::get_timestamp_ms();
555 }
558 {
559 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::SendWheelBasedSpeed));
560 wheelBasedSpeedTransmitTimestamp_ms = SystemTiming::get_timestamp_ms();
561 }
564 {
565 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::SendGroundBasedSpeed));
566 groundBasedSpeedTransmitTimestamp_ms = SystemTiming::get_timestamp_ms();
567 }
570 {
571 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::SendMachineSelectedSpeedCommand));
572 machineSelectedSpeedCommandTransmitTimestamp_ms = SystemTiming::get_timestamp_ms();
573 }
574 txFlags.process_all_flags();
575 }
576 else
577 {
578 LOG_ERROR("[Speed/Distance]: ISOBUS speed messages interface has not been initialized yet.");
579 }
580 }
581
582 void SpeedMessagesInterface::process_flags(std::uint32_t flag, void *parentPointer)
583 {
584 if (nullptr != parentPointer)
585 {
586 auto targetInterface = static_cast<SpeedMessagesInterface *>(parentPointer);
587 bool transmitSuccessful = false;
588
589 switch (flag)
590 {
591 case static_cast<std::uint32_t>(TransmitFlags::SendMachineSelectedSpeed):
592 {
593 transmitSuccessful = targetInterface->send_machine_selected_speed();
594 }
595 break;
596
597 case static_cast<std::uint32_t>(TransmitFlags::SendWheelBasedSpeed):
598 {
599 transmitSuccessful = targetInterface->send_wheel_based_speed();
600 }
601 break;
602
603 case static_cast<std::uint32_t>(TransmitFlags::SendGroundBasedSpeed):
604 {
605 transmitSuccessful = targetInterface->send_ground_based_speed();
606 }
607 break;
608
609 case static_cast<std::uint32_t>(TransmitFlags::SendMachineSelectedSpeedCommand):
610 {
611 transmitSuccessful = targetInterface->send_machine_selected_speed_command();
612 }
613 break;
614
615 default:
616 break;
617 }
618
619 if (false == transmitSuccessful)
620 {
621 targetInterface->txFlags.set_flag(flag);
622 }
623 }
624 }
625
626 void SpeedMessagesInterface::process_rx_message(const CANMessage &message, void *parentPointer)
627 {
628 assert(nullptr != parentPointer);
629 auto targetInterface = static_cast<SpeedMessagesInterface *>(parentPointer);
630
631 switch (message.get_identifier().get_parameter_group_number())
632 {
633 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeed):
634 {
635 if (CAN_DATA_LENGTH == message.get_data_length())
636 {
637 if (nullptr != message.get_source_control_function())
638 {
639 auto result = std::find_if(targetInterface->receivedMachineSelectedSpeedMessages.cbegin(),
640 targetInterface->receivedMachineSelectedSpeedMessages.cend(),
641 [&message](const std::shared_ptr<MachineSelectedSpeedData> &receivedInfo) {
642 return (nullptr != receivedInfo) && (receivedInfo->get_sender_control_function() == message.get_source_control_function());
643 });
644
645 if (result == targetInterface->receivedMachineSelectedSpeedMessages.end())
646 {
647 // There is no existing message object from this control function, so create a new one
648 targetInterface->receivedMachineSelectedSpeedMessages.push_back(std::make_shared<MachineSelectedSpeedData>(message.get_source_control_function()));
649 result = targetInterface->receivedMachineSelectedSpeedMessages.end() - 1;
650 }
651
652 auto &mssMessage = *result;
653 bool changed = false;
654
655 changed |= mssMessage->set_machine_speed(message.get_uint16_at(0));
656 changed |= mssMessage->set_machine_distance(message.get_uint32_at(2));
657 changed |= mssMessage->set_exit_reason_code(message.get_uint8_at(6) & 0x3F);
658 changed |= mssMessage->set_machine_direction_of_travel(static_cast<MachineDirection>(message.get_uint8_at(7) & 0x03));
659 changed |= mssMessage->set_speed_source(static_cast<MachineSelectedSpeedData::SpeedSource>((message.get_uint8_at(7) >> 2) & 0x07));
660 changed |= mssMessage->set_limit_status(static_cast<MachineSelectedSpeedData::LimitStatus>((message.get_uint8_at(7) >> 5) & 0x03));
661 mssMessage->set_timestamp_ms(SystemTiming::get_timestamp_ms());
662
663 targetInterface->machineSelectedSpeedDataEventPublisher.call(mssMessage, changed);
664 }
665 }
666 else
667 {
668 LOG_ERROR("[Speed/Distance]: Received a malformed machine selected speed. DLC must be 8.");
669 }
670 }
671 break;
672
673 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::WheelBasedSpeedAndDistance):
674 {
675 if (CAN_DATA_LENGTH == message.get_data_length())
676 {
677 if (nullptr != message.get_source_control_function())
678 {
679 auto result = std::find_if(targetInterface->receivedWheelBasedSpeedMessages.cbegin(),
680 targetInterface->receivedWheelBasedSpeedMessages.cend(),
681 [&message](const std::shared_ptr<WheelBasedMachineSpeedData> &receivedInfo) {
682 return (nullptr != receivedInfo) && (receivedInfo->get_sender_control_function() == message.get_source_control_function());
683 });
684
685 if (result == targetInterface->receivedWheelBasedSpeedMessages.end())
686 {
687 // There is no existing message object from this control function, so create a new one
688 targetInterface->receivedWheelBasedSpeedMessages.push_back(std::make_shared<WheelBasedMachineSpeedData>(message.get_source_control_function()));
689 result = targetInterface->receivedWheelBasedSpeedMessages.end() - 1;
690 }
691
692 auto &wheelSpeedMessage = *result;
693 bool changed = false;
694
695 changed |= wheelSpeedMessage->set_machine_speed(message.get_uint16_at(0));
696 changed |= wheelSpeedMessage->set_machine_distance(message.get_uint32_at(2));
697 changed |= wheelSpeedMessage->set_maximum_time_of_tractor_power(message.get_uint8_at(6));
698 changed |= wheelSpeedMessage->set_machine_direction_of_travel(static_cast<MachineDirection>(message.get_uint8_at(7) & 0x03));
699 changed |= wheelSpeedMessage->set_key_switch_state(static_cast<WheelBasedMachineSpeedData::KeySwitchState>((message.get_uint8_at(7) >> 2) & 0x03));
700 changed |= wheelSpeedMessage->set_implement_start_stop_operations_state(static_cast<WheelBasedMachineSpeedData::ImplementStartStopOperations>((message.get_uint8_at(7) >> 4) & 0x03));
701 changed |= wheelSpeedMessage->set_operator_direction_reversed_state(static_cast<WheelBasedMachineSpeedData::OperatorDirectionReversed>((message.get_uint8_at(7) >> 6) & 0x03));
702 wheelSpeedMessage->set_timestamp_ms(SystemTiming::get_timestamp_ms());
703
704 targetInterface->wheelBasedMachineSpeedDataEventPublisher.call(wheelSpeedMessage, changed);
705 }
706 }
707 else
708 {
709 LOG_ERROR("[Speed/Distance]: Received a malformed wheel-based speed and distance message. DLC must be 8.");
710 }
711 }
712 break;
713
714 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::GroundBasedSpeedAndDistance):
715 {
716 if (CAN_DATA_LENGTH == message.get_data_length())
717 {
718 if (nullptr != message.get_source_control_function())
719 {
720 auto result = std::find_if(targetInterface->receivedGroundBasedSpeedMessages.cbegin(),
721 targetInterface->receivedGroundBasedSpeedMessages.cend(),
722 [&message](const std::shared_ptr<GroundBasedSpeedData> &receivedInfo) {
723 return (nullptr != receivedInfo) && (receivedInfo->get_sender_control_function() == message.get_source_control_function());
724 });
725
726 if (result == targetInterface->receivedGroundBasedSpeedMessages.end())
727 {
728 // There is no existing message object from this control function, so create a new one
729 targetInterface->receivedGroundBasedSpeedMessages.push_back(std::make_shared<GroundBasedSpeedData>(message.get_source_control_function()));
730 result = targetInterface->receivedGroundBasedSpeedMessages.end() - 1;
731 }
732
733 auto &groundSpeedMessage = *result;
734 bool changed = false;
735
736 changed |= groundSpeedMessage->set_machine_speed(message.get_uint16_at(0));
737 changed |= groundSpeedMessage->set_machine_distance(message.get_uint32_at(2));
738 changed |= groundSpeedMessage->set_machine_direction_of_travel(static_cast<MachineDirection>(message.get_uint8_at(7) & 0x03));
739 groundSpeedMessage->set_timestamp_ms(SystemTiming::get_timestamp_ms());
740
741 targetInterface->groundBasedSpeedDataEventPublisher.call(groundSpeedMessage, changed);
742 }
743 }
744 else
745 {
746 LOG_ERROR("[Speed/Distance]: Received a malformed ground-based speed and distance message. DLC must be 8.");
747 }
748 }
749 break;
750
751 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeedCommand):
752 {
753 if (CAN_DATA_LENGTH == message.get_data_length())
754 {
755 if (nullptr != message.get_source_control_function())
756 {
757 auto result = std::find_if(targetInterface->receivedMachineSelectedSpeedCommandMessages.cbegin(),
758 targetInterface->receivedMachineSelectedSpeedCommandMessages.cend(),
759 [&message](const std::shared_ptr<MachineSelectedSpeedCommandData> &receivedInfo) {
760 return (nullptr != receivedInfo) && (receivedInfo->get_sender_control_function() == message.get_source_control_function());
761 });
762
763 if (result == targetInterface->receivedMachineSelectedSpeedCommandMessages.end())
764 {
765 // There is no existing message object from this control function, so create a new one
766 targetInterface->receivedMachineSelectedSpeedCommandMessages.push_back(std::make_shared<MachineSelectedSpeedCommandData>(message.get_source_control_function()));
767 result = targetInterface->receivedMachineSelectedSpeedCommandMessages.end() - 1;
768 }
769
770 auto &commandMessage = *result;
771 bool changed = false;
772
773 commandMessage->set_machine_speed_setpoint_command(message.get_uint16_at(0));
774 commandMessage->set_machine_selected_speed_setpoint_limit(message.get_uint16_at(2));
775 commandMessage->set_machine_direction_of_travel(static_cast<MachineDirection>(message.get_uint8_at(7) & 0x03));
776 commandMessage->set_timestamp_ms(SystemTiming::get_timestamp_ms());
777
778 targetInterface->machineSelectedSpeedCommandDataEventPublisher.call(commandMessage, changed);
779 }
780 }
781 else
782 {
783 LOG_ERROR("[Speed/Distance]: Received a malformed machine selected speed command message. DLC must be 8.");
784 }
785 }
786 break;
787
788 default:
789 break;
790 }
791 }
792
794 {
795 bool retVal = false;
796
798 {
799 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer = { static_cast<std::uint8_t>(machineSelectedSpeedTransmitData.get_machine_speed() & 0xFF),
800 static_cast<std::uint8_t>((machineSelectedSpeedTransmitData.get_machine_speed() >> 8) & 0xFF),
801 static_cast<std::uint8_t>(machineSelectedSpeedTransmitData.get_machine_distance() & 0xFF),
802 static_cast<std::uint8_t>((machineSelectedSpeedTransmitData.get_machine_distance() >> 8) & 0xFF),
803 static_cast<std::uint8_t>((machineSelectedSpeedTransmitData.get_machine_distance() >> 16) & 0xFF),
804 static_cast<std::uint8_t>((machineSelectedSpeedTransmitData.get_machine_distance() >> 24) & 0xFF),
805 static_cast<std::uint8_t>(0xC0 | static_cast<std::uint8_t>(machineSelectedSpeedTransmitData.get_exit_reason_code() & 0x7F)), // 0xC0 sets reserved bits to 1s
806 static_cast<std::uint8_t>(static_cast<std::uint8_t>(machineSelectedSpeedTransmitData.get_machine_direction_of_travel()) |
807 (static_cast<std::uint8_t>(machineSelectedSpeedTransmitData.get_speed_source()) << 2) |
808 (static_cast<std::uint8_t>(machineSelectedSpeedTransmitData.get_limit_status()) << 5))
809
810 };
811 retVal = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeed),
812 buffer.data(),
813 buffer.size(),
814 std::static_pointer_cast<InternalControlFunction>(machineSelectedSpeedTransmitData.get_sender_control_function()),
815 nullptr,
817 }
818 return retVal;
819 }
820
822 {
823 bool retVal = false;
824
826 {
827 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer = { static_cast<std::uint8_t>(wheelBasedSpeedTransmitData.get_machine_speed() & 0xFF),
828 static_cast<std::uint8_t>((wheelBasedSpeedTransmitData.get_machine_speed() >> 8) & 0xFF),
829 static_cast<std::uint8_t>(wheelBasedSpeedTransmitData.get_machine_distance() & 0xFF),
830 static_cast<std::uint8_t>((wheelBasedSpeedTransmitData.get_machine_distance() >> 8) & 0xFF),
831 static_cast<std::uint8_t>((wheelBasedSpeedTransmitData.get_machine_distance() >> 16) & 0xFF),
832 static_cast<std::uint8_t>((wheelBasedSpeedTransmitData.get_machine_distance() >> 24) & 0xFF),
834 static_cast<std::uint8_t>(static_cast<std::uint8_t>(wheelBasedSpeedTransmitData.get_machine_direction_of_travel()) |
835 (static_cast<std::uint8_t>(wheelBasedSpeedTransmitData.get_key_switch_state()) << 2) |
837 (static_cast<std::uint8_t>(wheelBasedSpeedTransmitData.get_operator_direction_reversed_state()) << 6)) };
838 retVal = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::WheelBasedSpeedAndDistance),
839 buffer.data(),
840 buffer.size(),
841 std::static_pointer_cast<InternalControlFunction>(wheelBasedSpeedTransmitData.get_sender_control_function()),
842 nullptr,
844 }
845 return retVal;
846 }
847
849 {
850 bool retVal = false;
851
853 {
854 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer = { static_cast<std::uint8_t>(groundBasedSpeedTransmitData.get_machine_speed() & 0xFF),
855 static_cast<std::uint8_t>((groundBasedSpeedTransmitData.get_machine_speed() >> 8) & 0xFF),
856 static_cast<std::uint8_t>(groundBasedSpeedTransmitData.get_machine_distance() & 0xFF),
857 static_cast<std::uint8_t>((groundBasedSpeedTransmitData.get_machine_distance() >> 8) & 0xFF),
858 static_cast<std::uint8_t>((groundBasedSpeedTransmitData.get_machine_distance() >> 16) & 0xFF),
859 static_cast<std::uint8_t>((groundBasedSpeedTransmitData.get_machine_distance() >> 24) & 0xFF),
860 0xFF, // Reserved
861 static_cast<std::uint8_t>(0xFC | static_cast<std::uint8_t>(groundBasedSpeedTransmitData.get_machine_direction_of_travel())) }; // 0xFC sets reserved bits to 1s
862 retVal = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::GroundBasedSpeedAndDistance),
863 buffer.data(),
864 buffer.size(),
865 std::static_pointer_cast<InternalControlFunction>(groundBasedSpeedTransmitData.get_sender_control_function()),
866 nullptr,
868 }
869 return retVal;
870 }
871
873 {
874 bool retVal = false;
875
877 {
878 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer = { static_cast<std::uint8_t>(machineSelectedSpeedCommandTransmitData.get_machine_speed_setpoint_command() & 0xFF),
879 static_cast<std::uint8_t>((machineSelectedSpeedCommandTransmitData.get_machine_speed_setpoint_command() >> 8) & 0xFF),
882 0xFF,
883 0xFF,
884 0xFF,
885 static_cast<std::uint8_t>(0xFC | static_cast<std::uint8_t>(machineSelectedSpeedCommandTransmitData.get_machine_direction_command())) };
886 retVal = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::MachineSelectedSpeedCommand),
887 buffer.data(),
888 buffer.size(),
889 std::static_pointer_cast<InternalControlFunction>(machineSelectedSpeedCommandTransmitData.get_sender_control_function()),
890 nullptr,
892 }
893 return retVal;
894 }
895
896} // namespace isobus
Defines some PGNs that are used in the library or are very common.
The main class that manages the ISOBUS stack including: callbacks, Name to Address management,...
A class that acts as a logging sink. The intent is that someone could make their own derived class of...
@ Priority3
Priority highest - 3 (Control messages priority)
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.
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.
std::uint8_t get_uint8_at(const std::uint32_t index) const
Get a 8-bit unsigned byte from the buffer at a specific index. A 8-bit unsigned byte can hold a value...
std::uint16_t get_uint16_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 16-bit unsigned integer from the buffer at a specific index. A 16-bit unsigned integer can hold...
CANIdentifier get_identifier() const
Returns the identifier of the message.
std::uint32_t get_uint32_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a 32-bit unsigned integer from the buffer at a specific index. A 32-bit unsigned integer can hold...
static CANNetworkManager CANNetwork
Static singleton of the one network manager. Use this to access stack functionality.
void add_any_control_function_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parent)
Registers a callback for ANY control function sending the associated PGN.
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.
void remove_any_control_function_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parent)
This is how you remove a callback added with add_any_control_function_parameter_group_number_callback...
Message normally sent by the Tractor ECU on the implement bus on construction and agricultural implem...
MachineDirection get_machine_direction_of_travel() const
Returns A measured signal indicating either forward or reverse as the direction of travel.
GroundBasedSpeedData(std::shared_ptr< ControlFunction > sender)
Constructor for a GroundBasedSpeedData.
std::uint32_t get_timestamp_ms() const
Returns the timestamp for when the message was received, in milliseconds.
bool set_machine_distance(std::uint32_t distance)
Sets the actual distance traveled by a machine, based on measurements from a sensor such as that is n...
std::shared_ptr< ControlFunction > get_sender_control_function() const
Returns a pointer to the sender of the message. If an ICF is the sender, returns the ICF being used t...
bool set_machine_speed(std::uint16_t speed)
Sets the actual ground speed of a machine, measured by a sensor such as that is not susceptible to wh...
bool set_machine_direction_of_travel(MachineDirection directionOfTravel)
Sets a measured signal indicating either forward or reverse as the direction of travel.
void set_timestamp_ms(std::uint32_t timestamp)
Sets the timestamp for when the message was received or sent.
std::uint32_t get_machine_distance() const
Actual distance traveled by a machine, based on measurements from a sensor such as that is not suscep...
std::uint16_t get_machine_speed() const
Returns the actual ground speed of a machine, measured by a sensor such as that is not susceptible to...
Message that provides the control of the machine speed and direction. If you receive this message,...
MachineDirection get_machine_direction_command() const
Returns The commanded direction of the machine.
bool set_machine_selected_speed_setpoint_limit(std::uint16_t speedLimit)
Sets the maximum allowed machine speed in mm/s, which gets communicated to the tractor/machine.
bool set_machine_direction_of_travel(MachineDirection commandedDirection)
Sets the commanded direction of the machine.
void set_timestamp_ms(std::uint32_t timestamp)
Sets the timestamp for when the message was received or sent.
std::shared_ptr< ControlFunction > get_sender_control_function() const
Returns a pointer to the sender of the message. If an ICF is the sender, returns the ICF being used t...
std::uint16_t get_machine_speed_setpoint_command() const
Returns the commanded setpoint value of the machine speed as measured by the selected source in mm/s.
bool set_machine_speed_setpoint_command(std::uint16_t speed)
Sets The commanded setpoint value of the machine speed as measured by the selected source in mm/s.
std::uint32_t get_timestamp_ms() const
Returns the timestamp for when the message was received, in milliseconds.
std::uint16_t get_machine_selected_speed_setpoint_limit() const
Returns the machine's maximum allowed speed in mm/s, which get's communicated to the tractor/machine.
MachineSelectedSpeedCommandData(std::shared_ptr< ControlFunction > sender)
Constructor for a MachineSelectedSpeedCommandData.
Message that provides the current machine selected speed, direction and source parameters.
void set_timestamp_ms(std::uint32_t timestamp)
Sets the timestamp for when the message was received or sent.
std::uint32_t get_timestamp_ms() const
Returns the timestamp for when the message was received, in milliseconds.
bool set_machine_direction_of_travel(MachineDirection directionOfTravel)
Sets a measured signal indicating either forward or reverse as the direction of travel.
std::uint32_t get_machine_distance() const
Returns the Actual distance travelled by the machine based on the value of selected machine speed (SP...
MachineSelectedSpeedData(std::shared_ptr< ControlFunction > sender)
Constructor for a MachineSelectedSpeedData.
std::uint16_t get_machine_speed() const
Returns the current machine selected speed.
bool set_exit_reason_code(std::uint8_t exitCode)
Sets the reason why the vehicle speed control unit cannot currently accept remote commands or has mos...
std::uint8_t get_exit_reason_code() const
Returns the reason why the vehicle speed control unit cannot currently accept remote commands or has ...
SpeedSource get_speed_source() const
Returns the speed source that is currently being reported in the machine selected speed parameter (SP...
bool set_machine_distance(std::uint32_t distance)
Sets the Actual distance travelled by the machine based on the value of selected machine speed (SPN 4...
SpeedSource
An indication of the speed source that is currently being reported in the machine selected speed para...
bool set_machine_speed(std::uint16_t speed)
Sets the machine selected speed.
bool set_limit_status(LimitStatus statusToSet)
Sets the Tractor ECU's present limit status associated with a parameter whose commands are persistent...
std::shared_ptr< ControlFunction > get_sender_control_function() const
Returns a pointer to the sender of the message. If an ICF is the sender, returns the ICF being used t...
MachineDirection get_machine_direction_of_travel() const
Returns A measured signal indicating either forward or reverse as the direction of travel.
LimitStatus get_limit_status() const
Returns The Tractor ECU's present limit status associated with a parameter whose commands are persist...
LimitStatus
This parameter is used to report the Tractor ECU's present limit status associated with a parameter w...
bool set_speed_source(SpeedSource selectedSource)
Sets the speed source that is currently being reported in the machine selected speed parameter (SPN-4...
Groups the data encoded in an ISO "Wheel-based Speed and Distance" message.
ImplementStartStopOperations
Enumerates the states of a switch or operator input to start or enable implement operations.
KeySwitchState
Enumerates the key switch states of the tractor or power unit.
KeySwitchState get_key_switch_state() const
Returns the key switch state of the tractor or power unit.
bool set_machine_direction_of_travel(MachineDirection direction)
Sets a measured signal indicating either forward or reverse as the direction of travel.
OperatorDirectionReversed
This parameter indicates whether the reported direction is reversed from the perspective of the opera...
WheelBasedMachineSpeedData(std::shared_ptr< ControlFunction > sender)
Constructor for a WheelBasedMachineSpeedData.
std::uint16_t get_machine_speed() const
Returns the value of the speed of a machine as calculated from the measured wheel or tail-shaft speed...
void set_timestamp_ms(std::uint32_t timestamp)
Sets the timestamp for when the message was received or sent.
bool set_machine_speed(std::uint16_t speed)
Sets the value of the speed of a machine as calculated from the measured wheel or tail-shaft speed.
std::uint32_t get_machine_distance() const
Returns The distance traveled by a machine as calculated from wheel or tail-shaft speed.
OperatorDirectionReversed get_operator_direction_reversed_state() const
Returns whether the reported direction is reversed from the perspective of the operator.
std::uint32_t get_timestamp_ms() const
Returns the timestamp for when the message was received, in milliseconds.
std::uint8_t get_maximum_time_of_tractor_power() const
Returns the maximum time (in minutes) of remaining tractor or power-unit-supplied electrical power at...
bool set_implement_start_stop_operations_state(ImplementStartStopOperations state)
Sets the state of a switch or other operator input to start or enable implement operations.
ImplementStartStopOperations get_implement_start_stop_operations_state() const
Returns the state of a switch or other operator input to start or enable implement operations.
bool set_key_switch_state(KeySwitchState state)
Sets the reported key switch state of the tractor or power unit.
bool set_machine_distance(std::uint32_t distance)
Sets the distance traveled by a machine as calculated from wheel or tail-shaft speed.
std::shared_ptr< ControlFunction > get_sender_control_function() const
Returns a pointer to the sender of the message. If an ICF is the sender, returns the ICF being used t...
bool set_operator_direction_reversed_state(OperatorDirectionReversed reverseState)
Sets whether the reported direction is reversed from the perspective of the operator.
bool set_maximum_time_of_tractor_power(std::uint8_t maxTime)
Sets the maximum time (in minutes) of remaining tractor or power-unit-supplied electrical power at th...
MachineDirection get_machine_direction_of_travel() const
Returns A measured signal indicating either forward or reverse as the direction of travel.
This interface manages and parses ISOBUS speed messages.
WheelBasedMachineSpeedData wheelBasedSpeedTransmitData
Use this to configure transmission of the wheel-based speed message. If you pass in an internal contr...
EventDispatcher< const std::shared_ptr< GroundBasedSpeedData >, bool > & get_ground_based_machine_speed_data_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated ground-based speed me...
~SpeedMessagesInterface()
Destructor for SpeedMessagesInterface. Cleans up PGN registrations if needed.
ProcessingFlags txFlags
Tx flag for sending messages periodically.
static constexpr std::uint16_t SAEvl01_MAX_VALUE
The maximum valid value for a SAEvl01 slot (see J1939)
bool send_machine_selected_speed_command() const
Sends the machine selected speed command message.
std::uint32_t machineSelectedSpeedTransmitTimestamp_ms
Timestamp used to know when to transmit the machine selected speed message in milliseconds.
MachineSelectedSpeedCommandData machineSelectedSpeedCommandTransmitData
Use this to configure transmission of the machine selected speed command message. If you pass in an i...
std::shared_ptr< GroundBasedSpeedData > get_received_ground_based_speed(std::size_t index)
Returns the content of the ground-based speed message based on the index of the sender....
EventDispatcher< const std::shared_ptr< WheelBasedMachineSpeedData >, bool > & get_wheel_based_machine_speed_data_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated wheel-based speed mes...
std::vector< std::shared_ptr< MachineSelectedSpeedCommandData > > receivedMachineSelectedSpeedCommandMessages
A list of all received ground-based speed messages.
bool send_machine_selected_speed() const
Sends the machine selected speed message.
bool send_ground_based_speed() const
Sends the ground-based speed message.
bool get_initialized() const
Returns if the interface has been initialized.
std::uint32_t groundBasedSpeedTransmitTimestamp_ms
Timestamp used to know when to transmit the ground-based speed message in milliseconds.
std::shared_ptr< MachineSelectedSpeedData > get_received_machine_selected_speed(std::size_t index)
Returns the content of the machine selected speed message based on the index of the sender....
static void process_rx_message(const CANMessage &message, void *parentPointer)
Processes a CAN message.
EventDispatcher< const std::shared_ptr< MachineSelectedSpeedCommandData >, bool > machineSelectedSpeedCommandDataEventPublisher
An event publisher for notifying when new machine selected speed command messages are received.
std::uint32_t wheelBasedSpeedTransmitTimestamp_ms
Timestamp used to know when to transmit the wheel-based speed message in milliseconds.
static constexpr std::uint32_t SAEds05_MAX_VALUE
The maximum valid value for a SAEds05 slot (see J1939)
std::vector< std::shared_ptr< WheelBasedMachineSpeedData > > receivedWheelBasedSpeedMessages
A list of all received wheel-based speed messages.
std::vector< std::shared_ptr< GroundBasedSpeedData > > receivedGroundBasedSpeedMessages
A list of all received ground-based speed messages.
SpeedMessagesInterface(std::shared_ptr< InternalControlFunction > source, bool enableSendingGroundBasedSpeedPeriodically=false, bool enableSendingWheelBasedSpeedPeriodically=false, bool enableSendingMachineSelectedSpeedPeriodically=false, bool enableSendingMachineSelectedSpeedCommandPeriodically=false)
Constructor for a SpeedMessagesInterface.
bool initialized
Stores if the interface has been initialized.
bool send_wheel_based_speed() const
Sends the wheel-based speed message.
EventDispatcher< const std::shared_ptr< MachineSelectedSpeedData >, bool > machineSelectedSpeedDataEventPublisher
An event publisher for notifying when new machine selected speed messages are received.
EventDispatcher< const std::shared_ptr< WheelBasedMachineSpeedData >, bool > wheelBasedMachineSpeedDataEventPublisher
An event publisher for notifying when new wheel-based speed messages are received.
TransmitFlags
Enumerates a set of flags to manage transmitting messages owned by this interface.
@ SendWheelBasedSpeed
A flag to manage sending wheel-based speed.
@ SendGroundBasedSpeed
A flag to manage sending ground-based speed.
@ SendMachineSelectedSpeed
A flag to manage sending machine selected speed.
@ SendMachineSelectedSpeedCommand
A flag to manage sending the machine selected speed command message.
EventDispatcher< const std::shared_ptr< MachineSelectedSpeedCommandData >, bool > & get_machine_selected_speed_command_data_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated machine selected spee...
static void process_flags(std::uint32_t flag, void *parentPointer)
Processes one flag (which sends the associated message)
EventDispatcher< const std::shared_ptr< MachineSelectedSpeedData >, bool > & get_machine_selected_speed_data_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated machine selected spee...
GroundBasedSpeedData groundBasedSpeedTransmitData
Use this to configure transmission of the ground-based speed message. If you pass in an internal cont...
std::size_t get_number_received_wheel_based_speed_sources() const
Returns the number of received, unique wheel-based speed message sources.
static constexpr std::uint32_t SPEED_DISTANCE_MESSAGE_TX_INTERVAL_MS
The interval (in milliseconds) defined in ISO11783-7 for sending this class's messages.
std::shared_ptr< MachineSelectedSpeedCommandData > get_received_machine_selected_speed_command(std::size_t index)
Returns the content of the machine selected speed command message based on the index of the sender....
MachineSelectedSpeedData machineSelectedSpeedTransmitData
Use this to configure transmission of the machine selected speed message. If you pass in an internal ...
std::vector< std::shared_ptr< MachineSelectedSpeedData > > receivedMachineSelectedSpeedMessages
A list of all received machine selected speed messages.
std::uint32_t machineSelectedSpeedCommandTransmitTimestamp_ms
Timestamp used to know when to transmit the ground-based speed message in milliseconds.
EventDispatcher< const std::shared_ptr< GroundBasedSpeedData >, bool > groundBasedSpeedDataEventPublisher
An event publisher for notifying when new ground-based speed messages are received.
std::size_t get_number_received_machine_selected_speed_command_sources() const
Returns the number of received, unique machine selected speed command message sources.
std::shared_ptr< WheelBasedMachineSpeedData > get_received_wheel_based_speed(std::size_t index)
Returns the content of the wheel-based speed message based on the index of the sender....
void initialize()
Sets up the class and registers it to receive callbacks from the network manager for processing guida...
void update()
Call this cyclically to update the interface. Transmits messages if needed and processes timeouts for...
std::size_t get_number_received_ground_based_speed_sources() const
Returns the number of received, unique ground-based speed message sources.
std::size_t get_number_received_machine_selected_speed_sources() const
Returns the number of received, unique machine selected speed message sources.
MachineDirection
Enumerates the values of the direction of travel for the machine.
Defines classes for processing/sending ISOBUS speed messages.
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.