Added Ws2812b specific device

Former-commit-id: 675c8f578de42d12e25162065c0d0381ad0e08f6
This commit is contained in:
T. van der Zwan 2013-12-23 21:58:54 +00:00
parent 7f3fbae314
commit 01b5dcdd5c
8 changed files with 475 additions and 128 deletions

View File

@ -26,6 +26,7 @@ SET(Leddevice_HEADERS
${CURRENT_SOURCE_DIR}/LedDeviceSedu.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2811.h
${CURRENT_SOURCE_DIR}/LedDeviceWs2812b.h
${CURRENT_SOURCE_DIR}/LedDeviceLpd6803.h
${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.h
${CURRENT_SOURCE_DIR}/LedDeviceLightpack.h
@ -42,6 +43,7 @@ SET(Leddevice_SOURCES
${CURRENT_SOURCE_DIR}/LedDeviceTest.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2801.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2811.cpp
${CURRENT_SOURCE_DIR}/LedDeviceWs2812b.cpp
${CURRENT_SOURCE_DIR}/LedDeviceLpd6803.cpp
${CURRENT_SOURCE_DIR}/LedDeviceLpd8806.cpp
${CURRENT_SOURCE_DIR}/LedDeviceAdalight.cpp

View File

@ -9,6 +9,7 @@
#include "LedDeviceTest.h"
#include "LedDeviceWs2801.h"
#include "LedDeviceWs2811.h"
#include "LedDeviceWs2812b.h"
#include "LedDeviceAdalight.h"
#include "LedDevicePaintpack.h"
#include "LedDeviceLightpack.h"
@ -32,6 +33,13 @@ LedDevice * LedDeviceFactory::construct(const Json::Value & deviceConfig)
device = deviceWs2801;
}
else if (type == "ws2812b")
{
LedDeviceWs2812b * deviceWs2812b = new LedDeviceWs2812b();
deviceWs2812b->open();
device = deviceWs2812b;
}
// else if (type == "ws2811")
// {
// const std::string output = deviceConfig["output"].asString();

View File

@ -0,0 +1,88 @@
// Local Hyperion-Leddevice includes
#include "LedDeviceWs2812b.h"
LedDeviceWs2812b::LedDeviceWs2812b() :
LedRs232Device("/dev/ttyAMA0", 4000000)
{
fillTable();
}
int LedDeviceWs2812b::write(const std::vector<ColorRgb> & ledValues)
{
// Ensure the size of the led-buffer
if (_ledBuffer.size() != ledValues.size()*3)
{
_ledBuffer.resize(ledValues.size()*3);
}
// Translate the channel of each color to a signal
auto bufIt = _ledBuffer.begin();
for (const ColorRgb& color : ledValues)
{
*bufIt++ = _byte2signalTable[color.red];
*bufIt++ = _byte2signalTable[color.green];
*bufIt++ = _byte2signalTable[color.blue];
}
return writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
}
int LedDeviceWs2812b::switchOff()
{
// Set all bytes in the signal buffer to zero
for (ByteSignal & signal : _ledBuffer)
{
signal = _byte2signalTable[0];
}
return writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
}
void LedDeviceWs2812b::fillTable()
{
_byte2signalTable.clear();
for (int byte=0; byte<256; ++byte)
{
const ByteSignal signal = byte2Signal(uint8_t(byte));
_byte2signalTable.push_back(signal);
}
}
LedDeviceWs2812b::ByteSignal LedDeviceWs2812b::byte2Signal(const uint8_t byte) const
{
ByteSignal result;
result.bit_12 = bits2Signal(byte & 0x80, byte & 0x40);
result.bit_34 = bits2Signal(byte & 0x20, byte & 0x10);
result.bit_56 = bits2Signal(byte & 0x08, byte & 0x04);
result.bit_78 = bits2Signal(byte & 0x02, byte & 0x01);
return result;
}
uint8_t LedDeviceWs2812b::bits2Signal(const bool bit1, const bool bit2) const
{
if (bit1)
{
if (bit2)
{
return 0x8C;
}
else
{
return 0xCC;
}
}
else
{
if (bit2)
{
return 0x8E;
}
else
{
return 0xCE;
}
}
return 0x00;
}

View File

@ -0,0 +1,34 @@
#pragma once
// Hyperion leddevice includes
#include "LedRs232Device.h"
class LedDeviceWs2812b : public LedRs232Device
{
public:
LedDeviceWs2812b();
virtual int write(const std::vector<ColorRgb> & ledValues);
virtual int switchOff();
private:
struct ByteSignal
{
uint8_t bit_12;
uint8_t bit_34;
uint8_t bit_56;
uint8_t bit_78;
};
std::vector<ByteSignal> _byte2signalTable;
void fillTable();
ByteSignal byte2Signal(const uint8_t byte) const;
uint8_t bits2Signal(const bool bit1, const bool bit2) const;
std::vector<ByteSignal> _ledBuffer;
};

View File

@ -58,6 +58,7 @@ int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data)
try
{
_rs232Port.write(data, size);
_rs232Port.flush();
}
catch (const serial::SerialException & serialExc)
{
@ -77,6 +78,7 @@ int LedRs232Device::writeBytes(const unsigned size, const uint8_t * data)
{
_rs232Port.open();
_rs232Port.write(data, size);
_rs232Port.flush();
}
catch (const std::exception & e)
{

View File

@ -51,9 +51,11 @@ add_executable(gpio2spi switchPinCtrl.c)
add_executable(test_rs232highspeed
TestRs232HighSpeed.cpp
../libsrc/leddevice/LedRs232Device.cpp)
../libsrc/leddevice/LedRs232Device.cpp
../libsrc/leddevice/LedDeviceWs2812b.cpp)
target_link_libraries(test_rs232highspeed
serialport)
include_directories(/usr/include)
add_executable(test_uartHighSpeed TestUartHighSpeed.cpp)
target_link_libraries(test_uartHighSpeed ${QT_LIBRARIES})

View File

@ -1,32 +1,258 @@
// Hyperion includes
// STL includes
#include <iostream>
#include <random>
// Serialport includes
#include <serial/serial.h>
int testSerialPortLib();
int testHyperionDevice(int argc, char** argv);
int testWs2812bDevice();
int main(int argc, char** argv)
{
// if (argc == 1)
// {
// return testSerialPortLib();
// }
// else
// {
// return testHyperionDevice(argc, argv);
// }
return testWs2812bDevice();
}
int testSerialPortLib()
{
serial::Serial rs232Port("/dev/ttyAMA0", 4000000);
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1,2);
std::vector<uint8_t> data;
for (int i=0; i<9; ++i)
{
int coinFlip = distribution(generator);
if (coinFlip == 1)
{
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
}
else
{
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
}
}
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
while (true)
{
char c = getchar();
if (c == 'q' || c == 'x')
{
break;
}
if (c != 'c')
{
continue;
}
rs232Port.write(data);
data.clear();
for (int i=0; i<9; ++i)
{
int coinFlip = distribution(generator);
if (coinFlip == 1)
{
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
data.push_back(0xCE);
}
else
{
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
data.push_back(0x8C);
}
}
}
try
{
rs232Port.close();
}
catch (const std::runtime_error& excp)
{
std::cout << "Caught exception: " << excp.what() << std::endl;
return -1;
}
return 0;
}
#include "../libsrc/leddevice/LedRs232Device.h"
class TestDevice : public LedRs232Device
{
public:
TestDevice() :
LedRs232Device("/dev/ttyAMA0", 2000000)
LedRs232Device("/dev/ttyAMA0", 4000000)
{
// empty
open();
}
int write(const std::vector<ColorRgb> &ledValues) \
{
std::vector<uint8_t> bytes(ledValues.size() * 3 * 4);
uint8_t * bytePtr = bytes.data();
for (ColorRgb color : ledValues)
{
byte2Signal(color.green, bytePtr);
bytePtr += 4;
byte2Signal(color.red, bytePtr);
bytePtr += 4;
byte2Signal(color.blue, bytePtr);
bytePtr += 4;
}
writeBytes(bytes.size(), bytes.data());
return 0;
}
int write(const std::vector<ColorRgb> &ledValues) { return 0; }
int switchOff() { return 0; }
void writeTestSequence()
void writeTestSequence(const std::vector<uint8_t> & data)
{
uint8_t data = 'T';
writeBytes(data.size(), data.data());
}
writeBytes(1, &data);
void byte2Signal(const uint8_t byte, uint8_t * output)
{
output[0] = bits2Signal(byte & 0x80, byte & 0x40);
output[1] = bits2Signal(byte & 0x20, byte & 0x10);
output[2] = bits2Signal(byte & 0x08, byte & 0x04);
output[3] = bits2Signal(byte & 0x02, byte & 0x01);
}
uint8_t bits2Signal(const bool bit1, const bool bit2)
{
if (bit1)
{
if (bit2)
{
return 0x8C;
}
else
{
return 0xCC;
}
}
else
{
if (bit2)
{
return 0x8E;
}
else
{
return 0xCE;
}
}
return 0x00;
}
};
int main()
int testHyperionDevice(int argc, char** argv)
{
TestDevice device;
device.writeTestSequence();
TestDevice rs232Device;
if (argc > 1 && strncmp(argv[1], "off", 3) == 0)
{
rs232Device.write(std::vector<ColorRgb>(150, {0, 0, 0}));
return 0;
}
int loopCnt = 0;
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
while (true)
{
char c = getchar();
if (c == 'q' || c == 'x')
{
break;
}
if (c != 'c')
{
continue;
}
rs232Device.write(std::vector<ColorRgb>(loopCnt, {255, 255, 255}));
++loopCnt;
}
rs232Device.write(std::vector<ColorRgb>(150, {0, 0, 0}));
return 0;
}
#include "../libsrc/leddevice/LedDeviceWs2812b.h"
#include <unistd.h>
int testWs2812bDevice()
{
LedDeviceWs2812b device;
device.open();
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
int loopCnt = 0;
while (true)
{
// char c = getchar();
// if (c == 'q' || c == 'x')
// {
// break;
// }
// if (c != 'c')
// {
// continue;
// }
if (loopCnt%4 == 0)
device.write(std::vector<ColorRgb>(25, {255, 0, 0}));
else if (loopCnt%4 == 1)
device.write(std::vector<ColorRgb>(25, {0, 255, 0}));
else if (loopCnt%4 == 2)
device.write(std::vector<ColorRgb>(25, {0, 0, 255}));
else if (loopCnt%4 == 3)
device.write(std::vector<ColorRgb>(25, {17, 188, 66}));
++loopCnt;
usleep(200000);
if (loopCnt > 200)
{
break;
}
}
device.write(std::vector<ColorRgb>(150, {0, 0, 0}));
device.switchOff();
return 0;
}

View File

@ -1,11 +1,13 @@
#include <random>
#include <iostream>
#include <stdio.h>
#include <unistd.h> //Used for UART
#include <fcntl.h> //Used for UART
#include <termios.h> //Used for UART
#include <sys/ioctl.h>
#include </usr/include/linux/tty_flags.h>
#include <linux/serial.h>
#include <csignal>
#include <cstdint>
@ -13,28 +15,6 @@
#include <QElapsedTimer>
struct serial_struct {
int type;
int line;
unsigned int port;
int irq;
int flags;
int xmit_fifo_size;
int custom_divisor;
int baud_base;
unsigned short close_delay;
char io_type;
char reserved_char[1];
int hub6;
unsigned short closing_wait; /* time to wait before closing */
unsigned short closing_wait2; /* no longer used... */
unsigned char *iomem_base;
unsigned short iomem_reg_shift;
unsigned int port_high;
unsigned long iomap_base; /* cookie passed into ioremap */
};
static volatile bool _running;
void signal_handler(int signum)
@ -73,62 +53,72 @@ int main()
printf("Error - Unable to open UART. Ensure it is not in use by another application\n");
}
//CONFIGURE THE UART
//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
// Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
// CSIZE:- CS5, CS6, CS7, CS8
// CLOCAL - Ignore modem status lines
// CREAD - Enable receiver
// IGNPAR = Ignore characters with parity errors
// ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
// PARENB - Parity enable
// PARODD - Odd parity (else even)
struct termios options;
tcgetattr(uart0_filestream, &options);
options.c_cflag = B4000000 | CS8 | CLOCAL | CREAD; //<Set baud rate
options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
tcflush(uart0_filestream, TCIFLUSH);
// if (0)
{
//CONFIGURE THE UART
//The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html):
// Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000
// CSIZE:- CS5, CS6, CS7, CS8
// CLOCAL - Ignore modem status lines
// CREAD - Enable receiver
// IGNPAR = Ignore characters with parity errors
// ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for bianry comms!)
// PARENB - Parity enable
// PARODD - Odd parity (else even)
struct termios options;
tcgetattr(uart0_filestream, &options);
options.c_cflag = B4000000 | CS8 | CLOCAL | CREAD; //<Set baud rate
options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
tcflush(uart0_filestream, TCIFLUSH);
std::cout << "options.c_cflag = " << options.c_cflag << std::endl;
std::cout << "options.c_iflag = " << options.c_iflag << std::endl;
std::cout << "options.c_oflag = " << options.c_oflag << std::endl;
std::cout << "options.c_lflag = " << options.c_lflag << std::endl;
std::cout << "options.c_cflag = " << options.c_cflag << std::endl;
std::cout << "options.c_iflag = " << options.c_iflag << std::endl;
std::cout << "options.c_oflag = " << options.c_oflag << std::endl;
std::cout << "options.c_lflag = " << options.c_lflag << std::endl;
tcsetattr(uart0_filestream, TCSANOW, &options);
// Let's verify configured options
tcgetattr(uart0_filestream, &options);
tcsetattr(uart0_filestream, TCSANOW, &options);
// Let's verify configured options
tcgetattr(uart0_filestream, &options);
std::cout << "options.c_cflag = " << options.c_cflag << std::endl;
std::cout << "options.c_iflag = " << options.c_iflag << std::endl;
std::cout << "options.c_oflag = " << options.c_oflag << std::endl;
std::cout << "options.c_lflag = " << options.c_lflag << std::endl;
std::cout << "options.c_cflag = " << options.c_cflag << std::endl;
std::cout << "options.c_iflag = " << options.c_iflag << std::endl;
std::cout << "options.c_oflag = " << options.c_oflag << std::endl;
std::cout << "options.c_lflag = " << options.c_lflag << std::endl;
}
{
struct serial_struct ser;
// {
// struct serial_struct ser;
if (-1 == ioctl(uart0_filestream, TIOCGSERIAL, &ser))
{
std::cerr << "Failed to obtian 'serial_struct' for setting custom baudrate" << std::endl;
}
// if (-1 == ioctl(uart0_filestream, TIOCGSERIAL, &ser))
// {
// std::cerr << "Failed to obtian 'serial_struct' for setting custom baudrate" << std::endl;
// }
std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 4000000" << std::endl;
// std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 4000000" << std::endl;
// set custom divisor
ser.custom_divisor = ser.baud_base / 8000000;
// update flags
ser.flags &= ~ASYNC_SPD_MASK;
ser.flags |= ASYNC_SPD_CUST;
// // set custom divisor
// ser.custom_divisor = ser.baud_base / 8000000;
// // update flags
// ser.flags &= ~ASYNC_SPD_MASK;
// ser.flags |= ASYNC_SPD_CUST;
// std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 8000000" << std::endl;
std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 8000000" << std::endl;
// if (-1 == ioctl(uart0_filestream, TIOCSSERIAL, &ser))
// {
// std::cerr << "Failed to configure 'serial_struct' for setting custom baudrate" << std::endl;
// }
// }
if (-1 == ioctl(uart0_filestream, TIOCSSERIAL, &ser))
{
std::cerr << "Failed to configure 'serial_struct' for setting custom baudrate" << std::endl;
}
// Check result
if (-1 == ioctl(uart0_filestream, TIOCGSERIAL, &ser))
{
std::cerr << "Failed to obtian 'serial_struct' for setting custom baudrate" << std::endl;
}
std::cout << "Current divisor: " << ser.custom_divisor << " ( = " << ser.baud_base << " / 4000000" << std::endl;
}
if (uart0_filestream < 0)
@ -141,8 +131,6 @@ int main()
uint8_t tx_buffer[3*3*8*4];
uint8_t *p_tx_buffer;
p_tx_buffer = &tx_buffer[0];
// for (int i=0; i<3; ++i)
// {
// Writing 0xFF, 0x00, 0x00
@ -151,51 +139,28 @@ int main()
// *p_tx_buffer++ = 0x8C;
// *p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1,2);
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
// }
p_tx_buffer = &tx_buffer[0];
for (int i=0; i<9; ++i)
{
int coinFlip = distribution(generator);
if (coinFlip == 1)
{
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
}
else
{
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
}
}
std::cout << "Binary stream: [";
for (unsigned char* txIt=&(tx_buffer[0]); txIt!=p_tx_buffer; ++txIt)
@ -227,6 +192,26 @@ int main()
return -1;
}
std::cout << "Writing " << count << " bytes to uart" << std::endl;
p_tx_buffer = &tx_buffer[0];
for (int i=0; i<9; ++i)
{
int coinFlip = distribution(generator);
if (coinFlip == 1)
{
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
*p_tx_buffer++ = 0xCE;
}
else
{
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
*p_tx_buffer++ = 0x8C;
}
}
}
//----- CLOSE THE UART -----