Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flexcan fixes + Latest updates #5

Merged
merged 3 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/linting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ jobs:
steps:
- uses: actions/checkout@v3
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
project-type: library
11 changes: 11 additions & 0 deletions src/can_address_claim_state_machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ namespace isobus
return m_currentState;
}

void AddressClaimStateMachine::on_address_violation()
{
if (State::AddressClaimingComplete == get_current_state())
{
CANStackLogger::warn("[AC]: Address violation for address %u",
get_claimed_address());

set_current_state(State::SendReclaimAddressOnRequest);
}
}

void AddressClaimStateMachine::process_commanded_address(std::uint8_t commandedAddress)
{
if (State::AddressClaimingComplete == get_current_state())
Expand Down
5 changes: 5 additions & 0 deletions src/can_address_claim_state_machine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ namespace isobus
/// @returns The current state of the state machine
State get_current_state() const;

/// @brief Used to inform the address claim state machine that two CFs are using the same source address.
/// This function may cause the state machine to emit an address claim depending on its state, as is
/// required by ISO11783-5.
void on_address_violation();

/// @brief Attempts to process a commanded address.
/// @details If the state machine has claimed successfully before,
/// this will attempt to move a NAME from the claimed address to the new, specified address.
Expand Down
2 changes: 1 addition & 1 deletion src/can_extended_transport_protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ namespace isobus
(StateMachineState::RxDataSession == tempSession->state) &&
(messageData[SEQUENCE_NUMBER_DATA_INDEX] == (tempSession->lastPacketNumber + 1)))
{
for (std::uint8_t i = SEQUENCE_NUMBER_DATA_INDEX; (i < PROTOCOL_BYTES_PER_FRAME) && ((PROTOCOL_BYTES_PER_FRAME * tempSession->lastPacketNumber) + i < tempSession->get_message_data_length()); i++)
for (std::uint8_t i = SEQUENCE_NUMBER_DATA_INDEX; (i < PROTOCOL_BYTES_PER_FRAME) && (((PROTOCOL_BYTES_PER_FRAME * tempSession->processedPacketsThisSession) + i) < tempSession->get_message_data_length()); i++)
{
std::uint32_t currentDataIndex = (PROTOCOL_BYTES_PER_FRAME * tempSession->processedPacketsThisSession) + i;
tempSession->sessionMessage.set_data(messageData[1 + SEQUENCE_NUMBER_DATA_INDEX + i], currentDataIndex);
Expand Down
5 changes: 5 additions & 0 deletions src/can_internal_control_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ namespace isobus
return ControlFunction::destroy(expectedRefCount);
}

void InternalControlFunction::on_address_violation(CANLibBadge<CANNetworkManager>)
{
stateMachine.on_address_violation();
}

void InternalControlFunction::process_commanded_address(std::uint8_t commandedAddress, CANLibBadge<CANNetworkManager>)
{
stateMachine.process_commanded_address(commandedAddress);
Expand Down
4 changes: 4 additions & 0 deletions src/can_internal_control_function.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ namespace isobus
/// @param[in] CANPort The CAN channel index for this control function to use
InternalControlFunction(NAME desiredName, std::uint8_t preferredAddress, std::uint8_t CANPort, CANLibBadge<InternalControlFunction>);

/// @brief Used to inform the member address claim state machine that two CFs are using the same source address.
/// @note Address violation occurs when two CFs are using the same source address.
void on_address_violation(CANLibBadge<CANNetworkManager>);

/// @brief Used by the network manager to tell the ICF that the address claim state machine needs to process
/// a J1939 command to move address.
void process_commanded_address(std::uint8_t commandedAddress, CANLibBadge<CANNetworkManager>);
Expand Down
26 changes: 26 additions & 0 deletions src/can_network_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,11 @@ namespace isobus
return configuration;
}

EventDispatcher<std::shared_ptr<InternalControlFunction>> &CANNetworkManager::get_address_violation_event_dispatcher()
{
return addressViolationEventDispatcher;
}

bool CANNetworkManager::add_protocol_parameter_group_number_callback(std::uint32_t parameterGroupNumber, CANLibCallback callback, void *parentPointer)
{
bool retVal = false;
Expand Down Expand Up @@ -840,6 +845,26 @@ namespace isobus
}
}

