AgIsoStack++
A control-function-focused implementation of the major ISOBUS and J1939 protocols
Loading...
Searching...
No Matches
can_parameter_group_number_request_protocol.cpp
Go to the documentation of this file.
1//================================================================================================
10//================================================================================================
14#include "isobus/utility/to_string.hpp"
15
16#include <algorithm>
17#include <cassert>
18
19namespace isobus
20{
21
23 myControlFunction(internalControlFunction)
24 {
25 assert(nullptr != myControlFunction && "ParameterGroupNumberRequestProtocol::ParameterGroupNumberRequestProtocol() called with nullptr internalControlFunction");
26 CANNetworkManager::CANNetwork.add_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::ParameterGroupNumberRequest), process_message, this);
27 CANNetworkManager::CANNetwork.add_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::RequestForRepetitionRate), process_message, this);
28 }
29
31 {
32 CANNetworkManager::CANNetwork.remove_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::ParameterGroupNumberRequest), process_message, this);
33 CANNetworkManager::CANNetwork.remove_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::RequestForRepetitionRate), process_message, this);
34 }
35
36 bool ParameterGroupNumberRequestProtocol::request_parameter_group_number(std::uint32_t pgn, std::shared_ptr<InternalControlFunction> source, std::shared_ptr<ControlFunction> destination)
37 {
38 std::array<std::uint8_t, PGN_REQUEST_LENGTH> buffer;
39
40 buffer[0] = static_cast<std::uint8_t>(pgn & 0xFF);
41 buffer[1] = static_cast<std::uint8_t>((pgn >> 8) & 0xFF);
42 buffer[2] = static_cast<std::uint8_t>((pgn >> 16) & 0xFF);
43
44 return CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::ParameterGroupNumberRequest),
45 buffer.data(),
47 source,
48 destination);
49 }
50
51 bool ParameterGroupNumberRequestProtocol::request_repetition_rate(std::uint32_t pgn, std::uint16_t repetitionRate_ms, std::shared_ptr<InternalControlFunction> source, std::shared_ptr<ControlFunction> destination)
52 {
53 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer;
54
55 buffer[0] = static_cast<std::uint8_t>(pgn & 0xFF);
56 buffer[1] = static_cast<std::uint8_t>((pgn >> 8) & 0xFF);
57 buffer[2] = static_cast<std::uint8_t>((pgn >> 16) & 0xFF);
58 buffer[3] = static_cast<std::uint8_t>(repetitionRate_ms & 0xFF);
59 buffer[4] = static_cast<std::uint8_t>((repetitionRate_ms >> 8) & 0xFF);
60 buffer[5] = 0xFF;
61 buffer[6] = 0xFF;
62 buffer[7] = 0xFF;
63
64 return CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::RequestForRepetitionRate),
65 buffer.data(),
67 source,
68 destination);
69 }
70
72 {
73 PGNRequestCallbackInfo pgnCallback(callback, pgn, parentPointer);
74 bool retVal = false;
75 LOCK_GUARD(Mutex, pgnRequestMutex);
76
77 if ((nullptr != callback) && (pgnRequestCallbacks.end() == std::find(pgnRequestCallbacks.begin(), pgnRequestCallbacks.end(), pgnCallback)))
78 {
79 pgnRequestCallbacks.push_back(pgnCallback);
80 retVal = true;
81 }
82 return retVal;
83 }
84
86 {
87 PGNRequestForRepetitionRateCallbackInfo repetitionRateCallback(callback, pgn, parentPointer);
88 bool retVal = false;
89 LOCK_GUARD(Mutex, pgnRequestMutex);
90
91 if ((nullptr != callback) && (repetitionRateCallbacks.end() == std::find(repetitionRateCallbacks.begin(), repetitionRateCallbacks.end(), repetitionRateCallback)))
92 {
93 repetitionRateCallbacks.push_back(repetitionRateCallback);
94 retVal = true;
95 }
96 return retVal;
97 }
98
99 bool ParameterGroupNumberRequestProtocol::remove_pgn_request_callback(std::uint32_t pgn, PGNRequestCallback callback, void *parentPointer)
100 {
101 PGNRequestCallbackInfo repetitionRateCallback(callback, pgn, parentPointer);
102 bool retVal = false;
103 LOCK_GUARD(Mutex, pgnRequestMutex);
104
105 auto callbackLocation = find(pgnRequestCallbacks.begin(), pgnRequestCallbacks.end(), repetitionRateCallback);
106
107 if (pgnRequestCallbacks.end() != callbackLocation)
108 {
109 pgnRequestCallbacks.erase(callbackLocation);
110 retVal = true;
111 }
112 return retVal;
113 }
114
116 {
117 PGNRequestForRepetitionRateCallbackInfo repetitionRateCallback(callback, pgn, parentPointer);
118 bool retVal = false;
119 LOCK_GUARD(Mutex, pgnRequestMutex);
120
121 auto callbackLocation = find(repetitionRateCallbacks.begin(), repetitionRateCallbacks.end(), repetitionRateCallback);
122
123 if (repetitionRateCallbacks.end() != callbackLocation)
124 {
125 repetitionRateCallbacks.erase(callbackLocation);
126 retVal = true;
127 }
128 return retVal;
129 }
130
135
140
141 ParameterGroupNumberRequestProtocol::PGNRequestCallbackInfo::PGNRequestCallbackInfo(PGNRequestCallback callback, std::uint32_t parameterGroupNumber, void *parentPointer) :
142 callbackFunction(callback),
143 pgn(parameterGroupNumber),
144 parent(parentPointer)
145 {
146 }
147
149 callbackFunction(callback),
150 pgn(parameterGroupNumber),
151 parent(parentPointer)
152 {
153 }
154
156 {
157 return ((obj.callbackFunction == this->callbackFunction) && (obj.pgn == this->pgn) && (obj.parent == this->parent));
158 }
159
161 {
162 return ((obj.callbackFunction == this->callbackFunction) && (obj.pgn == this->pgn) && (obj.parent == this->parent));
163 }
164
166 {
167 if (((nullptr == message.get_destination_control_function()) &&
170 {
171 switch (message.get_identifier().get_parameter_group_number())
172 {
173 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::RequestForRepetitionRate):
174 {
175 // Can't send this request to global, and must be 8 bytes. Ignore illegal message formats
176 if ((CAN_DATA_LENGTH == message.get_data_length()) && (nullptr != message.get_destination_control_function()))
177 {
178 std::uint32_t requestedPGN = message.get_uint24_at(0);
179 std::uint16_t requestedRate = message.get_uint16_at(3);
180 LOCK_GUARD(Mutex, pgnRequestMutex);
181 for (const auto &repetitionRateCallback : repetitionRateCallbacks)
182 {
183 if (((repetitionRateCallback.pgn == requestedPGN) ||
184 (static_cast<std::uint32_t>(isobus::CANLibParameterGroupNumber::Any) == repetitionRateCallback.pgn)) &&
185 (repetitionRateCallback.callbackFunction(requestedPGN, message.get_source_control_function(), message.get_destination_control_function(), requestedRate, repetitionRateCallback.parent)))
186 {
187 // If the callback was able to process the PGN request, stop processing more.
188 break;
189 }
190 }
191
192 // We can just ignore requests for repetition rate if we don't support them for this PGN. No need to NACK.
193 // From isobus.net:
194 // "CFs are not required to monitor the bus for this message."
195 // "If another CF cannot or does not want to use the requested repetition rate, which is necessary for systems with fixed timing control loops, it may ignore this message."
196 }
197 else
198 {
199 LOG_WARNING("[PR]: Received a malformed or broadcast request for repetition rate message. The message will not be processed.");
200 }
201 }
202 break;
203
204 case static_cast<std::uint32_t>(CANLibParameterGroupNumber::ParameterGroupNumberRequest):
205 {
206 if (message.get_data_length() >= PGN_REQUEST_LENGTH)
207 {
208 bool shouldAck = false;
210 bool anyCallbackProcessed = false;
211
212 std::uint32_t requestedPGN = message.get_uint24_at(0);
213
214 LOCK_GUARD(Mutex, pgnRequestMutex);
215 for (const auto &pgnRequestCallback : pgnRequestCallbacks)
216 {
217 if (((pgnRequestCallback.pgn == requestedPGN) ||
218 (static_cast<std::uint32_t>(isobus::CANLibParameterGroupNumber::Any) == pgnRequestCallback.pgn)) &&
219 (pgnRequestCallback.callbackFunction(requestedPGN, message.get_source_control_function(), shouldAck, ackType, pgnRequestCallback.parent)))
220 {
221 // If we're here, the callback was able to process the PGN request.
222 anyCallbackProcessed = true;
223
224 // Now we need to know if we shoulc ACK it.
225 // We should not ACK messages that send the actual PGN as a result of requesting it. This behavior is up to
226 // the application layer to do properly.
227 if (shouldAck && (nullptr != message.get_destination_control_function()))
228 {
229 send_acknowledgement(ackType,
230 requestedPGN,
232 }
233 // If this callback was able to process the PGN request, stop processing more.
234 break;
235 }
236 }
237
238 if ((!anyCallbackProcessed) && (nullptr != message.get_destination_control_function()))
239 {
241 requestedPGN,
243 LOG_WARNING("[PR]: NACK-ing PGN request for PGN " +
244 isobus::to_string(requestedPGN) +
245 " because no callback could handle it.");
246 }
247 }
248 else
249 {
250 LOG_WARNING("[PR]: Received a malformed PGN request message. The message will not be processed.");
251 }
252 }
253 break;
254
255 default:
256 break;
257 }
258 }
259 }
260
262 {
263 if (nullptr != parent)
264 {
265 reinterpret_cast<ParameterGroupNumberRequestProtocol *>(parent)->process_message(message);
266 }
267 }
268
269 bool ParameterGroupNumberRequestProtocol::send_acknowledgement(AcknowledgementType type, std::uint32_t parameterGroupNumber, std::shared_ptr<ControlFunction> destination) const
270 {
271 bool retVal = false;
272
273 if (nullptr != destination)
274 {
275 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer;
276
277 buffer[0] = static_cast<std::uint8_t>(type);
278 buffer[1] = 0xFF;
279 buffer[2] = 0xFF;
280 buffer[3] = 0xFF;
281 buffer[4] = destination->get_address();
282 buffer[5] = static_cast<std::uint8_t>(parameterGroupNumber & 0xFF);
283 buffer[6] = static_cast<std::uint8_t>((parameterGroupNumber >> 8) & 0xFF);
284 buffer[7] = static_cast<std::uint8_t>((parameterGroupNumber >> 16) & 0xFF);
285
286 retVal = CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::Acknowledge),
287 buffer.data(),
290 nullptr);
291 }
292 return retVal;
293 }
294
295} // namespace isobus
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...
This is a way to protect functions on public interfaces from being accessed by objects that shouldn't...
std::uint32_t get_parameter_group_number() const
Returns the PGN encoded in the identifier.
std::uint8_t get_destination_address() const
Returns the destination address of the frame 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::uint32_t get_uint24_at(const std::uint32_t index, const ByteFormat format=ByteFormat::LittleEndian) const
Get a right-aligned 24-bit integer from the buffer (returned as a uint32_t) at a specific index....
std::shared_ptr< ControlFunction > get_source_control_function() const
Gets the source control function that the message is from.
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::shared_ptr< ControlFunction > get_destination_control_function() const
Gets the destination control function that the message is to.
static CANNetworkManager CANNetwork
Static singleton of the one network manager. Use this to access stack functionality.
bool remove_protocol_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parentPointer)
Removes a PGN callback for a protocol class.
bool add_protocol_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parentPointer)
Adds a PGN callback for a protocol class.
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.
PGNRequestCallbackInfo(PGNRequestCallback callback, std::uint32_t parameterGroupNumber, void *parentPointer)
Constructor for PGNRequestCallbackInfo.
bool operator==(const PGNRequestCallbackInfo &obj) const
A utility function for determining if the data in the object is equal to another object.
void * parent
Pointer to the class that registered the callback, or nullptr
bool operator==(const PGNRequestForRepetitionRateCallbackInfo &obj) const
A utility function for determining if the data in the object is equal to another object.
PGNRequestForRepetitionRateCallbackInfo(PGNRequestForRepetitionRateCallback callback, std::uint32_t parameterGroupNumber, void *parentPointer)
Constructor for PGNRequestCallbackInfo.
std::shared_ptr< InternalControlFunction > myControlFunction
The internal control function that this protocol will send from.
std::vector< PGNRequestCallbackInfo > pgnRequestCallbacks
A list of all registered PGN callbacks and the PGN associated with each callback.
bool remove_pgn_request_callback(std::uint32_t pgn, PGNRequestCallback callback, void *parentPointer)
Removes a previously registered PGN request callback.
void process_message(const CANMessage &message)
A generic way for a protocol to process a received message.
static constexpr std::uint8_t PGN_REQUEST_LENGTH
The CAN data length of a PGN request.
bool register_pgn_request_callback(std::uint32_t pgn, PGNRequestCallback callback, void *parentPointer)
Registers for a callback on receipt of a PGN request.
bool remove_request_for_repetition_rate_callback(std::uint32_t pgn, PGNRequestForRepetitionRateCallback callback, void *parentPointer)
Removes a callback for repetition rate requests.
bool register_request_for_repetition_rate_callback(std::uint32_t pgn, PGNRequestForRepetitionRateCallback callback, void *parentPointer)
Registers for a callback on receipt of a request for repetition rate.
ParameterGroupNumberRequestProtocol(std::shared_ptr< InternalControlFunction > internalControlFunction, CANLibBadge< InternalControlFunction >)
The constructor for this protocol.
std::vector< PGNRequestForRepetitionRateCallbackInfo > repetitionRateCallbacks
A list of all registered request for repetition rate callbacks and the PGN associated with the callba...
std::size_t get_number_registered_pgn_request_callbacks() const
Returns the number of PGN request callbacks that have been registered with this protocol instance.
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.
std::size_t get_number_registered_request_for_repetition_rate_callbacks() const
Returns the number of PGN request for repetition rate callbacks that have been registered with this p...
static bool request_parameter_group_number(std::uint32_t pgn, std::shared_ptr< InternalControlFunction > source, std::shared_ptr< ControlFunction > destination)
Sends a PGN request to the specified control function.
bool send_acknowledgement(AcknowledgementType type, std::uint32_t parameterGroupNumber, std::shared_ptr< ControlFunction > destination) const
Sends a message using the acknowledgement PGN.
This namespace encompasses all of the ISO11783 stack's functionality to reduce global namespace pollu...
bool(*)(std::uint32_t parameterGroupNumber, std::shared_ptr< ControlFunction > requestingControlFunction, std::shared_ptr< ControlFunction > targetControlFunction, std::uint32_t repetitionRate, void *parentPointer) PGNRequestForRepetitionRateCallback
A callback for handling a request for repetition rate for a specific PGN.
constexpr std::uint8_t CAN_DATA_LENGTH
The length of a classical CAN frame.
constexpr std::uint8_t BROADCAST_CAN_ADDRESS
The global/broadcast CAN address.
bool(*)(std::uint32_t parameterGroupNumber, std::shared_ptr< ControlFunction > requestingControlFunction, bool &acknowledge, AcknowledgementType &acknowledgeType, void *parentPointer) PGNRequestCallback
A callback for handling a PGN request.
AcknowledgementType
The types of acknowledgement that can be sent in the Ack PGN.
@ Negative
"NACK" Indicates the request was not completed or we do not support the PGN