Compare commits

2 Commits

Author SHA1 Message Date
Stefano Calabretti 400513c97c Update README 2022-05-31 10:16:35 +02:00
Stefano Calabretti e2fcbf4154 new steering ids (#14)
* odometry id

* new steering ids

* Update gitignore

Co-authored-by: aesthetic-sofa <71275573+aesthetic-sofa@users.noreply.github.com>
2022-05-17 14:29:09 +02:00
9 changed files with 282 additions and 213 deletions
+3 -36
View File
@@ -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_ */
-40
View File
@@ -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_
+2
View File
@@ -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_ */
-1
View File
@@ -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
+62 -1
View File
@@ -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;
}
}
```
-55
View File
@@ -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,
};
}
+8 -5
View File
@@ -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
View File
@@ -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;
}
+140 -48
View File
@@ -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,
.headers.tx = {
.IDE = CAN_ID_EXT,
.RTR = CAN_RTR_DATA,
.DLC = packet->length,
.TransmitGlobalTime = DISABLE,
},
};
} }
HalStatus MMR_CAN_SendRaw( static HalStatus sendNormal(TransmissionParams *tp) {
MmrCan *can, setMessageType(tp, MMR_CAN_MESSAGE_TYPE_NORMAL);
MmrCanMessageId msgId, return send(tp);
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) { static HalStatus sendMulti(TransmissionParams *tp) {
CanTxHeader txHeader = HalStatus status = HAL_OK;
buildTxHeader(can, &packet); 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( return HAL_CAN_AddTxMessage(
can->handle, tp->handle,
&txHeader, &tp->headers.tx,
(uint8_t*)packet.data, tp->packet->data,
getNextMailbox(can) getNextMailbox()
); );
} }
static MmrCanHeader buildDefaultHeader(MmrCan *can, MmrCanMessageId msgId) { static CanMailbox *getNextMailbox() {
return (MmrCanHeader){ __currentMailbox++;
.messageId = msgId, __currentMailbox %= MAILBOXES_COUNT;
.senderId = can->id,
.priority = MMR_CAN_MESSAGE_PRIORITY_NORMAL, return __mailboxes + __currentMailbox;
.messageType = MMR_CAN_MESSAGE_TYPE_NORMAL,
};
} }
static CanTxHeader buildTxHeader(MmrCan *can, MmrCanPacket *packet) { static void syncHeaders(TransmissionParams *tp) {
return (CanTxHeader){ tp->headers.tx.ExtId = MMR_CAN_HeaderToBits(tp->headers.mmr);
.ExtId = MMR_CAN_HeaderToBits(packet->header),
.IDE = CAN_ID_EXT,
.RTR = CAN_RTR_DATA,
.DLC = packet->length,
.TransmitGlobalTime = DISABLE,
};
} }
static CanMailbox *getNextMailbox(MmrCan *can) { /**
can->currentMailbox++; * @brief
can->currentMailbox %= MAILBOXES_COUNT; * 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 can->mailboxes + can->currentMailbox; 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;
} }