/******************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Quick Ultralite module.
**
** $QT_BEGIN_LICENSE:COMM$
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** $QT_END_LICENSE$
**
******************************************************************************/
#include "candriverhelper.h"extern"C" {
#include <rscanfd/rscanfd_uciaprcn/rscfd.h>#include <rscanfd/rscanfd_uciaprcn/rscfd_p.h>#include <rscanfd/rscanfd_uciaprcn/rscfd_s.h>
}
#include <iostream>#include <algorithm>#include <canlog.h>#include <etl/iterator.h>usingnamespace std;
// NOTE:// Use CANBUS_USE_RX_FIFOS to Switch between using MessageBoxes and FIFO buffers for RX messages// Major differences:// MessageBox - no buffering at all, only single message could be stored there,// no interrupts on incomming messsages. Can cause loosing messages.// FIFO - Fifo element size and fifo length can be customized (see configure()). Messages are buffered,// low risk of loossing message, RX interrupts available. When not able to flush fifo fast enough,// fifo can get full, causing CAN error interrupts and losing messages// (no overwriting of existing messages is possible).namespace {
constunsignedint NUM_RX_FIFOS =1; // max is EE_RSCFD_MAXRXFIFOS
ee_rscfd_cfg_global g_global_config = EE_RSCFD_A_GCFG_BASIC;
ee_rscfd_cfg_channel g_channel_config = EE_RSCFD_A_CHCFG_BASIC;
ee_rscfd_a_afl g_filter_config = EE_RSCFD_A_AFL_RXBOX_ANY;
bool newMessages =false;
} // namespacenamespace CanBus {
namespace CanDriverHelper {
staticvoid int_rx0(void)
{
newMessages =true;
}
void configure(bool canFD, uint32_t bitrate, uint32_t dataBitrate, uint32_t numChannels)
{
// Alter global config
g_global_config.gctr.ie =0x0F; // enable interrupts form EE_RSCFD_GINT_DLCCHECK to EE_RSCFD_GINT_FDMSGOVF// Configure AFL registersconstunsignedint maxAFLRules = std::min(MAX_RECEIVE_RULES_FOR_UNIT / numChannels, MAX_RECEIVE_RULES_PER_CHANNEL);
for (int i =0; i < numChannels; ++i) {
g_global_config.rnc[i]= maxAFLRules;
}
#ifdef CANBUS_USE_RX_FIFOS
g_global_config.rmnb.nrxmb =0; // no standard RX boxes
g_global_config.rmnb.rmpls =0; // size of message boxfor (int i =0; i < NUM_RX_FIFOS; ++i) {
g_global_config.rfcc[i].rfie = EE_RSCFD_SET; // Enable RX interrupts
g_global_config.rfcc[i].rfpls = EE_RSCFD_FIFODL_16; // Size of fifo object
g_global_config.rfcc[i].rfdc = EE_RSCFD_FIFO_DEPTH_64; // Fifo depth
g_global_config.rfcc[i].rfim = EE_RSCFD_FIFO_INT_ONEVERY; // Interrupt on every message
g_global_config.rfcc[i].rfigcv
= EE_RSCFD_FIFO_ILEVEL_1D8; // Interrupt on fifo fill level 1 (not used with EE_RSCFD_FIFO_INT_ONEVERY)
}
#endif// Alter channel config
g_channel_config.arb_bitrate = bitrate;
g_channel_config.data_bitrate = canFD ? dataBitrate : 0;
g_channel_config.ctr.ie =0XFF; // enable interupts range from EE_RSCFD_CINT_BUSERR to EE_RSCFD_CINT_ARBLOST
g_channel_config.ctr.ie &=~EE_RSCFD_ERROR_ARBLOST; // arbitration lost is a normal thing// Alter filer settings
g_filter_config.mask.id = EE_RSCFD_MASK_IDDONTCARE;
#ifdef CANBUS_USE_RX_FIFOS
g_filter_config.ptr0.rmv = EE_RSCFD_CLEAR; // dissable messagebox
g_filter_config.ptr1.rxfifomask = EE_RSCFD_AFL_RXFIF0_EN0; // RX0#else
g_filter_config.ptr0.rmdp =0; // message box 0
g_filter_config.ptr0.rmv = EE_RSCFD_SET; // enable mesage boxes#endif
}
bool stopCAN(uint32_t controllerId)
{
LOG_CAN_INFO("Stopping CAN controller %d", controllerId);
if (EE_RSCFD_OK != EE_RSCFD_Stop(controllerId, EE_RSCFD_GLOBAL, EE_RSCFD_OPMODE_RESET)) {
LOG_CAN_ERROR("Failed to stop CAN controller %d", controllerId);
returnfalse;
}
LOG_CAN_INFO("CAN Controller %d stopped", controllerId);
returntrue;
}
bool initCAN(uint32_t controllerId, uint32_t numChannels)
{
LOG_CAN_INFO("Initializing CAN controller %d, num channels %d", controllerId, numChannels);
/* Configuration */if (EE_RSCFD_ERROR == EE_RSCFD_SetGlobalConfiguration(controllerId,&g_global_config)) {
LOG_CAN_ERROR("Failed to set global config for controller %d", controllerId);
returnfalse;
}
#ifdef CANBUS_USE_RX_FIFOSif (EE_RSCFD_ERROR == EE_RSCFD_SetGlobalFIFOConfiguration(controllerId,&g_global_config)) {
LOG_CAN_ERROR("Failed to set global FIFO config for controller %d", controllerId);
returnfalse;
}
#endif
LOG_CAN_INFO("Global config set for controller %d", controllerId);
for (unsignedint channelNo =0; channelNo < numChannels; ++channelNo) {
/* Port activation */if (EE_RSCFD_ERROR == EE_RSCFD_PortEnable(controllerId, channelNo)) {
LOG_CAN_ERROR("Failed to enable controller %d, port %d", controllerId, channelNo);
returnfalse;
}
/* Perform global activation */if (EE_RSCFD_ERROR
== EE_RSCFD_Start(controllerId,
channelNo,
EE_RSCFD_OPMODE_RESET,/* Channel Reset */
EE_RSCFD_CLEAR,
EE_RSCFD_CLEAR)) {
LOG_CAN_ERROR("Failed to reset controller %d, channel %d", controllerId, channelNo);
returnfalse;
}
if (EE_RSCFD_ERROR == EE_RSCFD_SetChannelConfiguration(controllerId, channelNo,&g_channel_config)) {
LOG_CAN_ERROR("Failed to set channel configuration, controller %d, channel %d", controllerId, channelNo);
returnfalse;
}
LOG_CAN_INFO("Channel config set, controller %d, channel %d", controllerId, channelNo);
}
LOG_CAN_INFO("CAN controller %d initialized", controllerId);
returntrue;
}
bool startCAN(uint32_t controllerId, uint32_t channelNo)
{
/* Activate Units and Channels */if (EE_RSCFD_ERROR
== EE_RSCFD_Start(controllerId,
channelNo,
EE_RSCFD_OPMODE_OPER,/* Channel Reset */
EE_RSCFD_SET,
EE_RSCFD_SET)) {
LOG_CAN_ERROR("Failed to start controller %d, channel %d", controllerId, channelNo);
returnfalse;
}
LOG_CAN_INFO("CAN Started, controller %d, channel %d", controllerId, channelNo);
returntrue;
}
bool setupReceieveRules(uint32_t controllerId, uint32_t channelNo,const MessageFilterList &filterList)
{
if (filterList.empty()) {
// Default filter for receiving all messagesif (EE_RSCFD_SetAFLEntry(controllerId, channelNo,0,&g_filter_config) != EE_RSCFD_OK) {
LOG_CAN_ERROR("Failed to set default message filter for controller %d, channel %d", controllerId, channelNo);
returnfalse;
}
} else {
// Use default filter as a base
ee_rscfd_a_afl theRule = g_filter_config;
for (MessageFilterList::const_iterator it = filterList.cbegin(); it != filterList.cend(); ++it) {
const u32 ruleId = std::distance(filterList.cbegin(), it);
theRule.id.id = it->id;
theRule.mask.id = it->mask;
theRule.mask.rtr = EE_RSCFD_MASK_IDDONTCARE;
theRule.mask.ide = EE_RSCFD_MASK_IDDONTCARE;
if (it->remoteFrame) {
theRule.id.rtr =*it->remoteFrame ? EE_RSCFD_FRAME_REMOTE : EE_RSCFD_FRAME_DATA;
theRule.mask.rtr = EE_RSCFD_MASK_FILTER;
}
if (it->extenedFrame) {
theRule.id.ide =*it->extenedFrame ? EE_RSCFD_ID_EXT : EE_RSCFD_ID_STD;
theRule.mask.ide = EE_RSCFD_MASK_FILTER;
}
if (EE_RSCFD_SetAFLEntry(controllerId, channelNo, ruleId,&theRule) != EE_RSCFD_OK) {
LOG_CAN_ERROR("Failed to set message filter rule %d for controller %d, channel %d",
ruleId,
controllerId,
channelNo);
LOG_CAN_ERROR("Maximum allowed rules for this channel is %d", g_global_config.rnc[channelNo]);
returnfalse;
}
}
}
LOG_CAN_INFO("Initialized filters for controller %d, channel %d", controllerId, channelNo);
returntrue;
}
bool setupFIFOs(uint32_t controllerId)
{
for (int fifo =0; fifo < NUM_RX_FIFOS; ++fifo) {
if (EE_RSCFD_EnableRXFIFO(controllerId, fifo, EE_RSCFD_RX_FIFO_EN) != EE_RSCFD_OK) {
LOG_CAN_ERROR("Failed to enable FIFO %d for controller %d", fifo, controllerId);
returnfalse;
}
}
LOG_CAN_INFO("FIFOs setup complete for controller %d", controllerId);
returntrue;
}
bool setGlobalInterrupts(uint32_t controllerId, InterruptVector errorInterrupt)
{
if (errorInterrupt
&& EE_RSCFD_CreateInterrupt(controllerId,
EE_RSCFD_GLOBAL,
EE_RSCFD_INT_GERR,
EE_RSCFD_INTENABLEDEFAULT,
errorInterrupt)
!= EE_RSCFD_OK) {
LOG_CAN_ERROR("Failed to create Global Error interrupt, for controller %d", controllerId);
returnfalse;
}
LOG_CAN_INFO("Global interrupts ready, for controller %d", controllerId);
returntrue;
}
bool setChannelInterrupts(uint32_t controllerId, uint32_t channelNo, InterruptVector errorInterrupt)
{
// No RX interrupts when using message boxes#ifdef CANBUS_USE_RX_FIFOSif (EE_RSCFD_CreateInterrupt(controllerId, EE_RSCFD_GLOBAL, EE_RSCFD_INT_RXF0, EE_RSCFD_INTENABLEDEFAULT, int_rx0)
!= EE_RSCFD_OK) {
LOG_CAN_ERROR("Failed to create RX interrupt for controller %d, channel %d", controllerId, channelNo);
returnfalse;
}
#endifif (errorInterrupt
&& EE_RSCFD_CreateInterrupt(controllerId, channelNo, EE_RSCFD_INT_CERR, EE_RSCFD_INTENABLEDEFAULT, errorInterrupt)
!= EE_RSCFD_OK) {
LOG_CAN_ERROR("Failed to create error interrupt for controller %d, channel %d", controllerId, channelNo);
returnfalse;
}
LOG_CAN_INFO("Interrupts ready for controller %d, channel %d", controllerId, channelNo);
returntrue;
}
bool printFIFOStatus(uint32_t controllerId, bool checkEmpty, bool checkFull, bool checkLost)
{
if (!checkEmpty &&!checkFull &&!checkLost) {
returntrue;
}
u08 status =0;
for (int fifo =0; fifo < NUM_RX_FIFOS; ++fifo) {
if (checkEmpty) {
if (EE_RSCFD_GetFIFOStatus(controllerId, EE_RSCFD_GLOBAL, fifo, EE_RSCFD_FIFO_STATUS_EMPTY,&status)
!= EE_RSCFD_OK) {
returnfalse;
} elseif (status) {
LOG_CAN_INFO("RX FIFO #%d for controller %d is empty", fifo, controllerId);
}
}
if (checkFull) {
if (EE_RSCFD_GetFIFOStatus(controllerId, EE_RSCFD_GLOBAL, fifo, EE_RSCFD_FIFO_STATUS_FULL,&status)
!= EE_RSCFD_OK) {
returnfalse;
} elseif (status) {
LOG_CAN_INFO("RX FIFO #%d controller %d is full", fifo, controllerId);
}
}
if (checkLost) {
if (EE_RSCFD_GetFIFOStatus(controllerId, EE_RSCFD_GLOBAL, fifo, EE_RSCFD_FIFO_STATUS_LOST,&status)
!= EE_RSCFD_OK) {
returnfalse;
} elseif (status) {
LOG_CAN_INFO("RX FIFO #%d controller %d lost messages", fifo, controllerId);
}
}
}
returntrue;
}
bool receiveMessages(uint32_t controllerId, CanMessageHandler receivedMessageHandler)
{
// No RX interrupts when using message boxes#ifdef CANBUS_USE_RX_FIFOSif (!newMessages) {
// No interrups == no messages, move along.returntrue;
}
newMessages =false;
#endif
u08 status = EE_RSCFD_FAULT_NODATA;
do {
ee_rscfd_message receivedMessage = {0};
#ifdef CANBUS_USE_RX_FIFOS
receivedMessage.path = EE_RSCFD_PATH_RXFIFO;
receivedMessage.pathdetail =0; // RX0#else
receivedMessage.path = EE_RSCFD_PATH_MSGBOX;
receivedMessage.pathdetail =0; // Messasge Box 0#endifif (EE_RSCFD_ReceiveMessage(controllerId,&status,&receivedMessage) != EE_RSCFD_OK) {
LOG_CAN_ERROR("Fatal error while receiving messages for controller %d", controllerId);
returnfalse;
}
if (status == EE_RSCFD_FAULT_NONE) {
receivedMessageHandler(receivedMessage);
} elseif (status != EE_RSCFD_FAULT_NODATA) {
LOG_CAN_ERROR("Error while receiving messages for controller %d, status: %d", controllerId, (int) status);
}
} while (status == EE_RSCFD_FAULT_NONE);
// Other status than "no data" should be considered as an errorreturn status == EE_RSCFD_FAULT_NODATA;
}
bool sendMessage(unsignedint controllerId,unsignedint channelNo, ee_rscfd_message &message)
{
u08 sendStatus = EE_RSCFD_FAULT_NONE;
message.path = EE_RSCFD_PATH_MSGBOX; /* Send via Message Box */
message.pathdetail = EE_RSCFD_PATHDETAIL_ANY; /* use any box... */
message.hdr.thlen = EE_RSCFD_CLEAR; /* No entry in THL */if (EE_RSCFD_SendMessage(controllerId, channelNo,&sendStatus,&message) != EE_RSCFD_OK) {
LOG_CAN_ERROR("Sending message failed completely for controller %d, channel %d", controllerId, channelNo);
returnfalse;
}
if (sendStatus != EE_RSCFD_FAULT_NONE) {
LOG_CAN_ERROR("Sending message for controller %d, channel %d failed with status: %d",
controllerId,
channelNo,
(int) sendStatus);
returnfalse;
}
returntrue;
}
uint16_t getError(uint32_t controllerId, uint32_t channelNo)
{
u16 InteruptErrorFlag =0;
u16 LastErrorFlag =0;
EE_RSCFD_GetError(controllerId, channelNo,&InteruptErrorFlag,&LastErrorFlag);
return InteruptErrorFlag;
}
} // namespace CanDriverHelper
} // namespace CanBus