Browse Source

Add support for BlinkyTape LED controllers

This adds support for the Blinkinlabs BlinkyTape controller, a
USB-powered digital LED strip controller. Devices are detected
automatically by scanning for their VID/PID, and connected to using
serial.

This code was tested in Windows.

Commit squashed and amended for code style and to fix Linux build by Adam Honse <calcprogrammer1@gmail.com>
merge-requests/654/head
Matt Mets 7 months ago
committed by Adam Honse
parent
commit
0db567b8bc
  1. 105
      Controllers/BlinkyTapeController/BlinkyTapeController.cpp
  2. 40
      Controllers/BlinkyTapeController/BlinkyTapeController.h
  3. 38
      Controllers/BlinkyTapeController/BlinkyTapeControllerDetect.cpp
  4. 137
      Controllers/BlinkyTapeController/RGBController_BlinkyTape.cpp
  5. 33
      Controllers/BlinkyTapeController/RGBController_BlinkyTape.h
  6. 5
      OpenRGB.pro
  7. 5
      serial_port/serial_port.h

105
Controllers/BlinkyTapeController/BlinkyTapeController.cpp

@ -0,0 +1,105 @@
/*---------------------------------------------------------*\
| BlinkyTapeController.cpp |
| |
| BlinkyTape controller interface |
| |
| Matt Mets (matt@blinkinlabs.com), 07/01/2021 |
\*---------------------------------------------------------*/
#include "BlinkyTapeController.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <string>
#ifndef WIN32
#define LPSTR char *
#define strtok_s strtok_r
#endif
BlinkyTapeController::BlinkyTapeController()
{
}
BlinkyTapeController::~BlinkyTapeController()
{
if(serialport != nullptr)
{
serialport->serial_close();
delete serialport;
}
}
void BlinkyTapeController::Initialize(const std::string &portname, int led_count)
{
num_leds = led_count;
port_name = portname;
serialport = new serial_port();
if(!serialport->serial_open(port_name.c_str(), 115200))
{
delete serialport;
serialport = nullptr;
}
}
std::string BlinkyTapeController::GetLocation()
{
if(serialport == nullptr)
{
return("");
}
return("COM: " + port_name);
}
char* BlinkyTapeController::GetLEDString()
{
return(led_string);
}
void BlinkyTapeController::SetLEDs(std::vector<RGBColor> colors)
{
if(serialport == nullptr)
{
return;
}
/*-------------------------------------------------------------*\
| BlinkyTape Protocol |
| |
| Packet size: Number of data bytes + 1 |
| |
| 0-n: Data Byte (0-254) |
| n+1: Packet End Byte (0xFF) |
\*-------------------------------------------------------------*/
const unsigned int payload_size = (colors.size() * 3);
const unsigned int packet_size = payload_size + 1;
std::vector<unsigned char> serial_buf(packet_size);
/*-------------------------------------------------------------*\
| Set up end byte |
\*-------------------------------------------------------------*/
serial_buf[packet_size - 1] = 0xFF;
/*-------------------------------------------------------------*\
| Copy in color data in RGB order |
\*-------------------------------------------------------------*/
for(unsigned int color_idx = 0; color_idx < colors.size(); color_idx++)
{
const unsigned int color_offset = color_idx * 3;
serial_buf[0x00 + color_offset] = std::min((unsigned int)254, RGBGetRValue(colors[color_idx]));
serial_buf[0x01 + color_offset] = std::min((unsigned int)254, RGBGetGValue(colors[color_idx]));
serial_buf[0x02 + color_offset] = std::min((unsigned int)254, RGBGetBValue(colors[color_idx]));
}
/*-------------------------------------------------------------*\
| Send the packet |
\*-------------------------------------------------------------*/
serialport->serial_write((char *)serial_buf.data(), packet_size);
}

40
Controllers/BlinkyTapeController/BlinkyTapeController.h

