Line data Source code
1 : /*! 2 : * @file MCP2515Controller.cpp 3 : * @brief Implementation of the MCP2515Controller class. 4 : * @version 0.1 5 : * @date 2025-01-31 6 : * @author Félix LE BIHAN (@Fle-bihh) 7 : * @author Tiago Pereira (@t-pereira06) 8 : * @author Ricardo Melo (@reomelo) 9 : * @author Michel Batista (@MicchelFAB) 10 : * 11 : * @details This file contains the implementation of the MCP2515Controller 12 : * class, which controls the MCP2515 CAN controller. 13 : * 14 : * @note This class is used to control the MCP2515 CAN controller for 15 : * communication. 16 : * 17 : * @warning Ensure that the SPI controller is properly implemented. 18 : * 19 : * @see MCP2515Controller.hpp for the class definition. 20 : * 21 : * @copyright Copyright (c) 2025 22 : * 23 : */ 24 : 25 : #include "MCP2515Controller.hpp" 26 : #include "SPIController.hpp" 27 : #include "NotificationManager.hpp" 28 : #include <QDebug> 29 : #include <QThread> 30 : #include <cstring> 31 : #include <stdexcept> 32 : 33 : /*! 34 : * @brief Construct a new MCP2515Controller::MCP2515Controller object 35 : * @param spiDevice The SPI device to use for communication. 36 : * @throw std::runtime_error if the SPI device cannot be opened. 37 : * @details This constructor initializes the MCP2515Controller object with the 38 : * specified SPI device. 39 : */ 40 0 : MCP2515Controller::MCP2515Controller(const std::string &spiDevice) 41 0 : : spiController(new SPIController()), configurator(*spiController), 42 0 : messageProcessor(), ownsSPIController(true) { 43 0 : if (!spiController->openDevice(spiDevice)) { 44 0 : throw std::runtime_error("Failed to open SPI device : " + spiDevice); 45 : } 46 0 : setupHandlers(); 47 0 : } 48 : 49 : /*! 50 : * @brief Construct a new MCP2515Controller::MCP2515Controller object 51 : * @param spiDevice The SPI device to use for communication. 52 : * @param spiController The SPI controller to use for communication. 53 : * @throw std::runtime_error if the SPI device cannot be opened. 54 : * @details This constructor initializes the MCP2515Controller object with the 55 : * specified SPI device and SPI controller. 56 : */ 57 10 : MCP2515Controller::MCP2515Controller(const std::string &spiDevice, 58 10 : ISPIController &spiController) 59 : : spiController(&spiController), configurator(spiController), 60 12 : messageProcessor(), ownsSPIController(false) { 61 10 : if (!spiController.openDevice(spiDevice)) { 62 1 : throw std::runtime_error("Failed to open SPI device : " + spiDevice); 63 : } 64 9 : setupHandlers(); 65 9 : } 66 : 67 : /*! 68 : * @brief Destroy the MCP2515Controller::MCP2515Controller object 69 : * @details This destructor closes the SPI device and deletes the SPI controller 70 : * if it was created by the MCP2515Controller. 71 : */ 72 9 : MCP2515Controller::~MCP2515Controller() { 73 9 : spiController->closeDevice(); 74 9 : if (this->ownsSPIController) { 75 0 : delete this->spiController; 76 : } 77 9 : } 78 : 79 : /*! 80 : * @brief Initialize the MCP2515 controller. 81 : * @throw std::runtime_error if the MCP2515 cannot be reset. 82 : * @returns True if the MCP2515 is successfully initialized 83 : * @details This function initializes the MCP2515 controller by resetting the 84 : * chip and configuring it. 85 : */ 86 1 : bool MCP2515Controller::init() { 87 1 : if (!configurator.resetChip()) { 88 0 : throw std::runtime_error("Failed to reset MCP2515"); 89 : } 90 : 91 1 : configurator.configureBaudRate(); 92 1 : configurator.configureTXBuffer(); 93 1 : configurator.configureRXBuffer(); 94 1 : configurator.configureFiltersAndMasks(); 95 1 : configurator.configureInterrupts(); 96 1 : configurator.setMode(0x00); 97 : 98 1 : if (!configurator.verifyMode(0x00)) { 99 0 : throw std::runtime_error("Failed to set MCP2515 to normal mode"); 100 : } 101 : 102 1 : return true; 103 : } 104 : 105 : /*! 106 : * @brief Start reading CAN messages. 107 : * @details This function starts reading CAN messages from the MCP2515. 108 : */ 109 12 : void MCP2515Controller::processReading() { 110 12 : while (!stopReadingFlag) { 111 : uint16_t frameID; 112 10 : std::vector<uint8_t> data; 113 : // qDebug() << "In loop" << stopReadingFlag; 114 : try { 115 10 : data = configurator.readCANMessage(frameID); 116 9 : if (!data.empty()) { 117 0 : messageProcessor.processMessage(frameID, data); 118 : } 119 1 : } catch (const std::exception &e) { 120 1 : qDebug() << "Error while processing CAN message:" << e.what(); 121 : } 122 : 123 10 : if (stopReadingFlag) { 124 0 : break; 125 : } 126 : 127 10 : QThread::msleep(10); 128 : } 129 2 : } 130 : 131 : /*! 132 : * @brief Stop reading CAN messages. 133 : * @details This function stops reading CAN messages from the MCP2515. 134 : */ 135 3 : void MCP2515Controller::stopReading() { stopReadingFlag = true; } 136 : 137 : /*! 138 : * @brief Send a CAN message. 139 : * @param frameID The frame ID of the message. 140 : * @param data The data of the message. 141 : * @details This function sends a CAN message with the specified frame ID and 142 : * data. 143 : */ 144 9 : void MCP2515Controller::setupHandlers() { 145 9 : messageProcessor.registerHandler(0x100, [this](const std::vector<uint8_t> &data) { 146 2 : if (data.size() == 1) { 147 1 : float speed = static_cast<float>(data[0]); 148 1 : emit speedUpdated(speed); 149 : } 150 2 : }); 151 : 152 9 : messageProcessor.registerHandler(0x300, [this](const std::vector<uint8_t> &data) { 153 3 : if (data.size() == 2) { 154 3 : uint16_t distance = (data[0] << 8) | data[1]; 155 : //emit distanceUpdated(distance); 156 3 : qDebug() << "Distance from CAN:" << distance; 157 3 : if (distance > 20) { 158 2 : if (!brakeWarningActive) { 159 2 : brakeWarningActive = true; 160 4 : QString message = QString("Brake!"); 161 2 : NotificationManager::instance()->showPersistentNotification(message, NotificationLevel::Warning); 162 : } 163 : } else { 164 1 : if (brakeWarningActive) { 165 1 : brakeWarningActive = false; 166 1 : NotificationManager::instance()->clearNotification(); 167 : } 168 : } 169 : } 170 3 : }); 171 9 : } 172 : 173 : /*! 174 : * @brief Check if the stop reading flag is set. 175 : * @returns True if the stop reading flag is set, false otherwise. 176 : * @details This function checks if the stop reading flag is set. 177 : */ 178 3 : bool MCP2515Controller::isStopReadingFlagSet() const { 179 3 : return this->stopReadingFlag; 180 : }