hyperion.ng/libsrc/leddevice/dev_spi/ProviderSpi.cpp
LordGrey ed5455458b
Disentangle LedDevice/LinearColorSmoothing, Bug Fixes & Test support (#654)
* Handle Exceptions in main & Pythoninit

* Have SSDPDiscover generic again

* Have SSDPDiscover generic again

* Change Info- to Debug logs as technical service messages

* Nanoleaf - When switched on, ensure UDP mode

* Include SQL Database in Cross-Compile instructions

* Fix Clazy (QT code checker) and clang Warnings

* Stop LedDevice:write for disabled device

* Nanoleaf: Fix uint printfs

* NanoLeaf: Fix indents to tabs

* NanoLeaf - Add debug verbosity switches

* Device switchability support, FileDevice with timestamp support

* Nanoleaf Light Panels now support External Control V2

* Enhance LedDeviceFile by Timestamp + fix readyness

* Stop color stream, if LedDevice disabled

* Nanoleaf - remove switchability

* Fix MultiColorAdjustment, if led-range is greater lednum

* Fix logging

* LedFileDevice/LedDevice - add testing support

* New "Led Test" effect

* LedDeviceFile - Add chrono include + Allow Led rewrites for testing

* Stabilize Effects for LedDevices where latchtime = 0

* Update LedDeviceFile, allow latchtime = 0

* Distangle LinearColorSmoothing and LEDDevice, Fix Effect configuration updates

* Updates LedDeviceFile - Initialize via Open

* Updates LedDeviceNanoleaf - Initialize via Open, Remove throwing exceptions

* Updates ProviderUDP - Remove throwing exceptions

* Framebuffer - Use precise timer

* TestSpi - Align to LedDevice updates

* Pretty Print CrossCompileHowTo as markdown-file

* Ensure that output is only written when LedDevice is ready

* Align APA102 Device to new device staging

* Logger - Remove clang warnings on extra semicolon

* Devices SPI - Align to Device stages and methods

* Fix cppcheck and clang findings

* Add Code-Template for new Devices

* Align devices to stages and methods, clean-up some code

* Allow to reopen LedDevice without restart

* Revert change "Remove Connect (PriorityMuxer::visiblePriorityChanged -> Hyperion::update) due to double writes"

* Remove visiblePriorityChanged from LedDevice to decouple LedDevice from hyperion logic

* Expose LedDevice getLedCount and align signedness
2020-02-10 15:21:58 +01:00

147 lines
3.0 KiB
C++

// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cerrno>
// Linux includes
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
// Local Hyperion includes
#include "ProviderSpi.h"
#include <utils/Logger.h>
ProviderSpi::ProviderSpi()
: LedDevice()
, _deviceName("/dev/spidev0.0")
, _baudRate_Hz(1000000)
, _fid(-1)
, _spiMode(SPI_MODE_0)
, _spiDataInvert(false)
{
memset(&_spi, 0, sizeof(_spi));
_latchTime_ms = 1;
}
ProviderSpi::~ProviderSpi()
{
}
bool ProviderSpi::init(const QJsonObject &deviceConfig)
{
bool isInitOK = LedDevice::init(deviceConfig);
_deviceName = deviceConfig["output"].toString(_deviceName);
_baudRate_Hz = deviceConfig["rate"].toInt(_baudRate_Hz);
_spiMode = deviceConfig["spimode"].toInt(_spiMode);
_spiDataInvert = deviceConfig["invert"].toBool(_spiDataInvert);
return isInitOK;
}
int ProviderSpi::open()
{
int retval = -1;
QString errortext;
_deviceReady = false;
if ( init(_devConfig) )
{
Debug(_log, "_baudRate_Hz %d, _latchTime_ns %d", _baudRate_Hz, _latchTime_ms);
Debug(_log, "_spiDataInvert %d, _spiMode %d", _spiDataInvert, _spiMode);
const int bitsPerWord = 8;
_fid = ::open(QSTRING_CSTR(_deviceName), O_RDWR);
if (_fid < 0)
{
errortext = QString ("Failed to open device (%1). Error message: %2").arg(_deviceName, strerror(errno));
retval = -1;
}
else
{
if (ioctl(_fid, SPI_IOC_WR_MODE, &_spiMode) == -1 || ioctl(_fid, SPI_IOC_RD_MODE, &_spiMode) == -1)
{
retval = -2;
}
else
{
if (ioctl(_fid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(_fid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
{
retval = -4;
}
else
{
if (ioctl(_fid, SPI_IOC_WR_MAX_SPEED_HZ, &_baudRate_Hz) == -1 || ioctl(_fid, SPI_IOC_RD_MAX_SPEED_HZ, &_baudRate_Hz) == -1)
{
retval = -6;
}
else
{
// Everything OK -> enable device
_deviceReady = true;
setEnable(true);
retval = 0;
}
}
}
if ( retval < 0 )
{
errortext = QString ("Failed to open device (%1). Error Code: %2").arg(_deviceName, retval);
}
}
if ( retval < 0 )
{
this->setInError( errortext );
}
}
return retval;
}
void ProviderSpi::close()
{
LedDevice::close();
// Device specific closing activites
if ( _fid > -1 )
{
if ( ::close(_fid) != 0 )
{
Error( _log, "Failed to close device (%s). Error message: %s", QSTRING_CSTR(_deviceName), strerror(errno) );
}
}
}
int ProviderSpi::writeBytes(const unsigned size, const uint8_t * data)
{
if (_fid < 0)
{
return -1;
}
_spi.tx_buf = __u64(data);
_spi.len = __u32(size);
if (_spiDataInvert)
{
uint8_t * newdata = (uint8_t *)malloc(size);
for (unsigned i = 0; i<size; i++) {
newdata[i] = data[i] ^ 0xff;
}
_spi.tx_buf = __u64(newdata);
}
int retVal = ioctl(_fid, SPI_IOC_MESSAGE(1), &_spi);
ErrorIf((retVal < 0), _log, "SPI failed to write. errno: %d, %s", errno, strerror(errno) );
return retVal;
}