Merge branch 'master' into macos_compile

Conflicts:
	libsrc/leddevice/CMakeLists.txt
	libsrc/leddevice/LedDeviceFactory.cpp
	test/TestRs232HighSpeed.cpp

Former-commit-id: 5583f2f881afd1a9b0c8ec3a52d7d3b54fe1dff7
This commit is contained in:
T. van der Zwan
2013-12-28 08:55:06 +01:00
27 changed files with 1428 additions and 187 deletions

View File

@@ -53,8 +53,16 @@ add_executable(test_qtscreenshot TestQtScreenshot.cpp)
target_link_libraries(test_qtscreenshot
${QT_LIBRARIES})
add_executable(determineWs2811Timing DetermineWs2811Timing.cpp)
add_executable(test_rs232highspeed
TestRs232HighSpeed.cpp
../libsrc/leddevice/LedRs232Device.cpp)
../libsrc/leddevice/LedRs232Device.cpp
../libsrc/leddevice/LedDeviceWs2812b.cpp)
target_link_libraries(test_rs232highspeed
serialport)
if(NOT APPLE AND UNIX)
include_directories(/usr/include)
add_executable(test_uartHighSpeed TestUartHighSpeed.cpp)
endif()

View File

@@ -0,0 +1,62 @@
// STl includes
#include <iostream>
#include <cmath>
bool requiredTiming(const int tHigh_ns, const int tLow_ns, const int error_ns, const int nrBits)
{
std::cout << "=== " << nrBits << " bits case ===== " << std::endl;
double bitLength_ns = (tHigh_ns + tLow_ns)/double(nrBits);
double baudrate_Hz = 1.0 / bitLength_ns * 1e9;
std::cout << "Required bit length: " << bitLength_ns << "ns => baudrate = " << baudrate_Hz << std::endl;
double highBitsExact = tHigh_ns/bitLength_ns;
int highBits = std::round(highBitsExact);
double lowBitsExact = tLow_ns/bitLength_ns;
int lowBits = std::round(lowBitsExact);
std::cout << "Bit division: high=" << highBits << "(" << highBitsExact << "); low=" << lowBits << "(" << lowBitsExact << ")" << std::endl;
double highBitsError = std::fabs(highBitsExact - highBits);
double lowBitsError = std::fabs(highBitsExact - highBits);
double highError_ns = highBitsError * bitLength_ns;
double lowError_ns = lowBitsError * bitLength_ns;
if (highError_ns > error_ns || lowError_ns > error_ns)
{
std::cerr << "Timing error outside specs: " << highError_ns << "; " << lowError_ns << " > " << error_ns << std::endl;
}
else
{
std::cout << "Timing within margins: " << highError_ns << "; " << lowError_ns << " < " << error_ns << std::endl;
}
return true;
}
int main()
{
// 10bits
requiredTiming(400, 850, 150, 10); // Zero
requiredTiming(800, 450, 150, 10); // One
// 6bits
requiredTiming(400, 850, 150, 6); // Zero
requiredTiming(800, 450, 150, 6); // One
// 5bits
requiredTiming(400, 850, 150, 5); // Zero
requiredTiming(800, 450, 150, 5); // One
requiredTiming(650, 600, 150, 5); // One
// 4bits
requiredTiming(400, 850, 150, 4); // Zero
requiredTiming(800, 450, 150, 4); // One
// 3bits
requiredTiming(400, 850, 150, 3); // Zero
requiredTiming(800, 450, 150, 3); // One
return 0;
}

View File

@@ -1,32 +1,260 @@
// 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.flushOutput();
rs232Port.write(data);
rs232Port.flush();
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;
}

248
test/TestUartHighSpeed.cpp Normal file
View File

