Skip to content

Commit

Permalink
feat(tp): complete rewrite of transport protocol with unit-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
GwnDaan committed Dec 16, 2023
1 parent a4363d3 commit 721f36c
Show file tree
Hide file tree
Showing 17 changed files with 3,759 additions and 808 deletions.
6 changes: 4 additions & 2 deletions isobus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ set(ISOBUS_SRC
"isobus_maintain_power_interface.cpp"
"isobus_virtual_terminal_objects.cpp"
"nmea2000_message_definitions.cpp"
"nmea2000_message_interface.cpp")
"nmea2000_message_interface.cpp"
"can_message_data.cpp")

# Prepend the source directory path to all the source files
prepend(ISOBUS_SRC ${ISOBUS_SRC_DIR} ${ISOBUS_SRC})
Expand Down Expand Up @@ -82,7 +83,8 @@ set(ISOBUS_INCLUDE
"isobus_maintain_power_interface.hpp"
"isobus_virtual_terminal_objects.hpp"
"nmea2000_message_definitions.hpp"
"nmea2000_message_interface.hpp")
"nmea2000_message_interface.hpp"
"can_message_data.hpp")
# Prepend the include directory path to all the include files
prepend(ISOBUS_INCLUDE ${ISOBUS_INCLUDE_DIR} ${ISOBUS_INCLUDE})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ namespace isobus
ECUtoVirtualTerminal = 0xE700,
Acknowledge = 0xE800,
ParameterGroupNumberRequest = 0xEA00,
TransportProtocolData = 0xEB00,
TransportProtocolCommand = 0xEC00,
TransportProtocolDataTransfer = 0xEB00,
TransportProtocolConnectionManagement = 0xEC00,
AddressClaim = 0xEE00,
ProprietaryA = 0xEF00,
MachineSelectedSpeed = 0xF022,
Expand Down
4 changes: 4 additions & 0 deletions isobus/include/isobus/isobus/can_message.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@

#include "isobus/isobus/can_control_function.hpp"
#include "isobus/isobus/can_identifier.hpp"
#include "isobus/utility/data_span.hpp"

#include <vector>

