AgIsoStack++
A control-function-focused implementation of the major ISOBUS and J1939 protocols
Loading...
Searching...
No Matches
isobus_shortcut_button_interface.cpp
Go to the documentation of this file.
1//================================================================================================
8//================================================================================================
10
15#include "isobus/utility/system_timing.hpp"
16
17#include <algorithm>
18#include <cassert>
19
20namespace isobus
21{
22 ShortcutButtonInterface::ShortcutButtonInterface(std::shared_ptr<InternalControlFunction> internalControlFunction, bool serverEnabled) :
23 sourceControlFunction(internalControlFunction),
24 txFlags(static_cast<std::uint32_t>(TransmitFlags::NumberOfFlags), process_flags, this),
25 actAsISBServer(serverEnabled)
26 {
27 assert(nullptr != sourceControlFunction); // You need an internal control function for the interface to function
28 }
29
31 {
32 if (initialized)
33 {
34 CANNetworkManager::CANNetwork.remove_global_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::AllImplementsStopOperationsSwitchState), process_rx_message, this);
35 }
36 }
37
39 {
40 if (!initialized)
41 {
42 CANNetworkManager::CANNetwork.add_global_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::AllImplementsStopOperationsSwitchState),
44 this);
45 initialized = true;
46 }
47 }
48
53
54 EventDispatcher<ShortcutButtonInterface::StopAllImplementOperationsState> &ShortcutButtonInterface::get_stop_all_implement_operations_state_event_dispatcher()
55 {
56 return ISBEventDispatcher;
57 }
58
60 {
62 {
63 if (newState != commandedState)
64 {
65 commandedState = newState;
66
68 {
69 LOG_ERROR("[ISB]: All implement operations must stop. (Triggered internally)");
70 }
71 else
72 {
73 LOG_INFO("[ISB]: Internal ISB state is now permitted.");
74 }
75 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::SendStopAllImplementOperationsSwitchState));
76 }
77 }
78 else
79 {
80 LOG_ERROR("[ISB]: You are attempting to set the internal ISB state but the ISB interface is not configured as a server!");
81 }
82 }
83
85 {
87
89 {
90 retVal = commandedState;
91 }
92 else
93 {
94 for (auto ISB = isobusShorcutButtonList.cbegin(); ISB != isobusShorcutButtonList.end(); ISB++)
95 {
97 {
98 retVal = ISB->commandedState; // Any stop condition will be returned.
99 break;
100 }
101 }
102 }
103 return retVal;
104 }
105
107 {
109 {
110 // Prune old ISBs
111 isobusShorcutButtonList.erase(std::remove_if(isobusShorcutButtonList.begin(), isobusShorcutButtonList.end(), [](ISBServerData &isb) {
112 return SystemTiming::time_expired_ms(isb.messageReceivedTimestamp_ms, TRANSMISSION_TIMEOUT_MS);
113 }),
115
116 txFlags.set_flag(static_cast<std::uint32_t>(TransmitFlags::SendStopAllImplementOperationsSwitchState));
117 }
118 txFlags.process_all_flags();
119 }
120
121 void ShortcutButtonInterface::process_rx_message(const CANMessage &message, void *parentPointer)
122 {
123 assert(nullptr != parentPointer);
124
125 static_cast<ShortcutButtonInterface *>(parentPointer)->process_message(message);
126 }
127
128 void ShortcutButtonInterface::process_flags(std::uint32_t flag, void *parent)
129 {
130 auto myInterface = static_cast<ShortcutButtonInterface *>(parent);
131 bool transmitSuccessful = true;
132 assert(nullptr != parent);
133
134 if (flag == static_cast<std::uint32_t>(TransmitFlags::SendStopAllImplementOperationsSwitchState))
135 {
136 transmitSuccessful = myInterface->send_stop_all_implement_operations_switch_state();
137
138 if (transmitSuccessful)
139 {
140 myInterface->stopAllImplementOperationsTransitionNumber++;
141 }
142 }
143
144 if (!transmitSuccessful)
145 {
146 myInterface->txFlags.set_flag(flag);
147 }
148 }
149
151 {
152 if ((message.get_can_port_index() == sourceControlFunction->get_can_port()) &&
153 (static_cast<std::uint32_t>(CANLibParameterGroupNumber::AllImplementsStopOperationsSwitchState) == message.get_identifier().get_parameter_group_number()))
154 {
155 if (CAN_DATA_LENGTH == message.get_data_length())
156 {
157 auto messageNAME = message.get_source_control_function()->get_NAME();
158 auto matches_isoname = [messageNAME](ISBServerData &isb) { return isb.ISONAME == messageNAME; };
159 auto ISB = std::find_if(isobusShorcutButtonList.begin(), isobusShorcutButtonList.end(), matches_isoname);
160 auto &messageData = message.get_data();
162
163 if (isobusShorcutButtonList.end() == ISB)
164 {
165 ISBServerData newISB;
166
167 LOG_DEBUG("[ISB]: New ISB detected at address %u", message.get_identifier().get_source_address());
168 newISB.ISONAME = messageNAME;
169 isobusShorcutButtonList.emplace_back(newISB);
170 ISB = std::prev(isobusShorcutButtonList.end());
171 }
172
173 if (isobusShorcutButtonList.end() != ISB)
174 {
175 std::uint8_t newTransitionCount = messageData.at(6);
176
177 if (((ISB->stopAllImplementOperationsTransitionNumber == 255) &&
178 (0 != newTransitionCount)) ||
179 ((ISB->stopAllImplementOperationsTransitionNumber < 255) &&
180 (newTransitionCount > ISB->stopAllImplementOperationsTransitionNumber + 1)))
181 {
182 // A Working Set shall consider an increase in the transitions without detecting a corresponding
183 // transition of the Stop all implement operations state as an error and react accordingly.
185 LOG_ERROR("[ISB]: Missed an ISB transition from ISB at address %u", message.get_identifier().get_source_address());
186 }
187 else
188 {
189 ISB->commandedState = static_cast<StopAllImplementOperationsState>(messageData.at(7) & 0x03);
190 }
191 ISB->messageReceivedTimestamp_ms = SystemTiming::get_timestamp_ms();
192 ISB->stopAllImplementOperationsTransitionNumber = messageData.at(6);
193
194 auto newState = get_state();
195 if (previousState != newState)
196 {
198 {
199 LOG_ERROR("[ISB]: All implement operations must stop. (ISB at address %u has commanded it)", message.get_identifier().get_source_address());
200 }
201 else
202 {
203 LOG_INFO("[ISB]: Implement operations now permitted.");
204 }
205 ISBEventDispatcher.call(newState);
206 }
207 }
208 }
209 else
210 {
211 LOG_WARNING("[ISB]: Received malformed All Implements Stop Operations Switch State. DLC must be 8.");
212 }
213 }
214 }
215
217 {
218 std::array<std::uint8_t, CAN_DATA_LENGTH> buffer = {
219 0xFF,
220 0xFF,
221 0xFF,
222 0xFF,
223 0xFF,
224 0xFF,
226 static_cast<std::uint8_t>(0xFC | static_cast<std::uint8_t>(commandedState))
227 };
228
229 return CANNetworkManager::CANNetwork.send_can_message(static_cast<std::uint32_t>(CANLibParameterGroupNumber::AllImplementsStopOperationsSwitchState),
230 buffer.data(),
231 buffer.size(),
233 nullptr,
235 }
236}
General constants used throughout this library.
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::uint8_t get_source_address() const
Returns the source address of the frame encoded in the identifier.
std::uint32_t get_parameter_group_number() const
Returns the PGN encoded in the identifier.
A class that represents a generic CAN message of arbitrary length.
std::uint8_t get_can_port_index() const
Returns the CAN channel index associated with the message.
const std::vector< std::uint8_t > & get_data() const
Gets a reference to the data in the CAN message.
std::uint32_t get_data_length() const
Returns the length of the data in the CAN message.
std::shared_ptr< ControlFunction > get_source_control_function() const
Gets the source control function that the message is from.
CANIdentifier get_identifier() const
Returns the identifier of the message.
void add_global_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parent)
This is how you register a callback for any PGN destined for the global address (0xFF)
static CANNetworkManager CANNetwork
Static singleton of the one network manager. Use this to access stack functionality.
void remove_global_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parent)
This is how you remove a callback for any PGN destined for the global address (0xFF)
bool send_can_message(std::uint32_t parameterGroupNumber, const std::uint8_t *dataBuffer, std::uint32_t dataLength, std::shared_ptr< InternalControlFunction > sourceControlFunction, std::shared_ptr< ControlFunction > destinationControlFunction=nullptr, CANIdentifier::CANPriority priority=CANIdentifier::CANPriority::PriorityDefault6, TransmitCompleteCallback txCompleteCallback=nullptr, void *parentPointer=nullptr, DataChunkCallback frameChunkCallback=nullptr)
This is the main way to send a CAN message of any length.
Stores data about a sender of the stop all implement operations switch state.
NAME ISONAME
The ISONAME of the sender, used as a lookup key.
An interface for communicating as or interpreting the messages of ISOBUS Shortcut Buttons.
ShortcutButtonInterface(std::shared_ptr< InternalControlFunction > internalControlFunction, bool serverEnabled=false)
Constructor for a ShortcutButtonInterface.
bool get_is_initialized() const
Returns if the interface has been initialized.
EventDispatcher< StopAllImplementOperationsState > ISBEventDispatcher
Manages callbacks about ISB states.
bool actAsISBServer
A setting that enables sending the ISB messages rather than just receiving them.
virtual ~ShortcutButtonInterface()
Destructor for a ShortcutButtonInterface.
static constexpr std::uint32_t TRANSMISSION_RATE_MS
The cyclic transmission time for PGN 0xFD02.
std::list< ISBServerData > isobusShorcutButtonList
A list of all senders of the ISB messages used to track transition counts.
TransmitFlags
Enumerates a set of flags that the interface uses to know if it should transmit a message.
@ SendStopAllImplementOperationsSwitchState
A flag to send the main ISB message.
std::shared_ptr< InternalControlFunction > sourceControlFunction
The internal control function that the interface is assigned to and will use to transmit.
EventDispatcher< StopAllImplementOperationsState > & get_stop_all_implement_operations_state_event_dispatcher()
Gets the event dispatcher for when the assigned bus' ISB state changes. The assigned bus is determine...
StopAllImplementOperationsState commandedState
The state set by the user to transmit if we're acting as a server.
void process_message(const CANMessage &message)
A generic way for a protocol to process a received message.
ProcessingFlags txFlags
A set of flags to manage retries while sending messages.
void set_stop_all_implement_operations_state(StopAllImplementOperationsState newState)
Sets the state that the interface will broadcast on the bus.
bool initialized
Stores if the interface has been initialized.
bool send_stop_all_implement_operations_switch_state() const
Sends the Stop all implement operations switch state message.
void initialize()
Used to initialize the interface. Registers for PGNs with the network manager.
StopAllImplementOperationsState get_state() const
Returns the current ISB state for the bus, which is a combination of the internal commanded state and...
std::uint8_t stopAllImplementOperationsTransitionNumber
A counter used to track our transitions from "stop" to "permit" when acting as a server.
static void process_rx_message(const CANMessage &message, void *parentPointer)
Parses incoming CAN messages for the interface.
static void process_flags(std::uint32_t flag, void *parent)
Processes the internal Tx flags.
void update()
This must be called cyclically to update the interface. This processes transmits and timeouts.
StopAllImplementOperationsState
Enumerates the states that can be sent in the main ISB message (pgn 64770, 0xFD02)
@ PermitAllImplementsToOperationOn
Permit all implements to operation ON.
std::uint32_t allImplementsStopOperationsSwitchStateTimestamp_ms
A timestamp to track the need for cyclic transmission of PGN 0xFD02.
Defines an interface for communicating as or from an ISOBUS shortcut button (ISB)....
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.