Multiple frames implementation (#2)
* Add rx event handlers * Fix compile errors and add constness * Pass sender id * Change api interface * Revert changes * Add filter fifo * Add default setup * Add receive function * Remove interrupt activation * Activate RX interrupts * Merge remote changes * Add event list constructor * Fix compilation bug * Send and receive multiple frames * Refactor * Refactor * Fix compile error * Use known syntax * Refactor * Provide storage * Add frame end * Add some documentation * Turn macros into functions * Refactor * Refactor * Fix compile error * Use ExtendedIds Co-authored-by: Riccardo998 <riccardo.storchi98@gmail.com>
This commit is contained in:
committed by
GitHub
parent
90d1836dfa
commit
7b09401b00
+44
-14
@@ -6,6 +6,7 @@
|
|||||||
#include "mmr_can_includes.h"
|
#include "mmr_can_includes.h"
|
||||||
#include "mmr_can_types.h"
|
#include "mmr_can_types.h"
|
||||||
#include "mmr_can_optimize.h"
|
#include "mmr_can_optimize.h"
|
||||||
|
#include "mmr_can_binary_literals.h"
|
||||||
|
|
||||||
#ifndef MMR_CAN_RX_FIFO
|
#ifndef MMR_CAN_RX_FIFO
|
||||||
#define MMR_CAN_RX_FIFO CAN_RX_FIFO0
|
#define MMR_CAN_RX_FIFO CAN_RX_FIFO0
|
||||||
@@ -23,15 +24,11 @@
|
|||||||
#define MMR_CAN_RX_INTERRUPT CAN_IT_RX_FIFO1_MSG_PENDING
|
#define MMR_CAN_RX_INTERRUPT CAN_IT_RX_FIFO1_MSG_PENDING
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MMR_CAN_ID
|
#ifndef MMR_CAN_MAX_DATA_LENGTH
|
||||||
#define MMR_CAN_ID 0x103
|
#define MMR_CAN_MAX_DATA_LENGTH 8
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MMR_CAN_BUFFER_LEN
|
typedef uint8_t CanRxBuffer[MMR_CAN_MAX_DATA_LENGTH];
|
||||||
#define MMR_CAN_BUFFER_LEN 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef uint8_t CanRxBuffer[MMR_CAN_BUFFER_LEN];
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -47,7 +44,10 @@ typedef struct {
|
|||||||
* The filter bank to use
|
* The filter bank to use
|
||||||
*
|
*
|
||||||
* In systems with more than one CAN interface,
|
* In systems with more than one CAN interface,
|
||||||
* this must go from 0 to slaveBankStart.
|
* this must go from 0 to slaveBankStart for the master CAN
|
||||||
|
* and from slaveBankStart to 27 for the slave CAN
|
||||||
|
*
|
||||||
|
* Master CAN is usually CAN1, while slave CAN is CAN2
|
||||||
*/
|
*/
|
||||||
CanFilterBank bank;
|
CanFilterBank bank;
|
||||||
|
|
||||||
@@ -63,13 +63,8 @@ typedef struct {
|
|||||||
CanFilterMask idMask;
|
CanFilterMask idMask;
|
||||||
} MmrCanFilterSettings;
|
} MmrCanFilterSettings;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/**
|
|
||||||
* The id of the CAN interface that will receive the packet.
|
|
||||||
*
|
|
||||||
* If you are using the CANbus in loopback mode, it can be the
|
|
||||||
* id that the sender is using.
|
|
||||||
*/
|
|
||||||
CanId remoteId;
|
CanId remoteId;
|
||||||
CanMailbox *mailbox;
|
CanMailbox *mailbox;
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
@@ -77,13 +72,48 @@ typedef struct {
|
|||||||
} MmrCanPacket;
|
} MmrCanPacket;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* These values can be appended to the extended-id
|
||||||
|
* portion of the CAN bus message (that is, the lower 5 bits
|
||||||
|
* of the standard id)
|
||||||
|
*
|
||||||
|
* They are used to check if a message is either standalone
|
||||||
|
* or split into multiple frames
|
||||||
|
*
|
||||||
|
* Multi-frame messages have a higher priority over normal ones
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
MMR_CAN_MESSAGE_TYPE_MULTI_FRAME = B_(0010),
|
||||||
|
MMR_CAN_MESSAGE_TYPE_MULTI_FRAME_END = B_(0011),
|
||||||
|
MMR_CAN_MESSAGE_TYPE_NORMAL = B_(1000),
|
||||||
|
} MmrCanMessageType;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Represents a CAN message
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
CanId senderId;
|
||||||
|
void *store;
|
||||||
|
} MmrCanMessage;
|
||||||
|
|
||||||
|
|
||||||
#define MMR_CAN_FilterConfigDefault(phcan) \
|
#define MMR_CAN_FilterConfigDefault(phcan) \
|
||||||
MMR_CAN_FilterConfig(phcan, MMR_CAN_GetDefaultFilterSettings())
|
MMR_CAN_FilterConfig(phcan, MMR_CAN_GetDefaultFilterSettings())
|
||||||
|
|
||||||
|
|
||||||
|
HalStatus MMR_CAN_BasicSetupAndStart(CanHandle *hcan);
|
||||||
HalStatus MMR_CAN_FilterConfig(CanHandle *hcan, MmrCanFilterSettings settings);
|
HalStatus MMR_CAN_FilterConfig(CanHandle *hcan, MmrCanFilterSettings settings);
|
||||||
CanFilterMask MMR_CAN_AlignStandardMask(CanFilterMask baseMask);
|
CanFilterMask MMR_CAN_AlignStandardMask(CanFilterMask baseMask);
|
||||||
MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings();
|
MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings();
|
||||||
|
|
||||||
HalStatus MMR_CAN_Send(CanHandle *hcan, MmrCanPacket packet);
|
HalStatus MMR_CAN_Send(CanHandle *hcan, MmrCanPacket packet);
|
||||||
|
HalStatus MMR_CAN_Receive(CanHandle *hcan, MmrCanMessage *result);
|
||||||
|
|
||||||
|
|
||||||
|
bool MMR_CAN_IsMultiFrame(CanRxHeader *header);
|
||||||
|
bool MMR_CAN_IsMultiFrameEnd(CanRxHeader *header);
|
||||||
|
|
||||||
#endif /* INC_MMR_CAN_H_ */
|
#endif /* INC_MMR_CAN_H_ */
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
#ifndef INC_MMR_CAN_BINARY_LITERALS_H_
|
||||||
|
#define INC_MMR_CAN_BINARY_LITERALS_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* These set of macros (B_, B8_, B16_, B32_) allow one
|
||||||
|
* to convert bit literals to their hexadecimal representation
|
||||||
|
*
|
||||||
|
* They are useful when it is needed to convey exactly which bits
|
||||||
|
* are being set for a particular register, message etc...
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* B_(1010) = 0xA
|
||||||
|
* B8_(1111, 1111) = 0xFF
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------
|
||||||
|
* Macros taken from https://stackoverflow.com/a/7577517 and
|
||||||
|
* sligthly readapted
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __B_0000 0
|
||||||
|
#define __B_0001 1
|
||||||
|
#define __B_0010 2
|
||||||
|
#define __B_0011 3
|
||||||
|
#define __B_0100 4
|
||||||
|
#define __B_0101 5
|
||||||
|
#define __B_0110 6
|
||||||
|
#define __B_0111 7
|
||||||
|
#define __B_1000 8
|
||||||
|
#define __B_1001 9
|
||||||
|
#define __B_1010 a
|
||||||
|
#define __B_1011 b
|
||||||
|
#define __B_1100 c
|
||||||
|
#define __B_1101 d
|
||||||
|
#define __B_1110 e
|
||||||
|
#define __B_1111 f
|
||||||
|
|
||||||
|
#define __B2H(bits) __B_ ## bits
|
||||||
|
#define _B2H(bits) __B2H(bits)
|
||||||
|
#define __HEX(n) 0x ## n
|
||||||
|
#define _HEX(n) __HEX(n)
|
||||||
|
#define __CCAT(a,b) a ## b
|
||||||
|
#define _CCAT(a,b) __CCAT(a,b)
|
||||||
|
|
||||||
|
#define B_(a) _HEX(_B2H(a))
|
||||||
|
#define B8_(a, b) _HEX(_CCAT(_B2H(a), _B2H(b)))
|
||||||
|
#define B16_(a, b, c, d) \
|
||||||
|
_HEX(_CCAT( \
|
||||||
|
_CCAT(_B2H(a), _B2H(b)), \
|
||||||
|
_CCAT(_B2H(c), _B2H(d)) \
|
||||||
|
))
|
||||||
|
|
||||||
|
#define B32_(a, b, c, d, e, f, g, h) \
|
||||||
|
_HEX(_CCAT( \
|
||||||
|
_CCAT( \
|
||||||
|
_CCAT(_B2H(a), _B2H(b)), \
|
||||||
|
_CCAT(_B2H(c),_B2H(d))), \
|
||||||
|
_CCAT( \
|
||||||
|
_CCAT(_B2H(e), _B2H(f)), \
|
||||||
|
_CCAT(_B2H(g), _B2H(h)) \
|
||||||
|
) \
|
||||||
|
))
|
||||||
|
|
||||||
|
#endif /* INC_MMR_CAN_BINARY_LITERALS_H_ */
|
||||||
@@ -2,21 +2,19 @@
|
|||||||
#define INC_MMR_CAN_EVENTS_H_
|
#define INC_MMR_CAN_EVENTS_H_
|
||||||
|
|
||||||
#include "mmr_can.h"
|
#include "mmr_can.h"
|
||||||
|
#include "mmr_can_util.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef void (*MmrCanEventHandler)(const MmrCanMessage *event);
|
||||||
CanId senderId;
|
|
||||||
uint8_t *message;
|
|
||||||
} MmrCanEvent;
|
|
||||||
|
|
||||||
typedef void (*MmrCanEventHandler)(MmrCanEvent *event);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const MmrCanEventHandler *handlers;
|
const MmrCanEventHandler *handlers;
|
||||||
const size_t count;
|
const size_t count;
|
||||||
} MmrCanEventList;
|
} MmrCanEventList;
|
||||||
|
|
||||||
|
#define MMR_CAN_CreateEventList(handlers) \
|
||||||
|
(const MmrCanEventList) { handlers, sizeofarray(handlers) }
|
||||||
|
|
||||||
void MMR_CAN_InitRxHandlers(const MmrCanEventList *rxEvents);
|
HalStatus MMR_CAN_InitRxHandlers(CanHandle *hcan, const MmrCanEventList *rxEvents);
|
||||||
|
|
||||||
|
|
||||||
#endif /* INC_MMR_CAN_EVENTS_H_ */
|
#endif /* INC_MMR_CAN_EVENTS_H_ */
|
||||||
|
|||||||
@@ -35,5 +35,6 @@ typedef HAL_StatusTypeDef HalStatus;
|
|||||||
typedef CAN_HandleTypeDef CanHandle;
|
typedef CAN_HandleTypeDef CanHandle;
|
||||||
typedef CAN_RxHeaderTypeDef CanRxHeader;
|
typedef CAN_RxHeaderTypeDef CanRxHeader;
|
||||||
typedef CAN_TxHeaderTypeDef CanTxHeader;
|
typedef CAN_TxHeaderTypeDef CanTxHeader;
|
||||||
|
typedef CAN_FilterTypeDef CanFilter;
|
||||||
|
|
||||||
#endif /* INC_MMR_CAN_TYPES_H_ */
|
#endif /* INC_MMR_CAN_TYPES_H_ */
|
||||||
|
|||||||
+8
-5
@@ -4,14 +4,17 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define arrayLength(array) \
|
#define sizeofarray(array) \
|
||||||
(sizeof(array) / sizeof(*(array)))
|
(sizeof(array) / sizeof(*(array)))
|
||||||
|
|
||||||
#define stringArrayLength(array) \
|
#define stringArrayLength(array) \
|
||||||
stringBufferLength((array), sizeof(array))
|
stringBufferLength((array), sizeofarray(array))
|
||||||
|
|
||||||
|
#define stringBufferLength(pbuffer, maxLen) \
|
||||||
|
strnlen((const char*)(pbuffer), maxLen)
|
||||||
|
|
||||||
|
#define min(a, b) ((a) < (b) ? a : b);
|
||||||
|
#define mask(value, bits) (value & bits)
|
||||||
|
|
||||||
size_t stringBufferLength(uint8_t *buffer, size_t maxLen) {
|
|
||||||
return strnlen((const char*)buffer, maxLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* INC_MMR_CAN_UTIL_H_ */
|
#endif /* INC_MMR_CAN_UTIL_H_ */
|
||||||
|
|||||||
+24
-11
@@ -1,8 +1,19 @@
|
|||||||
#include "mmr_can.h"
|
#include "mmr_can.h"
|
||||||
|
#include "mmr_can_util.h"
|
||||||
|
|
||||||
|
static uint8_t maskIdLower5Bits(CanRxHeader *header);
|
||||||
|
|
||||||
|
|
||||||
|
HalStatus MMR_CAN_BasicSetupAndStart(CanHandle *hcan) {
|
||||||
|
return
|
||||||
|
MMR_CAN_FilterConfigDefault(hcan) |
|
||||||
|
HAL_CAN_Start(hcan)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_FilterConfig(CanHandle *hcan, MmrCanFilterSettings settings) {
|
HalStatus MMR_CAN_FilterConfig(CanHandle *hcan, MmrCanFilterSettings settings) {
|
||||||
CAN_FilterTypeDef filter = {
|
CanFilter filter = {
|
||||||
.FilterActivation = settings.enabled
|
.FilterActivation = settings.enabled
|
||||||
? CAN_FILTER_ENABLE
|
? CAN_FILTER_ENABLE
|
||||||
: CAN_FILTER_DISABLE,
|
: CAN_FILTER_DISABLE,
|
||||||
@@ -19,11 +30,13 @@ HalStatus MMR_CAN_FilterConfig(CanHandle *hcan, MmrCanFilterSettings settings) {
|
|||||||
return HAL_CAN_ConfigFilter(hcan, &filter);
|
return HAL_CAN_ConfigFilter(hcan, &filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CanFilterMask MMR_CAN_AlignStandardMask(CanFilterMask baseMask) {
|
CanFilterMask MMR_CAN_AlignStandardMask(CanFilterMask baseMask) {
|
||||||
static const uint8_t extendedMaskSurplusBytes = 5;
|
static const uint8_t extendedMaskSurplusBytes = 5;
|
||||||
return baseMask << extendedMaskSurplusBytes;
|
return baseMask << extendedMaskSurplusBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings() {
|
MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings() {
|
||||||
return (MmrCanFilterSettings) {
|
return (MmrCanFilterSettings) {
|
||||||
.enabled = true,
|
.enabled = true,
|
||||||
@@ -35,14 +48,14 @@ MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_Send(CanHandle *hcan, MmrCanPacket packet) {
|
bool MMR_CAN_IsMultiFrame(CanRxHeader *header) {
|
||||||
CanTxHeader header = {
|
return maskIdLower5Bits(header) == MMR_CAN_MESSAGE_TYPE_MULTI_FRAME;
|
||||||
.IDE = CAN_ID_STD,
|
}
|
||||||
.RTR = CAN_RTR_DATA,
|
|
||||||
.DLC = packet.length,
|
bool MMR_CAN_IsMultiFrameEnd(CanRxHeader *header) {
|
||||||
.StdId = packet.remoteId,
|
return maskIdLower5Bits(header) == MMR_CAN_MESSAGE_TYPE_MULTI_FRAME;
|
||||||
.TransmitGlobalTime = DISABLE,
|
}
|
||||||
};
|
|
||||||
|
static always_inline uint8_t maskIdLower5Bits(CanRxHeader *header) {
|
||||||
return HAL_CAN_AddTxMessage(hcan, &header, packet.data, packet.mailbox);
|
return mask(header->ExtId, B8_(0001, 1111));
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-13
@@ -6,30 +6,30 @@ static const MmrCanEventList *_rxEvents = NULL;
|
|||||||
|
|
||||||
|
|
||||||
static void __handleCanRxInterrupt(CanHandle *hcan);
|
static void __handleCanRxInterrupt(CanHandle *hcan);
|
||||||
static void __invokeAll(const MmrCanEventList *events, MmrCanEvent *event);
|
static void __invokeAll(const MmrCanEventList *events, const MmrCanMessage *event);
|
||||||
static void __maybeInvoke(const MmrCanEventHandler handler, MmrCanEvent *event);
|
static void __maybeInvoke(const MmrCanEventHandler handler, const MmrCanMessage *event);
|
||||||
|
|
||||||
|
|
||||||
void MMR_CAN_InitRxHandlers(const MmrCanEventList *rxEvents) {
|
HalStatus MMR_CAN_InitRxHandlers(CanHandle *hcan, const MmrCanEventList *rxEvents) {
|
||||||
_rxEvents = rxEvents;
|
_rxEvents = rxEvents;
|
||||||
|
return HAL_CAN_ActivateNotification(hcan, MMR_CAN_RX_INTERRUPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void __handleCanRxInterrupt(CanHandle *hcan) {
|
static void __handleCanRxInterrupt(CanHandle *hcan) {
|
||||||
static CanRxHeader rxHeader = {};
|
static CanRxBuffer buffer = {};
|
||||||
static CanRxBuffer rxData = {};
|
static MmrCanMessage event = {
|
||||||
|
.store = buffer,
|
||||||
HAL_CAN_GetRxMessage(hcan, MMR_CAN_RX_FIFO, &rxHeader, rxData);
|
|
||||||
|
|
||||||
MmrCanEvent event = {
|
|
||||||
.senderId = rxHeader.StdId,
|
|
||||||
.message = rxData,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MMR_CAN_Receive(hcan, &event);
|
||||||
__invokeAll(_rxEvents, &event);
|
__invokeAll(_rxEvents, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __invokeAll(const MmrCanEventList *events, MmrCanEvent *event) {
|
static void __invokeAll(
|
||||||
|
const MmrCanEventList *events,
|
||||||
|
const MmrCanMessage *event
|
||||||
|
) {
|
||||||
if (!events) {
|
if (!events) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,10 @@ static void __invokeAll(const MmrCanEventList *events, MmrCanEvent *event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static always_inline void __maybeInvoke(const MmrCanEventHandler handler, MmrCanEvent *event) {
|
static always_inline void __maybeInvoke(
|
||||||
|
const MmrCanEventHandler handler,
|
||||||
|
const MmrCanMessage *event
|
||||||
|
) {
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(event);
|
handler(event);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include "mmr_can.h"
|
||||||
|
|
||||||
|
static HalStatus receiveOne(CanHandle *hcan, CanRxHeader *header, uint8_t *result);
|
||||||
|
static HalStatus receiveAll(CanHandle *hcan, CanRxHeader *header, uint8_t *result);
|
||||||
|
static bool headerIsMultiFrame(CanRxHeader *header, CanId targetId);
|
||||||
|
|
||||||
|
|
||||||
|
HalStatus MMR_CAN_Receive(CanHandle *hcan, MmrCanMessage *result) {
|
||||||
|
CanRxHeader header = {};
|
||||||
|
uint8_t *dest = result->store;
|
||||||
|
HalStatus status = receiveOne(hcan, &header, dest);
|
||||||
|
|
||||||
|
result->senderId = header.ExtId;
|
||||||
|
if (MMR_CAN_IsMultiFrame(&header)) {
|
||||||
|
status |= receiveAll(hcan, &header, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus receiveOne(
|
||||||
|
CanHandle *hcan,
|
||||||
|
CanRxHeader *header,
|
||||||
|
uint8_t *result
|
||||||
|
) {
|
||||||
|
return HAL_CAN_GetRxMessage(hcan, MMR_CAN_RX_FIFO, header, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HalStatus receiveAll(
|
||||||
|
CanHandle *hcan,
|
||||||
|
CanRxHeader *header,
|
||||||
|
uint8_t *result
|
||||||
|
) {
|
||||||
|
CanId targetId = header->ExtId;
|
||||||
|
HalStatus status = HAL_OK;
|
||||||
|
do {
|
||||||
|
result += MMR_CAN_MAX_DATA_LENGTH;
|
||||||
|
status |= receiveOne(hcan, header, result);
|
||||||
|
} while (
|
||||||
|
headerIsMultiFrame(header, targetId) && status == HAL_OK
|
||||||
|
);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool headerIsMultiFrame(CanRxHeader *header, CanId targetId) {
|
||||||
|
return
|
||||||
|
MMR_CAN_IsMultiFrame(header) &&
|
||||||
|
!MMR_CAN_IsMultiFrameEnd(header) &&
|
||||||
|
header->DLC >= MMR_CAN_MAX_DATA_LENGTH;
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include "mmr_can.h"
|
||||||
|
#include "mmr_can_util.h"
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus sendNormal(CanHandle *hcan, CanTxHeader *header, MmrCanPacket *packet);
|
||||||
|
static HalStatus sendMulti(CanHandle *hcan, CanTxHeader *header, MmrCanPacket *packet);
|
||||||
|
static HalStatus sendSingleMultiFrame(CanHandle *hcan, CanTxHeader *header, MmrCanPacket *packet, uint8_t *offset);
|
||||||
|
static uint8_t computeFramesToSend(MmrCanPacket *packet);
|
||||||
|
static uint8_t computeNextMessageLength(MmrCanPacket *packet, uint8_t offset);
|
||||||
|
|
||||||
|
|
||||||
|
HalStatus MMR_CAN_Send(CanHandle *hcan, MmrCanPacket packet) {
|
||||||
|
CanTxHeader header = {
|
||||||
|
.IDE = CAN_ID_EXT,
|
||||||
|
.RTR = CAN_RTR_DATA,
|
||||||
|
.DLC = packet.length,
|
||||||
|
.ExtId = packet.remoteId << 5,
|
||||||
|
.TransmitGlobalTime = DISABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
return packet.length <= MMR_CAN_MAX_DATA_LENGTH
|
||||||
|
? sendNormal(hcan, &header, &packet)
|
||||||
|
: sendMulti(hcan, &header, &packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus sendNormal(
|
||||||
|
CanHandle *hcan,
|
||||||
|
CanTxHeader *header,
|
||||||
|
MmrCanPacket *packet
|
||||||
|
) {
|
||||||
|
header->ExtId |= MMR_CAN_MESSAGE_TYPE_NORMAL;
|
||||||
|
return
|
||||||
|
HAL_CAN_AddTxMessage(hcan, header, packet->data, packet->mailbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus sendMulti(
|
||||||
|
CanHandle *hcan,
|
||||||
|
CanTxHeader *header,
|
||||||
|
MmrCanPacket *packet
|
||||||
|
) {
|
||||||
|
HalStatus status = HAL_OK;
|
||||||
|
uint8_t offset = 0;
|
||||||
|
uint8_t framesToSend = computeFramesToSend(packet);
|
||||||
|
|
||||||
|
header->ExtId |= MMR_CAN_MESSAGE_TYPE_MULTI_FRAME;
|
||||||
|
do {
|
||||||
|
bool isLastFrame = framesToSend <= 1;
|
||||||
|
if (isLastFrame) {
|
||||||
|
header->ExtId |= MMR_CAN_MESSAGE_TYPE_MULTI_FRAME_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
status |=
|
||||||
|
sendSingleMultiFrame(hcan, header, packet, &offset);
|
||||||
|
}
|
||||||
|
while (framesToSend-- > 1 && status == HAL_OK);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus sendSingleMultiFrame(
|
||||||
|
CanHandle *hcan,
|
||||||
|
CanTxHeader *header,
|
||||||
|
MmrCanPacket *packet,
|
||||||
|
uint8_t *offset
|
||||||
|
) {
|
||||||
|
uint8_t *dataStart = packet->data + (*offset);
|
||||||
|
uint8_t length = computeNextMessageLength(packet, *offset);
|
||||||
|
|
||||||
|
header->DLC = length;
|
||||||
|
*offset += length;
|
||||||
|
|
||||||
|
return HAL_CAN_AddTxMessage(hcan, header, dataStart, packet->mailbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Computes the frames that will need to be sent for a packet.
|
||||||
|
*
|
||||||
|
* For example, if a packet has 15 bytes, the function will return
|
||||||
|
* 2, as one packet is needed for the first 8 bytes and another is
|
||||||
|
* needed for the remaining 7.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* The computation is pretty simple
|
||||||
|
* Given
|
||||||
|
* length = 17 (bytes)
|
||||||
|
* We'll have
|
||||||
|
* framesToSend = 17 / 8 = 2 (frames)
|
||||||
|
* remainder = 17 % 8 = 1 (bytes)
|
||||||
|
* maybeOneForRemainder = 1 > 0 = 1 (frame)
|
||||||
|
* -------------------------------------------
|
||||||
|
* result = 2 + 1 = 3 (frames)
|
||||||
|
*/
|
||||||
|
static uint8_t computeFramesToSend(MmrCanPacket *packet) {
|
||||||
|
uint8_t length = packet->length;
|
||||||
|
uint8_t framesToSend = length / MMR_CAN_MAX_DATA_LENGTH;
|
||||||
|
uint8_t remainder = length % MMR_CAN_MAX_DATA_LENGTH;
|
||||||
|
uint8_t maybeOneForRemainder = remainder > 0;
|
||||||
|
|
||||||
|
return framesToSend + maybeOneForRemainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Returns the length for the next message, either
|
||||||
|
* 8 bytes or a lower value, keeping the offset into count.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* Given
|
||||||
|
* - a 17 bytes packet
|
||||||
|
* - an offset starting at 0 and supposedly incrementing
|
||||||
|
* of 8 after each call
|
||||||
|
*
|
||||||
|
* Three subsequent calls to this function will return
|
||||||
|
* First call -> min(17 - 0, 8) = min(17, 8) = 8 (bytes)
|
||||||
|
* Second call -> min(17 - 8, 8) = min(9, 8) = 8 (bytes)
|
||||||
|
* Third call -> min(17 - 16, 8) = min(1, 8) = 1 (byte)
|
||||||
|
*/
|
||||||
|
static uint8_t computeNextMessageLength(MmrCanPacket *packet, uint8_t offset) {
|
||||||
|
uint8_t remainingBytes = packet->length - offset;
|
||||||
|
return min(
|
||||||
|
remainingBytes, MMR_CAN_MAX_DATA_LENGTH
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user