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:
Stefano Calabretti
2021-12-09 11:39:39 +01:00
committed by GitHub
parent 90d1836dfa
commit 7b09401b00
9 changed files with 346 additions and 50 deletions
+24 -11
View File
@@ -1,8 +1,19 @@
#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) {
CAN_FilterTypeDef filter = {
CanFilter filter = {
.FilterActivation = settings.enabled
? CAN_FILTER_ENABLE
: CAN_FILTER_DISABLE,
@@ -19,11 +30,13 @@ HalStatus MMR_CAN_FilterConfig(CanHandle *hcan, MmrCanFilterSettings settings) {
return HAL_CAN_ConfigFilter(hcan, &filter);
}
CanFilterMask MMR_CAN_AlignStandardMask(CanFilterMask baseMask) {
static const uint8_t extendedMaskSurplusBytes = 5;
return baseMask << extendedMaskSurplusBytes;
}
MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings() {
return (MmrCanFilterSettings) {
.enabled = true,
@@ -35,14 +48,14 @@ MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings() {
}
HalStatus MMR_CAN_Send(CanHandle *hcan, MmrCanPacket packet) {
CanTxHeader header = {
.IDE = CAN_ID_STD,
.RTR = CAN_RTR_DATA,
.DLC = packet.length,
.StdId = packet.remoteId,
.TransmitGlobalTime = DISABLE,
};
return HAL_CAN_AddTxMessage(hcan, &header, packet.data, packet.mailbox);
bool MMR_CAN_IsMultiFrame(CanRxHeader *header) {
return maskIdLower5Bits(header) == MMR_CAN_MESSAGE_TYPE_MULTI_FRAME;
}
bool MMR_CAN_IsMultiFrameEnd(CanRxHeader *header) {
return maskIdLower5Bits(header) == MMR_CAN_MESSAGE_TYPE_MULTI_FRAME;
}
static always_inline uint8_t maskIdLower5Bits(CanRxHeader *header) {
return mask(header->ExtId, B8_(0001, 1111));
}
+16 -13
View File
@@ -6,30 +6,30 @@ static const MmrCanEventList *_rxEvents = NULL;
static void __handleCanRxInterrupt(CanHandle *hcan);
static void __invokeAll(const MmrCanEventList *events, MmrCanEvent *event);
static void __maybeInvoke(const MmrCanEventHandler handler, MmrCanEvent *event);
static void __invokeAll(const MmrCanEventList *events, const MmrCanMessage *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;
return HAL_CAN_ActivateNotification(hcan, MMR_CAN_RX_INTERRUPT);
}
static void __handleCanRxInterrupt(CanHandle *hcan) {
static CanRxHeader rxHeader = {};
static CanRxBuffer rxData = {};
HAL_CAN_GetRxMessage(hcan, MMR_CAN_RX_FIFO, &rxHeader, rxData);
MmrCanEvent event = {
.senderId = rxHeader.StdId,
.message = rxData,
static CanRxBuffer buffer = {};
static MmrCanMessage event = {
.store = buffer,
};
MMR_CAN_Receive(hcan, &event);
__invokeAll(_rxEvents, &event);
}
static void __invokeAll(const MmrCanEventList *events, MmrCanEvent *event) {
static void __invokeAll(
const MmrCanEventList *events,
const MmrCanMessage *event
) {
if (!events) {
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) {
handler(event);
}
+54
View File
@@ -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;
}
+130
View File
@@ -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
);
}