Moved all devices to separate library and added 'Factory' for device creation.

Former-commit-id: 26cab1b85b00406240689ad9c1018f0307028fe4
This commit is contained in:
T. van der Zwan
2013-12-17 18:50:15 +00:00
parent 9bfaffe93b
commit b63753f5dc
37 changed files with 240 additions and 175 deletions

View File

@@ -3,27 +3,17 @@
SET(CURRENT_HEADER_DIR ${CMAKE_SOURCE_DIR}/include/hyperion)
SET(CURRENT_SOURCE_DIR ${CMAKE_SOURCE_DIR}/libsrc/hyperion)
#add libusb and pthreads (required for the Lighpack usb device)
find_package(libusb-1.0 REQUIRED)
find_package(Threads REQUIRED)
include_directories(
../../include/hidapi
${LIBUSB_1_INCLUDE_DIRS}) # for Lightpack device
# Group the headers that go through the MOC compiler
SET(Hyperion_QT_HEADERS
${CURRENT_HEADER_DIR}/Hyperion.h
${CURRENT_SOURCE_DIR}/LinearColorSmoothing.h
${CURRENT_SOURCE_DIR}/device/LedDeviceAdalight.h
)
SET(Hyperion_HEADERS
${CURRENT_HEADER_DIR}/ImageProcessor.h
${CURRENT_HEADER_DIR}/ImageProcessorFactory.h
${CURRENT_HEADER_DIR}/ImageToLedsMap.h
${CURRENT_HEADER_DIR}/LedDevice.h
${CURRENT_HEADER_DIR}/LedString.h
${CURRENT_HEADER_DIR}/PriorityMuxer.h
@@ -31,18 +21,6 @@ SET(Hyperion_HEADERS
${CURRENT_HEADER_DIR}/BlackBorderProcessor.h
${CURRENT_SOURCE_DIR}/MultiColorTransform.h
${CURRENT_SOURCE_DIR}/device/LedSpiDevice.h
${CURRENT_SOURCE_DIR}/device/LedRs232Device.h
${CURRENT_SOURCE_DIR}/device/LedDeviceTest.h
${CURRENT_SOURCE_DIR}/device/LedDeviceSedu.h
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2801.h
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2811.h
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd6803.h
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.h
${CURRENT_SOURCE_DIR}/device/LedDeviceLightpack.h
${CURRENT_SOURCE_DIR}/device/LedDevicePaintpack.h
${CURRENT_SOURCE_DIR}/device/LedDeviceMultiLightpack.h
)
SET(Hyperion_SOURCES
@@ -57,19 +35,6 @@ SET(Hyperion_SOURCES
${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp
${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp
${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp
${CURRENT_SOURCE_DIR}/device/LedSpiDevice.cpp
${CURRENT_SOURCE_DIR}/device/LedRs232Device.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceSedu.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceTest.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2801.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceWs2811.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd6803.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceLpd8806.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceAdalight.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceLightpack.cpp
${CURRENT_SOURCE_DIR}/device/LedDevicePaintpack.cpp
${CURRENT_SOURCE_DIR}/device/LedDeviceMultiLightpack.cpp
)
set(Hyperion_RESOURCES
@@ -78,7 +43,7 @@ set(Hyperion_RESOURCES
QT4_WRAP_CPP(Hyperion_HEADERS_MOC ${Hyperion_QT_HEADERS})
qt4_add_resources(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
QT4_ADD_RESOURCES(Hyperion_RESOURCES_RCC ${Hyperion_RESOURCES} OPTIONS "-no-compress")
add_library(hyperion
${Hyperion_HEADERS}
@@ -90,10 +55,9 @@ add_library(hyperion
target_link_libraries(hyperion
hyperion-utils
leddevice
effectengine
hidapi-libusb
serialport
${LIBUSB_1_LIBRARIES} #apt-get install libusb-1.0-0-dev
${CMAKE_THREAD_LIBS_INIT}
${QT_LIBRARIES}
)

View File

@@ -14,19 +14,11 @@
// hyperion include
#include <hyperion/Hyperion.h>
#include <hyperion/LedDevice.h>
#include <hyperion/ImageProcessorFactory.h>
#include "device/LedDeviceLpd6803.h"
#include "device/LedDeviceLpd8806.h"
#include "device/LedDeviceSedu.h"
#include "device/LedDeviceTest.h"
#include "device/LedDeviceWs2801.h"
#include "device/LedDeviceWs2811.h"
#include "device/LedDeviceAdalight.h"
#include "device/LedDevicePaintpack.h"
#include "device/LedDeviceLightpack.h"
#include "device/LedDeviceMultiLightpack.h"
// Leddevice includes
#include <leddevice/LedDevice.h>
#include <leddevice/LedDeviceFactory.h>
#include "MultiColorTransform.h"
#include "LinearColorSmoothing.h"
@@ -34,116 +26,6 @@
// effect engine includes
#include <effectengine/EffectEngine.h>
LedDevice* Hyperion::createDevice(const Json::Value& deviceConfig)
{
std::cout << "Device configuration: " << deviceConfig << std::endl;
std::string type = deviceConfig.get("type", "UNSPECIFIED").asString();
std::transform(type.begin(), type.end(), type.begin(), ::tolower);
LedDevice* device = nullptr;
if (type == "ws2801" || type == "lightberry")
{
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt();
LedDeviceWs2801* deviceWs2801 = new LedDeviceWs2801(output, rate);
deviceWs2801->open();
device = deviceWs2801;
}
else if (type == "ws2811")
{
const std::string output = deviceConfig["output"].asString();
const std::string outputSpeed = deviceConfig["output"].asString();
const std::string timingOption = deviceConfig["timingOption"].asString();
ws2811::SpeedMode speedMode = (outputSpeed == "high")? ws2811::highspeed : ws2811::lowspeed;
if (outputSpeed != "high" && outputSpeed != "low")
{
std::cerr << "Incorrect speed-mode selected for WS2811: " << outputSpeed << " != {'high', 'low'}" << std::endl;
}
LedDeviceWs2811 * deviceWs2811 = new LedDeviceWs2811(output, ws2811::fromString(timingOption, ws2811::option_2855), speedMode);
deviceWs2811->open();
device = deviceWs2811;
}
else if (type == "lpd6803" || type == "ldp6803")
{
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt();
LedDeviceLpd6803* deviceLdp6803 = new LedDeviceLpd6803(output, rate);
deviceLdp6803->open();
device = deviceLdp6803;
}
else if (type == "lpd8806" || type == "ldp8806")
{
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt();
LedDeviceLpd8806* deviceLpd8806 = new LedDeviceLpd8806(output, rate);
deviceLpd8806->open();
device = deviceLpd8806;
}
else if (type == "sedu")
{
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt();
LedDeviceSedu* deviceSedu = new LedDeviceSedu(output, rate);
deviceSedu->open();
device = deviceSedu;
}
else if (type == "adalight")
{
const std::string output = deviceConfig["output"].asString();
const unsigned rate = deviceConfig["rate"].asInt();
LedDeviceAdalight* deviceAdalight = new LedDeviceAdalight(output, rate);
deviceAdalight->open();
device = deviceAdalight;
}
else if (type == "lightpack")
{
const std::string output = deviceConfig.get("output", "").asString();
LedDeviceLightpack* deviceLightpack = new LedDeviceLightpack();
deviceLightpack->open(output);
device = deviceLightpack;
}
else if (type == "paintpack")
{
LedDevicePaintpack * devicePainLightpack = new LedDevicePaintpack();
devicePainLightpack->open();
device = devicePainLightpack;
}
else if (type == "multi-lightpack")
{
LedDeviceMultiLightpack* deviceLightpack = new LedDeviceMultiLightpack();
deviceLightpack->open();
device = deviceLightpack;
}
else if (type == "test")
{
const std::string output = deviceConfig["output"].asString();
device = new LedDeviceTest(output);
}
else
{
std::cout << "Unable to create device " << type << std::endl;
// Unknown / Unimplemented device
}
return device;
}
Hyperion::ColorOrder Hyperion::createColorOrder(const Json::Value &deviceConfig)
{
@@ -379,7 +261,7 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) :
_muxer(_ledString.leds().size()),
_raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])),
_colorOrder(createColorOrder(jsonConfig["device"])),
_device(createDevice(jsonConfig["device"])),
_device(LedDeviceFactory::construct(jsonConfig["device"])),
_effectEngine(nullptr),
_timer()
{

View File

@@ -11,7 +11,7 @@
#include <linux/spi/spidev.h>
// hyperion incluse
#include <hyperion/LedDevice.h>
#include <leddevice/LedDevice.h>
/// Linear Smooting class
///

View File

@@ -1,62 +0,0 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
// hyperion local includes
#include "LedDeviceAdalight.h"
LedDeviceAdalight::LedDeviceAdalight(const std::string& outputDevice, const unsigned baudrate) :
LedRs232Device(outputDevice, baudrate),
_ledBuffer(0),
_timer()
{
// setup the timer
_timer.setSingleShot(false);
_timer.setInterval(5000);
connect(&_timer, SIGNAL(timeout()), this, SLOT(rewriteLeds()));
// start the timer
_timer.start();
}
int LedDeviceAdalight::write(const std::vector<ColorRgb> & ledValues)
{
if (_ledBuffer.size() == 0)
{
_ledBuffer.resize(6 + 3*ledValues.size());
_ledBuffer[0] = 'A';
_ledBuffer[1] = 'd';
_ledBuffer[2] = 'a';
_ledBuffer[3] = ((ledValues.size() - 1) >> 8) & 0xFF; // LED count high byte
_ledBuffer[4] = (ledValues.size() - 1) & 0xFF; // LED count low byte
_ledBuffer[5] = _ledBuffer[3] ^ _ledBuffer[4] ^ 0x55; // Checksum
}
// restart the timer
_timer.start();
// write data
memcpy(6 + _ledBuffer.data(), ledValues.data(), ledValues.size() * 3);
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}
int LedDeviceAdalight::switchOff()
{
// restart the timer
_timer.start();
// write data
memset(6 + _ledBuffer.data(), 0, _ledBuffer.size()-6);
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}
void LedDeviceAdalight::rewriteLeds()
{
writeBytes(_ledBuffer.size(), _ledBuffer.data());
}

View File

@@ -1,51 +0,0 @@
#pragma once
// STL includes
#include <string>
// Qt includes
#include <QTimer>
// hyperion incluse
#include "LedRs232Device.h"
///
/// Implementation of the LedDevice interface for writing to an Adalight led device.
///
class LedDeviceAdalight : public QObject, public LedRs232Device
{
Q_OBJECT
public:
///
/// Constructs the LedDevice for attached Adalight device
///
/// @param outputDevice The name of the output device (eg '/dev/ttyS0')
/// @param baudrate The used baudrate for writing to the output device
///
LedDeviceAdalight(const std::string& outputDevice, const unsigned baudrate);
///
/// Writes the led color values to the led-device
///
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
/// Switch the leds off
virtual int switchOff();
private slots:
/// Write the last data to the leds again
void rewriteLeds();
private:
/// The buffer containing the packed RGB values
std::vector<uint8_t> _ledBuffer;
/// Timer object which makes sure that led data is written at a minimum rate
/// The Adalight device will switch off when it does not receive data at least
/// every 15 seconds
QTimer _timer;
};

View File

@@ -1,270 +0,0 @@
// stl includes
#include <exception>
#include <cstring>
#include <wchar.h>
// Local Hyperion includes
#include "LedDeviceLightpack-hidapi.h"
// from USB_ID.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/USB_ID.h)
#define USB_OLD_VENDOR_ID 0x03EB
#define USB_OLD_PRODUCT_ID 0x204F
#define USB_VENDOR_ID 0x1D50
#define USB_PRODUCT_ID 0x6022
#define LIGHTPACK_INTERFACE 0
// from commands.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/commands.h)
// Commands to device, sends it in first byte of data[]
enum COMMANDS{
CMD_UPDATE_LEDS = 1,
CMD_OFF_ALL,
CMD_SET_TIMER_OPTIONS,
CMD_SET_PWM_LEVEL_MAX_VALUE, /* deprecated */
CMD_SET_SMOOTH_SLOWDOWN,
CMD_SET_BRIGHTNESS,
CMD_NOP = 0x0F
};
// from commands.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/commands.h)
enum DATA_VERSION_INDEXES{
INDEX_FW_VER_MAJOR = 1,
INDEX_FW_VER_MINOR
};
LedDeviceLightpackHidapi::LedDeviceLightpackHidapi() :
LedDevice(),
_deviceHandle(nullptr),
_serialNumber(""),
_firmwareVersion({-1,-1}),
_ledCount(-1),
_bitsPerChannel(-1),
_ledBuffer()
{
}
LedDeviceLightpackHidapi::~LedDeviceLightpackHidapi()
{
if (_deviceHandle != nullptr)
{
hid_close(_deviceHandle);
_deviceHandle = nullptr;
}
// TODO: Should be called to avoid memory loss, but only at the end of the application
//hid_exit();
}
int LedDeviceLightpackHidapi::open(const std::string & serialNumber)
{
// initialize the usb context
int error = hid_init();
if (error != 0)
{
std::cerr << "Error while initializing the hidapi context" << std::endl;
return -1;
}
std::cout << "Hidapi initialized" << std::endl;
// retrieve the list of usb devices
hid_device_info * deviceList = hid_enumerate(0x0, 0x0);
// iterate the list of devices
for (hid_device_info * deviceInfo = deviceList; deviceInfo != nullptr; deviceInfo = deviceInfo->next)
{
// try to open and initialize the device
error = testAndOpen(deviceInfo, serialNumber);
if (error == 0)
{
// a device was sucessfully opened. break from list
break;
}
}
// free the device list
hid_free_enumeration(deviceList);
if (_deviceHandle == nullptr)
{
if (_serialNumber.empty())
{
std::cerr << "No Lightpack device has been found" << std::endl;
}
else
{
std::cerr << "No Lightpack device has been found with serial " << _serialNumber << std::endl;
}
}
return _deviceHandle == nullptr ? -1 : 0;
}
int LedDeviceLightpackHidapi::testAndOpen(hid_device_info *device, const std::string & requestedSerialNumber)
{
if ((device->vendor_id == USB_VENDOR_ID && device->product_id == USB_PRODUCT_ID) ||
(device->vendor_id == USB_OLD_VENDOR_ID && device->product_id == USB_OLD_PRODUCT_ID))
{
std::cout << "Found a lightpack device. Retrieving more information..." << std::endl;
// get the serial number
std::string serialNumber = "";
if (device->serial_number != nullptr)
{
// the serial number needs to be converted to a char array instead of wchar
size_t size = wcslen(device->serial_number);
serialNumber.resize(size, '.');
for (size_t i = 0; i < size; ++i)
{
int c = wctob(device->serial_number[i]);
if (c != EOF)
{
serialNumber[i] = c;
}
}
}
else
{
std::cerr << "No serial number for Lightpack device" << std::endl;
}
std::cout << "Lightpack device found: path=" << device->path << " serial=" << serialNumber << std::endl;
// check if this is the device we are looking for
if (requestedSerialNumber.empty() || requestedSerialNumber == serialNumber)
{
// This is it!
_deviceHandle = hid_open_path(device->path);
if (_deviceHandle != nullptr)
{
_serialNumber = serialNumber;
std::cout << "Lightpack device successfully opened" << std::endl;
// get the firmware version
uint8_t buffer[256];
buffer[0] = 0; // report id
int error = hid_get_feature_report(_deviceHandle, buffer, sizeof(buffer));
if (error < 4)
{
std::cerr << "Unable to retrieve firmware version number from Lightpack device" << std::endl;
}
else
{
_firmwareVersion.majorVersion = buffer[INDEX_FW_VER_MAJOR+1];
_firmwareVersion.minorVersion = buffer[INDEX_FW_VER_MINOR+1];
}
// FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6
_firmwareVersion.majorVersion = 6;
// disable smoothing of the chosen device
disableSmoothing();
// determine the number of leds
if (_firmwareVersion.majorVersion == 4)
{
_ledCount = 8;
}
else
{
_ledCount = 10;
}
// determine the bits per channel
if (_firmwareVersion.majorVersion == 6)
{
// maybe also or version 7? The firmware suggest this is only for 6... (2013-11-13)
_bitsPerChannel = 12;
}
else
{
_bitsPerChannel = 8;
}
// set the led buffer size (repport id + command + 6 bytes per led)
_ledBuffer = std::vector<uint8_t>(2 + _ledCount * 6, 0);
_ledBuffer[0] = 0x0; // report id
_ledBuffer[1] = CMD_UPDATE_LEDS;
// return success
std::cout << "Lightpack device opened: path=" << device->path << " serial=" << _serialNumber << " version=" << _firmwareVersion.majorVersion << "." << _firmwareVersion.minorVersion << std::endl;
return 0;
}
else
{
std::cerr << "Unable to open Lightpack device. Searching for other device" << std::endl;
}
}
}
return -1;
}
int LedDeviceLightpackHidapi::write(const std::vector<ColorRgb> &ledValues)
{
return write(ledValues.data(), ledValues.size());
}
int LedDeviceLightpackHidapi::write(const ColorRgb * ledValues, int size)
{
int count = std::min(_ledCount, size);
for (int i = 0; i < count ; ++i)
{
const ColorRgb & color = ledValues[i];
// copy the most significant bits of the rgb values to the first three bytes
// offset 1 to accomodate for the report id and command byte
_ledBuffer[6*i+2] = color.red;
_ledBuffer[6*i+3] = color.green;
_ledBuffer[6*i+4] = color.blue;
// leave the next three bytes on zero...
// 12-bit values having zeros in the lowest 4 bits which is almost correct, but it saves extra
// switches to determine what to do and some bit shuffling
}
int error = writeBytes(_ledBuffer.data(), _ledBuffer.size());
return error >= 0 ? 0 : error;
}
int LedDeviceLightpackHidapi::switchOff()
{
unsigned char buf[2] = {0x0, CMD_OFF_ALL};
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
}
const std::string &LedDeviceLightpackHidapi::getSerialNumber() const
{
return _serialNumber;
}
int LedDeviceLightpackHidapi::getLedCount() const
{
return _ledCount;
}
int LedDeviceLightpackHidapi::writeBytes(uint8_t *data, int size)
{
// std::cout << "Writing " << size << " bytes: ";
// for (int i = 0; i < size ; ++i) printf("%02x ", data[i]);
// std::cout << std::endl;
int error = hid_send_feature_report(_deviceHandle, data, size);
if (error == size)
{
return 0;
}
std::cerr << "Unable to write " << size << " bytes to Lightpack device(" << error << ")" << std::endl;
return error;
}
int LedDeviceLightpackHidapi::disableSmoothing()
{
unsigned char buf[2] = {CMD_SET_SMOOTH_SLOWDOWN, 0};
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
}

View File

@@ -1,107 +0,0 @@
#pragma once
// stl includes
#include <vector>
#include <cstdint>
#include <string>
// libusb include
#include <hidapi/hidapi.h>
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// LedDevice implementation for a lightpack device (http://code.google.com/p/light-pack/)
///
class LedDeviceLightpackHidapi : public LedDevice
{
public:
///
/// Constructs the LedDeviceLightpack
///
LedDeviceLightpackHidapi();
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedDeviceLightpackHidapi();
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open(const std::string & serialNumber = "");
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues The RGB-color per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues Array of RGB values
/// @param[in] size The number of RGB values
///
/// @return Zero on success else negative
///
int write(const ColorRgb * ledValues, int size);
///
/// Switch the leds off
///
/// @return Zero on success else negative
///
virtual int switchOff();
/// Get the serial of the Lightpack
const std::string & getSerialNumber() const;
/// Get the number of leds
int getLedCount() const;
private:
///
/// Test if the device is a (or the) lightpack we are looking for
///
/// @return Zero on succes else negative
///
int testAndOpen(hid_device_info * device, const std::string & requestedSerialNumber);
/// write bytes to the device
int writeBytes(uint8_t *data, int size);
/// Disable the internal smoothing on the Lightpack device
int disableSmoothing();
struct Version
{
int majorVersion;
int minorVersion;
};
private:
/// libusb device handle
hid_device * _deviceHandle;
/// device serial number
std::string _serialNumber;
/// firmware version of the device
Version _firmwareVersion;
/// the number of leds of the device
int _ledCount;
/// the number of bits per channel
int _bitsPerChannel;
/// buffer for led data
std::vector<uint8_t> _ledBuffer;
};

View File

@@ -1,357 +0,0 @@
// stl includes
#include <exception>
#include <cstring>
// Local Hyperion includes
#include "LedDeviceLightpack.h"
// from USB_ID.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/USB_ID.h)
#define USB_OLD_VENDOR_ID 0x03EB
#define USB_OLD_PRODUCT_ID 0x204F
#define USB_VENDOR_ID 0x1D50
#define USB_PRODUCT_ID 0x6022
#define LIGHTPACK_INTERFACE 0
// from commands.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/commands.h)
// Commands to device, sends it in first byte of data[]
enum COMMANDS{
CMD_UPDATE_LEDS = 1,
CMD_OFF_ALL,
CMD_SET_TIMER_OPTIONS,
CMD_SET_PWM_LEVEL_MAX_VALUE, /* deprecated */
CMD_SET_SMOOTH_SLOWDOWN,
CMD_SET_BRIGHTNESS,
CMD_NOP = 0x0F
};
// from commands.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/commands.h)
enum DATA_VERSION_INDEXES{
INDEX_FW_VER_MAJOR = 1,
INDEX_FW_VER_MINOR
};
LedDeviceLightpack::LedDeviceLightpack() :
LedDevice(),
_libusbContext(nullptr),
_deviceHandle(nullptr),
_busNumber(-1),
_addressNumber(-1),
_serialNumber(""),
_firmwareVersion({-1,-1}),
_ledCount(-1),
_bitsPerChannel(-1),
_ledBuffer()
{
}
LedDeviceLightpack::~LedDeviceLightpack()
{
if (_deviceHandle != nullptr)
{
libusb_release_interface(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_attach_kernel_driver(_deviceHandle, LIGHTPACK_INTERFACE);
libusb_close(_deviceHandle);
_deviceHandle = nullptr;
}
if (_libusbContext != nullptr)
{
libusb_exit(_libusbContext);
_libusbContext = nullptr;
}
}
int LedDeviceLightpack::open(const std::string & serialNumber)
{
int error;
// initialize the usb context
if ((error = libusb_init(&_libusbContext)) != LIBUSB_SUCCESS)
{
std::cerr << "Error while initializing USB context(" << error << "): " << libusb_error_name(error) << std::endl;
_libusbContext = nullptr;
return -1;
}
//libusb_set_debug(_libusbContext, 3);
std::cout << "USB context initialized" << std::endl;
// retrieve the list of usb devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(_libusbContext, &deviceList);
// iterate the list of devices
for (ssize_t i = 0 ; i < deviceCount; ++i)
{
// try to open and initialize the device
error = testAndOpen(deviceList[i], serialNumber);
if (error == 0)
{
// a device was sucessfully opened. break from list
break;
}
}
// free the device list
libusb_free_device_list(deviceList, 1);
if (_deviceHandle == nullptr)
{
if (_serialNumber.empty())
{
std::cerr << "No Lightpack device has been found" << std::endl;
}
else
{
std::cerr << "No Lightpack device has been found with serial " << _serialNumber << std::endl;
}
}
return _deviceHandle == nullptr ? -1 : 0;
}
int LedDeviceLightpack::testAndOpen(libusb_device * device, const std::string & requestedSerialNumber)
{
libusb_device_descriptor deviceDescriptor;
int error = libusb_get_device_descriptor(device, &deviceDescriptor);
if (error != LIBUSB_SUCCESS)
{
std::cerr << "Error while retrieving device descriptor(" << error << "): " << libusb_error_name(error) << std::endl;
return -1;
}
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
std::cout << "Found a lightpack device. Retrieving more information..." << std::endl;
// get the hardware address
int busNumber = libusb_get_bus_number(device);
int addressNumber = libusb_get_device_address(device);
// get the serial number
std::string serialNumber;
if (deviceDescriptor.iSerialNumber != 0)
{
try
{
serialNumber = LedDeviceLightpack::getString(device, deviceDescriptor.iSerialNumber);
}
catch (int e)
{
std::cerr << "unable to retrieve serial number from Lightpack device(" << e << "): " << libusb_error_name(e) << std::endl;
serialNumber = "";
}
}
std::cout << "Lightpack device found: bus=" << busNumber << " address=" << addressNumber << " serial=" << serialNumber << std::endl;
// check if this is the device we are looking for
if (requestedSerialNumber.empty() || requestedSerialNumber == serialNumber)
{
// This is it!
try
{
_deviceHandle = openDevice(device);
_serialNumber = serialNumber;
_busNumber = busNumber;
_addressNumber = addressNumber;
std::cout << "Lightpack device successfully opened" << std::endl;
// get the firmware version
uint8_t buffer[256];
error = libusb_control_transfer(
_deviceHandle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
0x01,
0x0100,
0,
buffer, sizeof(buffer), 1000);
if (error < 3)
{
std::cerr << "Unable to retrieve firmware version number from Lightpack device(" << error << "): " << libusb_error_name(error) << std::endl;
}
else
{
_firmwareVersion.majorVersion = buffer[INDEX_FW_VER_MAJOR];
_firmwareVersion.minorVersion = buffer[INDEX_FW_VER_MINOR];
}
// FOR TESTING PURPOSE: FORCE MAJOR VERSION TO 6
_firmwareVersion.majorVersion = 6;
// disable smoothing of the chosen device
disableSmoothing();
// determine the number of leds
if (_firmwareVersion.majorVersion == 4)
{
_ledCount = 8;
}
else
{
_ledCount = 10;
}
// determine the bits per channel
if (_firmwareVersion.majorVersion == 6)
{
// maybe also or version 7? The firmware suggest this is only for 6... (2013-11-13)
_bitsPerChannel = 12;
}
else
{
_bitsPerChannel = 8;
}
// set the led buffer size (command + 6 bytes per led)
_ledBuffer = std::vector<uint8_t>(1 + _ledCount * 6, 0);
_ledBuffer[0] = CMD_UPDATE_LEDS;
// return success
std::cout << "Lightpack device opened: bus=" << _busNumber << " address=" << _addressNumber << " serial=" << _serialNumber << " version=" << _firmwareVersion.majorVersion << "." << _firmwareVersion.minorVersion << std::endl;
return 0;
}
catch(int e)
{
_deviceHandle = nullptr;
std::cerr << "Unable to open Lightpack device. Searching for other device(" << e << "): " << libusb_error_name(e) << std::endl;
}
}
}
return -1;
}
int LedDeviceLightpack::write(const std::vector<ColorRgb> &ledValues)
{
return write(ledValues.data(), ledValues.size());
}
int LedDeviceLightpack::write(const ColorRgb * ledValues, int size)
{
int count = std::min(_ledCount, size);
for (int i = 0; i < count ; ++i)
{
const ColorRgb & color = ledValues[i];
// copy the most significant bits of the rgb values to the first three bytes
// offset 1 to accomodate for the command byte
_ledBuffer[6*i+1] = color.red;
_ledBuffer[6*i+2] = color.green;
_ledBuffer[6*i+3] = color.blue;
// leave the next three bytes on zero...
// 12-bit values having zeros in the lowest 4 bits which is almost correct, but it saves extra
// switches to determine what to do and some bit shuffling
}
int error = writeBytes(_ledBuffer.data(), _ledBuffer.size());
return error >= 0 ? 0 : error;
}
int LedDeviceLightpack::switchOff()
{
unsigned char buf[1] = {CMD_OFF_ALL};
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
}
const std::string &LedDeviceLightpack::getSerialNumber() const
{
return _serialNumber;
}
int LedDeviceLightpack::getLedCount() const
{
return _ledCount;
}
int LedDeviceLightpack::writeBytes(uint8_t *data, int size)
{
// std::cout << "Writing " << size << " bytes: ";
// for (int i = 0; i < size ; ++i) printf("%02x ", data[i]);
// std::cout << std::endl;
int error = libusb_control_transfer(_deviceHandle,
LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
0x09,
(2 << 8),
0x00,
data, size, 1000);
if (error == size)
{
return 0;
}
std::cerr << "Unable to write " << size << " bytes to Lightpack device(" << error << "): " << libusb_error_name(error) << std::endl;
return error;
}
int LedDeviceLightpack::disableSmoothing()
{
unsigned char buf[2] = {CMD_SET_SMOOTH_SLOWDOWN, 0};
return writeBytes(buf, sizeof(buf)) == sizeof(buf);
}
libusb_device_handle * LedDeviceLightpack::openDevice(libusb_device *device)
{
libusb_device_handle * handle = nullptr;
int error = libusb_open(device, &handle);
if (error != LIBUSB_SUCCESS)
{
std::cerr << "unable to open device(" << error << "): " << libusb_error_name(error) << std::endl;
throw error;
}
// detach kernel driver if it is active
if (libusb_kernel_driver_active(handle, LIGHTPACK_INTERFACE) == 1)
{
error = libusb_detach_kernel_driver(handle, LIGHTPACK_INTERFACE);
if (error != LIBUSB_SUCCESS)
{
std::cerr << "unable to detach kernel driver(" << error << "): " << libusb_error_name(error) << std::endl;
libusb_close(handle);
throw error;
}
}
error = libusb_claim_interface(handle, LIGHTPACK_INTERFACE);
if (error != LIBUSB_SUCCESS)
{
std::cerr << "unable to claim interface(" << error << "): " << libusb_error_name(error) << std::endl;
libusb_attach_kernel_driver(handle, LIGHTPACK_INTERFACE);
libusb_close(handle);
throw error;
}
return handle;
}
std::string LedDeviceLightpack::getString(libusb_device * device, int stringDescriptorIndex)
{
libusb_device_handle * handle = nullptr;
int error = libusb_open(device, &handle);
if (error != LIBUSB_SUCCESS)
{
throw error;
}
char buffer[256];
error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer));
if (error <= 0)
{
libusb_close(handle);
throw error;
}
libusb_close(handle);
return std::string(buffer, error);
}

View File

@@ -1,119 +0,0 @@
#pragma once
// stl includes
#include <vector>
#include <cstdint>
#include <string>
// libusb include
#include <libusb.h>
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// LedDevice implementation for a lightpack device (http://code.google.com/p/light-pack/)
///
class LedDeviceLightpack : public LedDevice
{
public:
///
/// Constructs the LedDeviceLightpack
///
LedDeviceLightpack();
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedDeviceLightpack();
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open(const std::string & serialNumber = "");
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues The RGB-color per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues Array of RGB values
/// @param[in] size The number of RGB values
///
/// @return Zero on success else negative
///
int write(const ColorRgb * ledValues, int size);
///
/// Switch the leds off
///
/// @return Zero on success else negative
///
virtual int switchOff();
/// Get the serial of the Lightpack
const std::string & getSerialNumber() const;
/// Get the number of leds
int getLedCount() const;
private:
///
/// Test if the device is a (or the) lightpack we are looking for
///
/// @return Zero on succes else negative
///
int testAndOpen(libusb_device * device, const std::string & requestedSerialNumber);
/// write bytes to the device
int writeBytes(uint8_t *data, int size);
/// Disable the internal smoothing on the Lightpack device
int disableSmoothing();
struct Version
{
int majorVersion;
int minorVersion;
};
static libusb_device_handle * openDevice(libusb_device * device);
static std::string getString(libusb_device * device, int stringDescriptorIndex);
private:
/// libusb context
libusb_context * _libusbContext;
/// libusb device handle
libusb_device_handle * _deviceHandle;
/// harware bus number
int _busNumber;
/// hardware address number
int _addressNumber;
/// device serial number
std::string _serialNumber;
/// firmware version of the device
Version _firmwareVersion;
/// the number of leds of the device
int _ledCount;
/// the number of bits per channel
int _bitsPerChannel;
/// buffer for led data
std::vector<uint8_t> _ledBuffer;
};

View File

@@ -1,49 +0,0 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
// hyperion local includes
#include "LedDeviceLpd6803.h"
LedDeviceLpd6803::LedDeviceLpd6803(const std::string& outputDevice, const unsigned baudrate) :
LedSpiDevice(outputDevice, baudrate),
_ledBuffer(0)
{
// empty
}
int LedDeviceLpd6803::write(const std::vector<ColorRgb> &ledValues)
{
// Reconfigure if the current connfiguration does not match the required configuration
if (4 + 2*ledValues.size() != _ledBuffer.size())
{
// Initialise the buffer
_ledBuffer.resize(4 + 2*ledValues.size(), 0x00);
}
// Copy the colors from the ColorRgb vector to the Ldp6803 data vector
for (unsigned iLed=0; iLed<ledValues.size(); ++iLed)
{
const ColorRgb& rgb = ledValues[iLed];
_ledBuffer[4 + 2 * iLed] = 0x80 | ((rgb.red & 0xf8) >> 1) | (rgb.green >> 6);
_ledBuffer[5 + 2 * iLed] = ((rgb.green & 0x38) << 2) | (rgb.blue >> 3);
}
// Write the data
if (writeBytes(_ledBuffer.size(), _ledBuffer.data()) < 0)
{
return -1;
}
return 0;
}
int LedDeviceLpd6803::switchOff()
{
return write(std::vector<ColorRgb>(_ledBuffer.size(), ColorRgb{0,0,0}));
}

View File

@@ -1,42 +0,0 @@
#pragma once
// Local hyperion incluse
#include "LedSpiDevice.h"
///
/// Implementation of the LedDevice interface for writing to LDP6803 led device.
///
/// 00000000 00000000 00000000 00000000 1RRRRRGG GGGBBBBB 1RRRRRGG GGGBBBBB ...
/// |---------------------------------| |---------------| |---------------|
/// 32 zeros to start the frame Led1 Led2 ...
///
/// For each led, the first bit is always 1, and then you have 5 bits each for red, green and blue
/// (R, G and B in the above illustration) making 16 bits per led. Total bytes = 4 + (2 x number of
/// leds)
///
class LedDeviceLpd6803 : public LedSpiDevice
{
public:
///
/// Constructs the LedDevice for a string containing leds of the type LDP6803
///
/// @param[in] outputDevice The name of the output device (eg '/dev/spidev0.0')
/// @param[in] baudrate The used baudrate for writing to the output device
///
LedDeviceLpd6803(const std::string& outputDevice, const unsigned baudrate);
///
/// Writes the led color values to the led-device
///
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
/// Switch the leds off
virtual int switchOff();
private:
/// The buffer containing the packed RGB values
std::vector<uint8_t> _ledBuffer;
};

View File

@@ -1,54 +0,0 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
// hyperion local includes
#include "LedDeviceLpd8806.h"
LedDeviceLpd8806::LedDeviceLpd8806(const std::string& outputDevice, const unsigned baudrate) :
LedSpiDevice(outputDevice, baudrate),
_ledBuffer(0)
{
// empty
}
int LedDeviceLpd8806::write(const std::vector<ColorRgb> &ledValues)
{
const unsigned clearSize = ledValues.size()/32+1;
// Reconfigure if the current connfiguration does not match the required configuration
if (3*ledValues.size() + clearSize != _ledBuffer.size())
{
// Initialise the buffer
_ledBuffer.resize(3*ledValues.size() + clearSize, 0x00);
// Perform an initial reset to start accepting data on the first led
writeBytes(clearSize, _ledBuffer.data());
}
// Copy the colors from the ColorRgb vector to the Ldp8806 data vector
for (unsigned iLed=0; iLed<ledValues.size(); ++iLed)
{
const ColorRgb& rgb = ledValues[iLed];
_ledBuffer[iLed*3] = 0x80 | (rgb.red >> 1);
_ledBuffer[iLed*3+1] = 0x80 | (rgb.green >> 1);
_ledBuffer[iLed*3+2] = 0x80 | (rgb.blue >> 1);
}
// Write the data
if (writeBytes(_ledBuffer.size(), _ledBuffer.data()) < 0)
{
return -1;
}
return 0;
}
int LedDeviceLpd8806::switchOff()
{
return write(std::vector<ColorRgb>(_ledBuffer.size(), ColorRgb{0,0,0}));
}

View File

@@ -1,103 +0,0 @@
#pragma once
// Local hyperion incluse
#include "LedSpiDevice.h"
///
/// Implementation of the LedDevice interface for writing to LPD8806 led device.
///
/// The following description is copied from 'adafruit' (github.com/adafruit/LPD8806)
///
/// Clearing up some misconceptions about how the LPD8806 drivers work:
///
/// The LPD8806 is not a FIFO shift register. The first data out controls the
/// LED *closest* to the processor (unlike a typical shift register, where the
/// first data out winds up at the *furthest* LED). Each LED driver 'fills up'
/// with data and then passes through all subsequent bytes until a latch
/// condition takes place. This is actually pretty common among LED drivers.
///
/// All color data bytes have the high bit (128) set, with the remaining
/// seven bits containing a brightness value (0-127). A byte with the high
/// bit clear has special meaning (explained later).
///
/// The rest gets bizarre...
///
/// The LPD8806 does not perform an in-unison latch (which would display the
/// newly-transmitted data all at once). Rather, each individual byte (even
/// the separate G, R, B components of each LED) is latched AS IT ARRIVES...
/// or more accurately, as the first bit of the subsequent byte arrives and
/// is passed through. So the strip actually refreshes at the speed the data
/// is issued, not instantaneously (this can be observed by greatly reducing
/// the data rate). This has implications for POV displays and light painting
/// applications. The 'subsequent' rule also means that at least one extra
/// byte must follow the last pixel, in order for the final blue LED to latch.
///
/// To reset the pass-through behavior and begin sending new data to the start
/// of the strip, a number of zero bytes must be issued (remember, all color
/// data bytes have the high bit set, thus are in the range 128 to 255, so the
/// zero is 'special'). This should be done before each full payload of color
/// values to the strip. Curiously, zero bytes can only travel one meter (32
/// LEDs) down the line before needing backup; the next meter requires an
/// extra zero byte, and so forth. Longer strips will require progressively
/// more zeros. *(see note below)
///
/// In the interest of efficiency, it's possible to combine the former EOD
/// extra latch byte and the latter zero reset...the same data can do double
/// duty, latching the last blue LED while also resetting the strip for the
/// next payload.
///
/// So: reset byte(s) of suitable length are issued once at startup to 'prime'
/// the strip to a known ready state. After each subsequent LED color payload,
/// these reset byte(s) are then issued at the END of each payload, both to
/// latch the last LED and to prep the strip for the start of the next payload
/// (even if that data does not arrive immediately). This avoids a tiny bit
/// of latency as the new color payload can begin issuing immediately on some
/// signal, such as a timer or GPIO trigger.
///
/// Technically these zero byte(s) are not a latch, as the color data (save
/// for the last byte) is already latched. It's a start-of-data marker, or
/// an indicator to clear the thing-that's-not-a-shift-register. But for
/// conversational consistency with other LED drivers, we'll refer to it as
/// a 'latch' anyway.
///
/// This has been validated independently with multiple customers'
/// hardware. Please do not report as a bug or issue pull requests for
/// this. Fewer zeros sometimes gives the *illusion* of working, the first
/// payload will correctly load and latch, but subsequent frames will drop
/// data at the end. The data shortfall won't always be visually apparent
/// depending on the color data loaded on the prior and subsequent frames.
/// Tested. Confirmed. Fact.
///
///
/// The summary of the story is that the following needs to be writen on the spi-device:
/// 1RRRRRRR 1GGGGGGG 1BBBBBBB 1RRRRRRR 1GGGGGGG ... ... 1GGGGGGG 1BBBBBBB 00000000 00000000 ...
/// |---------led_1----------| |---------led_2-- -led_n----------| |----clear data--
///
/// The number of zeroes in the 'clear data' is (#led/32 + 1)bytes (or *8 for bits)
///
class LedDeviceLpd8806 : public LedSpiDevice
{
public:
///
/// Constructs the LedDevice for a string containing leds of the type LPD8806
///
/// @param[in] outputDevice The name of the output device (eg '/dev/spidev0.0')
/// @param[in] baudrate The used baudrate for writing to the output device
///
LedDeviceLpd8806(const std::string& outputDevice, const unsigned baudrate);
///
/// Writes the led color values to the led-device
///
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
/// Switch the leds off
virtual int switchOff();
private:
/// The buffer containing the packed RGB values
std::vector<uint8_t> _ledBuffer;
};

View File

@@ -1,191 +0,0 @@
// stl includes
#include <exception>
#include <cstring>
#include <algorithm>
// Local Hyperion includes
#include "LedDeviceMultiLightpack.h"
// from USB_ID.h (http://code.google.com/p/light-pack/source/browse/CommonHeaders/USB_ID.h)
#define USB_OLD_VENDOR_ID 0x03EB
#define USB_OLD_PRODUCT_ID 0x204F
#define USB_VENDOR_ID 0x1D50
#define USB_PRODUCT_ID 0x6022
bool compareLightpacks(LedDeviceLightpack * lhs, LedDeviceLightpack * rhs)
{
return lhs->getSerialNumber() < rhs->getSerialNumber();
}
LedDeviceMultiLightpack::LedDeviceMultiLightpack() :
LedDevice(),
_lightpacks()
{
}
LedDeviceMultiLightpack::~LedDeviceMultiLightpack()
{
for (LedDeviceLightpack * device : _lightpacks)
{
delete device;
}
}
int LedDeviceMultiLightpack::open()
{
// retrieve a list with Lightpack serials
std::list<std::string> serialList = getLightpackSerials();
// sort the list of Lightpacks based on the serial to get a fixed order
std::sort(_lightpacks.begin(), _lightpacks.end(), compareLightpacks);
// open each lightpack device
for (const std::string & serial : serialList)
{
LedDeviceLightpack * device = new LedDeviceLightpack();
int error = device->open(serial);
if (error == 0)
{
_lightpacks.push_back(device);
}
else
{
std::cerr << "Error while creating Lightpack device with serial " << serial << std::endl;
delete device;
}
}
if (_lightpacks.size() == 0)
{
std::cerr << "No Lightpack devices were found" << std::endl;
}
else
{
std::cout << _lightpacks.size() << " Lightpack devices were found" << std::endl;
}
return _lightpacks.size() > 0 ? 0 : -1;
}
int LedDeviceMultiLightpack::write(const std::vector<ColorRgb> &ledValues)
{
const ColorRgb * data = ledValues.data();
int size = ledValues.size();
for (LedDeviceLightpack * device : _lightpacks)
{
int count = std::min(device->getLedCount(), size);
if (count > 0)
{
device->write(data, count);
data += count;
size -= count;
}
else
{
std::cout << "Unable to write data to Lightpack device: no more led data available" << std::endl;
}
}
return 0;
}
int LedDeviceMultiLightpack::switchOff()
{
for (LedDeviceLightpack * device : _lightpacks)
{
device->switchOff();
}
return 0;
}
std::list<std::string> LedDeviceMultiLightpack::getLightpackSerials()
{
std::list<std::string> serialList;
std::cout << "Getting list of Lightpack serials" << std::endl;
// initialize the usb context
libusb_context * libusbContext;
int error = libusb_init(&libusbContext);
if (error != LIBUSB_SUCCESS)
{
std::cerr << "Error while initializing USB context(" << error << "): " << libusb_error_name(error) << std::endl;
libusbContext = nullptr;
return serialList;
}
//libusb_set_debug(_libusbContext, 3);
std::cout << "USB context initialized in multi Lightpack device" << std::endl;
// retrieve the list of usb devices
libusb_device ** deviceList;
ssize_t deviceCount = libusb_get_device_list(libusbContext, &deviceList);
// iterate the list of devices
for (ssize_t i = 0 ; i < deviceCount; ++i)
{
libusb_device_descriptor deviceDescriptor;
error = libusb_get_device_descriptor(deviceList[i], &deviceDescriptor);
if (error != LIBUSB_SUCCESS)
{
std::cerr << "Error while retrieving device descriptor(" << error << "): " << libusb_error_name(error) << std::endl;
continue;
}
if ((deviceDescriptor.idVendor == USB_VENDOR_ID && deviceDescriptor.idProduct == USB_PRODUCT_ID) ||
(deviceDescriptor.idVendor == USB_OLD_VENDOR_ID && deviceDescriptor.idProduct == USB_OLD_PRODUCT_ID))
{
std::cout << "Found a lightpack device. Retrieving serial..." << std::endl;
// get the serial number
std::string serialNumber;
if (deviceDescriptor.iSerialNumber != 0)
{
try
{
serialNumber = LedDeviceMultiLightpack::getString(deviceList[i], deviceDescriptor.iSerialNumber);
}
catch (int e)
{
std::cerr << "Unable to retrieve serial number(" << e << "): " << libusb_error_name(e) << std::endl;
continue;
}
}
std::cout << "Lightpack device found with serial " << serialNumber << std::endl;
serialList.push_back(serialNumber);
}
}
// free the device list
libusb_free_device_list(deviceList, 1);
libusb_exit(libusbContext);
return serialList;
}
std::string LedDeviceMultiLightpack::getString(libusb_device * device, int stringDescriptorIndex)
{
libusb_device_handle * handle = nullptr;
int error = libusb_open(device, &handle);
if (error != LIBUSB_SUCCESS)
{
throw error;
}
char buffer[256];
error = libusb_get_string_descriptor_ascii(handle, stringDescriptorIndex, reinterpret_cast<unsigned char *>(buffer), sizeof(buffer));
if (error <= 0)
{
libusb_close(handle);
throw error;
}
libusb_close(handle);
return std::string(buffer, error);
}

View File

@@ -1,62 +0,0 @@
#pragma once
// stl includes
#include <vector>
#include <cstdint>
#include <string>
#include <list>
// libusb include
#include <libusb.h>
// Hyperion includes
#include <hyperion/LedDevice.h>
#include "LedDeviceLightpack.h"
///
/// LedDevice implementation for multiple lightpack devices
///
class LedDeviceMultiLightpack : public LedDevice
{
public:
///
/// Constructs the LedDeviceMultiLightpack
///
LedDeviceMultiLightpack();
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedDeviceMultiLightpack();
///
/// Opens and configures the output device7
///
/// @return Zero on succes else negative
///
int open();
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues The RGB-color per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
///
/// Switch the leds off
///
/// @return Zero on success else negative
///
virtual int switchOff();
private:
static std::list<std::string> getLightpackSerials();
static std::string getString(libusb_device * device, int stringDescriptorIndex);
private:
/// buffer for led data
std::vector<LedDeviceLightpack *> _lightpacks;
};

View File

@@ -1,77 +0,0 @@
// Hyperion includes
#include "LedDevicePaintpack.h"
LedDevicePaintpack::LedDevicePaintpack() :
LedDevice(),
_deviceHandle(nullptr)
{
// empty
}
int LedDevicePaintpack::open()
{
// initialize the usb context
int error = hid_init();
if (error != 0)
{
std::cerr << "Error while initializing the hidapi context" << std::endl;
return -1;
}
std::cout << "Hidapi initialized" << std::endl;
// Initialise the paintpack device
const unsigned short Paintpack_VendorId = 0x0ebf;
const unsigned short Paintpack_ProductId = 0x0025;
_deviceHandle = hid_open(Paintpack_VendorId, Paintpack_ProductId, nullptr);
if (_deviceHandle == nullptr)
{
// Failed to open the device
std::cerr << "Failed to open HID Paintpakc device " << std::endl;
return -1;
}
return 0;
}
LedDevicePaintpack::~LedDevicePaintpack()
{
if (_deviceHandle != nullptr)
{
hid_close(_deviceHandle);
_deviceHandle = nullptr;
}
hid_exit();
}
int LedDevicePaintpack::write(const std::vector<ColorRgb>& ledValues)
{
if (_ledBuffer.size() < 3 + ledValues.size()*3)
{
_ledBuffer.resize(3 + ledValues.size()*3, uint8_t(0));
_ledBuffer[0] = 0;
_ledBuffer[1] = 3;
_ledBuffer[2] = 0;
}
auto bufIt = _ledBuffer.begin()+3;
for (const ColorRgb & ledValue : ledValues)
{
*bufIt = ledValue.red;
++bufIt;
*bufIt = ledValue.green;
++bufIt;
*bufIt = ledValue.blue;
++bufIt;
}
return hid_write(_deviceHandle, _ledBuffer.data(), _ledBuffer.size());
}
int LedDevicePaintpack::switchOff()
{
std::fill(_ledBuffer.begin()+3, _ledBuffer.end(), uint8_t(0));
return hid_write(_deviceHandle, _ledBuffer.data(), _ledBuffer.size());
}

View File

@@ -1,59 +0,0 @@
#pragma once
// STL includes
#include <vector>
// libusb include
#include <hidapi/hidapi.h>
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// LedDevice implementation for a paintpack device ()
///
class LedDevicePaintpack : public LedDevice
{
public:
/**
* Constructs the paintpack device
*/
LedDevicePaintpack();
/**
* Destructs the paintpack device, closes USB connection if open
*/
virtual ~LedDevicePaintpack();
/**
* Opens the Paintpack device
*
* @return Zero on succes else negative
*/
int open();
///
/// Writes the RGB-Color values to the leds.
///
/// @param[in] ledValues The RGB-color per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb>& ledValues);
///
/// Switch the leds off
///
/// @return Zero on success else negative
///
virtual int switchOff();
private:
/// libusb device handle
hid_device * _deviceHandle;
/// buffer for led data
std::vector<uint8_t> _ledBuffer;
};

View File

@@ -1,63 +0,0 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
// hyperion local includes
#include "LedDeviceSedu.h"
struct FrameSpec
{
uint8_t id;
size_t size;
};
LedDeviceSedu::LedDeviceSedu(const std::string& outputDevice, const unsigned baudrate) :
LedRs232Device(outputDevice, baudrate),
_ledBuffer(0)
{
// empty
}
int LedDeviceSedu::write(const std::vector<ColorRgb> &ledValues)
{
if (_ledBuffer.size() == 0)
{
std::vector<FrameSpec> frameSpecs{{0xA0, 96}, {0xA1, 256}, {0xA2, 512}, {0xB0, 768}, {0xB1, 1536}, {0xB2, 3072} };
const unsigned reqColorChannels = ledValues.size() * sizeof(ColorRgb);
for (const FrameSpec& frameSpec : frameSpecs)
{
if (reqColorChannels <= frameSpec.size)
{
_ledBuffer.clear();
_ledBuffer.resize(frameSpec.size + 3, 0);
_ledBuffer[0] = 0x5A;
_ledBuffer[1] = frameSpec.id;
_ledBuffer.back() = 0xA5;
break;
}
}
if (_ledBuffer.size() == 0)
{
std::cout << "More rgb-channels required then available" << std::endl;
return -1;
}
}
memcpy(_ledBuffer.data()+2, ledValues.data(), ledValues.size() * sizeof(ColorRgb));
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}
int LedDeviceSedu::switchOff()
{
memset(_ledBuffer.data()+2, 0, _ledBuffer.size()-3);
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
}

View File

@@ -1,37 +0,0 @@
#pragma once
// STL includes
#include <string>
// hyperion incluse
#include "LedRs232Device.h"
///
/// Implementation of the LedDevice interface for writing to SEDU led device.
///
class LedDeviceSedu : public LedRs232Device
{
public:
///
/// Constructs the LedDevice for attached via SEDU device
///
/// @param outputDevice The name of the output device (eg '/dev/ttyS0')
/// @param baudrate The used baudrate for writing to the output device
///
LedDeviceSedu(const std::string& outputDevice, const unsigned baudrate);
///
/// Writes the led color values to the led-device
///
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
/// Switch the leds off
virtual int switchOff();
private:
/// The buffer containing the packed RGB values
std::vector<uint8_t> _ledBuffer;
};

View File

@@ -1,31 +0,0 @@
// Local-Hyperion includes
#include "LedDeviceTest.h"
LedDeviceTest::LedDeviceTest(const std::string& output) :
_ofs(output.empty()?"/home/pi/LedDevice.out":output.c_str())
{
// empty
}
LedDeviceTest::~LedDeviceTest()
{
// empty
}
int LedDeviceTest::write(const std::vector<ColorRgb> & ledValues)
{
_ofs << "[";
for (const ColorRgb& color : ledValues)
{
_ofs << color;
}
_ofs << "]" << std::endl;
return 0;
}
int LedDeviceTest::switchOff()
{
return 0;
}

View File

@@ -1,41 +0,0 @@
#pragma once
// STL includes0
#include <fstream>
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// Implementation of the LedDevice that write the led-colors to an
/// ASCII-textfile('/home/pi/LedDevice.out')
///
class LedDeviceTest : public LedDevice
{
public:
///
/// Constructs the test-device, which opens an output stream to the file
///
LedDeviceTest(const std::string& output);
///
/// Destructor of this test-device
///
virtual ~LedDeviceTest();
///
/// Writes the given led-color values to the output stream
///
/// @param ledValues The color-value per led
///
/// @return Zero on success else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
/// Switch the leds off
virtual int switchOff();
private:
/// The outputstream
std::ofstream _ofs;
};

View File

@@ -1,34 +0,0 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
// hyperion local includes
#include "LedDeviceWs2801.h"
LedDeviceWs2801::LedDeviceWs2801(const std::string& outputDevice, const unsigned baudrate) :
LedSpiDevice(outputDevice, baudrate, 500000),
mLedCount(0)
{
// empty
}
int LedDeviceWs2801::write(const std::vector<ColorRgb> &ledValues)
{
mLedCount = ledValues.size();
const unsigned dataLen = ledValues.size() * sizeof(ColorRgb);
const uint8_t * dataPtr = reinterpret_cast<const uint8_t *>(ledValues.data());
return writeBytes(dataLen, dataPtr);
}
int LedDeviceWs2801::switchOff()
{
return write(std::vector<ColorRgb>(mLedCount, ColorRgb{0,0,0}));
}

View File

@@ -1,39 +0,0 @@
#pragma once
// STL includes
#include <string>
// hyperion incluse
#include "LedSpiDevice.h"
///
/// Implementation of the LedDevice interface for writing to Ws2801 led device.
///
class LedDeviceWs2801 : public LedSpiDevice
{
public:
///
/// Constructs the LedDevice for a string containing leds of the type Ws2801
///
/// @param outputDevice The name of the output device (eg '/etc/SpiDev.0.0')
/// @param baudrate The used baudrate for writing to the output device
///
LedDeviceWs2801(const std::string& outputDevice,
const unsigned baudrate);
///
/// Writes the led color values to the led-device
///
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> &ledValues);
/// Switch the leds off
virtual int switchOff();
private:
/// the number of leds (needed when switching off)
size_t mLedCount;
};

View File

@@ -1,182 +0,0 @@
// Local hyperion includes
#include "LedDeviceWs2811.h"
ws2811::SignalTiming ws2811::fromString(const std::string& signalTiming, const SignalTiming defaultValue)
{
SignalTiming result = defaultValue;
if (signalTiming == "3755" || signalTiming == "option_3755")
{
result = option_3755;
}
else if (signalTiming == "3773" || signalTiming == "option_3773")
{
result = option_3773;
}
else if (signalTiming == "2855" || signalTiming == "option_2855")
{
result = option_2855;
}
else if (signalTiming == "2882" || signalTiming == "option_2882")
{
result = option_2882;
}
return result;
}
unsigned ws2811::getBaudrate(const SpeedMode speedMode)
{
switch (speedMode)
{
case highspeed:
// Bit length: 125ns
return 8000000;
case lowspeed:
// Bit length: 250ns
return 4000000;
}
return 0;
}
inline unsigned ws2811::getLength(const SignalTiming timing, const TimeOption option)
{
switch (timing)
{
case option_3755:
// Reference: http://www.mikrocontroller.net/attachment/180459/WS2812B_preliminary.pdf
// Unit length: 125ns
switch (option)
{
case T0H:
return 3; // 400ns +-150ns
case T0L:
return 7; // 850ns +-150ns
case T1H:
return 7; // 800ns +-150ns
case T1L:
return 3; // 450ns +-150ns
}
case option_3773:
// Reference: www.adafruit.com/datasheets/WS2812.pdf
// Unit length: 125ns
switch (option)
{
case T0H:
return 3; // 350ns +-150ns
case T0L:
return 7; // 800ns +-150ns
case T1H:
return 7; // 700ns +-150ns
case T1L:
return 3; // 600ns +-150ns
}
case option_2855:
// Reference: www.adafruit.com/datasheets/WS2811.pdf
// Unit length: 250ns
switch (option)
{
case T0H:
return 2; // 500ns +-150ns
case T0L:
return 8; // 2000ns +-150ns
case T1H:
return 5; // 1200ns +-150ns
case T1L:
return 5; // 1300ns +-150ns
}
case option_2882:
// Reference: www.szparkson.net/download/WS2811.pdf
// Unit length: 250ns
switch (option)
{
case T0H:
return 2; // 500ns +-150ns
case T0L:
return 8; // 2000ns +-150ns
case T1H:
return 8; // 2000ns +-150ns
case T1L:
return 2; // 500ns +-150ns
}
default:
std::cerr << "Unknown signal timing for ws2811: " << timing << std::endl;
}
return 0;
}
uint8_t ws2811::bitToSignal(unsigned lenHigh)
{
// Sanity check on the length of the 'high' signal
assert(0 < lenHigh && lenHigh < 10);
uint8_t result = 0x00;
for (unsigned i=1; i<lenHigh; ++i)
{
result |= (1 << (8-i));
}
return result;
}
ws2811::ByteSignal ws2811::translate(SignalTiming ledOption, uint8_t byte)
{
ByteSignal result;
result.bit_1 = bitToSignal(getLength(ledOption, (byte & 0x80)?T1H:T0H));
result.bit_2 = bitToSignal(getLength(ledOption, (byte & 0x40)?T1H:T0H));
result.bit_3 = bitToSignal(getLength(ledOption, (byte & 0x20)?T1H:T0H));
result.bit_4 = bitToSignal(getLength(ledOption, (byte & 0x10)?T1H:T0H));
result.bit_5 = bitToSignal(getLength(ledOption, (byte & 0x08)?T1H:T0H));
result.bit_6 = bitToSignal(getLength(ledOption, (byte & 0x04)?T1H:T0H));
result.bit_7 = bitToSignal(getLength(ledOption, (byte & 0x02)?T1H:T0H));
result.bit_8 = bitToSignal(getLength(ledOption, (byte & 0x01)?T1H:T0H));
return result;
}
LedDeviceWs2811::LedDeviceWs2811(
const std::string & outputDevice,
const ws2811::SignalTiming signalTiming,
const ws2811::SpeedMode speedMode) :
LedRs232Device(outputDevice, ws2811::getBaudrate(speedMode))
{
fillEncodeTable(signalTiming);
}
int LedDeviceWs2811::write(const std::vector<ColorRgb> & ledValues)
{
if (_ledBuffer.size() != ledValues.size() * 3)
{
_ledBuffer.resize(ledValues.size() * 3);
}
auto bufIt = _ledBuffer.begin();
for (const ColorRgb & color : ledValues)
{
*bufIt = _byteToSignalTable[color.red ];
++bufIt;
*bufIt = _byteToSignalTable[color.green];
++bufIt;
*bufIt = _byteToSignalTable[color.blue ];
++bufIt;
}
writeBytes(_ledBuffer.size() * 3, reinterpret_cast<uint8_t *>(_ledBuffer.data()));
return 0;
}
int LedDeviceWs2811::switchOff()
{
write(std::vector<ColorRgb>(_ledBuffer.size()/3, ColorRgb::BLACK));
return 0;
}
void LedDeviceWs2811::fillEncodeTable(const ws2811::SignalTiming ledOption)
{
_byteToSignalTable.resize(256);
for (unsigned byteValue=0; byteValue<256; ++byteValue)
{
const uint8_t byteVal = uint8_t(byteValue);
_byteToSignalTable[byteValue] = ws2811::translate(ledOption, byteVal);
}
}

View File

@@ -1,147 +0,0 @@
#pragma once
// STL includes
#include <cassert>
// Local hyperion includes
#include "LedRs232Device.h"
namespace ws2811
{
///
/// Enumaration of known signal timings
///
enum SignalTiming
{
option_3755,
option_3773,
option_2855,
option_2882,
not_a_signaltiming
};
///
/// Enumaration of the possible speeds on which the ws2811 can operate.
///
enum SpeedMode
{
lowspeed,
highspeed
};
///
/// Enumeration of the signal 'parts' (T 0 high, T 1 high, T 0 low, T 1 low).
///
enum TimeOption
{
T0H,
T1H,
T0L,
T1L
};
///
/// Structure holding the signal for a signle byte
///
struct ByteSignal
{
uint8_t bit_1;
uint8_t bit_2;
uint8_t bit_3;
uint8_t bit_4;
uint8_t bit_5;
uint8_t bit_6;
uint8_t bit_7;
uint8_t bit_8;
};
// Make sure the structure is exatly the length we require
static_assert(sizeof(ByteSignal) == 8, "Incorrect sizeof ByteSignal (expected 8)");
///
/// Translates a string to a signal timing
///
/// @param signalTiming The string specifying the signal timing
/// @param defaultValue The default value (used if the string does not match any known timing)
///
/// @return The SignalTiming (or not_a_signaltiming if it did not match)
///
SignalTiming fromString(const std::string& signalTiming, const SignalTiming defaultValue);
///
/// Returns the required baudrate for a specific signal-timing
///
/// @param SpeedMode The WS2811/WS2812 speed mode (WS2812b only has highspeed)
///
/// @return The required baudrate for the signal timing
///
unsigned getBaudrate(const SpeedMode speedMode);
///
/// The number of 'signal units' (bits) For the subpart of a specific timing scheme
///
/// @param timing The controller option
/// @param option The signal part
///
unsigned getLength(const SignalTiming timing, const TimeOption option);
///
/// Constructs a 'bit' based signal with defined 'high' length (and implicite defined 'low'
/// length. The signal is based on a 10bits bytes (incl. high startbit and low stopbit). The
/// total length of the high is given as parameter:<br>
/// lenHigh=7 => |-------|___| => 1 1111 1100 0 => 252 (start and stop bit are implicite)
///
/// @param lenHigh The total length of the 'high' length (incl start-bit)
/// @return The byte representing the high-low signal
///
uint8_t bitToSignal(unsigned lenHigh);
///
/// Translate a byte into signal levels for a specific WS2811 option
///
/// @param ledOption The WS2811 configuration
/// @param byte The byte to translate
///
/// @return The signal for the given byte (one byte per bit)
///
ByteSignal translate(SignalTiming ledOption, uint8_t byte);
}
class LedDeviceWs2811 : public LedRs232Device
{
public:
///
/// Constructs the LedDevice with Ws2811 attached via a serial port
///
/// @param outputDevice The name of the output device (eg '/dev/ttyS0')
/// @param signalTiming The timing scheme used by the Ws2811 chip
/// @param speedMode The speed modus of the Ws2811 chip
///
LedDeviceWs2811(const std::string& outputDevice, const ws2811::SignalTiming signalTiming, const ws2811::SpeedMode speedMode);
///
/// Writes the led color values to the led-device
///
/// @param ledValues The color-value per led
/// @return Zero on succes else negative
///
virtual int write(const std::vector<ColorRgb> & ledValues);
/// Switch the leds off
virtual int switchOff();
private:
///
/// Fill the byte encoding table (_byteToSignalTable) for the specific timing option
///
/// @param ledOption The timing option
///
void fillEncodeTable(const ws2811::SignalTiming ledOption);
/// Translation table of byte to signal///
std::vector<ws2811::ByteSignal> _byteToSignalTable;
/// The buffer containing the packed RGB values
std::vector<ws2811::ByteSignal> _ledBuffer;
};

View File

@@ -1,66 +0,0 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Local Hyperion includes
#include "LedRs232Device.h"
LedRs232Device::LedRs232Device(const std::string& outputDevice, const unsigned baudrate) :
mDeviceName(outputDevice),
mBaudRate_Hz(baudrate),
_rs232Port()
{
// empty
}
LedRs232Device::~LedRs232Device()
{
if (_rs232Port.isOpen())
{
_rs232Port.close();
}
}
int LedRs232Device::open()
{
try
{
_rs232Port.setPort(mDeviceName);
_rs232Port.setBaudrate(mBaudRate_Hz);
_rs232Port.open();
}
catch (const std::exception& e)
{
std::cerr << "Unable to open RS232 device (" << e.what() << ")" << std::endl;
return -1;
}
return 0;
}
int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data)
{
if (!_rs232Port.isOpen())
{
return -1;
}
// for (int i = 0; i < 20; ++i)
// std::cout << std::hex << (int)data[i] << " ";
// std::cout << std::endl;
try
{
_rs232Port.write(data, size);
}
catch (const std::exception& e)
{
std::cerr << "Unable to write to RS232 device (" << e.what() << ")" << std::endl;
return -1;
}
return 0;
}

View File

@@ -1,54 +0,0 @@
#pragma once
// Serial includes
#include <serial/serial.h>
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// The LedRs232Device implements an abstract base-class for LedDevices using a RS232-device.
///
class LedRs232Device : public LedDevice
{
public:
///
/// Constructs the LedDevice attached to a RS232-device
///
/// @param[in] outputDevice The name of the output device (eg '/etc/ttyS0')
/// @param[in] baudrate The used baudrate for writing to the output device
///
LedRs232Device(const std::string& outputDevice, const unsigned baudrate);
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedRs232Device();
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
protected:
/**
* Writes the given bytes to the RS232-device and
*
* @param[in[ size The length of the data
* @param[in] data The data
*
* @return Zero on succes else negative
*/
int writeBytes(const unsigned size, const uint8_t *data);
private:
/// The name of the output device
const std::string mDeviceName;
/// The used baudrate of the output device
const int mBaudRate_Hz;
/// The RS232 serial-device
serial::Serial _rs232Port;
};

View File

@@ -1,84 +0,0 @@
// STL includes
#include <cstring>
#include <cstdio>
#include <iostream>
// Linux includes
#include <fcntl.h>
#include <sys/ioctl.h>
// Local Hyperion includes
#include "LedSpiDevice.h"
LedSpiDevice::LedSpiDevice(const std::string& outputDevice, const unsigned baudrate, const int latchTime_ns) :
mDeviceName(outputDevice),
mBaudRate_Hz(baudrate),
mLatchTime_ns(latchTime_ns),
mFid(-1)
{
memset(&spi, 0, sizeof(spi));
}
LedSpiDevice::~LedSpiDevice()
{
// close(mFid);
}
int LedSpiDevice::open()
{
const int bitsPerWord = 8;
mFid = ::open(mDeviceName.c_str(), O_RDWR);
if (mFid < 0)
{
std::cerr << "Failed to open device('" << mDeviceName << "') " << std::endl;
return -1;
}
int mode = SPI_MODE_0;
if (ioctl(mFid, SPI_IOC_WR_MODE, &mode) == -1 || ioctl(mFid, SPI_IOC_RD_MODE, &mode) == -1)
{
return -2;
}
if (ioctl(mFid, SPI_IOC_WR_BITS_PER_WORD, &bitsPerWord) == -1 || ioctl(mFid, SPI_IOC_RD_BITS_PER_WORD, &bitsPerWord) == -1)
{
return -4;
}
if (ioctl(mFid, SPI_IOC_WR_MAX_SPEED_HZ, &mBaudRate_Hz) == -1 || ioctl(mFid, SPI_IOC_RD_MAX_SPEED_HZ, &mBaudRate_Hz) == -1)
{
return -6;
}
return 0;
}
int LedSpiDevice::writeBytes(const unsigned size, const uint8_t * data)
{
if (mFid < 0)
{
return -1;
}
spi.tx_buf = __u64(data);
spi.len = __u32(size);
int retVal = ioctl(mFid, SPI_IOC_MESSAGE(1), &spi);
if (retVal == 0 && mLatchTime_ns > 0)
{
// The 'latch' time for latching the shifted-value into the leds
timespec latchTime;
latchTime.tv_sec = 0;
latchTime.tv_nsec = mLatchTime_ns;
// Sleep to latch the leds (only if write succesfull)
nanosleep(&latchTime, NULL);
}
return retVal;
}

View File

@@ -1,61 +0,0 @@
#pragma once
// Linux-SPI includes
#include <linux/spi/spidev.h>
// Hyperion includes
#include <hyperion/LedDevice.h>
///
/// The LedSpiDevice implements an abstract base-class for LedDevices using the SPI-device.
///
class LedSpiDevice : public LedDevice
{
public:
///
/// Constructs the LedDevice attached to a SPI-device
///
/// @param[in] outputDevice The name of the output device (eg '/etc/SpiDev.0.0')
/// @param[in] baudrate The used baudrate for writing to the output device
/// @param[in] latchTime_ns The latch-time to latch in the values across the SPI-device (negative
/// means no latch required) [ns]
///
LedSpiDevice(const std::string& outputDevice, const unsigned baudrate, const int latchTime_ns = -1);
///
/// Destructor of the LedDevice; closes the output device if it is open
///
virtual ~LedSpiDevice();
///
/// Opens and configures the output device
///
/// @return Zero on succes else negative
///
int open();
protected:
///
/// Writes the given bytes/bits to the SPI-device and sleeps the latch time to ensure that the
/// values are latched.
///
/// @param[in[ size The length of the data
/// @param[in] data The data
///
/// @return Zero on succes else negative
///
int writeBytes(const unsigned size, const uint8_t *data);
private:
/// The name of the output device
const std::string mDeviceName;
/// The used baudrate of the output device
const int mBaudRate_Hz;
/// The time which the device should be untouched after a write
const int mLatchTime_ns;
/// The File Identifier of the opened output device (or -1 if not opened)
int mFid;
/// The transfer structure for writing to the spi-device
spi_ioc_transfer spi;
};