#include #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; }