Program Listing for File spi.cpp

Return to documentation for file (src/spi.cpp)

#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>

extern "C" {
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#ifdef __linux__
#include <linux/spi/spidev.h>
#include <linux/types.h>
#endif
}

#include "spi_bus/spi.hh"

using iplo::SPI;

void SPI::open() {
    if ((_fd = ::open(_fileName, O_RDWR | O_NONBLOCK)) < 0) {
        std::perror("Error opening SPI bus");
        std::exit(-1);
    }
}

void SPI::close() const {
    if (::close(_fd) < 0) {
        std::perror("Error closing SPI bus");
        std::exit(-1);
    }
}

SPI::SPI(const char* fileName) : _fileName(fileName) {
    open();
}

SPI::SPI(const char* fileName, const SpiConfig& config) : _fileName(fileName) {
    open();
    setConfig(config);
}

std::int32_t SPI::read(std::uint8_t* rxBuffer, std::uint8_t rxBufferLength) {
#ifdef __linux__  // Mockup code for development on different platforms.
    struct spi_ioc_transfer spiMessage[1];

    std::memset(spiMessage, 0, sizeof(spiMessage));
    spiMessage[0].rx_buf = (unsigned long) rxBuffer;
    spiMessage[0].len = rxBufferLength;
    spiMessage[0].delay_usecs = _spiConfig.delayUs;

    return ::ioctl(_fd, SPI_IOC_MESSAGE(1), spiMessage);
#else
    return rxBufferLength;
#endif
}

std::int32_t SPI::write(std::uint8_t* txBuffer, std::uint8_t txBufferLength) {
#ifdef __linux__  // Mockup code for development on different platforms.
    struct spi_ioc_transfer spiMessage[1];

    std::memset(spiMessage, 0, sizeof(spiMessage));
    spiMessage[0].tx_buf = (unsigned long) txBuffer;
    spiMessage[0].len = txBufferLength;
    spiMessage[0].delay_usecs = _spiConfig.delayUs;

    return ::ioctl(_fd, SPI_IOC_MESSAGE(1), spiMessage);
#else
    return txBufferLength;
#endif
}

std::int32_t SPI::xfer(std::uint8_t* txBuffer, std::uint8_t txBufferLength, std::uint8_t* rxBuffer,
                       std::uint8_t rxBufferLength) {
#ifdef __linux__  // Mockup code for development on different platforms.
    struct spi_ioc_transfer spiMessage[1];

    std::memset(spiMessage, 0, sizeof(spiMessage));
    spiMessage[0].rx_buf = (unsigned long) rxBuffer;
    spiMessage[0].tx_buf = (unsigned long) txBuffer;
    spiMessage[0].len = txBufferLength;
    spiMessage[0].delay_usecs = _spiConfig.delayUs;

    return ::ioctl(_fd, SPI_IOC_MESSAGE(1), spiMessage);
#else
    return rxBufferLength;
#endif
}

bool SPI::setSpeed(std::uint32_t speedHz) {
#ifdef __linux__  // Mockup code for development on different platforms.
    if (::ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speedHz) < 0) {
        return false;
    }

    if (::ioctl(_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speedHz) < 0) {
        return false;
    }

    _spiConfig.speedHz = speedHz;  // Only assign new value if properly set.
    return true;
#else
    return bool(speedHz);
#endif
}

bool SPI::setMode(std::uint8_t mode) {
#ifdef __linux__  // Mockup code for development on different platforms.
    if (::ioctl(_fd, SPI_IOC_WR_MODE, &mode) < 0) {
        return false;
    }
    if (::ioctl(_fd, SPI_IOC_RD_MODE, &mode) < 0) {
        return false;
    }

    _spiConfig.mode = mode;  // Only assign new value if properly set.
    return true;
#else
    return bool(mode);
#endif
}

bool SPI::setBitsPerWord(std::uint8_t bits) {
#ifdef __linux__  // Mockup code for development on different platforms.
    if (::ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) {
        return false;
    }
    if (::ioctl(_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
        return false;
    }

    _spiConfig.bitsPerWord = bits;  // Only assign new value if properly set.
    return true;
#else
    return bool(bits);
#endif
}

bool SPI::setConfig(const SpiConfig& spiConfig) {
    if (!setMode(spiConfig.mode)) {
        std::perror("Error setting mode on SPI bus");
        return false;
    }

    if (!setSpeed(spiConfig.speedHz)) {
        std::perror("Error setting speedHz for SPI bus");
        return false;
    }

    if (!setBitsPerWord(spiConfig.bitsPerWord)) {
        std::perror("Error setting bits per word value");
        return false;
    }

    return true;
}

SPI::~SPI() {
    close();
}