mirror of
https://github.com/hyperion-project/hyperion.ng.git
synced 2023-10-10 13:36:59 +02:00
Modified the ws2812b to use a 3bit encoding speed which allows operation of the uart at slower speed.
Former-commit-id: fb89050546f85f82fb1fcc4cc2d24f95d8f78de5
This commit is contained in:
parent
acbff8b7ce
commit
9be0aa9715
@ -6,109 +6,91 @@
|
|||||||
#include "LedDeviceWs2812b.h"
|
#include "LedDeviceWs2812b.h"
|
||||||
|
|
||||||
LedDeviceWs2812b::LedDeviceWs2812b() :
|
LedDeviceWs2812b::LedDeviceWs2812b() :
|
||||||
LedRs232Device("/dev/ttyAMA0", 4000000)
|
LedRs232Device("/dev/ttyAMA0", 2500000)
|
||||||
{
|
{
|
||||||
fillTable();
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
int LedDeviceWs2812b::write(const std::vector<ColorRgb> & ledValues)
|
int LedDeviceWs2812b::write(const std::vector<ColorRgb> & ledValues)
|
||||||
{
|
{
|
||||||
// Ensure the size of the led-buffer
|
// Ensure the size of the led-buffer
|
||||||
if (_ledBuffer.size() != ledValues.size()*3)
|
if (_ledBuffer.size() != ledValues.size()*8)
|
||||||
{
|
{
|
||||||
_ledBuffer.resize(ledValues.size()*3);
|
_ledBuffer.resize(ledValues.size()*8, ~0x24);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate the channel of each color to a signal
|
// Translate the channel of each color to a signal
|
||||||
for (unsigned iLed=0; iLed<ledValues.size(); ++iLed)
|
uint8_t * signal_ptr = _ledBuffer.data();
|
||||||
|
for (const ColorRgb & color : ledValues)
|
||||||
{
|
{
|
||||||
const ColorRgb & color = ledValues[iLed];
|
signal_ptr = color2signal(color, signal_ptr);
|
||||||
|
|
||||||
_ledBuffer[3*iLed] = _byte2signalTable[color.red];
|
|
||||||
_ledBuffer[3*iLed + 1] = _byte2signalTable[color.green];
|
|
||||||
_ledBuffer[3*iLed + 2] = _byte2signalTable[color.blue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int result = writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
|
const int result = writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||||
// Official latch time is 50us (lets give it 50us more)
|
// Official latch time is 50us (lets give it 50us more)
|
||||||
usleep(100);
|
usleep(100);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t * LedDeviceWs2812b::color2signal(const ColorRgb & color, uint8_t * signal)
|
||||||
|
{
|
||||||
|
*signal = bits2Signal(color.red & 0x80, color.red & 0x40, color.red & 0x20);
|
||||||
|
++signal;
|
||||||
|
*signal = bits2Signal(color.red & 0x10, color.red & 0x08, color.red & 0x04);
|
||||||
|
++signal;
|
||||||
|
*signal = bits2Signal(color.red & 0x02, color.green & 0x01, color.green & 0x80);
|
||||||
|
++signal;
|
||||||
|
*signal = bits2Signal(color.green & 0x40, color.green & 0x20, color.green & 0x10);
|
||||||
|
++signal;
|
||||||
|
*signal = bits2Signal(color.green & 0x08, color.green & 0x04, color.green & 0x02);
|
||||||
|
++signal;
|
||||||
|
*signal = bits2Signal(color.green & 0x01, color.blue & 0x80, color.blue & 0x40);
|
||||||
|
++signal;
|
||||||
|
*signal = bits2Signal(color.blue & 0x20, color.blue & 0x10, color.blue & 0x08);
|
||||||
|
++signal;
|
||||||
|
*signal = bits2Signal(color.blue & 0x04, color.blue & 0x02, color.blue & 0x01);
|
||||||
|
++signal;
|
||||||
|
|
||||||
|
return signal;
|
||||||
|
}
|
||||||
|
|
||||||
int LedDeviceWs2812b::switchOff()
|
int LedDeviceWs2812b::switchOff()
|
||||||
{
|
{
|
||||||
// Set all bytes in the signal buffer to zero
|
// Set all bytes in the signal buffer to zero
|
||||||
for (ByteSignal & signal : _ledBuffer)
|
for (uint8_t & signal : _ledBuffer)
|
||||||
{
|
{
|
||||||
signal = _byte2signalTable[0];
|
signal = ~0x24;
|
||||||
}
|
}
|
||||||
|
|
||||||
return writeBytes(_ledBuffer.size()*sizeof(ByteSignal), reinterpret_cast<uint8_t *>(_ledBuffer.data()));
|
return writeBytes(_ledBuffer.size(), _ledBuffer.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LedDeviceWs2812b::fillTable()
|
uint8_t LedDeviceWs2812b::bits2Signal(const bool bit_1, const bool bit_2, const bool bit_3) const
|
||||||
{
|
|
||||||
_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
|
|
||||||
{
|
{
|
||||||
// See https://github.com/tvdzwan/hyperion/wiki/Ws2812b for the explanation of the given
|
// See https://github.com/tvdzwan/hyperion/wiki/Ws2812b for the explanation of the given
|
||||||
// translations
|
// translations
|
||||||
|
|
||||||
// Encoding scheme 1
|
// Bit index(default):1 2 3
|
||||||
// 00 1 1000 1100 0 1 0111 0011 0 1 1100 1110 0 0xCE
|
// | | |
|
||||||
// 01 1 1000 1110 0 1 0111 0001 0 1 1000 1110 0 0x8E
|
// default value (1) 00 100 10 (0)
|
||||||
// 10 1 1100 1100 0 1 0011 0011 0 1 1100 1100 0 0xCC
|
//
|
||||||
// 11 1 1100 1110 0 1 0011 0001 0 1 1000 1100 0 0x8C
|
// Reversed value (1) 01 001 00 (0)
|
||||||
|
// | | |
|
||||||
|
// Bit index (rev): 3 2 1
|
||||||
|
uint8_t result = 0x24;
|
||||||
|
|
||||||
// Encoding schem 2
|
if(bit_1)
|
||||||
// 00 - 1 0000 1000 0 - 1 1111 0111 0 - 1 1110 1111 0 - 0xEF
|
|
||||||
// 01 - 1 0000 1111 0 - 1 1111 0000 0 - 1 0000 1111 0 - 0x0F
|
|
||||||
// 10 - 1 1110 1000 0 - 1 0001 0111 0 - 1 1110 1000 0 - 0xE8
|
|
||||||
// 11 - 1 1110 1111 0 - 1 0001 0000 0 - 1 0000 1000 0 - 0x08
|
|
||||||
|
|
||||||
if (bit1)
|
|
||||||
{
|
{
|
||||||
if (bit2)
|
result |= 0x01;
|
||||||
{
|
|
||||||
// return 0x08;
|
|
||||||
return 0x8C;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// return 0xE8;
|
|
||||||
return 0xCC;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
if (bit_2)
|
||||||
{
|
{
|
||||||
if (bit2)
|
result |= 0x08;
|
||||||
{
|
}
|
||||||
// return 0x0F;
|
if (bit_3)
|
||||||
return 0x8E;
|
{
|
||||||
}
|
result |= 0x40;
|
||||||
else
|
|
||||||
{
|
|
||||||
// return 0xEF;
|
|
||||||
return 0xCE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0x00;
|
return ~result;
|
||||||
}
|
}
|
||||||
|
@ -34,43 +34,27 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Structure holding the four output-bytes corresponding to a single input byte
|
/// Translate a color to the signal bits. The resulting bits are written to the given memory.
|
||||||
///
|
///
|
||||||
struct ByteSignal
|
/// @param color The color to translate
|
||||||
{
|
/// @param signal The pointer at the beginning of the signal to write
|
||||||
uint8_t bit_12;
|
/// @return The pointer at the end of the written signal
|
||||||
uint8_t bit_34;
|
///
|
||||||
uint8_t bit_56;
|
uint8_t * color2signal(const ColorRgb & color, uint8_t * signal);
|
||||||
uint8_t bit_78;
|
|
||||||
};
|
|
||||||
/// Translation table from single input-byte to output-bytes
|
|
||||||
std::vector<ByteSignal> _byte2signalTable;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Fills the translation table (_byte2signalTable)
|
/// Translates three bits to a single byte
|
||||||
///
|
|
||||||
void fillTable();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Computes the output bytes that belong to a given input-byte (no table lookup)
|
|
||||||
///
|
|
||||||
/// @param byte The input byte
|
|
||||||
/// @return The four bytes (ByteSignal) for the output signal
|
|
||||||
///
|
|
||||||
ByteSignal byte2Signal(const uint8_t byte) const;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Translates two bits to a single byte
|
|
||||||
///
|
///
|
||||||
/// @param bit1 The value of the first bit (1=true, zero=false)
|
/// @param bit1 The value of the first bit (1=true, zero=false)
|
||||||
/// @param bit1 The value of the ssecond bit (1=true, zero=false)
|
/// @param bit2 The value of the second bit (1=true, zero=false)
|
||||||
|
/// @param bit3 The value of the third bit (1=true, zero=false)
|
||||||
///
|
///
|
||||||
/// @return The output-byte for the given two bit
|
/// @return The output-byte for the given two bit
|
||||||
///
|
///
|
||||||
uint8_t bits2Signal(const bool bit1, const bool bit2) const;
|
uint8_t bits2Signal(const bool bit1, const bool bit2, const bool bit3) const;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The output buffer for writing bytes to the output
|
/// The output buffer for writing bytes to the output
|
||||||
///
|
///
|
||||||
std::vector<ByteSignal> _ledBuffer;
|
std::vector<uint8_t> _ledBuffer;
|
||||||
};
|
};
|
||||||
|
@ -95,8 +95,16 @@ void signal_handler(int signum)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test3bitsEncoding();
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
if (true)
|
||||||
|
{
|
||||||
|
test3bitsEncoding();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
_running = true;
|
_running = true;
|
||||||
signal(SIGTERM, &signal_handler);
|
signal(SIGTERM, &signal_handler);
|
||||||
|
|
||||||
@ -246,3 +254,128 @@ int main()
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> bit3Encode(const std::vector<uint8_t> & bytes);
|
||||||
|
uint8_t bit3Encode(const bool bit_1, const bool bit_2, const bool bit_3);
|
||||||
|
|
||||||
|
void test3bitsEncoding()
|
||||||
|
{
|
||||||
|
//OPEN THE UART
|
||||||
|
int uart0_filestream = open("/dev/ttyAMA0", O_WRONLY | O_NOCTTY | O_NDELAY);
|
||||||
|
if (uart0_filestream == -1)
|
||||||
|
{
|
||||||
|
//ERROR - CAN'T OPEN SERIAL PORT
|
||||||
|
printf("Error - Unable to open UART. Ensure it is not in use by another application\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the port
|
||||||
|
struct termios options;
|
||||||
|
tcgetattr(uart0_filestream, &options);
|
||||||
|
options.c_cflag = B2500000 | CS7 | CLOCAL;
|
||||||
|
options.c_iflag = IGNPAR;
|
||||||
|
options.c_oflag = 0;
|
||||||
|
options.c_lflag = 0;
|
||||||
|
|
||||||
|
tcflush(uart0_filestream, TCIFLUSH);
|
||||||
|
tcsetattr(uart0_filestream, TCSANOW, &options);
|
||||||
|
|
||||||
|
std::vector<uint8_t> colorRed;
|
||||||
|
for (unsigned i=0; i<10; ++i)
|
||||||
|
{
|
||||||
|
colorRed.push_back(0x00);
|
||||||
|
colorRed.push_back(0xFF);
|
||||||
|
colorRed.push_back(0x00);
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> colorGreen;
|
||||||
|
for (unsigned i=0; i<10; ++i)
|
||||||
|
{
|
||||||
|
colorGreen.push_back(0xFF);
|
||||||
|
colorGreen.push_back(0x00);
|
||||||
|
colorGreen.push_back(0x00);
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> colorBlue;
|
||||||
|
for (unsigned i=0; i<10; ++i)
|
||||||
|
{
|
||||||
|
colorBlue.push_back(0x00);
|
||||||
|
colorBlue.push_back(0x00);
|
||||||
|
colorBlue.push_back(0xFF);
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> colorBlack;
|
||||||
|
for (unsigned i=0; i<10; ++i)
|
||||||
|
{
|
||||||
|
colorBlack.push_back(0x00);
|
||||||
|
colorBlack.push_back(0x00);
|
||||||
|
colorBlack.push_back(0x00);
|
||||||
|
}
|
||||||
|
const std::vector<uint8_t> colorRedSignal = bit3Encode(colorRed);
|
||||||
|
const std::vector<uint8_t> colorGreenSignal = bit3Encode(colorGreen);
|
||||||
|
const std::vector<uint8_t> colorBlueSignal = bit3Encode(colorBlue);
|
||||||
|
const std::vector<uint8_t> colorBlackSignal = bit3Encode(colorBlack);
|
||||||
|
|
||||||
|
for (unsigned i=0; i<100; ++i)
|
||||||
|
{
|
||||||
|
write(uart0_filestream, colorRedSignal.data(), colorRedSignal.size());
|
||||||
|
usleep(100000);
|
||||||
|
write(uart0_filestream, colorGreenSignal.data(), colorGreenSignal.size());
|
||||||
|
usleep(100000);
|
||||||
|
write(uart0_filestream, colorBlueSignal.data(), colorBlueSignal.size());
|
||||||
|
usleep(100000);
|
||||||
|
}
|
||||||
|
write(uart0_filestream, colorBlackSignal.data(), colorBlackSignal.size());
|
||||||
|
|
||||||
|
//----- CLOSE THE UART -----
|
||||||
|
close(uart0_filestream);
|
||||||
|
|
||||||
|
std::cout << "Program finished" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> bit3Encode(const std::vector<uint8_t> & bytes)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> result;
|
||||||
|
|
||||||
|
for (unsigned iByte=0; iByte<bytes.size(); iByte+=3)
|
||||||
|
{
|
||||||
|
const uint8_t & byte1 = bytes[iByte];
|
||||||
|
const uint8_t & byte2 = bytes[iByte + 1];
|
||||||
|
const uint8_t & byte3 = bytes[iByte + 2];
|
||||||
|
|
||||||
|
result.push_back(bit3Encode(byte1 & 0x80, byte1 & 0x40, byte1 & 0x20));
|
||||||
|
result.push_back(bit3Encode(byte1 & 0x10, byte1 & 0x08, byte1 & 0x04));
|
||||||
|
result.push_back(bit3Encode(byte1 & 0x02, byte1 & 0x01, byte2 & 0x80));
|
||||||
|
result.push_back(bit3Encode(byte2 & 0x40, byte2 & 0x20, byte2 & 0x10));
|
||||||
|
result.push_back(bit3Encode(byte2 & 0x08, byte2 & 0x04, byte2 & 0x02));
|
||||||
|
result.push_back(bit3Encode(byte2 & 0x01, byte3 & 0x80, byte3 & 0x40));
|
||||||
|
result.push_back(bit3Encode(byte3 & 0x20, byte3 & 0x10, byte3 & 0x08));
|
||||||
|
result.push_back(bit3Encode(byte3 & 0x04, byte3 & 0x02, byte3 & 0x01));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bit3Encode(const bool bit_1, const bool bit_2, const bool bit_3)
|
||||||
|
{
|
||||||
|
// Bit index(default):1 2 3
|
||||||
|
// | | |
|
||||||
|
// default value (1) 00 100 10 (0)
|
||||||
|
//
|
||||||
|
// Reversed value (1) 01 001 00 (0)
|
||||||
|
// | | |
|
||||||
|
// Bit index (rev): 3 2 1
|
||||||
|
uint8_t result = 0x24;
|
||||||
|
|
||||||
|
if(bit_1)
|
||||||
|
{
|
||||||
|
result |= 0x01;
|
||||||
|
}
|
||||||
|
if (bit_2)
|
||||||
|
{
|
||||||
|
result |= 0x08;
|
||||||
|
}
|
||||||
|
if (bit_3)
|
||||||
|
{
|
||||||
|
result |= 0x40;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ~result;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user