C

Qt Quick Ultralite Automotive Cluster Demo

/****************************************************************************** ** ** 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 <algorithm> #include <canlog.h> #include <etl/iterator.h> using namespace 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 { const unsigned int 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; } // namespace namespace CanBus { namespace CanDriverHelper { static void 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 registers const unsigned int 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 box for (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); return false; } LOG_CAN_INFO("CAN Controller %d stopped", controllerId); return true; } 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); return false; } #ifdef CANBUS_USE_RX_FIFOS if (EE_RSCFD_ERROR == EE_RSCFD_SetGlobalFIFOConfiguration(controllerId, &g_global_config)) { LOG_CAN_ERROR("Failed to set global FIFO config for controller %d", controllerId); return false; } #endif LOG_CAN_INFO("Global config set for controller %d", controllerId); for (unsigned int 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); return false; } /* 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); return false; } 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); return false; } LOG_CAN_INFO("Channel config set, controller %d, channel %d", controllerId, channelNo); } LOG_CAN_INFO("CAN controller %d initialized", controllerId); return true; } 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); return false; } LOG_CAN_INFO("CAN Started, controller %d, channel %d", controllerId, channelNo); return true; } bool setupReceieveRules(uint32_t controllerId, uint32_t channelNo, const MessageFilterList &filterList) { if (filterList.empty()) { // Default filter for receiving all messages if (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); return false; } } 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]); return false; } } } LOG_CAN_INFO("Initialized filters for controller %d, channel %d", controllerId, channelNo); return true; } 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); return false; } } LOG_CAN_INFO("FIFOs setup complete for controller %d", controllerId); return true; } 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); return false; } LOG_CAN_INFO("Global interrupts ready, for controller %d", controllerId); return true; } bool setChannelInterrupts(uint32_t controllerId, uint32_t channelNo, InterruptVector errorInterrupt) { // No RX interrupts when using message boxes #ifdef CANBUS_USE_RX_FIFOS if (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); return false; } #endif if (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); return false; } LOG_CAN_INFO("Interrupts ready for controller %d, channel %d", controllerId, channelNo); return true; } bool printFIFOStatus(uint32_t controllerId, bool checkEmpty, bool checkFull, bool checkLost) { if (!checkEmpty && !checkFull && !checkLost) { return true; } 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) { return false; } else if (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) { return false; } else if (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) { return false; } else if (status) { LOG_CAN_INFO("RX FIFO #%d controller %d lost messages", fifo, controllerId); } } } return true; } bool receiveMessages(uint32_t controllerId, CanMessageHandler receivedMessageHandler) { // No RX interrupts when using message boxes #ifdef CANBUS_USE_RX_FIFOS if (!newMessages) { // No interrups == no messages, move along. return true; } 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 #endif if (EE_RSCFD_ReceiveMessage(controllerId, &status, &receivedMessage) != EE_RSCFD_OK) { LOG_CAN_ERROR("Fatal error while receiving messages for controller %d", controllerId); return false; } if (status == EE_RSCFD_FAULT_NONE) { receivedMessageHandler(receivedMessage); } else if (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 error return status == EE_RSCFD_FAULT_NODATA; } bool sendMessage(unsigned int controllerId, unsigned int 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); return false; } if (sendStatus != EE_RSCFD_FAULT_NONE) { LOG_CAN_ERROR("Sending message for controller %d, channel %d failed with status: %d", controllerId, channelNo, (int) sendStatus); return false; } return true; } 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