Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 400513c97c | |||
| e2fcbf4154 |
+3
-36
@@ -46,15 +46,6 @@ typedef uint32_t (*MmrCanTickProvider)();
|
|||||||
typedef uint8_t CanRxBuffer[MMR_CAN_MAX_DATA_LENGTH];
|
typedef uint8_t CanRxBuffer[MMR_CAN_MAX_DATA_LENGTH];
|
||||||
|
|
||||||
|
|
||||||
typedef struct MmrCan {
|
|
||||||
CanId id;
|
|
||||||
CanHandle *handle;
|
|
||||||
CanFifo fifo;
|
|
||||||
CanMailbox mailboxes[MAILBOXES_COUNT];
|
|
||||||
uint8_t currentMailbox;
|
|
||||||
} MmrCan;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct MmrCanFilterSettings {
|
typedef struct MmrCanFilterSettings {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
|
||||||
@@ -124,7 +115,7 @@ typedef struct MmrCanFilterSettings {
|
|||||||
*/
|
*/
|
||||||
typedef struct MmrCanPacket {
|
typedef struct MmrCanPacket {
|
||||||
MmrCanHeader header;
|
MmrCanHeader header;
|
||||||
void *data;
|
uint8_t *data;
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
} MmrCanPacket;
|
} MmrCanPacket;
|
||||||
|
|
||||||
@@ -182,22 +173,6 @@ typedef struct MmrCanMessage {
|
|||||||
extern MmrCanTickProvider __mmr_can_tickProvider;
|
extern MmrCanTickProvider __mmr_can_tickProvider;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MmrCan MMR_CAN_Create(CanHandle *hcan, CanFifo rxFifo);
|
|
||||||
HalStatus MMR_CAN_Start(MmrCan *can);
|
|
||||||
HalStatus MMR_CAN_EnableFilter(MmrCan *can, CanFilterMask mask, CanFilterBank bank);
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_SendString(MmrCan *can, MmrCanMessageId msgId, const char *data);
|
|
||||||
HalStatus MMR_CAN_SendInt(MmrCan *can, MmrCanMessageId msgId, int data);
|
|
||||||
HalStatus MMR_CAN_SendFloat(MmrCan *can, MmrCanMessageId msgId, float data);
|
|
||||||
HalStatus MMR_CAN_SendRaw(MmrCan *can, MmrCanMessageId msgId, void *data, uint8_t length);
|
|
||||||
HalStatus MMR_CAN_SendPacket(MmrCan *can, MmrCanPacket packet);
|
|
||||||
|
|
||||||
|
|
||||||
#define MMR_CAN_SendStruct(pcan, messageId, pdata) \
|
|
||||||
MMR_CAN_SendRaw(pcan, messageId, pdata, sizeof(*pdata))
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Sets the tick provider.
|
* Sets the tick provider.
|
||||||
@@ -234,14 +209,6 @@ HalStatus MMR_CAN_FilterConfig(CanHandle *hcan, MmrCanFilterSettings settings);
|
|||||||
*/
|
*/
|
||||||
MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings();
|
MmrCanFilterSettings MMR_CAN_GetDefaultFilterSettings();
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_SendString(MmrCan *can, MmrCanMessageId msgId, const char *data);
|
|
||||||
HalStatus MMR_CAN_SendInt(MmrCan *can, MmrCanMessageId msgId, int data);
|
|
||||||
HalStatus MMR_CAN_SendFloat(MmrCan *can, MmrCanMessageId msgId, float data);
|
|
||||||
HalStatus MMR_CAN_SendRaw(MmrCan *can, MmrCanMessageId msgId, void *data, uint8_t length);
|
|
||||||
HalStatus MMR_CAN_SendPacket(MmrCan *can, MmrCanPacket packet);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
* Sends a can packet over the network.
|
* Sends a can packet over the network.
|
||||||
@@ -268,7 +235,7 @@ HalStatus MMR_CAN_SendNoTamper(CanHandle *hcan, MmrCanPacket packet);
|
|||||||
* @brief
|
* @brief
|
||||||
* Tries to receive a message.
|
* Tries to receive a message.
|
||||||
*/
|
*/
|
||||||
MmrResult MMR_CAN_TryReceive(MmrCan *can, MmrCanMessage *result);
|
MmrResult MMR_CAN_TryReceive(CanHandle *hcan, MmrCanMessage *result);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
@@ -278,6 +245,6 @@ MmrResult MMR_CAN_TryReceive(MmrCan *can, MmrCanMessage *result);
|
|||||||
* If a multi-frame message is received, this function will block
|
* If a multi-frame message is received, this function will block
|
||||||
* and read every frame for that particular message.
|
* and read every frame for that particular message.
|
||||||
*/
|
*/
|
||||||
HalStatus MMR_CAN_Receive(MmrCan *can, MmrCanMessage *result);
|
HalStatus MMR_CAN_Receive(CanHandle *hcan, MmrCanMessage *result);
|
||||||
|
|
||||||
#endif /* INC_MMR_CAN_H_ */
|
#endif /* INC_MMR_CAN_H_ */
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
#ifndef MMR_CAN_ECU_MESSAGES_H_
|
|
||||||
#define MMR_CAN_ECU_MESSAGES_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef struct EcuPedalThrottle {
|
|
||||||
float apsAVoltage;
|
|
||||||
float apsBVoltage;
|
|
||||||
float throttleAVoltage;
|
|
||||||
float throttleBVoltage;
|
|
||||||
} EcuPedalThrottle;
|
|
||||||
|
|
||||||
typedef struct EcuTemperatures {
|
|
||||||
int16_t oil;
|
|
||||||
int16_t engine;
|
|
||||||
int16_t intake;
|
|
||||||
int16_t ambient;
|
|
||||||
} EcuTemperatures;
|
|
||||||
|
|
||||||
typedef struct EcuEngineFn1 {
|
|
||||||
float engineRpm;
|
|
||||||
float gear;
|
|
||||||
uint16_t vehicleSpeed;
|
|
||||||
uint16_t throttle;
|
|
||||||
} EcuEngineFn1;
|
|
||||||
|
|
||||||
typedef struct EcuPressures {
|
|
||||||
float oil;
|
|
||||||
float fuel;
|
|
||||||
float intake;
|
|
||||||
float ambient;
|
|
||||||
} EcuPressures;
|
|
||||||
|
|
||||||
typedef struct EcuEngineFn2 {
|
|
||||||
float batteryVoltage;
|
|
||||||
float acceleratorPedal;
|
|
||||||
float fanControl;
|
|
||||||
} EcuEngineFn2;
|
|
||||||
|
|
||||||
#endif // !MMR_CAN_ECU_MESSAGES_H_
|
|
||||||
@@ -79,5 +79,7 @@ MmrCanHeader MMR_CAN_HeaderFromBits(uint32_t bits);
|
|||||||
* Tells wether the given header represents an SCS.
|
* Tells wether the given header represents an SCS.
|
||||||
*/
|
*/
|
||||||
bool MMR_CAN_IsHeaderScs(MmrCanHeader header);
|
bool MMR_CAN_IsHeaderScs(MmrCanHeader header);
|
||||||
|
bool MMR_CAN_IsMultiFrame(MmrCanHeader header);
|
||||||
|
bool MMR_CAN_IsMultiFrameEnd(MmrCanHeader header);
|
||||||
|
|
||||||
#endif /* INC_MMR_CAN_HEADER_H_ */
|
#endif /* INC_MMR_CAN_HEADER_H_ */
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
typedef uint32_t CanId;
|
typedef uint32_t CanId;
|
||||||
typedef uint32_t CanMailbox;
|
typedef uint32_t CanMailbox;
|
||||||
typedef uint32_t CanFifo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ You can add this library to your project by either cloning it or adding it as a
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Add as a submodule (recommended)
|
## Add as a submodule (recommended)
|
||||||
To **add mmr_can as a submodule**, go into your project folder and run
|
To **add mmr_can as a submodule**, go into your project folder and run
|
||||||
```
|
```
|
||||||
git submodule add https://github.com/mmr-driverless/mmr_can.git Drivers/MMR_CAN
|
git submodule add https://github.com/mmr-driverless/mmr_can.git Drivers/MMR_CAN
|
||||||
@@ -16,3 +16,64 @@ mmr_can will be cloned inside the `Drivers` folder
|
|||||||
After adding the submodule, right click on your project's name from within the STM32CubeIDE, then `Properties (last option) > C/C++ General > Paths and Symbols`
|
After adding the submodule, right click on your project's name from within the STM32CubeIDE, then `Properties (last option) > C/C++ General > Paths and Symbols`
|
||||||
|
|
||||||
You'll see a list of directories on the right, click on `Add`, then type `Drivers/MMR_CAN/Inc` and press enter
|
You'll see a list of directories on the right, click on `Add`, then type `Drivers/MMR_CAN/Inc` and press enter
|
||||||
|
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Configure the CAN peripheral in the _.ioc_ file, then call the following initialization function
|
||||||
|
inside _main_.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "mmr_can.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// MX_CAN_INIT()...
|
||||||
|
|
||||||
|
if (MMR_CAN_BasicSetupAndStart(&hcan) != HAK_OK) {
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
|
|
||||||
|
// while (1) {...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sending a message
|
||||||
|
```c
|
||||||
|
void sendAMessage() {
|
||||||
|
// my_data_type data = something;
|
||||||
|
uint16_t data = 123;
|
||||||
|
MmrCanPacket packet = {
|
||||||
|
.data = (uint8_t*)(&data),
|
||||||
|
.length = sizeof(data),
|
||||||
|
.header.messageId = MMR_CAN_MESSAGE_ID_<ID>,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (MMR_CAN_Send(&hcan, packet) != HAL_OK) {
|
||||||
|
; // Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Receiving a message
|
||||||
|
```c
|
||||||
|
void receiveAMessage() {
|
||||||
|
CanRxBuffer buffer = {};
|
||||||
|
MmrCanMessage message = {
|
||||||
|
.store = buffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
MmrResult result = MMR_CAN_TryReceive(&hcan, &message);
|
||||||
|
if (result == MMR_RESULT_ERROR) {
|
||||||
|
; // Error
|
||||||
|
}
|
||||||
|
else if (result == MMR_RESULT_PENDING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.header.messageId == MMR_CAN_MESSAGE_ID<TARGET_ID>) {
|
||||||
|
uint16_t data = *(uint16_t*)buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#include "mmr_can_ecu_messages.h"
|
|
||||||
#include "mmr_can.h"
|
|
||||||
|
|
||||||
#define ecuToHost(byteA, byteB) ((byteA << 8) | (byteB))
|
|
||||||
|
|
||||||
|
|
||||||
EcuPedalThrottle MMR_CAN_GetEcuPedalThrottle(MmrCanMessage *message) {
|
|
||||||
uint8_t *buffer = message->store
|
|
||||||
return (EcuPedalThrottle) {
|
|
||||||
.apsAVoltage = ecuToHost(buffer[0], buffer[1]) / 1000,
|
|
||||||
.apsBVoltage = ecuToHost(buffer[2], buffer[3]) / 1000,
|
|
||||||
.throttleAVoltage = ecuToHost(buffer[4], buffer[5]) / 1000,
|
|
||||||
.throttleBVoltage = ecuToHost(buffer[6], buffer[7]) / 1000,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
EcuTemperatures MMR_CAN_GetEcuTemperatures(MmrCanMessage *message) {
|
|
||||||
uint8_t *buffer = message->store
|
|
||||||
return (EcuTemperatures) {
|
|
||||||
.oil = ecuToHost(buffer[0], buffer[1]) - 40,
|
|
||||||
.engine = ecuToHost(buffer[2], buffer[3]) - 40,
|
|
||||||
.intake = ecuToHost(buffer[4], buffer[5]) - 40,
|
|
||||||
.ambient = ecuToHost(buffer[6], buffer[7]) - 40,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
EcuEngineFn1 MMR_CAN_GetEcuEngineFn1(MmrCanMessage *message) {
|
|
||||||
uint8_t *buffer = message->store
|
|
||||||
return (EcuEngineFn1) {
|
|
||||||
.engineRpm = ecuToHost(buffer[0], buffer[1]),
|
|
||||||
.gear = ecuToHost(buffer[2], buffer[3])
|
|
||||||
.vehicleSpeed = ecuToHost(buffer[4], buffer[5]) / 100,
|
|
||||||
.throttle = ecuToHost(buffer[6], buffer[7]) / 100,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
EcuPressures MMR_CAN_GetEcuPressures(MmrCanMessage *message) {
|
|
||||||
uint8_t *buffer = message->store
|
|
||||||
return (EcuPressures) {
|
|
||||||
.oil = ecuToHost(buffer[0], buffer[1]) / 100,
|
|
||||||
.fuel = ecuToHost(buffer[2], buffer[3]) / 100,
|
|
||||||
.intake = ecuToHost(buffer[4], buffer[5]) / 10,
|
|
||||||
.ambient = ecuToHost(buffer[6], buffer[7]) / 10,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
EcuEngineFn2 MMR_CAN_GetEcuEngineFn2(MmrCanMessage *message) {
|
|
||||||
uint8_t *buffer = message->store
|
|
||||||
return (EcuEngineFn2) {
|
|
||||||
.batteryVoltage = ecuToHost(buffer[0], buffer[1]) / 1000,
|
|
||||||
.acceleratorPedal = ecuToHost(buffer[2], buffer[3]) / 100,
|
|
||||||
.fanControl = ecuToHost(buffer[4], buffer[5]) / 100,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2,11 +2,6 @@
|
|||||||
#include "mmr_can_util.h"
|
#include "mmr_can_util.h"
|
||||||
#include "mmr_can_optimize.h"
|
#include "mmr_can_optimize.h"
|
||||||
|
|
||||||
struct MmrCanHeader {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t MMR_CAN_HeaderToBits(MmrCanHeader header) {
|
uint32_t MMR_CAN_HeaderToBits(MmrCanHeader header) {
|
||||||
return 0
|
return 0
|
||||||
| ((uint32_t)header.priority << 26)
|
| ((uint32_t)header.priority << 26)
|
||||||
@@ -30,3 +25,11 @@ MmrCanHeader MMR_CAN_HeaderFromBits(uint32_t bits) {
|
|||||||
bool MMR_CAN_IsHeaderScs(MmrCanHeader header) {
|
bool MMR_CAN_IsHeaderScs(MmrCanHeader header) {
|
||||||
return header.messageType == MMR_CAN_MESSAGE_TYPE_SCS;
|
return header.messageType == MMR_CAN_MESSAGE_TYPE_SCS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MMR_CAN_IsMultiFrame(MmrCanHeader header) {
|
||||||
|
return header.messageType == MMR_CAN_MESSAGE_TYPE_MULTI_FRAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MMR_CAN_IsMultiFrameEnd(MmrCanHeader header) {
|
||||||
|
return header.messageType == MMR_CAN_MESSAGE_TYPE_MULTI_FRAME_END;
|
||||||
|
}
|
||||||
|
|||||||
+67
-27
@@ -1,29 +1,26 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include "mmr_can.h"
|
#include "mmr_can.h"
|
||||||
|
|
||||||
|
|
||||||
#define cast(pmsg, to) (*(to*)(pmsg->store))
|
typedef struct {
|
||||||
|
CanHandle *handle;
|
||||||
|
uint8_t *result;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
CanRxHeader rx;
|
||||||
|
MmrCanHeader mmr;
|
||||||
|
} headers;
|
||||||
|
|
||||||
|
uint8_t fifo;
|
||||||
|
} ReceptionParams;
|
||||||
|
|
||||||
|
|
||||||
uint16_t MMR_CAN_GetUInt16(MmrCanMessage *message) {
|
static HalStatus receiveOne(ReceptionParams *rp);
|
||||||
return cast(message, uint16_t);
|
static HalStatus receiveAll(ReceptionParams *rp);
|
||||||
}
|
static bool headerIsMultiFrame(MmrCanHeader header, CanId targetId);
|
||||||
|
|
||||||
uint32_t MMR_CAN_GetUInt32(MmrCanMessage *message) {
|
|
||||||
return cast(message, uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t MMR_CAN_GetUInt64(MmrCanMessage *message) {
|
|
||||||
return cast(message, uint64_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
float MMR_CAN_GetFloat(MmrCanMessage *message) {
|
|
||||||
return cast(message, float);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
MmrResult MMR_CAN_TryReceive(MmrCan *can, MmrCanMessage *result) {
|
MmrResult MMR_CAN_TryReceive(CanHandle *hcan, MmrCanMessage *result) {
|
||||||
size_t pendingMessages =
|
size_t pendingMessages =
|
||||||
HAL_CAN_GetRxFifoFillLevel(hcan, MMR_CAN_RX_FIFO);
|
HAL_CAN_GetRxFifoFillLevel(hcan, MMR_CAN_RX_FIFO);
|
||||||
|
|
||||||
@@ -37,15 +34,58 @@ MmrResult MMR_CAN_TryReceive(MmrCan *can, MmrCanMessage *result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_Receive(MmrCan *can, MmrCanMessage *result) {
|
HalStatus MMR_CAN_Receive(CanHandle *hcan, MmrCanMessage *result) {
|
||||||
CanRxHeader rxHeader = {};
|
ReceptionParams rp = {
|
||||||
HalStatus status = HAL_CAN_GetRxMessage(
|
.handle = hcan,
|
||||||
can->handle,
|
.result = (uint8_t*)result->store,
|
||||||
can->fifo,
|
.fifo = MMR_CAN_RX_FIFO,
|
||||||
&rxHeader,
|
};
|
||||||
result->store
|
|
||||||
);
|
HalStatus status = receiveOne(&rp);
|
||||||
|
if (status != HAL_OK) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->header = rp.headers.mmr;
|
||||||
|
if (MMR_CAN_IsMultiFrame(rp.headers.mmr)) {
|
||||||
|
status |= receiveAll(&rp);
|
||||||
|
}
|
||||||
|
|
||||||
result->header = MMR_CAN_HeaderFromBits(rxHeader.ExtId);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus receiveAll(ReceptionParams *rp) {
|
||||||
|
CanId targetId = rp->headers.mmr.senderId;
|
||||||
|
HalStatus status = HAL_OK;
|
||||||
|
do {
|
||||||
|
rp->result += MMR_CAN_MAX_DATA_LENGTH;
|
||||||
|
status |= receiveOne(rp);
|
||||||
|
}
|
||||||
|
while (
|
||||||
|
headerIsMultiFrame(rp->headers.mmr, targetId) && status == HAL_OK
|
||||||
|
);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus receiveOne(ReceptionParams *rp) {
|
||||||
|
HalStatus status = HAL_CAN_GetRxMessage(
|
||||||
|
rp->handle,
|
||||||
|
rp->fifo,
|
||||||
|
&rp->headers.rx,
|
||||||
|
rp->result
|
||||||
|
);
|
||||||
|
|
||||||
|
rp->headers.mmr = MMR_CAN_HeaderFromBits(rp->headers.rx.ExtId);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool headerIsMultiFrame(MmrCanHeader header, CanId targetId) {
|
||||||
|
return
|
||||||
|
MMR_CAN_IsMultiFrame(header) &&
|
||||||
|
!MMR_CAN_IsMultiFrameEnd(header) &&
|
||||||
|
header.senderId == targetId;
|
||||||
|
}
|
||||||
|
|||||||
+151
-59
@@ -2,82 +2,174 @@
|
|||||||
#include "mmr_can.h"
|
#include "mmr_can.h"
|
||||||
#include "mmr_can_util.h"
|
#include "mmr_can_util.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CanHandle *handle;
|
||||||
|
MmrCanPacket *packet;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
CanTxHeader tx;
|
||||||
|
MmrCanHeader mmr;
|
||||||
|
} headers;
|
||||||
|
} TransmissionParams;
|
||||||
|
|
||||||
|
|
||||||
|
static TransmissionParams buildParams(CanHandle *hcan, MmrCanPacket *packet);
|
||||||
|
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);
|
||||||
|
static CanMailbox *getNextMailbox();
|
||||||
|
|
||||||
|
|
||||||
#define MAILBOXES_COUNT 3
|
#define MAILBOXES_COUNT 3
|
||||||
|
|
||||||
static MmrCanHeader buildDefaultHeader(MmrCan *can, MmrCanMessageId msgId);
|
static CanMailbox __mailboxes[MAILBOXES_COUNT] = {};
|
||||||
static CanTxHeader buildTxHeader(MmrCan *can, MmrCanPacket *packet);
|
static uint8_t __currentMailbox = 0;
|
||||||
static CanMailbox *getNextMailbox(MmrCan *can);
|
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_SendString(MmrCan *can, MmrCanMessageId msgId, const char *data) {
|
HalStatus MMR_CAN_Send(CanHandle *hcan, MmrCanPacket packet) {
|
||||||
uint8_t len =
|
TransmissionParams tp =
|
||||||
strnlen(data, MMR_CAN_MAX_DATA_LENGTH);
|
buildParams(hcan, &packet);
|
||||||
|
|
||||||
return MMR_CAN_SendRaw(can, msgId, &data, len);
|
syncHeaders(&tp);
|
||||||
|
return packet.length <= MMR_CAN_MAX_DATA_LENGTH
|
||||||
|
? sendNormal(&tp)
|
||||||
|
: sendMulti(&tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_SendInt(MmrCan *can, MmrCanMessageId msgId, int data) {
|
HalStatus MMR_CAN_SendNoTamper(CanHandle *hcan, MmrCanPacket packet) {
|
||||||
return MMR_CAN_SendRaw(can, msgId, &data, sizeof(data))
|
TransmissionParams tp =
|
||||||
|
buildParams(hcan, &packet);
|
||||||
|
|
||||||
|
return send(&tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_SendFloat(MmrCan *can, MmrCanMessageId msgId, float data) {
|
static TransmissionParams buildParams(CanHandle *hcan, MmrCanPacket *packet) {
|
||||||
return MMR_CAN_SendRaw(can, msgId, &data, sizeof(data));
|
return (TransmissionParams) {
|
||||||
}
|
.handle = hcan,
|
||||||
|
.packet = packet,
|
||||||
|
.headers.mmr = packet->header,
|
||||||
HalStatus MMR_CAN_SendRaw(
|
.headers.tx = {
|
||||||
MmrCan *can,
|
|
||||||
MmrCanMessageId msgId,
|
|
||||||
void *data,
|
|
||||||
uint8_t length
|
|
||||||
) {
|
|
||||||
return MMR_CAN_SendPacket(can, (MmrCanPacket){
|
|
||||||
.header = buildDefaultHeader(can, msgId),
|
|
||||||
.data = data,
|
|
||||||
.length = length,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
HalStatus MMR_CAN_SendPacket(MmrCan *can, MmrCanPacket packet) {
|
|
||||||
CanTxHeader txHeader =
|
|
||||||
buildTxHeader(can, &packet);
|
|
||||||
|
|
||||||
return HAL_CAN_AddTxMessage(
|
|
||||||
can->handle,
|
|
||||||
&txHeader,
|
|
||||||
(uint8_t*)packet.data,
|
|
||||||
getNextMailbox(can)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static MmrCanHeader buildDefaultHeader(MmrCan *can, MmrCanMessageId msgId) {
|
|
||||||
return (MmrCanHeader){
|
|
||||||
.messageId = msgId,
|
|
||||||
.senderId = can->id,
|
|
||||||
.priority = MMR_CAN_MESSAGE_PRIORITY_NORMAL,
|
|
||||||
.messageType = MMR_CAN_MESSAGE_TYPE_NORMAL,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static CanTxHeader buildTxHeader(MmrCan *can, MmrCanPacket *packet) {
|
|
||||||
return (CanTxHeader){
|
|
||||||
.ExtId = MMR_CAN_HeaderToBits(packet->header),
|
|
||||||
.IDE = CAN_ID_EXT,
|
.IDE = CAN_ID_EXT,
|
||||||
.RTR = CAN_RTR_DATA,
|
.RTR = CAN_RTR_DATA,
|
||||||
.DLC = packet->length,
|
.DLC = packet->length,
|
||||||
.TransmitGlobalTime = DISABLE,
|
.TransmitGlobalTime = DISABLE,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static CanMailbox *getNextMailbox(MmrCan *can) {
|
static HalStatus sendNormal(TransmissionParams *tp) {
|
||||||
can->currentMailbox++;
|
setMessageType(tp, MMR_CAN_MESSAGE_TYPE_NORMAL);
|
||||||
can->currentMailbox %= MAILBOXES_COUNT;
|
return send(tp);
|
||||||
|
}
|
||||||
return can->mailboxes + can->currentMailbox;
|
|
||||||
|
|
||||||
|
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->headers.tx.DLC = length;
|
||||||
|
tp->packet->length -= length;
|
||||||
|
|
||||||
|
HalStatus result = send(tp);
|
||||||
|
|
||||||
|
tp->packet->data += length;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HalStatus send(TransmissionParams *tp) {
|
||||||
|
syncHeaders(tp);
|
||||||
|
|
||||||
|
return HAL_CAN_AddTxMessage(
|
||||||
|
tp->handle,
|
||||||
|
&tp->headers.tx,
|
||||||
|
tp->packet->data,
|
||||||
|
getNextMailbox()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static CanMailbox *getNextMailbox() {
|
||||||
|
__currentMailbox++;
|
||||||
|
__currentMailbox %= MAILBOXES_COUNT;
|
||||||
|
|
||||||
|
return __mailboxes + __currentMailbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user