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.
384 lines
12 KiB
384 lines
12 KiB
#include "zcanreceiver.hpp"
|
|
|
|
#ifdef HAL_CAN_MODULE_ENABLED
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
using namespace iflytop;
|
|
using namespace zcr;
|
|
|
|
#define TAG "ZCanCmder"
|
|
|
|
#define OVER_TIME_MS 5
|
|
|
|
ZCanCmder::CFG *ZCanCmder::createCFG(uint8_t deviceId) {
|
|
CFG *cfg = new CFG();
|
|
ZASSERT(cfg != NULL);
|
|
cfg->deviceId = deviceId;
|
|
#ifdef STM32F103xB
|
|
cfg->canHandle = &hcan;
|
|
#else
|
|
cfg->canHandle = &hcan1;
|
|
#endif
|
|
cfg->canFilterIndex0 = 0;
|
|
cfg->maxFilterNum = 7;
|
|
cfg->rxfifoNum = CAN_RX_FIFO0;
|
|
return cfg;
|
|
}
|
|
void ZCanCmder::init(CFG *cfg) {
|
|
HAL_StatusTypeDef hal_status;
|
|
m_config = cfg;
|
|
m_lock.init();
|
|
|
|
/**
|
|
* @brief 初始化CAN
|
|
*/
|
|
|
|
/**
|
|
* @brief 初始化消息接收buf
|
|
*/
|
|
m_canPacketRxBuffer[0].dataIsReady = false;
|
|
m_canPacketRxBuffer[0].id = 0; // 只接收来自主机的消息
|
|
m_canPacketRxBuffer[0].m_canPacketNum = 0;
|
|
|
|
/**
|
|
* @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(m_config->canHandle); // 开启CAN
|
|
if (hal_status != HAL_OK) {
|
|
ZLOGE(TAG, "start can fail\r\n");
|
|
return;
|
|
}
|
|
/**
|
|
* @brief 监听回调
|
|
*/
|
|
ZCanIRQDispatcher::instance().regListener(this);
|
|
HAL_StatusTypeDef status = activateRxIT();
|
|
if (status != HAL_OK) {
|
|
ZLOGE(TAG, "activateRxIT fail\r\n");
|
|
return;
|
|
}
|
|
// ZHALCORE::getInstance()->regPeriodJob([this](ZHALCORE::Context &context) { loop(); }, 0);
|
|
}
|
|
HAL_StatusTypeDef ZCanCmder::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 = m_config->rxfifoNum; // 关联过滤器到rxfifoNum
|
|
sFilterConfig.FilterActivation = ENABLE; // 激活过滤器
|
|
sFilterConfig.SlaveStartFilterBank = m_config->maxFilterNum; // slave filter start index
|
|
|
|
/*******************************************************************************
|
|
* 接收所有消息 *
|
|
*******************************************************************************/
|
|
filterId = (0); //
|
|
mask = (0); //
|
|
sFilterConfig.FilterBank = m_config->canFilterIndex0; //
|
|
sFilterConfig.FilterMaskIdLow = mask & 0xffff; //
|
|
sFilterConfig.FilterMaskIdHigh = (mask & 0xffff0000) >> 16; //
|
|
sFilterConfig.FilterIdLow = filterId & 0xffff; //
|
|
sFilterConfig.FilterIdHigh = (filterId & 0xffff0000) >> 16; //
|
|
HAL_Status = HAL_CAN_ConfigFilter(m_config->canHandle, &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;
|
|
}
|
|
|
|
void ZCanCmder::registerListener(IZcanCmderListener *listener) { m_listenerList.push_back(listener); }
|
|
void ZCanCmder::sendPacket(uint8_t *packet, size_t len) {
|
|
/**
|
|
* @brief
|
|
*/
|
|
int npacket = len / 8 + (len % 8 == 0 ? 0 : 1);
|
|
if (npacket > 255) {
|
|
ZLOGE(TAG, "sendPacket fail, len:%d", len);
|
|
return;
|
|
}
|
|
int finalpacketlen = len % 8 == 0 ? 8 : len % 8;
|
|
|
|
for (uint8_t i = 0; i < npacket; i++) {
|
|
bool suc = false;
|
|
if (i == npacket - 1) {
|
|
suc = sendPacketSub(npacket, i, packet + i * 8, finalpacketlen, OVER_TIME_MS);
|
|
} else {
|
|
suc = sendPacketSub(npacket, i, packet + i * 8, 8, OVER_TIME_MS);
|
|
}
|
|
if (!suc) {
|
|
ZLOGE(TAG, "sendPacket fail, packet(%d:%d)", npacket, i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
#if 0
|
|
void ZCanCmder::sendAck(zcr_cmd_header_t *cmdheader, uint8_t *data, size_t len) {
|
|
zlock_guard l(m_lock);
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, cmdheader, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_ack;
|
|
memcpy(txheader->data, data, len);
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + len);
|
|
}
|
|
void ZCanCmder::sendErrorAck(zcr_cmd_header_t *cmdheader, uint16_t id, uint32_t errcode) {
|
|
zlock_guard l(m_lock);
|
|
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, cmdheader, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_error_ack;
|
|
zcan_cmder_error_ack_t *error_ack = (zcan_cmder_error_ack_t *)txheader->data;
|
|
error_ack->id = id;
|
|
error_ack->errorcode = errcode;
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + sizeof(zcan_cmder_error_ack_t));
|
|
}
|
|
|
|
void ZCanCmder::sendExecStatusReport(zcr_cmd_header_t *rxcmdheader, uint8_t *data, size_t len) {
|
|
zlock_guard l(m_lock);
|
|
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, rxcmdheader, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_cmd_exec_status_report;
|
|
memcpy(txheader->data, data, len);
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + len);
|
|
}
|
|
void ZCanCmder::sendStatusReport(zcr_cmd_header_t *rxcmdheader, uint8_t *data, size_t len) {
|
|
zlock_guard l(m_lock);
|
|
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, rxcmdheader, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_report;
|
|
memcpy(txheader->data, data, len);
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + len);
|
|
}
|
|
#endif
|
|
int32_t ZCanCmder::sendBufAck(zcr_cmd_header_t *rx_cmd_header, uint8_t *data, int32_t len) {
|
|
zlock_guard l(m_lock);
|
|
ZASSERT(sizeof(txbuff) > sizeof(zcr_cmd_header_t) + len);
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, rx_cmd_header, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_ack;
|
|
memcpy(txheader->data, data, len);
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + len);
|
|
return 0;
|
|
}
|
|
int32_t ZCanCmder::triggerEvent(zcr_cmd_header_t *cmd_header, uint8_t *data, int32_t len) {
|
|
zlock_guard l(m_lock);
|
|
m_reportIndex++;
|
|
ZASSERT(sizeof(txbuff) > sizeof(zcr_cmd_header_t) + len);
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, cmd_header, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_event;
|
|
txheader->packetindex = m_reportIndex;
|
|
memcpy(txheader->data, data, len);
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + len);
|
|
return 0;
|
|
}
|
|
|
|
int32_t ZCanCmder::sendAck(zcr_cmd_header_t *rx_cmd_header, int32_t *ackvar, int32_t nack) {
|
|
zlock_guard l(m_lock);
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, rx_cmd_header, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_ack;
|
|
|
|
int32_t *txackcache = (int32_t *)txheader->data;
|
|
for (int i = 0; i < nack; i++) {
|
|
txackcache[i] = ackvar[i];
|
|
}
|
|
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + sizeof(int32_t) * nack);
|
|
return 0;
|
|
}
|
|
int32_t ZCanCmder::sendErrorAck(zcr_cmd_header_t *rx_cmd_header, int32_t errorcode) {
|
|
zlock_guard l(m_lock);
|
|
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
|
|
memcpy(txheader, rx_cmd_header, sizeof(zcr_cmd_header_t));
|
|
txheader->packetType = kptv2_error_ack;
|
|
|
|
int32_t *txackcache = (int32_t *)txheader->data;
|
|
txackcache[0] = errorcode;
|
|
|
|
sendPacket(txbuff, sizeof(zcr_cmd_header_t) + sizeof(int32_t));
|
|
return 0;
|
|
}
|
|
|
|
bool ZCanCmder::sendPacketSub(int npacket, int packetIndex, uint8_t *packet, size_t len, int overtimems) {
|
|
zlock_guard l(m_lock);
|
|
|
|
// ZLOGI(TAG, "sendPacketSub(%d:%d)", npacket, packetIndex);
|
|
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 = (m_config->deviceId << 16) | (npacket << 8) | packetIndex;
|
|
pHeader.IDE = CAN_ID_EXT;
|
|
pHeader.RTR = CAN_RTR_DATA;
|
|
pHeader.DLC = len;
|
|
pHeader.TransmitGlobalTime = DISABLE;
|
|
|
|
memcpy(aData, packet, len);
|
|
|
|
m_lastTransmitStatus = HAL_CAN_AddTxMessage(m_config->canHandle, &pHeader, aData, &txMailBox);
|
|
if (m_lastTransmitStatus != HAL_OK) {
|
|
ZLOGE(TAG, "HAL_CAN_AddTxMessage fail");
|
|
return false;
|
|
}
|
|
|
|
while (HAL_CAN_IsTxMessagePending(m_config->canHandle, txMailBox)) {
|
|
if (zos_haspassedms(enterticket) > (uint32_t)overtimems) {
|
|
m_lastTransmitStatus = HAL_TIMEOUT;
|
|
HAL_CAN_AbortTxRequest(m_config->canHandle, txMailBox);
|
|
return false;
|
|
}
|
|
// m_os->sleepMS(1);
|
|
}
|
|
if (txPacketInterval_ms > 0) {
|
|
osDelay(txPacketInterval_ms);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ZCanCmder::getRxMessage(CAN_RxHeaderTypeDef *pHeader, uint8_t aData[] /*8byte table*/) {
|
|
/**
|
|
* @brief 读取当前FIFO中缓存了多少帧的数据
|
|
*/
|
|
uint32_t level = HAL_CAN_GetRxFifoFillLevel(m_config->canHandle, m_config->rxfifoNum);
|
|
if (level == 0) {
|
|
return false;
|
|
}
|
|
HAL_StatusTypeDef HAL_RetVal;
|
|
HAL_RetVal = HAL_CAN_GetRxMessage(m_config->canHandle, m_config->rxfifoNum, pHeader, aData);
|
|
if (HAL_OK == HAL_RetVal) {
|
|
// 处理接收到的can总线数据
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
void ZCanCmder::STM32_HAL_onCAN_RxFifo0MsgPending(CAN_HandleTypeDef *canHandle) {
|
|
/**
|
|
* @brief 中断上下文
|
|
*/
|
|
// ZLOG_INFO("%s\n", __FUNCTION__);
|
|
// printf("------------------%s\n", __FUNCTION__);
|
|
if (canHandle != m_config->canHandle) {
|
|
return;
|
|
}
|
|
/**
|
|
* @brief 处理can接收到消息
|
|
*/
|
|
CAN_RxHeaderTypeDef pHeader;
|
|
uint8_t aData[8] /*8byte table*/;
|
|
while (getRxMessage(&pHeader, aData)) {
|
|
/**
|
|
* @brief 消息格式
|
|
*
|
|
* [2] [3bit] [8bit] [8bit] [8bit]
|
|
* , from frameNum frameId
|
|
*/
|
|
uint8_t from = (pHeader.ExtId >> 16 & 0xFF);
|
|
uint8_t nframe = (pHeader.ExtId & 0xFF00) >> 8;
|
|
uint8_t frameId = (pHeader.ExtId & 0x00FF);
|
|
CanPacketRxBuffer *rxbuf = &m_canPacketRxBuffer[0];
|
|
if (from != rxbuf->id) {
|
|
// 目前只接收来自主机的消息
|
|
continue;
|
|
}
|
|
|
|
if (rxbuf->dataIsReady) {
|
|
// 上次接收到的消息还没有来的急处理
|
|
continue;
|
|
}
|
|
/**
|
|
* @TODO:判断是否丢包
|
|
*/
|
|
if (frameId == 0) {
|
|
rxbuf->m_canPacketNum = 0;
|
|
}
|
|
|
|
if (rxbuf->m_canPacketNum < 255) {
|
|
rxbuf->m_canPacket[rxbuf->m_canPacketNum].dlc = pHeader.DLC;
|
|
memcpy(rxbuf->m_canPacket[rxbuf->m_canPacketNum].aData, aData, 8);
|
|
rxbuf->m_canPacketNum++;
|
|
}
|
|
if (nframe == frameId + 1) {
|
|
rxbuf->dataIsReady = true;
|
|
}
|
|
}
|
|
|
|
// deactivateRxIT();
|
|
}
|
|
void ZCanCmder::STM32_HAL_onCAN_Error(CAN_HandleTypeDef *canHandle) {
|
|
if (canHandle != m_config->canHandle) {
|
|
return;
|
|
}
|
|
ZLOGE(TAG, "onCAN_Error\r\n");
|
|
}
|
|
void ZCanCmder::loop() {
|
|
CanPacketRxBuffer *rxbuf = &m_canPacketRxBuffer[0];
|
|
if (rxbuf->dataIsReady) {
|
|
int dataoff = 0;
|
|
for (size_t i = 0; i < rxbuf->m_canPacketNum; i++) {
|
|
memcpy(rxbuf->rxdata + dataoff, rxbuf->m_canPacket[i].aData, rxbuf->m_canPacket[i].dlc);
|
|
dataoff += rxbuf->m_canPacket[i].dlc;
|
|
}
|
|
rxbuf->rxdataSize = dataoff;
|
|
// ZLOGI(TAG,"rx packet");
|
|
|
|
for (auto &var : m_listenerList) {
|
|
if (var) var->onRceivePacket(rxbuf->get_cmdheader(), rxbuf->get_params(), rxbuf->get_params_len());
|
|
}
|
|
rxbuf->dataIsReady = false;
|
|
}
|
|
}
|
|
HAL_StatusTypeDef ZCanCmder::activateRxIT() {
|
|
HAL_StatusTypeDef hal_status = HAL_ERROR;
|
|
if (m_config->rxfifoNum == CAN_RX_FIFO0) {
|
|
hal_status = HAL_CAN_ActivateNotification(m_config->canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);
|
|
} else if (m_config->rxfifoNum == CAN_RX_FIFO1) {
|
|
hal_status = HAL_CAN_ActivateNotification(m_config->canHandle, CAN_IT_RX_FIFO1_MSG_PENDING);
|
|
} else {
|
|
ZLOGE(TAG, "start can HAL_CAN_ActivateNotification CAN_IT_RX_FIFO0_MSG_PENDING fail\r\n");
|
|
return hal_status;
|
|
}
|
|
return hal_status;
|
|
}
|
|
HAL_StatusTypeDef ZCanCmder::deactivateRxIT() {
|
|
HAL_StatusTypeDef hal_status = HAL_ERROR;
|
|
if (m_config->rxfifoNum == CAN_RX_FIFO0) {
|
|
hal_status = HAL_CAN_DeactivateNotification(m_config->canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);
|
|
} else if (m_config->rxfifoNum == CAN_RX_FIFO1) {
|
|
hal_status = HAL_CAN_DeactivateNotification(m_config->canHandle, CAN_IT_RX_FIFO1_MSG_PENDING);
|
|
} else {
|
|
ZLOGE(TAG, "start can HAL_CAN_ActivateNotification CAN_IT_RX_FIFO0_MSG_PENDING fail\r\n");
|
|
return hal_status;
|
|
}
|
|
return hal_status;
|
|
}
|
|
|
|
#endif
|