From 15fd537fa81170ee028b4365afa7d76d7d1385c7 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Sat, 26 Oct 2019 21:34:25 -0500 Subject: [PATCH] Add support for RGB E1.31 Streaming ACN multicast devices using libe131. Linux only for now. --- .gitmodules | 3 + OpenAuraSDK.cpp | 4 +- OpenAuraSDK.pro | 5 + RGBController/E131ControllerDetect.cpp | 170 ++++++++++++++++++++++ RGBController/RGBController_E131.cpp | 193 +++++++++++++++++++++++++ RGBController/RGBController_E131.h | 54 +++++++ dependencies/libe131 | 1 + 7 files changed, 429 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 100644 RGBController/E131ControllerDetect.cpp create mode 100644 RGBController/RGBController_E131.cpp create mode 100644 RGBController/RGBController_E131.h create mode 160000 dependencies/libe131 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..9d63ed0ff --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "dependencies/libe131"] + path = dependencies/libe131 + url = https://github.com/hhromic/libe131 diff --git a/OpenAuraSDK.cpp b/OpenAuraSDK.cpp index f70007937..97452e4bc 100644 --- a/OpenAuraSDK.cpp +++ b/OpenAuraSDK.cpp @@ -439,6 +439,7 @@ void DetectHyperXControllers(std::vector &busses, std::vec void DetectLEDStripControllers(std::vector &rgb_controllers); void DetectOpenRazerControllers(std::vector &rgb_controllers); void DetectRazerChromaSDKControllers(std::vector& rgb_controllers); +void DetectE131Controllers(std::vector &rgb_controllers); /******************************************************************************************\ * * @@ -458,10 +459,11 @@ void DetectRGBControllers(void) DetectHyperXControllers(busses, rgb_controllers); DetectLEDStripControllers(rgb_controllers); - + #ifdef WIN32 DetectRazerChromaSDKControllers(rgb_controllers); #else + DetectE131Controllers(rgb_controllers); DetectOpenRazerControllers(rgb_controllers); #endif diff --git a/OpenAuraSDK.pro b/OpenAuraSDK.pro index 1cc653130..05d35a995 100644 --- a/OpenAuraSDK.pro +++ b/OpenAuraSDK.pro @@ -6,6 +6,7 @@ TARGET = OpenAuraSDK.bin TEMPLATE = app INCLUDEPATH += \ + dependencies/libe131/src/ \ i2c_smbus/ \ net_port/ \ serial_port/ \ @@ -19,6 +20,7 @@ INCLUDEPATH += \ qt/ SOURCES += \ + dependencies/libe131/src/e131.c \ main.cpp \ OpenAuraSDK.cpp \ qt/OpenAuraSDKQtDialog.cpp \ @@ -39,9 +41,11 @@ SOURCES += \ Controllers/LEDStripController/LEDStripController.cpp \ Controllers/LEDStripController/LEDStripControllerDetect.cpp \ RGBController/OpenRazerDetect.cpp \ + RGBController/E131ControllerDetect.cpp \ RGBController/RGBController_Aura.cpp \ RGBController/RGBController_Corsair.cpp \ RGBController/RGBController_CorsairPro.cpp \ + RGBController/RGBController_E131.cpp \ RGBController/RGBController_HuePlus.cpp \ RGBController/RGBController_HyperX.cpp \ RGBController/RGBController_LEDStrip.cpp \ @@ -63,6 +67,7 @@ HEADERS += \ RGBController/RGBController_Aura.h \ RGBController/RGBController_Corsair.h \ RGBController/RGBController_CorsairPro.h \ + RGBController/RGBController_E131.h \ RGBController/RGBController_HuePlus.h \ RGBController/RGBController_HyperX.h \ RGBController/RGBController_OpenRazer.h diff --git a/RGBController/E131ControllerDetect.cpp b/RGBController/E131ControllerDetect.cpp new file mode 100644 index 000000000..266394136 --- /dev/null +++ b/RGBController/E131ControllerDetect.cpp @@ -0,0 +1,170 @@ +#include "RGBController.h" +#include "RGBController_E131.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#endif + +#ifndef WIN32 +#define LPSTR char * +#define strtok_s strtok_r +#endif + +/******************************************************************************************\ +* * +* DetectE131Controllers * +* * +* Detect devices supported by the E131 driver * +* * * +\******************************************************************************************/ + +void DetectE131Controllers(std::vector &rgb_controllers) +{ + RGBController_E131* new_controller; + + //Get file path in executable directory + std::ifstream infile; + char filename[2048]; + char arg1[64]; + +#ifdef WIN32 + GetModuleFileName(NULL, filename, 2048); + strcpy(filename, std::string(filename).substr(0, std::string(filename).find_last_of("\\/")).c_str()); + strcat(filename, "\\e131.txt"); +#else + snprintf(arg1, 64, "/proc/%d/exe", getpid()); + readlink(arg1, filename, 1024); + strcpy(filename, std::string(filename).substr(0, std::string(filename).find_last_of("\\/")).c_str()); + strcat(filename, "/e131.txt"); +#endif + + E131Device dev; + std::vector devices; + + bool new_device = false; + + //Open settings file + infile.open(filename); + + if (infile.good()) + { + for (std::string line; std::getline(infile, line); ) + { + if (new_device) + { + dev.name = line; + new_device = false; + } + + if (line == "") + { + continue; + } + + if ((line[0] != ';') && (line[0] != '#') && (line[0] != '/')) + { + char * argument; + char * value; + + value = (char *)line.c_str(); + + argument = strtok_s(value, "=", &value); + + //Strip off new line characters if present + argument = strtok(argument, "\r\n"); + value = strtok(value, "\r\n"); + + if(argument) + { + if (strcmp(argument, "e131_device_start") == 0) + { + new_device = true; + } + else if(strcmp(argument, "num_leds") == 0) + { + dev.num_leds = atoi(value); + } + else if(strcmp(argument, "start_universe") == 0) + { + dev.start_universe = atoi(value); + } + else if(strcmp(argument, "start_channel") == 0) + { + dev.start_channel = atoi(value); + } + else if(strcmp(argument, "rgb_order") == 0) + { + if(strcmp(value, "RGB") == 0) + { + dev.rgb_order = E131_RGB_ORDER_RGB; + } + else if(strcmp(value, "RBG") == 0) + { + dev.rgb_order = E131_RGB_ORDER_RBG; + } + else if(strcmp(value, "GRB") == 0) + { + dev.rgb_order = E131_RGB_ORDER_GRB; + } + else if(strcmp(value, "GBR") == 0) + { + dev.rgb_order = E131_RGB_ORDER_GBR; + } + else if(strcmp(value, "BRG") == 0) + { + dev.rgb_order = E131_RGB_ORDER_BRG; + } + else if(strcmp(value, "BGR") == 0) + { + dev.rgb_order = E131_RGB_ORDER_BGR; + } + else + { + dev.rgb_order = atoi(value); + } + } + else if(strcmp(argument, "type") == 0) + { + if(strcmp(value, "SINGLE") == 0) + { + dev.type = ZONE_TYPE_SINGLE; + } + else if(strcmp(value, "LINEAR") == 0) + { + dev.type = ZONE_TYPE_LINEAR; + } + else if(strcmp(value, "MATRIX") == 0) + { + dev.type = ZONE_TYPE_MATRIX; + } + else + { + dev.type = atoi(value); + } + } + else if(strcmp(argument, "e131_device_end") == 0) + { + devices.push_back(dev); + } + } + } + } + + if(devices.size() > 0) + { + new_controller = new RGBController_E131(devices); + rgb_controllers.push_back(new_controller); + } + } + +} /* DetectLEDStripControllers() */ \ No newline at end of file diff --git a/RGBController/RGBController_E131.cpp b/RGBController/RGBController_E131.cpp new file mode 100644 index 000000000..508a1e66f --- /dev/null +++ b/RGBController/RGBController_E131.cpp @@ -0,0 +1,193 @@ +/*-----------------------------------------*\ +| RGBController_LEDStrip.cpp | +| | +| Generic RGB Interface for OpenAuraSDK | +| E1.31 Streaming ACN interface | +| | +| Adam Honse (CalcProgrammer1) 10/18/2019 | +\*-----------------------------------------*/ + +#include "RGBController_E131.h" +#include +#include + +RGBController_E131::RGBController_E131(std::vector device_list) +{ + name = "E1.31 Streaming ACN Device"; + + devices = device_list; + + unsigned int led_zone_idx = 0; + mode led_mode; + led_mode.name = "Custom"; + modes.push_back(led_mode); + + sockfd = e131_socket(); + + for (int i = 0; i < devices.size(); i++) + { + /*-----------------------------------------*\ + | Add LEDs | + \*-----------------------------------------*/ + for (int led_idx = 0; led_idx < devices[i].num_leds; led_idx++) + { + colors.push_back(0x00000000); + led new_led; + new_led.name = devices[i].name + " LED"; + leds.push_back(new_led); + } + + /*-----------------------------------------*\ + | Add Zones | + \*-----------------------------------------*/ + zone led_zone; + led_zone.name = devices[i].name; + led_zone.type = devices[i].type; + std::vector led_zone_map; + for (int led_idx = 0; led_idx < devices[i].num_leds; led_idx++) + { + led_zone_map.push_back(led_zone_idx); + led_zone_idx++; + } + led_zone.map.push_back(led_zone_map); + zones.push_back(led_zone); + + /*-----------------------------------------*\ + | Add Universes | + \*-----------------------------------------*/ + unsigned int total_universes = ceil( ( ( devices[i].num_leds * 3 ) + devices[i].start_channel ) / 512.0f ); + + for (int univ_idx = 0; univ_idx < total_universes; univ_idx++) + { + unsigned int universe = devices[i].start_universe + univ_idx; + bool universe_exists = false; + + for (int pkt_idx = 0; pkt_idx < packets.size(); pkt_idx++) + { + if(universes[pkt_idx] == universe) + { + universe_exists = true; + } + } + + if(!universe_exists) + { + e131_packet_t packet; + e131_addr_t dest_addr; + + e131_pkt_init(&packet, universe, 512); + e131_multicast_dest(&dest_addr, universe, E131_DEFAULT_PORT); + + packets.push_back(packet); + universes.push_back(universe); + dest_addrs.push_back(dest_addr); + } + } + } +} + +int RGBController_E131::GetMode() +{ + return 0; +} + +void RGBController_E131::SetMode(int mode) +{ + +} + +void RGBController_E131::SetCustomMode() +{ + +} + +void RGBController_E131::SetAllLEDs(RGBColor color) +{ + for (int i = 0; i < colors.size(); i++) + { + colors[i] = color; + } + + UpdateLEDs(); +} + +void RGBController_E131::SetAllZoneLEDs(int zone, RGBColor color) +{ + for (int x = 0; x < zones[zone].map.size(); x++) + { + for (int y = 0; y < zones[zone].map[x].size(); y++) + { + colors[zones[zone].map[x][y]] = color; + } + } + + UpdateLEDs(); +} + +void RGBController_E131::SetLED(int led, RGBColor color) +{ + colors[led] = color; + + UpdateLEDs(); +} + +void RGBController_E131::UpdateLEDs() +{ + int color_idx = 0; + + for(int device_idx = 0; device_idx < devices.size(); device_idx++) + { + unsigned int total_universes = ceil( ( ( devices[device_idx].num_leds * 3 ) + devices[device_idx].start_channel ) / 512.0f ); + unsigned int channel_idx = devices[device_idx].start_channel; + unsigned int led_idx = 0; + unsigned int rgb_idx = 0; + bool done = false; + + for (int univ_idx = 0; univ_idx < total_universes; univ_idx++) + { + unsigned int universe = devices[device_idx].start_universe + univ_idx; + + for(int packet_idx = 0; packet_idx < packets.size(); packet_idx++) + { + if(!done && (universes[packet_idx] == universe)) + { + while(!done && (channel_idx <= 512)) + { + switch(rgb_idx) + { + case 0: + packets[packet_idx].dmp.prop_val[channel_idx] = RGBGetRValue( colors[color_idx] ); + rgb_idx = 1; + break; + case 1: + packets[packet_idx].dmp.prop_val[channel_idx] = RGBGetGValue( colors[color_idx] ); + rgb_idx = 2; + break; + case 2: + packets[packet_idx].dmp.prop_val[channel_idx] = RGBGetBValue( colors[color_idx] ); + rgb_idx = 0; + led_idx++; + color_idx++; + break; + } + + if(led_idx >= devices[device_idx].num_leds) + { + done = true; + } + + channel_idx++; + } + } + } + + channel_idx = 1; + } + } + + for(int packet_idx = 0; packet_idx < packets.size(); packet_idx++) + { + e131_send(sockfd, &packets[packet_idx], &dest_addrs[packet_idx]); + packets[packet_idx].frame.seq_number++; + } +} \ No newline at end of file diff --git a/RGBController/RGBController_E131.h b/RGBController/RGBController_E131.h new file mode 100644 index 000000000..fac3d3256 --- /dev/null +++ b/RGBController/RGBController_E131.h @@ -0,0 +1,54 @@ +/*-----------------------------------------*\ +| RGBController_E131.h | +| | +| Generic RGB Interface for OpenAuraSDK | +| E1.31 Streaming ACN interface | +| | +| Adam Honse (CalcProgrammer1) 10/18/2019 | +\*-----------------------------------------*/ + +#pragma once +#include "RGBController.h" +#include + +typedef unsigned int e131_rgb_order; + +enum + { + E131_RGB_ORDER_RGB, + E131_RGB_ORDER_RBG, + E131_RGB_ORDER_GRB, + E131_RGB_ORDER_GBR, + E131_RGB_ORDER_BRG, + E131_RGB_ORDER_BGR + }; + +struct E131Device +{ + std::string name; + unsigned int num_leds; + unsigned int start_universe; + unsigned int start_channel; + e131_rgb_order rgb_order; + zone_type type; +}; + +class RGBController_E131 : public RGBController +{ +public: + RGBController_E131(std::vector device_list); + int GetMode(); + void SetMode(int mode); + void SetCustomMode(); + void SetAllLEDs(RGBColor color); + void SetAllZoneLEDs(int zone, RGBColor color); + void SetLED(int led, RGBColor color); + void UpdateLEDs(); + +private: + std::vector devices; + std::vector packets; + std::vector dest_addrs; + std::vector universes; + int sockfd; +}; \ No newline at end of file diff --git a/dependencies/libe131 b/dependencies/libe131 new file mode 160000 index 000000000..0fc009f1f --- /dev/null +++ b/dependencies/libe131 @@ -0,0 +1 @@ +Subproject commit 0fc009f1f6c7eb93c465ccc8d79d5490f5186835