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.
 
 
 

394 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
#define MAIN_DEVICE_CAN_ID 0
static void assign_packet_checksum(uint8_t *packet, int len) {
uint8_t checksum = 0;
for (int i = 0; i < len - 1; i++) {
checksum += packet[i];
}
packet[len - 1] = checksum;
}
ZCanReceiver::CFG *ZCanReceiver::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 ZCanReceiver::initialize(CFG *cfg) {
HAL_StatusTypeDef hal_status;
m_config = cfg;
m_lock.init();
m_rxFramePool.init();
m_pendingMsgQueue.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(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 ZCanReceiver::initializeFilter() {
/**
* @brief 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 = (MAIN_DEVICE_CAN_ID); //
mask = (0xffffffff); //
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 ZCanReceiver::registerListener(IZCanRxProcesser *listener) { rxprocesser = listener; }
// static inline const char *dumphex(uint8_t *packet, size_t len) {
// static char buf[1024];
// memset(buf, 0, sizeof(buf));
// for (size_t i = 0; i < len; i++) {
// sprintf(buf + i * 2, "%02x", packet[i]);
// }
// return buf;
// }
static const char *hex2str(const char *hex, size_t len) __attribute__((unused));
static const char *hex2str(const char *hex, size_t len) {
static char buf[256];
memset(buf, 0, sizeof(buf));
for (size_t i = 0; i < len; i++) {
sprintf(buf + i * 2, "%02X", hex[i]);
}
return buf;
}
void ZCanReceiver::sendPacket(uint8_t *packet, size_t len) {
// ZLOGI(TAG, "tx %s(%d)", hex2str((const char *)packet, len), len);
/**
* @brief
*/
int npacket = len / 7 + (len % 7 == 0 ? 0 : 1);
if (npacket > 255) {
ZLOGE(TAG, "sendPacket fail, len:%d", len);
return;
}
int finalpacketlen = len % 7 == 0 ? 7 : len % 7;
for (uint8_t i = 0; i < npacket; i++) {
bool suc = false;
if (i == npacket - 1) {
suc = sendPacketSub(npacket, i, packet + i * 7, finalpacketlen, OVER_TIME_MS);
} else {
suc = sendPacketSub(npacket, i, packet + i * 7, 7, OVER_TIME_MS);
}
if (!suc) {
ZLOGE(TAG, "sendPacket fail, packet(%d:%d)", npacket, i);
return;
}
}
}
int32_t ZCanReceiver::sendBufAck(zcr_cmd_header_t *rx_cmd_header, uint8_t *data, int32_t len) {
zlock_guard l(m_lock);
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
int packetlen = sizeof(zcr_cmd_header_t) + len + 1;
ZASSERT(sizeof(txbuff) > packetlen);
memcpy(txheader, rx_cmd_header, sizeof(zcr_cmd_header_t));
txheader->packetType = kptv2_ack;
txheader->datalen = len;
memcpy(txheader->data, data, len);
assign_packet_checksum(txbuff, packetlen);
sendPacket(txbuff, packetlen);
return 0;
}
int32_t ZCanReceiver::triggerEvent(zcr_cmd_header_t *cmd_header, uint8_t *data, int32_t len) {
zlock_guard l(m_lock);
zcr_cmd_header_t *txheader = (zcr_cmd_header_t *)txbuff;
int packetlen = sizeof(zcr_cmd_header_t) + len + 1;
ZASSERT(sizeof(txbuff) > packetlen);
memcpy(txheader, cmd_header, sizeof(zcr_cmd_header_t));
txheader->packetType = kptv2_event;
txheader->index = m_reportIndex;
txheader->datalen = len;
memcpy(txheader->data, data, len);
assign_packet_checksum(txbuff, packetlen);
sendPacket(txbuff, packetlen);
m_reportIndex++;
return 0;
}
int32_t ZCanReceiver::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;
int packetlen = sizeof(zcr_cmd_header_t) + sizeof(int32_t) * nack + 1;
memcpy(txheader, rx_cmd_header, sizeof(zcr_cmd_header_t));
txheader->packetType = kptv2_ack;
int32_t *txackcache = (int32_t *)txheader->data;
txheader->datalen = nack * sizeof(int32_t);
for (int i = 0; i < nack; i++) {
txackcache[i] = ackvar[i];
}
assign_packet_checksum(txbuff, packetlen);
sendPacket(txbuff, packetlen);
return 0;
}
int32_t ZCanReceiver::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;
int32_t *txackcache = (int32_t *)txheader->data;
int packetlen = sizeof(zcr_cmd_header_t) + sizeof(int32_t) * 1 + 1;
memcpy(txheader, rx_cmd_header, sizeof(zcr_cmd_header_t));
txheader->packetType = kptv2_error_ack;
txheader->datalen = sizeof(int32_t);
txackcache[0] = errorcode;
assign_packet_checksum(txbuff, packetlen);
sendPacket(txbuff, packetlen);
return 0;
}
bool ZCanReceiver::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 = m_config->deviceId;
pHeader.ExtId = 0;
pHeader.IDE = CAN_ID_STD;
pHeader.RTR = CAN_RTR_DATA;
pHeader.DLC = len + 1;
pHeader.TransmitGlobalTime = DISABLE;
aData[0] = (npacket << 4) | packetIndex;
memcpy(aData + 1, 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);
osDelay(1);
}
if (txPacketInterval_ms > 0) {
osDelay(txPacketInterval_ms);
}
return true;
}
bool ZCanReceiver::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 ZCanReceiver::STM32_HAL_onCAN_RxFifo0MsgPending(CAN_HandleTypeDef *canHandle) {
/**
* @brief 中断上下文
*/
if (canHandle != m_config->canHandle) {
return;
}
/**
* @brief 处理can接收到消息
*/
CAN_RxHeaderTypeDef pHeader;
uint8_t aData[8] = {0};
// CanPacketRxBuffer *rxbuf = &m_canPacketRxBuffer;
while (getRxMessage(&pHeader, aData)) {
// 过滤掉非标准帧和远程帧,和DLC为0的帧
if (pHeader.RTR != CAN_RTR_DATA || pHeader.IDE != CAN_ID_STD) continue;
if (pHeader.DLC == 0) continue;
// printf(".");
/**
* @brief 处理接收到的数据
*/
uint8_t from = (pHeader.StdId & 0xFF);
uint8_t nframe = (aData[0] & 0xF0) >> 4;
uint8_t frameoff = (aData[0] & 0x0F);
// 只接收来自主机的消息
if (from != MAIN_DEVICE_CAN_ID) continue;
// 当frameoff==0,重置接收缓存
if (frameoff == 0) {
if (curRxBuf != nullptr) {
m_rxFramePool.free(&curRxBuf);
}
curRxBuf = m_rxFramePool.alloc();
}
if (!curRxBuf) return; // 分配内存失败
// 当接收到非期望frameoff的数据时,说明发生了丢包,重置接收缓存
if (curRxBuf->canPacketNum != frameoff) {
m_rxFramePool.free(&curRxBuf);
continue;
}
// 接收到有效包
if (curRxBuf->rxdataLen + pHeader.DLC - 1 < sizeof(curRxBuf->rxdata)) {
memcpy(&curRxBuf->rxdata[curRxBuf->rxdataLen], &aData[1], pHeader.DLC - 1);
curRxBuf->canPacketNum++;
curRxBuf->rxdataLen += pHeader.DLC - 1;
}
if (nframe == frameoff + 1) {
curRxBuf->npacket = nframe;
bool pass = rxprocesser->filterPacket(curRxBuf);
if (pass) {
// printf("y\n");
m_pendingMsgQueue.sendIRQ(curRxBuf);
} else {
// printf("x\n");
m_rxFramePool.free(&curRxBuf);
}
}
}
// deactivateRxIT();
}
void ZCanReceiver::STM32_HAL_onCAN_Error(CAN_HandleTypeDef *canHandle) {
if (canHandle != m_config->canHandle) {
return;
}
ZLOGE(TAG, "onCAN_Error\r\n");
}
void ZCanReceiver::processRx() {
auto *rx = m_pendingMsgQueue.receive();
if (rx) {
// !处理接收到的数据!
if (rxprocesser) rxprocesser->processRxPacket(rx);
}
}
void ZCanReceiver::loop() { processRx(); }
HAL_StatusTypeDef ZCanReceiver::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 ZCanReceiver::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