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();
}