blob: c548efe029ddd352a83a096984715e9f526d4ca9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 - 2018 Johannes Messmer (admin@jomess.com), fortiss GmbH
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Johannes Messmer - initial API and implementation and/or initial documentation
* Jose Cabral - Cleaning of namespaces
*******************************************************************************/
#include "spi.h"
#include <sstream>
#include <string>
unsigned long const EmbrickSPIHandler::scmDefaultSpiSpeed = 300000;
unsigned long const EmbrickSPIHandler::scmMaxSpiSpeed = 700000;
char const EmbrickSPIHandler::mSpiMode = SPI_CPHA;
char const EmbrickSPIHandler::mSpiBitOrder = 0; // MSB first
const char * const EmbrickSPIHandler::scmFailedToInitHandler = "Failed to init spidev handler. Check if spi is enabled.";
const char * const EmbrickSPIHandler::scmFailedToConfigMode = "Failed to config spi write mode.";
const char * const EmbrickSPIHandler::scmFailedToConfigBitOrder = "Failed to config spi bit order.";
const char * const EmbrickSPIHandler::scmFailedToConfigSpeed = "Failed to config spi speed.";
const char * const EmbrickSPIHandler::scmFailedToTestBus = "Failed to send test byte to spi.";
const char * const EmbrickSPIHandler::scmFailedToTransferBuffer = "Failed to transfer buffer via spi.";
EmbrickSPIHandler::EmbrickSPIHandler(unsigned int paInterface) :
mError(0) {
// Convert int to string
std::ostringstream interfaceStream;
interfaceStream << paInterface;
std::string interfaceStr = interfaceStream.str();
std::string spidev = "/dev/spidev" + interfaceStr + ".0";
init(spidev.c_str());
}
EmbrickSPIHandler::~EmbrickSPIHandler() {
deInit();
}
void EmbrickSPIHandler::init(const char* paSpidev) {
// Init spidev
DEVLOG_DEBUG("emBrick[SPIHandler]: Open spidev '%s'\n", paSpidev);
mFd = open(paSpidev, O_RDWR);
if(mFd < 0) {
return fail(scmFailedToInitHandler);
}
// Set mode to SPI_CPOL and SPI_CPHA
if(!config(SPI_IOC_WR_MODE, SPI_IOC_RD_MODE, mSpiMode)) {
return fail(scmFailedToConfigMode);
}
// Set MSB (Most Significant Bit First)
if(!config(SPI_IOC_WR_LSB_FIRST, SPI_IOC_RD_LSB_FIRST, mSpiBitOrder)) {
return fail(scmFailedToConfigBitOrder);
}
// Set speed
if(!config(SPI_IOC_WR_MAX_SPEED_HZ, SPI_IOC_RD_MAX_SPEED_HZ, scmMaxSpiSpeed)) {
return fail(scmFailedToConfigSpeed);
}
mSpiSpeed = scmDefaultSpiSpeed;
// Test
unsigned char testByte[1] = { 0 };
if(!transfer(testByte, testByte, 1)) {
return fail(scmFailedToTestBus);
}
DEVLOG_INFO("emBrick[SPIHandler]: Ready.\n");
}
void EmbrickSPIHandler::deInit() {
// Close handler if open
if(mFd >= 0) {
close(mFd);
}
}
template<typename T> bool EmbrickSPIHandler::config(unsigned int paConfig, unsigned int paConfigVerify, T paValue) {
int status;
// Set config via ioctl
status = ioctl(mFd, paConfig, &paValue);
if(status < 0) {
return false;
}
// Verify config
T valueCheck;
status = ioctl(mFd, paConfigVerify, &valueCheck);
if(status < 0) {
return false;
}
return valueCheck == paValue;
}
void EmbrickSPIHandler::fail(const char* paReason) {
mError = paReason;
DEVLOG_ERROR("emBrick[SPIHandler]: %s\n", mError);
}
bool EmbrickSPIHandler::transfer(unsigned char* paSendBuffer, unsigned char* paReceiveBuffer, int paLength) {
struct spi_ioc_transfer msg{};
msg.tx_buf = (unsigned long) paSendBuffer;
msg.rx_buf = (unsigned long) paReceiveBuffer;
msg.len = paLength;
msg.delay_usecs = 0;
msg.speed_hz = mSpiSpeed;
msg.bits_per_word = 8;
msg.cs_change = 0;
msg.pad = 0;
// Send data to spi bus
int status = ioctl(mFd, SPI_IOC_MESSAGE(1), &msg);
if(status < 0) {
fail(scmFailedToTransferBuffer);
return false;
}
return true;
}
void EmbrickSPIHandler::setSpeed(const unsigned long paSpeed) {
mSpiSpeed = paSpeed;
}