void CANNetworkManager::process_can_message_for_address_violations(const CANMessage &currentMessage)
{
auto sourceAddress = currentMessage.get_identifier().get_source_address();

if ((BROADCAST_CAN_ADDRESS != sourceAddress) &&
(NULL_CAN_ADDRESS != sourceAddress))
{
for (auto &internalCF : internalControlFunctions)
{
if ((nullptr != internalCF) &&
(internalCF->get_address() == sourceAddress) &&
(currentMessage.get_can_port_index() == internalCF->get_can_port()))
{
internalCF->on_address_violation({});
addressViolationEventDispatcher.call(internalCF);
}
}
}
}

void CANNetworkManager::process_control_function_state_change_callback(std::shared_ptr<ControlFunction> controlFunction, ControlFunctionState state)
{
#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
Expand Down Expand Up @@ -937,6 +962,7 @@ namespace isobus
CANMessage currentMessage = get_next_can_message_from_rx_queue();

update_address_table(currentMessage);
process_can_message_for_address_violations(currentMessage);

// Update Special Callbacks, like protocols and non-cf specific ones
process_protocol_pgn_callbacks(currentMessage);
Expand Down
14 changes: 14 additions & 0 deletions src/can_network_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "can_network_configuration.hpp"
#include "can_transport_protocol.hpp"
#include "nmea2000_fast_packet_protocol.hpp"
#include "event_dispatcher.hpp"

#include <array>
#include <deque>
Expand Down Expand Up @@ -175,6 +176,11 @@ namespace isobus
/// @returns The configuration class for this network manager
CANNetworkConfiguration &get_configuration();

/// @brief Returns the network manager's event dispatcher for notifying consumers whenever an
/// address violation occurs involving an internal control function.
/// @returns An event dispatcher which can be used to get notified about address violations
EventDispatcher<std::shared_ptr<InternalControlFunction>> &get_address_violation_event_dispatcher();

protected:
// Using protected region to allow protocols use of special functions from the network manager
friend class AddressClaimStateMachine; ///< Allows the network manager to work closely with the address claiming process
Expand Down Expand Up @@ -289,6 +295,13 @@ namespace isobus
/// @param[in] currentMessage The message to process
void process_any_control_function_pgn_callbacks(const CANMessage &currentMessage);

/// @brief Validates that a CAN message has not caused an address violation.
/// If a violation is found, the network manager will notify the affected address claim state machine
/// to re-claim as is required by ISO 11783-5, and will attempt to activate a DTC that is defined in ISO 11783-5.
/// @note Address violation occurs when two CFs are using the same source address.
/// @param[in] currentMessage The message to process
void process_can_message_for_address_violations(const CANMessage &currentMessage);

/// @brief Checks the control function state callback list to see if we need to call
/// a control function state callback.
/// @param[in] controlFunction The controlFunction whose state has changed
Expand Down Expand Up @@ -361,6 +374,7 @@ namespace isobus
std::list<ControlFunctionStateCallback> controlFunctionStateCallbacks; ///< List of all control function state callbacks
std::vector<ParameterGroupNumberCallbackData> globalParameterGroupNumberCallbacks; ///< A list of all global PGN callbacks
std::vector<ParameterGroupNumberCallbackData> anyControlFunctionParameterGroupNumberCallbacks; ///< A list of all global PGN callbacks
EventDispatcher<std::shared_ptr<InternalControlFunction>> addressViolationEventDispatcher; // An event dispatcher for notifying consumers about address violations
#if !defined CAN_STACK_DISABLE_THREADS && !defined ARDUINO
std::mutex receiveMessageMutex; ///< A mutex for receive messages thread safety
std::mutex protocolPGNCallbacksMutex; ///< A mutex for PGN callback thread safety
Expand Down
11 changes: 6 additions & 5 deletions src/flex_can_t4_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
namespace isobus
{
#if defined(__IMXRT1062__)
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_256> FlexCANT4Plugin::can0;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_256> FlexCANT4Plugin::can1;
FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_256> FlexCANT4Plugin::can2;
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_512> FlexCANT4Plugin::can0;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_512> FlexCANT4Plugin::can1;
FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_512> FlexCANT4Plugin::can2;
#elif defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_256> FlexCANT4Plugin::can0;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_256> FlexCANT4Plugin::can1;
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_512> FlexCANT4Plugin::can0;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_512> FlexCANT4Plugin::can1;
#endif

FlexCANT4Plugin::FlexCANT4Plugin(std::uint8_t channel) :
Expand Down Expand Up @@ -104,6 +104,7 @@ namespace isobus
message.id = canFrame.identifier;
message.len = canFrame.dataLength;
message.flags.extended = true;
message.seq = 1; // Try to get messages to go out sequentially...
memcpy(message.buf, canFrame.data, canFrame.dataLength);

if (0 == selectedChannel)
Expand Down
10 changes: 5 additions & 5 deletions src/flex_can_t4_plugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ namespace isobus

private:
#if defined(__IMXRT1062__)
static FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_256> can0;
static FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_256> can1;
static FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_256> can2;
static FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_512> can0;
static FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_512> can1;
static FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_512> can2;
#elif defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
static FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_256> can0;
static FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_256> can1;
static FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_512> can0;
static FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_512> can1;
#endif
std::uint8_t selectedChannel;
bool isOpen = false;
Expand Down
11 changes: 6 additions & 5 deletions src/isobus_device_descriptor_object_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -542,14 +542,15 @@ namespace isobus
std::string deviceElementDesignator;
std::uint16_t parentObject = static_cast<std::uint16_t>(static_cast<std::uint16_t>(binaryPool[9 + numberDesignatorBytes]) | (static_cast<std::uint16_t>(binaryPool[10 + numberDesignatorBytes]) << 8));
std::uint16_t uniqueID = static_cast<std::uint16_t>(static_cast<std::uint16_t>(binaryPool[3]) | (static_cast<std::uint16_t>(binaryPool[4]) << 8));
std::uint16_t elementNumber = static_cast<std::uint16_t>(binaryPool[7 + numberDesignatorBytes]) | (static_cast<std::uint16_t>(binaryPool[8 + numberDesignatorBytes]) << 8);
auto type = static_cast<task_controller_object::DeviceElementObject::Type>(binaryPool[5]);

for (std::uint16_t i = 0; i < numberDesignatorBytes; i++)
{
deviceElementDesignator.push_back(binaryPool[7 + i]);
}

if (add_device_element(deviceElementDesignator, binaryPool[7 + numberDesignatorBytes], parentObject, type, uniqueID))
if (add_device_element(deviceElementDesignator, elementNumber, parentObject, type, uniqueID))
{
auto DETObject = std::static_pointer_cast<task_controller_object::DeviceElementObject>(get_object_by_id(uniqueID));

Expand Down Expand Up @@ -975,8 +976,8 @@ namespace isobus
}
else if (task_controller_object::ObjectTypes::DeviceValuePresentation != child->get_object_type())
{
CANStackLogger::error("[DDOP]: Object %u has a child %u with an object type that is not allowed." +
currentProcessData->get_device_value_presentation_object_id(),
CANStackLogger::error("[DDOP]: Object %u has a child %u with an object type that is not allowed.",
currentProcessData->get_device_value_presentation_object_id(),
child->get_object_id());
CANStackLogger::error("[DDOP]: A DPD object may only have DVP children.");
retVal = false;
Expand All @@ -1003,8 +1004,8 @@ namespace isobus
}
else if (task_controller_object::ObjectTypes::DeviceValuePresentation != child->get_object_type())
{
CANStackLogger::error("[DDOP]: Object %u has a child %u with an object type that is not allowed." +
currentProperty->get_device_value_presentation_object_id(),
CANStackLogger::error("[DDOP]: Object %u has a child %u with an object type that is not allowed.",
currentProperty->get_device_value_presentation_object_id(),
child->get_object_id());
CANStackLogger::error("[DDOP]: A DPT object may only have DVP children.");
retVal = false;
Expand Down
18 changes: 18 additions & 0 deletions src/isobus_diagnostic_protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace isobus
CANNetworkManager::CANNetwork.add_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::DiagnosticMessage22), process_message, this);
CANNetworkManager::CANNetwork.add_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::DiagnosticMessage13), process_message, this);
CANNetworkManager::CANNetwork.add_global_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::DiagnosticMessage13), process_message, this);
addressViolationEventHandle = CANNetworkManager::CANNetwork.get_address_violation_event_dispatcher().add_listener([this](std::shared_ptr<InternalControlFunction> affectedCF) { this->on_address_violation(affectedCF); });

