22#include "isobus/utility/system_timing.hpp"
27 sendCANFrameCallback(sendCANFrameCallback)
33 if ((!enable) && (enable !=
enabled))
35 LOG_DEBUG(
"[HB]: Disabling ISOBUS heartbeat interface.");
46 std::shared_ptr<ControlFunction> destinationControlFunction)
const
50 if ((
nullptr != sourceControlFunction) &&
51 (
nullptr != destinationControlFunction) &&
56 sourceControlFunction,
57 destinationControlFunction);
64 auto pgnRequestProtocol = newControlFunction->get_pgn_request_protocol().lock();
66 if (
nullptr != pgnRequestProtocol)
68 pgnRequestProtocol->register_request_for_repetition_rate_callback(
static_cast<std::uint32_t
>(CANLibParameterGroupNumber::HeartbeatMessage),
process_request_for_heartbeat,
this);
74 auto pgnRequestProtocol = destroyedControlFunction->get_pgn_request_protocol().lock();
76 if (
nullptr != pgnRequestProtocol)
78 pgnRequestProtocol->remove_request_for_repetition_rate_callback(
static_cast<std::uint32_t
>(CANLibParameterGroupNumber::HeartbeatMessage),
process_request_for_heartbeat,
this);
99 if (nullptr != heartbeat.controlFunction)
101 if (ControlFunction::Type::Internal == heartbeat.controlFunction->get_type())
103 if ((SystemTiming::time_expired_ms(heartbeat.timestamp_ms, heartbeat.repetitionRate_ms)) &&
104 heartbeat.send(*this))
106 heartbeat.sequenceCounter++;
108 if (heartbeat.sequenceCounter > 250)
110 heartbeat.sequenceCounter = 0;
114 else if (SystemTiming::time_expired_ms(heartbeat.timestamp_ms, SEQUENCE_TIMEOUT_MS))
117 LOG_ERROR(
"[HB]: Heartbeat from control function at address 0x%02X timed out.", heartbeat.controlFunction->get_address());
118 heartbeatErrorEventDispatcher.call(HeartBeatError::TimedOut, heartbeat.controlFunction);
131 HeartbeatInterface::Heartbeat::Heartbeat(std::shared_ptr<ControlFunction> sendingControlFunction) :
132 controlFunction(sendingControlFunction),
133 timestamp_ms(SystemTiming::get_timestamp_ms())
140 const std::array<std::uint8_t, 1> buffer = { sequenceCounter };
142 retVal = parent.
sendCANFrameCallback(
static_cast<std::uint32_t
>(CANLibParameterGroupNumber::HeartbeatMessage),
149 timestamp_ms = SystemTiming::get_timestamp_ms();
164 return (message.get_source_control_function() == hb.controlFunction);
169 managedHeartbeat->timestamp_ms = SystemTiming::get_timestamp_ms();
171 if (message.
get_uint8_at(0) == managedHeartbeat->sequenceCounter)
173 LOG_ERROR(
"[HB]: Duplicate sequence counter received in heartbeat.");
176 else if (message.
get_uint8_at(0) != ((managedHeartbeat->sequenceCounter + 1) % 250))
178 LOG_ERROR(
"[HB]: Invalid sequence counter received in heartbeat.");
185 LOG_DEBUG(
"[HB]: Tracking new heartbeat from control function at address 0x%02X.", message.
get_source_control_function()->get_address());
189 LOG_WARNING(
"[HB]: Initial heartbeat sequence counter not received from control function at address 0x%02X.", message.
get_source_control_function()->get_address());
201 std::shared_ptr<ControlFunction> requestingControlFunction,
202 std::shared_ptr<ControlFunction> targetControlFunction,
203 std::uint32_t repetitionRate,
208 if (
nullptr != parentPointer)
212 if ((interface->is_enabled()) &&
213 (
static_cast<std::uint32_t
>(CANLibParameterGroupNumber::HeartbeatMessage) == parameterGroupNumber))
219 LOG_WARNING(
"[HB]: Control function at address 0x%02X requested the ISOBUS heartbeat at non-compliant interval. Interval should be 100ms.", requestingControlFunction->get_address());
223 LOG_DEBUG(
"[HB]: Control function at address 0x%02X requested the ISOBUS heartbeat from control function at address 0x%02X.", requestingControlFunction->get_address(), targetControlFunction->get_address());
226 auto managedHeartbeat = std::find_if(interface->trackedHeartbeats.begin(),
227 interface->trackedHeartbeats.end(),
228 [targetControlFunction](
const Heartbeat &hb) {
229 return (targetControlFunction == hb.controlFunction);
232 if (managedHeartbeat == interface->trackedHeartbeats.end())
234 interface->trackedHeartbeats.emplace_back(targetControlFunction);
Defines some PGNs that are used in the library or are very common.
A protocol that handles PGN requests.
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...
CANIdentifier get_identifier() const
Returns the identifier of the message.
static CANNetworkManager CANNetwork
Static singleton of the one network manager. Use this to access stack functionality.
std::shared_ptr< InternalControlFunction > get_internal_control_function(std::shared_ptr< ControlFunction > controlFunction)
Returns an internal control function if the passed-in control function is an internal type.
This class is used to store information about a tracked heartbeat.
bool send(const HeartbeatInterface &parent)
Transmits a heartbeat message (for internal control functions only). Updates the sequence counter and...
This class is used to send and receive ISOBUS heartbeats.
EventDispatcher< std::shared_ptr< ControlFunction > > newTrackedHeartbeatEventDispatcher
Event dispatcher for when a heartbeat message from another control function becomes tracked by this i...
static bool process_request_for_heartbeat(std::uint32_t parameterGroupNumber, std::shared_ptr< ControlFunction > requestingControlFunction, std::shared_ptr< ControlFunction > targetControlFunction, std::uint32_t repetitionRate, void *parentPointer)
Processes a PGN request for a heartbeat.
void set_enabled(bool enable)
This can be used to disable or enable this heartbeat functionality. It's probably best to leave it en...
EventDispatcher< std::shared_ptr< ControlFunction > > & get_new_tracked_heartbeat_event_dispatcher()
Returns an event dispatcher which can be used to register for new tracked heartbeat events....
std::list< Heartbeat > trackedHeartbeats
Store tracked heartbeat data, per CF.
@ InvalidSequenceCounter
The sequence counter is not valid.
EventDispatcher< HeartBeatError, std::shared_ptr< ControlFunction > > & get_heartbeat_error_event_dispatcher()
Returns an event dispatcher which can be used to register for heartbeat errors. Heartbeat errors are ...
bool is_enabled() const
Returns if the interface is currently enabled or not.
@ Initial
The heartbeat sequence number value shall be set to 251 once upon initialization of a CF.
bool enabled
Attribute that specifies if this interface is enabled. When false, the interface does nothing.
bool request_heartbeat(std::shared_ptr< InternalControlFunction > sourceControlFunction, std::shared_ptr< ControlFunction > destinationControlFunction) const
This method can be used to request that another control function on the bus start sending the heartbe...
void update()
Updates the interface. Called by the network manager, so there is no need for you to call it in your ...
void process_rx_message(const CANMessage &message)
Processes a CAN message, called by the network manager.
static constexpr std::uint32_t SEQUENCE_REPETITION_RATE_MS
A consuming CF shall send a Request for Repetition rate for the heart beat message with a repetition ...
EventDispatcher< HeartBeatError, std::shared_ptr< ControlFunction > > heartbeatErrorEventDispatcher
Event dispatcher for heartbeat errors.
const CANMessageFrameCallback sendCANFrameCallback
A callback for sending a CAN frame.
void on_destroyed_internal_control_function(std::shared_ptr< InternalControlFunction > destroyedControlFunction)
Called when an internal control function is deleted. Cleans up stale registrations with PGN request p...
void on_new_internal_control_function(std::shared_ptr< InternalControlFunction > newControlFunction)
Called by the internal control function class when a new internal control function is added....
HeartbeatInterface(const CANMessageFrameCallback &sendCANFrameCallback)
Constructor for a HeartbeatInterface.
static bool request_repetition_rate(std::uint32_t pgn, std::uint16_t repetitionRate_ms, std::shared_ptr< InternalControlFunction > source, std::shared_ptr< ControlFunction > destination)
Sends a PGN request for repetition rate.
Defines an interface for sending and receiving ISOBUS heartbeats. The heartbeat message is used to de...
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...
DataSpan< const std::uint8_t > CANDataSpan
A read-only span of data for a CAN message.
std::function< bool(std::uint32_t parameterGroupNumber, CANDataSpan data, std::shared_ptr< InternalControlFunction > sourceControlFunction, std::shared_ptr< ControlFunction > destinationControlFunction, CANIdentifier::CANPriority priority)> CANMessageFrameCallback
A callback for communicating CAN message frames.