LCOV - code coverage report
Current view: top level - canbus - SPIController.cpp (source / functions) Hit Total Coverage
Test: filtered.info Lines: 42 48 87.5 %
Date: 2025-07-25 11:48:17 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*!
       2             :  * @file SPIController.cpp
       3             :  * @brief Implementation of the SPIController 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 SPIController class,
      12             :  * which controls the SPI communication.
      13             :  *
      14             :  * @note This class is used to control the SPI communication for the MCP2515 CAN
      15             :  * controller.
      16             :  *
      17             :  * @warning Ensure that the SPI device is properly connected and configured on
      18             :  * your system.
      19             :  *
      20             :  * @see SPIController.hpp for the class definition.
      21             :  *
      22             :  * @copyright Copyright (c) 2025
      23             :  *
      24             :  */
      25             : 
      26             : #include "SPIController.hpp"
      27             : #include <cstring>
      28             : #include <fcntl.h>
      29             : #include <linux/spi/spidev.h>
      30             : #include <stdexcept>
      31             : #include <sys/ioctl.h>
      32             : #include <unistd.h>
      33             : 
      34             : /*!
      35             :  * @brief Construct a new SPIController::SPIController object
      36             :  *
      37             :  * @param ioctlFunc
      38             :  * @param openFunc
      39             :  * @param closeFunc
      40             :  * @details This constructor initializes the SPIController object with the
      41             :  * specified functions.
      42             :  */
      43           7 : SPIController::SPIController(IoctlFunc ioctlFunc, OpenFunc openFunc,
      44           7 :                                                                                                                  CloseFunc closeFunc)
      45             :                 : spi_fd(-1), mode(DefaultMode), bits(DefaultBitsPerWord),
      46             :                         speed(DefaultSpeedHz), m_ioctlFunc(ioctlFunc), m_openFunc(openFunc),
      47           7 :                         m_closeFunc(closeFunc) {}
      48             : 
      49             : /*!
      50             :  * @brief Destroy the SPIController::SPIController object
      51             :  *
      52             :  * @details This destructor closes the SPI device.
      53             :  */
      54          14 : SPIController::~SPIController() { closeDevice(); }
      55             : 
      56             : /*!
      57             :  * @brief Open the SPI device.
      58             :  *
      59             :  * @param device The device to open.
      60             :  * @returns True if the device was opened successfully.
      61             :  * @throws std::runtime_error if the device cannot be opened.
      62             :  * @details This function opens the SPI device with the specified device name.
      63             :  */
      64           7 : bool SPIController::openDevice(const std::string &device) {
      65           7 :         spi_fd = m_openFunc(device.c_str(), O_RDWR);
      66           7 :         if (spi_fd < 0) {
      67           1 :                 throw std::runtime_error("Failed to open SPI device");
      68             :         }
      69           6 :         return true;
      70             : }
      71             : 
      72             : /*!
      73             :  * @brief Configure the SPI device.
      74             :  *
      75             :  * @param mode The SPI mode.
      76             :  * @param bits The number of bits per word.
      77             :  * @param speed The speed in Hz.
      78             :  * @throws std::runtime_error if the device is not open.
      79             :  * @throws std::runtime_error if the SPI mode cannot be set.
      80             :  * @throws std::runtime_error if the bits per word cannot be set.
      81             :  * @throws std::runtime_error if the speed cannot be set.
      82             :  * @details This function configures the SPI device with the specified mode,
      83             :  * bits per word, and speed.
      84             :  */
      85           1 : void SPIController::configure(uint8_t mode, uint8_t bits, uint32_t speed) {
      86           1 :         if (spi_fd < 0) {
      87           0 :                 throw std::runtime_error("SPI device not open");
      88             :         }
      89             : 
      90           1 :         this->mode = mode;
      91           1 :         this->bits = bits;
      92           1 :         this->speed = speed;
      93             : 
      94           1 :         if (m_ioctlFunc(spi_fd, SPI_IOC_WR_MODE, &mode) < 0) {
      95           0 :                 throw std::runtime_error("Failed to set SPI mode");
      96             :         }
      97             : 
      98           1 :         if (m_ioctlFunc(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
      99           0 :                 throw std::runtime_error("Failed to set SPI bits per word");
     100             :         }
     101             : 
     102           1 :         if (m_ioctlFunc(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) {
     103           0 :                 throw std::runtime_error("Failed to set SPI speed");
     104             :         }
     105           1 : }
     106             : 
     107             : /*!
     108             :  * @brief Write a byte to the SPI device.
     109             :  *
     110             :  * @param address The address to write to.
     111             :  * @param data The data to write.
     112             :  * @details This function writes a byte to the SPI device at the specified
     113             :  * address.
     114             :  */
     115           1 : void SPIController::writeByte(uint8_t address, uint8_t data) {
     116           1 :         uint8_t tx[] = {static_cast<uint8_t>(Opcode::Write), address, data};
     117           1 :         spiTransfer(tx, nullptr, sizeof(tx));
     118           1 : }
     119             : 
     120             : /*!
     121             :  * @brief Read a byte from the SPI device.
     122             :  *
     123             :  * @param address The address to read from.
     124             :  * @returns The byte read from the SPI device.
     125             :  * @details This function reads a byte from the SPI device at the specified
     126             :  * address.
     127             :  */
     128           1 : uint8_t SPIController::readByte(uint8_t address) {
     129           1 :         uint8_t tx[] = {static_cast<uint8_t>(Opcode::Read), address, 0x00};
     130           1 :         uint8_t rx[sizeof(tx)] = {0};
     131           1 :         spiTransfer(tx, rx, sizeof(tx));
     132           1 :         return rx[2];
     133             : }
     134             : 
     135             : /*!
     136             :  * @brief Transfer data over SPI.
     137             :  *
     138             :  * @param tx The data to transmit.
     139             :  * @param rx The data to receive.
     140             :  * @param length The length of the data.
     141             :  * @throws std::runtime_error if the SPI device is not open.
     142             :  * @throws std::runtime_error if the SPI transfer fails.
     143             :  * @details This function transfers data over SPI.
     144             :  */
     145           3 : void SPIController::spiTransfer(const uint8_t *tx, uint8_t *rx, size_t length) {
     146           3 :         if (spi_fd < 0) {
     147           0 :                 throw std::runtime_error("SPI device not open");
     148             :         }
     149             : 
     150           3 :         struct spi_ioc_transfer transfer = {};
     151           3 :         transfer.tx_buf = reinterpret_cast<unsigned long>(tx);
     152           3 :         transfer.rx_buf = reinterpret_cast<unsigned long>(rx);
     153           3 :         transfer.len = length;
     154           3 :         transfer.speed_hz = speed;
     155           3 :         transfer.bits_per_word = bits;
     156             : 
     157           3 :         if (m_ioctlFunc(spi_fd, SPI_IOC_MESSAGE(1), &transfer) < 0) {
     158           0 :                 throw std::runtime_error("SPI transfer error");
     159             :         }
     160           3 : }
     161             : 
     162             : /*!
     163             :  * @brief Close the SPI device.
     164             :  * @details This function closes the SPI device.
     165             :  */
     166           8 : void SPIController::closeDevice() {
     167           8 :         if (spi_fd >= 0) {
     168           6 :                 m_closeFunc(spi_fd);
     169           6 :                 spi_fd = -1;
     170             :         }
     171           8 : }

Generated by: LCOV version 1.14