Move CAN interface to STA Core library

This commit is contained in:
Henrik Stickann 2022-05-09 21:25:44 +02:00
parent 92e3dd474b
commit e2854fceee
7 changed files with 529 additions and 0 deletions

View File

@ -0,0 +1,100 @@
/**
* @file
* @brief CAN controller driver interface.
*/
#ifndef STA_INTF_CAN_CONTROLLER_HPP
#define STA_INTF_CAN_CONTROLLER_HPP
/**
* @defgroup can CAN
* @brief CAN Controller interface definition.
*/
/**
* @defgroup canAPI API
* @ingroup can
* @brief Public library interface.
*/
/**
* @defgroup canBuildConfig Build config
* @ingroup can
* @brief Build configuration options.
*/
#include <sta/intf/can/filter.hpp>
#include <sta/intf/can/headers.hpp>
namespace sta
{
/**
* @brief CAN controller driver interface.
*
* @ingroup canAPI
*/
class CanController
{
public:
// RX/TX
//
/**
* @brief Send frame to CAN controller for transmission.
*
* @param header CAN frame TX header
* @param payload CAN frame payload
* @return True on success
*/
virtual bool sendFrame(const CanTxHeader & header, const uint8_t * payload) = 0;
/**
* @brief Get received frame from the CAN controller.
*
* @param[in] fifo FIFO storing frame
* @param[out] header CAN frame RX header destination
* @param[out] payload CAN frame payload destination
* @return True on success
*/
virtual bool receiveFrame(uint8_t fifo, CanRxHeader * header, uint8_t * payload) = 0;
/**
* @brief Get RX FIFO flags.
*
* @return FIFO flags
*/
virtual uint32_t getRxFifoFlags() = 0;
// RX filter
//
/**
* @brief Change filter settings.
*
* @param idx Filter index
* @param filter Filter configuration
* @param active Enable filter after applying settings
*/
virtual void configureFilter(uint8_t idx, const CanFilter & filter, bool active = false) = 0;
/**
* @brief Enable filter.
*
* @param idx Filter index
*/
virtual void enableFilter(uint8_t idx) = 0;
/**
* @brief Disable filter.
*
* @param idx Filter index
*/
virtual void disableFilter(uint8_t idx) = 0;
/**
* @brief Disable and clear all filters.
*/
virtual void clearFilters() = 0;
};
} // namespace sta
#endif // STA_INTF_CAN_CONTROLLER_HPP

View File

@ -0,0 +1,49 @@
/**
* @file
* @brief CAN message filter types.
*/
#ifndef STA_INFT_CAN_FILTER_HPP
#define STA_INFT_CAN_FILTER_HPP
#include <sta/intf/can/id.hpp>
#include <cstdint>
namespace sta
{
/**
* @defgroup canFilter Filters
* @ingroup canAPI
* @brief CAN message filter types.
*/
/**
* @brief ID format matched by CAN filter.
*
* @ingroup canFilter
*/
enum class CanFilterIdFormat
{
ANY, /**< Match both ID formats */
STD, /**< Match standard format IDs */
EXT /**< Match extended format IDs */
};
/**
* @brief CAN filter settings.
*
* @ingroup canFilter
*/
struct CanFilter
{
CanId obj; /**< ID object */
CanId mask; /**< ID mask */
CanFilterIdFormat type; /**< ID format to match */
uint8_t fifo; /**< FIFO to store matches */
};
} // namespace sta
#endif // STA_INFT_CAN_FILTER_HPP

View File

@ -0,0 +1,48 @@
/**
* @file
* @brief CAN frame headers.
*/
#ifndef STA_INTF_CAN_HEADERS_HPP
#define STA_INTF_CAN_HEADERS_HPP
#include <sta/intf/can/id.hpp>
#include <cstdint>
namespace sta
{
/**
* @defgroup canHeader Frame headers
* @ingroup canAPI
* @brief CAN header types for transmitted / received frames.
*/
/**
* @brief CAN TX frame header.
*
* @ingroup canHeader
*/
struct CanTxHeader
{
CanFrameId id; /**< Frame ID */
uint8_t payloadLength; /**< Size of data to send */
};
/**
* @brief CAN RX frame header.
*
* @ingroup canHeader
*/
struct CanRxHeader
{
CanFrameId id; /**< Frame ID */
uint8_t payloadLength; /**< Size of received data */
uint32_t timestamp; /**< RX timestamp */
uint8_t filter; /**< RX filter match */
};
} // namespace sta
#endif // STA_INTF_CAN_HEADERS_HPP