@@ -0,0 +1,248 @@
#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 <linux/serial.h>
#include <csignal>
#include <cstdint>
#include <bitset>
#include <vector>
#include <pthread.h>
#include <sched.h>
void set_realtime_priority() {
int ret;
// We'll operate on the currently running thread.
pthread_t this_thread = pthread_self();
// struct sched_param is used to store the scheduling priority
struct sched_param params;
// We'll set the priority to the maximum.
params.sched_priority = sched_get_priority_max(SCHED_FIFO);
std::cout << "Trying to set thread realtime prio = " << params.sched_priority << std::endl;
// Attempt to set thread real-time priority to the SCHED_FIFO policy
ret = pthread_setschedparam(this_thread, SCHED_FIFO, &params);
if (ret != 0) {
// Print the error
std::cout << "Unsuccessful in setting thread realtime prio (erno=" << ret << ")" << std::endl;
return;
}
// Now verify the change in thread priority
int policy = 0;
ret = pthread_getschedparam(this_thread, &policy, &params);
if (ret != 0) {
std::cout << "Couldn't retrieve real-time scheduling paramers" << std::endl;
return;
}
// Check the correct policy was applied
if(policy != SCHED_FIFO) {
std::cout << "Scheduling is NOT SCHED_FIFO!" << std::endl;
} else {
std::cout << "SCHED_FIFO OK" << std::endl;
}
// Print thread scheduling priority
std::cout << "Thread priority is " << params.sched_priority << std::endl;
}
struct ColorSignal
{
uint8_t green_1;
uint8_t green_2;
uint8_t green_3;
uint8_t green_4;
uint8_t red_1;
uint8_t red_2;
uint8_t red_3;
uint8_t red_4;
uint8_t blue_1;
uint8_t blue_2;
uint8_t blue_3;
uint8_t blue_4;
};
static ColorSignal RED_Signal = { 0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0x8C, 0x8C, 0x8C,
0xCE, 0xCE, 0xCE, 0xCE };
static ColorSignal GREEN_Signal = { 0xCE, 0x8C, 0x8C, 0x8C,
0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE };
static ColorSignal BLUE_Signal = { 0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0x8C, 0x8C, 0x8C};
static ColorSignal BLACK_Signal = { 0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE,
0xCE, 0xCE, 0xCE, 0xCE};
static volatile bool _running;
void signal_handler(int signum)
{
_running = false;
}
int main()
{
_running = true;
signal(SIGTERM, &signal_handler);
//-------------------------
//----- SETUP USART 0 -----
//-------------------------
//At bootup, pins 8 and 10 are already set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively
int uart0_filestream = -1;
//OPEN THE UART
//The flags (defined in fcntl.h):
// Access modes (use 1 of these):
// O_RDONLY - Open for reading only.
// O_RDWR - Open for reading and writing.
// O_WRONLY - Open for writing only.
//
// O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status
// if there is no input immediately available (instead of blocking). Likewise, write requests can also return
// immediately with a failure status if the output can't be written immediately.
//
// O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process.
uart0_filestream = open("/dev/ttyAMA0", O_WRONLY | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode
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");
}
// 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; //<Set baud rate
options.c_iflag = IGNPAR;
options.c_oflag = 0;
options.c_lflag = 0;
cfmakeraw(&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;
tcflush(uart0_filestream, TCIFLUSH);
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;
}
{
struct serial_struct ser;
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;
// 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;
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)
{
std::cerr << "Opening the device has failed" << std::endl;
return -1;
}
//----- TX BYTES -----
std::vector<ColorSignal> signalData(10, RED_Signal);
int loopCnt = 0;
std::cout << "Type 'c' to continue, 'q' or 'x' to quit: ";
while (_running)
{
char c = getchar();
if (c == 'q' || c == 'x')
{
break;
}
if (c != 'c')
{
continue;
}
set_realtime_priority();
for (int iRun=0; iRun<10; ++iRun)
{
// tcflush(uart0_filestream, TCOFLUSH);
write(uart0_filestream, signalData.data(), signalData.size()*sizeof(ColorSignal));
tcdrain(uart0_filestream);
usleep(100000);
++loopCnt;
if (loopCnt%3 == 2)
signalData = std::vector<ColorSignal>(10, GREEN_Signal);
else if(loopCnt%3 == 1)
signalData = std::vector<ColorSignal>(10, BLUE_Signal);
else if(loopCnt%3 == 0)
signalData = std::vector<ColorSignal>(10, RED_Signal);
}
}
signalData = std::vector<ColorSignal>(50, BLACK_Signal);
write(uart0_filestream, signalData.data(), signalData.size()*sizeof(ColorSignal));
//----- CLOSE THE UART -----
close(uart0_filestream);
std::cout << "Program finished" << std::endl;
return 0;
}