namespace isobus
{
/// @brief A read-only span of data for a CAN message
using CANDataSpan = DataSpan<const std::uint8_t>;

//================================================================================================
/// @class CANMessage
///
Expand Down
172 changes: 172 additions & 0 deletions isobus/include/isobus/isobus/can_message_data.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//================================================================================================
/// @file can_message_data.hpp
///
/// @brief An interface class that represents data payload of a CAN message of arbitrary length.
/// @author Daan Steenbergen
///
/// @copyright 2023 - The OpenAgriculture Developers
//================================================================================================

#ifndef CAN_MESSAGE_DATA_HPP
#define CAN_MESSAGE_DATA_HPP

#include "isobus/isobus/can_callbacks.hpp"
#include "isobus/isobus/can_control_function.hpp"
#include "isobus/isobus/can_message.hpp"
#include "isobus/utility/data_span.hpp"

#include <cstdint>
#include <memory>
#include <vector>

namespace isobus
{
//================================================================================================
/// @class CANMessageData
///
/// @brief A interface class that represents data payload of a CAN message of arbitrary length.
//================================================================================================
class CANMessageData
{
public:
/// @brief Default destructor.
virtual ~CANMessageData() = default;

/// @brief Get the size of the data.
/// @return The size of the data.
virtual std::size_t size() const = 0;

/// @brief Get the byte at the given index.
/// @param[in] index The index of the byte to get.
/// @return The byte at the given index.
virtual std::uint8_t get_byte(std::size_t index) = 0;

/// @brief If the data isn't owned by this class, make a copy of the data.
/// @param[in] self A pointer to this object.
/// @return A copy of the data if it isn't owned by this class, otherwise a moved pointer.
virtual std::unique_ptr<CANMessageData> copy_if_not_owned(std::unique_ptr<CANMessageData> self) const = 0;
};

//================================================================================================
/// @class CANMessageDataVector
///
/// @brief A class that represents data of a CAN message by holding a vector of bytes.
//================================================================================================
class CANMessageDataVector : public CANMessageData
, public std::vector<std::uint8_t>
{
public:
/// @brief Construct a new CANMessageDataVector object.
/// @param[in] size The size of the data.
explicit CANMessageDataVector(std::size_t size);

/// @brief Construct a new CANMessageDataVector object.
/// @param[in] data The data to copy.
explicit CANMessageDataVector(const std::vector<std::uint8_t> &data);

/// @brief Construct a new CANMessageDataVector object.
/// @param[in] data A pointer to the data to copy.
/// @param[in] size The size of the data to copy.
CANMessageDataVector(const std::uint8_t *data, std::size_t size);

/// @brief Get the size of the data.
/// @return The size of the data.
std::size_t size() const override;

/// @brief Get the byte at the given index.
/// @param[in] index The index of the byte to get.
/// @return The byte at the given index.
std::uint8_t get_byte(std::size_t index) override;

/// @brief Set the byte at the given index.
/// @param[in] index The index of the byte to set.
/// @param[in] value The value to set the byte to.
void set_byte(std::size_t index, std::uint8_t value);

/// @brief Get the data span.
/// @return The data span.
CANDataSpan data() const;

/// @brief If the data isn't owned by this class, make a copy of the data.
/// @param[in] self A pointer to this object.
/// @return A copy of the data if it isn't owned by this class, otherwise it returns itself.
std::unique_ptr<CANMessageData> copy_if_not_owned(std::unique_ptr<CANMessageData> self) const override;
};

//================================================================================================
/// @class CANMessageDataView
///
/// @brief A class that represents data of a CAN message by holding a view of an array of bytes.
/// The view is not owned by this class, it is simply holding a pointer to the array of bytes.
//================================================================================================
class CANMessageDataView : public CANMessageData
, public CANDataSpan
{
public:
/// @brief Construct a new CANMessageDataView object.
/// @param[in] ptr The pointer to the array of bytes.
/// @param[in] len The length of the array of bytes.
CANMessageDataView(const std::uint8_t *ptr, std::size_t len);

/// @brief Get the size of the data.
/// @return The size of the data.
std::size_t size() const override;

/// @brief Get the byte at the given index.
/// @param[in] index The index of the byte to get.
/// @return The byte at the given index.
std::uint8_t get_byte(std::size_t index) override;

/// @brief Get the data span.
/// @return The data span.
CANDataSpan data() const;

/// @brief If the data isn't owned by this class, make a copy of the data.
/// @param[in] self A pointer to this object.
/// @return A copy of the data if it isn't owned by this class, otherwise it returns itself.
std::unique_ptr<CANMessageData> copy_if_not_owned(std::unique_ptr<CANMessageData> self) const override;
};

//================================================================================================
/// @class CANMessageDataCallback
///
/// @brief A class that represents data of a CAN message by using a callback function.
//================================================================================================
class CANMessageDataCallback : public CANMessageData
{
public:
/// @brief Constructor for transport data that uses a callback function.
/// @param[in] size The size of the data.
/// @param[in] callback The callback function to be called for each data chunk.
/// @param[in] parentPointer The parent object that owns this callback (optional).
/// @param[in] chunkSize The size of each data chunk (optional, default is 7).
CANMessageDataCallback(std::size_t size,
DataChunkCallback callback,
void *parentPointer = nullptr,
std::size_t chunkSize = 7);

/// @brief Get the size of the data.
/// @return The size of the data.
std::size_t size() const override;

/// @brief Get the byte at the given index.
/// @param[in] index The index of the byte to get.
/// @return The byte at the given index.
std::uint8_t get_byte(std::size_t index) override;

/// @brief If the data isn't owned by this class, make a copy of the data.
/// @param[in] self A pointer to this object.
/// @return A copy of the data if it isn't owned by this class, otherwise it returns itself.
std::unique_ptr<CANMessageData> copy_if_not_owned(std::unique_ptr<CANMessageData> self) const override;

private:
std::size_t totalSize; ///< The total size of the data.
DataChunkCallback callback; ///< The callback function to be called for each data chunk.
void *parentPointer; ///< The parent object that gets passed to the callback function.
std::vector<std::uint8_t> buffer; ///< The buffer to store the data chunks.
std::size_t bufferSize; ///< The size of the buffer.
std::size_t dataOffset = 0; ///< The offset of the data in the buffer.
};
} // namespace isobus

#endif // CAN_MESSAGE_DATA_HPP
13 changes: 12 additions & 1 deletion isobus/include/isobus/isobus/can_network_configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace isobus
/// @returns The max number of concurrent TP sessions
std::uint32_t get_max_number_transport_protocol_sessions() const;

/// @brief Sets the minimum time to wait between sending BAM frames
/// @brief Sets the minimum time to wait between sending BAM frames (default is 50 ms)
/// @details The acceptable range as defined by ISO-11783 is 10 to 200 ms.
/// This is a minumum time, so if you set it to some value, like 10 ms, the
/// stack will attempt to transmit it as close to that time as it can, but it is
Expand Down Expand Up @@ -73,13 +73,24 @@ namespace isobus
/// @returns The max number of frames to use in transport protocols in each network manager update
std::uint8_t get_max_number_of_network_manager_protocol_frames_per_update() const;

/// @brief Set the the number of packets per CTS message for TP sessions. The default
/// is 16. Note that the receiving control function may not support this limitation, or choose
/// to ignore it and use a different number of packets per CTS packet.
/// @param[in] numberPackets The number of packets per CTS packet for TP sessions.
void set_number_of_packets_per_cts_message(std::uint8_t numberPackets);

/// @brief Get the the number of packets per CTS packet for TP sessions.
/// @returns The number of packets per CTS packet for TP sessions.
std::uint8_t get_number_of_packets_per_cts_message() const;

private:
static constexpr std::uint8_t DEFAULT_BAM_PACKET_DELAY_TIME_MS = 50; ///< The default time between BAM frames, as defined by J1939

std::uint32_t maxNumberTransportProtocolSessions = 4; ///< The max number of TP sessions allowed
std::uint32_t minimumTimeBetweenTransportProtocolBAMFrames = DEFAULT_BAM_PACKET_DELAY_TIME_MS; ///< The configurable time between BAM frames
std::uint8_t extendedTransportProtocolMaxNumberOfFramesPerEDPO = 0xFF; ///< Used to control throttling of ETP sessions.
std::uint8_t networkManagerMaxFramesToSendPerUpdate = 0xFF; ///< Used to control the max number of transport layer frames added to the driver queue per network manager update
std::uint8_t numberOfPacketsPerCTSMessage = 16; ///< The number of packets per CTS message for TP sessions
};
} // namespace isobus

Expand Down
4 changes: 2 additions & 2 deletions isobus/include/isobus/isobus/can_network_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,9 @@ namespace isobus
static constexpr std::uint32_t BUSLOAD_UPDATE_FREQUENCY_MS = 100; ///< Bus load bit accumulation happens over a 100ms window

CANNetworkConfiguration configuration; ///< The configuration for this network manager
ExtendedTransportProtocolManager extendedTransportProtocol; ///< Static instance of the protocol manager
ExtendedTransportProtocolManager extendedTransportProtocol; ///< Instance of the extended transport protocol manager
FastPacketProtocol fastPacketProtocol; ///< Instance of the fast packet protocol
TransportProtocolManager transportProtocol; ///< Static instance of the transport protocol manager
TransportProtocolManager transportProtocol; ///< Instance of the transport protocol manager

std::array<std::deque<std::uint32_t>, CAN_PORT_MAXIMUM> busloadMessageBitsHistory; ///< Stores the approximate number of bits processed on each channel over multiple previous time windows
std::array<std::uint32_t, CAN_PORT_MAXIMUM> currentBusloadBitAccumulator; ///< Accumulates the approximate number of bits processed on each channel during the current time window
Expand Down
Loading

0 comments on commit 721f36c

Please sign in to comment.