View File

@ -0,0 +1,82 @@
/**
* @file
* @brief CAN frame ID types.
*/
#ifndef STA_INTF_CAN_ID_HPP
#define STA_INTF_CAN_ID_HPP
#include <cstdint>
namespace sta
{
/**
* @defgroup canID Frame IDs
* @ingroup canAPI
* @brief Types for working with CAN ID values and formats.
*/
/**
* @brief CAN frame ID format.
*
* @ingroup canID
*/
enum class CanIdFormat : uint8_t
{
STD, /**< Standard format */
EXT /**< Extended format */
};
/**
* @brief CAN frame ID.
*
* @ingroup canID
*/
struct CanId
{
uint32_t sid; /**< Standard ID field (11 bits) */
uint32_t eid; /**< Extended ID field (18 bits) */
};
/**
* @brief CAN frame ID and format.
*
* @ingroup canID
*/
struct CanFrameId
{
CanIdFormat format; /**< ID format */
uint32_t sid; /**< Standard ID field (11 bits) */
uint32_t eid; /**< Extended ID field (18 bits) */
};
// Comparison operators
//
bool operator ==(const CanId & lhs, const CanId & rhs);
bool operator !=(const CanId & lhs, const CanId & rhs);
bool operator ==(const CanFrameId & lhs, const CanFrameId & rhs);
bool operator !=(const CanFrameId & lhs, const CanFrameId & rhs);
} // namespace sta
/**
* @brief Maximum CAN standard ID value.
*
* @ingroup canID
*/
#define CAN_SID_MAX UINT32_C(0x7FF)
/**
* @brief Maximum CAN extended ID value.
*
* @ingroup canID
*/
#define CAN_EID_MAX UINT32_C(0x3FFFF)
#endif // STA_INTF_CAN_ID_HPP

View File

@ -0,0 +1,104 @@
/**
* @file
* @brief Subscription interface for CAN controller drivers.
*/
#ifndef STA_INTF_CAN_SUBSCRIBABLE_HPP
#define STA_INTF_CAN_SUBSCRIBABLE_HPP
#include <sta/intf/can/filter.hpp>
#include <sta/intf/can/headers.hpp>
namespace sta
{
/**
* @defgroup canSub Subscription
* @ingroup canAPI
* @brief Subscription interface for CAN controller drivers.
*/
/**
* @brief Callback for handling received frames.
*
* @param header Frame header
* @param buffer Frame payload buffer
*
* @ingroup canSub
*/
using CanRxCallback = void (*) (const CanRxHeader & header, const uint8_t * buffer);
/**
* @brief Filter configuration and message handler.
*
* @ingroup canSub
*/
struct CanFilterConfig
{
CanFilter filter; /**< Filter handled by callback */
CanRxCallback callback; /**< Callback for message handling */
};
/**
* @brief CAN controller with subscriptions.
*
* @tparam T Implementation of CanController interface
*
* @ingroup canSub
*/
template <typename T>
class SubscribableCanController : public T
{
public:
using T::T;
// Subscriptions
//
/**
* @brief Subscribe to specific message types.
*
* @param subscriptions Array of message filters and handlers
* @param num Number of array entries
*/
bool subscribe(const CanFilterConfig * subscriptions, uint8_t num);
/**
* @brief Subscribe to all messages.
*
* @param callback Called when message is received
* @param fifo FIFO used for received messages
*/
void subscribeAll(CanRxCallback callback, uint8_t fifo);
/**
* @brief Unsubscribe from all messages.
*
* No more messages will be received.
*/
void unsubscribeAll();
/**
* @brief Read message from RX FIFO and notify subscriber.
*/
void receiveAndNotify(uint8_t fifo);
/**
* @brief Process pending frames from RX FIFOs.
*/
void processMessages();
private:
CanRxCallback filterCallbacks_[T::MAX_FILTER_COUNT]; /**< Callbacks for RX filters */
};
} // namespace sta
#include <sta/intf/can/subscribable.tpp>
#endif // STA_INTF_CAN_SUBSCRIBABLE_HPP

