AgIsoStack++
A control-function-focused implementation of the major ISOBUS and J1939 protocols
Loading...
Searching...
No Matches
nmea2000_message_interface.cpp
Go to the documentation of this file.
1//================================================================================================
18//================================================================================================
24#include "isobus/utility/system_timing.hpp"
25
26#include <algorithm>
27
28namespace isobus
29{
30 using namespace NMEA2000Messages;
31
32 NMEA2000MessageInterface::NMEA2000MessageInterface(std::shared_ptr<InternalControlFunction> sendingControlFunction,
33 bool enableSendingCogSogCyclically,
34 bool enableSendingDatumCyclically,
35 bool enableSendingGNSSPositionDataCyclically,
36 bool enableSendingPositionDeltaHighPrecisionRapidUpdateCyclically,
37 bool enableSendingPositionRapidUpdateCyclically,
38 bool enableSendingRateOfTurnCyclically,
39 bool enableSendingVesselHeadingCyclically) :
40 txFlags(static_cast<std::uint32_t>(TransmitFlags::NumberOfFlags), process_flags, this),
41 cogSogTransmitMessage(sendingControlFunction),
42 datumTransmitMessage(sendingControlFunction),
43 gnssPositionDataTransmitMessage(sendingControlFunction),
44 positionDeltaHighPrecisionRapidUpdateTransmitMessage(sendingControlFunction),
45 positionRapidUpdateTransmitMessage(sendingControlFunction),
46 rateOfTurnTransmitMessage(sendingControlFunction),
47 vesselHeadingTransmitMessage(sendingControlFunction),
48 sendCogSogCyclically(enableSendingCogSogCyclically),
49 sendDatumCyclically(enableSendingDatumCyclically),
50 sendGNSSPositionDataCyclically(enableSendingGNSSPositionDataCyclically),
51 sendPositionDeltaHighPrecisionRapidUpdateCyclically(enableSendingPositionDeltaHighPrecisionRapidUpdateCyclically),
52 sendPositionRapidUpdateCyclically(enableSendingPositionRapidUpdateCyclically),
53 sendRateOfTurnCyclically(enableSendingRateOfTurnCyclically),
54 sendVesselHeadingCyclically(enableSendingVesselHeadingCyclically)
55 {
56 }
57
62
67
72
77
82
87
92
97
102
107
112
117
122
127
132
133 std::shared_ptr<CourseOverGroundSpeedOverGroundRapidUpdate> NMEA2000MessageInterface::get_received_course_speed_over_ground_message(std::size_t index) const
134 {
135 std::shared_ptr<CourseOverGroundSpeedOverGroundRapidUpdate> retVal = nullptr;
136
137 if (index < receivedCogSogMessages.size())
138 {
139 retVal = receivedCogSogMessages.at(index);
140 }
141 return retVal;
142 }
143
144 std::shared_ptr<Datum> NMEA2000MessageInterface::get_received_datum_message(std::size_t index) const
145 {
146 std::shared_ptr<Datum> retVal = nullptr;
147
148 if (index < receivedDatumMessages.size())
149 {
150 retVal = receivedDatumMessages.at(index);
151 }
152 return retVal;
153 }
154
155 std::shared_ptr<GNSSPositionData> NMEA2000MessageInterface::get_received_gnss_position_data_message(std::size_t index) const
156 {
157 std::shared_ptr<GNSSPositionData> retVal = nullptr;
158
159 if (index < receivedGNSSPositionDataMessages.size())
160 {
161 retVal = receivedGNSSPositionDataMessages.at(index);
162 }
163 return retVal;
164 }
165
166 std::shared_ptr<PositionDeltaHighPrecisionRapidUpdate> NMEA2000MessageInterface::get_received_position_delta_high_precision_rapid_update_message(std::size_t index) const
167 {
168 std::shared_ptr<PositionDeltaHighPrecisionRapidUpdate> retVal = nullptr;
169
171 {
173 }
174 return retVal;
175 }
176
177 std::shared_ptr<PositionRapidUpdate> NMEA2000MessageInterface::get_received_position_rapid_update_message(std::size_t index) const
178 {
179 std::shared_ptr<PositionRapidUpdate> retVal = nullptr;
180
181 if (index < receivedPositionRapidUpdateMessages.size())
182 {
183 retVal = receivedPositionRapidUpdateMessages.at(index);
184 }
185 return retVal;
186 }
187
188 std::shared_ptr<RateOfTurn> NMEA2000MessageInterface::get_received_rate_of_turn_message(std::size_t index) const
189 {
190 std::shared_ptr<RateOfTurn> retVal = nullptr;
191
192 if (index < receivedRateOfTurnMessages.size())
193 {
194 retVal = receivedRateOfTurnMessages.at(index);
195 }
196 return retVal;
197 }
198
199 std::shared_ptr<VesselHeading> NMEA2000MessageInterface::get_received_vessel_heading_message(std::size_t index) const
200 {
201 std::shared_ptr<VesselHeading> retVal = nullptr;
202
203 if (index < receivedVesselHeadingMessages.size())
204 {
205 retVal = receivedVesselHeadingMessages.at(index);
206 }
207 return retVal;
208 }
209
210 EventDispatcher<const std::shared_ptr<NMEA2000Messages::CourseOverGroundSpeedOverGroundRapidUpdate>, bool> &NMEA2000MessageInterface::get_course_speed_over_ground_rapid_update_event_publisher()
211 {
213 }
214
215 EventDispatcher<const std::shared_ptr<NMEA2000Messages::Datum>, bool> &NMEA2000MessageInterface::get_datum_event_publisher()
216 {
217 return datumEventPublisher;
218 }
219
220 EventDispatcher<const std::shared_ptr<NMEA2000Messages::GNSSPositionData>, bool> &NMEA2000MessageInterface::get_gnss_position_data_event_publisher()
221 {
223 }
224
225 EventDispatcher<const std::shared_ptr<NMEA2000Messages::PositionDeltaHighPrecisionRapidUpdate>, bool> &NMEA2000MessageInterface::get_position_delta_high_precision_rapid_update_event_publisher()
226 {
228 }
229
230 EventDispatcher<const std::shared_ptr<NMEA2000Messages::PositionRapidUpdate>, bool> &NMEA2000MessageInterface::get_position_rapid_update_event_publisher()
231 {
233 }
234
235 EventDispatcher<const std::shared_ptr<NMEA2000Messages::RateOfTurn>, bool> &NMEA2000MessageInterface::get_rate_of_turn_event_publisher()
236 {
238 }
239
240 EventDispatcher<const std::shared_ptr<NMEA2000Messages::VesselHeading>, bool> &NMEA2000MessageInterface::get_vessel_heading_event_publisher()
241 {
243 }
244
249
254
259
264
269
274
279
284
289
294
299
304
309
314
316 {
317 if (!initialized)
318 {
319 const auto &fastPacketProtocol = CANNetworkManager::CANNetwork.get_fast_packet_protocol(0); // TODO: This should be a configurable can index (will be solved with the new CAN network manager)
320 fastPacketProtocol->register_multipacket_message_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::Datum), process_rx_message, this);
321 fastPacketProtocol->register_multipacket_message_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::GNSSPositionData), process_rx_message, this);
322 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::CourseOverGroundSpeedOverGroundRapidUpdate), process_rx_message, this);
323 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionDeltaHighPrecisionRapidUpdate), process_rx_message, this);
324 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionRapidUpdate), process_rx_message, this);
325 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::RateOfTurn), process_rx_message, this);
326 CANNetworkManager::CANNetwork.add_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::VesselHeading), process_rx_message, this);
327 initialized = true;
328 }
329 }
330
332 {
333 return initialized;
334 }
335
337 {
338 if (initialized)
339 {
340 const auto &fastPacketProtocol = CANNetworkManager::CANNetwork.get_fast_packet_protocol(0); // TODO: This should be a configurable can index (will be solved with the new CAN network manager)
341 fastPacketProtocol->remove_multipacket_message_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::Datum), process_rx_message, this);
342 fastPacketProtocol->remove_multipacket_message_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::GNSSPositionData), process_rx_message, this);
343 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::CourseOverGroundSpeedOverGroundRapidUpdate), process_rx_message, this);
344 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionDeltaHighPrecisionRapidUpdate), process_rx_message, this);
345 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionRapidUpdate), process_rx_message, this);
346 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::RateOfTurn), process_rx_message, this);
347 CANNetworkManager::CANNetwork.remove_any_control_function_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::VesselHeading), process_rx_message, this);
348 initialized = false;
349 }
350 }
351
353 {
354 if (initialized)
355 {
357 txFlags.process_all_flags();
359 }
360 else
361 {
362 LOG_ERROR("[NMEA2K]: Interface not initialized!");
363 }
364 }
365
366 void NMEA2000MessageInterface::process_flags(std::uint32_t flag, void *parentPointer)
367 {
368 if ((nullptr != parentPointer) &&
369 (flag < static_cast<std::uint32_t>(TransmitFlags::NumberOfFlags)))
370 {
371 auto targetInterface = static_cast<NMEA2000MessageInterface *>(parentPointer);
372 std::vector<std::uint8_t> messageBuffer;
373 bool transmitSuccessful = true;
374
375 switch (static_cast<TransmitFlags>(flag))
376 {
377 case TransmitFlags::CourseOverGroundSpeedOverGroundRapidUpdate:
378 {
379 if (nullptr != targetInterface->cogSogTransmitMessage.get_control_function())
380 {
381 targetInterface->cogSogTransmitMessage.serialize(messageBuffer);
382 transmitSuccessful = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::CourseOverGroundSpeedOverGroundRapidUpdate),
383 messageBuffer.data(),
384 messageBuffer.size(),
385 std::static_pointer_cast<InternalControlFunction>(targetInterface->cogSogTransmitMessage.get_control_function()),
386 nullptr,
388 }
389 }
390 break;
391
392 case TransmitFlags::Datum:
393 {
394 if (nullptr != targetInterface->datumTransmitMessage.get_control_function())
395 {
396 targetInterface->datumTransmitMessage.serialize(messageBuffer);
397 transmitSuccessful = CANNetworkManager::CANNetwork.get_fast_packet_protocol(0)->send_multipacket_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::Datum),
398 messageBuffer.data(),
399 messageBuffer.size(),
400 std::static_pointer_cast<InternalControlFunction>(targetInterface->datumTransmitMessage.get_control_function()),
401 nullptr,
403 }
404 }
405 break;
406
407 case TransmitFlags::GNSSPositionData:
408 {
409 if (nullptr != targetInterface->gnssPositionDataTransmitMessage.get_control_function())
410 {
411 targetInterface->gnssPositionDataTransmitMessage.serialize(messageBuffer);
412 transmitSuccessful = CANNetworkManager::CANNetwork.get_fast_packet_protocol(0)->send_multipacket_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::GNSSPositionData),
413 messageBuffer.data(),
414 messageBuffer.size(),
415 std::static_pointer_cast<InternalControlFunction>(targetInterface->gnssPositionDataTransmitMessage.get_control_function()),
416 nullptr,
418 }
419 }
420 break;
421
422 case TransmitFlags::PositionDeltaHighPrecisionRapidUpdate:
423 {
424 if (nullptr != targetInterface->positionDeltaHighPrecisionRapidUpdateTransmitMessage.get_control_function())
425 {
426 targetInterface->positionDeltaHighPrecisionRapidUpdateTransmitMessage.serialize(messageBuffer);
427 transmitSuccessful = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionDeltaHighPrecisionRapidUpdate),
428 messageBuffer.data(),
429 messageBuffer.size(),
430 std::static_pointer_cast<InternalControlFunction>(targetInterface->positionDeltaHighPrecisionRapidUpdateTransmitMessage.get_control_function()),
431 nullptr,
433 }
434 }
435 break;
436
437 case TransmitFlags::PositionRapidUpdate:
438 {
439 if (nullptr != targetInterface->positionRapidUpdateTransmitMessage.get_control_function())
440 {
441 targetInterface->positionRapidUpdateTransmitMessage.serialize(messageBuffer);
442 transmitSuccessful = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionRapidUpdate),
443 messageBuffer.data(),
444 messageBuffer.size(),
445 std::static_pointer_cast<InternalControlFunction>(targetInterface->positionRapidUpdateTransmitMessage.get_control_function()),
446 nullptr,
448 }
449 }
450 break;
451
452 case TransmitFlags::RateOfTurn:
453 {
454 if (nullptr != targetInterface->rateOfTurnTransmitMessage.get_control_function())
455 {
456 targetInterface->rateOfTurnTransmitMessage.serialize(messageBuffer);
457 transmitSuccessful = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::RateOfTurn),
458 messageBuffer.data(),
459 messageBuffer.size(),
460 std::static_pointer_cast<InternalControlFunction>(targetInterface->rateOfTurnTransmitMessage.get_control_function()),
461 nullptr,
463 }
464 }
465 break;
466
467 case TransmitFlags::VesselHeading:
468 {
469 if (nullptr != targetInterface->vesselHeadingTransmitMessage.get_control_function())
470 {
471 targetInterface->vesselHeadingTransmitMessage.serialize(messageBuffer);
472 transmitSuccessful = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::VesselHeading),
473 messageBuffer.data(),
474 messageBuffer.size(),
475 std::static_pointer_cast<InternalControlFunction>(targetInterface->vesselHeadingTransmitMessage.get_control_function()),
476 nullptr,
478 }
479 }
480 break;
481
482 default:
483 break;
484 }
485
486 if (!transmitSuccessful)
487 {
488 targetInterface->txFlags.set_flag(static_cast<std::uint32_t>(flag));
489 }
490 }
491 }
492
493 void NMEA2000MessageInterface::process_rx_message(const CANMessage &message, void *parentPointer)
494 {
495 if (nullptr != parentPointer)
496 {
497 auto targetInterface = static_cast<NMEA2000MessageInterface *>(parentPointer);
498
499 switch (message.get_identifier().get_parameter_group_number())
500 {
501 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::CourseOverGroundSpeedOverGroundRapidUpdate):
502 {
503 if (message.get_source_control_function() != nullptr)
504 {
505 auto result = std::find_if(targetInterface->receivedCogSogMessages.begin(),
506 targetInterface->receivedCogSogMessages.end(),
507 [&message](const std::shared_ptr<CourseOverGroundSpeedOverGroundRapidUpdate> &receivedCommand) {
508 return (nullptr != receivedCommand) && (receivedCommand->get_control_function() == message.get_source_control_function());
509 });
510
511 if (result == targetInterface->receivedCogSogMessages.end())
512 {
513 // There is no existing message object from this control function, so create a new one
514 targetInterface->receivedCogSogMessages.push_back(std::make_shared<CourseOverGroundSpeedOverGroundRapidUpdate>(message.get_source_control_function()));
515 result = targetInterface->receivedCogSogMessages.end() - 1;
516 }
517
518 bool anySignalChanged = (*result)->deserialize(message);
519 targetInterface->cogSogEventPublisher.call(*result, anySignalChanged);
520 }
521 }
522 break;
523
524 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::Datum):
525 {
526 if (message.get_source_control_function() != nullptr)
527 {
528 auto result = std::find_if(targetInterface->receivedDatumMessages.begin(),
529 targetInterface->receivedDatumMessages.end(),
530 [&message](const std::shared_ptr<Datum> &receivedCommand) {
531 return (nullptr != receivedCommand) && (receivedCommand->get_control_function() == message.get_source_control_function());
532 });
533
534 if (result == targetInterface->receivedDatumMessages.end())
535 {
536 // There is no existing message object from this control function, so create a new one
537 targetInterface->receivedDatumMessages.push_back(std::make_shared<Datum>(message.get_source_control_function()));
538 result = targetInterface->receivedDatumMessages.end() - 1;
539 }
540
541 bool anySignalChanged = (*result)->deserialize(message);
542 targetInterface->datumEventPublisher.call(*result, anySignalChanged);
543 }
544 }
545 break;
546
547 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::GNSSPositionData):
548 {
549 if (message.get_source_control_function() != nullptr)
550 {
551 auto result = std::find_if(targetInterface->receivedGNSSPositionDataMessages.begin(),
552 targetInterface->receivedGNSSPositionDataMessages.end(),
553 [&message](const std::shared_ptr<GNSSPositionData> &receivedCommand) {
554 return (nullptr != receivedCommand) && (receivedCommand->get_control_function() == message.get_source_control_function());
555 });
556
557 if (result == targetInterface->receivedGNSSPositionDataMessages.end())
558 {
559 // There is no existing message object from this control function, so create a new one
560 targetInterface->receivedGNSSPositionDataMessages.push_back(std::make_shared<GNSSPositionData>(message.get_source_control_function()));
561 result = targetInterface->receivedGNSSPositionDataMessages.end() - 1;
562 }
563
564 bool anySignalChanged = (*result)->deserialize(message);
565 targetInterface->gnssPositionDataEventPublisher.call(*result, anySignalChanged);
566 }
567 }
568 break;
569
570 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionDeltaHighPrecisionRapidUpdate):
571 {
572 if (message.get_source_control_function() != nullptr)
573 {
574 auto result = std::find_if(targetInterface->receivedPositionDeltaHighPrecisionRapidUpdateMessages.begin(),
575 targetInterface->receivedPositionDeltaHighPrecisionRapidUpdateMessages.end(),
576 [&message](const std::shared_ptr<PositionDeltaHighPrecisionRapidUpdate> &receivedCommand) {
577 return (nullptr != receivedCommand) && (receivedCommand->get_control_function() == message.get_source_control_function());
578 });
579
580 if (result == targetInterface->receivedPositionDeltaHighPrecisionRapidUpdateMessages.end())
581 {
582 // There is no existing message object from this control function, so create a new one
583 targetInterface->receivedPositionDeltaHighPrecisionRapidUpdateMessages.push_back(std::make_shared<PositionDeltaHighPrecisionRapidUpdate>(message.get_source_control_function()));
584 result = targetInterface->receivedPositionDeltaHighPrecisionRapidUpdateMessages.end() - 1;
585 }
586
587 bool anySignalChanged = (*result)->deserialize(message);
588 targetInterface->positionDeltaHighPrecisionRapidUpdateEventPublisher.call(*result, anySignalChanged);
589 }
590 }
591 break;
592
593 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::PositionRapidUpdate):
594 {
595 if (message.get_source_control_function() != nullptr)
596 {
597 auto result = std::find_if(targetInterface->receivedPositionRapidUpdateMessages.begin(),
598 targetInterface->receivedPositionRapidUpdateMessages.end(),
599 [&message](const std::shared_ptr<PositionRapidUpdate> &receivedCommand) {
600 return (nullptr != receivedCommand) && (receivedCommand->get_control_function() == message.get_source_control_function());
601 });
602
603 if (result == targetInterface->receivedPositionRapidUpdateMessages.end())
604 {
605 // There is no existing message object from this control function, so create a new one
606 targetInterface->receivedPositionRapidUpdateMessages.push_back(std::make_shared<PositionRapidUpdate>(message.get_source_control_function()));
607 result = targetInterface->receivedPositionRapidUpdateMessages.end() - 1;
608 }
609
610 bool anySignalChanged = (*result)->deserialize(message);
611 targetInterface->positionRapidUpdateEventPublisher.call(*result, anySignalChanged);
612 }
613 }
614 break;
615
616 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::RateOfTurn):
617 {
618 if (message.get_source_control_function() != nullptr)
619 {
620 auto result = std::find_if(targetInterface->receivedRateOfTurnMessages.begin(),
621 targetInterface->receivedRateOfTurnMessages.end(),
622 [&message](const std::shared_ptr<RateOfTurn> &receivedCommand) {
623 return (nullptr != receivedCommand) && (receivedCommand->get_control_function() == message.get_source_control_function());
624 });
625
626 if (result == targetInterface->receivedRateOfTurnMessages.end())
627 {
628 // There is no existing message object from this control function, so create a new one
629 targetInterface->receivedRateOfTurnMessages.push_back(std::make_shared<RateOfTurn>(message.get_source_control_function()));
630 result = targetInterface->receivedRateOfTurnMessages.end() - 1;
631 }
632
633 bool anySignalChanged = (*result)->deserialize(message);
634 targetInterface->rateOfTurnEventPublisher.call(*result, anySignalChanged);
635 }
636 }
637 break;
638
639 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::VesselHeading):
640 {
641 if (message.get_source_control_function() != nullptr)
642 {
643 auto result = std::find_if(targetInterface->receivedVesselHeadingMessages.begin(),
644 targetInterface->receivedVesselHeadingMessages.end(),
645 [&message](const std::shared_ptr<VesselHeading> &receivedCommand) {
646 return (nullptr != receivedCommand) && (receivedCommand->get_control_function() == message.get_source_control_function());
647 });
648
649 if (result == targetInterface->receivedVesselHeadingMessages.end())
650 {
651 // There is no existing message object from this control function, so create a new one
652 targetInterface->receivedVesselHeadingMessages.push_back(std::make_shared<VesselHeading>(message.get_source_control_function()));
653 result = targetInterface->receivedVesselHeadingMessages.end() - 1;
654 }
655
656 bool anySignalChanged = (*result)->deserialize(message);
657 targetInterface->vesselHeadingEventPublisher.call(*result, anySignalChanged);
658 }
659 }
660 break;
661
662 default:
663 break;
664 }
665 }
666 }
667
669 {
670 if (initialized)
671 {
672 receivedCogSogMessages.erase(std::remove_if(receivedCogSogMessages.begin(),
674 [](std::shared_ptr<CourseOverGroundSpeedOverGroundRapidUpdate> message) {
675 if (SystemTiming::time_expired_ms(message->get_timestamp(), 3 * CourseOverGroundSpeedOverGroundRapidUpdate::get_timeout()))
676 {
677 LOG_WARNING("[NMEA2K]: COG & SOG message Rx timeout.");
678 return true;
679 }
680 return false;
681 }),
683 receivedDatumMessages.erase(std::remove_if(receivedDatumMessages.begin(),
685 [](std::shared_ptr<Datum> message) {
686 if (SystemTiming::time_expired_ms(message->get_timestamp(), 3 * Datum::get_timeout()))
687 {
688 LOG_WARNING("[NMEA2K]: Datum message Rx timeout.");
689 return true;
690 }
691 return false;
692 }),
696 [](std::shared_ptr<GNSSPositionData> message) {
697 if (SystemTiming::time_expired_ms(message->get_timestamp(), 3 * GNSSPositionData::get_timeout()))
698 {
699 LOG_WARNING("[NMEA2K]: GNSS position data message Rx timeout.");
700 return true;
701 }
702 return false;
703 }),
707 [](std::shared_ptr<PositionDeltaHighPrecisionRapidUpdate> message) {
708 if (SystemTiming::time_expired_ms(message->get_timestamp(), 3 * PositionDeltaHighPrecisionRapidUpdate::get_timeout()))
709 {
710 LOG_WARNING("[NMEA2K]: Position Delta High Precision Rapid Update Rx timeout.");
711 return true;
712 }
713 return false;
714 }),
718 [](std::shared_ptr<PositionRapidUpdate> message) {
719 if (SystemTiming::time_expired_ms(message->get_timestamp(), 3 * PositionRapidUpdate::get_timeout()))
720 {
721 LOG_WARNING("[NMEA2K]: Position delta high precision rapid update message Rx timeout.");
722 return true;
723 }
724 return false;
725 }),
727 receivedRateOfTurnMessages.erase(std::remove_if(receivedRateOfTurnMessages.begin(),
729 [](std::shared_ptr<RateOfTurn> message) {
730 if (SystemTiming::time_expired_ms(message->get_timestamp(), 3 * RateOfTurn::get_timeout()))
731 {
732 LOG_WARNING("[NMEA2K]: Rate of turn message Rx timeout.");
733 return true;
734 }
735 return false;
736 }),
740 [](std::shared_ptr<VesselHeading> message) {
741 if (SystemTiming::time_expired_ms(message->get_timestamp(), 3 * VesselHeading::get_timeout()))
742 {
743 LOG_WARNING("[NMEA2K]: Vessel heading message Rx timeout.");
744 return true;
745 }
746 return false;
747 }),
749 }
750 }
751
752 void NMEA2000MessageInterface::check_transmit_timeouts()
753 {
754 if (sendCogSogCyclically && SystemTiming::time_expired_ms(cogSogTransmitMessage.get_timestamp(), CourseOverGroundSpeedOverGroundRapidUpdate::get_timeout()))
755 {
756 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::CourseOverGroundSpeedOverGroundRapidUpdate));
757 cogSogTransmitMessage.set_timestamp(SystemTiming::get_timestamp_ms());
758 }
759 if (sendDatumCyclically && SystemTiming::time_expired_ms(datumTransmitMessage.get_timestamp(), Datum::get_timeout()))
760 {
761 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::Datum));
762 datumTransmitMessage.set_timestamp(SystemTiming::get_timestamp_ms());
763 }
764 if (sendPositionDeltaHighPrecisionRapidUpdateCyclically && SystemTiming::time_expired_ms(positionDeltaHighPrecisionRapidUpdateTransmitMessage.get_timestamp(), PositionDeltaHighPrecisionRapidUpdate::get_timeout()))
765 {
766 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::PositionDeltaHighPrecisionRapidUpdate));
767 positionDeltaHighPrecisionRapidUpdateTransmitMessage.set_timestamp(SystemTiming::get_timestamp_ms());
768 }
769 if (sendGNSSPositionDataCyclically && SystemTiming::time_expired_ms(gnssPositionDataTransmitMessage.get_timestamp(), GNSSPositionData::get_timeout()))
770 {
771 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::GNSSPositionData));
772 gnssPositionDataTransmitMessage.set_timestamp(SystemTiming::get_timestamp_ms());
773 }
774 if (sendPositionRapidUpdateCyclically && SystemTiming::time_expired_ms(positionRapidUpdateTransmitMessage.get_timestamp(), PositionRapidUpdate::get_timeout()))
775 {
776 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::PositionRapidUpdate));
777 positionRapidUpdateTransmitMessage.set_timestamp(SystemTiming::get_timestamp_ms());
778 }
779 if (sendRateOfTurnCyclically && SystemTiming::time_expired_ms(rateOfTurnTransmitMessage.get_timestamp(), RateOfTurn::get_timeout()))
780 {
781 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::RateOfTurn));
782 rateOfTurnTransmitMessage.set_timestamp(SystemTiming::get_timestamp_ms());
783 }
784 if (sendVesselHeadingCyclically && SystemTiming::time_expired_ms(vesselHeadingTransmitMessage.get_timestamp(), VesselHeading::get_timeout()))
785 {
786 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::VesselHeading));
787 vesselHeadingTransmitMessage.set_timestamp(SystemTiming::get_timestamp_ms());
788 }
789 }
790} // 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)
@ Priority2
Priority highest - 2.
@ PriorityDefault6
The default 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::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.
std::unique_ptr< FastPacketProtocol > & get_fast_packet_protocol(std::uint8_t canPortIndex)
Returns the class instance of the NMEA2k fast packet protocol. Use this to register for FP multipacke...
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...
An interface for sending and receiving common NMEA2000 messages on an ISO11783 network.
void check_transmit_timeouts()
Checks to see if any transmit flags need to be set based on the last time the message was sent,...
NMEA2000Messages::GNSSPositionData gnssPositionDataTransmitMessage
Stores a set of data specifically for transmitting the PGN 129029 (0x1F805) if enabled.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::Datum >, bool > datumEventPublisher
An event dispatcher for notifying when new guidance machine info messages are received.
std::vector< std::shared_ptr< NMEA2000Messages::PositionRapidUpdate > > receivedPositionRapidUpdateMessages
Stores all received (and not timed out) sources of the position rapid update message.
std::shared_ptr< NMEA2000Messages::RateOfTurn > get_received_rate_of_turn_message(std::size_t index) const
Returns the content of the rate of turn message based on the index of the sender. Use this to read th...
EventDispatcher< const std::shared_ptr< NMEA2000Messages::GNSSPositionData >, bool > & get_gnss_position_data_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated GNSS position data me...
bool get_enable_sending_cog_sog_cyclically() const
Returns if the interface has cyclic sending of the course/speed over ground message enabled.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::PositionDeltaHighPrecisionRapidUpdate >, bool > positionDeltaHighPrecisionRapidUpdateEventPublisher
An event dispatcher for notifying when new guidance machine info messages are received.
void set_enable_sending_vessel_heading_cyclically(bool enable)
Instructs the interface to enable or disable sending the vessel heading message cyclically.
std::vector< std::shared_ptr< NMEA2000Messages::VesselHeading > > receivedVesselHeadingMessages
Stores all received (and not timed out) sources of the vessel heading message.
std::shared_ptr< NMEA2000Messages::Datum > get_received_datum_message(std::size_t index) const
Returns the content of the Datum message based on the index of the sender. Use this to read the recei...
NMEA2000Messages::VesselHeading vesselHeadingTransmitMessage
Stores a set of data specifically for transmitting the PGN 127250 (0x1F112) if enabled.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::VesselHeading >, bool > vesselHeadingEventPublisher
An event dispatcher for notifying when new guidance machine info messages are received.
bool get_enable_sending_rate_of_turn_cyclically() const
Returns if the interface has cyclic sending of the rate of turn message enabled.
void set_enable_sending_datum_cyclically(bool enable)
Instructs the interface to enable or disable sending the datum data message cyclically.
NMEA2000Messages::RateOfTurn rateOfTurnTransmitMessage
Stores a set of data specifically for transmitting the PGN 127251 (0x1F113) if enabled.
bool sendGNSSPositionDataCyclically
Determines if the interface will try to send the GNSS position data message cyclically.
static void process_flags(std::uint32_t flag, void *parentPointer)
A generic callback for a the class to process flags from the ProcessingFlags
NMEA2000Messages::RateOfTurn & get_rate_of_turn_transmit_message()
Returns a RateOfTurn object that you can use to set the message's individual signal values,...
std::vector< std::shared_ptr< NMEA2000Messages::Datum > > receivedDatumMessages
Stores all received (and not timed out) sources of the Datum message.
ProcessingFlags txFlags
A set of flags used to track what messages need to be transmitted or retried.
void set_enable_sending_position_rapid_update_cyclically(bool enable)
Instructs the interface to enable or disable sending the position rapid update message cyclically.
NMEA2000MessageInterface(std::shared_ptr< InternalControlFunction > sendingControlFunction, bool enableSendingCogSogCyclically, bool enableSendingDatumCyclically, bool enableSendingGNSSPositionDataCyclically, bool enableSendingPositionDeltaHighPrecisionRapidUpdateCyclically, bool enableSendingPositionRapidUpdateCyclically, bool enableSendingRateOfTurnCyclically, bool enableSendingVesselHeadingCyclically)
Constructor for a NMEA2000MessageInterface.
bool get_enable_sending_datum_cyclically() const
Returns if the interface has cyclic sending of the datum message enabled.
void update()
Updates the diagnostic protocol. Must be called periodically. 50ms Is a good minimum interval for thi...
EventDispatcher< const std::shared_ptr< NMEA2000Messages::PositionRapidUpdate >, bool > positionRapidUpdateEventPublisher
An event dispatcher for notifying when new guidance machine info messages are received.
void check_receive_timeouts()
Checks to see if any received messages are timed out and prunes them if needed.
void set_enable_sending_gnss_position_data_cyclically(bool enable)
Instructs the interface to enable or disable sending the GNSS position data message cyclically.
bool get_enable_sending_position_rapid_update_cyclically() const
Returns if the interface has cyclic sending of the position rapid update message enabled.
bool sendVesselHeadingCyclically
Determines if the interface will try to send the vessel heading message cyclically.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::CourseOverGroundSpeedOverGroundRapidUpdate >, bool > & get_course_speed_over_ground_rapid_update_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated COG & SOG messages ar...
bool sendDatumCyclically
Determines if the interface will try to send the Datum message cyclically.
NMEA2000Messages::GNSSPositionData & get_gnss_position_data_transmit_message()
Returns a GNSSPositionData object that you can use to set the message's individual signal values,...
NMEA2000Messages::PositionDeltaHighPrecisionRapidUpdate positionDeltaHighPrecisionRapidUpdateTransmitMessage
Stores a set of data specifically for transmitting the PGN 129027 (0x1F803) if enabled.
NMEA2000Messages::Datum & get_datum_transmit_message()
Returns a Datum object that you can use to set the message's individual signal values,...
bool get_enable_sending_vessel_heading_cyclically() const
Returns if the interface has cyclic sending of the vessel heading message enabled.
std::size_t get_number_received_rate_of_turn_message_sources() const
Returns the number of unique rate of turn message senders.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::GNSSPositionData >, bool > gnssPositionDataEventPublisher
An event dispatcher for notifying when new guidance machine info messages are received.
NMEA2000Messages::Datum datumTransmitMessage
Stores a set of data specifically for transmitting the PGN 129044 (0x1F814) if enabled.
bool sendPositionRapidUpdateCyclically
Determines if the interface will try to send the position rapid update message cyclically.
std::shared_ptr< NMEA2000Messages::GNSSPositionData > get_received_gnss_position_data_message(std::size_t index) const
Returns the content of the GNSS position data message based on the index of the sender....
std::size_t get_number_received_datum_message_sources() const
Returns the number of unique datum message senders.
std::size_t get_number_received_vessel_heading_message_sources() const
Returns the number of unique vessel heading message senders.
bool get_initialized() const
Returns if initialize has been called.
static void process_rx_message(const CANMessage &message, void *parentPointer)
Processes a CAN message destined for an instance of this interface.
NMEA2000Messages::PositionDeltaHighPrecisionRapidUpdate & get_position_delta_high_precision_rapid_update_transmit_message()
Returns a PositionDeltaHighPrecisionRapidUpdate object that you can use to set the message's individu...
std::size_t get_number_received_gnss_position_data_message_sources() const
Returns the number of unique GNSS position data message senders.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::CourseOverGroundSpeedOverGroundRapidUpdate >, bool > cogSogEventPublisher
An event dispatcher for notifying when new guidance machine info messages are received.
void initialize()
Initializes the interface. Registers it with the network manager. Must be called before the interface...
std::shared_ptr< NMEA2000Messages::PositionDeltaHighPrecisionRapidUpdate > get_received_position_delta_high_precision_rapid_update_message(std::size_t index) const
Returns the content of the position delta high precision rapid update message based on the index of t...
std::shared_ptr< NMEA2000Messages::CourseOverGroundSpeedOverGroundRapidUpdate > get_received_course_speed_over_ground_message(std::size_t index) const
Returns the content of the COG & SOG message based on the index of the sender. Use this to read the r...
void set_enable_sending_position_delta_high_precision_rapid_update_cyclically(bool enable)
Instructs the interface to enable or disable sending the position delta high precision rapid update m...
EventDispatcher< const std::shared_ptr< NMEA2000Messages::VesselHeading >, bool > & get_vessel_heading_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated vessel heading messag...
EventDispatcher< const std::shared_ptr< NMEA2000Messages::RateOfTurn >, bool > rateOfTurnEventPublisher
An event dispatcher for notifying when new guidance machine info messages are received.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::PositionRapidUpdate >, bool > & get_position_rapid_update_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated position rapid update...
bool get_enable_sending_position_delta_high_precision_rapid_update_cyclically() const
Returns if the interface has cyclic sending of the position delta high precision rapid update message...
std::shared_ptr< NMEA2000Messages::PositionRapidUpdate > get_received_position_rapid_update_message(std::size_t index) const
Returns the content of the position rapid update message based on the index of the sender....
std::size_t get_number_received_position_rapid_update_message_sources() const
Returns the number of unique position rapid update message senders.
NMEA2000Messages::CourseOverGroundSpeedOverGroundRapidUpdate cogSogTransmitMessage
Stores a set of data specifically for transmitting the PGN 129026 (0x1F802) if enabled.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::RateOfTurn >, bool > & get_rate_of_turn_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated rate of turn messages...
NMEA2000Messages::PositionRapidUpdate positionRapidUpdateTransmitMessage
Stores a set of data specifically for transmitting the PGN 129025 (0x1F801) if enabled.
void set_enable_sending_cog_sog_cyclically(bool enable)
Instructs the interface to enable or disable sending the course/speed over ground message cyclically.
void set_enable_sending_rate_of_turn_cyclically(bool enable)
Instructs the interface to enable or disable sending the rate of turn message cyclically.
EventDispatcher< const std::shared_ptr< NMEA2000Messages::Datum >, bool > & get_datum_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated datum messages are re...
std::size_t get_number_received_position_delta_high_precision_rapid_update_message_sources() const
Returns the number of unique delta position message senders.
bool sendCogSogCyclically
Determines if the interface will try to send the COG & SOG message cyclically.
NMEA2000Messages::VesselHeading & get_vessel_heading_transmit_message()
Returns a VesselHeading object that you can use to set the message's individual signal values,...
void terminate()
Unregisters the interface from the network manager.
std::shared_ptr< NMEA2000Messages::VesselHeading > get_received_vessel_heading_message(std::size_t index) const
Returns the content of the vessel heading message based on the index of the sender....
bool get_enable_sending_gnss_position_data_cyclically() const
Returns if the interface has cyclic sending of the GNSS position data message enabled.
NMEA2000Messages::CourseOverGroundSpeedOverGroundRapidUpdate & get_cog_sog_transmit_message()
Returns a CourseOverGroundSpeedOverGroundRapidUpdate object that you can use to set the message's ind...
EventDispatcher< const std::shared_ptr< NMEA2000Messages::PositionDeltaHighPrecisionRapidUpdate >, bool > & get_position_delta_high_precision_rapid_update_event_publisher()
Returns an event dispatcher which you can use to get callbacks when new/updated position delta high p...
NMEA2000Messages::PositionRapidUpdate & get_position_rapid_update_transmit_message()
Returns a PositionRapidUpdate object that you can use to set the message's individual signal values,...
std::vector< std::shared_ptr< NMEA2000Messages::PositionDeltaHighPrecisionRapidUpdate > > receivedPositionDeltaHighPrecisionRapidUpdateMessages
Stores all received (and not timed out) sources of the position delta message.
std::vector< std::shared_ptr< NMEA2000Messages::RateOfTurn > > receivedRateOfTurnMessages
Stores all received (and not timed out) sources of the rate of turn message.
~NMEA2000MessageInterface()
Destructor for a NMEA2000MessageInterface.
std::vector< std::shared_ptr< NMEA2000Messages::GNSSPositionData > > receivedGNSSPositionDataMessages
Stores all received (and not timed out) sources of the GNSS position data message.
TransmitFlags
Enumerates a set of flags to manage sending various NMEA2000 messages from this interface.
bool sendRateOfTurnCyclically
Determines if the interface will try to send the rate of turn message cyclically.
std::vector< std::shared_ptr< NMEA2000Messages::CourseOverGroundSpeedOverGroundRapidUpdate > > receivedCogSogMessages
Stores all received (and not timed out) sources of the COG & SOG message.
bool sendPositionDeltaHighPrecisionRapidUpdateCyclically
Determines if the interface will try to send the position delta high precision rapid update message m...
std::size_t get_number_received_course_speed_over_ground_message_sources() const
Returns the number of unique senders of the COG & SOG message.
bool initialized
Tracks if initialize has been called.
Represents the data sent in the NMEA2K PGN 129026 (0x1F802)
void serialize(std::vector< std::uint8_t > &buffer) const
Serializes the current state of this object into a buffer to be sent on the CAN bus.
A NMEA2000 message that describes datum (reference frame) information. PGN 129044 (0x1F814) A common ...
static std::uint32_t get_timeout()
Returns the timeout (the sending interval) for this message in milliseconds.
Represents the data sent in the NMEA2K PGN 129029 (0x1F805)
static std::uint32_t get_timeout()
Returns the timeout (the sending interval) for this message in milliseconds.
This message is a way for a GNSS receiver to provide a current position without using fast packet bas...
static std::uint32_t get_timeout()
Returns the timeout (the sending interval) for this message in milliseconds.
Represents the data sent in the NMEA2K PGN 129025 (0x1F801)
static std::uint32_t get_timeout()
Returns the timeout (the sending interval) for this message in milliseconds.
Represents the data sent in the NMEA2K PGN 127251 (0x1F113)
static std::uint32_t get_timeout()
Returns the timeout (the sending interval) for this message in milliseconds.
Represents the data sent in the NMEA2K PGN 127250 (0x1F112)
static std::uint32_t get_timeout()
Returns the timeout (the sending interval) for this message in milliseconds.
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...
A protocol that handles the NMEA 2000 (IEC 61162-3) fast packet protocol.
A message interface for processing or sending NMEA2K messages commonly used on an ISO 11783 network.