Files
OpenRGB/Controllers/AMBXController/AMBXController.cpp

196 lines
5.2 KiB
C++

/*---------------------------------------------------------*\
| AMBXController.cpp |
| |
| Driver for Philips amBX Gaming lights |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "AMBXController.h"
#include "LogManager.h"
#include "StringUtils.h"
#include <cstring>
#include <thread>
#include <chrono>
AMBXController::AMBXController(const char* path)
{
initialized = false;
usb_context = nullptr;
dev_handle = nullptr;
location = "USB: ";
location += path;
// Initialize libusb in this instance
if(libusb_init(&usb_context) < 0)
{
return;
}
// Get the device list
libusb_device** device_list;
ssize_t device_count = libusb_get_device_list(usb_context, &device_list);
if(device_count < 0)
{
return;
}
for(ssize_t i = 0; i < device_count; i++)
{
libusb_device* device = device_list[i];
struct libusb_device_descriptor desc;
if(libusb_get_device_descriptor(device, &desc) != LIBUSB_SUCCESS)
{
continue;
}
if(desc.idVendor == AMBX_VID && desc.idProduct == AMBX_PID)
{
uint8_t bus = libusb_get_bus_number(device);
uint8_t address = libusb_get_device_address(device);
char current_path[32];
snprintf(current_path, sizeof(current_path), "%d-%d", bus, address);
if(strcmp(path, current_path) == 0)
{
// Try to open this device
if(libusb_open(device, &dev_handle) != LIBUSB_SUCCESS)
{
continue;
}
// Try to detach the kernel driver if attached
if(libusb_kernel_driver_active(dev_handle, 0))
{
libusb_detach_kernel_driver(dev_handle, 0);
}
// Set auto-detach for Windows compatibility
libusb_set_auto_detach_kernel_driver(dev_handle, 1);
// Claim the interface
if(libusb_claim_interface(dev_handle, 0) != LIBUSB_SUCCESS)
{
libusb_close(dev_handle);
dev_handle = nullptr;
continue;
}
// Get string descriptor for serial number if available
if(desc.iSerialNumber != 0)
{
unsigned char serial_str[256];
int serial_result = libusb_get_string_descriptor_ascii(dev_handle, desc.iSerialNumber,
serial_str, sizeof(serial_str));
if(serial_result > 0)
{
serial = std::string(reinterpret_cast<char*>(serial_str), serial_result);
}
}
// Successfully opened and claimed the device
initialized = true;
break;
}
}
}
libusb_free_device_list(device_list, 1);
}
AMBXController::~AMBXController()
{
if(initialized)
{
// Turn off all lights before closing
unsigned int led_ids[5] =
{
AMBX_LIGHT_LEFT,
AMBX_LIGHT_RIGHT,
AMBX_LIGHT_WALL_LEFT,
AMBX_LIGHT_WALL_CENTER,
AMBX_LIGHT_WALL_RIGHT
};
RGBColor colors[5] = { 0, 0, 0, 0, 0 };
SetLEDColors(led_ids, colors, 5);
}
if(dev_handle != nullptr)
{
// Release the interface
libusb_release_interface(dev_handle, 0);
// Close the device
libusb_close(dev_handle);
dev_handle = nullptr;
}
if(usb_context != nullptr)
{
libusb_exit(usb_context);
usb_context = nullptr;
}
}
std::string AMBXController::GetDeviceLocation()
{
return location;
}
std::string AMBXController::GetSerialString()
{
return serial;
}
bool AMBXController::IsInitialized()
{
return initialized;
}
void AMBXController::SendPacket(unsigned char* packet, unsigned int size)
{
if(!initialized || dev_handle == nullptr)
{
return;
}
int actual_length = 0;
libusb_interrupt_transfer(dev_handle, AMBX_ENDPOINT_OUT, packet, size, &actual_length, 100);
}
void AMBXController::SetLEDColor(unsigned int led, RGBColor color)
{
if(!initialized)
{
return;
}
unsigned char color_buf[6] =
{
AMBX_PACKET_HEADER,
static_cast<unsigned char>(led),
AMBX_SET_COLOR,
(unsigned char)RGBGetRValue(color),
(unsigned char)RGBGetGValue(color),
(unsigned char)RGBGetBValue(color)
};
SendPacket(color_buf, 6);
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
void AMBXController::SetLEDColors(unsigned int* leds, RGBColor* colors, unsigned int count)
{
for(unsigned int i = 0; i < count; i++)
{
SetLEDColor(leds[i], colors[i]);
}
}