@ -0,0 +1,40 @@
/*---------------------------------------------------------*\
| Definitions for BlinkyTape Interface |
| |
| Matt Mets (matt@blinkinlabs.com), 07/01/2021 |
\*---------------------------------------------------------*/
#ifndef BLINKYTAPE_H
#define BLINKYTAPE_H
#include "RGBController.h"
#include "serial_port.h"
struct BlinkyTapeDevice
{
std::string port;
unsigned int num_leds;
};
class BlinkyTapeController
{
public:
BlinkyTapeController();
~BlinkyTapeController();
void Initialize(const std::string &portname, int led_count);
char* GetLEDString();
std::string GetLocation();
void SetLEDs(std::vector<RGBColor> colors);
int num_leds;
private:
char led_string[1024];
std::string port_name;
serial_port *serialport = nullptr;
};
#endif

38
Controllers/BlinkyTapeController/BlinkyTapeControllerDetect.cpp

@ -0,0 +1,38 @@
#include "Detector.h"
#include "BlinkyTapeController.h"
#include "RGBController.h"
#include "RGBController_BlinkyTape.h"
#include "SettingsManager.h"
#include "find_usb_serial_port.h"
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#define BLINKINLABS_VID 0x1D50
#define BLINKYTAPE_PID 0x605E
/******************************************************************************************\
* *
* DetectBlinkyTapeControllers *
* *
* Detect BlinkyTape devices *
* *
\******************************************************************************************/
void DetectBlinkyTapeControllers(std::vector<RGBController*> &rgb_controllers)
{
std::vector<std::string *> device_locations = find_usb_serial_port(BLINKINLABS_VID, BLINKYTAPE_PID);
for(unsigned int device_idx = 0; device_idx < device_locations.size(); device_idx++)
{
int led_count = 64;
BlinkyTapeController* controller = new BlinkyTapeController();
controller->Initialize(*device_locations[device_idx], led_count);
RGBController_BlinkyTape* rgb_controller = new RGBController_BlinkyTape(controller);
rgb_controllers.push_back(rgb_controller);
}
}
REGISTER_DETECTOR("BlinkyTape", DetectBlinkyTapeControllers);

137
Controllers/BlinkyTapeController/RGBController_BlinkyTape.cpp

@ -0,0 +1,137 @@
/*---------------------------------------------------------*\
| RGBController_BlinkyTape.cpp |
| |
| Generic RGB Interface for BlinkyTape Led controller |
| |
| Matt Mets (matt@blinkinlabs.com), 07/01/2021 |
\*---------------------------------------------------------*/
#include "RGBController_BlinkyTape.h"
RGBController_BlinkyTape::RGBController_BlinkyTape(BlinkyTapeController* controller_ptr)
{
controller = controller_ptr;
name = "BlinkyTape";
vendor = "Blinkinlabs";
type = DEVICE_TYPE_LEDSTRIP;
description = "BlinkyTape Controller Device";
location = controller->GetLocation();
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
SetupZones();
}
RGBController_BlinkyTape::~RGBController_BlinkyTape()
{
delete controller;
}
void RGBController_BlinkyTape::SetupZones()
{
zones.clear();
leds.clear();
zone led_zone;
led_zone.name = "LED Strip";
led_zone.type = ZONE_TYPE_LINEAR;
led_zone.leds_min = 1;
led_zone.leds_max = 512;
led_zone.leds_count = 0;
led_zone.matrix_map = NULL;
zones.push_back(led_zone);
ResizeZone(0, controller->num_leds);
}
void RGBController_BlinkyTape::ResizeZone(int zone, int new_size)
{
/*-------------------------------------------------*\
| Explicitly cast these to avoid compiler warnings |
\*-------------------------------------------------*/
const unsigned int zone_u = static_cast<unsigned int>(zone);
const unsigned int new_size_u = static_cast<unsigned int>(new_size);
/*-------------------------------------------------*\
| Check that the zone is in bounds |
\*-------------------------------------------------*/
if((zone_u > zones.size()) || (zone < 0))
{
return;
}
/*-------------------------------------------------*\
| And that the new size is in bounds |
\*-------------------------------------------------*/
if((new_size_u > zones.at(zone).leds_max) || (new_size_u < zones.at(zone).leds_min))
{
return;
}
/*-------------------------------------------------*\
| And that there's actually a change |
\*-------------------------------------------------*/
if(zones.at(zone).leds_count == new_size_u)
{
return;
}
/*-------------------------------------------------*\
| If the new size is less than the current size, |
| just chop off the end |
\*-------------------------------------------------*/
if(leds.size() > new_size_u)
{
leds.resize(new_size);
}
/*-------------------------------------------------*\
| Otherwise, add new LEDs to the end |
\*-------------------------------------------------*/
if(leds.size() < new_size_u)
{
for(size_t led_idx = leds.size(); led_idx < new_size_u; led_idx++)
{
led new_led;
new_led.name = "LED ";
new_led.name.append(std::to_string(led_idx));
leds.push_back(new_led);
}
}
zones.at(zone).leds_count = new_size;
SetupColors();
}
void RGBController_BlinkyTape::DeviceUpdateLEDs()
{
controller->SetLEDs(colors);
}
void RGBController_BlinkyTape::UpdateZoneLEDs(int /*zone*/)
{
controller->SetLEDs(colors);
}
void RGBController_BlinkyTape::UpdateSingleLED(int /*led*/)
{
controller->SetLEDs(colors);
}
void RGBController_BlinkyTape::SetCustomMode()
{
}
void RGBController_BlinkyTape::DeviceUpdateMode()
{
}