View File

@ -0,0 +1,120 @@
/**
* @brief Implementation of template class CanController<T>.
*/
#ifndef STA_INTF_CAN_SUBSCRIBABLE_TPP
#define STA_INTF_CAN_SUBSCRIBABLE_TPP
#ifndef STA_INTF_CAN_SUBSCRIBABLE_HPP
#error "Direct use of internal header. Use <sta/intf/can/subscribable.hpp> instead"
#endif // !STA_INTF_CAN_SUBSCRIBABLE_HPP
#ifndef STA_STDLIB_DISABLE
# include <algorithm> // fill_n
#endif // !STA_STDLIB_DISABLE
namespace sta
{
template <typename T>
bool SubscribableCanController<T>::subscribe(const CanFilterConfig * subscriptions, uint8_t num)
{
// Check bounds
if (num > T::MAX_FILTER_COUNT)
return false;
// Clear previous subscriptions
unsubscribeAll();
for (uint8_t i = 0; i < num; ++i)
{
// Save handler callback
filterCallbacks_[i] = subscriptions[i].callback;
// Configure and enable filter
T::configureFilter(i, subscriptions[i].filter, true);
}
return true;
}
template <typename T>
void SubscribableCanController<T>::subscribeAll(CanRxCallback callback, uint8_t fifo)
{
uint8_t filterIdx = 0;
// Clear previous subscriptions
unsubscribeAll();
// Setup default filter
CanFilter filter{};
filter.type = CanFilterIdFormat::ANY;
filter.fifo = fifo;
// Store callback
filterCallbacks_[filterIdx] = callback;
// Configure and enable default filter
T::configureFilter(filterIdx, filter, true);
}
template <typename T>
void SubscribableCanController<T>::unsubscribeAll()
{
// Disable all filters
T::clearFilters();
// Clear filter callbacks
#ifndef STA_STDLIB_DISABLE
std::fill_n(filterCallbacks_, T::MAX_FILTER_COUNT, nullptr);
#else // STA_STDLIB_DISABLE
for (uint8_t i = 0; i < T::MAX_FILTER_COUNT; ++i)
{
filterCallbacks_[i] = nullptr;
}
#endif // STA_STDLIB_DISABLE
}
template <typename T>
void SubscribableCanController<T>::receiveAndNotify(uint8_t fifo)
{
CanRxHeader header;
uint8_t payload[T::MAX_PAYLOAD_SIZE];
if (T::receiveFrame(fifo, &header, payload))
{
//displayFrameUART(frame);
// Forward frame to filter callback
if (fifo <= T::MAX_FILTER_COUNT && filterCallbacks_[header.filter])
{
filterCallbacks_[header.filter](header, payload);
}
}
}
template <typename T>
void SubscribableCanController<T>::processMessages()
{
// Read RX interrupt flags
uint32_t RFIF = T::getRxFifoFlags();
if (RFIF != 0)
{
// Check all flags
for (uint8_t fifo = 0; fifo < T::MAX_FIFO_COUNT; ++fifo)
{
// Process messages if flag is set
if (RFIF & 0x1)
{
receiveAndNotify(fifo);
}
// Shift next RX flag to LSB
RFIF >>= 1;
}
}
}
} // namespace sta
#endif // STA_INTF_CAN_SUBSCRIBABLE_TPP

26
src/can/id.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <sta/intf/can/id.hpp>
namespace sta
{
bool operator ==(const CanId & lhs, const CanId & rhs)
{
return (lhs.sid == rhs.sid && lhs.eid == rhs.eid);
}
bool operator !=(const CanId & lhs, const CanId & rhs)
{
return !(lhs == rhs);
}
bool operator ==(const CanFrameId & lhs, const CanFrameId & rhs)
{
return (lhs.format == rhs.format && lhs.sid == rhs.sid && lhs.eid == rhs.eid);
}
bool operator !=(const CanFrameId & lhs, const CanFrameId & rhs)
{
return !(lhs == rhs);
}
} // namespace sta