if (auto requestProtocol = myControlFunction->get_pgn_request_protocol().lock())
{
Expand Down Expand Up @@ -148,6 +149,7 @@ namespace isobus
CANNetworkManager::CANNetwork.remove_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::DiagnosticMessage22), process_message, this);
CANNetworkManager::CANNetwork.remove_protocol_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::DiagnosticMessage13), process_message, this);
CANNetworkManager::CANNetwork.remove_global_parameter_group_number_callback(static_cast<std::uint32_t>(CANLibParameterGroupNumber::DiagnosticMessage13), process_message, this);
addressViolationEventHandle.reset();
}
}

Expand Down Expand Up @@ -605,6 +607,22 @@ namespace isobus
}
}

void DiagnosticProtocol::on_address_violation(std::shared_ptr<InternalControlFunction> affectedControlFunction)
{
if ((nullptr != affectedControlFunction) &&
(!get_j1939_mode()) &&
(BROADCAST_CAN_ADDRESS != affectedControlFunction->get_address()) &&
(NULL_CAN_ADDRESS != affectedControlFunction->get_address()))
{
constexpr std::uint32_t ADDRESS_VIOLATION_SPN_BASE = 2000; // Defined in ISO 11783-5 section 4.4.4.3

set_diagnostic_trouble_code_active(DiagnosticTroubleCode(ADDRESS_VIOLATION_SPN_BASE + affectedControlFunction->get_address(),
FailureModeIdentifier::ConditionExists,
LampStatus::None),
true);
}
}

