| /******************************************************************************* | |
| * 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; | |
| } | |