You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
270 lines
8.5 KiB
270 lines
8.5 KiB
#include "zcan.hpp"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "stm32halport\halport\gins.h"
|
|
using namespace iflytop;
|
|
|
|
#define TAG "ZCanCmder"
|
|
|
|
#define OVER_TIME_MS 5
|
|
#define FIFO_NUM CAN_RX_FIFO0
|
|
|
|
extern "C" {
|
|
|
|
ZCAN1 *zcan1;
|
|
|
|
void HAL_CAN_TxMailbox0CompleteCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_TxMailbox1CompleteCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_TxMailbox2CompleteCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_TxMailbox0AbortCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_TxMailbox1AbortCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_TxMailbox2AbortCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
|
|
if (zcan1) zcan1->STM32_HAL_onCAN_RxFifo0MsgPending(hcan);
|
|
}
|
|
void HAL_CAN_RxFifo0FullCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_RxFifo1FullCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_SleepCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_WakeUpFromRxMsgCallback(CAN_HandleTypeDef *hcan) {}
|
|
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {}
|
|
}
|
|
|
|
static void can1_init() {
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
__HAL_RCC_CAN1_CLK_ENABLE();
|
|
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
|
|
GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
|
GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
|
|
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
|
|
|
// M1_CAN_RX
|
|
// M1_CAN_TX
|
|
|
|
// static_assert(M1_CAN_RX == PA11);
|
|
// static_assert(M1_CAN_TX == PA12);
|
|
|
|
/* CAN1 interrupt Init */
|
|
HAL_NVIC_SetPriority(CAN1_TX_IRQn, 5, 0);
|
|
HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
|
|
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 5, 0);
|
|
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
|
|
HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 5, 0);
|
|
HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
|
|
HAL_NVIC_SetPriority(CAN1_SCE_IRQn, 5, 0);
|
|
HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn);
|
|
|
|
hcan1.Instance = CAN1;
|
|
hcan1.Init.Prescaler = 4;
|
|
hcan1.Init.Mode = CAN_MODE_NORMAL;
|
|
hcan1.Init.SyncJumpWidth = CAN_SJW_3TQ;
|
|
hcan1.Init.TimeSeg1 = CAN_BS1_14TQ;
|
|
hcan1.Init.TimeSeg2 = CAN_BS2_3TQ;
|
|
hcan1.Init.TimeTriggeredMode = ENABLE;
|
|
hcan1.Init.AutoBusOff = ENABLE;
|
|
hcan1.Init.AutoWakeUp = DISABLE;
|
|
hcan1.Init.AutoRetransmission = ENABLE;
|
|
hcan1.Init.ReceiveFifoLocked = ENABLE;
|
|
hcan1.Init.TransmitFifoPriority = DISABLE;
|
|
if (HAL_CAN_Init(&hcan1) != HAL_OK) {
|
|
Error_Handler();
|
|
}
|
|
}
|
|
|
|
HAL_StatusTypeDef ZCAN1::initializeFilter() {
|
|
/**
|
|
* @brief ID区帧格式
|
|
* [ 27:0 ]
|
|
* [ STDID ] [ EXTID ]
|
|
* [11 :9] [8:6] [5:0] [17:16] [15:8] [7:0]
|
|
* 优先级 属性 帧类型 目标ID 源ID
|
|
*/
|
|
HAL_StatusTypeDef HAL_Status;
|
|
CAN_FilterTypeDef sFilterConfig;
|
|
|
|
uint32_t filterId;
|
|
uint32_t mask;
|
|
|
|
memset(&sFilterConfig, 0, sizeof(sFilterConfig));
|
|
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; // 设为MASK模式
|
|
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; // CAN_FILTERSCALE_16BIT
|
|
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; // 关联过滤器到rxfifoNum
|
|
sFilterConfig.FilterActivation = ENABLE; // 激活过滤器
|
|
sFilterConfig.SlaveStartFilterBank = 7; // slave filter start index
|
|
|
|
/*******************************************************************************
|
|
* 接收所有消息 *
|
|
*******************************************************************************/
|
|
filterId = (0); //
|
|
mask = (0); //
|
|
sFilterConfig.FilterBank = 0; //
|
|
sFilterConfig.FilterMaskIdLow = mask & 0xffff; //
|
|
sFilterConfig.FilterMaskIdHigh = (mask & 0xffff0000) >> 16; //
|
|
sFilterConfig.FilterIdLow = filterId & 0xffff; //
|
|
sFilterConfig.FilterIdHigh = (filterId & 0xffff0000) >> 16; //
|
|
HAL_Status = HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
|
|
if (HAL_Status != HAL_OK) {
|
|
ZLOGE(TAG, "HAL_CAN_ConfigFilter filter0 fail");
|
|
return HAL_Status;
|
|
}
|
|
ZLOGI(TAG, "HAL_CAN_ConfigFilter filterID1 %08x", filterId >> 3);
|
|
return HAL_Status;
|
|
}
|
|
|
|
HAL_StatusTypeDef ZCAN1::activateRxIT() {
|
|
HAL_StatusTypeDef hal_status = HAL_ERROR;
|
|
hal_status = HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
|
|
return hal_status;
|
|
}
|
|
|
|
void ZCAN1::zcaninit() {
|
|
if (inited) return;
|
|
|
|
inited = true;
|
|
can1_init();
|
|
HAL_StatusTypeDef hal_status;
|
|
m_lock.init();
|
|
|
|
/**
|
|
* @brief 初始化过滤器
|
|
*/
|
|
hal_status = initializeFilter();
|
|
if (hal_status != HAL_OK) {
|
|
ZLOGE(TAG, "start can initializeFilter fail\r\n");
|
|
return;
|
|
}
|
|
/**
|
|
* @brief 启动CAN
|
|
*/
|
|
hal_status = HAL_CAN_Start(&hcan1); // 开启CAN
|
|
if (hal_status != HAL_OK) {
|
|
ZLOGE(TAG, "start can fail\r\n");
|
|
return;
|
|
}
|
|
/**
|
|
* @brief 监听回调
|
|
*/
|
|
HAL_StatusTypeDef status = activateRxIT();
|
|
if (status != HAL_OK) {
|
|
ZLOGE(TAG, "activateRxIT fail\r\n");
|
|
return;
|
|
}
|
|
zcan1 = this;
|
|
// ZHALCORE::getInstance()->regPeriodJob([this](ZHALCORE::Context &context) { loop(); }, 0);
|
|
rxQueue.initialize(5, sizeof(zcanrx_t));
|
|
canListener.init("canListener");
|
|
canListener.start([this]() {
|
|
while (1) {
|
|
zcanrx_t rx;
|
|
if (rxQueue.receive(&rx, 1000)) {
|
|
// ZLOGI(TAG, "zcanrx 0x%08x:%s", rx.extid, zhex2str(rx.rxpacket, rx.rkpacketlen));
|
|
if (onZcanRx) onZcanRx(&rx);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
bool ZCAN1::_txMsg(const uint32_t extid, const uint8_t txdata[], uint32_t txdatalen, int32_t overtime) {
|
|
zlock_guard l(m_lock);
|
|
CAN_TxHeaderTypeDef pHeader;
|
|
uint8_t aData[8] /*8byte table*/;
|
|
uint32_t txMailBox = 0;
|
|
|
|
uint32_t enterticket = zos_get_tick();
|
|
|
|
memset(&pHeader, 0, sizeof(pHeader));
|
|
memset(aData, 0, sizeof(aData));
|
|
pHeader.StdId = 0x00;
|
|
pHeader.ExtId = extid;
|
|
pHeader.IDE = CAN_ID_EXT;
|
|
pHeader.RTR = CAN_RTR_DATA;
|
|
pHeader.DLC = txdatalen;
|
|
pHeader.TransmitGlobalTime = DISABLE;
|
|
|
|
memcpy(aData, txdata, txdatalen);
|
|
|
|
HAL_StatusTypeDef txsuc = HAL_CAN_AddTxMessage(&hcan1, &pHeader, aData, &txMailBox);
|
|
if (txsuc != HAL_OK) {
|
|
ZLOGE(TAG, "HAL_CAN_AddTxMessage fail");
|
|
return false;
|
|
}
|
|
int i = 1;
|
|
while (HAL_CAN_IsTxMessagePending(&hcan1, txMailBox)) {
|
|
if (zos_haspassedms(enterticket) > (uint32_t)overtime) {
|
|
if (!txNoError) ZLOGE(TAG, "HAL_CAN_IsTxMessagePending overtime");
|
|
HAL_CAN_AbortTxRequest(&hcan1, txMailBox);
|
|
return false;
|
|
}
|
|
osDelay(i);
|
|
i++;
|
|
}
|
|
return true;
|
|
}
|
|
bool ZCAN1::txMsgNoError(const uint32_t extid, const uint8_t txdata[], uint32_t txdatalen, int32_t overtime) {
|
|
zlock_guard l(m_lock);
|
|
txNoError = true;
|
|
bool suc = _txMsg(extid, txdata, txdatalen, overtime);
|
|
txNoError = false;
|
|
return suc;
|
|
}
|
|
bool ZCAN1::txMsg(const uint32_t extid, const uint8_t txdata[], uint32_t txdatalen, int32_t overtime) {
|
|
zlock_guard l(m_lock);
|
|
return _txMsg(extid, txdata, txdatalen, overtime);
|
|
}
|
|
|
|
void ZCAN1::regOnCanMessage(function<void(zcanrx_t *rx)> onmessage) { onZcanRx = onmessage; }
|
|
|
|
bool ZCAN1::getRxMsg(zcanrx_t *rx) {
|
|
/**
|
|
* @brief 读取当前FIFO中缓存了多少帧的数据
|
|
*/
|
|
|
|
CAN_RxHeaderTypeDef pHeader;
|
|
uint32_t level = HAL_CAN_GetRxFifoFillLevel(&hcan1, FIFO_NUM);
|
|
if (level == 0) {
|
|
return false;
|
|
}
|
|
HAL_StatusTypeDef HAL_RetVal;
|
|
HAL_RetVal = HAL_CAN_GetRxMessage(&hcan1, FIFO_NUM, &pHeader, rx->rxpacket);
|
|
rx->extid = pHeader.ExtId;
|
|
rx->rkpacketlen = pHeader.DLC;
|
|
if (HAL_OK == HAL_RetVal) {
|
|
// 处理接收到的can总线数据
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline const char *zhex2str(uint8_t *data, uint32_t len) {
|
|
static char str[256];
|
|
for (uint32_t i = 0; i < len; i++) {
|
|
sprintf(str + i * 2, "%02X", data[i]);
|
|
}
|
|
return str;
|
|
}
|
|
void ZCAN1::STM32_HAL_onCAN_RxFifo0MsgPending(CAN_HandleTypeDef *canHandle) {
|
|
if (canHandle != &hcan1) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* @brief TODO:临时测试代码
|
|
*/
|
|
while (true) {
|
|
zcanrx_t rx;
|
|
bool rxmsg = getRxMsg(&rx);
|
|
if (rxmsg) {
|
|
rxQueue.send(&rx, 0);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
void ZCAN1::STM32_HAL_onCAN_Error(CAN_HandleTypeDef *canHandle) { ZLOGE(TAG, "onCAN_Error\r\n"); }
|