bool DiagnosticProtocol::send_diagnostic_message_1() const
{
bool retVal = false;
Expand Down
9 changes: 6 additions & 3 deletions src/isobus_diagnostic_protocol.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,9 +391,6 @@ namespace isobus
/// @returns The two bit lamp state for CAN
std::uint8_t convert_flash_state_to_byte(FlashState flash) const;

/// @brief A utility function that will clean up PGN registrations
void deregister_all_pgns();

/// @brief This is a way to find the overall lamp states to report
/// @details This searches the active DTC list to find if a lamp is on or off, and to find the overall flash state for that lamp.
/// Basically, since the lamp states are global to the CAN message, we need a way to resolve the "total" lamp state from the list.
Expand All @@ -410,6 +407,11 @@ namespace isobus
/// @param[out] lampOn If the lamp state is on for any DTC
void get_inactive_list_lamp_state_and_flash_state(Lamps targetLamp, FlashState &flash, bool &lampOn) const;

/// @brief A callback function used to consume address violation events and activate a DTC
/// as required in ISO11783-5.
/// @param[in] affectedControlFunction The control function affected by an address violation
void on_address_violation(std::shared_ptr<InternalControlFunction> affectedControlFunction);

/// @brief Sends a DM1 encoded CAN message
/// @returns true if the message was sent, otherwise false
bool send_diagnostic_message_1() const;
Expand Down Expand Up @@ -488,6 +490,7 @@ namespace isobus
static void process_flags(std::uint32_t flag, void *parentPointer);

std::shared_ptr<InternalControlFunction> myControlFunction; ///< The internal control function that this protocol will send from
std::shared_ptr<void> addressViolationEventHandle; ///< Stores the handle from registering for address violation events
NetworkType networkType; ///< The diagnostic network type that this protocol will use
std::vector<DiagnosticTroubleCode> activeDTCList; ///< Keeps track of all the active DTCs
std::vector<DiagnosticTroubleCode> inactiveDTCList; ///< Keeps track of all the previously active DTCs
Expand Down