33
Controllers/BlinkyTapeController/RGBController_BlinkyTape.h

@ -0,0 +1,33 @@
/*---------------------------------------------------------*\
| RGBController_BlinkyTape.h |
| |
| Generic RGB Interface for BlinkyTape Led controller |
| |
| Matt Mets (matt@blinkinlabs.com), 07/01/2021 |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "serial_port.h"
#include "BlinkyTapeController.h"
class RGBController_BlinkyTape : public RGBController
{
public:
RGBController_BlinkyTape(BlinkyTapeController* controller_ptr);
~RGBController_BlinkyTape();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void SetCustomMode();
void DeviceUpdateMode();
private:
BlinkyTapeController* controller;
};

5
OpenRGB.pro

@ -206,6 +206,8 @@ HEADERS +=
Controllers/AsusAuraUSBController/RGBController_AsusAuraMouse.h \
Controllers/AsusAuraUSBController/RGBController_AsusAuraTUFKeyboard.h \
Controllers/AsusAuraUSBController/RGBController_AsusAuraUSB.h \
Controllers/BlinkyTapeController/BlinkyTapeController.h \
Controllers/BlinkyTapeController/RGBController_BlinkyTape.h \
Controllers/CoolerMasterController/CMARGBcontroller.h \
Controllers/CoolerMasterController/CMMP750Controller.h \
Controllers/CoolerMasterController/CMSmallARGBController.h \
@ -513,6 +515,9 @@ SOURCES +=
Controllers/AsusAuraUSBController/RGBController_AsusAuraMouse.cpp \
Controllers/AsusAuraUSBController/RGBController_AsusAuraTUFKeyboard.cpp \
Controllers/AsusAuraUSBController/RGBController_AsusAuraUSB.cpp \
Controllers/BlinkyTapeController/BlinkyTapeController.cpp \
Controllers/BlinkyTapeController/BlinkyTapeControllerDetect.cpp \
Controllers/BlinkyTapeController/RGBController_BlinkyTape.cpp \
Controllers/CoolerMasterController/CMARGBcontroller.cpp \
Controllers/CoolerMasterController/CMMP750Controller.cpp \
Controllers/CoolerMasterController/CMSmallARGBController.cpp \

5
serial_port/serial_port.h

@ -14,7 +14,10 @@
#include <stdio.h>
#ifdef _WIN32
/*---------------------------------------------------------*\
| Windows interferes with std::max unless NOMINMAX defined |
\*---------------------------------------------------------*/
#define NOMINMAX
#include <windows.h>
#endif /* _WIN32 */

Loading…
Cancel
Save