906dfcd3db
* Add ack message type * Rename dictionaryEntry to messageId * Refactor * Map message ids
143 lines
3.4 KiB
C
143 lines
3.4 KiB
C
#include <stdbool.h>
|
|
#include "mmr_can.h"
|
|
#include "mmr_can_util.h"
|
|
|
|
|
|
typedef struct {
|
|
CanHandle *handle;
|
|
MmrCanPacket *packet;
|
|
|
|
struct {
|
|
CanTxHeader tx;
|
|
MmrCanHeader mmr;
|
|
} headers;
|
|
} TransmissionParams;
|
|
|
|
|
|
static HalStatus send(TransmissionParams *tp);
|
|
static HalStatus sendNormal(TransmissionParams *tp);
|
|
static HalStatus sendMulti(TransmissionParams *tp);
|
|
static HalStatus sendSingleMultiFrame(TransmissionParams *tp);
|
|
static uint8_t computeFramesToSend(MmrCanPacket *packet);
|
|
static uint8_t computeNextMessageLength(MmrCanPacket *packet);
|
|
static void setMessageType(TransmissionParams *header, MmrCanMessageType type);
|
|
static void syncHeaders(TransmissionParams *tp);
|
|
|
|
|
|
HalStatus MMR_CAN_Send(CanHandle *hcan, MmrCanPacket packet) {
|
|
TransmissionParams tp = {
|
|
.handle = hcan,
|
|
.packet = &packet,
|
|
.headers.tx = {
|
|
.IDE = CAN_ID_EXT,
|
|
.RTR = CAN_RTR_DATA,
|
|
.DLC = packet.length,
|
|
.TransmitGlobalTime = DISABLE,
|
|
},
|
|
};
|
|
syncHeaders(&tp);
|
|
|
|
return packet.length <= MMR_CAN_MAX_DATA_LENGTH
|
|
? sendNormal(&tp)
|
|
: sendMulti(&tp);
|
|
}
|
|
|
|
|
|
static HalStatus sendNormal(TransmissionParams *tp) {
|
|
setMessageType(tp, MMR_CAN_MESSAGE_TYPE_NORMAL);
|
|
return send(tp);
|
|
}
|
|
|
|
|
|
static HalStatus sendMulti(TransmissionParams *tp) {
|
|
HalStatus status = HAL_OK;
|
|
uint8_t framesToSend = computeFramesToSend(tp->packet);
|
|
|
|
setMessageType(tp, MMR_CAN_MESSAGE_TYPE_MULTI_FRAME);
|
|
do {
|
|
bool isLastFrame = framesToSend <= 1;
|
|
if (isLastFrame) {
|
|
setMessageType(tp, MMR_CAN_MESSAGE_TYPE_MULTI_FRAME_END);
|
|
}
|
|
|
|
status |= sendSingleMultiFrame(tp);
|
|
}
|
|
while (framesToSend-- > 1 && status == HAL_OK);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
static HalStatus sendSingleMultiFrame(TransmissionParams *tp) {
|
|
uint8_t length =
|
|
computeNextMessageLength(tp->packet);
|
|
|
|
tp->packet->length -= length;
|
|
tp->packet->data += length;
|
|
tp->headers.tx.DLC = length;
|
|
|
|
return send(tp);
|
|
}
|
|
|
|
|
|
static HalStatus send(TransmissionParams *tp) {
|
|
syncHeaders(tp);
|
|
|
|
return HAL_CAN_AddTxMessage(
|
|
tp->handle,
|
|
&tp->headers.tx,
|
|
tp->packet->data,
|
|
tp->packet->mailbox
|
|
);
|
|
}
|
|
|
|
|
|
static void syncHeaders(TransmissionParams *tp) {
|
|
tp->headers.tx.ExtId = *MMR_CAN_HeaderToBits(&tp->headers.mmr);
|
|
}
|
|
|
|
|
|
/**
|
|
* @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.
|
|
*/
|
|
static uint8_t computeNextMessageLength(MmrCanPacket *packet) {
|
|
return min(
|
|
packet->length, MMR_CAN_MAX_DATA_LENGTH
|
|
);
|
|
}
|
|
|
|
static always_inline void setMessageType(TransmissionParams *tp, MmrCanMessageType type) {
|
|
tp->headers.mmr.messageType = type;
|
|
}
|